• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdepimlibs API Reference
  • KDE Home
  • Contact Us
 

akonadi

  • sources
  • kde-4.14
  • kdepimlibs
  • akonadi
pastehelper.cpp
1 /*
2  Copyright (c) 2008 Volker Krause <vkrause@kde.org>
3 
4  This library is free software; you can redistribute it and/or modify it
5  under the terms of the GNU Library General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or (at your
7  option) any later version.
8 
9  This library is distributed in the hope that it will be useful, but WITHOUT
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12  License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to the
16  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  02110-1301, USA.
18 */
19 
20 #include "pastehelper_p.h"
21 
22 #include "collectioncopyjob.h"
23 #include "collectionmovejob.h"
24 #include "collectionfetchjob.h"
25 #include "item.h"
26 #include "itemcreatejob.h"
27 #include "itemcopyjob.h"
28 #include "itemmodifyjob.h"
29 #include "itemmovejob.h"
30 #include "linkjob.h"
31 #include "transactionsequence.h"
32 #include "session.h"
33 #include "unlinkjob.h"
34 
35 #include <KDebug>
36 #include <KUrl>
37 
38 #include <QtCore/QByteArray>
39 #include <QtCore/QMimeData>
40 #include <QtCore/QStringList>
41 #include <QtCore/QMutexLocker>
42 
43 #include <boost/bind.hpp>
44 
45 using namespace Akonadi;
46 
47 class PasteHelperJob: public Akonadi::TransactionSequence
48 {
49  Q_OBJECT
50 
51 public:
52  explicit PasteHelperJob(Qt::DropAction action, const Akonadi::Item::List &items,
53  const Akonadi::Collection::List &collections,
54  const Akonadi::Collection &destination,
55  QObject *parent = 0);
56  virtual ~PasteHelperJob();
57 
58 private Q_SLOTS:
59  void onDragSourceCollectionFetched(KJob *job);
60 
61 private:
62  void runActions();
63  void runItemsActions();
64  void runCollectionsActions();
65 
66 private:
67  Qt::DropAction mAction;
68  Akonadi::Item::List mItems;
69  Akonadi::Collection::List mCollections;
70  Akonadi::Collection mDestCollection;
71 };
72 
73 PasteHelperJob::PasteHelperJob(Qt::DropAction action, const Item::List &items,
74  const Collection::List &collections,
75  const Collection &destination,
76  QObject *parent)
77  : TransactionSequence(parent)
78  , mAction(action)
79  , mItems(items)
80  , mCollections(collections)
81  , mDestCollection(destination)
82 {
83  //FIXME: The below code disables transactions in otder to avoid data loss due to nested
84  //transactions (copy and colcopy in the server doesn't see the items retrieved into the cache and copies empty payloads).
85  //Remove once this is fixed properly, see the other FIXME comments.
86  setProperty("transactionsDisabled", true);
87 
88  Collection dragSourceCollection;
89  if (!items.isEmpty() && items.first().parentCollection().isValid()) {
90  // Check if all items have the same parent collection ID
91  const Collection parent = items.first().parentCollection();
92  if (std::find_if(items.constBegin(), items.constEnd(),
93  boost::bind(&Entity::operator!=, boost::bind(static_cast<Collection (Item::*)() const>(&Item::parentCollection), _1), parent))
94  == items.constEnd())
95  {
96  dragSourceCollection = parent;
97  }
98 
99  kDebug() << items.first().parentCollection().id() << dragSourceCollection.id();
100  }
101 
102  if (dragSourceCollection.isValid()) {
103  // Disable autocommitting, because starting a Link/Unlink/Copy/Move job
104  // after the transaction has ended leaves the job hanging
105  setAutomaticCommittingEnabled(false);
106 
107  CollectionFetchJob *fetch = new CollectionFetchJob(dragSourceCollection,
108  CollectionFetchJob::Base,
109  this);
110  QObject::connect(fetch, SIGNAL(finished(KJob*)),
111  this, SLOT(onDragSourceCollectionFetched(KJob*)));
112  } else {
113  runActions();
114  }
115 }
116 
117 PasteHelperJob::~PasteHelperJob()
118 {
119 }
120 
121 void PasteHelperJob::onDragSourceCollectionFetched(KJob *job)
122 {
123  CollectionFetchJob *fetch = qobject_cast<CollectionFetchJob*>(job);
124  kDebug() << fetch->error() << fetch->collections().count();
125  if (fetch->error() || fetch->collections().count() != 1) {
126  runActions();
127  commit();
128  return;
129  }
130 
131 
132  // If the source collection is virtual, treat copy and move actions differently
133  const Collection sourceCollection = fetch->collections().first();
134  kDebug() << "FROM: " << sourceCollection.id() << sourceCollection.name() << sourceCollection.isVirtual();
135  kDebug() << "DEST: " << mDestCollection.id() << mDestCollection.name() << mDestCollection.isVirtual();
136  kDebug() << "ACTN:" << mAction;
137  if (sourceCollection.isVirtual()) {
138  switch (mAction) {
139  case Qt::CopyAction:
140  if (mDestCollection.isVirtual()) {
141  new LinkJob(mDestCollection, mItems, this);
142  } else {
143  new ItemCopyJob(mItems, mDestCollection, this);
144  }
145  break;
146  case Qt::MoveAction:
147  new UnlinkJob(sourceCollection, mItems, this);
148  if (mDestCollection.isVirtual()) {
149  new LinkJob(mDestCollection, mItems, this);
150  } else {
151  new ItemCopyJob(mItems, mDestCollection, this);
152  }
153  break;
154  case Qt::LinkAction:
155  new LinkJob(mDestCollection, mItems, this);
156  break;
157  default:
158  Q_ASSERT(false);
159  }
160  runCollectionsActions();
161  commit();
162  } else {
163  runActions();
164  }
165 
166  commit();
167 }
168 
169 void PasteHelperJob::runActions()
170 {
171  runItemsActions();
172  runCollectionsActions();
173 }
174 
175 void PasteHelperJob::runItemsActions()
176 {
177  if (mItems.isEmpty()) {
178  return;
179  }
180 
181  switch (mAction) {
182  case Qt::CopyAction:
183  new ItemCopyJob(mItems, mDestCollection, this);
184  break;
185  case Qt::MoveAction:
186  new ItemMoveJob(mItems, mDestCollection, this);
187  break;
188  case Qt::LinkAction:
189  new LinkJob(mDestCollection, mItems, this);
190  break;
191  default:
192  Q_ASSERT(false); // WTF?!
193  }
194 }
195 
196 void PasteHelperJob::runCollectionsActions()
197 {
198  if (mCollections.isEmpty()) {
199  return;
200  }
201 
202  switch (mAction) {
203  case Qt::CopyAction:
204  foreach (const Collection &col, mCollections) { // FIXME: remove once we have a batch job for collections as well
205  new CollectionCopyJob(col, mDestCollection, this);
206  }
207  break;
208  case Qt::MoveAction:
209  foreach (const Collection &col, mCollections) { // FIXME: remove once we have a batch job for collections as well
210  new CollectionMoveJob(col, mDestCollection, this);
211  }
212  break;
213  case Qt::LinkAction:
214  // Not supported for collections
215  break;
216  default:
217  Q_ASSERT(false); // WTF?!
218  }
219 }
220 
221 
222 
223 bool PasteHelper::canPaste(const QMimeData *mimeData, const Collection &collection)
224 {
225  if (!mimeData || !collection.isValid()) {
226  return false;
227  }
228 
229  // check that the target collection has the rights to
230  // create the pasted items resp. collections
231  Collection::Rights neededRights = Collection::ReadOnly;
232  if (KUrl::List::canDecode(mimeData)) {
233  const KUrl::List urls = KUrl::List::fromMimeData(mimeData);
234  foreach (const KUrl &url, urls) {
235  if (url.hasQueryItem(QLatin1String("item"))) {
236  neededRights |= Collection::CanCreateItem;
237  } else if (url.hasQueryItem(QLatin1String("collection"))) {
238  neededRights |= Collection::CanCreateCollection;
239  }
240  }
241 
242  if ((collection.rights() & neededRights) == 0) {
243  return false;
244  }
245 
246  // check that the target collection supports the mime types of the
247  // items/collections that shall be pasted
248  bool supportsMimeTypes = true;
249  foreach (const KUrl &url, urls) {
250  // collections do not provide mimetype information, so ignore this check
251  if (url.hasQueryItem(QLatin1String("collection"))) {
252  continue;
253  }
254 
255  const QString mimeType = url.queryItemValue(QLatin1String("type"));
256  if (!collection.contentMimeTypes().contains(mimeType)) {
257  supportsMimeTypes = false;
258  break;
259  }
260  }
261 
262  if (!supportsMimeTypes) {
263  return false;
264  }
265 
266  return true;
267  }
268 
269  return false;
270 }
271 
272 KJob *PasteHelper::paste(const QMimeData *mimeData, const Collection &collection, bool copy, Session *session)
273 {
274  if (!canPaste(mimeData, collection)) {
275  return 0;
276  }
277 
278  // we try to drop data not coming with the akonadi:// url
279  // find a type the target collection supports
280  foreach (const QString &type, mimeData->formats()) {
281  if (!collection.contentMimeTypes().contains(type)) {
282  continue;
283  }
284 
285  QByteArray item = mimeData->data(type);
286  // HACK for some unknown reason the data is sometimes 0-terminated...
287  if (!item.isEmpty() && item.at(item.size() - 1) == 0) {
288  item.resize(item.size() - 1);
289  }
290 
291  Item it;
292  it.setMimeType(type);
293  it.setPayloadFromData(item);
294 
295  ItemCreateJob *job = new ItemCreateJob(it, collection);
296  return job;
297  }
298 
299  if (!KUrl::List::canDecode(mimeData)) {
300  return 0;
301  }
302 
303  // data contains an url list
304  return pasteUriList(mimeData, collection, copy ? Qt::CopyAction : Qt::MoveAction, session);
305 }
306 
307 KJob *PasteHelper::pasteUriList(const QMimeData *mimeData, const Collection &destination, Qt::DropAction action, Session *session)
308 {
309  if (!KUrl::List::canDecode(mimeData)) {
310  return 0;
311  }
312 
313  if (!canPaste(mimeData, destination)) {
314  return 0;
315  }
316 
317  const KUrl::List urls = KUrl::List::fromMimeData(mimeData);
318  Collection::List collections;
319  Item::List items;
320  foreach (const KUrl &url, urls) {
321  const Collection collection = Collection::fromUrl(url);
322  if (collection.isValid()) {
323  collections.append(collection);
324  }
325  Item item = Item::fromUrl(url);
326  if (url.hasQueryItem(QLatin1String("parent"))) {
327  item.setParentCollection(Collection(url.queryItem(QLatin1String("parent")).toLongLong()));
328  }
329  if (item.isValid()) {
330  items.append(item);
331  }
332  // TODO: handle non Akonadi URLs?
333  }
334 
335 
336  PasteHelperJob *job = new PasteHelperJob(action, items,
337  collections, destination,
338  session);
339 
340  return job;
341 }
342 
343 #include "pastehelper.moc"
QMimeData::data
QByteArray data(const QString &mimeType) const
Akonadi::CollectionFetchJob::collections
Collection::List collections() const
Returns the list of fetched collection.
Definition: collectionfetchjob.cpp:169
Akonadi::Collection::name
QString name() const
Returns the i18n'ed name of the collection.
Definition: collection.cpp:81
QByteArray
QByteArray::at
char at(int i) const
Akonadi::CollectionMoveJob
Job that moves a collection in the Akonadi storage to a new parent collection.
Definition: collectionmovejob.h:50
Akonadi::ItemCopyJob
Job that copies a set of items to a target collection in the Akonadi storage.
Definition: itemcopyjob.h:60
Akonadi::Collection
Represents a collection of PIM items.
Definition: collection.h:75
Akonadi::PasteHelper::paste
KJob * paste(const QMimeData *mimeData, const Collection &collection, bool copy=true, Session *session=0)
Paste/drop the given mime data into the given collection.
Definition: pastehelper.cpp:272
Akonadi::CollectionFetchJob
Job that fetches collections from the Akonadi storage.
Definition: collectionfetchjob.h:53
QStringList::contains
bool contains(const QString &str, Qt::CaseSensitivity cs) const
QByteArray::isEmpty
bool isEmpty() const
Akonadi::Collection::CanCreateCollection
Can create new subcollections in this collection.
Definition: collection.h:92
Akonadi::PasteHelper::pasteUriList
KJob * pasteUriList(const QMimeData *mimeData, const Collection &collection, Qt::DropAction action, Session *session=0)
URI list paste/drop.
Definition: pastehelper.cpp:307
Akonadi::UnlinkJob
Job that unlinks items inside the Akonadi storage.
Definition: unlinkjob.h:64
Akonadi::LinkJob
Job that links items inside the Akonadi storage.
Definition: linkjob.h:64
QMimeData
Akonadi::CollectionFetchJob::Base
Only fetch the base collection.
Definition: collectionfetchjob.h:62
QByteArray::resize
void resize(int size)
Akonadi::Collection::ReadOnly
Can only read items or subcollection of this collection.
Definition: collection.h:87
QList::count
int count(const T &value) const
QList::append
void append(const T &value)
Akonadi::Entity::parentCollection
Collection parentCollection() const
Returns the parent collection of this object.
Definition: entity.cpp:185
QObject
Akonadi::Collection::CanCreateItem
Can create new items in this collection.
Definition: collection.h:89
Akonadi::Session
A communication session with the Akonadi storage.
Definition: session.h:59
QList::first
T & first()
QString
QList
Akonadi::ItemCreateJob
Job that creates a new item in the Akonadi storage.
Definition: itemcreatejob.h:73
Akonadi::Entity::id
Id id() const
Returns the unique identifier of the entity.
Definition: entity.cpp:72
Akonadi::CollectionCopyJob
Job that copies a collection into another collection in the Akonadi storage.
Definition: collectioncopyjob.h:57
Akonadi::Collection::rights
Rights rights() const
Returns the rights the user has on the collection.
Definition: collection.cpp:99
Akonadi::PasteHelper::canPaste
bool canPaste(const QMimeData *mimeData, const Collection &collection)
Check whether the given mime data can be pasted into the given collection.
Definition: pastehelper.cpp:223
Akonadi::ItemMoveJob
Job that moves an item into a different collection in the Akonadi storage.
Definition: itemmovejob.h:48
Akonadi::TransactionSequence
Base class for jobs that need to run a sequence of sub-jobs in a transaction.
Definition: transactionsequence.h:69
QLatin1String
Akonadi::Collection::contentMimeTypes
QStringList contentMimeTypes() const
Returns a list of possible content mimetypes, e.g.
Definition: collection.cpp:115
QMimeData::formats
virtual QStringList formats() const
Akonadi::Entity::isValid
bool isValid() const
Returns whether the entity is valid.
Definition: entity.cpp:97
QByteArray::size
int size() const
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
Akonadi::Collection::fromUrl
static Collection fromUrl(const KUrl &url)
Creates a collection from the given url.
Definition: collection.cpp:172
Akonadi::Collection::isVirtual
bool isVirtual() const
Returns whether the collection is virtual, for example a search collection.
Definition: collection.cpp:261
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:38:03 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi

Skip menu "akonadi"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Modules
  • Related Pages

kdepimlibs API Reference

Skip menu "kdepimlibs API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal