97
currentTransaction( 0 ),
98
knownLocalCollections( 0 ),
94
99
incremental( false ),
95
100
streaming( false ),
96
101
hierarchicalRIDs( false ),
97
102
localListDone( false ),
98
103
deliveryDone( false )
110
qDeleteAll( rootRemoteNodes );
113
/** Utility method to reset the node tree. */
100
117
localRoot = new LocalNode( Collection::root() );
101
118
localRoot->processed = true; // never try to delete that one
119
if ( currentTransaction ) {
120
// we are running the update transaction, initialize pending remote nodes
121
localRoot->pendingRemoteNodes.swap( rootRemoteNodes );
102
126
localUidMap.insert( localRoot->collection.id(), localRoot );
103
127
if ( !hierarchicalRIDs ) {
104
128
localRidMap.insert( QString(), localRoot );
113
132
/** Create a local node from the given local collection and integrate it into the local tree structure. */
114
133
LocalNode* createLocalNode( const Collection &col )
157
176
RemoteNode *node = new RemoteNode( col );
158
localRoot->pendingRemoteNodes.append( node );
177
rootRemoteNodes.append( node );
161
180
/** Create local nodes as we receive the local listing from the Akonadi server. */
162
181
void localCollectionsReceived( const Akonadi::Collection::List &localCols )
164
foreach ( const Collection &c, localCols )
183
foreach ( const Collection &c, localCols ) {
165
184
createLocalNode( c );
185
knownLocalCollections++;
168
189
/** Once the local collection listing finished we can continue with the interesting stuff. */
189
210
* @note This is used as a fallback if the resource lost the RID update somehow.
190
211
* This can be used because the Akonadi server enforces unique child collection names inside the hierarchy
192
LocalNode* findLocalChildNodeByName( LocalNode *localParentNode, const QString &name )
213
LocalNode* findLocalChildNodeByName( LocalNode *localParentNode, const QString &name ) const
194
215
if ( name.isEmpty() ) { // shouldn't happen...
212
233
Find the local node that matches the given remote collection, returns 0
213
234
if that doesn't exist (yet).
215
LocalNode* findMatchingLocalNode( const Collection &collection )
236
LocalNode* findMatchingLocalNode( const Collection &collection ) const
217
238
if ( !hierarchicalRIDs ) {
218
239
if ( localRidMap.contains( collection.remoteId() ) ) {
314
Checks if any of the remote nodes is not equal to the current local one. If so return true.
316
bool checkPendingRemoteNodes() const
318
if ( rootRemoteNodes.size() != knownLocalCollections ) {
322
foreach ( RemoteNode *remoteNode, rootRemoteNodes ) {
323
// every remote note should have a local node already
324
LocalNode *localNode = findMatchingLocalNode( remoteNode->collection );
326
if ( checkLocalCollection( localNode, remoteNode ) ) {
293
337
Checks the pending remote nodes attached to the given local root node
294
338
to see if any of them can be processed by now. If not, they are moved to
295
339
the closest ancestor available.
379
Checks if the given localNode and remoteNode are different
381
bool checkLocalCollection( LocalNode *localNode, RemoteNode *remoteNode ) const
383
const Collection &localCollection = localNode->collection;
384
const Collection &remoteCollection = remoteNode->collection;
386
if ( localCollection.contentMimeTypes().size() != remoteCollection.contentMimeTypes().size() ) {
389
for ( int i = 0; i < remoteCollection.contentMimeTypes().size(); i++ ) {
390
const QString &m = remoteCollection.contentMimeTypes().at( i );
391
if( !localCollection.contentMimeTypes().contains( m ) ) {
397
if ( localCollection.parentCollection().remoteId() != remoteCollection.parentCollection().remoteId() ) {
400
if ( localCollection.name() != remoteCollection.name() ) {
403
if ( localCollection.remoteId() != remoteCollection.remoteId() ) {
406
if ( localCollection.remoteRevision() != remoteCollection.remoteRevision() ) {
409
if ( !(localCollection.cachePolicy() == remoteCollection.cachePolicy()) ) {
413
// CollectionModifyJob adds the remote attributes to the local collection
414
foreach ( const Attribute* attr, remoteCollection.attributes() ) {
415
const Attribute* localAttr = localCollection.attribute( attr->type() );
416
// The attribute must both exist and have equal contents
417
if ( !localAttr || localAttr->serialized() != attr->serialized() ) {
335
426
Performs a local update for the given node pair.
337
428
void updateLocalCollection( LocalNode *localNode, RemoteNode *remoteNode )
339
430
Collection upd( remoteNode->collection );
340
431
Q_ASSERT( !upd.remoteId().isEmpty() );
432
Q_ASSERT( currentTransaction );
341
433
upd.setId( localNode->collection.id() );
342
434
if ( localNode->collection.attribute<EntityDisplayAttribute>() ) {
343
435
upd.removeAttribute<EntityDisplayAttribute>();
350
442
Collection c( upd );
351
443
c.setParentCollection( localNode->collection.parentCollection() );
353
CollectionModifyJob *mod = new CollectionModifyJob( c, q );
445
CollectionModifyJob *mod = new CollectionModifyJob( c, currentTransaction );
354
446
connect( mod, SIGNAL(result(KJob*)), q, SLOT(updateLocalCollectionResult(KJob*)) );
362
454
// local parent has been created
363
455
if ( newParent && oldParent != newParent ) {
365
CollectionMoveJob *move = new CollectionMoveJob( upd, newParent->collection, q );
457
CollectionMoveJob *move = new CollectionMoveJob( upd, newParent->collection, currentTransaction );
366
458
connect( move, SIGNAL(result(KJob*)), q, SLOT(updateLocalCollectionResult(KJob*)) );
394
486
Collection col( remoteNode->collection );
395
487
Q_ASSERT( !col.remoteId().isEmpty() );
396
488
col.setParentCollection( localParent->collection );
397
CollectionCreateJob *create = new CollectionCreateJob( col, q );
489
CollectionCreateJob *create = new CollectionCreateJob( col, currentTransaction );
398
490
create->setProperty( LOCAL_NODE, QVariant::fromValue( localParent ) );
399
491
create->setProperty( REMOTE_NODE, QVariant::fromValue( remoteNode ) );
400
492
connect( create, SIGNAL(result(KJob*)), q, SLOT(createLocalCollectionResult(KJob*)) );
493
585
Q_ASSERT( !col.remoteId().isEmpty() ); // empty RID -> stuff we haven't even written to the remote side yet
496
CollectionDeleteJob *job = new CollectionDeleteJob( col, q );
588
Q_ASSERT( currentTransaction );
589
CollectionDeleteJob *job = new CollectionDeleteJob( col, currentTransaction );
497
590
connect( job, SIGNAL(result(KJob*)), q, SLOT(deleteLocalCollectionsResult(KJob*)) );
499
592
// It can happen that the groupware servers report us deleted collections
500
593
// twice, in this case this collection delete job will fail on the second try.
501
594
// To avoid a rollback of the complete transaction we gracefully allow the job
503
q->setIgnoreJobFailure( job );
596
currentTransaction->setIgnoreJobFailure( job );
609
Check update necessity.
611
void checkUpdateNecessity()
613
bool updateNeeded = checkPendingRemoteNodes();
614
if ( !updateNeeded ) {
615
// We can end right now
620
// Since there are differences with the remote collections we need to sync. Start a transaction here.
621
Q_ASSERT( !currentTransaction );
622
currentTransaction = new TransactionSequence( q );
623
currentTransaction->setAutomaticCommittingEnabled( false );
624
q->connect( currentTransaction, SIGNAL(result(KJob*)), SLOT(transactionSequenceResult(KJob*)) );
626
// Now that a transaction is started we need to fetch local collections again and do the update
630
/** After the transaction has finished report we're done as well. */
631
void transactionSequenceResult( KJob *job )
633
if ( job->error() ) {
634
return; // handled by the base class
516
641
Process what's currently available.
650
// If a transaction is not started yet we are still checking if the update is
652
if ( !currentTransaction ) {
653
checkUpdateNecessity();
657
// Since the transaction is already running we need to execute the update.
525
658
processPendingRemoteNodes( localRoot );
527
660
if ( !incremental && deliveryDone ) {
604
739
// removed remote collections in incremental mode
605
740
Collection::List removedRemoteCollections;
742
// used to store the list of remote nodes passed by the user
743
QList<RemoteNode*> rootRemoteNodes;
745
// keep track of the total number of local collections that are known
746
// only used during the preliminary check to see if updating is needed
747
int knownLocalCollections;
607
749
bool incremental;
609
751
bool hierarchicalRIDs;
656
798
void CollectionSync::doStart()
658
CollectionFetchJob *job = new CollectionFetchJob( Collection::root(), CollectionFetchJob::Recursive, this );
801
Job *parent = ( d->currentTransaction ? static_cast<Job*>( d->currentTransaction ) : static_cast<Job*>( this ) );
802
CollectionFetchJob *job = new CollectionFetchJob( Collection::root(), CollectionFetchJob::Recursive, parent );
659
803
job->fetchScope().setResource( d->resourceId );
660
804
job->fetchScope().setIncludeUnsubscribed( true );
661
805
job->fetchScope().setAncestorRetrieval( CollectionFetchScope::Parent );
680
824
d->hierarchicalRIDs = hierarchical;
827
void CollectionSync::rollback()
829
if ( d->currentTransaction ) {
830
d->currentTransaction->rollback();
683
834
#include "moc_collectionsync_p.cpp"