• 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
trashjob.cpp
1 /*
2  Copyright (c) 2011 Christian Mollekopf <chrigi_1@fastmail.fm>
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 "trashjob.h"
21 
22 #include "collection.h"
23 #include "entitydeletedattribute.h"
24 #include "item.h"
25 #include "job_p.h"
26 #include "trashsettings.h"
27 
28 #include <KLocalizedString>
29 
30 #include <akonadi/itemdeletejob.h>
31 #include <akonadi/collectiondeletejob.h>
32 #include <akonadi/itemmovejob.h>
33 #include <akonadi/collectionmovejob.h>
34 #include <akonadi/itemmodifyjob.h>
35 #include <akonadi/collectionmodifyjob.h>
36 #include <akonadi/itemfetchscope.h>
37 #include <akonadi/collectionfetchscope.h>
38 #include <akonadi/itemfetchjob.h>
39 #include <akonadi/collectionfetchjob.h>
40 
41 #include <QHash>
42 
43 using namespace Akonadi;
44 
45 class TrashJob::TrashJobPrivate : public JobPrivate
46 {
47 public:
48  TrashJobPrivate(TrashJob *parent)
49  : JobPrivate(parent)
50  , mKeepTrashInCollection(false)
51  , mSetRestoreCollection(false)
52  , mDeleteIfInTrash(false)
53  {
54  }
55 //4.
56  void selectResult(KJob *job);
57 //3.
58  //Helper functions to recursivly set the attribute on deleted collections
59  void setAttribute(const Akonadi::Collection::List &);
60  void setAttribute(const Akonadi::Item::List &);
61  //Set attributes after ensuring that move job was successful
62  void setAttribute(KJob *job);
63 
64 //2.
65  //called after parent of the trashed item was fetched (needed to see in which resource the item is in)
66  void parentCollectionReceived(const Akonadi::Collection::List &);
67 
68 //1.
69  //called after initial fetch of trashed items
70  void itemsReceived(const Akonadi::Item::List &);
71  //called after initial fetch of trashed collection
72  void collectionsReceived(const Akonadi::Collection::List &);
73 
74  Q_DECLARE_PUBLIC(TrashJob)
75 
76  Item::List mItems;
77  Collection mCollection;
78  Collection mRestoreCollection;
79  Collection mTrashCollection;
80  bool mKeepTrashInCollection;
81  bool mSetRestoreCollection; //only set restore collection when moved to trash collection (not in place)
82  bool mDeleteIfInTrash;
83  QHash<Collection, Item::List> mCollectionItems; //list of trashed items sorted according to parent collection
84  QHash<Entity::Id, Collection> mParentCollections; //fetched parent collcetion of items (containing the resource name)
85 
86 };
87 
88 void TrashJob::TrashJobPrivate::selectResult(KJob *job)
89 {
90  Q_Q(TrashJob);
91  if (job->error()) {
92  kWarning() << job->objectName();
93  kWarning() << job->errorString();
94  return; // KCompositeJob takes care of errors
95  }
96 
97  if (!q->hasSubjobs() || (q->subjobs().contains(static_cast<KJob *>(q->sender())) && q->subjobs().size() == 1)) {
98  q->emitResult();
99  }
100 }
101 
102 void TrashJob::TrashJobPrivate::setAttribute(const Akonadi::Collection::List &list)
103 {
104  Q_Q(TrashJob);
105  QListIterator<Collection> i(list);
106  while (i.hasNext()) {
107  const Collection &col = i.next();
108  EntityDeletedAttribute *eda = new EntityDeletedAttribute();
109  if (mSetRestoreCollection) {
110  Q_ASSERT(mRestoreCollection.isValid());
111  eda->setRestoreCollection(mRestoreCollection);
112  }
113 
114  Collection modCol(col.id()); //really only modify attribute (forget old remote ids, etc.), otherwise we have an error because of the move
115  modCol.addAttribute(eda);
116 
117  CollectionModifyJob *job = new CollectionModifyJob(modCol, q);
118  q->connect(job, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*)));
119 
120  ItemFetchJob *itemFetchJob = new ItemFetchJob(col, q);
121  //TODO not sure if it is guaranteed that itemsReceived is always before result (otherwise the result is emitted before the attributes are set)
122  q->connect(itemFetchJob, SIGNAL(itemsReceived(Akonadi::Item::List)), SLOT(setAttribute(Akonadi::Item::List)));
123  q->connect(itemFetchJob, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*)));
124  }
125 }
126 
127 void TrashJob::TrashJobPrivate::setAttribute(const Akonadi::Item::List &list)
128 {
129  Q_Q(TrashJob);
130  Item::List items = list;
131  QMutableListIterator<Item> i(items);
132  while (i.hasNext()) {
133  const Item &item = i.next();
134  EntityDeletedAttribute *eda = new EntityDeletedAttribute();
135  if (mSetRestoreCollection) {
136  //When deleting a collection, we want to restore the deleted collection's items restored to the deleted collection's parent, not the items parent
137  if (mRestoreCollection.isValid()) {
138  eda->setRestoreCollection(mRestoreCollection);
139  } else {
140  Q_ASSERT(mParentCollections.contains(item.parentCollection().id()));
141  eda->setRestoreCollection(mParentCollections.value(item.parentCollection().id()));
142  }
143  }
144 
145  Item modItem(item.id()); //really only modify attribute (forget old remote ids, etc.)
146  modItem.addAttribute(eda);
147  ItemModifyJob *job = new ItemModifyJob(modItem, q);
148  job->setIgnorePayload(true);
149  q->connect(job, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*)));
150  }
151 
152  //For some reason it is not possible to apply this change to multiple items at once
153  /*ItemModifyJob *job = new ItemModifyJob(items, q);
154  q->connect( job, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*)) );*/
155 }
156 
157 void TrashJob::TrashJobPrivate::setAttribute(KJob *job)
158 {
159  Q_Q(TrashJob);
160  if (job->error()) {
161  kWarning() << job->objectName();
162  kWarning() << job->errorString();
163  q->setError(Job::Unknown);
164  q->setErrorText(i18n("Move to trash collection failed, aborting trash operation"));
165  return;
166  }
167 
168  //For Items
169  const QVariant var = job->property("MovedItems");
170  if (var.isValid()) {
171  int id = var.toInt();
172  Q_ASSERT(id >= 0);
173  setAttribute(mCollectionItems.value(Collection(id)));
174  return;
175  }
176 
177  //For a collection
178  Q_ASSERT(mCollection.isValid());
179  setAttribute(Collection::List() << mCollection);
180  //Set the attribute on all subcollections and items
181  CollectionFetchJob *colFetchJob = new CollectionFetchJob(mCollection, CollectionFetchJob::Recursive, q);
182  q->connect(colFetchJob, SIGNAL(collectionsReceived(Akonadi::Collection::List)), SLOT(setAttribute(Akonadi::Collection::List)));
183  q->connect(colFetchJob, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*)));
184 }
185 
186 void TrashJob::TrashJobPrivate::parentCollectionReceived(const Akonadi::Collection::List &collections)
187 {
188  Q_Q(TrashJob);
189  Q_ASSERT(collections.size() == 1);
190  const Collection &parentCollection = collections.first();
191 
192  //store attribute
193  Q_ASSERT(!parentCollection.resource().isEmpty());
194  Collection trashCollection = mTrashCollection;
195  if (!mTrashCollection.isValid()) {
196  trashCollection = TrashSettings::getTrashCollection(parentCollection.resource());
197  }
198  if (!mKeepTrashInCollection && trashCollection.isValid()) { //Only set the restore collection if the item is moved to trash
199  mSetRestoreCollection = true;
200  }
201 
202  mParentCollections.insert(parentCollection.id(), parentCollection);
203 
204  if (trashCollection.isValid()) { //Move the items to the correct collection if available
205  ItemMoveJob *job = new ItemMoveJob(mCollectionItems.value(parentCollection), trashCollection, q);
206  job->setProperty("MovedItems", parentCollection.id());
207  q->connect(job, SIGNAL(result(KJob*)), SLOT(setAttribute(KJob*))); //Wait until the move finished to set the attirbute
208  q->connect(job, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*)));
209  } else {
210  setAttribute(mCollectionItems.value(parentCollection));
211  }
212 }
213 
214 void TrashJob::TrashJobPrivate::itemsReceived(const Akonadi::Item::List &items)
215 {
216  Q_Q(TrashJob);
217  if (items.isEmpty()) {
218  q->setError(Job::Unknown);
219  q->setErrorText(i18n("Invalid items passed"));
220  q->emitResult();
221  return;
222  }
223 
224  Item::List toDelete;
225 
226  QListIterator<Item> i(items);
227  while (i.hasNext()) {
228  const Item &item = i.next();
229  if (item.hasAttribute<EntityDeletedAttribute>()) {
230  toDelete.append(item);
231  continue;
232  }
233  Q_ASSERT(item.parentCollection().isValid());
234  mCollectionItems[item.parentCollection()].append(item); //Sort by parent col ( = restore collection)
235  }
236 
237  foreach (const Collection &col, mCollectionItems.keys()) { //krazy:exclude=foreach
238  CollectionFetchJob *job = new CollectionFetchJob(col, Akonadi::CollectionFetchJob::Base, q);
239  q->connect(job, SIGNAL(collectionsReceived(Akonadi::Collection::List)),
240  SLOT(parentCollectionReceived(Akonadi::Collection::List)));
241  }
242 
243  if (mDeleteIfInTrash && !toDelete.isEmpty()) {
244  ItemDeleteJob *job = new ItemDeleteJob(toDelete, q);
245  q->connect(job, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*)));
246  } else if (mCollectionItems.isEmpty()) { //No job started, so we abort the job
247  kWarning() << "Nothing to do";
248  q->emitResult();
249  }
250 
251 }
252 
253 void TrashJob::TrashJobPrivate::collectionsReceived(const Akonadi::Collection::List &collections)
254 {
255  Q_Q(TrashJob);
256  if (collections.isEmpty()) {
257  q->setError(Job::Unknown);
258  q->setErrorText(i18n("Invalid collection passed"));
259  q->emitResult();
260  return;
261  }
262  Q_ASSERT(collections.size() == 1);
263  mCollection = collections.first();
264 
265  if (mCollection.hasAttribute<EntityDeletedAttribute>()) { //marked as deleted
266  if (mDeleteIfInTrash) {
267  CollectionDeleteJob *job = new CollectionDeleteJob(mCollection, q);
268  q->connect(job, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*)));
269  } else {
270  kWarning() << "Nothing to do";
271  q->emitResult();
272  }
273  return;
274  }
275 
276  Collection trashCollection = mTrashCollection;
277  if (!mTrashCollection.isValid()) {
278  trashCollection = TrashSettings::getTrashCollection(mCollection.resource());
279  }
280  if (!mKeepTrashInCollection && trashCollection.isValid()) { //only set the restore collection if the item is moved to trash
281  mSetRestoreCollection = true;
282  Q_ASSERT(mCollection.parentCollection().isValid());
283  mRestoreCollection = mCollection.parentCollection();
284  mRestoreCollection.setResource(mCollection.resource()); //The parent collection doesn't contain the resource, so we have to set it manually
285  }
286 
287  if (trashCollection.isValid()) {
288  CollectionMoveJob *job = new CollectionMoveJob(mCollection, trashCollection, q);
289  q->connect(job, SIGNAL(result(KJob*)), SLOT(setAttribute(KJob*)));
290  q->connect(job, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*)));
291  } else {
292  setAttribute(Collection::List() << mCollection);
293  }
294 
295 }
296 
297 TrashJob::TrashJob(const Item &item, QObject *parent)
298  : Job(new TrashJobPrivate(this), parent)
299 {
300  Q_D(TrashJob);
301  d->mItems << item;
302 }
303 
304 TrashJob::TrashJob(const Item::List &items, QObject *parent)
305  : Job(new TrashJobPrivate(this), parent)
306 {
307  Q_D(TrashJob);
308  d->mItems = items;
309 }
310 
311 TrashJob::TrashJob(const Collection &collection, QObject *parent)
312  : Job(new TrashJobPrivate(this), parent)
313 {
314  Q_D(TrashJob);
315  d->mCollection = collection;
316 }
317 
318 TrashJob::~TrashJob()
319 {
320 }
321 
322 Item::List TrashJob::items() const
323 {
324  Q_D(const TrashJob);
325  return d->mItems;
326 }
327 
328 void TrashJob::setTrashCollection(const Akonadi::Collection &collection)
329 {
330  Q_D(TrashJob);
331  d->mTrashCollection = collection;
332 }
333 
334 void TrashJob::keepTrashInCollection(bool enable)
335 {
336  Q_D(TrashJob);
337  d->mKeepTrashInCollection = enable;
338 }
339 
340 void TrashJob::deleteIfInTrash(bool enable)
341 {
342  Q_D(TrashJob);
343  d->mDeleteIfInTrash = enable;
344 }
345 
346 void TrashJob::doStart()
347 {
348  Q_D(TrashJob);
349 
350  //Fetch items first to ensure that the EntityDeletedAttribute is available
351  if (!d->mItems.isEmpty()) {
352  ItemFetchJob *job = new ItemFetchJob(d->mItems, this);
353  job->fetchScope().setAncestorRetrieval(Akonadi::ItemFetchScope::Parent); //so we have access to the resource
354  //job->fetchScope().setCacheOnly(true);
355  job->fetchScope().fetchAttribute<EntityDeletedAttribute>(true);
356  connect(job, SIGNAL(itemsReceived(Akonadi::Item::List)), this, SLOT(itemsReceived(Akonadi::Item::List)));
357 
358  } else if (d->mCollection.isValid()) {
359  CollectionFetchJob *job = new CollectionFetchJob(d->mCollection, CollectionFetchJob::Base, this);
360  job->fetchScope().setAncestorRetrieval(Akonadi::CollectionFetchScope::Parent);
361  connect(job, SIGNAL(collectionsReceived(Akonadi::Collection::List)), this, SLOT(collectionsReceived(Akonadi::Collection::List)));
362 
363  } else {
364  kWarning() << "No valid collection or empty itemlist";
365  setError(Job::Unknown);
366  setErrorText(i18n("No valid collection or empty itemlist"));
367  emitResult();
368  }
369 }
370 
371 #include "moc_trashjob.cpp"
Akonadi::CollectionModifyJob
Job that modifies a collection in the Akonadi storage.
Definition: collectionmodifyjob.h:82
Akonadi::ItemFetchScope::fetchAttribute
void fetchAttribute(const QByteArray &type, bool fetch=true)
Sets whether the attribute of the given type should be fetched.
Definition: itemfetchscope.cpp:80
Akonadi::CollectionFetchScope::setAncestorRetrieval
void setAncestorRetrieval(AncestorRetrieval ancestorDepth)
Sets how many levels of ancestor collections should be included in the retrieval. ...
Definition: collectionfetchscope.cpp:138
Akonadi::Job::Unknown
Unknown error.
Definition: job.h:108
Akonadi::CollectionMoveJob
Job that moves a collection in the Akonadi storage to a new parent collection.
Definition: collectionmovejob.h:50
Akonadi::CollectionFetchJob::fetchScope
CollectionFetchScope & fetchScope()
Returns the collection fetch scope.
Definition: collectionfetchjob.cpp:439
Akonadi::Collection
Represents a collection of PIM items.
Definition: collection.h:75
Akonadi::CollectionFetchJob
Job that fetches collections from the Akonadi storage.
Definition: collectionfetchjob.h:53
Akonadi::Job
Base class for all actions in the Akonadi storage.
Definition: job.h:86
Akonadi::TrashJob::keepTrashInCollection
void keepTrashInCollection(bool enable)
Ignore configured Trash collections and keep all items local.
Definition: trashjob.cpp:334
Akonadi::CollectionFetchScope::Parent
Only retrieve the immediate parent collection.
Definition: collectionfetchscope.h:76
QList::size
int size() const
Akonadi::CollectionFetchJob::Base
Only fetch the base collection.
Definition: collectionfetchjob.h:62
Akonadi::ItemDeleteJob
Job that deletes items from the Akonadi storage.
Definition: itemdeletejob.h:62
Akonadi::ItemFetchJob::fetchScope
ItemFetchScope & fetchScope()
Returns the item fetch scope.
Definition: itemfetchjob.cpp:261
Akonadi::Entity::parentCollection
Collection parentCollection() const
Returns the parent collection of this object.
Definition: entity.cpp:185
QVariant::toInt
int toInt(bool *ok) const
QHash
Akonadi::ItemFetchScope::Parent
Only retrieve the immediate parent collection.
Definition: itemfetchscope.h:78
QObject
QList::isEmpty
bool isEmpty() const
Akonadi::TrashJob::deleteIfInTrash
void deleteIfInTrash(bool enable)
Delete Items which are already in trash, instead of ignoring them.
Definition: trashjob.cpp:340
Akonadi::CollectionDeleteJob
Job that deletes a collection in the Akonadi storage.
Definition: collectiondeletejob.h:63
QList::first
T & first()
QList
Akonadi::Job::List
QList< Job * > List
Describes a list of jobs.
Definition: job.h:97
Akonadi::Entity::id
Id id() const
Returns the unique identifier of the entity.
Definition: entity.cpp:72
Akonadi::TrashJob::TrashJob
TrashJob(const Item &item, QObject *parent=0)
Creates a new trash job that marks item as trash, and moves it to the configured trash collection...
Definition: trashjob.cpp:297
Akonadi::TrashJob
Job that moves items/collection to trash.
Definition: trashjob.h:66
Akonadi::Entity
The base class for Item and Collection.
Definition: entity.h:59
Akonadi::ItemFetchScope::setAncestorRetrieval
void setAncestorRetrieval(AncestorRetrieval ancestorDepth)
Sets how many levels of ancestor collections should be included in the retrieval. ...
Definition: itemfetchscope.cpp:132
Akonadi::EntityDeletedAttribute
An Attribute that marks that an entity was marked as deleted.
Definition: entitydeletedattribute.h:49
Akonadi::ItemModifyJob::setIgnorePayload
void setIgnorePayload(bool ignore)
Sets whether the payload of the modified item shall be omitted from transmission to the Akonadi stora...
Definition: itemmodifyjob.cpp:411
Akonadi::ItemMoveJob
Job that moves an item into a different collection in the Akonadi storage.
Definition: itemmovejob.h:48
Akonadi::TrashSettings::getTrashCollection
AKONADI_EXPORT Collection getTrashCollection(const QString &resource)
Get the trash collection for the given resource.
Definition: trashsettings.cpp:30
Akonadi::TrashJob::setTrashCollection
void setTrashCollection(const Collection &trashcollection)
Moves all entities to the give collection.
Definition: trashjob.cpp:328
QMutableListIterator
Akonadi::ItemModifyJob
Job that modifies an existing item in the Akonadi storage.
Definition: itemmodifyjob.h:97
Akonadi::ItemFetchJob
Job that fetches items from the Akonadi storage.
Definition: itemfetchjob.h:82
Akonadi::JobPrivate
Definition: job_p.h:31
Akonadi::TrashJob::doStart
virtual void doStart()
This method must be reimplemented in the concrete jobs.
Definition: trashjob.cpp:346
QVariant::isValid
bool isValid() const
QListIterator
Akonadi::Entity::isValid
bool isValid() const
Returns whether the entity is valid.
Definition: entity.cpp:97
Akonadi::CollectionFetchJob::Recursive
List all sub-collections.
Definition: collectionfetchjob.h:64
Akonadi::Collection::setResource
void setResource(const QString &identifier)
Sets the identifier of the resource owning the collection.
Definition: collection.cpp:212
Akonadi::EntityDeletedAttribute::setRestoreCollection
void setRestoreCollection(const Collection &col)
Sets the collection used to restore items which have been moved to trash using a TrashJob If the Reso...
Definition: entitydeletedattribute.cpp:49
QVariant
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