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

akonadi

  • akonadi
collectionsync.cpp
1/*
2 Copyright (c) 2007, 2009 Volker Krause <vkrause@kde.org>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19
20#include "collectionsync_p.h"
21#include "collection.h"
22
23#include "collectioncreatejob.h"
24#include "collectiondeletejob.h"
25#include "collectionfetchjob.h"
26#include "collectionmodifyjob.h"
27#include "collectionfetchscope.h"
28#include "collectionmovejob.h"
29
30#include "cachepolicy.h"
31
32#include <kdebug.h>
33#include <KLocalizedString>
34#include <QtCore/QVariant>
35
36using namespace Akonadi;
37
38struct RemoteNode;
39
43struct LocalNode
44{
45 LocalNode(const Collection &col)
46 : collection(col)
47 , processed(false)
48 {}
49
50 ~LocalNode()
51 {
52 qDeleteAll(childNodes);
53 qDeleteAll(pendingRemoteNodes);
54 }
55
56 Collection collection;
57 QList<LocalNode *> childNodes;
58 QHash<QString, LocalNode *> childRidMap;
62 QList<RemoteNode *> pendingRemoteNodes;
63 bool processed;
64};
65
66Q_DECLARE_METATYPE(LocalNode *)
67static const char LOCAL_NODE[] = "LocalNode";
68
73struct RemoteNode
74{
75 RemoteNode(const Collection &col)
76 : collection(col)
77 {}
78
79 Collection collection;
80};
81
82Q_DECLARE_METATYPE(RemoteNode *)
83static const char REMOTE_NODE[] = "RemoteNode";
84
85static const char CONTENTMIMETYPES[] = "CONTENTMIMETYPES";
86
90class CollectionSync::Private
91{
92public:
93 Private(CollectionSync *parent)
94 : q(parent)
95 , pendingJobs(0)
96 , progress(0)
97 , localRoot(0)
98 , currentTransaction(0)
99 , knownLocalCollections(0)
100 , incremental(false)
101 , streaming(false)
102 , hierarchicalRIDs(false)
103 , localListDone(false)
104 , deliveryDone(false)
105 {
106 }
107
108 ~Private()
109 {
110 delete localRoot;
111 qDeleteAll(rootRemoteNodes);
112 }
113
115 void resetNodeTree()
116 {
117 delete localRoot;
118 localRoot = new LocalNode(Collection::root());
119 localRoot->processed = true; // never try to delete that one
120 if (currentTransaction) {
121 // we are running the update transaction, initialize pending remote nodes
122 localRoot->pendingRemoteNodes.swap(rootRemoteNodes);
123 }
124
125 localUidMap.clear();
126 localRidMap.clear();
127 localUidMap.insert(localRoot->collection.id(), localRoot);
128 if (!hierarchicalRIDs) {
129 localRidMap.insert(QString(), localRoot);
130 }
131 }
132
134 LocalNode *createLocalNode(const Collection &col)
135 {
136 LocalNode *node = new LocalNode(col);
137 Q_ASSERT(!localUidMap.contains(col.id()));
138 localUidMap.insert(node->collection.id(), node);
139 if (!hierarchicalRIDs && !col.remoteId().isEmpty()) {
140 localRidMap.insert(node->collection.remoteId(), node);
141 }
142
143 // add already existing children
144 if (localPendingCollections.contains(col.id())) {
145 QVector<Collection::Id> childIds = localPendingCollections.take(col.id());
146 foreach (Collection::Id childId, childIds) {
147 Q_ASSERT(localUidMap.contains(childId));
148 LocalNode *childNode = localUidMap.value(childId);
149 node->childNodes.append(childNode);
150 if (!childNode->collection.remoteId().isEmpty()) {
151 node->childRidMap.insert(childNode->collection.remoteId(), childNode);
152 }
153 }
154 }
155
156 // set our parent and add ourselves as child
157 if (localUidMap.contains(col.parentCollection().id())) {
158 LocalNode *parentNode = localUidMap.value(col.parentCollection().id());
159 parentNode->childNodes.append(node);
160 if (!node->collection.remoteId().isEmpty()) {
161 parentNode->childRidMap.insert(node->collection.remoteId(), node);
162 }
163 } else {
164 localPendingCollections[col.parentCollection().id()].append(col.id());
165 }
166
167 return node;
168 }
169
171 void createRemoteNode(const Collection &col)
172 {
173 if (col.remoteId().isEmpty()) {
174 kWarning() << "Collection '" << col.name() << "' does not have a remote identifier - skipping";
175 return;
176 }
177 RemoteNode *node = new RemoteNode(col);
178 rootRemoteNodes.append(node);
179 }
180
182 void localCollectionsReceived(const Akonadi::Collection::List &localCols)
183 {
184 foreach (const Collection &c, localCols) {
185 createLocalNode(c);
186 knownLocalCollections++;
187 }
188 }
189
191 void localCollectionFetchResult(KJob *job)
192 {
193 if (job->error()) {
194 return; // handled by the base class
195 }
196
197 // safety check: the local tree has to be connected
198 if (!localPendingCollections.isEmpty()) {
199 q->setError(Unknown);
200 q->setErrorText(i18n("Inconsistent local collection tree detected."));
201 q->emitResult();
202 return;
203 }
204
205 localListDone = true;
206 execute();
207 }
208
214 LocalNode *findLocalChildNodeByName(LocalNode *localParentNode, const QString &name) const
215 {
216 if (name.isEmpty()) { // shouldn't happen...
217 return 0;
218 }
219
220 if (localParentNode == localRoot) { // possibly non-unique names on top-level
221 return 0;
222 }
223
224 foreach (LocalNode *childNode, localParentNode->childNodes) {
225 // the restriction on empty RIDs can possibly removed, but for now I only understand the implication for this case
226 if (childNode->collection.name() == name && childNode->collection.remoteId().isEmpty()) {
227 return childNode;
228 }
229 }
230 return 0;
231 }
232
237 LocalNode *findMatchingLocalNode(const Collection &collection) const
238 {
239 if (!hierarchicalRIDs) {
240 if (localRidMap.contains(collection.remoteId())) {
241 return localRidMap.value(collection.remoteId());
242 }
243 return 0;
244 } else {
245 if (collection.id() == Collection::root().id() || collection.remoteId() == Collection::root().remoteId()) {
246 return localRoot;
247 }
248 LocalNode *localParent = 0;
249 if (collection.parentCollection().id() < 0 && collection.parentCollection().remoteId().isEmpty()) {
250 kWarning() << "Remote collection without valid parent found: " << collection;
251 return 0;
252 }
253 if (collection.parentCollection().id() == Collection::root().id() || collection.parentCollection().remoteId() == Collection::root().remoteId()) {
254 localParent = localRoot;
255 } else {
256 localParent = findMatchingLocalNode(collection.parentCollection());
257 }
258
259 if (localParent) {
260 if (localParent->childRidMap.contains(collection.remoteId())) {
261 return localParent->childRidMap.value(collection.remoteId());
262 }
263 // check if we have a local folder with a matching name and no RID, if so let's use that one
264 // we would get an error if we don't do this anyway, as we'd try to create two sibling nodes with the same name
265 if (LocalNode *recoveredLocalNode = findLocalChildNodeByName(localParent, collection.name())) {
266 kDebug() << "Recovering collection with lost RID:" << collection << recoveredLocalNode->collection;
267 return recoveredLocalNode;
268 }
269 }
270 return 0;
271 }
272 }
273
279 LocalNode *findBestLocalAncestor(const Collection &collection, bool *exactMatch = 0)
280 {
281 if (!hierarchicalRIDs) {
282 return localRoot;
283 }
284 if (collection == Collection::root()) {
285 if (exactMatch) {
286 *exactMatch = true;
287 }
288 return localRoot;
289 }
290 if (collection.parentCollection().id() < 0 && collection.parentCollection().remoteId().isEmpty()) {
291 kWarning() << "Remote collection without valid parent found: " << collection;
292 return 0;
293 }
294 bool parentIsExact = false;
295 LocalNode *localParent = findBestLocalAncestor(collection.parentCollection(), &parentIsExact);
296 if (!parentIsExact) {
297 if (exactMatch) {
298 *exactMatch = false;
299 }
300 return localParent;
301 }
302 if (localParent->childRidMap.contains(collection.remoteId())) {
303 if (exactMatch) {
304 *exactMatch = true;
305 }
306 return localParent->childRidMap.value(collection.remoteId());
307 }
308 if (exactMatch) {
309 *exactMatch = false;
310 }
311 return localParent;
312 }
313
317 bool checkPendingRemoteNodes() const
318 {
319 if (rootRemoteNodes.size() != knownLocalCollections) {
320 return true;
321 }
322
323 foreach (RemoteNode *remoteNode, rootRemoteNodes) {
324 // every remote note should have a local node already
325 LocalNode *localNode = findMatchingLocalNode(remoteNode->collection);
326 if (localNode) {
327 if (checkLocalCollection(localNode, remoteNode)) {
328 return true;
329 }
330 } else {
331 return true;
332 }
333 }
334 return false;
335 }
336
342 void processPendingRemoteNodes(LocalNode *_localRoot)
343 {
344 QList<RemoteNode *> pendingRemoteNodes(_localRoot->pendingRemoteNodes);
345 _localRoot->pendingRemoteNodes.clear();
346 QHash<LocalNode *, QList<RemoteNode *> > pendingCreations;
347 foreach (RemoteNode *remoteNode, pendingRemoteNodes) {
348 // step 1: see if we have a matching local node already
349 LocalNode *localNode = findMatchingLocalNode(remoteNode->collection);
350 if (localNode) {
351 Q_ASSERT(!localNode->processed);
352 updateLocalCollection(localNode, remoteNode);
353 continue;
354 }
355 // step 2: check if we have the parent at least, then we can create it
356 localNode = findMatchingLocalNode(remoteNode->collection.parentCollection());
357 if (localNode) {
358 pendingCreations[localNode].append(remoteNode);
359 continue;
360 }
361 // step 3: find the best matching ancestor and enqueue it for later processing
362 localNode = findBestLocalAncestor(remoteNode->collection);
363 if (!localNode) {
364 q->setError(Unknown);
365 q->setErrorText(i18n("Remote collection without root-terminated ancestor chain provided, resource is broken."));
366 q->emitResult();
367 return;
368 }
369 localNode->pendingRemoteNodes.append(remoteNode);
370 }
371
372 // process the now possible collection creations
373 for (QHash<LocalNode *, QList<RemoteNode *> >::const_iterator it = pendingCreations.constBegin();
374 it != pendingCreations.constEnd(); ++it) {
375 createLocalCollections(it.key(), it.value());
376 }
377 }
378
382 bool checkLocalCollection(LocalNode *localNode, RemoteNode *remoteNode) const
383 {
384 const Collection &localCollection = localNode->collection;
385 const Collection &remoteCollection = remoteNode->collection;
386
387 if (!keepLocalChanges.contains(CONTENTMIMETYPES)) {
388 if (localCollection.contentMimeTypes().size() != remoteCollection.contentMimeTypes().size()) {
389 return true;
390 } else {
391 for (int i = 0; i < remoteCollection.contentMimeTypes().size(); i++) {
392 const QString &m = remoteCollection.contentMimeTypes().at(i);
393 if (!localCollection.contentMimeTypes().contains(m)) {
394 return true;
395 }
396 }
397 }
398 }
399
400 if (localCollection.parentCollection().remoteId() != remoteCollection.parentCollection().remoteId()) {
401 return true;
402 }
403 if (localCollection.name() != remoteCollection.name()) {
404 return true;
405 }
406 if (localCollection.remoteId() != remoteCollection.remoteId()) {
407 return true;
408 }
409 if (localCollection.remoteRevision() != remoteCollection.remoteRevision()) {
410 return true;
411 }
412 if (!(localCollection.cachePolicy() == remoteCollection.cachePolicy())) {
413 return true;
414 }
415
416 // CollectionModifyJob adds the remote attributes to the local collection
417 foreach (const Attribute *attr, remoteCollection.attributes()) {
418 const Attribute *localAttr = localCollection.attribute(attr->type());
419 if (localAttr && keepLocalChanges.contains(attr->type())) {
420 continue;
421 }
422 // The attribute must both exist and have equal contents
423 if (!localAttr || localAttr->serialized() != attr->serialized()) {
424 return true;
425 }
426 }
427
428 return false;
429 }
430
434 void updateLocalCollection(LocalNode *localNode, RemoteNode *remoteNode)
435 {
436 Collection upd(remoteNode->collection);
437 Q_ASSERT(!upd.remoteId().isEmpty());
438 Q_ASSERT(currentTransaction);
439 upd.setId(localNode->collection.id());
440 if (keepLocalChanges.contains(CONTENTMIMETYPES)) {
441 upd.setContentMimeTypes(localNode->collection.contentMimeTypes());
442 }
443 foreach (Attribute *remoteAttr, upd.attributes()) {
444 if (keepLocalChanges.contains(remoteAttr->type()) && localNode->collection.hasAttribute(remoteAttr->type())) {
445 //We don't want to overwrite the attribute changes with the defaults provided by the resource.
446 Attribute *localAttr = localNode->collection.attribute(remoteAttr->type());
447 upd.removeAttribute(localAttr->type());
448 upd.addAttribute(localAttr->clone());
449 }
450 }
451
452 {
453 // ### HACK to work around the implicit move attempts of CollectionModifyJob
454 // which we do explicitly below
455 Collection c(upd);
456 c.setParentCollection(localNode->collection.parentCollection());
457 ++pendingJobs;
458 CollectionModifyJob *mod = new CollectionModifyJob(c, currentTransaction);
459 connect(mod, SIGNAL(result(KJob*)), q, SLOT(updateLocalCollectionResult(KJob*)));
460 }
461
462 // detecting moves is only possible with global RIDs
463 if (!hierarchicalRIDs) {
464 LocalNode *oldParent = localUidMap.value(localNode->collection.parentCollection().id());
465 LocalNode *newParent = findMatchingLocalNode(remoteNode->collection.parentCollection());
466 // TODO: handle the newParent == 0 case correctly, ie. defer the move until the new
467 // local parent has been created
468 if (newParent && oldParent != newParent) {
469 ++pendingJobs;
470 CollectionMoveJob *move = new CollectionMoveJob(upd, newParent->collection, currentTransaction);
471 connect(move, SIGNAL(result(KJob*)), q, SLOT(updateLocalCollectionResult(KJob*)));
472 }
473 }
474
475 localNode->processed = true;
476 delete remoteNode;
477 }
478
479 void updateLocalCollectionResult(KJob *job)
480 {
481 --pendingJobs;
482 if (job->error()) {
483 return; // handled by the base class
484 }
485 if (qobject_cast<CollectionModifyJob *>(job)) {
486 ++progress;
487 }
488 checkDone();
489 }
490
495 void createLocalCollections(LocalNode *localParent, QList<RemoteNode *> remoteNodes)
496 {
497 foreach (RemoteNode *remoteNode, remoteNodes) {
498 ++pendingJobs;
499 Collection col(remoteNode->collection);
500 Q_ASSERT(!col.remoteId().isEmpty());
501 col.setParentCollection(localParent->collection);
502 CollectionCreateJob *create = new CollectionCreateJob(col, currentTransaction);
503 create->setProperty(LOCAL_NODE, QVariant::fromValue(localParent));
504 create->setProperty(REMOTE_NODE, QVariant::fromValue(remoteNode));
505 connect(create, SIGNAL(result(KJob*)), q, SLOT(createLocalCollectionResult(KJob*)));
506 }
507 }
508
509 void createLocalCollectionResult(KJob *job)
510 {
511 --pendingJobs;
512 if (job->error()) {
513 return; // handled by the base class
514 }
515
516 const Collection newLocal = static_cast<CollectionCreateJob *>(job)->collection();
517 LocalNode *localNode = createLocalNode(newLocal);
518 localNode->processed = true;
519
520 LocalNode *localParent = job->property(LOCAL_NODE).value<LocalNode *>();
521 Q_ASSERT(localParent->childNodes.contains(localNode));
522 RemoteNode *remoteNode = job->property(REMOTE_NODE).value<RemoteNode *>();
523 delete remoteNode;
524 ++progress;
525
526 processPendingRemoteNodes(localParent);
527 if (!hierarchicalRIDs) {
528 processPendingRemoteNodes(localRoot);
529 }
530
531 checkDone();
532 }
533
537 bool hasProcessedChildren(LocalNode *localNode) const
538 {
539 if (localNode->processed) {
540 return true;
541 }
542 foreach (LocalNode *child, localNode->childNodes) {
543 if (hasProcessedChildren(child)) {
544 return true;
545 }
546 }
547 return false;
548 }
549
554 Collection::List findUnprocessedLocalCollections(LocalNode *localNode) const
555 {
556 Collection::List rv;
557 if (!localNode->processed) {
558 if (hasProcessedChildren(localNode)) {
559 kWarning() << "Found unprocessed local node with processed children, excluding from deletion";
560 kWarning() << localNode->collection;
561 return rv;
562 }
563 if (localNode->collection.remoteId().isEmpty()) {
564 kWarning() << "Found unprocessed local node without remoteId, excluding from deletion";
565 kWarning() << localNode->collection;
566 return rv;
567 }
568 rv.append(localNode->collection);
569 return rv;
570 }
571
572 foreach (LocalNode *child, localNode->childNodes) {
573 rv.append(findUnprocessedLocalCollections(child));
574 }
575 return rv;
576 }
577
581 void deleteUnprocessedLocalNodes()
582 {
583 if (incremental) {
584 return;
585 }
586 const Collection::List cols = findUnprocessedLocalCollections(localRoot);
587 deleteLocalCollections(cols);
588 }
589
594 void deleteLocalCollections(const Collection::List &cols)
595 {
596 q->setTotalAmount(KJob::Bytes, q->totalAmount(KJob::Bytes) + cols.size());
597 foreach (const Collection &col, cols) {
598 Q_ASSERT(!col.remoteId().isEmpty()); // empty RID -> stuff we haven't even written to the remote side yet
599
600 ++pendingJobs;
601 Q_ASSERT(currentTransaction);
602 CollectionDeleteJob *job = new CollectionDeleteJob(col, currentTransaction);
603 connect(job, SIGNAL(result(KJob*)), q, SLOT(deleteLocalCollectionsResult(KJob*)));
604
605 // It can happen that the groupware servers report us deleted collections
606 // twice, in this case this collection delete job will fail on the second try.
607 // To avoid a rollback of the complete transaction we gracefully allow the job
608 // to fail :)
609 currentTransaction->setIgnoreJobFailure(job);
610 }
611 }
612
613 void deleteLocalCollectionsResult(KJob *)
614 {
615 --pendingJobs;
616
617 ++progress;
618 checkDone();
619 }
620
624 void checkUpdateNecessity()
625 {
626 bool updateNeeded = checkPendingRemoteNodes();
627 if (!updateNeeded) {
628 // We can end right now
629 q->emitResult();
630 return;
631 }
632
633 // Since there are differences with the remote collections we need to sync. Start a transaction here.
634 Q_ASSERT(!currentTransaction);
635 currentTransaction = new TransactionSequence(q);
636 currentTransaction->setAutomaticCommittingEnabled(false);
637 q->connect(currentTransaction, SIGNAL(result(KJob*)), SLOT(transactionSequenceResult(KJob*)));
638
639 // Now that a transaction is started we need to fetch local collections again and do the update
640 q->doStart();
641 }
642
644 void transactionSequenceResult(KJob *job)
645 {
646 if (job->error()) {
647 return; // handled by the base class
648 }
649
650 q->emitResult();
651 }
652
656 void execute()
657 {
658 kDebug() << Q_FUNC_INFO << "localListDone: " << localListDone << " deliveryDone: " << deliveryDone;
659 if (!localListDone || !deliveryDone) {
660 return;
661 }
662
663 // If a transaction is not started yet we are still checking if the update is
664 // actually needed.
665 if (!currentTransaction) {
666 checkUpdateNecessity();
667 return;
668 }
669
670 // Since the transaction is already running we need to execute the update.
671 processPendingRemoteNodes(localRoot);
672
673 if (!incremental && deliveryDone) {
674 deleteUnprocessedLocalNodes();
675 }
676
677 if (!hierarchicalRIDs) {
678 deleteLocalCollections(removedRemoteCollections);
679 } else {
680 Collection::List localCols;
681 foreach (const Collection &c, removedRemoteCollections) {
682 LocalNode *node = findMatchingLocalNode(c);
683 if (node) {
684 localCols.append(node->collection);
685 }
686 }
687 deleteLocalCollections(localCols);
688 }
689 removedRemoteCollections.clear();
690
691 checkDone();
692 }
693
697 QList<RemoteNode *> findPendingRemoteNodes(LocalNode *localNode)
698 {
699 QList<RemoteNode *> rv;
700 rv.append(localNode->pendingRemoteNodes);
701 foreach (LocalNode *child, localNode->childNodes) {
702 rv.append(findPendingRemoteNodes(child));
703 }
704 return rv;
705 }
706
711 void checkDone()
712 {
713 q->setProcessedAmount(KJob::Bytes, progress);
714
715 // still running jobs or not fully delivered local/remote state
716 if (!deliveryDone || pendingJobs > 0 || !localListDone) {
717 return;
718 }
719
720 // safety check: there must be no pending remote nodes anymore
721 QList<RemoteNode *> orphans = findPendingRemoteNodes(localRoot);
722 if (!orphans.isEmpty()) {
723 q->setError(Unknown);
724 q->setErrorText(i18n("Found unresolved orphan collections"));
725 foreach (RemoteNode *orphan, orphans) {
726 kDebug() << "found orphan collection:" << orphan->collection;
727 }
728 q->emitResult();
729 return;
730 }
731
732 kDebug() << Q_FUNC_INFO << "q->commit()";
733 Q_ASSERT(currentTransaction);
734 currentTransaction->commit();
735 }
736
737 CollectionSync *q;
738
739 QString resourceId;
740
741 int pendingJobs;
742 int progress;
743
744 LocalNode *localRoot;
745 TransactionSequence *currentTransaction;
746 QHash<Collection::Id, LocalNode *> localUidMap;
747 QHash<QString, LocalNode *> localRidMap;
748
749 // temporary during build-up of the local node tree, must be empty afterwards
750 QHash<Collection::Id, QVector<Collection::Id> > localPendingCollections;
751
752 // removed remote collections in incremental mode
753 Collection::List removedRemoteCollections;
754
755 // used to store the list of remote nodes passed by the user
756 QList<RemoteNode *> rootRemoteNodes;
757
758 // keep track of the total number of local collections that are known
759 // only used during the preliminary check to see if updating is needed
760 int knownLocalCollections;
761
762 bool incremental;
763 bool streaming;
764 bool hierarchicalRIDs;
765
766 bool localListDone;
767 bool deliveryDone;
768
769 // List of parts where local changes should not be overwritten
770 QSet<QByteArray> keepLocalChanges;
771};
772
773CollectionSync::CollectionSync(const QString &resourceId, QObject *parent)
774 : Job(parent)
775 , d(new Private(this))
776{
777 d->resourceId = resourceId;
778 setTotalAmount(KJob::Bytes, 0);
779}
780
781CollectionSync::~CollectionSync()
782{
783 delete d;
784}
785
786void CollectionSync::setRemoteCollections(const Collection::List &remoteCollections)
787{
788 setTotalAmount(KJob::Bytes, totalAmount(KJob::Bytes) + remoteCollections.count());
789 foreach (const Collection &c, remoteCollections) {
790 d->createRemoteNode(c);
791 }
792
793 if (!d->streaming) {
794 d->deliveryDone = true;
795 }
796 d->execute();
797}
798
799void CollectionSync::setRemoteCollections(const Collection::List &changedCollections, const Collection::List &removedCollections)
800{
801 setTotalAmount(KJob::Bytes, totalAmount(KJob::Bytes) + changedCollections.count());
802 d->incremental = true;
803 foreach (const Collection &c, changedCollections) {
804 d->createRemoteNode(c);
805 }
806 d->removedRemoteCollections += removedCollections;
807
808 if (!d->streaming) {
809 d->deliveryDone = true;
810 }
811 d->execute();
812}
813
814void CollectionSync::doStart()
815{
816 d->resetNodeTree();
817 Job *parent = (d->currentTransaction ? static_cast<Job *>(d->currentTransaction) : static_cast<Job *>(this));
818 CollectionFetchJob *job = new CollectionFetchJob(Collection::root(), CollectionFetchJob::Recursive, parent);
819 job->fetchScope().setResource(d->resourceId);
820 job->fetchScope().setIncludeUnsubscribed(true);
821 job->fetchScope().setAncestorRetrieval(CollectionFetchScope::Parent);
822 connect(job, SIGNAL(collectionsReceived(Akonadi::Collection::List)),
823 SLOT(localCollectionsReceived(Akonadi::Collection::List)));
824 connect(job, SIGNAL(result(KJob*)), SLOT(localCollectionFetchResult(KJob*)));
825}
826
827void CollectionSync::setStreamingEnabled(bool streaming)
828{
829 d->streaming = streaming;
830}
831
832void CollectionSync::retrievalDone()
833{
834 d->deliveryDone = true;
835 d->execute();
836}
837
838void CollectionSync::setHierarchicalRemoteIds(bool hierarchical)
839{
840 d->hierarchicalRIDs = hierarchical;
841}
842
843void CollectionSync::rollback()
844{
845 if (d->currentTransaction) {
846 d->currentTransaction->rollback();
847 }
848}
849
850void CollectionSync::setKeepLocalChanges(const QSet<QByteArray> &parts)
851{
852 d->keepLocalChanges = parts;
853}
854
855#include "moc_collectionsync_p.cpp"
Akonadi::Attribute
Provides interface for custom attributes for Entity.
Definition attribute.h:139
Akonadi::Attribute::serialized
virtual QByteArray serialized() const =0
Returns a QByteArray representation of the attribute which will be storaged.
Akonadi::Attribute::clone
virtual Attribute * clone() const =0
Creates a copy of this attribute.
Akonadi::Attribute::type
virtual QByteArray type() const =0
Returns the type of the attribute.
Akonadi::CollectionCreateJob
Job that creates a new collection in the Akonadi storage.
Definition collectioncreatejob.h:53
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::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::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::setIncludeUnsubscribed
AKONADI_DEPRECATED void setIncludeUnsubscribed(bool include)
Sets whether unsubscribed collections should be included in the collection listing.
Definition collectionfetchscope.cpp:94
Akonadi::CollectionFetchScope::setAncestorRetrieval
void setAncestorRetrieval(AncestorRetrieval ancestorDepth)
Sets how many levels of ancestor collections should be included in the retrieval.
Definition collectionfetchscope.cpp:138
Akonadi::CollectionFetchScope::Parent
@ Parent
Only retrieve the immediate parent collection.
Definition collectionfetchscope.h:76
Akonadi::CollectionModifyJob
Job that modifies a collection in the Akonadi storage.
Definition collectionmodifyjob.h:83
Akonadi::CollectionMoveJob
Job that moves a collection in the Akonadi storage to a new parent collection.
Definition collectionmovejob.h:51
Akonadi::CollectionSync
Definition collectionsync_p.h:54
Akonadi::CollectionSync::rollback
void rollback()
Do a rollback operation if needed.
Definition collectionsync.cpp:843
Akonadi::CollectionSync::~CollectionSync
~CollectionSync()
Destroys this job.
Definition collectionsync.cpp:781
Akonadi::CollectionSync::setStreamingEnabled
void setStreamingEnabled(bool streaming)
Enables streaming, that is not all collections are delivered at once.
Definition collectionsync.cpp:827
Akonadi::CollectionSync::setKeepLocalChanges
void setKeepLocalChanges(const QSet< QByteArray > &parts)
Allows to specify parts of the collection that should not be changed if locally available.
Definition collectionsync.cpp:850
Akonadi::CollectionSync::retrievalDone
void retrievalDone()
Indicate that all collections have been retrieved in streaming mode.
Definition collectionsync.cpp:832
Akonadi::CollectionSync::setHierarchicalRemoteIds
void setHierarchicalRemoteIds(bool hierarchical)
Indicate whether the resource supplies collections with hierarchical or global remote identifiers.
Definition collectionsync.cpp:838
Akonadi::CollectionSync::CollectionSync
CollectionSync(const QString &resourceId, QObject *parent=0)
Creates a new collection synchronzier.
Definition collectionsync.cpp:773
Akonadi::CollectionSync::doStart
void doStart()
This method must be reimplemented in the concrete jobs.
Definition collectionsync.cpp:814
Akonadi::CollectionSync::setRemoteCollections
void setRemoteCollections(const Collection::List &remoteCollections)
Sets the result of a full remote collection listing.
Definition collectionsync.cpp:786
Akonadi::Collection
Represents a collection of PIM items.
Definition collection.h:76
Akonadi::Collection::contentMimeTypes
QStringList contentMimeTypes() const
Returns a list of possible content mimetypes, e.g.
Definition collection.cpp:115
Akonadi::Collection::root
static Collection root()
Returns the root collection.
Definition collection.cpp:192
Akonadi::Collection::cachePolicy
CachePolicy cachePolicy() const
Returns the cache policy of the collection.
Definition collection.cpp:249
Akonadi::Collection::List
QList< Collection > List
Describes a list of collections.
Definition collection.h:81
Akonadi::Collection::name
QString name() const
Returns the i18n'ed name of the collection.
Definition collection.cpp:81
Akonadi::Entity::remoteId
QString remoteId() const
Returns the remote id of the entity.
Definition entity.cpp:82
Akonadi::Entity::remoteRevision
QString remoteRevision() const
Returns the remote revision of the entity.
Definition entity.cpp:92
Akonadi::Entity::parentCollection
Collection parentCollection() const
Returns the parent collection of this object.
Definition entity.cpp:185
Akonadi::Entity::attributes
Attribute::List attributes() const
Returns a list of all attributes of the entity.
Definition entity.cpp:153
Akonadi::Entity::hasAttribute
bool hasAttribute(const QByteArray &name) const
Returns true if the entity has an attribute of the given type name, false otherwise.
Definition entity.cpp:148
Akonadi::Entity::setParentCollection
void setParentCollection(const Collection &parent)
Set the parent collection of this object.
Definition entity.cpp:194
Akonadi::Entity::id
Id id() const
Returns the unique identifier of the entity.
Definition entity.cpp:72
Akonadi::Entity::Id
qint64 Id
Describes the unique id type.
Definition entity.h:65
Akonadi::Entity::attribute
Attribute * attribute(const QByteArray &name) const
Returns the attribute of the given type name if available, 0 otherwise.
Definition entity.cpp:167
Akonadi::Job
Base class for all actions in the Akonadi storage.
Definition job.h:87
Akonadi::Job::Unknown
@ Unknown
Unknown error.
Definition job.h:108
Akonadi::TransactionSequence
Base class for jobs that need to run a sequence of sub-jobs in a transaction.
Definition transactionsequence.h:70
Akonadi::TransactionSequence::commit
void commit()
Commits the transaction as soon as all pending sub-jobs finished successfully.
Definition transactionsequence.cpp:154
Akonadi::TransactionSequence::setIgnoreJobFailure
void setIgnoreJobFailure(KJob *job)
Sets which job of the sequence might fail without rolling back the complete transaction.
Definition transactionsequence.cpp:186
Akonadi::TransactionSequence::rollback
void rollback()
Rolls back the current transaction as soon as possible.
Definition transactionsequence.cpp:215
Akonadi::TransactionSequence::setAutomaticCommittingEnabled
void setAutomaticCommittingEnabled(bool enable)
Disable automatic committing.
Definition transactionsequence.cpp:209
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