21 #include "resourcebase.h"
22 #include "agentbase_p.h"
24 #include "resourceadaptor.h"
25 #include "collectiondeletejob.h"
26 #include "collectionsync_p.h"
27 #include "dbusconnectionpool.h"
29 #include "kdepimlibs-version.h"
30 #include "resourcescheduler_p.h"
31 #include "tracerinterface.h"
32 #include "xdgbasedirs_p.h"
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"
44 #include "resourceselectjob_p.h"
45 #include "monitor_p.h"
46 #include "servermanager_p.h"
47 #include "recursivemover_p.h"
49 #include <kaboutdata.h>
50 #include <kcmdlineargs.h>
52 #include <klocalizedstring.h>
54 #include <akonadi/tagmodifyjob.h>
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>
64 using namespace Akonadi;
69 Q_CLASSINFO(
"D-Bus Interface",
"org.kde.dfaure")
76 , mItemSyncFetchScope(0)
77 , mItemTransactionMode(
ItemSync::SingleTransaction)
78 , mCollectionSyncer(0)
79 , mHierarchicalRid(false)
80 , mUnemittedProgress(0)
81 , mAutomaticProgressReporting(true)
82 , mDisableAutomaticItemDeliveryDone(false)
83 , mItemSyncBatchSize(10)
84 , mCurrentCollectionFetchJob(0)
86 Internal::setClientType(Internal::Resource);
87 mStatusMessage = defaultReadyMessage();
88 mProgressEmissionCompressor.setInterval(1000);
89 mProgressEmissionCompressor.setSingleShot(
true);
91 mKeepLocalCollectionChanges <<
"ENTITYDISPLAY";
94 ~ResourceBasePrivate()
96 delete mItemSyncFetchScope;
104 if (!DBusConnectionPool::threadConnection().registerService(serviceId)) {
105 QString reason = DBusConnectionPool::threadConnection().lastError().message();
106 if (reason.isEmpty()) {
107 reason = QString::fromLatin1(
"this service is probably running already.");
109 kError() <<
"Unable to register service" << serviceId <<
"at D-Bus:" << reason;
111 if (QThread::currentThread() == QCoreApplication::instance()->thread()) {
112 QCoreApplication::instance()->exit(1);
116 AgentBasePrivate::delayedInit();
120 virtual void changeProcessed()
122 if (m_recursiveMover) {
123 m_recursiveMover->changeProcessed();
124 QTimer::singleShot(0, m_recursiveMover, SLOT(replayNext()));
129 if (!mChangeRecorder->
isEmpty()) {
130 scheduler->scheduleChangeReplay();
132 scheduler->taskDone();
135 void slotAbortRequested();
137 void slotDeliveryDone(KJob *job);
138 void slotCollectionSyncDone(KJob *job);
139 void slotLocalListDone(KJob *job);
140 void slotSynchronizeCollection(
const Collection &col);
141 void slotItemRetrievalCollectionFetchDone(KJob *job);
142 void slotCollectionListDone(KJob *job);
143 void slotSynchronizeCollectionAttributes(
const Collection &col);
144 void slotCollectionListForAttributesDone(KJob *job);
145 void slotCollectionAttributesSyncDone(KJob *job);
146 void slotAttributeRetrievalCollectionFetchDone(KJob *job);
148 void slotItemSyncDone(KJob *job);
150 void slotPercent(KJob *job,
unsigned long percent);
151 void slotDelayedEmitProgress();
152 void slotDeleteResourceCollection();
153 void slotDeleteResourceCollectionDone(KJob *job);
154 void slotCollectionDeletionDone(KJob *job);
158 void slotPrepareItemRetrieval(
const Akonadi::Item &item);
159 void slotPrepareItemRetrievalResult(KJob *job);
161 void changeCommittedResult(KJob *job);
164 void slotRecursiveMoveReplayResult(KJob *job);
166 void slotSessionReconnected()
173 void createItemSyncInstanceIfMissing()
176 Q_ASSERT_X(scheduler->currentTask().type == ResourceScheduler::SyncCollection,
177 "createItemSyncInstance",
"Calling items retrieval methods although no item retrieval is in progress");
179 mItemSyncer =
new ItemSync(q->currentCollection());
181 mItemSyncer->setBatchSize(mItemSyncBatchSize);
182 if (mItemSyncFetchScope) {
183 mItemSyncer->setFetchScope(*mItemSyncFetchScope);
185 mItemSyncer->setDisableAutomaticDeliveryDone(mDisableAutomaticItemDeliveryDone);
186 mItemSyncer->setProperty(
"collection", QVariant::fromValue(q->currentCollection()));
187 connect(mItemSyncer, SIGNAL(percent(KJob*,ulong)), q, SLOT(slotPercent(KJob*,ulong)));
188 connect(mItemSyncer, SIGNAL(result(KJob*)), q, SLOT(slotItemSyncDone(KJob*)));
189 connect(mItemSyncer, SIGNAL(readyForNextBatch(
int)), q, SIGNAL(retrieveNextItemSyncBatch(
int)));
191 Q_ASSERT(mItemSyncer);
196 Q_SCRIPTABLE QString dumpToString()
const
200 QMetaObject::invokeMethod(const_cast<ResourceBase *>(q),
"dumpResourceToString", Qt::DirectConnection, Q_RETURN_ARG(QString, retVal));
201 return scheduler->dumpToString() + QLatin1Char(
'\n') + retVal;
204 Q_SCRIPTABLE
void dump()
209 Q_SCRIPTABLE
void clear()
222 if (collection.
remoteId().isEmpty()) {
226 AgentBasePrivate::itemAdded(item, collection);
229 void itemChanged(
const Akonadi::Item &item,
const QSet< QByteArray > &partIdentifiers)
231 if (item.remoteId().isEmpty()) {
235 AgentBasePrivate::itemChanged(item, partIdentifiers);
238 void itemsFlagsChanged(
const Item::List &items,
const QSet< QByteArray > &addedFlags,
239 const QSet< QByteArray > &removedFlags)
241 if (addedFlags.isEmpty() && removedFlags.isEmpty()) {
246 Item::List validItems;
247 foreach (
const Akonadi::Item &item, items) {
248 if (!item.remoteId().isEmpty()) {
252 if (validItems.isEmpty()) {
257 AgentBasePrivate::itemsFlagsChanged(validItems, addedFlags, removedFlags);
260 void itemsTagsChanged(
const Item::List &items,
const QSet<Tag> &addedTags,
const QSet<Tag> &removedTags)
262 if (addedTags.isEmpty() && removedTags.isEmpty()) {
267 Item::List validItems;
268 foreach (
const Akonadi::Item &item, items) {
269 if (!item.remoteId().isEmpty()) {
273 if (validItems.isEmpty()) {
278 AgentBasePrivate::itemsTagsChanged(validItems, addedTags, removedTags);
284 if (item.remoteId().isEmpty() || destination.
remoteId().isEmpty() || destination == source) {
288 AgentBasePrivate::itemMoved(item, source, destination);
291 void itemsMoved(
const Item::List &items,
const Collection &source,
const Collection &destination)
293 if (destination.
remoteId().isEmpty() || destination == source) {
298 Item::List validItems;
299 foreach (
const Akonadi::Item &item, items) {
300 if (!item.remoteId().isEmpty()) {
304 if (validItems.isEmpty()) {
309 AgentBasePrivate::itemsMoved(validItems, source, destination);
312 void itemRemoved(
const Akonadi::Item &item)
314 if (item.remoteId().isEmpty()) {
318 if (!item.parentCollection().isValid()) {
319 kWarning() <<
"Invalid parent collection for item" << item.id();
323 AgentBasePrivate::itemRemoved(item);
326 void itemsRemoved(
const Item::List &items)
328 Item::List validItems;
329 foreach (
const Akonadi::Item &item, items) {
330 if (!item.parentCollection().isValid()) {
331 kWarning() <<
"Invalid parent collection for item" << item.id();
334 if (!item.remoteId().isEmpty()) {
338 if (validItems.isEmpty()) {
343 AgentBasePrivate::itemsRemoved(validItems);
352 AgentBasePrivate::collectionAdded(collection, parent);
357 if (collection.
remoteId().isEmpty()) {
361 AgentBasePrivate::collectionChanged(collection);
364 void collectionChanged(
const Akonadi::Collection &collection,
const QSet< QByteArray > &partIdentifiers)
366 if (collection.
remoteId().isEmpty()) {
370 AgentBasePrivate::collectionChanged(collection, partIdentifiers);
376 if (destination.
remoteId().isEmpty() || source == destination) {
384 AgentBasePrivate::collectionRemoved(collection);
386 scheduler->taskDone();
389 scheduler->scheduleMoveReplay(collection, mover);
395 if (collection.
remoteId().isEmpty()) {
401 AgentBasePrivate::collectionMoved(collection, source, destination);
406 if (collection.
remoteId().isEmpty()) {
410 AgentBasePrivate::collectionRemoved(collection);
415 if (!tag.isValid()) {
420 AgentBasePrivate::tagAdded(tag);
425 if (tag.remoteId().isEmpty()) {
430 AgentBasePrivate::tagChanged(tag);
435 if (tag.remoteId().isEmpty()) {
440 AgentBasePrivate::tagRemoved(tag);
447 ResourceScheduler *scheduler;
452 bool mHierarchicalRid;
453 QTimer mProgressEmissionCompressor;
454 int mUnemittedProgress;
455 QMap<Akonadi::Collection::Id, QVariantMap> mUnemittedAdvancedStatus;
456 bool mAutomaticProgressReporting;
457 bool mDisableAutomaticItemDeliveryDone;
458 QPointer<RecursiveMover> m_recursiveMover;
459 int mItemSyncBatchSize;
460 QSet<QByteArray> mKeepLocalCollectionChanges;
461 KJob *mCurrentCollectionFetchJob;
465 :
AgentBase(new ResourceBasePrivate(this), id)
469 new Akonadi__ResourceAdaptor(
this);
471 d->scheduler =
new ResourceScheduler(
this);
473 d->mChangeRecorder->setChangeRecordingEnabled(
true);
474 d->mChangeRecorder->setCollectionMoveTranslationEnabled(
false);
475 connect(d->mChangeRecorder, SIGNAL(changesAdded()),
476 d->scheduler, SLOT(scheduleChangeReplay()));
478 d->mChangeRecorder->setResourceMonitored(d->mId.toLatin1());
479 d->mChangeRecorder->fetchCollection(
true);
481 connect(d->scheduler, SIGNAL(executeFullSync()),
483 connect(d->scheduler, SIGNAL(executeCollectionTreeSync()),
489 connect(d->scheduler, SIGNAL(executeItemFetch(Akonadi::Item,QSet<QByteArray>)),
490 SLOT(slotPrepareItemRetrieval(Akonadi::Item)));
491 connect(d->scheduler, SIGNAL(executeResourceCollectionDeletion()),
492 SLOT(slotDeleteResourceCollection()));
495 connect(d->scheduler, SIGNAL(
status(
int,QString)),
496 SIGNAL(
status(
int,QString)));
497 connect(d->scheduler, SIGNAL(executeChangeReplay()),
498 d->mChangeRecorder, SLOT(replayNext()));
499 connect(d->scheduler, SIGNAL(executeRecursiveMoveReplay(
RecursiveMover*)),
501 connect(d->scheduler, SIGNAL(fullSyncComplete()), SIGNAL(
synchronized()));
503 connect(d->mChangeRecorder, SIGNAL(nothingToReplay()), d->scheduler, SLOT(
taskDone()));
506 connect(
this, SIGNAL(
abortRequested()),
this, SLOT(slotAbortRequested()));
507 connect(
this, SIGNAL(
synchronized()), d->scheduler, SLOT(
taskDone()));
512 connect(&d->mProgressEmissionCompressor, SIGNAL(timeout()),
513 this, SLOT(slotDelayedEmitProgress()));
515 d->scheduler->setOnline(d->mOnline);
516 if (!d->mChangeRecorder->isEmpty()) {
517 d->scheduler->scheduleChangeReplay();
522 connect(d->mChangeRecorder->session(), SIGNAL(reconnected()), SLOT(slotSessionReconnected()));
531 d_func()->scheduler->scheduleFullSync();
544 QString ResourceBase::parseArguments(
int argc,
char **argv)
548 kDebug() <<
"Not enough arguments passed...";
552 for (
int i = 1; i < argc - 1; ++i) {
553 if (QLatin1String(argv[i]) == QLatin1String(
"--identifier")) {
554 identifier = QLatin1String(argv[i + 1]);
558 if (identifier.isEmpty()) {
559 kDebug() <<
"Identifier argument missing";
563 const QFileInfo fi(QString::fromLocal8Bit(argv[0]));
565 const QByteArray catalog = fi.baseName().toLatin1();
568 ki18nc(
"@title application name",
"Akonadi Resource"), KDEPIMLIBS_VERSION,
569 ki18nc(
"@title application description",
"Akonadi Resource"));
571 KCmdLineOptions options;
572 options.add(
"identifier <argument>",
573 ki18nc(
"@label commandline option",
"Resource identifier"));
574 KCmdLineArgs::addCmdLineOptions(options);
581 QApplication::setQuitOnLastWindowClosed(
false);
582 KGlobal::locale()->insertCatalog(QLatin1String(
"libakonadi"));
583 int rv = kapp->exec();
588 void ResourceBasePrivate::slotAbortRequested()
592 scheduler->cancelQueues();
593 QMetaObject::invokeMethod(q,
"abortActivity");
599 Q_ASSERT(d->scheduler->currentTask().type == ResourceScheduler::FetchItem);
600 if (!item.isValid()) {
601 d->scheduler->currentTask().sendDBusReplies(i18nc(
"@info",
"Invalid item retrieved"));
602 d->scheduler->taskDone();
607 QSet<QByteArray> requestedParts = d->scheduler->currentTask().itemParts;
608 foreach (
const QByteArray &part, requestedParts) {
609 if (!item.loadedPayloadParts().contains(part)) {
610 kWarning() <<
"Item does not provide part" << part;
615 job->d_func()->setSilent(
true );
618 connect(job, SIGNAL(result(KJob*)), SLOT(slotDeliveryDone(KJob*)));
621 void ResourceBasePrivate::slotDeliveryDone(KJob *job)
624 Q_ASSERT(scheduler->currentTask().type == ResourceScheduler::FetchItem);
626 emit q->error(i18nc(
"@info",
"Error while creating item: %1", job->errorString()));
628 scheduler->currentTask().sendDBusReplies(job->error() ? job->errorString() : QString());
629 scheduler->taskDone();
635 Q_ASSERT(d->scheduler->currentTask().type == ResourceScheduler::SyncCollectionAttributes);
638 d->scheduler->taskDone();
643 connect(job, SIGNAL(result(KJob*)), SLOT(slotCollectionAttributesSyncDone(KJob*)));
646 void ResourceBasePrivate::slotCollectionAttributesSyncDone(KJob *job)
649 Q_ASSERT(scheduler->currentTask().type == ResourceScheduler::SyncCollectionAttributes);
651 emit q->error(i18nc(
"@info",
"Error while updating collection: %1", job->errorString()));
653 emit q->attributesSynchronized(scheduler->currentTask().collection.id());
654 scheduler->taskDone();
657 void ResourceBasePrivate::slotDeleteResourceCollection()
663 connect(job, SIGNAL(result(KJob*)), q, SLOT(slotDeleteResourceCollectionDone(KJob*)));
666 void ResourceBasePrivate::slotDeleteResourceCollectionDone(KJob *job)
670 emit q->error(job->errorString());
671 scheduler->taskDone();
677 connect(job, SIGNAL(result(KJob*)), q, SLOT(slotCollectionDeletionDone(KJob*)));
680 scheduler->taskDone();
685 void ResourceBasePrivate::slotCollectionDeletionDone(KJob *job)
689 emit q->error(job->errorString());
692 scheduler->taskDone();
699 connect(job, SIGNAL(result(KJob*)), scheduler, SLOT(taskDone()));
710 connect(transaction, SIGNAL(finished(KJob*)),
711 this, SLOT(changeCommittedResult(KJob*)));
714 Q_FOREACH (
const Item &item, items) {
716 job->d_func()->setClean();
726 connect(job, SIGNAL(result(KJob*)), SLOT(changeCommittedResult(KJob*)));
729 void ResourceBasePrivate::changeCommittedResult(KJob *job)
732 kWarning() << job->errorText();
736 if (qobject_cast<CollectionModifyJob *>(job)) {
738 emit q->error(i18nc(
"@info",
"Updating local collection failed: %1.", job->errorText()));
740 mChangeRecorder->d_ptr->invalidateCache(static_cast<CollectionModifyJob *>(job)->collection());
751 connect(job, SIGNAL(result(KJob*)), SLOT(changeCommittedResult(KJob*)));
754 bool ResourceBase::requestItemDelivery(qint64 uid,
const QString &remoteId,
755 const QString &mimeType,
const QStringList &parts)
757 return requestItemDeliveryV2(uid, remoteId, mimeType, parts).isEmpty();
760 QString ResourceBase::requestItemDeliveryV2(qint64 uid,
const QString &remoteId,
const QString &mimeType,
const QStringList &_parts)
764 const QString errorMsg = i18nc(
"@info",
"Cannot fetch item in offline mode.");
765 emit
error(errorMsg);
769 setDelayedReply(
true);
772 item.setMimeType(mimeType);
773 item.setRemoteId(remoteId);
775 QSet<QByteArray> parts;
776 Q_FOREACH (
const QString &str, _parts) {
777 parts.insert(str.toLatin1());
780 d->scheduler->scheduleItemFetch(item, parts, message());
789 Q_ASSERT_X(d->scheduler->currentTask().type == ResourceScheduler::SyncCollectionTree ||
790 d->scheduler->currentTask().type == ResourceScheduler::SyncAll,
791 "ResourceBase::collectionsRetrieved()",
792 "Calling collectionsRetrieved() although no collection retrieval is in progress");
793 if (!d->mCollectionSyncer) {
795 d->mCollectionSyncer->setHierarchicalRemoteIds(d->mHierarchicalRid);
796 d->mCollectionSyncer->setKeepLocalChanges(d->mKeepLocalCollectionChanges);
797 connect(d->mCollectionSyncer, SIGNAL(
percent(KJob*,ulong)), SLOT(slotPercent(KJob*,ulong)));
798 connect(d->mCollectionSyncer, SIGNAL(result(KJob*)), SLOT(slotCollectionSyncDone(KJob*)));
800 d->mCollectionSyncer->setRemoteCollections(collections);
807 Q_ASSERT_X(d->scheduler->currentTask().type == ResourceScheduler::SyncCollectionTree ||
808 d->scheduler->currentTask().type == ResourceScheduler::SyncAll,
809 "ResourceBase::collectionsRetrievedIncremental()",
810 "Calling collectionsRetrievedIncremental() although no collection retrieval is in progress");
811 if (!d->mCollectionSyncer) {
813 d->mCollectionSyncer->setHierarchicalRemoteIds(d->mHierarchicalRid);
814 d->mCollectionSyncer->setKeepLocalChanges(d->mKeepLocalCollectionChanges);
815 connect(d->mCollectionSyncer, SIGNAL(
percent(KJob*,ulong)), SLOT(slotPercent(KJob*,ulong)));
816 connect(d->mCollectionSyncer, SIGNAL(result(KJob*)), SLOT(slotCollectionSyncDone(KJob*)));
818 d->mCollectionSyncer->setRemoteCollections(changedCollections, removedCollections);
824 Q_ASSERT_X(d->scheduler->currentTask().type == ResourceScheduler::SyncCollectionTree ||
825 d->scheduler->currentTask().type == ResourceScheduler::SyncAll,
826 "ResourceBase::setCollectionStreamingEnabled()",
827 "Calling setCollectionStreamingEnabled() although no collection retrieval is in progress");
828 if (!d->mCollectionSyncer) {
830 d->mCollectionSyncer->setHierarchicalRemoteIds(d->mHierarchicalRid);
831 connect(d->mCollectionSyncer, SIGNAL(
percent(KJob*,ulong)), SLOT(slotPercent(KJob*,ulong)));
832 connect(d->mCollectionSyncer, SIGNAL(result(KJob*)), SLOT(slotCollectionSyncDone(KJob*)));
834 d->mCollectionSyncer->setStreamingEnabled(enable);
840 Q_ASSERT_X(d->scheduler->currentTask().type == ResourceScheduler::SyncCollectionTree ||
841 d->scheduler->currentTask().type == ResourceScheduler::SyncAll,
842 "ResourceBase::collectionsRetrievalDone()",
843 "Calling collectionsRetrievalDone() although no collection retrieval is in progress");
845 if (d->mCollectionSyncer) {
846 d->mCollectionSyncer->retrievalDone();
850 d->scheduler->taskDone();
857 d->mKeepLocalCollectionChanges = parts;
860 void ResourceBasePrivate::slotCollectionSyncDone(KJob *job)
863 mCollectionSyncer = 0;
866 emit q->error(job->errorString());
869 if (scheduler->currentTask().type == ResourceScheduler::SyncAll) {
871 list->
setFetchScope(q->changeRecorder()->collectionFetchScope());
874 q->connect(list, SIGNAL(result(KJob*)), q, SLOT(slotLocalListDone(KJob*)));
876 }
else if (scheduler->currentTask().type == ResourceScheduler::SyncCollectionTree) {
877 scheduler->scheduleCollectionTreeSyncCompletion();
880 scheduler->taskDone();
883 void ResourceBasePrivate::slotLocalListDone(KJob *job)
887 emit q->error(job->errorString());
891 scheduler->scheduleSync(col);
893 scheduler->scheduleFullSyncCompletion();
895 scheduler->taskDone();
898 void ResourceBasePrivate::slotSynchronizeCollection(
const Collection &col)
901 currentCollection = col;
908 if (!contentTypes.isEmpty() || col.
isVirtual()) {
909 if (mAutomaticProgressReporting) {
910 emit q->status(
AgentBase::Running, i18nc(
"@info:status",
"Syncing folder '%1'", currentCollection.displayName()));
914 fetchJob->
setFetchScope(q->changeRecorder()->collectionFetchScope());
915 connect(fetchJob, SIGNAL(result(KJob*)), q, SLOT(slotItemRetrievalCollectionFetchDone(KJob*)));
916 mCurrentCollectionFetchJob = fetchJob;
920 scheduler->taskDone();
923 void ResourceBasePrivate::slotItemRetrievalCollectionFetchDone(KJob *job)
926 mCurrentCollectionFetchJob = 0;
928 kWarning() <<
"Failed to retrieve collection for sync: " << job->errorString();
929 q->cancelTask(i18n(
"Failed to retrieve collection for sync."));
939 return d->mItemSyncBatchSize;
945 d->mItemSyncBatchSize = batchSize;
948 void ResourceBasePrivate::slotSynchronizeCollectionAttributes(
const Collection &col)
952 fetchJob->
setFetchScope(q->changeRecorder()->collectionFetchScope());
953 connect(fetchJob, SIGNAL(result(KJob*)), q, SLOT(slotAttributeRetrievalCollectionFetchDone(KJob*)));
954 Q_ASSERT(!mCurrentCollectionFetchJob);
955 mCurrentCollectionFetchJob = fetchJob;
958 void ResourceBasePrivate::slotAttributeRetrievalCollectionFetchDone(KJob *job)
960 mCurrentCollectionFetchJob = 0;
963 kWarning() <<
"Failed to retrieve collection for attribute sync: " << job->errorString();
964 q->cancelTask(i18n(
"Failed to retrieve collection for attribute sync."));
971 void ResourceBasePrivate::slotPrepareItemRetrieval(
const Akonadi::Item &item)
979 const QSet<QByteArray> attributes = q->changeRecorder()->itemFetchScope().attributes();
980 foreach (
const QByteArray &attribute, attributes) {
984 q->connect(fetch, SIGNAL(result(KJob*)), SLOT(slotPrepareItemRetrievalResult(KJob*)));
987 void ResourceBasePrivate::slotPrepareItemRetrievalResult(KJob *job)
990 Q_ASSERT_X(scheduler->currentTask().type == ResourceScheduler::FetchItem,
991 "ResourceBasePrivate::slotPrepareItemRetrievalResult()",
992 "Preparing item retrieval although no item retrieval is in progress");
994 q->cancelTask(job->errorText());
998 if (fetch->
items().count() != 1) {
999 q->cancelTask(i18n(
"The requested item no longer exists"));
1002 const Item item = fetch->
items().first();
1003 const QSet<QByteArray> parts = scheduler->currentTask().itemParts;
1004 if (!q->retrieveItem(item, parts)) {
1009 void ResourceBasePrivate::slotRecursiveMoveReplay(
RecursiveMover *mover)
1013 Q_ASSERT(!m_recursiveMover);
1014 m_recursiveMover = mover;
1015 connect(mover, SIGNAL(result(KJob*)), q, SLOT(slotRecursiveMoveReplayResult(KJob*)));
1019 void ResourceBasePrivate::slotRecursiveMoveReplayResult(KJob *job)
1022 m_recursiveMover = 0;
1036 if (d->mItemSyncer) {
1037 d->mItemSyncer->deliveryDone();
1040 d->scheduler->taskDone();
1047 d->scheduler->scheduleResourceCollectionDeletion();
1053 d->scheduler->scheduleCacheInvalidation(collection);
1059 Q_ASSERT_X(d->scheduler->currentTask().type == ResourceScheduler::SyncCollection ,
1060 "ResourceBase::currentCollection()",
1061 "Trying to access current collection although no item retrieval is in progress");
1062 return d->currentCollection;
1068 Q_ASSERT_X(d->scheduler->currentTask().type == ResourceScheduler::FetchItem ,
1069 "ResourceBase::currentItem()",
1070 "Trying to access current item although no item retrieval is in progress");
1071 return d->scheduler->currentTask().item;
1076 d_func()->scheduler->scheduleCollectionTreeSync();
1082 if (d->mCurrentCollectionFetchJob) {
1083 d->mCurrentCollectionFetchJob->kill();
1084 d->mCurrentCollectionFetchJob = 0;
1086 switch (d->scheduler->currentTask().type) {
1087 case ResourceScheduler::FetchItem:
1090 case ResourceScheduler::ChangeReplay:
1091 d->changeProcessed();
1093 case ResourceScheduler::SyncCollectionTree:
1094 case ResourceScheduler::SyncAll:
1095 if (d->mCollectionSyncer) {
1096 d->mCollectionSyncer->rollback();
1098 d->scheduler->taskDone();
1101 case ResourceScheduler::SyncCollection:
1102 if (d->mItemSyncer) {
1103 d->mItemSyncer->rollback();
1105 d->scheduler->taskDone();
1109 d->scheduler->taskDone();
1123 d->scheduler->deferTask();
1128 d_func()->scheduler->setOnline(state);
1142 connect(job, SIGNAL(result(KJob*)), SLOT(slotCollectionListDone(KJob*)));
1145 void ResourceBasePrivate::slotCollectionListDone(KJob *job)
1147 if (!job->error()) {
1149 Q_FOREACH (
const Collection &collection, list) {
1153 scheduler->scheduleAttributesSync(collection);
1154 scheduler->scheduleSync(collection);
1158 kWarning() <<
"Failed to fetch collection for collection sync: " << job->
errorString();
1167 connect(job, SIGNAL(result(KJob*)), SLOT(slotCollectionListForAttributesDone(KJob*)));
1170 void ResourceBasePrivate::slotCollectionListForAttributesDone(KJob *job)
1172 if (!job->error()) {
1174 if (!list.isEmpty()) {
1176 scheduler->scheduleAttributesSync(col);
1187 if (d->mItemSyncer) {
1188 d->mItemSyncer->setTotalItems(amount);
1195 d->mDisableAutomaticItemDeliveryDone = disable;
1201 d->createItemSyncInstanceIfMissing();
1202 if (d->mItemSyncer) {
1203 d->mItemSyncer->setStreamingEnabled(enable);
1210 d->createItemSyncInstanceIfMissing();
1211 if (d->mItemSyncer) {
1212 d->mItemSyncer->setFullSyncItems(items);
1217 const Item::List &removedItems)
1220 d->createItemSyncInstanceIfMissing();
1221 if (d->mItemSyncer) {
1222 d->mItemSyncer->setIncrementalSyncItems(changedItems, removedItems);
1226 void ResourceBasePrivate::slotItemSyncDone(KJob *job)
1231 emit q->error(job->errorString());
1233 scheduler->taskDone();
1236 void ResourceBasePrivate::slotDelayedEmitProgress()
1239 if (mAutomaticProgressReporting) {
1240 emit q->percent(mUnemittedProgress);
1242 Q_FOREACH (
const QVariantMap &statusMap, mUnemittedAdvancedStatus) {
1243 emit q->advancedStatus(statusMap);
1246 mUnemittedProgress = 0;
1247 mUnemittedAdvancedStatus.clear();
1250 void ResourceBasePrivate::slotPercent(KJob *job,
unsigned long percent)
1252 mUnemittedProgress = percent;
1256 QVariantMap statusMap;
1257 statusMap.insert(QLatin1String(
"key"), QString::fromLatin1(
"collectionSyncProgress"));
1258 statusMap.insert(QLatin1String(
"collectionId"), collection.
id());
1259 statusMap.insert(QLatin1String(
"percent"), static_cast<unsigned int>(percent));
1261 mUnemittedAdvancedStatus[collection.
id()] = statusMap;
1264 if (percent == 100) {
1265 mProgressEmissionCompressor.stop();
1266 slotDelayedEmitProgress();
1267 }
else if (!mProgressEmissionCompressor.isActive()) {
1268 mProgressEmissionCompressor.start();
1275 d->mHierarchicalRid = enable;
1281 d->scheduler->scheduleCustomTask(receiver, method, argument, priority);
1287 d->scheduler->taskDone();
1302 d->mItemTransactionMode = mode;
1308 if (!d->mItemSyncFetchScope) {
1311 *(d->mItemSyncFetchScope) = fetchScope;
1317 d->mAutomaticProgressReporting = enabled;
1323 return d->dumpNotificationListToString();
1329 return d->dumpToString();
1335 return d->dumpMemoryInfo();
1341 return d->dumpMemoryInfoToString();
1344 #include "resourcebase.moc"
1345 #include "moc_resourcebase.cpp"
Job that modifies a collection in the Akonadi storage.
Helper class for expanding inter-resource collection moves inside ResourceBase.
void fetchAttribute(const QByteArray &type, bool fetch=true)
Sets whether the attribute of the given type should be fetched.
void retrieveCollectionAttributes(const Akonadi::Collection &collection)
Retrieve the attributes of a single collection from the backend.
void abortActivity()
Abort any activity in progress in the backend.
void disableRevisionCheck()
Disables the check of the revision number.
void percent(int progress)
This signal should be emitted whenever the progress of an action in the agent (e.g.
virtual void retrieveCollections()=0
Retrieve the collection tree from the remote server and supply it via collectionsRetrieved() or colle...
Collection::List collections() const
Returns the list of fetched collection.
void abortRequested()
Emitted when another application has remotely asked the agent to abort its current operation...
QString dumpNotificationListToString() const
Dump the contents of the current ChangeReplay.
void attributesSynchronized(qlonglong collectionId)
Emitted when a collection attributes synchronization has been completed.
void setUpdateGid(bool update)
Sets whether the GID shall be updated either from the gid parameter or by extracting it from the payl...
bool shouldList(ListPurpose purpose) const
Returns whether the collection should be listed or not for the specified purpose Takes enabled state ...
ChangeRecorder * changeRecorder() const
Returns the Akonadi::ChangeRecorder object used for monitoring.
void collectionsRetrievalDone()
Call this method to indicate you finished synchronizing the collection tree.
void setAutomaticProgressReporting(bool enabled)
Enable or disable automatic progress reporting.
void setCollectionStreamingEnabled(bool enable)
Enable collection streaming, that is collections don't have to be delivered at once as result of a re...
void synchronizeCollectionAttributes(qint64 id)
This method is called whenever the collection with the given id shall have its attributes synchronize...
Only list direct sub-collections of the base collection.
CollectionFetchScope & fetchScope()
Returns the collection fetch scope.
void setResource(const QString &resource)
Sets a resource filter, that is only collections owned by the specified resource are retrieved...
Represents a collection of PIM items.
Job that fetches collections from the Akonadi storage.
void itemsRetrieved(const Item::List &items)
Call this method to supply the full collection listing from the remote server.
void setListFilter(ListFilter)
Sets a filter for the collections to be listed.
static QString virtualMimeType()
Returns the mimetype used for virtual collections.
void setAgentName(const QString &name)
This method is used to set the name of the agent.
void agentNameChanged(const QString &name)
This signal is emitted whenever the name of the agent has changed.
static QString mimeType()
Returns the mimetype used for collections.
void setItemSynchronizationFetchScope(const ItemFetchScope &fetchScope)
Set the fetch scope applied for item synchronization.
void setKeepLocalCollectionChanges(const QSet< QByteArray > &parts)
Allows to keep locally changed collection parts during the collection sync.
void synchronizeCollectionTree()
Refetches the Collections.
void setTotalItems(int amount)
Call this method when you want to use the itemsRetrieved() method in streaming mode and indicate the ...
void nameChanged(const QString &name)
This signal is emitted whenever the name of the resource has changed.
void changesCommitted(const Item::List &items)
Resets the dirty flag of all given items and updates remote ids.
Item::List items() const
Returns the fetched items.
The base class for all Akonadi agents and resources.
Only fetch the base collection.
Syncs between items known to a client (usually a resource) and the Akonadi storage.
void itemsRetrievalDone()
Call this method to indicate you finished synchronizing the current collection.
void deferTask()
Stops the execution of the current task and continues with the next one.
ItemFetchScope & fetchScope()
Returns the item fetch scope.
SchedulePriority
Describes the scheduling priority of a task that has been queued for execution.
void synchronize()
This method is called whenever the resource should start synchronize all data.
void error(const QString &message)
This signal shall be used to report errors.
virtual int status() const
This method returns the current status code of the agent.
void clearCache()
Call this method to remove all items and collections of the resource from the server cache...
void collectionAttributesRetrieved(const Collection &collection)
Call this method from retrieveCollectionAttributes() once the result is available.
QString remoteId() const
Returns the remote id of the entity.
void collectionsRetrieved(const Collection::List &collections)
Call this to supply the full folder tree retrieved from the remote server.
static Collection root()
Returns the root collection.
Item currentItem() const
Returns the item that is currently retrieved.
Job that deletes a collection in the Akonadi storage.
void itemsRetrievedIncremental(const Item::List &changedItems, const Item::List &removedItems)
Call this method to supply incrementally retrieved items from the remote server.
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...
void doSetOnline(bool online)
Inherited from AgentBase.
Id id() const
Returns the unique identifier of the entity.
void collectionTreeSynchronized()
Emitted when a collection tree synchronization has been completed.
void setFetchScope(const CollectionFetchScope &fetchScope)
Sets the collection fetch scope.
void synchronizeCollection(qint64 id)
This method is called whenever the collection with the given id shall be synchronized.
Specifies which parts of an item should be fetched from the Akonadi storage.
QString identifier() const
Returns the instance identifier of this agent.
void setAncestorRetrieval(AncestorRetrieval ancestorDepth)
Sets how many levels of ancestor collections should be included in the retrieval. ...
void setItemTransactionMode(ItemSync::TransactionMode mode)
Set transaction mode for item sync'ing.
Helper job to invalidate item cache for an entire collection.
void setIgnorePayload(bool ignore)
Sets whether the payload of the modified item shall be omitted from transmission to the Akonadi stora...
TransactionMode
Transaction mode used by ItemSync.
void changeCommitted(const Item &item)
Resets the dirty flag of the given item and updates the remote id.
Base class for jobs that need to run a sequence of sub-jobs in a transaction.
void dumpMemoryInfo() const
Dumps memory usage information to stdout.
void setHierarchicalRemoteIdentifiersEnabled(bool enable)
Indicate the use of hierarchical remote identifiers.
bool isOnline() const
Returns whether the agent is currently online.
void itemRetrieved(const Item &item)
Call this method from retrieveItem() once the result is available.
void setCollection(const Akonadi::Collection &collection, const Akonadi::Collection &parentCollection)
Set the collection that is actually moved.
Job that modifies an existing item in the Akonadi storage.
Job that fetches items from the Akonadi storage.
Job that selects a resource context for remote identifier based operations.
Job that modifies a tag in the Akonadi storage.
~ResourceBase()
Destroys the base resource.
void changeProcessed()
Removes the previously emitted change from the records.
QStringList contentMimeTypes() const
Returns a list of possible content mimetypes, e.g.
static int init(int argc, char **argv)
Use this method in the main function of your resource application to initialize your resource subclas...
int itemSyncBatchSize() const
Returns the batch size used during the item sync.
void setItemStreamingEnabled(bool enable)
Enable item streaming.
QString name() const
Returns the name of the resource.
void taskDone()
Indicate that the current task is finished.
void cancelTask()
Stops the execution of the current task and continues with the next one.
bool isEmpty() const
Returns whether there are recorded changes.
void setItemSyncBatchSize(int batchSize)
Set the batch size used during the item sync.
Collection currentCollection() const
Returns the collection that is currently synchronized.
QString resource() const
Returns the identifier of the resource owning the collection.
QString agentName() const
Returns the name of the agent.
The user canceld this job.
void setDisableAutomaticItemDeliveryDone(bool disable)
Disables the automatic completion of the item sync, based on the number of delivered items...
ResourceBase(const QString &id)
Creates a base resource.
virtual QString errorString() const
Returns the error string, if there has been an error, an empty string otherwise.
The agent is working on something.
bool isValid() const
Returns whether the entity is valid.
void setTransactionMode(TransactionMode mode)
Set the transaction mode to use for this sync.
void collectionsRetrievedIncremental(const Collection::List &changedCollections, const Collection::List &removedCollections)
Call this to supply incrementally retrieved collections from the remote server.
static QString addNamespace(const QString &string)
Adds the multi-instance namespace to string if required (with '_' as separator).
void setName(const QString &name)
This method is used to set the name of the resource.
List all sub-collections.
Listing for synchronization.
QString dumpMemoryInfoToString() const
Returns a string with memory usage information.
QList< Collection > List
Describes a list of collections.
The base class for all Akonadi resources.
Only retrieve collections for synchronization, taking the local preference and enabled into account...
bool isVirtual() const
Returns whether the collection is virtual, for example a search collection.
QString dumpSchedulerToString() const
Dump the state of the scheduler.
void scheduleCustomTask(QObject *receiver, const char *method, const QVariant &argument, SchedulePriority priority=Append)
Schedules a custom task in the internal scheduler.
void setCacheOnly(bool cacheOnly)
Sets whether payload data should be requested from remote sources or just from the local cache...
void invalidateCache(const Collection &collection)
Call this method to invalidate all cached content in collection.