• 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
trashrestorejob.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 "trashrestorejob.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/collectionfetchjob.h>
37 #include <akonadi/itemfetchjob.h>
38 #include <akonadi/collectionfetchscope.h>
39 #include <akonadi/itemfetchscope.h>
40 
41 #include <QHash>
42 
43 using namespace Akonadi;
44 
45 class TrashRestoreJob::TrashRestoreJobPrivate : public JobPrivate
46 {
47  public:
48  TrashRestoreJobPrivate( TrashRestoreJob *parent )
49  : JobPrivate( parent ) {
50  }
51 
52  void selectResult( KJob * );
53 
54  //Called when the target collection was fetched,
55  //will issue the move and the removal of the attributes if collection is valid
56  void targetCollectionFetched( KJob * );
57 
58  void removeAttribute( const Akonadi::Item::List & );
59  void removeAttribute( const Akonadi::Collection::List & );
60 
61  //Called after initial fetch of items, issues fetch of target collection or removes attributes for in place restore
62  void itemsReceived( const Akonadi::Item::List & );
63  void collectionsReceived( const Akonadi::Collection::List & );
64 
65  Q_DECLARE_PUBLIC( TrashRestoreJob )
66 
67  Item::List mItems;
68  Collection mCollection;
69  Collection mTargetCollection;
70  QHash<Collection, Item::List> restoreCollections; //groups items to target restore collections
71 
72 };
73 
74 void TrashRestoreJob::TrashRestoreJobPrivate::selectResult( KJob *job )
75 {
76  Q_Q( TrashRestoreJob );
77  if ( job->error() ) {
78  kWarning() << job->errorString();
79  return; // KCompositeJob takes care of errors
80  }
81 
82  if ( !q->hasSubjobs() || ( q->subjobs().contains( static_cast<KJob*>( q->sender() ) ) && q->subjobs().size() == 1 ) ) {
83  //kWarning() << "trash restore finished";
84  q->emitResult();
85  }
86 }
87 
88 void TrashRestoreJob::TrashRestoreJobPrivate::targetCollectionFetched( KJob *job )
89 {
90  Q_Q( TrashRestoreJob );
91 
92  CollectionFetchJob *fetchJob = qobject_cast<CollectionFetchJob*> ( job );
93  Q_ASSERT( fetchJob );
94  const Collection::List &list = fetchJob->collections();
95 
96  if ( list.isEmpty() || !list.first().isValid() || list.first().hasAttribute<Akonadi::EntityDeletedAttribute>() ) { //target collection is invalid/not existing
97 
98  const QString res = fetchJob->property( "Resource" ).toString();
99  if ( res.isEmpty() ) { //There is no fallback
100  q->setError( Job::Unknown );
101  q->setErrorText( i18n( "Could not find restore collection and restore resource is not available" ) );
102  q->emitResult();
103  //FAIL
104  kWarning() << "restore collection not available";
105  return;
106  }
107 
108  //Try again with the root collection of the resource as fallback
109  CollectionFetchJob *resRootFetch = new CollectionFetchJob( Collection::root(), CollectionFetchJob::FirstLevel, q );
110  resRootFetch->fetchScope().setResource( res );
111  const QVariant &var = fetchJob->property( "Items" );
112  if ( var.isValid() ) {
113  resRootFetch->setProperty( "Items", var.toInt() );
114  }
115  q->connect( resRootFetch, SIGNAL(result(KJob*)), SLOT(targetCollectionFetched(KJob*)) );
116  q->connect( resRootFetch, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*)) );
117  return;
118  }
119  Q_ASSERT( list.size() == 1 );
120  //SUCCESS
121  //We know where to move the entity, so remove the attributes and move them to the right location
122  if ( !mItems.isEmpty() ) {
123  const QVariant &var = fetchJob->property( "Items" );
124  Q_ASSERT( var.isValid() );
125  const Item::List &items = restoreCollections[Collection( var.toInt() )];
126 
127  //store removed attribute if destination collection is valid or the item doesn't have a restore collection
128  //TODO only remove the attribute if the move job was successful (although it is unlikely that it fails since we already fetched the collection)
129  removeAttribute( items );
130  if ( items.first().parentCollection() != list.first() ) {
131  ItemMoveJob *job = new ItemMoveJob( items, list.first(), q );
132  q->connect( job, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*)) );
133  }
134  } else {
135  Q_ASSERT( mCollection.isValid() );
136  //TODO only remove the attribute if the move job was successful
137  removeAttribute( Collection::List() << mCollection );
138  CollectionFetchJob *collectionFetchJob = new CollectionFetchJob( mCollection, CollectionFetchJob::Recursive, q );
139  q->connect( collectionFetchJob, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*)) );
140  q->connect( collectionFetchJob, SIGNAL(collectionsReceived(Akonadi::Collection::List)), SLOT(removeAttribute(Akonadi::Collection::List)) );
141 
142  if ( mCollection.parentCollection() != list.first() ) {
143  CollectionMoveJob *job = new CollectionMoveJob( mCollection, list.first(), q );
144  q->connect( job, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*)) );
145  }
146  }
147 
148 }
149 
150 void TrashRestoreJob::TrashRestoreJobPrivate::itemsReceived( const Akonadi::Item::List &items )
151 {
152  Q_Q( TrashRestoreJob );
153  if ( items.isEmpty() ) {
154  q->setError( Job::Unknown );
155  q->setErrorText( i18n( "Invalid items passed" ) );
156  q->emitResult();
157  return;
158  }
159  mItems = items;
160 
161  //Sort by restore collection
162  foreach( const Item &item, mItems ) {
163  if ( !item.hasAttribute<Akonadi::EntityDeletedAttribute>() ) {
164  continue;
165  }
166  //If the restore collection is invalid we restore the item in place, so we don't need to know its restore resource => we can put those cases in the same list
167  restoreCollections[item.attribute<Akonadi::EntityDeletedAttribute>()->restoreCollection()].append( item );
168  }
169 
170  foreach( const Collection &col, restoreCollections.keys() ) { //krazy:exclude=foreach
171  const Item &first = restoreCollections.value( col ).first();
172  //Move the items to the correct collection if available
173  Collection targetCollection = col;
174  const QString restoreResource = first.attribute<Akonadi::EntityDeletedAttribute>()->restoreResource();
175 
176  //Restore in place if no restore collection is set
177  if ( !targetCollection.isValid() ) {
178  removeAttribute( restoreCollections.value( col ) );
179  return;
180  }
181 
182  //Explicit target overrides the resource
183  if ( mTargetCollection.isValid() ) {
184  targetCollection = mTargetCollection;
185  }
186 
187  //Try to fetch the target resource to see if it is available
188  CollectionFetchJob *fetchJob = new CollectionFetchJob( targetCollection, Akonadi::CollectionFetchJob::Base, q );
189  if ( !mTargetCollection.isValid() ) { //explicit targets don't have a fallback
190  fetchJob->setProperty( "Resource", restoreResource );
191  }
192  fetchJob->setProperty( "Items", col.id() ); //to find the items in restore collections again
193  q->connect( fetchJob, SIGNAL(result(KJob*)), SLOT(targetCollectionFetched(KJob*)) );
194  }
195 }
196 
197 void TrashRestoreJob::TrashRestoreJobPrivate::collectionsReceived( const Akonadi::Collection::List &collections )
198 {
199  Q_Q( TrashRestoreJob );
200  if ( collections.isEmpty() ) {
201  q->setError( Job::Unknown );
202  q->setErrorText( i18n( "Invalid collection passed" ) );
203  q->emitResult();
204  return;
205  }
206  Q_ASSERT( collections.size() == 1 );
207  mCollection = collections.first();
208 
209  if ( !mCollection.hasAttribute<Akonadi::EntityDeletedAttribute>() ) {
210  return;
211  }
212 
213  const QString restoreResource = mCollection.attribute<Akonadi::EntityDeletedAttribute>()->restoreResource();
214  Collection targetCollection = mCollection.attribute<EntityDeletedAttribute>()->restoreCollection();
215 
216  //Restore in place if no restore collection/resource is set
217  if ( !targetCollection.isValid() ) {
218  removeAttribute( Collection::List() << mCollection );
219  CollectionFetchJob *collectionFetchJob = new CollectionFetchJob( mCollection, CollectionFetchJob::Recursive, q );
220  q->connect( collectionFetchJob, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*)) );
221  q->connect( collectionFetchJob, SIGNAL(collectionsReceived(Akonadi::Collection::List)), SLOT(removeAttribute(Akonadi::Collection::List)) );
222  return;
223  }
224 
225  //Explicit target overrides the resource/configured restore collection
226  if ( mTargetCollection.isValid() ) {
227  targetCollection = mTargetCollection;
228  }
229 
230  //Fetch the target collection to check if it's valid
231  CollectionFetchJob *fetchJob = new CollectionFetchJob( targetCollection, CollectionFetchJob::Base, q );
232  if ( !mTargetCollection.isValid() ) { //explicit targets don't have a fallback
233  fetchJob->setProperty( "Resource", restoreResource );
234  }
235  q->connect( fetchJob, SIGNAL(result(KJob*)), SLOT(targetCollectionFetched(KJob*)) );
236 }
237 
238 void TrashRestoreJob::TrashRestoreJobPrivate::removeAttribute( const Akonadi::Collection::List &list )
239 {
240  Q_Q( TrashRestoreJob );
241  QListIterator<Collection> i( list );
242  while ( i.hasNext() ) {
243  Collection col = i.next();
244  col.removeAttribute<EntityDeletedAttribute>();
245 
246  CollectionModifyJob *job = new CollectionModifyJob( col, q );
247  q->connect( job, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*)) );
248 
249  ItemFetchJob *itemFetchJob = new ItemFetchJob( col, q );
250  itemFetchJob->fetchScope().fetchAttribute<EntityDeletedAttribute> ( true );
251  q->connect( itemFetchJob, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*)) );
252  q->connect( itemFetchJob, SIGNAL(itemsReceived(Akonadi::Item::List)), SLOT(removeAttribute(Akonadi::Item::List)) );
253  }
254 }
255 
256 void TrashRestoreJob::TrashRestoreJobPrivate::removeAttribute( const Akonadi::Item::List &list )
257 {
258  Q_Q( TrashRestoreJob );
259  Item::List items = list;
260  QMutableListIterator<Item> i( items );
261  while ( i.hasNext() ) {
262  Item &item = i.next();
263  item.removeAttribute<EntityDeletedAttribute>();
264  ItemModifyJob *job = new ItemModifyJob( item, q );
265  job->setIgnorePayload( true );
266  q->connect( job, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*)) );
267  }
268  //For some reason it is not possible to apply this change to multiple items at once
269  //ItemModifyJob *job = new ItemModifyJob(items, q);
270  //q->connect( job, SIGNAL(result(KJob*)), SLOT(selectResult(KJob*)) );
271 }
272 
273 TrashRestoreJob::TrashRestoreJob( const Item & item, QObject * parent )
274  : Job( new TrashRestoreJobPrivate( this ), parent )
275 {
276  Q_D( TrashRestoreJob );
277  d->mItems << item;
278 }
279 
280 TrashRestoreJob::TrashRestoreJob( const Item::List& items, QObject* parent )
281  : Job( new TrashRestoreJobPrivate( this ), parent )
282 {
283  Q_D( TrashRestoreJob );
284  d->mItems = items;
285 }
286 
287 TrashRestoreJob::TrashRestoreJob( const Collection& collection, QObject* parent )
288  : Job( new TrashRestoreJobPrivate( this ), parent )
289 {
290  Q_D( TrashRestoreJob );
291  d->mCollection = collection;
292 }
293 
294 TrashRestoreJob::~TrashRestoreJob()
295 {
296 }
297 
298 void TrashRestoreJob::setTargetCollection( const Akonadi::Collection collection )
299 {
300  Q_D( TrashRestoreJob );
301  d->mTargetCollection = collection;
302 }
303 
304 Item::List TrashRestoreJob::items() const
305 {
306  Q_D( const TrashRestoreJob );
307  return d->mItems;
308 }
309 
310 void TrashRestoreJob::doStart()
311 {
312  Q_D( TrashRestoreJob );
313 
314  //We always have to fetch the entities to ensure that the EntityDeletedAttribute is available
315  if ( !d->mItems.isEmpty() ) {
316  ItemFetchJob *job = new ItemFetchJob( d->mItems, this );
317  job->fetchScope().setCacheOnly( true );
318  job->fetchScope().fetchAttribute<EntityDeletedAttribute> ( true );
319  connect( job, SIGNAL(itemsReceived(Akonadi::Item::List)), this, SLOT(itemsReceived(Akonadi::Item::List)) );
320  } else if ( d->mCollection.isValid() ) {
321  CollectionFetchJob *job = new CollectionFetchJob( d->mCollection, CollectionFetchJob::Base, this );
322  connect( job, SIGNAL(collectionsReceived(Akonadi::Collection::List)), this, SLOT(collectionsReceived(Akonadi::Collection::List)) );
323  } else {
324  kWarning() << "No valid collection or empty itemlist";
325  setError( Job::Unknown );
326  setErrorText( i18n( "No valid collection or empty itemlist" ) );
327  emitResult();
328  }
329 
330 }
331 
332 #include "moc_trashrestorejob.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::CollectionFetchJob::collections
Collection::List collections() const
Returns the list of fetched collection.
Definition: collectionfetchjob.cpp:175
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::FirstLevel
Only list direct sub-collections of the base collection.
Definition: collectionfetchjob.h:63
Akonadi::CollectionFetchJob::fetchScope
CollectionFetchScope & fetchScope()
Returns the collection fetch scope.
Definition: collectionfetchjob.cpp:437
Akonadi::TrashRestoreJob::setTargetCollection
void setTargetCollection(const Collection collection)
Sets the target collection, where the item is moved to.
Definition: trashrestorejob.cpp:298
Akonadi::CollectionFetchScope::setResource
void setResource(const QString &resource)
Sets a resource filter, that is only collections owned by the specified resource are retrieved...
Definition: collectionfetchscope.cpp:114
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::CollectionFetchJob::Base
Only fetch the base collection.
Definition: collectionfetchjob.h:62
Akonadi::Entity::attribute
Attribute * attribute(const QByteArray &name) const
Returns the attribute of the given type name if available, 0 otherwise.
Definition: entity.cpp:165
Akonadi::ItemFetchJob::fetchScope
ItemFetchScope & fetchScope()
Returns the item fetch scope.
Definition: itemfetchjob.cpp:256
Akonadi::TrashRestoreJob::doStart
virtual void doStart()
This method must be reimplemented in the concrete jobs.
Definition: trashrestorejob.cpp:310
Akonadi::Entity::removeAttribute
void removeAttribute(const QByteArray &name)
Removes and deletes the attribute of the given type name.
Definition: entity.cpp:140
Akonadi::Entity::parentCollection
Collection parentCollection() const
Returns the parent collection of this object.
Definition: entity.cpp:186
Akonadi::TrashRestoreJob::TrashRestoreJob
TrashRestoreJob(const Item &item, QObject *parent=0)
All items need to be from the same resource.
Definition: trashrestorejob.cpp:273
Akonadi::Collection::root
static Collection root()
Returns the root collection.
Definition: collection.cpp:192
Akonadi::TrashRestoreJob
Job that restores entites from trash.
Definition: trashrestorejob.h:56
Akonadi::Entity::id
Id id() const
Returns the unique identifier of the entity.
Definition: entity.cpp:72
Akonadi::EntityDeletedAttribute
An Attribute that marks that an entity was marked as deleted.
Definition: entitydeletedattribute.h:49
Akonadi::ItemMoveJob
Job that moves an item into a different collection in the Akonadi storage.
Definition: itemmovejob.h:48
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::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::ItemFetchScope::setCacheOnly
void setCacheOnly(bool cacheOnly)
Sets whether payload data should be requested from remote sources or just from the local cache...
Definition: itemfetchscope.cpp:106
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