• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.14.10 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
64using namespace Akonadi;
65
66class Akonadi::ResourceBasePrivate : public AgentBasePrivate
67{
68 Q_OBJECT
69 Q_CLASSINFO("D-Bus Interface", "org.kde.dfaure")
70
71public:
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
196public 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
216protected 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
445public:
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
467ResourceBase::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
528ResourceBase::~ResourceBase()
529{
530}
531
532void ResourceBase::synchronize()
533{
534 d_func()->scheduler->scheduleFullSync();
535}
536
537void ResourceBase::setName(const QString &name)
538{
539 AgentBase::setAgentName(name);
540}
541
542QString ResourceBase::name() const
543{
544 return AgentBase::agentName();
545}
546
547QString 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
582int 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
591void ResourceBasePrivate::slotAbortRequested()
592{
593 Q_Q(ResourceBase);
594
595 scheduler->cancelQueues();
596 QMetaObject::invokeMethod(q, "abortActivity");
597}
598
599void 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
624void 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
635void 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
649void 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
660void 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
669void 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
688void 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
698void 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
705void ResourceBase::changeCommitted(const Item &item)
706{
707 changesCommitted(Item::List() << item);
708}
709
710void 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
726void ResourceBase::changeCommitted(const Collection &collection)
727{
728 CollectionModifyJob *job = new CollectionModifyJob(collection);
729 connect(job, SIGNAL(result(KJob*)), SLOT(changeCommittedResult(KJob*)));
730}
731
732void 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
751void ResourceBase::changeCommitted(const Tag &tag)
752{
753 TagModifyJob *job = new TagModifyJob(tag);
754 connect(job, SIGNAL(result(KJob*)), SLOT(changeCommittedResult(KJob*)));
755}
756
757bool 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
763QString 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
789void 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
806void 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
824void 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
840void 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
857void ResourceBase::setKeepLocalCollectionChanges(const QSet<QByteArray> &parts)
858{
859 Q_D(ResourceBase);
860 d->mKeepLocalCollectionChanges = parts;
861}
862
863void 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
886void 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
901void 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
926void 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
939int ResourceBase::itemSyncBatchSize() const
940{
941 Q_D(const ResourceBase);
942 return d->mItemSyncBatchSize;
943}
944
945void ResourceBase::setItemSyncBatchSize(int batchSize)
946{
947 Q_D(ResourceBase);
948 d->mItemSyncBatchSize = batchSize;
949}
950
951void 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
961void 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
974void 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
990void 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
1012void 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
1022void 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
1035void 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
1047void ResourceBase::clearCache()
1048{
1049 Q_D(ResourceBase);
1050 d->scheduler->scheduleResourceCollectionDeletion();
1051}
1052
1053void ResourceBase::invalidateCache(const Collection &collection)
1054{
1055 Q_D(ResourceBase);
1056 d->scheduler->scheduleCacheInvalidation(collection);
1057}
1058
1059Collection 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
1068Item 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
1077void ResourceBase::synchronizeCollectionTree()
1078{
1079 d_func()->scheduler->scheduleCollectionTreeSync();
1080}
1081
1082void 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
1116void ResourceBase::cancelTask(const QString &msg)
1117{
1118 cancelTask();
1119
1120 emit error(msg);
1121}
1122
1123void ResourceBase::deferTask()
1124{
1125 Q_D(ResourceBase);
1126 d->scheduler->deferTask();
1127}
1128
1129void ResourceBase::doSetOnline(bool state)
1130{
1131 d_func()->scheduler->setOnline(state);
1132}
1133
1134void ResourceBase::synchronizeCollection(qint64 collectionId)
1135{
1136 synchronizeCollection(collectionId, false);
1137}
1138
1139void 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
1148void 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
1165void 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
1173void 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
1185void 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
1195void 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
1204void ResourceBase::setItemStreamingEnabled(bool enable)
1205{
1206 Q_D(ResourceBase);
1207 d->createItemSyncInstanceIfMissing();
1208 if (d->mItemSyncer) {
1209 d->mItemSyncer->setStreamingEnabled(enable);
1210 }
1211}
1212
1213void 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
1222void 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
1232void 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
1242void 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
1256void 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
1278void ResourceBase::setHierarchicalRemoteIdentifiersEnabled(bool enable)
1279{
1280 Q_D(ResourceBase);
1281 d->mHierarchicalRid = enable;
1282}
1283
1284void 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
1290void ResourceBase::taskDone()
1291{
1292 Q_D(ResourceBase);
1293 d->scheduler->taskDone();
1294}
1295
1296void ResourceBase::retrieveCollectionAttributes(const Collection &collection)
1297{
1298 collectionAttributesRetrieved(collection);
1299}
1300
1301void Akonadi::ResourceBase::abortActivity()
1302{
1303}
1304
1305void ResourceBase::setItemTransactionMode(ItemSync::TransactionMode mode)
1306{
1307 Q_D(ResourceBase);
1308 d->mItemTransactionMode = mode;
1309}
1310
1311void 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
1320void ResourceBase::setItemMergingMode(ItemSync::MergeMode mode)
1321{
1322 Q_D(ResourceBase);
1323 d->mItemMergeMode = mode;
1324}
1325
1326void ResourceBase::setAutomaticProgressReporting(bool enabled)
1327{
1328 Q_D(ResourceBase);
1329 d->mAutomaticProgressReporting = enabled;
1330}
1331
1332QString ResourceBase::dumpNotificationListToString() const
1333{
1334 Q_D(const ResourceBase);
1335 return d->dumpNotificationListToString();
1336}
1337
1338QString ResourceBase::dumpSchedulerToString() const
1339{
1340 Q_D(const ResourceBase);
1341 return d->dumpToString();
1342}
1343
1344void ResourceBase::dumpMemoryInfo() const
1345{
1346 Q_D(const ResourceBase);
1347 return d->dumpMemoryInfo();
1348}
1349
1350QString 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::AgentBasePrivate
Definition agentbase_p.h:40
Akonadi::AgentBase
The base class for all Akonadi agents and resources.
Definition agentbase.h:81
Akonadi::AgentBase::status
virtual int status() const
This method returns the current status code of the agent.
Akonadi::AgentBase::isOnline
bool isOnline() const
Returns whether the agent is currently online.
Akonadi::AgentBase::setAgentName
void setAgentName(const QString &name)
This method is used to set the name of the agent.
Definition agentbase.cpp:1136
Akonadi::AgentBase::changeRecorder
ChangeRecorder * changeRecorder() const
Returns the Akonadi::ChangeRecorder object used for monitoring.
Definition agentbase.cpp:1175
Akonadi::AgentBase::agentName
QString agentName() const
Returns the name of the agent.
Definition agentbase.cpp:1159
Akonadi::AgentBase::Running
@ Running
The agent is working on something.
Definition agentbase.h:413
Akonadi::AgentBase::percent
void percent(int progress)
This signal should be emitted whenever the progress of an action in the agent (e.g.
Akonadi::AgentBase::abortRequested
void abortRequested()
Emitted when another application has remotely asked the agent to abort its current operation.
Akonadi::AgentBase::identifier
QString identifier() const
Returns the instance identifier of this agent.
Definition agentbase.cpp:1131
Akonadi::AgentBase::agentNameChanged
void agentNameChanged(const QString &name)
This signal is emitted whenever the name of the agent has changed.
Akonadi::AgentBase::error
void error(const QString &message)
This signal shall be used to report errors.
Akonadi::ChangeRecorder::isEmpty
bool isEmpty() const
Returns whether there are recorded changes.
Definition changerecorder.cpp:91
Akonadi::ChangeRecorder::changeProcessed
void changeProcessed()
Removes the previously emitted change from the records.
Definition changerecorder.cpp:97
Akonadi::CollectionDeleteJob
Job that deletes a collection in the Akonadi storage.
Definition collectiondeletejob.h:64
Akonadi::CollectionFetchJob
Job that fetches collections from the Akonadi storage.
Definition collectionfetchjob.h:54
Akonadi::CollectionFetchJob::setFetchScope
void setFetchScope(const CollectionFetchScope &fetchScope)
Sets the collection fetch scope.
Definition collectionfetchjob.cpp:433
Akonadi::CollectionFetchJob::fetchScope
CollectionFetchScope & fetchScope()
Returns the collection fetch scope.
Definition collectionfetchjob.cpp:439
Akonadi::CollectionFetchJob::Recursive
@ Recursive
List all sub-collections.
Definition collectionfetchjob.h:64
Akonadi::CollectionFetchJob::FirstLevel
@ FirstLevel
Only list direct sub-collections of the base collection.
Definition collectionfetchjob.h:63
Akonadi::CollectionFetchJob::Base
@ Base
Only fetch the base collection.
Definition collectionfetchjob.h:62
Akonadi::CollectionFetchJob::collections
Collection::List collections() const
Returns the list of fetched collection.
Definition collectionfetchjob.cpp:169
Akonadi::CollectionFetchScope::Sync
@ Sync
Only retrieve collections for synchronization, taking the local preference and enabled into account.
Definition collectionfetchscope.h:135
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::CollectionFetchScope::setListFilter
void setListFilter(ListFilter)
Sets a filter for the collections to be listed.
Definition collectionfetchscope.cpp:148
Akonadi::CollectionModifyJob
Job that modifies a collection in the Akonadi storage.
Definition collectionmodifyjob.h:83
Akonadi::CollectionSync
Definition collectionsync_p.h:54
Akonadi::Collection
Represents a collection of PIM items.
Definition collection.h:76
Akonadi::Collection::resource
QString resource() const
Returns the identifier of the resource owning the collection.
Definition collection.cpp:207
Akonadi::Collection::contentMimeTypes
QStringList contentMimeTypes() const
Returns a list of possible content mimetypes, e.g.
Definition collection.cpp:115
Akonadi::Collection::mimeType
static QString mimeType()
Returns the mimetype used for collections.
Definition collection.cpp:197
Akonadi::Collection::displayName
QString displayName() const
Returns the display name (EntityDisplayAttribute::displayName()) if set, and Collection::name() other...
Definition collection.cpp:86
Akonadi::Collection::ListSync
@ ListSync
Listing for synchronization.
Definition collection.h:336
Akonadi::Collection::root
static Collection root()
Returns the root collection.
Definition collection.cpp:192
Akonadi::Collection::virtualMimeType
static QString virtualMimeType()
Returns the mimetype used for virtual collections.
Definition collection.cpp:202
Akonadi::Collection::List
QList< Collection > List
Describes a list of collections.
Definition collection.h:81
Akonadi::Collection::isVirtual
bool isVirtual() const
Returns whether the collection is virtual, for example a search collection.
Definition collection.cpp:261
Akonadi::Entity::remoteId
QString remoteId() const
Returns the remote id of the entity.
Definition entity.cpp:82
Akonadi::InvalidateCacheJob
Helper job to invalidate item cache for an entire collection.
Definition invalidatecachejob_p.h:35
Akonadi::ItemFetchJob
Job that fetches items from the Akonadi storage.
Definition itemfetchjob.h:83
Akonadi::ItemFetchJob::fetchScope
ItemFetchScope & fetchScope()
Returns the item fetch scope.
Definition itemfetchjob.cpp:261
Akonadi::ItemFetchJob::items
Item::List items() const
Returns the fetched items.
Definition itemfetchjob.cpp:233
Akonadi::ItemFetchScope
Specifies which parts of an item should be fetched from the Akonadi storage.
Definition itemfetchscope.h:70
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::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::ItemFetchScope::setAncestorRetrieval
void setAncestorRetrieval(AncestorRetrieval ancestorDepth)
Sets how many levels of ancestor collections should be included in the retrieval.
Definition itemfetchscope.cpp:132
Akonadi::ItemModifyJob
Job that modifies an existing item in the Akonadi storage.
Definition itemmodifyjob.h:98
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::ItemModifyJob::disableRevisionCheck
void disableRevisionCheck()
Disables the check of the revision number.
Definition itemmodifyjob.cpp:451
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::ItemSync
Syncs between items known to a client (usually a resource) and the Akonadi storage.
Definition itemsync.h:55
Akonadi::ItemSync::TransactionMode
TransactionMode
Transaction mode used by ItemSync.
Definition itemsync.h:170
Akonadi::Job::UserCanceled
@ UserCanceled
The user canceld this job.
Definition job.h:107
Akonadi::Monitor::collectionFetchScope
CollectionFetchScope & collectionFetchScope()
Returns the collection fetch scope.
Definition monitor.cpp:255
Akonadi::RecursiveMover
Helper class for expanding inter-resource collection moves inside ResourceBase.
Definition recursivemover_p.h:38
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::ResourceBase
The base class for all Akonadi resources.
Definition resourcebase.h:148
Akonadi::ResourceBase::setItemTransactionMode
void setItemTransactionMode(ItemSync::TransactionMode mode)
Set transaction mode for item sync'ing.
Definition resourcebase.cpp:1305
Akonadi::ResourceBase::dumpNotificationListToString
QString dumpNotificationListToString() const
Dump the contents of the current ChangeReplay.
Definition resourcebase.cpp:1332
Akonadi::ResourceBase::dumpMemoryInfo
void dumpMemoryInfo() const
Dumps memory usage information to stdout.
Definition resourcebase.cpp:1344
Akonadi::ResourceBase::taskDone
void taskDone()
Indicate that the current task is finished.
Definition resourcebase.cpp:1290
Akonadi::ResourceBase::invalidateCache
void invalidateCache(const Collection &collection)
Call this method to invalidate all cached content in collection.
Definition resourcebase.cpp:1053
Akonadi::ResourceBase::collectionAttributesRetrieved
void collectionAttributesRetrieved(const Collection &collection)
Call this method from retrieveCollectionAttributes() once the result is available.
Definition resourcebase.cpp:635
Akonadi::ResourceBase::itemSyncBatchSize
int itemSyncBatchSize() const
Returns the batch size used during the item sync.
Definition resourcebase.cpp:939
Akonadi::ResourceBase::setItemSyncBatchSize
void setItemSyncBatchSize(int batchSize)
Set the batch size used during the item sync.
Definition resourcebase.cpp:945
Akonadi::ResourceBase::doSetOnline
void doSetOnline(bool online)
Inherited from AgentBase.
Definition resourcebase.cpp:1129
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::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::setItemSynchronizationFetchScope
void setItemSynchronizationFetchScope(const ItemFetchScope &fetchScope)
Set the fetch scope applied for item synchronization.
Definition resourcebase.cpp:1311
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::ResourceBase::retrieveCollections
virtual void retrieveCollections()=0
Retrieve the collection tree from the remote server and supply it via collectionsRetrieved() or colle...
Akonadi::ResourceBase::dumpSchedulerToString
QString dumpSchedulerToString() const
Dump the state of the scheduler.
Definition resourcebase.cpp:1338
Akonadi::ResourceBase::dumpMemoryInfoToString
QString dumpMemoryInfoToString() const
Returns a string with memory usage information.
Definition resourcebase.cpp:1350
Akonadi::ResourceBase::SchedulePriority
SchedulePriority
Describes the scheduling priority of a task that has been queued for execution.
Definition resourcebase.h:704
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::attributesSynchronized
void attributesSynchronized(qlonglong collectionId)
Emitted when a collection attributes synchronization has been completed.
Akonadi::ResourceBase::itemsRetrievalDone
void itemsRetrievalDone()
Call this method to indicate you finished synchronizing the current collection.
Definition resourcebase.cpp:1035
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::setAutomaticProgressReporting
void setAutomaticProgressReporting(bool enabled)
Enable or disable automatic progress reporting.
Definition resourcebase.cpp:1326
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::ResourceBase::deferTask
void deferTask()
Stops the execution of the current task and continues with the next one.
Definition resourcebase.cpp:1123
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::collectionsRetrievalDone
void collectionsRetrievalDone()
Call this method to indicate you finished synchronizing the collection tree.
Definition resourcebase.cpp:840
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::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::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::ResourceBase::itemRetrieved
void itemRetrieved(const Item &item)
Call this method from retrieveItem() once the result is available.
Definition resourcebase.cpp:599
Akonadi::ResourceBase::synchronize
void synchronize()
This method is called whenever the resource should start synchronize all data.
Definition resourcebase.cpp:532
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::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::ResourceBase::currentCollection
Collection currentCollection() const
Returns the collection that is currently synchronized.
Definition resourcebase.cpp:1059
Akonadi::ResourceBase::nameChanged
void nameChanged(const QString &name)
This signal is emitted whenever the name of the resource has changed.
Akonadi::ResourceBase::cancelTask
void cancelTask()
Stops the execution of the current task and continues with the next one.
Definition resourcebase.cpp:1082
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::ResourceBase::setItemMergingMode
void setItemMergingMode(ItemSync::MergeMode mode)
Set merge mode for item sync'ing.
Definition resourcebase.cpp:1320
Akonadi::ResourceBase::setHierarchicalRemoteIdentifiersEnabled
void setHierarchicalRemoteIdentifiersEnabled(bool enable)
Indicate the use of hierarchical remote identifiers.
Definition resourcebase.cpp:1278
Akonadi::ResourceBase::ResourceBase
ResourceBase(const QString &id)
Creates a base resource.
Definition resourcebase.cpp:467
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::collectionTreeSynchronized
void collectionTreeSynchronized()
Emitted when a collection tree synchronization has been completed.
Akonadi::ResourceBase::setName
void setName(const QString &name)
This method is used to set the name of the resource.
Definition resourcebase.cpp:537
Akonadi::ResourceBase::synchronizeCollectionTree
void synchronizeCollectionTree()
Refetches the Collections.
Definition resourcebase.cpp:1077
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::changesCommitted
void changesCommitted(const Item::List &items)
Resets the dirty flag of all given items and updates remote ids.
Definition resourcebase.cpp:710
Akonadi::ResourceBase::abortActivity
void abortActivity()
Abort any activity in progress in the backend.
Definition resourcebase.cpp:1301
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::ResourceBase::currentItem
Item currentItem() const
Returns the item that is currently retrieved.
Definition resourcebase.cpp:1068
Akonadi::ResourceBase::~ResourceBase
~ResourceBase()
Destroys the base resource.
Definition resourcebase.cpp:528
Akonadi::ResourceSelectJob
Job that selects a resource context for remote identifier based operations.
Definition resourceselectjob_p.h:83
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::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::TagModifyJob
Job that modifies a tag in the Akonadi storage.
Definition tagmodifyjob.h:35
Akonadi::Tag
An Akonadi Tag.
Definition tag.h:44
Akonadi::TransactionSequence
Base class for jobs that need to run a sequence of sub-jobs in a transaction.
Definition transactionsequence.h:70
Akonadi
FreeBusyManager::Singleton.
Definition actionstatemanager_p.h:28
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Wed Jan 24 2024 00:00:00 by doxygen 1.10.0 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
  • Related Pages

kdepimlibs-4.14.10 API Reference

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