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

akonadi

resourcebase.cpp
00001 /*
00002     Copyright (c) 2006 Till Adam <adam@kde.org>
00003     Copyright (c) 2007 Volker Krause <vkrause@kde.org>
00004 
00005     This library is free software; you can redistribute it and/or modify it
00006     under the terms of the GNU Library General Public License as published by
00007     the Free Software Foundation; either version 2 of the License, or (at your
00008     option) any later version.
00009 
00010     This library is distributed in the hope that it will be useful, but WITHOUT
00011     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00012     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00013     License for more details.
00014 
00015     You should have received a copy of the GNU Library General Public License
00016     along with this library; see the file COPYING.LIB.  If not, write to the
00017     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00018     02110-1301, USA.
00019 */
00020 
00021 #include "resourcebase.h"
00022 #include "agentbase_p.h"
00023 
00024 #include "resourceadaptor.h"
00025 #include "collectiondeletejob.h"
00026 #include "collectionsync_p.h"
00027 #include "dbusconnectionpool.h"
00028 #include "itemsync.h"
00029 #include "kdepimlibs-version.h"
00030 #include "resourcescheduler_p.h"
00031 #include "tracerinterface.h"
00032 #include "xdgbasedirs_p.h"
00033 
00034 #include "changerecorder.h"
00035 #include "collectionfetchjob.h"
00036 #include "collectionfetchscope.h"
00037 #include "collectionmodifyjob.h"
00038 #include "invalidatecachejob_p.h"
00039 #include "itemfetchjob.h"
00040 #include "itemfetchscope.h"
00041 #include "itemmodifyjob.h"
00042 #include "itemmodifyjob_p.h"
00043 #include "session.h"
00044 #include "resourceselectjob_p.h"
00045 #include "monitor_p.h"
00046 #include "servermanager_p.h"
00047 
00048 #include <kaboutdata.h>
00049 #include <kcmdlineargs.h>
00050 #include <kdebug.h>
00051 #include <klocale.h>
00052 
00053 #include <QtCore/QDebug>
00054 #include <QtCore/QDir>
00055 #include <QtCore/QHash>
00056 #include <QtCore/QSettings>
00057 #include <QtCore/QTimer>
00058 #include <QtGui/QApplication>
00059 #include <QtDBus/QtDBus>
00060 
00061 using namespace Akonadi;
00062 
00063 class Akonadi::ResourceBasePrivate : public AgentBasePrivate
00064 {
00065   Q_OBJECT
00066   Q_CLASSINFO( "D-Bus Interface", "org.kde.dfaure" )
00067 
00068   public:
00069     ResourceBasePrivate( ResourceBase *parent )
00070       : AgentBasePrivate( parent ),
00071         scheduler( 0 ),
00072         mItemSyncer( 0 ),
00073         mItemSyncFetchScope( 0 ),
00074         mItemTransactionMode( ItemSync::SingleTransaction ),
00075         mCollectionSyncer( 0 ),
00076         mHierarchicalRid( false ),
00077         mUnemittedProgress( 0 ),
00078         mAutomaticProgressReporting( true )
00079     {
00080       Internal::setClientType( Internal::Resource );
00081       mStatusMessage = defaultReadyMessage();
00082       mProgressEmissionCompressor.setInterval( 1000 );
00083       mProgressEmissionCompressor.setSingleShot( true );
00084     }
00085 
00086     ~ResourceBasePrivate()
00087     {
00088       delete mItemSyncFetchScope;
00089     }
00090 
00091     Q_DECLARE_PUBLIC( ResourceBase )
00092 
00093     void delayedInit()
00094     {
00095       if ( !DBusConnectionPool::threadConnection().registerService( QLatin1String( "org.freedesktop.Akonadi.Resource." ) + mId ) ) {
00096         QString reason = DBusConnectionPool::threadConnection().lastError().message();
00097         if ( reason.isEmpty() ) {
00098           reason = QString::fromLatin1( "this service is probably running already." );
00099         }
00100         kError() << "Unable to register service at D-Bus: " << reason;
00101 
00102         if ( QThread::currentThread() == QCoreApplication::instance()->thread() )
00103           QCoreApplication::instance()->exit(1);
00104 
00105       } else {
00106         AgentBasePrivate::delayedInit();
00107       }
00108     }
00109 
00110     virtual void changeProcessed()
00111     {
00112       mChangeRecorder->changeProcessed();
00113       if ( !mChangeRecorder->isEmpty() )
00114         scheduler->scheduleChangeReplay();
00115       scheduler->taskDone();
00116     }
00117 
00118     void slotAbortRequested();
00119 
00120     void slotDeliveryDone( KJob* job );
00121     void slotCollectionSyncDone( KJob *job );
00122     void slotLocalListDone( KJob *job );
00123     void slotSynchronizeCollection( const Collection &col );
00124     void slotCollectionListDone( KJob *job );
00125     void slotSynchronizeCollectionAttributes( const Collection &col );
00126     void slotCollectionListForAttributesDone( KJob *job );
00127     void slotCollectionAttributesSyncDone( KJob *job );
00128 
00129     void slotItemSyncDone( KJob *job );
00130 
00131     void slotPercent( KJob* job, unsigned long percent );
00132     void slotDelayedEmitProgress();
00133     void slotDeleteResourceCollection();
00134     void slotDeleteResourceCollectionDone( KJob *job );
00135     void slotCollectionDeletionDone( KJob *job );
00136 
00137     void slotInvalidateCache( const Akonadi::Collection &collection );
00138 
00139     void slotPrepareItemRetrieval( const Akonadi::Item &item );
00140     void slotPrepareItemRetrievalResult( KJob* job );
00141 
00142     void changeCommittedResult( KJob* job );
00143 
00144     void slotSessionReconnected()
00145     {
00146       Q_Q( ResourceBase );
00147 
00148       new ResourceSelectJob( q->identifier() );
00149     }
00150 
00151     void createItemSyncInstanceIfMissing()
00152     {
00153       Q_Q( ResourceBase );
00154       Q_ASSERT_X( scheduler->currentTask().type == ResourceScheduler::SyncCollection,
00155                   "createItemSyncInstance", "Calling items retrieval methods although no item retrieval is in progress" );
00156       if ( !mItemSyncer ) {
00157         mItemSyncer = new ItemSync( q->currentCollection() );
00158         mItemSyncer->setTransactionMode( mItemTransactionMode );
00159         if ( mItemSyncFetchScope )
00160           mItemSyncer->setFetchScope( *mItemSyncFetchScope );
00161         mItemSyncer->setProperty( "collection", QVariant::fromValue( q->currentCollection() ) );
00162         connect( mItemSyncer, SIGNAL(percent(KJob*,ulong)), q, SLOT(slotPercent(KJob*,ulong)) );
00163         connect( mItemSyncer, SIGNAL(result(KJob*)), q, SLOT(slotItemSyncDone(KJob*)) );
00164       }
00165       Q_ASSERT( mItemSyncer );
00166     }
00167 
00168   public Q_SLOTS:
00169     // Dump the contents of the current ChangeReplay
00170     Q_SCRIPTABLE QString dumpNotificationListToString() const
00171     {
00172       return mChangeRecorder->dumpNotificationListToString();
00173     }
00174 
00175     // Dump the state of the scheduler
00176     Q_SCRIPTABLE QString dumpToString() const
00177     {
00178       return scheduler->dumpToString();
00179     }
00180 
00181     Q_SCRIPTABLE void dump()
00182     {
00183       scheduler->dump();
00184     }
00185 
00186     Q_SCRIPTABLE void clear()
00187     {
00188       scheduler->clear();
00189     }
00190 
00191   protected Q_SLOTS:
00192     // reimplementations from AgentbBasePrivate, containing sanity checks that only apply to resources
00193     // such as making sure that RIDs are present as well as translations of cross-resource moves
00194     // TODO: we could possibly add recovery code for no-RID notifications by re-enquing those to the change recorder
00195     // as the corresponding Add notifications, although that contains a risk of endless fail/retry loops
00196 
00197     void itemAdded(const Akonadi::Item& item, const Akonadi::Collection& collection)
00198     {
00199       if ( collection.remoteId().isEmpty() ) {
00200         changeProcessed();
00201         return;
00202       }
00203       AgentBasePrivate::itemAdded( item, collection );
00204     }
00205 
00206     void itemChanged(const Akonadi::Item& item, const QSet< QByteArray >& partIdentifiers)
00207     {
00208       if ( item.remoteId().isEmpty() ) {
00209         changeProcessed();
00210         return;
00211       }
00212       AgentBasePrivate::itemChanged( item, partIdentifiers );
00213     }
00214 
00215     // TODO move the move translation code from AgebtBasePrivate here, it's wrong for agents
00216     void itemMoved(const Akonadi::Item &item, const Akonadi::Collection &source, const Akonadi::Collection &destination)
00217     {
00218       if ( item.remoteId().isEmpty() || destination.remoteId().isEmpty() || destination == source ) {
00219         changeProcessed();
00220         return;
00221       }
00222       AgentBasePrivate::itemMoved( item, source, destination );
00223     }
00224 
00225     void itemRemoved(const Akonadi::Item& item)
00226     {
00227       if ( item.remoteId().isEmpty() ) {
00228         changeProcessed();
00229         return;
00230       }
00231       AgentBasePrivate::itemRemoved( item );
00232     }
00233 
00234     void collectionAdded(const Akonadi::Collection& collection, const Akonadi::Collection& parent)
00235     {
00236       if ( parent.remoteId().isEmpty() ) {
00237         changeProcessed();
00238         return;
00239       }
00240       AgentBasePrivate::collectionAdded( collection, parent );
00241     }
00242 
00243     void collectionChanged(const Akonadi::Collection& collection)
00244     {
00245       if ( collection.remoteId().isEmpty() ) {
00246         changeProcessed();
00247         return;
00248       }
00249       AgentBasePrivate::collectionChanged( collection );
00250     }
00251 
00252     void collectionChanged(const Akonadi::Collection& collection, const QSet< QByteArray >& partIdentifiers)
00253     {
00254       if ( collection.remoteId().isEmpty() ) {
00255         changeProcessed();
00256         return;
00257       }
00258       AgentBasePrivate::collectionChanged( collection, partIdentifiers );
00259     }
00260 
00261     // TODO move the move translation code from AgebtBasePrivate here, it's wrong for agents
00262     void collectionMoved(const Akonadi::Collection& collection, const Akonadi::Collection& source, const Akonadi::Collection& destination)
00263     {
00264       if ( collection.remoteId().isEmpty() || destination.remoteId().isEmpty() || source == destination ) {
00265         changeProcessed();
00266         return;
00267       }
00268       AgentBasePrivate::collectionMoved( collection, source, destination );
00269     }
00270 
00271     void collectionRemoved(const Akonadi::Collection& collection)
00272     {
00273       if ( collection.remoteId().isEmpty() ) {
00274         changeProcessed();
00275         return;
00276       }
00277       AgentBasePrivate::collectionRemoved( collection );
00278     }
00279 
00280   public:
00281     // synchronize states
00282     Collection currentCollection;
00283 
00284     ResourceScheduler *scheduler;
00285     ItemSync *mItemSyncer;
00286     ItemFetchScope *mItemSyncFetchScope;
00287     ItemSync::TransactionMode mItemTransactionMode;
00288     CollectionSync *mCollectionSyncer;
00289     bool mHierarchicalRid;
00290     QTimer mProgressEmissionCompressor;
00291     int mUnemittedProgress;
00292     QMap<Akonadi::Collection::Id, QVariantMap> mUnemittedAdvancedStatus;
00293     bool mAutomaticProgressReporting;
00294 };
00295 
00296 ResourceBase::ResourceBase( const QString & id )
00297   : AgentBase( new ResourceBasePrivate( this ), id )
00298 {
00299   Q_D( ResourceBase );
00300 
00301   new Akonadi__ResourceAdaptor( this );
00302 
00303   d->scheduler = new ResourceScheduler( this );
00304 
00305   d->mChangeRecorder->setChangeRecordingEnabled( true );
00306   connect( d->mChangeRecorder, SIGNAL(changesAdded()),
00307            d->scheduler, SLOT(scheduleChangeReplay()) );
00308 
00309   d->mChangeRecorder->setResourceMonitored( d->mId.toLatin1() );
00310   d->mChangeRecorder->fetchCollection( true );
00311 
00312   connect( d->scheduler, SIGNAL(executeFullSync()),
00313            SLOT(retrieveCollections()) );
00314   connect( d->scheduler, SIGNAL(executeCollectionTreeSync()),
00315            SLOT(retrieveCollections()) );
00316   connect( d->scheduler, SIGNAL(executeCollectionSync(Akonadi::Collection)),
00317            SLOT(slotSynchronizeCollection(Akonadi::Collection)) );
00318   connect( d->scheduler, SIGNAL(executeCollectionAttributesSync(Akonadi::Collection)),
00319            SLOT(slotSynchronizeCollectionAttributes(Akonadi::Collection)) );
00320   connect( d->scheduler, SIGNAL(executeItemFetch(Akonadi::Item,QSet<QByteArray>)),
00321            SLOT(slotPrepareItemRetrieval(Akonadi::Item)) );
00322   connect( d->scheduler, SIGNAL(executeResourceCollectionDeletion()),
00323            SLOT(slotDeleteResourceCollection()) );
00324   connect ( d->scheduler, SIGNAL(executeCacheInvalidation(Akonadi::Collection)),
00325             SLOT(slotInvalidateCache(Akonadi::Collection)) );
00326   connect( d->scheduler, SIGNAL(status(int,QString)),
00327            SIGNAL(status(int,QString)) );
00328   connect( d->scheduler, SIGNAL(executeChangeReplay()),
00329            d->mChangeRecorder, SLOT(replayNext()) );
00330   connect( d->scheduler, SIGNAL(fullSyncComplete()), SIGNAL(synchronized()) );
00331   connect( d->scheduler, SIGNAL(collectionTreeSyncComplete()), SIGNAL(collectionTreeSynchronized()) );
00332   connect( d->mChangeRecorder, SIGNAL(nothingToReplay()), d->scheduler, SLOT(taskDone()) );
00333   connect( d->mChangeRecorder, SIGNAL(collectionRemoved(Akonadi::Collection)),
00334            d->scheduler, SLOT(collectionRemoved(Akonadi::Collection)) );
00335   connect( this, SIGNAL(abortRequested()), this, SLOT(slotAbortRequested()) );
00336   connect( this, SIGNAL(synchronized()), d->scheduler, SLOT(taskDone()) );
00337   connect( this, SIGNAL(collectionTreeSynchronized()), d->scheduler, SLOT(taskDone()) );
00338   connect( this, SIGNAL(agentNameChanged(QString)),
00339            this, SIGNAL(nameChanged(QString)) );
00340 
00341   connect( &d->mProgressEmissionCompressor, SIGNAL(timeout()),
00342            this, SLOT(slotDelayedEmitProgress()) );
00343 
00344   d->scheduler->setOnline( d->mOnline );
00345   if ( !d->mChangeRecorder->isEmpty() )
00346     d->scheduler->scheduleChangeReplay();
00347 
00348   DBusConnectionPool::threadConnection().registerObject( QLatin1String( "/Debug" ), d, QDBusConnection::ExportScriptableSlots );
00349 
00350   new ResourceSelectJob( identifier() );
00351 
00352   connect( d->mChangeRecorder->session(), SIGNAL(reconnected()), SLOT(slotSessionReconnected()) );
00353 }
00354 
00355 ResourceBase::~ResourceBase()
00356 {
00357 }
00358 
00359 void ResourceBase::synchronize()
00360 {
00361   d_func()->scheduler->scheduleFullSync();
00362 }
00363 
00364 void ResourceBase::setName( const QString &name )
00365 {
00366   AgentBase::setAgentName( name );
00367 }
00368 
00369 QString ResourceBase::name() const
00370 {
00371   return AgentBase::agentName();
00372 }
00373 
00374 QString ResourceBase::parseArguments( int argc, char **argv )
00375 {
00376   QString identifier;
00377   if ( argc < 3 ) {
00378     kDebug() << "Not enough arguments passed...";
00379     exit( 1 );
00380   }
00381 
00382   for ( int i = 1; i < argc - 1; ++i ) {
00383     if ( QLatin1String( argv[ i ] ) == QLatin1String( "--identifier" ) )
00384       identifier = QLatin1String( argv[ i + 1 ] );
00385   }
00386 
00387   if ( identifier.isEmpty() ) {
00388     kDebug() << "Identifier argument missing";
00389     exit( 1 );
00390   }
00391 
00392   const QFileInfo fi( QString::fromLocal8Bit( argv[0] ) );
00393   // strip off full path and possible .exe suffix
00394   const QByteArray catalog = fi.baseName().toLatin1();
00395 
00396   KCmdLineArgs::init( argc, argv, identifier.toLatin1(), catalog,
00397                       ki18nc( "@title application name", "Akonadi Resource" ), KDEPIMLIBS_VERSION,
00398                       ki18nc( "@title application description", "Akonadi Resource" ) );
00399 
00400   KCmdLineOptions options;
00401   options.add( "identifier <argument>",
00402                ki18nc( "@label commandline option", "Resource identifier" ) );
00403   KCmdLineArgs::addCmdLineOptions( options );
00404 
00405   return identifier;
00406 }
00407 
00408 int ResourceBase::init( ResourceBase *r )
00409 {
00410   QApplication::setQuitOnLastWindowClosed( false );
00411   KGlobal::locale()->insertCatalog( QLatin1String( "libakonadi" ) );
00412   int rv = kapp->exec();
00413   delete r;
00414   return rv;
00415 }
00416 
00417 void ResourceBasePrivate::slotAbortRequested()
00418 {
00419   Q_Q( ResourceBase );
00420 
00421   scheduler->cancelQueues();
00422   QMetaObject::invokeMethod( q, "abortActivity" );
00423 }
00424 
00425 void ResourceBase::itemRetrieved( const Item &item )
00426 {
00427   Q_D( ResourceBase );
00428   Q_ASSERT( d->scheduler->currentTask().type == ResourceScheduler::FetchItem );
00429   if ( !item.isValid() ) {
00430     d->scheduler->currentTask().sendDBusReplies( false );
00431     d->scheduler->taskDone();
00432     return;
00433   }
00434 
00435   Item i( item );
00436   QSet<QByteArray> requestedParts = d->scheduler->currentTask().itemParts;
00437   foreach ( const QByteArray &part, requestedParts ) {
00438     if ( !item.loadedPayloadParts().contains( part ) ) {
00439       kWarning() << "Item does not provide part" << part;
00440     }
00441   }
00442 
00443   ItemModifyJob *job = new ItemModifyJob( i );
00444   // FIXME: remove once the item with which we call retrieveItem() has a revision number
00445   job->disableRevisionCheck();
00446   connect( job, SIGNAL(result(KJob*)), SLOT(slotDeliveryDone(KJob*)) );
00447 }
00448 
00449 void ResourceBasePrivate::slotDeliveryDone(KJob * job)
00450 {
00451   Q_Q( ResourceBase );
00452   Q_ASSERT( scheduler->currentTask().type == ResourceScheduler::FetchItem );
00453   if ( job->error() ) {
00454     emit q->error( QLatin1String( "Error while creating item: " ) + job->errorString() );
00455   }
00456   scheduler->currentTask().sendDBusReplies( !job->error() );
00457   scheduler->taskDone();
00458 }
00459 
00460 void ResourceBase::collectionAttributesRetrieved( const Collection &collection )
00461 {
00462   Q_D( ResourceBase );
00463   Q_ASSERT( d->scheduler->currentTask().type == ResourceScheduler::SyncCollectionAttributes );
00464   if ( !collection.isValid() ) {
00465     emit attributesSynchronized( d->scheduler->currentTask().collection.id() );
00466     d->scheduler->taskDone();
00467     return;
00468   }
00469 
00470   CollectionModifyJob *job = new CollectionModifyJob( collection );
00471   connect( job, SIGNAL(result(KJob*)), SLOT(slotCollectionAttributesSyncDone(KJob*)) );
00472 }
00473 
00474 void ResourceBasePrivate::slotCollectionAttributesSyncDone(KJob * job)
00475 {
00476   Q_Q( ResourceBase );
00477   Q_ASSERT( scheduler->currentTask().type == ResourceScheduler::SyncCollectionAttributes );
00478   if ( job->error() ) {
00479     emit q->error( QLatin1String( "Error while updating collection: " ) + job->errorString() );
00480   }
00481   emit q->attributesSynchronized( scheduler->currentTask().collection.id() );
00482   scheduler->taskDone();
00483 }
00484 
00485 void ResourceBasePrivate::slotDeleteResourceCollection()
00486 {
00487   Q_Q( ResourceBase );
00488 
00489   CollectionFetchJob *job = new CollectionFetchJob( Collection::root(), CollectionFetchJob::FirstLevel );
00490   job->fetchScope().setResource( q->identifier() );
00491   connect( job, SIGNAL(result(KJob*)), q, SLOT(slotDeleteResourceCollectionDone(KJob*)) );
00492 }
00493 
00494 void ResourceBasePrivate::slotDeleteResourceCollectionDone( KJob *job )
00495 {
00496   Q_Q( ResourceBase );
00497   if ( job->error() ) {
00498     emit q->error( job->errorString() );
00499     scheduler->taskDone();
00500   } else {
00501     const CollectionFetchJob *fetchJob = static_cast<const CollectionFetchJob*>( job );
00502 
00503     if ( !fetchJob->collections().isEmpty() ) {
00504       CollectionDeleteJob *job = new CollectionDeleteJob( fetchJob->collections().first() );
00505       connect( job, SIGNAL(result(KJob*)), q, SLOT(slotCollectionDeletionDone(KJob*)) );
00506     } else {
00507       // there is no resource collection, so just ignore the request
00508       scheduler->taskDone();
00509     }
00510   }
00511 }
00512 
00513 void ResourceBasePrivate::slotCollectionDeletionDone( KJob *job )
00514 {
00515   Q_Q( ResourceBase );
00516   if ( job->error() ) {
00517     emit q->error( job->errorString() );
00518   }
00519 
00520   scheduler->taskDone();
00521 }
00522 
00523 void ResourceBasePrivate::slotInvalidateCache( const Akonadi::Collection &collection )
00524 {
00525   Q_Q( ResourceBase );
00526   InvalidateCacheJob *job = new InvalidateCacheJob( collection, q );
00527   connect( job, SIGNAL(result(KJob*)), scheduler, SLOT(taskDone()) );
00528 }
00529 
00530 void ResourceBase::changeCommitted( const Item& item )
00531 {
00532   Q_D( ResourceBase );
00533   ItemModifyJob *job = new ItemModifyJob( item );
00534   job->d_func()->setClean();
00535   job->disableRevisionCheck(); // TODO: remove, but where/how do we handle the error?
00536   job->setIgnorePayload( true ); // we only want to reset the dirty flag and update the remote id
00537   d->changeProcessed();
00538 }
00539 
00540 void ResourceBase::changeCommitted( const Collection &collection )
00541 {
00542   CollectionModifyJob *job = new CollectionModifyJob( collection );
00543   connect( job, SIGNAL(result(KJob*)), SLOT(changeCommittedResult(KJob*)) );
00544 }
00545 
00546 void ResourceBasePrivate::changeCommittedResult( KJob *job )
00547 {
00548   Q_Q( ResourceBase );
00549   if ( job->error() )
00550     emit q->error( i18nc( "@info", "Updating local collection failed: %1.", job->errorText() ) );
00551   mChangeRecorder->d_ptr->invalidateCache( static_cast<CollectionModifyJob*>( job )->collection() );
00552   changeProcessed();
00553 }
00554 
00555 bool ResourceBase::requestItemDelivery( qint64 uid, const QString & remoteId,
00556                                         const QString &mimeType, const QStringList &_parts )
00557 {
00558   Q_D( ResourceBase );
00559   if ( !isOnline() ) {
00560     emit error( i18nc( "@info", "Cannot fetch item in offline mode." ) );
00561     return false;
00562   }
00563 
00564   setDelayedReply( true );
00565   // FIXME: we need at least the revision number too
00566   Item item( uid );
00567   item.setMimeType( mimeType );
00568   item.setRemoteId( remoteId );
00569 
00570   QSet<QByteArray> parts;
00571   Q_FOREACH( const QString &str, _parts )
00572     parts.insert( str.toLatin1() );
00573 
00574   d->scheduler->scheduleItemFetch( item, parts, message().createReply() );
00575 
00576   return true;
00577 }
00578 
00579 void ResourceBase::collectionsRetrieved( const Collection::List & collections )
00580 {
00581   Q_D( ResourceBase );
00582   Q_ASSERT_X( d->scheduler->currentTask().type == ResourceScheduler::SyncCollectionTree ||
00583               d->scheduler->currentTask().type == ResourceScheduler::SyncAll,
00584               "ResourceBase::collectionsRetrieved()",
00585               "Calling collectionsRetrieved() although no collection retrieval is in progress" );
00586   if ( !d->mCollectionSyncer ) {
00587     d->mCollectionSyncer = new CollectionSync( identifier() );
00588     d->mCollectionSyncer->setHierarchicalRemoteIds( d->mHierarchicalRid );
00589     connect( d->mCollectionSyncer, SIGNAL(percent(KJob*,ulong)), SLOT(slotPercent(KJob*,ulong)) );
00590     connect( d->mCollectionSyncer, SIGNAL(result(KJob*)), SLOT(slotCollectionSyncDone(KJob*)) );
00591   }
00592   d->mCollectionSyncer->setRemoteCollections( collections );
00593 }
00594 
00595 void ResourceBase::collectionsRetrievedIncremental( const Collection::List & changedCollections,
00596                                                     const Collection::List & removedCollections )
00597 {
00598   Q_D( ResourceBase );
00599   Q_ASSERT_X( d->scheduler->currentTask().type == ResourceScheduler::SyncCollectionTree ||
00600               d->scheduler->currentTask().type == ResourceScheduler::SyncAll,
00601               "ResourceBase::collectionsRetrievedIncremental()",
00602               "Calling collectionsRetrievedIncremental() although no collection retrieval is in progress" );
00603   if ( !d->mCollectionSyncer ) {
00604     d->mCollectionSyncer = new CollectionSync( identifier() );
00605     d->mCollectionSyncer->setHierarchicalRemoteIds( d->mHierarchicalRid );
00606     connect( d->mCollectionSyncer, SIGNAL(percent(KJob*,ulong)), SLOT(slotPercent(KJob*,ulong)) );
00607     connect( d->mCollectionSyncer, SIGNAL(result(KJob*)), SLOT(slotCollectionSyncDone(KJob*)) );
00608   }
00609   d->mCollectionSyncer->setRemoteCollections( changedCollections, removedCollections );
00610 }
00611 
00612 void ResourceBase::setCollectionStreamingEnabled( bool enable )
00613 {
00614   Q_D( ResourceBase );
00615   Q_ASSERT_X( d->scheduler->currentTask().type == ResourceScheduler::SyncCollectionTree ||
00616               d->scheduler->currentTask().type == ResourceScheduler::SyncAll,
00617               "ResourceBase::setCollectionStreamingEnabled()",
00618               "Calling setCollectionStreamingEnabled() although no collection retrieval is in progress" );
00619   if ( !d->mCollectionSyncer ) {
00620     d->mCollectionSyncer = new CollectionSync( identifier() );
00621     d->mCollectionSyncer->setHierarchicalRemoteIds( d->mHierarchicalRid );
00622     connect( d->mCollectionSyncer, SIGNAL(percent(KJob*,ulong)), SLOT(slotPercent(KJob*,ulong)) );
00623     connect( d->mCollectionSyncer, SIGNAL(result(KJob*)), SLOT(slotCollectionSyncDone(KJob*)) );
00624   }
00625   d->mCollectionSyncer->setStreamingEnabled( enable );
00626 }
00627 
00628 void ResourceBase::collectionsRetrievalDone()
00629 {
00630   Q_D( ResourceBase );
00631   Q_ASSERT_X( d->scheduler->currentTask().type == ResourceScheduler::SyncCollectionTree ||
00632               d->scheduler->currentTask().type == ResourceScheduler::SyncAll,
00633               "ResourceBase::collectionsRetrievalDone()",
00634               "Calling collectionsRetrievalDone() although no collection retrieval is in progress" );
00635   // streaming enabled, so finalize the sync
00636   if ( d->mCollectionSyncer ) {
00637     d->mCollectionSyncer->retrievalDone();
00638   }
00639   // user did the sync himself, we are done now
00640   else {
00641     // FIXME: we need the same special case for SyncAll as in slotCollectionSyncDone here!
00642     d->scheduler->taskDone();
00643   }
00644 }
00645 
00646 void ResourceBasePrivate::slotCollectionSyncDone( KJob * job )
00647 {
00648   Q_Q( ResourceBase );
00649   mCollectionSyncer = 0;
00650   if ( job->error() ) {
00651     if ( job->error() != Job::UserCanceled )
00652       emit q->error( job->errorString() );
00653   } else {
00654     if ( scheduler->currentTask().type == ResourceScheduler::SyncAll ) {
00655       CollectionFetchJob *list = new CollectionFetchJob( Collection::root(), CollectionFetchJob::Recursive );
00656       list->setFetchScope( q->changeRecorder()->collectionFetchScope() );
00657       list->fetchScope().setResource( mId );
00658       q->connect( list, SIGNAL(result(KJob*)), q, SLOT(slotLocalListDone(KJob*)) );
00659       return;
00660     } else if ( scheduler->currentTask().type == ResourceScheduler::SyncCollectionTree ) {
00661       scheduler->scheduleCollectionTreeSyncCompletion();
00662     }
00663   }
00664   scheduler->taskDone();
00665 }
00666 
00667 void ResourceBasePrivate::slotLocalListDone( KJob * job )
00668 {
00669   Q_Q( ResourceBase );
00670   if ( job->error() ) {
00671     emit q->error( job->errorString() );
00672   } else {
00673     Collection::List cols = static_cast<CollectionFetchJob*>( job )->collections();
00674     foreach ( const Collection &col, cols ) {
00675       scheduler->scheduleSync( col );
00676     }
00677     scheduler->scheduleFullSyncCompletion();
00678   }
00679   scheduler->taskDone();
00680 }
00681 
00682 void ResourceBasePrivate::slotSynchronizeCollection( const Collection &col )
00683 {
00684   Q_Q( ResourceBase );
00685   currentCollection = col;
00686   // check if this collection actually can contain anything
00687   QStringList contentTypes = currentCollection.contentMimeTypes();
00688   contentTypes.removeAll( Collection::mimeType() );
00689   if ( !contentTypes.isEmpty() || (col.rights() & (Collection::CanLinkItem)) ) { // HACK to check for virtual collections
00690     if ( mAutomaticProgressReporting ) {
00691       emit q->status( AgentBase::Running, i18nc( "@info:status", "Syncing folder '%1'", currentCollection.name() ) );
00692     }
00693     q->retrieveItems( currentCollection );
00694     return;
00695   }
00696   scheduler->taskDone();
00697 }
00698 
00699 void ResourceBasePrivate::slotSynchronizeCollectionAttributes( const Collection &col )
00700 {
00701   Q_Q( ResourceBase );
00702   QMetaObject::invokeMethod( q, "retrieveCollectionAttributes", Q_ARG( Akonadi::Collection, col ) );
00703 }
00704 
00705 void ResourceBasePrivate::slotPrepareItemRetrieval( const Akonadi::Item &item )
00706 {
00707   Q_Q( ResourceBase );
00708   ItemFetchJob *fetch = new ItemFetchJob( item, this );
00709   fetch->fetchScope().setAncestorRetrieval( q->changeRecorder()->itemFetchScope().ancestorRetrieval() );
00710   fetch->fetchScope().setCacheOnly( true );
00711 
00712   // copy list of attributes to fetch
00713   const QSet<QByteArray> attributes = q->changeRecorder()->itemFetchScope().attributes();
00714   foreach ( const QByteArray &attribute, attributes )
00715     fetch->fetchScope().fetchAttribute( attribute );
00716 
00717   q->connect( fetch, SIGNAL(result(KJob*)), SLOT(slotPrepareItemRetrievalResult(KJob*)) );
00718 }
00719 
00720 void ResourceBasePrivate::slotPrepareItemRetrievalResult( KJob* job )
00721 {
00722   Q_Q( ResourceBase );
00723   Q_ASSERT_X( scheduler->currentTask().type == ResourceScheduler::FetchItem,
00724             "ResourceBasePrivate::slotPrepareItemRetrievalResult()",
00725             "Preparing item retrieval although no item retrieval is in progress" );
00726   if ( job->error() ) {
00727     q->cancelTask( job->errorText() );
00728     return;
00729   }
00730   ItemFetchJob *fetch = qobject_cast<ItemFetchJob*>( job );
00731   if ( fetch->items().count() != 1 ) {
00732     q->cancelTask( i18n( "The requested item no longer exists" ) );
00733     return;
00734   }
00735   const Item item = fetch->items().first();
00736   const QSet<QByteArray> parts = scheduler->currentTask().itemParts;
00737   if ( !q->retrieveItem( item, parts ) )
00738     q->cancelTask();
00739 }
00740 
00741 void ResourceBase::itemsRetrievalDone()
00742 {
00743   Q_D( ResourceBase );
00744   // streaming enabled, so finalize the sync
00745   if ( d->mItemSyncer ) {
00746     d->mItemSyncer->deliveryDone();
00747   }
00748   // user did the sync himself, we are done now
00749   else {
00750     d->scheduler->taskDone();
00751   }
00752 }
00753 
00754 void ResourceBase::clearCache()
00755 {
00756   Q_D( ResourceBase );
00757   d->scheduler->scheduleResourceCollectionDeletion();
00758 }
00759 
00760 void ResourceBase::invalidateCache(const Collection& collection)
00761 {
00762   Q_D( ResourceBase );
00763   d->scheduler->scheduleCacheInvalidation( collection );
00764 }
00765 
00766 Collection ResourceBase::currentCollection() const
00767 {
00768   Q_D( const ResourceBase );
00769   Q_ASSERT_X( d->scheduler->currentTask().type == ResourceScheduler::SyncCollection ,
00770               "ResourceBase::currentCollection()",
00771               "Trying to access current collection although no item retrieval is in progress" );
00772   return d->currentCollection;
00773 }
00774 
00775 Item ResourceBase::currentItem() const
00776 {
00777   Q_D( const ResourceBase );
00778   Q_ASSERT_X( d->scheduler->currentTask().type == ResourceScheduler::FetchItem ,
00779               "ResourceBase::currentItem()",
00780               "Trying to access current item although no item retrieval is in progress" );
00781   return d->scheduler->currentTask().item;
00782 }
00783 
00784 void ResourceBase::synchronizeCollectionTree()
00785 {
00786   d_func()->scheduler->scheduleCollectionTreeSync();
00787 }
00788 
00789 void ResourceBase::cancelTask()
00790 {
00791   Q_D( ResourceBase );
00792   switch ( d->scheduler->currentTask().type ) {
00793     case ResourceScheduler::FetchItem:
00794       itemRetrieved( Item() ); // sends the error reply and
00795       break;
00796     case ResourceScheduler::ChangeReplay:
00797       d->changeProcessed();
00798       break;
00799     case ResourceScheduler::SyncCollectionTree:
00800     case ResourceScheduler::SyncAll:
00801       if ( d->mCollectionSyncer )
00802         d->mCollectionSyncer->rollback();
00803       else
00804         d->scheduler->taskDone();
00805       break;
00806     case ResourceScheduler::SyncCollection:
00807       if ( d->mItemSyncer ) {
00808         d->mItemSyncer->rollback();
00809       } else {
00810         d->scheduler->taskDone();
00811       }
00812       break;
00813     default:
00814       d->scheduler->taskDone();
00815   }
00816 }
00817 
00818 void ResourceBase::cancelTask( const QString &msg )
00819 {
00820   cancelTask();
00821 
00822   emit error( msg );
00823 }
00824 
00825 void ResourceBase::deferTask()
00826 {
00827   Q_D( ResourceBase );
00828   d->scheduler->deferTask();
00829 }
00830 
00831 void ResourceBase::doSetOnline( bool state )
00832 {
00833   d_func()->scheduler->setOnline( state );
00834 }
00835 
00836 void ResourceBase::synchronizeCollection( qint64 collectionId )
00837 {
00838   synchronizeCollection( collectionId, false );
00839 }
00840 
00841 void ResourceBase::synchronizeCollection( qint64 collectionId, bool recursive )
00842 {
00843   CollectionFetchJob* job = new CollectionFetchJob( Collection( collectionId ), recursive ? CollectionFetchJob::Recursive : CollectionFetchJob::Base );
00844   job->setFetchScope( changeRecorder()->collectionFetchScope() );
00845   job->fetchScope().setResource( identifier() );
00846   job->setProperty( "recursive", recursive );
00847   connect( job, SIGNAL(result(KJob*)), SLOT(slotCollectionListDone(KJob*)) );
00848 }
00849 
00850 void ResourceBasePrivate::slotCollectionListDone( KJob *job )
00851 {
00852   if ( !job->error() ) {
00853     Collection::List list = static_cast<CollectionFetchJob*>( job )->collections();
00854     if ( !list.isEmpty() ) {
00855       if ( job->property( "recursive" ).toBool() ) {
00856         Q_FOREACH ( const Collection &collection, list ) {
00857           scheduler->scheduleSync( collection );
00858         }
00859       } else {
00860         scheduler->scheduleSync( list.first() );
00861       }
00862     }
00863   }
00864   // TODO: error handling
00865 }
00866 
00867 void ResourceBase::synchronizeCollectionAttributes( qint64 collectionId )
00868 {
00869   CollectionFetchJob* job = new CollectionFetchJob( Collection( collectionId ), CollectionFetchJob::Base );
00870   job->setFetchScope( changeRecorder()->collectionFetchScope() );
00871   job->fetchScope().setResource( identifier() );
00872   connect( job, SIGNAL(result(KJob*)), SLOT(slotCollectionListForAttributesDone(KJob*)) );
00873 }
00874 
00875 void ResourceBasePrivate::slotCollectionListForAttributesDone( KJob *job )
00876 {
00877   if ( !job->error() ) {
00878     Collection::List list = static_cast<CollectionFetchJob*>( job )->collections();
00879     if ( !list.isEmpty() ) {
00880       Collection col = list.first();
00881       scheduler->scheduleAttributesSync( col );
00882     }
00883   }
00884   // TODO: error handling
00885 }
00886 
00887 void ResourceBase::setTotalItems( int amount )
00888 {
00889   kDebug() << amount;
00890   Q_D( ResourceBase );
00891   setItemStreamingEnabled( true );
00892   if ( d->mItemSyncer ) {
00893     d->mItemSyncer->setTotalItems( amount );
00894   }
00895 }
00896 
00897 void ResourceBase::setItemStreamingEnabled( bool enable )
00898 {
00899   Q_D( ResourceBase );
00900   d->createItemSyncInstanceIfMissing();
00901   if ( d->mItemSyncer ) {
00902     d->mItemSyncer->setStreamingEnabled( enable );
00903   }
00904 }
00905 
00906 void ResourceBase::itemsRetrieved( const Item::List &items )
00907 {
00908   Q_D( ResourceBase );
00909   d->createItemSyncInstanceIfMissing();
00910   if ( d->mItemSyncer ) {
00911     d->mItemSyncer->setFullSyncItems( items );
00912   }
00913 }
00914 
00915 void ResourceBase::itemsRetrievedIncremental( const Item::List &changedItems,
00916                                               const Item::List &removedItems )
00917 {
00918   Q_D( ResourceBase );
00919   d->createItemSyncInstanceIfMissing();
00920   if ( d->mItemSyncer ) {
00921     d->mItemSyncer->setIncrementalSyncItems( changedItems, removedItems );
00922   }
00923 }
00924 
00925 void ResourceBasePrivate::slotItemSyncDone( KJob *job )
00926 {
00927   mItemSyncer = 0;
00928   Q_Q( ResourceBase );
00929   if ( job->error() && job->error() != Job::UserCanceled ) {
00930     emit q->error( job->errorString() );
00931   }
00932   scheduler->taskDone();
00933 }
00934 
00935 
00936 void ResourceBasePrivate::slotDelayedEmitProgress()
00937 {
00938   Q_Q( ResourceBase );
00939   if ( mAutomaticProgressReporting ) {
00940     emit q->percent( mUnemittedProgress );
00941 
00942     Q_FOREACH( const QVariantMap &statusMap, mUnemittedAdvancedStatus ) {
00943         emit q->advancedStatus( statusMap );
00944     }
00945   }
00946   mUnemittedProgress = 0;
00947   mUnemittedAdvancedStatus.clear();
00948 }
00949 
00950 void ResourceBasePrivate::slotPercent( KJob *job, unsigned long percent )
00951 {
00952   mUnemittedProgress = percent;
00953 
00954   const Collection collection = job->property( "collection" ).value<Collection>();
00955   if ( collection.isValid() ) {
00956     QVariantMap statusMap;
00957     statusMap.insert( QLatin1String( "key" ), QString::fromLatin1( "collectionSyncProgress" ) );
00958     statusMap.insert( QLatin1String( "collectionId" ), collection.id() );
00959     statusMap.insert( QLatin1String( "percent" ), static_cast<unsigned int>( percent ) );
00960 
00961     mUnemittedAdvancedStatus[collection.id()] = statusMap;
00962   }
00963   // deliver completion right away, intermediate progress at 1s intervals
00964   if ( percent == 100 ) {
00965     mProgressEmissionCompressor.stop();
00966     slotDelayedEmitProgress();
00967   } else if ( !mProgressEmissionCompressor.isActive() ) {
00968     mProgressEmissionCompressor.start();
00969   }
00970 }
00971 
00972 void ResourceBase::setHierarchicalRemoteIdentifiersEnabled( bool enable )
00973 {
00974   Q_D( ResourceBase );
00975   d->mHierarchicalRid = enable;
00976 }
00977 
00978 void ResourceBase::scheduleCustomTask( QObject *receiver, const char *method, const QVariant &argument, SchedulePriority priority )
00979 {
00980   Q_D( ResourceBase );
00981   d->scheduler->scheduleCustomTask( receiver, method, argument, priority );
00982 }
00983 
00984 void ResourceBase::taskDone()
00985 {
00986   Q_D( ResourceBase );
00987   d->scheduler->taskDone();
00988 }
00989 
00990 void ResourceBase::retrieveCollectionAttributes( const Collection &collection )
00991 {
00992   collectionAttributesRetrieved( collection );
00993 }
00994 
00995 void Akonadi::ResourceBase::abortActivity()
00996 {
00997 
00998 }
00999 
01000 void ResourceBase::setItemTransactionMode(ItemSync::TransactionMode mode)
01001 {
01002   Q_D( ResourceBase );
01003   d->mItemTransactionMode = mode;
01004 }
01005 
01006 void ResourceBase::setItemSynchronizationFetchScope(const ItemFetchScope& fetchScope)
01007 {
01008   Q_D( ResourceBase );
01009   if ( !d->mItemSyncFetchScope )
01010     d->mItemSyncFetchScope = new ItemFetchScope;
01011   *(d->mItemSyncFetchScope) = fetchScope;
01012 }
01013 
01014 void ResourceBase::setAutomaticProgressReporting( bool enabled )
01015 {
01016   Q_D( ResourceBase );
01017   d->mAutomaticProgressReporting = enabled;
01018 }
01019 
01020 QString ResourceBase::dumpNotificationListToString() const
01021 {
01022   Q_D( const ResourceBase );
01023   return d->dumpNotificationListToString();
01024 }
01025 
01026 QString ResourceBase::dumpSchedulerToString() const
01027 {
01028   Q_D( const ResourceBase );
01029   return d->dumpToString();
01030 }
01031 
01032 #include "resourcebase.moc"
01033 #include "moc_resourcebase.cpp"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Tue May 8 2012 00:00:45 by doxygen 1.8.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
  • Modules
  • Related Pages

kdepimlibs-4.8.3 API Reference

Skip menu "kdepimlibs-4.8.3 API Reference"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • 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