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

akonadi

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

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