akonadi
collectionsync.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "collectionsync_p.h"
00021 #include "collection.h"
00022
00023 #include "collectioncreatejob.h"
00024 #include "collectiondeletejob.h"
00025 #include "collectionfetchjob.h"
00026 #include "collectionmodifyjob.h"
00027
00028
00029 #include <kdebug.h>
00030
00031 using namespace Akonadi;
00032
00036 class CollectionSync::Private
00037 {
00038 public:
00039 Private() :
00040 pendingJobs( 0 ),
00041 incremental( false ),
00042 streaming( false )
00043 {
00044 }
00045
00046 QString resourceId;
00047
00048
00049 QHash<QString,Collection> localCollections;
00050 QSet<Collection> unprocessedLocalCollections;
00051
00052
00053 QHash<Collection::Id, Collection> remoteCollections;
00054
00055
00056 QList<Collection> orphanRemoteCollections;
00057
00058
00059 Collection::List removedRemoteCollections;
00060
00061
00062 int pendingJobs;
00063
00064 bool incremental;
00065 bool streaming;
00066 };
00067
00068 CollectionSync::CollectionSync( const QString &resourceId, QObject *parent ) :
00069 TransactionSequence( parent ),
00070 d( new Private )
00071 {
00072 d->resourceId = resourceId;
00073 }
00074
00075 CollectionSync::~CollectionSync()
00076 {
00077 delete d;
00078 }
00079
00080 void CollectionSync::setRemoteCollections(const Collection::List & remoteCollections)
00081 {
00082 foreach ( const Collection &c, remoteCollections ) {
00083 d->remoteCollections.insert( c.id(), c );
00084 }
00085 if ( !d->streaming )
00086 retrievalDone();
00087 }
00088
00089 void CollectionSync::setRemoteCollections(const Collection::List & changedCollections, const Collection::List & removedCollections)
00090 {
00091 d->incremental = true;
00092 foreach ( const Collection &c, changedCollections ) {
00093 d->remoteCollections.insert( c.id(), c );
00094 }
00095 d->removedRemoteCollections += removedCollections;
00096 if ( !d->streaming )
00097 retrievalDone();
00098 }
00099
00100 void CollectionSync::doStart()
00101 {
00102 }
00103
00104 void CollectionSync::slotLocalListDone(KJob * job)
00105 {
00106 if ( job->error() )
00107 return;
00108
00109 Collection::List list = static_cast<CollectionFetchJob*>( job )->collections();
00110 foreach ( const Collection &c, list ) {
00111 d->localCollections.insert( c.remoteId(), c );
00112 d->unprocessedLocalCollections.insert( c );
00113 }
00114
00115
00116
00117 foreach ( const Collection &c, d->remoteCollections ) {
00118 if ( c.remoteId().isEmpty() ) {
00119 kWarning( 5250 ) << "Collection '" << c.name() <<"' does not have a remote identifier - skipping";
00120 continue;
00121 }
00122
00123 Collection local = d->localCollections.value( c.remoteId() );
00124 d->unprocessedLocalCollections.remove( local );
00125
00126 if ( !local.isValid() ) {
00127
00128 Collection localParent;
00129 if ( c.parent() >= 0 )
00130 localParent = Collection( c.parent() );
00131 if ( c.parentRemoteId().isEmpty() )
00132 localParent = Collection::root();
00133 else
00134 localParent = d->localCollections.value( c.parentRemoteId() );
00135
00136
00137 if ( !localParent.isValid() ) {
00138 d->orphanRemoteCollections << c;
00139 continue;
00140 }
00141
00142 createLocalCollection( c, localParent );
00143 continue;
00144 }
00145
00146
00147 d->pendingJobs++;
00148 Collection upd( c );
00149 upd.setId( local.id() );
00150 CollectionModifyJob *mod = new CollectionModifyJob( upd, this );
00151 connect( mod, SIGNAL(result(KJob*)), SLOT(slotLocalChangeDone(KJob*)) );
00152 }
00153
00154
00155 if ( !d->incremental )
00156 d->removedRemoteCollections = d->unprocessedLocalCollections.toList();
00157 foreach ( const Collection &c, d->removedRemoteCollections ) {
00158 d->pendingJobs++;
00159 CollectionDeleteJob *job = new CollectionDeleteJob( c, this );
00160 connect( job, SIGNAL(result(KJob*)), SLOT(slotLocalChangeDone(KJob*)) );
00161 }
00162 d->localCollections.clear();
00163
00164 checkDone();
00165 }
00166
00167 void CollectionSync::slotLocalCreateDone(KJob * job)
00168 {
00169 d->pendingJobs--;
00170 if ( job->error() )
00171 return;
00172
00173 Collection newLocal = static_cast<CollectionCreateJob*>( job )->collection();
00174
00175
00176
00177 Collection::List stillOrphans;
00178 foreach ( const Collection &orphan, d->orphanRemoteCollections ) {
00179 if ( orphan.parentRemoteId() == newLocal.remoteId() ) {
00180 createLocalCollection( orphan, newLocal );
00181 } else {
00182 stillOrphans << orphan;
00183 }
00184 }
00185 d->orphanRemoteCollections = stillOrphans;
00186
00187 checkDone();
00188 }
00189
00190 void CollectionSync::createLocalCollection(const Collection & c, const Collection & parent)
00191 {
00192 d->pendingJobs++;
00193 Collection col( c );
00194 col.setParent( parent );
00195 CollectionCreateJob *create = new CollectionCreateJob( col, this );
00196 connect( create, SIGNAL(result(KJob*)), SLOT(slotLocalCreateDone(KJob*)) );
00197 }
00198
00199 void CollectionSync::checkDone()
00200 {
00201
00202 if ( d->pendingJobs > 0 )
00203 return;
00204
00205
00206 if ( !d->orphanRemoteCollections.isEmpty() ) {
00207 setError( Unknown );
00208 setErrorText( QLatin1String( "Found unresolved orphan collections" ) );
00209 foreach ( const Collection &col, d->orphanRemoteCollections )
00210 kDebug() << "found orphan collection:" << col.remoteId() << "parent:" << col.parentRemoteId();
00211 }
00212
00213 commit();
00214 }
00215
00216 void CollectionSync::slotLocalChangeDone(KJob * job)
00217 {
00218 if ( job->error() )
00219 return;
00220 d->pendingJobs--;
00221 checkDone();
00222 }
00223
00224 void CollectionSync::setStreamingEnabled( bool streaming )
00225 {
00226 d->streaming = streaming;
00227 }
00228
00229 void CollectionSync::retrievalDone()
00230 {
00231 CollectionFetchJob *job = new CollectionFetchJob( Collection::root(), CollectionFetchJob::Recursive, this );
00232 job->setResource( d->resourceId );
00233 connect( job, SIGNAL(result(KJob*)), SLOT(slotLocalListDone(KJob*)) );
00234 }
00235
00236 #include "collectionsync_p.moc"