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.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 {
00043 }
00044
00045 QString resourceId;
00046
00047
00048 QHash<QString,Collection> localCollections;
00049 QSet<Collection> unprocessedLocalCollections;
00050
00051
00052 QHash<Collection::Id, Collection> remoteCollections;
00053
00054
00055 QList<Collection> orphanRemoteCollections;
00056
00057
00058 Collection::List removedRemoteCollections;
00059
00060
00061 int pendingJobs;
00062
00063 bool incremental;
00064 };
00065
00066 CollectionSync::CollectionSync( const QString &resourceId, QObject *parent ) :
00067 TransactionSequence( parent ),
00068 d( new Private )
00069 {
00070 d->resourceId = resourceId;
00071 }
00072
00073 CollectionSync::~CollectionSync()
00074 {
00075 delete d;
00076 }
00077
00078 void CollectionSync::setRemoteCollections(const Collection::List & remoteCollections)
00079 {
00080 foreach ( const Collection &c, remoteCollections ) {
00081 d->remoteCollections.insert( c.id(), c );
00082 }
00083 }
00084
00085 void CollectionSync::setRemoteCollections(const Collection::List & changedCollections, const Collection::List & removedCollections)
00086 {
00087 d->incremental = true;
00088 foreach ( const Collection &c, changedCollections ) {
00089 d->remoteCollections.insert( c.id(), c );
00090 }
00091 d->removedRemoteCollections = removedCollections;
00092 }
00093
00094 void CollectionSync::doStart()
00095 {
00096 CollectionFetchJob *job = new CollectionFetchJob( Collection::root(), CollectionFetchJob::Recursive, this );
00097 job->setResource( d->resourceId );
00098 connect( job, SIGNAL(result(KJob*)), SLOT(slotLocalListDone(KJob*)) );
00099 }
00100
00101 void CollectionSync::slotLocalListDone(KJob * job)
00102 {
00103 if ( job->error() )
00104 return;
00105
00106 Collection::List list = static_cast<CollectionFetchJob*>( job )->collections();
00107 foreach ( const Collection &c, list ) {
00108 d->localCollections.insert( c.remoteId(), c );
00109 d->unprocessedLocalCollections.insert( c );
00110 }
00111
00112
00113
00114 foreach ( const Collection &c, d->remoteCollections ) {
00115 if ( c.remoteId().isEmpty() ) {
00116 kWarning( 5250 ) << "Collection '" << c.name() <<"' does not have a remote identifier - skipping";
00117 continue;
00118 }
00119
00120 Collection local = d->localCollections.value( c.remoteId() );
00121 d->unprocessedLocalCollections.remove( local );
00122
00123 if ( !local.isValid() ) {
00124
00125 Collection localParent;
00126 if ( c.parent() >= 0 )
00127 localParent = Collection( c.parent() );
00128 if ( c.parentRemoteId().isEmpty() )
00129 localParent = Collection::root();
00130 else
00131 localParent = d->localCollections.value( c.parentRemoteId() );
00132
00133
00134 if ( !localParent.isValid() ) {
00135 d->orphanRemoteCollections << c;
00136 continue;
00137 }
00138
00139 createLocalCollection( c, localParent );
00140 continue;
00141 }
00142
00143
00144 d->pendingJobs++;
00145 Collection upd( c );
00146 upd.setId( local.id() );
00147 CollectionModifyJob *mod = new CollectionModifyJob( upd, this );
00148 connect( mod, SIGNAL(result(KJob*)), SLOT(slotLocalChangeDone(KJob*)) );
00149 }
00150
00151
00152 if ( !d->incremental )
00153 d->removedRemoteCollections = d->unprocessedLocalCollections.toList();
00154 foreach ( const Collection &c, d->removedRemoteCollections ) {
00155 d->pendingJobs++;
00156 CollectionDeleteJob *job = new CollectionDeleteJob( c, this );
00157 connect( job, SIGNAL(result(KJob*)), SLOT(slotLocalChangeDone(KJob*)) );
00158 }
00159 d->localCollections.clear();
00160
00161 checkDone();
00162 }
00163
00164 void CollectionSync::slotLocalCreateDone(KJob * job)
00165 {
00166 d->pendingJobs--;
00167 if ( job->error() )
00168 return;
00169
00170 Collection newLocal = static_cast<CollectionCreateJob*>( job )->collection();
00171
00172
00173
00174 Collection::List stillOrphans;
00175 foreach ( const Collection &orphan, d->orphanRemoteCollections ) {
00176 if ( orphan.parentRemoteId() == newLocal.remoteId() ) {
00177 createLocalCollection( orphan, newLocal );
00178 } else {
00179 stillOrphans << orphan;
00180 }
00181 }
00182 d->orphanRemoteCollections = stillOrphans;
00183
00184 checkDone();
00185 }
00186
00187 void CollectionSync::createLocalCollection(const Collection & c, const Collection & parent)
00188 {
00189 d->pendingJobs++;
00190 Collection col( c );
00191 col.setParent( parent );
00192 CollectionCreateJob *create = new CollectionCreateJob( col, this );
00193 connect( create, SIGNAL(result(KJob*)), SLOT(slotLocalCreateDone(KJob*)) );
00194 }
00195
00196 void CollectionSync::checkDone()
00197 {
00198
00199 if ( d->pendingJobs > 0 )
00200 return;
00201
00202
00203 if ( !d->orphanRemoteCollections.isEmpty() ) {
00204 setError( Unknown );
00205 setErrorText( QLatin1String( "Found unresolved orphan collections" ) );
00206 foreach ( const Collection &col, d->orphanRemoteCollections )
00207 kDebug() << "found orphan collection:" << col.remoteId() << "parent:" << col.parentRemoteId();
00208 }
00209
00210 commit();
00211 }
00212
00213 void CollectionSync::slotLocalChangeDone(KJob * job)
00214 {
00215 if ( job->error() )
00216 return;
00217 d->pendingJobs--;
00218 checkDone();
00219 }
00220
00221 #include "collectionsync.moc"