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

akonadi

  • akonadi
resourcebase.cpp
1 /*
2  Copyright (c) 2006 Till Adam <adam@kde.org>
3  Copyright (c) 2007 Volker Krause <vkrause@kde.org>
4 
5  This library is free software; you can redistribute it and/or modify it
6  under the terms of the GNU Library General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or (at your
8  option) any later version.
9 
10  This library is distributed in the hope that it will be useful, but WITHOUT
11  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13  License for more details.
14 
15  You should have received a copy of the GNU Library General Public License
16  along with this library; see the file COPYING.LIB. If not, write to the
17  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18  02110-1301, USA.
19 */
20 
21 #include "resourcebase.h"
22 #include "agentbase_p.h"
23 
24 #include "resourceadaptor.h"
25 #include "collectiondeletejob.h"
26 #include "collectionsync_p.h"
27 #include "dbusconnectionpool.h"
28 #include "itemsync.h"
29 #include "kdepimlibs-version.h"
30 #include "resourcescheduler_p.h"
31 #include "tracerinterface.h"
32 #include "xdgbasedirs_p.h"
33 
34 #include "changerecorder.h"
35 #include "collectionfetchjob.h"
36 #include "collectionfetchscope.h"
37 #include "collectionmodifyjob.h"
38 #include "invalidatecachejob_p.h"
39 #include "itemfetchjob.h"
40 #include "itemfetchscope.h"
41 #include "itemmodifyjob.h"
42 #include "itemmodifyjob_p.h"
43 #include "session.h"
44 #include "resourceselectjob_p.h"
45 #include "monitor_p.h"
46 #include "servermanager_p.h"
47 #include "recursivemover_p.h"
48 
49 #include <kaboutdata.h>
50 #include <kcmdlineargs.h>
51 #include <kdebug.h>
52 #include <klocalizedstring.h>
53 #include <kglobal.h>
54 #include <akonadi/tagmodifyjob.h>
55 
56 #include <QtCore/QDebug>
57 #include <QtCore/QDir>
58 #include <QtCore/QHash>
59 #include <QtCore/QSettings>
60 #include <QtCore/QTimer>
61 #include <QApplication>
62 #include <QtDBus/QtDBus>
63 
64 using namespace Akonadi;
65 
66 class Akonadi::ResourceBasePrivate : public AgentBasePrivate
67 {
68  Q_OBJECT
69  Q_CLASSINFO("D-Bus Interface", "org.kde.dfaure")
70 
71 public:
72  ResourceBasePrivate(ResourceBase *parent)
73  : AgentBasePrivate(parent)
74  , scheduler(0)
75  , mItemSyncer(0)
76  , mItemSyncFetchScope(0)
77  , mItemTransactionMode(ItemSync::SingleTransaction)
78  , mCollectionSyncer(0)
79  , mHierarchicalRid(false)
80  , mUnemittedProgress(0)
81  , mAutomaticProgressReporting(true)
82  , mDisableAutomaticItemDeliveryDone(false)
83  , mItemSyncBatchSize(10)
84  , mCurrentCollectionFetchJob(0)
85  {
86  Internal::setClientType(Internal::Resource);
87  mStatusMessage = defaultReadyMessage();
88  mProgressEmissionCompressor.setInterval(1000);
89  mProgressEmissionCompressor.setSingleShot(true);
90  // HACK: skip local changes of the EntityDisplayAttribute by default. Remove this for KDE5 and adjust resource implementations accordingly.
91  mKeepLocalCollectionChanges << "ENTITYDISPLAY";
92  }
93 
94  ~ResourceBasePrivate()
95  {
96  delete mItemSyncFetchScope;
97  }
98 
99  Q_DECLARE_PUBLIC(ResourceBase)
100 
101  void delayedInit()
102  {
103  const QString serviceId = ServerManager::agentServiceName(ServerManager::Resource, mId);
104  if (!DBusConnectionPool::threadConnection().registerService(serviceId)) {
105  QString reason = DBusConnectionPool::threadConnection().lastError().message();
106  if (reason.isEmpty()) {
107  reason = QString::fromLatin1("this service is probably running already.");
108  }
109  kError() << "Unable to register service" << serviceId << "at D-Bus:" << reason;
110 
111  if (QThread::currentThread() == QCoreApplication::instance()->thread()) {
112  QCoreApplication::instance()->exit(1);
113  }
114 
115  } else {
116  AgentBasePrivate::delayedInit();
117  }
118  }
119 
120  virtual void changeProcessed()
121  {
122  if (m_recursiveMover) {
123  m_recursiveMover->changeProcessed();
124  QTimer::singleShot(0, m_recursiveMover, SLOT(replayNext()));
125  return;
126  }
127 
128  mChangeRecorder->changeProcessed();
129  if (!mChangeRecorder->isEmpty()) {
130  scheduler->scheduleChangeReplay();
131  }
132  scheduler->taskDone();
133  }
134 
135  void slotAbortRequested();
136 
137  void slotDeliveryDone(KJob *job);
138  void slotCollectionSyncDone(KJob *job);
139  void slotLocalListDone(KJob *job);
140  void slotSynchronizeCollection(const Collection &col);
141  void slotItemRetrievalCollectionFetchDone(KJob *job);
142  void slotCollectionListDone(KJob *job);
143  void slotSynchronizeCollectionAttributes(const Collection &col);
144  void slotCollectionListForAttributesDone(KJob *job);
145  void slotCollectionAttributesSyncDone(KJob *job);
146  void slotAttributeRetrievalCollectionFetchDone(KJob *job);
147 
148  void slotItemSyncDone(KJob *job);
149 
150  void slotPercent(KJob *job, unsigned long percent);
151  void slotDelayedEmitProgress();
152  void slotDeleteResourceCollection();
153  void slotDeleteResourceCollectionDone(KJob *job);
154  void slotCollectionDeletionDone(KJob *job);
155 
156  void slotInvalidateCache(const Akonadi::Collection &collection);
157 
158  void slotPrepareItemRetrieval(const Akonadi::Item &item);
159  void slotPrepareItemRetrievalResult(KJob *job);
160 
161  void changeCommittedResult(KJob *job);
162 
163  void slotRecursiveMoveReplay(RecursiveMover *mover);
164  void slotRecursiveMoveReplayResult(KJob *job);
165 
166  void slotSessionReconnected()
167  {
168  Q_Q(ResourceBase);
169 
170  new ResourceSelectJob(q->identifier());
171  }
172 
173  void createItemSyncInstanceIfMissing()
174  {
175  Q_Q(ResourceBase);
176  Q_ASSERT_X(scheduler->currentTask().type == ResourceScheduler::SyncCollection,
177  "createItemSyncInstance", "Calling items retrieval methods although no item retrieval is in progress");
178  if (!mItemSyncer) {
179  mItemSyncer = new ItemSync(q->currentCollection());
180  mItemSyncer->setTransactionMode(mItemTransactionMode);
181  mItemSyncer->setBatchSize(mItemSyncBatchSize);
182  if (mItemSyncFetchScope) {
183  mItemSyncer->setFetchScope(*mItemSyncFetchScope);
184  }
185  mItemSyncer->setDisableAutomaticDeliveryDone(mDisableAutomaticItemDeliveryDone);
186  mItemSyncer->setProperty("collection", QVariant::fromValue(q->currentCollection()));
187  connect(mItemSyncer, SIGNAL(percent(KJob*,ulong)), q, SLOT(slotPercent(KJob*,ulong)));
188  connect(mItemSyncer, SIGNAL(result(KJob*)), q, SLOT(slotItemSyncDone(KJob*)));
189  connect(mItemSyncer, SIGNAL(readyForNextBatch(int)), q, SIGNAL(retrieveNextItemSyncBatch(int)));
190  }
191  Q_ASSERT(mItemSyncer);
192  }
193 
194 public Q_SLOTS:
195  // Dump the state of the scheduler
196  Q_SCRIPTABLE QString dumpToString() const
197  {
198  Q_Q(const ResourceBase);
199  QString retVal;
200  QMetaObject::invokeMethod(const_cast<ResourceBase *>(q), "dumpResourceToString", Qt::DirectConnection, Q_RETURN_ARG(QString, retVal));
201  return scheduler->dumpToString() + QLatin1Char('\n') + retVal;
202  }
203 
204  Q_SCRIPTABLE void dump()
205  {
206  scheduler->dump();
207  }
208 
209  Q_SCRIPTABLE void clear()
210  {
211  scheduler->clear();
212  }
213 
214 protected Q_SLOTS:
215  // reimplementations from AgentbBasePrivate, containing sanity checks that only apply to resources
216  // such as making sure that RIDs are present as well as translations of cross-resource moves
217  // TODO: we could possibly add recovery code for no-RID notifications by re-enquing those to the change recorder
218  // as the corresponding Add notifications, although that contains a risk of endless fail/retry loops
219 
220  void itemAdded(const Akonadi::Item &item, const Akonadi::Collection &collection)
221  {
222  if (collection.remoteId().isEmpty()) {
223  changeProcessed();
224  return;
225  }
226  AgentBasePrivate::itemAdded(item, collection);
227  }
228 
229  void itemChanged(const Akonadi::Item &item, const QSet< QByteArray > &partIdentifiers)
230  {
231  if (item.remoteId().isEmpty()) {
232  changeProcessed();
233  return;
234  }
235  AgentBasePrivate::itemChanged(item, partIdentifiers);
236  }
237 
238  void itemsFlagsChanged(const Item::List &items, const QSet< QByteArray > &addedFlags,
239  const QSet< QByteArray > &removedFlags)
240  {
241  if (addedFlags.isEmpty() && removedFlags.isEmpty()) {
242  changeProcessed();
243  return;
244  }
245 
246  Item::List validItems;
247  foreach (const Akonadi::Item &item, items) {
248  if (!item.remoteId().isEmpty()) {
249  validItems << item;
250  }
251  }
252  if (validItems.isEmpty()) {
253  changeProcessed();
254  return;
255  }
256 
257  AgentBasePrivate::itemsFlagsChanged(validItems, addedFlags, removedFlags);
258  }
259 
260  void itemsTagsChanged(const Item::List &items, const QSet<Tag> &addedTags, const QSet<Tag> &removedTags)
261  {
262  if (addedTags.isEmpty() && removedTags.isEmpty()) {
263  changeProcessed();
264  return;
265  }
266 
267  Item::List validItems;
268  foreach (const Akonadi::Item &item, items) {
269  if (!item.remoteId().isEmpty()) {
270  validItems << item;
271  }
272  }
273  if (validItems.isEmpty()) {
274  changeProcessed();
275  return;
276  }
277 
278  AgentBasePrivate::itemsTagsChanged(validItems, addedTags, removedTags);
279  }
280 
281  // TODO move the move translation code from AgentBasePrivate here, it's wrong for agents
282  void itemMoved(const Akonadi::Item &item, const Akonadi::Collection &source, const Akonadi::Collection &destination)
283  {
284  if (item.remoteId().isEmpty() || destination.remoteId().isEmpty() || destination == source) {
285  changeProcessed();
286  return;
287  }
288  AgentBasePrivate::itemMoved(item, source, destination);
289  }
290 
291  void itemsMoved(const Item::List &items, const Collection &source, const Collection &destination)
292  {
293  if (destination.remoteId().isEmpty() || destination == source) {
294  changeProcessed();
295  return;
296  }
297 
298  Item::List validItems;
299  foreach (const Akonadi::Item &item, items) {
300  if (!item.remoteId().isEmpty()) {
301  validItems << item;
302  }
303  }
304  if (validItems.isEmpty()) {
305  changeProcessed();
306  return;
307  }
308 
309  AgentBasePrivate::itemsMoved(validItems, source, destination);
310  }
311 
312  void itemRemoved(const Akonadi::Item &item)
313  {
314  if (item.remoteId().isEmpty()) {
315  changeProcessed();
316  return;
317  }
318  if (!item.parentCollection().isValid()) {
319  kWarning() << "Invalid parent collection for item" << item.id();
320  changeProcessed();
321  return;
322  }
323  AgentBasePrivate::itemRemoved(item);
324  }
325 
326  void itemsRemoved(const Item::List &items)
327  {
328  Item::List validItems;
329  foreach (const Akonadi::Item &item, items) {
330  if (!item.parentCollection().isValid()) {
331  kWarning() << "Invalid parent collection for item" << item.id();
332  continue;
333  }
334  if (!item.remoteId().isEmpty()) {
335  validItems << item;
336  }
337  }
338  if (validItems.isEmpty()) {
339  changeProcessed();
340  return;
341  }
342 
343  AgentBasePrivate::itemsRemoved(validItems);
344  }
345 
346  void collectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent)
347  {
348  if (parent.remoteId().isEmpty()) {
349  changeProcessed();
350  return;
351  }
352  AgentBasePrivate::collectionAdded(collection, parent);
353  }
354 
355  void collectionChanged(const Akonadi::Collection &collection)
356  {
357  if (collection.remoteId().isEmpty()) {
358  changeProcessed();
359  return;
360  }
361  AgentBasePrivate::collectionChanged(collection);
362  }
363 
364  void collectionChanged(const Akonadi::Collection &collection, const QSet< QByteArray > &partIdentifiers)
365  {
366  if (collection.remoteId().isEmpty()) {
367  changeProcessed();
368  return;
369  }
370  AgentBasePrivate::collectionChanged(collection, partIdentifiers);
371  }
372 
373  void collectionMoved(const Akonadi::Collection &collection, const Akonadi::Collection &source, const Akonadi::Collection &destination)
374  {
375  // unknown destination or source == destination means we can't do/don't have to do anything
376  if (destination.remoteId().isEmpty() || source == destination) {
377  changeProcessed();
378  return;
379  }
380 
381  // inter-resource moves, requires we know which resources the source and destination are in though
382  if (!source.resource().isEmpty() && !destination.resource().isEmpty() && source.resource() != destination.resource()) {
383  if (source.resource() == q_ptr->identifier()) { // moved away from us
384  AgentBasePrivate::collectionRemoved(collection);
385  } else if (destination.resource() == q_ptr->identifier()) { // moved to us
386  scheduler->taskDone(); // stop change replay for now
387  RecursiveMover *mover = new RecursiveMover(this);
388  mover->setCollection(collection, destination);
389  scheduler->scheduleMoveReplay(collection, mover);
390  }
391  return;
392  }
393 
394  // intra-resource move, requires the moved collection to have a valid id though
395  if (collection.remoteId().isEmpty()) {
396  changeProcessed();
397  return;
398  }
399 
400  // intra-resource move, ie. something we can handle internally
401  AgentBasePrivate::collectionMoved(collection, source, destination);
402  }
403 
404  void collectionRemoved(const Akonadi::Collection &collection)
405  {
406  if (collection.remoteId().isEmpty()) {
407  changeProcessed();
408  return;
409  }
410  AgentBasePrivate::collectionRemoved(collection);
411  }
412 
413  void tagAdded(const Akonadi::Tag &tag)
414  {
415  if (!tag.isValid()) {
416  changeProcessed();
417  return;
418  }
419 
420  AgentBasePrivate::tagAdded(tag);
421  }
422 
423  void tagChanged(const Akonadi::Tag &tag)
424  {
425  if (tag.remoteId().isEmpty()) {
426  changeProcessed();
427  return;
428  }
429 
430  AgentBasePrivate::tagChanged(tag);
431  }
432 
433  void tagRemoved(const Akonadi::Tag &tag)
434  {
435  if (tag.remoteId().isEmpty()) {
436  changeProcessed();
437  return;
438  }
439 
440  AgentBasePrivate::tagRemoved(tag);
441  }
442 
443 public:
444  // synchronize states
445  Collection currentCollection;
446 
447  ResourceScheduler *scheduler;
448  ItemSync *mItemSyncer;
449  ItemFetchScope *mItemSyncFetchScope;
450  ItemSync::TransactionMode mItemTransactionMode;
451  CollectionSync *mCollectionSyncer;
452  bool mHierarchicalRid;
453  QTimer mProgressEmissionCompressor;
454  int mUnemittedProgress;
455  QMap<Akonadi::Collection::Id, QVariantMap> mUnemittedAdvancedStatus;
456  bool mAutomaticProgressReporting;
457  bool mDisableAutomaticItemDeliveryDone;
458  QPointer<RecursiveMover> m_recursiveMover;
459  int mItemSyncBatchSize;
460  QSet<QByteArray> mKeepLocalCollectionChanges;
461  KJob *mCurrentCollectionFetchJob;
462 };
463 
464 ResourceBase::ResourceBase(const QString &id)
465  : AgentBase(new ResourceBasePrivate(this), id)
466 {
467  Q_D(ResourceBase);
468 
469  new Akonadi__ResourceAdaptor(this);
470 
471  d->scheduler = new ResourceScheduler(this);
472 
473  d->mChangeRecorder->setChangeRecordingEnabled(true);
474  d->mChangeRecorder->setCollectionMoveTranslationEnabled(false); // we deal with this ourselves
475  connect(d->mChangeRecorder, SIGNAL(changesAdded()),
476  d->scheduler, SLOT(scheduleChangeReplay()));
477 
478  d->mChangeRecorder->setResourceMonitored(d->mId.toLatin1());
479  d->mChangeRecorder->fetchCollection(true);
480 
481  connect(d->scheduler, SIGNAL(executeFullSync()),
482  SLOT(retrieveCollections()));
483  connect(d->scheduler, SIGNAL(executeCollectionTreeSync()),
484  SLOT(retrieveCollections()));
485  connect(d->scheduler, SIGNAL(executeCollectionSync(Akonadi::Collection)),
486  SLOT(slotSynchronizeCollection(Akonadi::Collection)));
487  connect(d->scheduler, SIGNAL(executeCollectionAttributesSync(Akonadi::Collection)),
488  SLOT(slotSynchronizeCollectionAttributes(Akonadi::Collection)));
489  connect(d->scheduler, SIGNAL(executeItemFetch(Akonadi::Item,QSet<QByteArray>)),
490  SLOT(slotPrepareItemRetrieval(Akonadi::Item)));
491  connect(d->scheduler, SIGNAL(executeResourceCollectionDeletion()),
492  SLOT(slotDeleteResourceCollection()));
493  connect(d->scheduler, SIGNAL(executeCacheInvalidation(Akonadi::Collection)),
494  SLOT(slotInvalidateCache(Akonadi::Collection)));
495  connect(d->scheduler, SIGNAL(status(int,QString)),
496  SIGNAL(status(int,QString)));
497  connect(d->scheduler, SIGNAL(executeChangeReplay()),
498  d->mChangeRecorder, SLOT(replayNext()));
499  connect(d->scheduler, SIGNAL(executeRecursiveMoveReplay(RecursiveMover*)),
500  SLOT(slotRecursiveMoveReplay(RecursiveMover*)));
501  connect(d->scheduler, SIGNAL(fullSyncComplete()), SIGNAL(synchronized()));
502  connect(d->scheduler, SIGNAL(collectionTreeSyncComplete()), SIGNAL(collectionTreeSynchronized()));
503  connect(d->mChangeRecorder, SIGNAL(nothingToReplay()), d->scheduler, SLOT(taskDone()));
504  connect(d->mChangeRecorder, SIGNAL(collectionRemoved(Akonadi::Collection)),
505  d->scheduler, SLOT(collectionRemoved(Akonadi::Collection)));
506  connect(this, SIGNAL(abortRequested()), this, SLOT(slotAbortRequested()));
507  connect(this, SIGNAL(synchronized()), d->scheduler, SLOT(taskDone()));
508  connect(this, SIGNAL(collectionTreeSynchronized()), d->scheduler, SLOT(taskDone()));
509  connect(this, SIGNAL(agentNameChanged(QString)),
510  this, SIGNAL(nameChanged(QString)));
511 
512  connect(&d->mProgressEmissionCompressor, SIGNAL(timeout()),
513  this, SLOT(slotDelayedEmitProgress()));
514 
515  d->scheduler->setOnline(d->mOnline);
516  if (!d->mChangeRecorder->isEmpty()) {
517  d->scheduler->scheduleChangeReplay();
518  }
519 
520  new ResourceSelectJob(identifier());
521 
522  connect(d->mChangeRecorder->session(), SIGNAL(reconnected()), SLOT(slotSessionReconnected()));
523 }
524 
525 ResourceBase::~ResourceBase()
526 {
527 }
528 
529 void ResourceBase::synchronize()
530 {
531  d_func()->scheduler->scheduleFullSync();
532 }
533 
534 void ResourceBase::setName(const QString &name)
535 {
536  AgentBase::setAgentName(name);
537 }
538 
539 QString ResourceBase::name() const
540 {
541  return AgentBase::agentName();
542 }
543 
544 QString ResourceBase::parseArguments(int argc, char **argv)
545 {
546  QString identifier;
547  if (argc < 3) {
548  kDebug() << "Not enough arguments passed...";
549  exit(1);
550  }
551 
552  for (int i = 1; i < argc - 1; ++i) {
553  if (QLatin1String(argv[i]) == QLatin1String("--identifier")) {
554  identifier = QLatin1String(argv[i + 1]);
555  }
556  }
557 
558  if (identifier.isEmpty()) {
559  kDebug() << "Identifier argument missing";
560  exit(1);
561  }
562 
563  const QFileInfo fi(QString::fromLocal8Bit(argv[0]));
564  // strip off full path and possible .exe suffix
565  const QByteArray catalog = fi.baseName().toLatin1();
566 
567  KCmdLineArgs::init(argc, argv, ServerManager::addNamespace(identifier).toLatin1(), catalog,
568  ki18nc("@title application name", "Akonadi Resource"), KDEPIMLIBS_VERSION,
569  ki18nc("@title application description", "Akonadi Resource"));
570 
571  KCmdLineOptions options;
572  options.add("identifier <argument>",
573  ki18nc("@label commandline option", "Resource identifier"));
574  KCmdLineArgs::addCmdLineOptions(options);
575 
576  return identifier;
577 }
578 
579 int ResourceBase::init(ResourceBase *r)
580 {
581  QApplication::setQuitOnLastWindowClosed(false);
582  KGlobal::locale()->insertCatalog(QLatin1String("libakonadi"));
583  int rv = kapp->exec();
584  delete r;
585  return rv;
586 }
587 
588 void ResourceBasePrivate::slotAbortRequested()
589 {
590  Q_Q(ResourceBase);
591 
592  scheduler->cancelQueues();
593  QMetaObject::invokeMethod(q, "abortActivity");
594 }
595 
596 void ResourceBase::itemRetrieved(const Item &item)
597 {
598  Q_D(ResourceBase);
599  Q_ASSERT(d->scheduler->currentTask().type == ResourceScheduler::FetchItem);
600  if (!item.isValid()) {
601  d->scheduler->currentTask().sendDBusReplies(i18nc("@info", "Invalid item retrieved"));
602  d->scheduler->taskDone();
603  return;
604  }
605 
606  Item i(item);
607  QSet<QByteArray> requestedParts = d->scheduler->currentTask().itemParts;
608  foreach (const QByteArray &part, requestedParts) {
609  if (!item.loadedPayloadParts().contains(part)) {
610  kWarning() << "Item does not provide part" << part;
611  }
612  }
613 
614  ItemModifyJob *job = new ItemModifyJob(i);
615  job->d_func()->setSilent( true );
616  // FIXME: remove once the item with which we call retrieveItem() has a revision number
617  job->disableRevisionCheck();
618  connect(job, SIGNAL(result(KJob*)), SLOT(slotDeliveryDone(KJob*)));
619 }
620 
621 void ResourceBasePrivate::slotDeliveryDone(KJob *job)
622 {
623  Q_Q(ResourceBase);
624  Q_ASSERT(scheduler->currentTask().type == ResourceScheduler::FetchItem);
625  if (job->error()) {
626  emit q->error(i18nc("@info", "Error while creating item: %1", job->errorString()));
627  }
628  scheduler->currentTask().sendDBusReplies(job->error() ? job->errorString() : QString());
629  scheduler->taskDone();
630 }
631 
632 void ResourceBase::collectionAttributesRetrieved(const Collection &collection)
633 {
634  Q_D(ResourceBase);
635  Q_ASSERT(d->scheduler->currentTask().type == ResourceScheduler::SyncCollectionAttributes);
636  if (!collection.isValid()) {
637  emit attributesSynchronized(d->scheduler->currentTask().collection.id());
638  d->scheduler->taskDone();
639  return;
640  }
641 
642  CollectionModifyJob *job = new CollectionModifyJob(collection);
643  connect(job, SIGNAL(result(KJob*)), SLOT(slotCollectionAttributesSyncDone(KJob*)));
644 }
645 
646 void ResourceBasePrivate::slotCollectionAttributesSyncDone(KJob *job)
647 {
648  Q_Q(ResourceBase);
649  Q_ASSERT(scheduler->currentTask().type == ResourceScheduler::SyncCollectionAttributes);
650  if (job->error()) {
651  emit q->error(i18nc("@info", "Error while updating collection: %1", job->errorString()));
652  }
653  emit q->attributesSynchronized(scheduler->currentTask().collection.id());
654  scheduler->taskDone();
655 }
656 
657 void ResourceBasePrivate::slotDeleteResourceCollection()
658 {
659  Q_Q(ResourceBase);
660 
661  CollectionFetchJob *job = new CollectionFetchJob(Collection::root(), CollectionFetchJob::FirstLevel);
662  job->fetchScope().setResource(q->identifier());
663  connect(job, SIGNAL(result(KJob*)), q, SLOT(slotDeleteResourceCollectionDone(KJob*)));
664 }
665 
666 void ResourceBasePrivate::slotDeleteResourceCollectionDone(KJob *job)
667 {
668  Q_Q(ResourceBase);
669  if (job->error()) {
670  emit q->error(job->errorString());
671  scheduler->taskDone();
672  } else {
673  const CollectionFetchJob *fetchJob = static_cast<const CollectionFetchJob *>(job);
674 
675  if (!fetchJob->collections().isEmpty()) {
676  CollectionDeleteJob *job = new CollectionDeleteJob(fetchJob->collections().first());
677  connect(job, SIGNAL(result(KJob*)), q, SLOT(slotCollectionDeletionDone(KJob*)));
678  } else {
679  // there is no resource collection, so just ignore the request
680  scheduler->taskDone();
681  }
682  }
683 }
684 
685 void ResourceBasePrivate::slotCollectionDeletionDone(KJob *job)
686 {
687  Q_Q(ResourceBase);
688  if (job->error()) {
689  emit q->error(job->errorString());
690  }
691 
692  scheduler->taskDone();
693 }
694 
695 void ResourceBasePrivate::slotInvalidateCache(const Akonadi::Collection &collection)
696 {
697  Q_Q(ResourceBase);
698  InvalidateCacheJob *job = new InvalidateCacheJob(collection, q);
699  connect(job, SIGNAL(result(KJob*)), scheduler, SLOT(taskDone()));
700 }
701 
702 void ResourceBase::changeCommitted(const Item &item)
703 {
704  changesCommitted(Item::List() << item);
705 }
706 
707 void ResourceBase::changesCommitted(const Item::List &items)
708 {
709  TransactionSequence *transaction = new TransactionSequence(this);
710  connect(transaction, SIGNAL(finished(KJob*)),
711  this, SLOT(changeCommittedResult(KJob*)));
712 
713  // Modify the items one-by-one, because STORE does not support mass RID change
714  Q_FOREACH (const Item &item, items) {
715  ItemModifyJob *job = new ItemModifyJob(item, transaction);
716  job->d_func()->setClean();
717  job->disableRevisionCheck(); // TODO: remove, but where/how do we handle the error?
718  job->setIgnorePayload(true); // we only want to reset the dirty flag and update the remote id
719  job->setUpdateGid(true); // allow resources to update GID too
720  }
721 }
722 
723 void ResourceBase::changeCommitted(const Collection &collection)
724 {
725  CollectionModifyJob *job = new CollectionModifyJob(collection);
726  connect(job, SIGNAL(result(KJob*)), SLOT(changeCommittedResult(KJob*)));
727 }
728 
729 void ResourceBasePrivate::changeCommittedResult(KJob *job)
730 {
731  if (job->error()) {
732  kWarning() << job->errorText();
733  }
734 
735  Q_Q(ResourceBase);
736  if (qobject_cast<CollectionModifyJob *>(job)) {
737  if (job->error()) {
738  emit q->error(i18nc("@info", "Updating local collection failed: %1.", job->errorText()));
739  }
740  mChangeRecorder->d_ptr->invalidateCache(static_cast<CollectionModifyJob *>(job)->collection());
741  } else {
742  // Item and tag cache is invalidated by modify job
743  }
744 
745  changeProcessed();
746 }
747 
748 void ResourceBase::changeCommitted(const Tag &tag)
749 {
750  TagModifyJob *job = new TagModifyJob(tag);
751  connect(job, SIGNAL(result(KJob*)), SLOT(changeCommittedResult(KJob*)));
752 }
753 
754 bool ResourceBase::requestItemDelivery(qint64 uid, const QString &remoteId,
755  const QString &mimeType, const QStringList &parts)
756 {
757  return requestItemDeliveryV2(uid, remoteId, mimeType, parts).isEmpty();
758 }
759 
760 QString ResourceBase::requestItemDeliveryV2(qint64 uid, const QString &remoteId, const QString &mimeType, const QStringList &_parts)
761 {
762  Q_D(ResourceBase);
763  if (!isOnline()) {
764  const QString errorMsg = i18nc("@info", "Cannot fetch item in offline mode.");
765  emit error(errorMsg);
766  return errorMsg;
767  }
768 
769  setDelayedReply(true);
770  // FIXME: we need at least the revision number too
771  Item item(uid);
772  item.setMimeType(mimeType);
773  item.setRemoteId(remoteId);
774 
775  QSet<QByteArray> parts;
776  Q_FOREACH (const QString &str, _parts) {
777  parts.insert(str.toLatin1());
778  }
779 
780  d->scheduler->scheduleItemFetch(item, parts, message());
781 
782  return QString();
783 
784 }
785 
786 void ResourceBase::collectionsRetrieved(const Collection::List &collections)
787 {
788  Q_D(ResourceBase);
789  Q_ASSERT_X(d->scheduler->currentTask().type == ResourceScheduler::SyncCollectionTree ||
790  d->scheduler->currentTask().type == ResourceScheduler::SyncAll,
791  "ResourceBase::collectionsRetrieved()",
792  "Calling collectionsRetrieved() although no collection retrieval is in progress");
793  if (!d->mCollectionSyncer) {
794  d->mCollectionSyncer = new CollectionSync(identifier());
795  d->mCollectionSyncer->setHierarchicalRemoteIds(d->mHierarchicalRid);
796  d->mCollectionSyncer->setKeepLocalChanges(d->mKeepLocalCollectionChanges);
797  connect(d->mCollectionSyncer, SIGNAL(percent(KJob*,ulong)), SLOT(slotPercent(KJob*,ulong)));
798  connect(d->mCollectionSyncer, SIGNAL(result(KJob*)), SLOT(slotCollectionSyncDone(KJob*)));
799  }
800  d->mCollectionSyncer->setRemoteCollections(collections);
801 }
802 
803 void ResourceBase::collectionsRetrievedIncremental(const Collection::List &changedCollections,
804  const Collection::List &removedCollections)
805 {
806  Q_D(ResourceBase);
807  Q_ASSERT_X(d->scheduler->currentTask().type == ResourceScheduler::SyncCollectionTree ||
808  d->scheduler->currentTask().type == ResourceScheduler::SyncAll,
809  "ResourceBase::collectionsRetrievedIncremental()",
810  "Calling collectionsRetrievedIncremental() although no collection retrieval is in progress");
811  if (!d->mCollectionSyncer) {
812  d->mCollectionSyncer = new CollectionSync(identifier());
813  d->mCollectionSyncer->setHierarchicalRemoteIds(d->mHierarchicalRid);
814  d->mCollectionSyncer->setKeepLocalChanges(d->mKeepLocalCollectionChanges);
815  connect(d->mCollectionSyncer, SIGNAL(percent(KJob*,ulong)), SLOT(slotPercent(KJob*,ulong)));
816  connect(d->mCollectionSyncer, SIGNAL(result(KJob*)), SLOT(slotCollectionSyncDone(KJob*)));
817  }
818  d->mCollectionSyncer->setRemoteCollections(changedCollections, removedCollections);
819 }
820 
821 void ResourceBase::setCollectionStreamingEnabled(bool enable)
822 {
823  Q_D(ResourceBase);
824  Q_ASSERT_X(d->scheduler->currentTask().type == ResourceScheduler::SyncCollectionTree ||
825  d->scheduler->currentTask().type == ResourceScheduler::SyncAll,
826  "ResourceBase::setCollectionStreamingEnabled()",
827  "Calling setCollectionStreamingEnabled() although no collection retrieval is in progress");
828  if (!d->mCollectionSyncer) {
829  d->mCollectionSyncer = new CollectionSync(identifier());
830  d->mCollectionSyncer->setHierarchicalRemoteIds(d->mHierarchicalRid);
831  connect(d->mCollectionSyncer, SIGNAL(percent(KJob*,ulong)), SLOT(slotPercent(KJob*,ulong)));
832  connect(d->mCollectionSyncer, SIGNAL(result(KJob*)), SLOT(slotCollectionSyncDone(KJob*)));
833  }
834  d->mCollectionSyncer->setStreamingEnabled(enable);
835 }
836 
837 void ResourceBase::collectionsRetrievalDone()
838 {
839  Q_D(ResourceBase);
840  Q_ASSERT_X(d->scheduler->currentTask().type == ResourceScheduler::SyncCollectionTree ||
841  d->scheduler->currentTask().type == ResourceScheduler::SyncAll,
842  "ResourceBase::collectionsRetrievalDone()",
843  "Calling collectionsRetrievalDone() although no collection retrieval is in progress");
844  // streaming enabled, so finalize the sync
845  if (d->mCollectionSyncer) {
846  d->mCollectionSyncer->retrievalDone();
847  } else {
848  // user did the sync himself, we are done now
849  // FIXME: we need the same special case for SyncAll as in slotCollectionSyncDone here!
850  d->scheduler->taskDone();
851  }
852 }
853 
854 void ResourceBase::setKeepLocalCollectionChanges(const QSet<QByteArray> &parts)
855 {
856  Q_D(ResourceBase);
857  d->mKeepLocalCollectionChanges = parts;
858 }
859 
860 void ResourceBasePrivate::slotCollectionSyncDone(KJob *job)
861 {
862  Q_Q(ResourceBase);
863  mCollectionSyncer = 0;
864  if (job->error()) {
865  if (job->error() != Job::UserCanceled) {
866  emit q->error(job->errorString());
867  }
868  } else {
869  if (scheduler->currentTask().type == ResourceScheduler::SyncAll) {
870  CollectionFetchJob *list = new CollectionFetchJob(Collection::root(), CollectionFetchJob::Recursive);
871  list->setFetchScope(q->changeRecorder()->collectionFetchScope());
872  list->fetchScope().setResource(mId);
873  list->fetchScope().setListFilter(CollectionFetchScope::Sync);
874  q->connect(list, SIGNAL(result(KJob*)), q, SLOT(slotLocalListDone(KJob*)));
875  return;
876  } else if (scheduler->currentTask().type == ResourceScheduler::SyncCollectionTree) {
877  scheduler->scheduleCollectionTreeSyncCompletion();
878  }
879  }
880  scheduler->taskDone();
881 }
882 
883 void ResourceBasePrivate::slotLocalListDone(KJob *job)
884 {
885  Q_Q(ResourceBase);
886  if (job->error()) {
887  emit q->error(job->errorString());
888  } else {
889  Collection::List cols = static_cast<CollectionFetchJob *>(job)->collections();
890  foreach (const Collection &col, cols) {
891  scheduler->scheduleSync(col);
892  }
893  scheduler->scheduleFullSyncCompletion();
894  }
895  scheduler->taskDone();
896 }
897 
898 void ResourceBasePrivate::slotSynchronizeCollection(const Collection &col)
899 {
900  Q_Q(ResourceBase);
901  currentCollection = col;
902  // This can happen due to FetchHelper::triggerOnDemandFetch() in the akonadi server (not an error).
903  if (!col.remoteId().isEmpty()) {
904  // check if this collection actually can contain anything
905  QStringList contentTypes = currentCollection.contentMimeTypes();
906  contentTypes.removeAll(Collection::mimeType());
907  contentTypes.removeAll(Collection::virtualMimeType());
908  if (!contentTypes.isEmpty() || col.isVirtual()) {
909  if (mAutomaticProgressReporting) {
910  emit q->status(AgentBase::Running, i18nc("@info:status", "Syncing folder '%1'", currentCollection.displayName()));
911  }
912 
913  Akonadi::CollectionFetchJob *fetchJob = new Akonadi::CollectionFetchJob(col, CollectionFetchJob::Base, this);
914  fetchJob->setFetchScope(q->changeRecorder()->collectionFetchScope());
915  connect(fetchJob, SIGNAL(result(KJob*)), q, SLOT(slotItemRetrievalCollectionFetchDone(KJob*)));
916  mCurrentCollectionFetchJob = fetchJob;
917  return;
918  }
919  }
920  scheduler->taskDone();
921 }
922 
923 void ResourceBasePrivate::slotItemRetrievalCollectionFetchDone(KJob *job)
924 {
925  Q_Q(ResourceBase);
926  mCurrentCollectionFetchJob = 0;
927  if (job->error()) {
928  kWarning() << "Failed to retrieve collection for sync: " << job->errorString();
929  q->cancelTask(i18n("Failed to retrieve collection for sync."));
930  return;
931  }
932  Akonadi::CollectionFetchJob *fetchJob = static_cast<Akonadi::CollectionFetchJob*>(job);
933  q->retrieveItems(fetchJob->collections().first());
934 }
935 
936 int ResourceBase::itemSyncBatchSize() const
937 {
938  Q_D(const ResourceBase);
939  return d->mItemSyncBatchSize;
940 }
941 
942 void ResourceBase::setItemSyncBatchSize(int batchSize)
943 {
944  Q_D(ResourceBase);
945  d->mItemSyncBatchSize = batchSize;
946 }
947 
948 void ResourceBasePrivate::slotSynchronizeCollectionAttributes(const Collection &col)
949 {
950  Q_Q(ResourceBase);
951  Akonadi::CollectionFetchJob *fetchJob = new Akonadi::CollectionFetchJob(col, CollectionFetchJob::Base, this);
952  fetchJob->setFetchScope(q->changeRecorder()->collectionFetchScope());
953  connect(fetchJob, SIGNAL(result(KJob*)), q, SLOT(slotAttributeRetrievalCollectionFetchDone(KJob*)));
954  Q_ASSERT(!mCurrentCollectionFetchJob);
955  mCurrentCollectionFetchJob = fetchJob;
956 }
957 
958 void ResourceBasePrivate::slotAttributeRetrievalCollectionFetchDone(KJob *job)
959 {
960  mCurrentCollectionFetchJob = 0;
961  Q_Q(ResourceBase);
962  if (job->error()) {
963  kWarning() << "Failed to retrieve collection for attribute sync: " << job->errorString();
964  q->cancelTask(i18n("Failed to retrieve collection for attribute sync."));
965  return;
966  }
967  Akonadi::CollectionFetchJob *fetchJob = static_cast<Akonadi::CollectionFetchJob*>(job);
968  QMetaObject::invokeMethod(q, "retrieveCollectionAttributes", Q_ARG(Akonadi::Collection, fetchJob->collections().first()));
969 }
970 
971 void ResourceBasePrivate::slotPrepareItemRetrieval(const Akonadi::Item &item)
972 {
973  Q_Q(ResourceBase);
974  ItemFetchJob *fetch = new ItemFetchJob(item, this);
975  fetch->fetchScope().setAncestorRetrieval(q->changeRecorder()->itemFetchScope().ancestorRetrieval());
976  fetch->fetchScope().setCacheOnly(true);
977 
978  // copy list of attributes to fetch
979  const QSet<QByteArray> attributes = q->changeRecorder()->itemFetchScope().attributes();
980  foreach (const QByteArray &attribute, attributes) {
981  fetch->fetchScope().fetchAttribute(attribute);
982  }
983 
984  q->connect(fetch, SIGNAL(result(KJob*)), SLOT(slotPrepareItemRetrievalResult(KJob*)));
985 }
986 
987 void ResourceBasePrivate::slotPrepareItemRetrievalResult(KJob *job)
988 {
989  Q_Q(ResourceBase);
990  Q_ASSERT_X(scheduler->currentTask().type == ResourceScheduler::FetchItem,
991  "ResourceBasePrivate::slotPrepareItemRetrievalResult()",
992  "Preparing item retrieval although no item retrieval is in progress");
993  if (job->error()) {
994  q->cancelTask(job->errorText());
995  return;
996  }
997  ItemFetchJob *fetch = qobject_cast<ItemFetchJob *>(job);
998  if (fetch->items().count() != 1) {
999  q->cancelTask(i18n("The requested item no longer exists"));
1000  return;
1001  }
1002  const Item item = fetch->items().first();
1003  const QSet<QByteArray> parts = scheduler->currentTask().itemParts;
1004  if (!q->retrieveItem(item, parts)) {
1005  q->cancelTask();
1006  }
1007 }
1008 
1009 void ResourceBasePrivate::slotRecursiveMoveReplay(RecursiveMover *mover)
1010 {
1011  Q_Q(ResourceBase);
1012  Q_ASSERT(mover);
1013  Q_ASSERT(!m_recursiveMover);
1014  m_recursiveMover = mover;
1015  connect(mover, SIGNAL(result(KJob*)), q, SLOT(slotRecursiveMoveReplayResult(KJob*)));
1016  mover->start();
1017 }
1018 
1019 void ResourceBasePrivate::slotRecursiveMoveReplayResult(KJob *job)
1020 {
1021  Q_Q(ResourceBase);
1022  m_recursiveMover = 0;
1023 
1024  if (job->error()) {
1025  q->deferTask();
1026  return;
1027  }
1028 
1029  changeProcessed();
1030 }
1031 
1032 void ResourceBase::itemsRetrievalDone()
1033 {
1034  Q_D(ResourceBase);
1035  // streaming enabled, so finalize the sync
1036  if (d->mItemSyncer) {
1037  d->mItemSyncer->deliveryDone();
1038  } else {
1039  // user did the sync himself, we are done now
1040  d->scheduler->taskDone();
1041  }
1042 }
1043 
1044 void ResourceBase::clearCache()
1045 {
1046  Q_D(ResourceBase);
1047  d->scheduler->scheduleResourceCollectionDeletion();
1048 }
1049 
1050 void ResourceBase::invalidateCache(const Collection &collection)
1051 {
1052  Q_D(ResourceBase);
1053  d->scheduler->scheduleCacheInvalidation(collection);
1054 }
1055 
1056 Collection ResourceBase::currentCollection() const
1057 {
1058  Q_D(const ResourceBase);
1059  Q_ASSERT_X(d->scheduler->currentTask().type == ResourceScheduler::SyncCollection ,
1060  "ResourceBase::currentCollection()",
1061  "Trying to access current collection although no item retrieval is in progress");
1062  return d->currentCollection;
1063 }
1064 
1065 Item ResourceBase::currentItem() const
1066 {
1067  Q_D(const ResourceBase);
1068  Q_ASSERT_X(d->scheduler->currentTask().type == ResourceScheduler::FetchItem ,
1069  "ResourceBase::currentItem()",
1070  "Trying to access current item although no item retrieval is in progress");
1071  return d->scheduler->currentTask().item;
1072 }
1073 
1074 void ResourceBase::synchronizeCollectionTree()
1075 {
1076  d_func()->scheduler->scheduleCollectionTreeSync();
1077 }
1078 
1079 void ResourceBase::cancelTask()
1080 {
1081  Q_D(ResourceBase);
1082  if (d->mCurrentCollectionFetchJob) {
1083  d->mCurrentCollectionFetchJob->kill();
1084  d->mCurrentCollectionFetchJob = 0;
1085  }
1086  switch (d->scheduler->currentTask().type) {
1087  case ResourceScheduler::FetchItem:
1088  itemRetrieved(Item()); // sends the error reply and
1089  break;
1090  case ResourceScheduler::ChangeReplay:
1091  d->changeProcessed();
1092  break;
1093  case ResourceScheduler::SyncCollectionTree:
1094  case ResourceScheduler::SyncAll:
1095  if (d->mCollectionSyncer) {
1096  d->mCollectionSyncer->rollback();
1097  } else {
1098  d->scheduler->taskDone();
1099  }
1100  break;
1101  case ResourceScheduler::SyncCollection:
1102  if (d->mItemSyncer) {
1103  d->mItemSyncer->rollback();
1104  } else {
1105  d->scheduler->taskDone();
1106  }
1107  break;
1108  default:
1109  d->scheduler->taskDone();
1110  }
1111 }
1112 
1113 void ResourceBase::cancelTask(const QString &msg)
1114 {
1115  cancelTask();
1116 
1117  emit error(msg);
1118 }
1119 
1120 void ResourceBase::deferTask()
1121 {
1122  Q_D(ResourceBase);
1123  d->scheduler->deferTask();
1124 }
1125 
1126 void ResourceBase::doSetOnline(bool state)
1127 {
1128  d_func()->scheduler->setOnline(state);
1129 }
1130 
1131 void ResourceBase::synchronizeCollection(qint64 collectionId)
1132 {
1133  synchronizeCollection(collectionId, false);
1134 }
1135 
1136 void ResourceBase::synchronizeCollection(qint64 collectionId, bool recursive)
1137 {
1138  CollectionFetchJob *job = new CollectionFetchJob(Collection(collectionId), recursive ? CollectionFetchJob::Recursive : CollectionFetchJob::Base);
1139  job->setFetchScope(changeRecorder()->collectionFetchScope());
1140  job->fetchScope().setResource(identifier());
1141  job->fetchScope().setListFilter(CollectionFetchScope::Sync);
1142  connect(job, SIGNAL(result(KJob*)), SLOT(slotCollectionListDone(KJob*)));
1143 }
1144 
1145 void ResourceBasePrivate::slotCollectionListDone(KJob *job)
1146 {
1147  if (!job->error()) {
1148  const Collection::List list = static_cast<CollectionFetchJob *>(job)->collections();
1149  Q_FOREACH (const Collection &collection, list) {
1150  //We also get collections that should not be synced but are part of the tree.
1151  if (collection.shouldList(Collection::ListSync)) {
1152  // Schedule attribute sync before each collection sync
1153  scheduler->scheduleAttributesSync(collection);
1154  scheduler->scheduleSync(collection);
1155  }
1156  }
1157  } else {
1158  kWarning() << "Failed to fetch collection for collection sync: " << job->errorString();
1159  }
1160 }
1161 
1162 void ResourceBase::synchronizeCollectionAttributes(qint64 collectionId)
1163 {
1164  CollectionFetchJob *job = new CollectionFetchJob(Collection(collectionId), CollectionFetchJob::Base);
1165  job->setFetchScope(changeRecorder()->collectionFetchScope());
1166  job->fetchScope().setResource(identifier());
1167  connect(job, SIGNAL(result(KJob*)), SLOT(slotCollectionListForAttributesDone(KJob*)));
1168 }
1169 
1170 void ResourceBasePrivate::slotCollectionListForAttributesDone(KJob *job)
1171 {
1172  if (!job->error()) {
1173  Collection::List list = static_cast<CollectionFetchJob *>(job)->collections();
1174  if (!list.isEmpty()) {
1175  Collection col = list.first();
1176  scheduler->scheduleAttributesSync(col);
1177  }
1178  }
1179  // TODO: error handling
1180 }
1181 
1182 void ResourceBase::setTotalItems(int amount)
1183 {
1184  kDebug() << amount;
1185  Q_D(ResourceBase);
1186  setItemStreamingEnabled(true);
1187  if (d->mItemSyncer) {
1188  d->mItemSyncer->setTotalItems(amount);
1189  }
1190 }
1191 
1192 void ResourceBase::setDisableAutomaticItemDeliveryDone(bool disable)
1193 {
1194  Q_D(ResourceBase);
1195  d->mDisableAutomaticItemDeliveryDone = disable;
1196 }
1197 
1198 void ResourceBase::setItemStreamingEnabled(bool enable)
1199 {
1200  Q_D(ResourceBase);
1201  d->createItemSyncInstanceIfMissing();
1202  if (d->mItemSyncer) {
1203  d->mItemSyncer->setStreamingEnabled(enable);
1204  }
1205 }
1206 
1207 void ResourceBase::itemsRetrieved(const Item::List &items)
1208 {
1209  Q_D(ResourceBase);
1210  d->createItemSyncInstanceIfMissing();
1211  if (d->mItemSyncer) {
1212  d->mItemSyncer->setFullSyncItems(items);
1213  }
1214 }
1215 
1216 void ResourceBase::itemsRetrievedIncremental(const Item::List &changedItems,
1217  const Item::List &removedItems)
1218 {
1219  Q_D(ResourceBase);
1220  d->createItemSyncInstanceIfMissing();
1221  if (d->mItemSyncer) {
1222  d->mItemSyncer->setIncrementalSyncItems(changedItems, removedItems);
1223  }
1224 }
1225 
1226 void ResourceBasePrivate::slotItemSyncDone(KJob *job)
1227 {
1228  mItemSyncer = 0;
1229  Q_Q(ResourceBase);
1230  if (job->error() && job->error() != Job::UserCanceled) {
1231  emit q->error(job->errorString());
1232  }
1233  scheduler->taskDone();
1234 }
1235 
1236 void ResourceBasePrivate::slotDelayedEmitProgress()
1237 {
1238  Q_Q(ResourceBase);
1239  if (mAutomaticProgressReporting) {
1240  emit q->percent(mUnemittedProgress);
1241 
1242  Q_FOREACH (const QVariantMap &statusMap, mUnemittedAdvancedStatus) {
1243  emit q->advancedStatus(statusMap);
1244  }
1245  }
1246  mUnemittedProgress = 0;
1247  mUnemittedAdvancedStatus.clear();
1248 }
1249 
1250 void ResourceBasePrivate::slotPercent(KJob *job, unsigned long percent)
1251 {
1252  mUnemittedProgress = percent;
1253 
1254  const Collection collection = job->property("collection").value<Collection>();
1255  if (collection.isValid()) {
1256  QVariantMap statusMap;
1257  statusMap.insert(QLatin1String("key"), QString::fromLatin1("collectionSyncProgress"));
1258  statusMap.insert(QLatin1String("collectionId"), collection.id());
1259  statusMap.insert(QLatin1String("percent"), static_cast<unsigned int>(percent));
1260 
1261  mUnemittedAdvancedStatus[collection.id()] = statusMap;
1262  }
1263  // deliver completion right away, intermediate progress at 1s intervals
1264  if (percent == 100) {
1265  mProgressEmissionCompressor.stop();
1266  slotDelayedEmitProgress();
1267  } else if (!mProgressEmissionCompressor.isActive()) {
1268  mProgressEmissionCompressor.start();
1269  }
1270 }
1271 
1272 void ResourceBase::setHierarchicalRemoteIdentifiersEnabled(bool enable)
1273 {
1274  Q_D(ResourceBase);
1275  d->mHierarchicalRid = enable;
1276 }
1277 
1278 void ResourceBase::scheduleCustomTask(QObject *receiver, const char *method, const QVariant &argument, SchedulePriority priority)
1279 {
1280  Q_D(ResourceBase);
1281  d->scheduler->scheduleCustomTask(receiver, method, argument, priority);
1282 }
1283 
1284 void ResourceBase::taskDone()
1285 {
1286  Q_D(ResourceBase);
1287  d->scheduler->taskDone();
1288 }
1289 
1290 void ResourceBase::retrieveCollectionAttributes(const Collection &collection)
1291 {
1292  collectionAttributesRetrieved(collection);
1293 }
1294 
1295 void Akonadi::ResourceBase::abortActivity()
1296 {
1297 }
1298 
1299 void ResourceBase::setItemTransactionMode(ItemSync::TransactionMode mode)
1300 {
1301  Q_D(ResourceBase);
1302  d->mItemTransactionMode = mode;
1303 }
1304 
1305 void ResourceBase::setItemSynchronizationFetchScope(const ItemFetchScope &fetchScope)
1306 {
1307  Q_D(ResourceBase);
1308  if (!d->mItemSyncFetchScope) {
1309  d->mItemSyncFetchScope = new ItemFetchScope;
1310  }
1311  *(d->mItemSyncFetchScope) = fetchScope;
1312 }
1313 
1314 void ResourceBase::setAutomaticProgressReporting(bool enabled)
1315 {
1316  Q_D(ResourceBase);
1317  d->mAutomaticProgressReporting = enabled;
1318 }
1319 
1320 QString ResourceBase::dumpNotificationListToString() const
1321 {
1322  Q_D(const ResourceBase);
1323  return d->dumpNotificationListToString();
1324 }
1325 
1326 QString ResourceBase::dumpSchedulerToString() const
1327 {
1328  Q_D(const ResourceBase);
1329  return d->dumpToString();
1330 }
1331 
1332 void ResourceBase::dumpMemoryInfo() const
1333 {
1334  Q_D(const ResourceBase);
1335  return d->dumpMemoryInfo();
1336 }
1337 
1338 QString ResourceBase::dumpMemoryInfoToString() const
1339 {
1340  Q_D(const ResourceBase);
1341  return d->dumpMemoryInfoToString();
1342 }
1343 
1344 #include "resourcebase.moc"
1345 #include "moc_resourcebase.cpp"
Akonadi::CollectionModifyJob
Job that modifies a collection in the Akonadi storage.
Definition: collectionmodifyjob.h:82
Akonadi::RecursiveMover
Helper class for expanding inter-resource collection moves inside ResourceBase.
Definition: recursivemover_p.h:37
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::ResourceBase::retrieveCollectionAttributes
void retrieveCollectionAttributes(const Akonadi::Collection &collection)
Retrieve the attributes of a single collection from the backend.
Definition: resourcebase.cpp:1290
Akonadi::ResourceBase::abortActivity
void abortActivity()
Abort any activity in progress in the backend.
Definition: resourcebase.cpp:1295
Akonadi::ItemModifyJob::disableRevisionCheck
void disableRevisionCheck()
Disables the check of the revision number.
Definition: itemmodifyjob.cpp:451
Akonadi::AgentBase::percent
void percent(int progress)
This signal should be emitted whenever the progress of an action in the agent (e.g.
Akonadi::ResourceBase::retrieveCollections
virtual void retrieveCollections()=0
Retrieve the collection tree from the remote server and supply it via collectionsRetrieved() or colle...
Akonadi::CollectionFetchJob::collections
Collection::List collections() const
Returns the list of fetched collection.
Definition: collectionfetchjob.cpp:169
Akonadi::AgentBase::abortRequested
void abortRequested()
Emitted when another application has remotely asked the agent to abort its current operation...
Akonadi::ResourceBase::dumpNotificationListToString
QString dumpNotificationListToString() const
Dump the contents of the current ChangeReplay.
Definition: resourcebase.cpp:1320
Akonadi::ResourceBase::attributesSynchronized
void attributesSynchronized(qlonglong collectionId)
Emitted when a collection attributes synchronization has been completed.
Akonadi::ItemModifyJob::setUpdateGid
void setUpdateGid(bool update)
Sets whether the GID shall be updated either from the gid parameter or by extracting it from the payl...
Definition: itemmodifyjob.cpp:435
Akonadi::Collection::shouldList
bool shouldList(ListPurpose purpose) const
Returns whether the collection should be listed or not for the specified purpose Takes enabled state ...
Definition: collection.cpp:321
Akonadi::ResourceBase::collectionsRetrievalDone
void collectionsRetrievalDone()
Call this method to indicate you finished synchronizing the collection tree.
Definition: resourcebase.cpp:837
Akonadi::ResourceBase::setAutomaticProgressReporting
void setAutomaticProgressReporting(bool enabled)
Enable or disable automatic progress reporting.
Definition: resourcebase.cpp:1314
Akonadi::ResourceBase::setCollectionStreamingEnabled
void setCollectionStreamingEnabled(bool enable)
Enable collection streaming, that is collections don't have to be delivered at once as result of a re...
Definition: resourcebase.cpp:821
Akonadi::ResourceBase::synchronizeCollectionAttributes
void synchronizeCollectionAttributes(qint64 id)
This method is called whenever the collection with the given id shall have its attributes synchronize...
Definition: resourcebase.cpp:1162
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:439
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:118
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::ResourceBase::itemsRetrieved
void itemsRetrieved(const Item::List &items)
Call this method to supply the full collection listing from the remote server.
Definition: resourcebase.cpp:1207
Akonadi::CollectionFetchScope::setListFilter
void setListFilter(ListFilter)
Sets a filter for the collections to be listed.
Definition: collectionfetchscope.cpp:148
Akonadi::Collection::virtualMimeType
static QString virtualMimeType()
Returns the mimetype used for virtual collections.
Definition: collection.cpp:202
Akonadi::AgentBase::agentNameChanged
void agentNameChanged(const QString &name)
This signal is emitted whenever the name of the agent has changed.
Akonadi::Collection::mimeType
static QString mimeType()
Returns the mimetype used for collections.
Definition: collection.cpp:197
Akonadi::ResourceBase::setItemSynchronizationFetchScope
void setItemSynchronizationFetchScope(const ItemFetchScope &fetchScope)
Set the fetch scope applied for item synchronization.
Definition: resourcebase.cpp:1305
Akonadi::ResourceBase::setKeepLocalCollectionChanges
void setKeepLocalCollectionChanges(const QSet< QByteArray > &parts)
Allows to keep locally changed collection parts during the collection sync.
Definition: resourcebase.cpp:854
Akonadi::ResourceBase::synchronizeCollectionTree
void synchronizeCollectionTree()
Refetches the Collections.
Definition: resourcebase.cpp:1074
Akonadi::ResourceBase::setTotalItems
void setTotalItems(int amount)
Call this method when you want to use the itemsRetrieved() method in streaming mode and indicate the ...
Definition: resourcebase.cpp:1182
Akonadi::ResourceBase::nameChanged
void nameChanged(const QString &name)
This signal is emitted whenever the name of the resource has changed.
Akonadi::AgentBasePrivate
Definition: agentbase_p.h:39
Akonadi::ResourceBase::changesCommitted
void changesCommitted(const Item::List &items)
Resets the dirty flag of all given items and updates remote ids.
Definition: resourcebase.cpp:707
Akonadi::ItemFetchJob::items
Item::List items() const
Returns the fetched items.
Definition: itemfetchjob.cpp:233
Akonadi::AgentBase
The base class for all Akonadi agents and resources.
Definition: agentbase.h:80
Akonadi::CollectionFetchJob::Base
Only fetch the base collection.
Definition: collectionfetchjob.h:62
Akonadi::ItemSync
Syncs between items known to a client (usually a resource) and the Akonadi storage.
Definition: itemsync.h:54
Akonadi::ResourceBase::itemsRetrievalDone
void itemsRetrievalDone()
Call this method to indicate you finished synchronizing the current collection.
Definition: resourcebase.cpp:1032
Akonadi::ResourceBase::deferTask
void deferTask()
Stops the execution of the current task and continues with the next one.
Definition: resourcebase.cpp:1120
Akonadi::ItemFetchJob::fetchScope
ItemFetchScope & fetchScope()
Returns the item fetch scope.
Definition: itemfetchjob.cpp:261
Akonadi::AgentBase::setAgentName
void setAgentName(const QString &name)
This method is used to set the name of the agent.
Definition: agentbase.cpp:1136
Akonadi::ResourceBase::SchedulePriority
SchedulePriority
Describes the scheduling priority of a task that has been queued for execution.
Definition: resourcebase.h:687
Akonadi::ResourceBase::synchronize
void synchronize()
This method is called whenever the resource should start synchronize all data.
Definition: resourcebase.cpp:529
Akonadi::AgentBase::error
void error(const QString &message)
This signal shall be used to report errors.
Akonadi::AgentBase::status
virtual int status() const
This method returns the current status code of the agent.
Akonadi::ResourceBase::clearCache
void clearCache()
Call this method to remove all items and collections of the resource from the server cache...
Definition: resourcebase.cpp:1044
Akonadi::ResourceBase::collectionAttributesRetrieved
void collectionAttributesRetrieved(const Collection &collection)
Call this method from retrieveCollectionAttributes() once the result is available.
Definition: resourcebase.cpp:632
Akonadi::Entity::remoteId
QString remoteId() const
Returns the remote id of the entity.
Definition: entity.cpp:82
Akonadi::ResourceBase::collectionsRetrieved
void collectionsRetrieved(const Collection::List &collections)
Call this to supply the full folder tree retrieved from the remote server.
Definition: resourcebase.cpp:786
Akonadi::Collection::root
static Collection root()
Returns the root collection.
Definition: collection.cpp:192
Akonadi::ResourceBase::currentItem
Item currentItem() const
Returns the item that is currently retrieved.
Definition: resourcebase.cpp:1065
Akonadi::CollectionDeleteJob
Job that deletes a collection in the Akonadi storage.
Definition: collectiondeletejob.h:63
Akonadi::ResourceBase::itemsRetrievedIncremental
void itemsRetrievedIncremental(const Item::List &changedItems, const Item::List &removedItems)
Call this method to supply incrementally retrieved items from the remote server.
Definition: resourcebase.cpp:1216
Akonadi::ServerManager::agentServiceName
static QString agentServiceName(ServiceAgentType agentType, const QString &identifier)
Returns the namespaced D-Bus service name for an agent of type agentType with agent identifier identi...
Definition: servermanager.cpp:323
Akonadi::ResourceBase::doSetOnline
void doSetOnline(bool online)
Inherited from AgentBase.
Definition: resourcebase.cpp:1126
Akonadi::Entity::id
Id id() const
Returns the unique identifier of the entity.
Definition: entity.cpp:72
Akonadi::ResourceBase::collectionTreeSynchronized
void collectionTreeSynchronized()
Emitted when a collection tree synchronization has been completed.
Akonadi::CollectionFetchJob::setFetchScope
void setFetchScope(const CollectionFetchScope &fetchScope)
Sets the collection fetch scope.
Definition: collectionfetchjob.cpp:433
Akonadi::ResourceBase::synchronizeCollection
void synchronizeCollection(qint64 id)
This method is called whenever the collection with the given id shall be synchronized.
Definition: resourcebase.cpp:1131
Akonadi::ItemFetchScope
Specifies which parts of an item should be fetched from the Akonadi storage.
Definition: itemfetchscope.h:69
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::ResourceBase::setItemTransactionMode
void setItemTransactionMode(ItemSync::TransactionMode mode)
Set transaction mode for item sync'ing.
Definition: resourcebase.cpp:1299
Akonadi::InvalidateCacheJob
Helper job to invalidate item cache for an entire collection.
Definition: invalidatecachejob_p.h:34
Akonadi::AgentBase::identifier
QString identifier() const
Returns the instance identifier of this agent.
Definition: agentbase.cpp:1131
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::ItemSync::TransactionMode
TransactionMode
Transaction mode used by ItemSync.
Definition: itemsync.h:164
Akonadi::ResourceBase::changeCommitted
void changeCommitted(const Item &item)
Resets the dirty flag of the given item and updates the remote id.
Definition: resourcebase.cpp:702
Akonadi::TransactionSequence
Base class for jobs that need to run a sequence of sub-jobs in a transaction.
Definition: transactionsequence.h:69
Akonadi::AgentBase::changeRecorder
ChangeRecorder * changeRecorder() const
Returns the Akonadi::ChangeRecorder object used for monitoring.
Definition: agentbase.cpp:1175
Akonadi::ResourceBase::dumpMemoryInfo
void dumpMemoryInfo() const
Dumps memory usage information to stdout.
Definition: resourcebase.cpp:1332
Akonadi::ResourceBase::setHierarchicalRemoteIdentifiersEnabled
void setHierarchicalRemoteIdentifiersEnabled(bool enable)
Indicate the use of hierarchical remote identifiers.
Definition: resourcebase.cpp:1272
Akonadi::CollectionSync
Definition: collectionsync_p.h:53
Akonadi::AgentBase::isOnline
bool isOnline() const
Returns whether the agent is currently online.
Akonadi::ResourceBase::itemRetrieved
void itemRetrieved(const Item &item)
Call this method from retrieveItem() once the result is available.
Definition: resourcebase.cpp:596
Akonadi
FreeBusyManager::Singleton.
Definition: actionstatemanager_p.h:28
Akonadi::RecursiveMover::setCollection
void setCollection(const Akonadi::Collection &collection, const Akonadi::Collection &parentCollection)
Set the collection that is actually moved.
Definition: recursivemover.cpp:47
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::ResourceSelectJob
Job that selects a resource context for remote identifier based operations.
Definition: resourceselectjob_p.h:82
Akonadi::TagModifyJob
Job that modifies a tag in the Akonadi storage.
Definition: tagmodifyjob.h:34
Akonadi::ResourceBase::~ResourceBase
~ResourceBase()
Destroys the base resource.
Definition: resourcebase.cpp:525
Akonadi::Tag
An Akonadi Tag.
Definition: tag.h:43
Akonadi::ChangeRecorder::changeProcessed
void changeProcessed()
Removes the previously emitted change from the records.
Definition: changerecorder.cpp:97
Akonadi::Collection::contentMimeTypes
QStringList contentMimeTypes() const
Returns a list of possible content mimetypes, e.g.
Definition: collection.cpp:115
Akonadi::ResourceBase::init
static int init(int argc, char **argv)
Use this method in the main function of your resource application to initialize your resource subclas...
Definition: resourcebase.h:180
Akonadi::ResourceBase::itemSyncBatchSize
int itemSyncBatchSize() const
Returns the batch size used during the item sync.
Definition: resourcebase.cpp:936
Akonadi::ResourceBase::setItemStreamingEnabled
void setItemStreamingEnabled(bool enable)
Enable item streaming.
Definition: resourcebase.cpp:1198
Akonadi::ResourceBase::name
QString name() const
Returns the name of the resource.
Definition: resourcebase.cpp:539
Akonadi::ResourceBase::taskDone
void taskDone()
Indicate that the current task is finished.
Definition: resourcebase.cpp:1284
Akonadi::ResourceBase::cancelTask
void cancelTask()
Stops the execution of the current task and continues with the next one.
Definition: resourcebase.cpp:1079
Akonadi::ChangeRecorder::isEmpty
bool isEmpty() const
Returns whether there are recorded changes.
Definition: changerecorder.cpp:91
Akonadi::ResourceBase::setItemSyncBatchSize
void setItemSyncBatchSize(int batchSize)
Set the batch size used during the item sync.
Definition: resourcebase.cpp:942
Akonadi::ResourceBase::currentCollection
Collection currentCollection() const
Returns the collection that is currently synchronized.
Definition: resourcebase.cpp:1056
Akonadi::Collection::resource
QString resource() const
Returns the identifier of the resource owning the collection.
Definition: collection.cpp:207
Akonadi::Job::UserCanceled
The user canceld this job.
Definition: job.h:107
Akonadi::ResourceBase::setDisableAutomaticItemDeliveryDone
void setDisableAutomaticItemDeliveryDone(bool disable)
Disables the automatic completion of the item sync, based on the number of delivered items...
Definition: resourcebase.cpp:1192
Akonadi::ResourceBase::ResourceBase
ResourceBase(const QString &id)
Creates a base resource.
Definition: resourcebase.cpp:464
Akonadi::Job::errorString
virtual QString errorString() const
Returns the error string, if there has been an error, an empty string otherwise.
Definition: job.cpp:301
Akonadi::AgentBase::Running
The agent is working on something.
Definition: agentbase.h:413
Akonadi::Entity::isValid
bool isValid() const
Returns whether the entity is valid.
Definition: entity.cpp:97
Akonadi::ItemSync::setTransactionMode
void setTransactionMode(TransactionMode mode)
Set the transaction mode to use for this sync.
Definition: itemsync.cpp:519
Akonadi::ResourceBase::collectionsRetrievedIncremental
void collectionsRetrievedIncremental(const Collection::List &changedCollections, const Collection::List &removedCollections)
Call this to supply incrementally retrieved collections from the remote server.
Definition: resourcebase.cpp:803
Akonadi::ServerManager::addNamespace
static QString addNamespace(const QString &string)
Adds the multi-instance namespace to string if required (with '_' as separator).
Definition: servermanager.cpp:337
Akonadi::ResourceBase::setName
void setName(const QString &name)
This method is used to set the name of the resource.
Definition: resourcebase.cpp:534
Akonadi::CollectionFetchJob::Recursive
List all sub-collections.
Definition: collectionfetchjob.h:64
Akonadi::Collection::ListSync
Listing for synchronization.
Definition: collection.h:336
Akonadi::ResourceBase::dumpMemoryInfoToString
QString dumpMemoryInfoToString() const
Returns a string with memory usage information.
Definition: resourcebase.cpp:1338
Akonadi::Collection::List
QList< Collection > List
Describes a list of collections.
Definition: collection.h:81
Akonadi::AgentBase::agentName
QString agentName() const
Returns the name of the agent.
Definition: agentbase.cpp:1159
Akonadi::ResourceBase
The base class for all Akonadi resources.
Definition: resourcebase.h:147
Akonadi::CollectionFetchScope::Sync
Only retrieve collections for synchronization, taking the local preference and enabled into account...
Definition: collectionfetchscope.h:135
Akonadi::Collection::isVirtual
bool isVirtual() const
Returns whether the collection is virtual, for example a search collection.
Definition: collection.cpp:261
Akonadi::ResourceBase::dumpSchedulerToString
QString dumpSchedulerToString() const
Dump the state of the scheduler.
Definition: resourcebase.cpp:1326
Akonadi::ResourceBase::scheduleCustomTask
void scheduleCustomTask(QObject *receiver, const char *method, const QVariant &argument, SchedulePriority priority=Append)
Schedules a custom task in the internal scheduler.
Definition: resourcebase.cpp:1278
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:109
Akonadi::ResourceBase::invalidateCache
void invalidateCache(const Collection &collection)
Call this method to invalidate all cached content in collection.
Definition: resourcebase.cpp:1050
This file is part of the KDE documentation.
Documentation copyright © 1996-2015 The KDE developers.
Generated on Sun Apr 26 2015 12:33:57 by doxygen 1.8.9.1 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-4.14.7 API Reference

Skip menu "kdepimlibs-4.14.7 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
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