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

akonadi

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

KDE's Doxygen guidelines are available online.

akonadi

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

kdepimlibs API Reference

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

Search



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

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