• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • Sitemap
  • 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 "collectionsync.h"
00026 #include "itemsync.h"
00027 #include "resourcescheduler.h"
00028 #include "tracerinterface.h"
00029 #include "xdgbasedirs_p.h"
00030 
00031 #include "changerecorder.h"
00032 #include "collectionfetchjob.h"
00033 #include "collectionmodifyjob.h"
00034 #include "itemfetchjob.h"
00035 #include "itemfetchscope.h"
00036 #include "itemmodifyjob.h"
00037 #include "itemmodifyjob_p.h"
00038 #include "session.h"
00039 
00040 #include <kaboutdata.h>
00041 #include <kcmdlineargs.h>
00042 #include <kdebug.h>
00043 #include <klocale.h>
00044 
00045 #include <QtCore/QDebug>
00046 #include <QtCore/QDir>
00047 #include <QtCore/QHash>
00048 #include <QtCore/QSettings>
00049 #include <QtCore/QTimer>
00050 #include <QtGui/QApplication>
00051 #include <QtDBus/QtDBus>
00052 
00053 using namespace Akonadi;
00054 
00055 class Akonadi::ResourceBasePrivate : public AgentBasePrivate
00056 {
00057   public:
00058     ResourceBasePrivate( ResourceBase *parent )
00059       : AgentBasePrivate( parent ),
00060         scheduler( 0 ),
00061         mItemSyncer( 0 )
00062     {
00063       mStatusMessage = defaultReadyMessage();
00064     }
00065 
00066     Q_DECLARE_PUBLIC( ResourceBase )
00067 
00068     void delayedInit()
00069     {
00070       if ( !QDBusConnection::sessionBus().registerService( QLatin1String( "org.freedesktop.Akonadi.Resource." ) + mId ) )
00071         kFatal() << "Unable to register service at D-Bus: " << QDBusConnection::sessionBus().lastError().message();
00072       AgentBasePrivate::delayedInit();
00073     }
00074 
00075     virtual void changeProcessed()
00076     {
00077       mMonitor->changeProcessed();
00078       if ( !mMonitor->isEmpty() )
00079         scheduler->scheduleChangeReplay();
00080       scheduler->taskDone();
00081     }
00082 
00083     void slotDeliveryDone( KJob* job );
00084 
00085     void slotCollectionSyncDone( KJob *job );
00086     void slotLocalListDone( KJob *job );
00087     void slotSynchronizeCollection( const Collection &col );
00088     void slotCollectionListDone( KJob *job );
00089 
00090     void slotItemSyncDone( KJob *job );
00091 
00092     void slotPercent( KJob* job, unsigned long percent );
00093 
00094     QString mName;
00095 
00096     // synchronize states
00097     Collection currentCollection;
00098 
00099     ResourceScheduler *scheduler;
00100     ItemSync *mItemSyncer;
00101 };
00102 
00103 ResourceBase::ResourceBase( const QString & id )
00104   : AgentBase( new ResourceBasePrivate( this ), id )
00105 {
00106   Q_D( ResourceBase );
00107 
00108   new ResourceAdaptor( this );
00109 
00110   const QString name = d->mSettings->value( QLatin1String( "Resource/Name" ) ).toString();
00111   if ( !name.isEmpty() )
00112     d->mName = name;
00113 
00114   d->scheduler = new ResourceScheduler( this );
00115 
00116   d->mMonitor->setChangeRecordingEnabled( true );
00117   connect( d->mMonitor, SIGNAL(changesAdded()),
00118            d->scheduler, SLOT(scheduleChangeReplay()) );
00119 
00120   d->mMonitor->setResourceMonitored( d->mId.toLatin1() );
00121 
00122   connect( d->scheduler, SIGNAL(executeFullSync()),
00123            SLOT(retrieveCollections()) );
00124   connect( d->scheduler, SIGNAL(executeCollectionTreeSync()),
00125            SLOT(retrieveCollections()) );
00126   connect( d->scheduler, SIGNAL(executeCollectionSync(Akonadi::Collection)),
00127            SLOT(slotSynchronizeCollection(Akonadi::Collection)) );
00128   connect( d->scheduler, SIGNAL(executeItemFetch(Akonadi::Item,QSet<QByteArray>)),
00129            SLOT(retrieveItem(Akonadi::Item,QSet<QByteArray>)) );
00130   connect( d->scheduler, SIGNAL(executeChangeReplay()),
00131            d->mMonitor, SLOT(replayNext()) );
00132 
00133   d->scheduler->setOnline( d->mOnline );
00134   if ( !d->mMonitor->isEmpty() )
00135     d->scheduler->scheduleChangeReplay();
00136 }
00137 
00138 ResourceBase::~ResourceBase()
00139 {
00140 }
00141 
00142 void ResourceBase::synchronize()
00143 {
00144   d_func()->scheduler->scheduleFullSync();
00145 }
00146 
00147 void ResourceBase::setName( const QString &name )
00148 {
00149   Q_D( ResourceBase );
00150   if ( name == d->mName )
00151     return;
00152 
00153   // TODO: rename collection
00154   d->mName = name;
00155 
00156   if ( d->mName.isEmpty() || d->mName == d->mId )
00157     d->mSettings->remove( QLatin1String( "Resource/Name" ) );
00158   else
00159     d->mSettings->setValue( QLatin1String( "Resource/Name" ), d->mName );
00160 
00161   d->mSettings->sync();
00162 
00163   emit nameChanged( d->mName );
00164 }
00165 
00166 QString ResourceBase::name() const
00167 {
00168   Q_D( const ResourceBase );
00169   if ( d->mName.isEmpty() )
00170     return d->mId;
00171   else
00172     return d->mName;
00173 }
00174 
00175 static char* sAppName = 0;
00176 
00177 QString ResourceBase::parseArguments( int argc, char **argv )
00178 {
00179   QString identifier;
00180   if ( argc < 3 ) {
00181     kDebug( 5250 ) << "Not enough arguments passed...";
00182     exit( 1 );
00183   }
00184 
00185   for ( int i = 1; i < argc - 1; ++i ) {
00186     if ( QLatin1String( argv[ i ] ) == QLatin1String( "--identifier" ) )
00187       identifier = QLatin1String( argv[ i + 1 ] );
00188   }
00189 
00190   if ( identifier.isEmpty() ) {
00191     kDebug( 5250 ) << "Identifier argument missing";
00192     exit( 1 );
00193   }
00194 
00195   sAppName = qstrdup( identifier.toLatin1().constData() );
00196   KCmdLineArgs::init( argc, argv, sAppName, 0,
00197                       ki18nc("@title, application name", "Akonadi Resource"), "0.1",
00198                       ki18nc("@title, application description", "Akonadi Resource") );
00199 
00200   KCmdLineOptions options;
00201   options.add("identifier <argument>",
00202               ki18nc("@label, commandline option", "Resource identifier"));
00203   KCmdLineArgs::addCmdLineOptions( options );
00204 
00205   return identifier;
00206 }
00207 
00208 int ResourceBase::init( ResourceBase *r )
00209 {
00210   QApplication::setQuitOnLastWindowClosed( false );
00211   int rv = kapp->exec();
00212   delete r;
00213   delete[] sAppName;
00214   return rv;
00215 }
00216 
00217 void ResourceBase::itemRetrieved( const Item &item )
00218 {
00219   Q_D( ResourceBase );
00220   Q_ASSERT( d->scheduler->currentTask().type == ResourceScheduler::FetchItem );
00221   if ( !item.isValid() ) {
00222     QDBusMessage reply( d->scheduler->currentTask().dbusMsg );
00223     reply << false;
00224     QDBusConnection::sessionBus().send( reply );
00225     d->scheduler->taskDone();
00226     return;
00227   }
00228 
00229   Item i( item );
00230   QSet<QByteArray> requestedParts = d->scheduler->currentTask().itemParts;
00231   foreach ( const QByteArray &part, requestedParts ) {
00232     if ( !item.loadedPayloadParts().contains( part ) ) {
00233       kWarning( 5250 ) << "Item does not provide part" << part;
00234     }
00235   }
00236 
00237   ItemModifyJob *job = new ItemModifyJob( i );
00238   // FIXME: remove once the item with which we call retrieveItem() has a revision number
00239   job->disableRevisionCheck();
00240   connect( job, SIGNAL(result(KJob*)), SLOT(slotDeliveryDone(KJob*)) );
00241 }
00242 
00243 void ResourceBasePrivate::slotDeliveryDone(KJob * job)
00244 {
00245   Q_Q( ResourceBase );
00246   Q_ASSERT( scheduler->currentTask().type == ResourceScheduler::FetchItem );
00247   QDBusMessage reply( scheduler->currentTask().dbusMsg );
00248   if ( job->error() ) {
00249     emit q->error( QLatin1String( "Error while creating item: " ) + job->errorString() );
00250     reply << false;
00251   } else {
00252     reply << true;
00253   }
00254   QDBusConnection::sessionBus().send( reply );
00255   scheduler->taskDone();
00256 }
00257 
00258 void ResourceBase::changeCommitted(const Item& item)
00259 {
00260   Q_D( ResourceBase );
00261   ItemModifyJob *job = new ItemModifyJob( item );
00262   job->d_func()->setClean();
00263   job->disableRevisionCheck(); // TODO: remove, but where/how do we handle the error?
00264   d->changeProcessed();
00265 }
00266 
00267 void ResourceBase::changeCommitted( const Collection &collection )
00268 {
00269   Q_D( ResourceBase );
00270   CollectionModifyJob *job = new CollectionModifyJob( collection );
00271   Q_UNUSED( job );
00272   //TODO: error checking
00273   d->changeProcessed();
00274 }
00275 
00276 bool ResourceBase::requestItemDelivery( qint64 uid, const QString & remoteId,
00277                                         const QString &mimeType, const QStringList &_parts )
00278 {
00279   Q_D( ResourceBase );
00280   if ( !isOnline() ) {
00281     emit error( i18nc( "@info", "Cannot fetch item in offline mode." ) );
00282     return false;
00283   }
00284 
00285   setDelayedReply( true );
00286   // FIXME: we need at least the revision number too
00287   Item item( uid );
00288   item.setMimeType( mimeType );
00289   item.setRemoteId( remoteId );
00290 
00291   QSet<QByteArray> parts;
00292   Q_FOREACH( const QString &str, _parts )
00293     parts.insert( str.toLatin1() );
00294 
00295   d->scheduler->scheduleItemFetch( item, parts, message().createReply() );
00296 
00297   return true;
00298 }
00299 
00300 void ResourceBase::collectionsRetrieved(const Collection::List & collections)
00301 {
00302   Q_D( ResourceBase );
00303   CollectionSync *syncer = new CollectionSync( d->mId );
00304   syncer->setRemoteCollections( collections );
00305   connect( syncer, SIGNAL(result(KJob*)), SLOT(slotCollectionSyncDone(KJob*)) );
00306 }
00307 
00308 void ResourceBase::collectionsRetrievedIncremental(const Collection::List & changedCollections, const Collection::List & removedCollections)
00309 {
00310   Q_D( ResourceBase );
00311   CollectionSync *syncer = new CollectionSync( d->mId );
00312   syncer->setRemoteCollections( changedCollections, removedCollections );
00313   connect( syncer, SIGNAL(result(KJob*)), SLOT(slotCollectionSyncDone(KJob*)) );
00314 }
00315 
00316 void ResourceBasePrivate::slotCollectionSyncDone(KJob * job)
00317 {
00318   Q_Q( ResourceBase );
00319   if ( job->error() ) {
00320     emit q->error( job->errorString() );
00321   } else {
00322     if ( scheduler->currentTask().type == ResourceScheduler::SyncAll ) {
00323       CollectionFetchJob *list = new CollectionFetchJob( Collection::root(), CollectionFetchJob::Recursive );
00324       list->setResource( mId );
00325       q->connect( list, SIGNAL(result(KJob*)), q, SLOT(slotLocalListDone(KJob*)) );
00326       return;
00327     }
00328   }
00329   if ( scheduler->isEmpty() )
00330     emit q->status( AgentBase::Idle );
00331   scheduler->taskDone();
00332 }
00333 
00334 void ResourceBasePrivate::slotLocalListDone(KJob * job)
00335 {
00336   Q_Q( ResourceBase );
00337   if ( job->error() ) {
00338     emit q->error( job->errorString() );
00339   } else {
00340     Collection::List cols = static_cast<CollectionFetchJob*>( job )->collections();
00341     foreach ( const Collection &col, cols ) {
00342       scheduler->scheduleSync( col );
00343     }
00344   }
00345   scheduler->taskDone();
00346 }
00347 
00348 void ResourceBasePrivate::slotSynchronizeCollection( const Collection &col )
00349 {
00350   Q_Q( ResourceBase );
00351   currentCollection = col;
00352   // check if this collection actually can contain anything
00353   QStringList contentTypes = currentCollection.contentMimeTypes();
00354   contentTypes.removeAll( Collection::mimeType() );
00355   if ( !contentTypes.isEmpty() ) {
00356     emit q->status( AgentBase::Running, i18nc( "@info:status", "Syncing collection '%1'", currentCollection.name() ) );
00357     q->retrieveItems( currentCollection );
00358     return;
00359   }
00360   scheduler->taskDone();
00361 }
00362 
00363 void ResourceBase::itemsRetrievalDone()
00364 {
00365   Q_D( ResourceBase );
00366   // streaming enabled, so finalize the sync
00367   if ( d->mItemSyncer ) {
00368     d->mItemSyncer->deliveryDone();
00369   }
00370   // user did the sync himself, we are done now
00371   else {
00372     if ( d->scheduler->isEmpty() )
00373       emit status( Idle );
00374     d->scheduler->taskDone();
00375   }
00376 }
00377 
00378 Collection ResourceBase::currentCollection() const
00379 {
00380   Q_D( const ResourceBase );
00381   Q_ASSERT_X( d->scheduler->currentTask().type == ResourceScheduler::SyncCollection ,
00382               "ResourceBase::currentCollection()",
00383               "Trying to access current collection although no item retrieval is in progress" );
00384   return d->currentCollection;
00385 }
00386 
00387 Item ResourceBase::currentItem() const
00388 {
00389   Q_D( const ResourceBase );
00390   Q_ASSERT_X( d->scheduler->currentTask().type == ResourceScheduler::FetchItem ,
00391               "ResourceBase::currentItem()",
00392               "Trying to access current item although no item retrieval is in progress" );
00393   return d->scheduler->currentTask().item;
00394 }
00395 
00396 void ResourceBase::synchronizeCollectionTree()
00397 {
00398   d_func()->scheduler->scheduleCollectionTreeSync();
00399 }
00400 
00401 void ResourceBase::cancelTask()
00402 {
00403   d_func()->changeProcessed();
00404 }
00405 
00406 void ResourceBase::cancelTask( const QString &msg )
00407 {
00408   cancelTask();
00409 
00410   emit error( msg );
00411 }
00412 
00413 void ResourceBase::doSetOnline( bool state )
00414 {
00415   d_func()->scheduler->setOnline( state );
00416 }
00417 
00418 void ResourceBase::synchronizeCollection(qint64 collectionId )
00419 {
00420   CollectionFetchJob* job = new CollectionFetchJob( Collection(collectionId), CollectionFetchJob::Base );
00421   job->setResource( identifier() );
00422   connect( job, SIGNAL(result(KJob*)), SLOT(slotCollectionListDone(KJob*)) );
00423 }
00424 
00425 void ResourceBasePrivate::slotCollectionListDone( KJob *job )
00426 {
00427   if ( !job->error() ) {
00428     Collection::List list = static_cast<CollectionFetchJob*>( job )->collections();
00429     if ( !list.isEmpty() ) {
00430       Collection col = list.first();
00431       scheduler->scheduleSync( col );
00432     }
00433   }
00434   // TODO: error handling
00435 }
00436 
00437 void ResourceBase::setTotalItems( int amount )
00438 {
00439   kDebug() << amount;
00440   Q_D( ResourceBase );
00441   setItemStreamingEnabled( true );
00442   d->mItemSyncer->setTotalItems( amount );
00443 }
00444 
00445 void ResourceBase::setItemStreamingEnabled( bool enable )
00446 {
00447   Q_D( ResourceBase );
00448   Q_ASSERT_X( d->scheduler->currentTask().type == ResourceScheduler::SyncCollection,
00449               "ResourceBase::setItemStreamingEnabled()",
00450               "Calling setItemStreamingEnabled() although no item retrieval is in progress" );
00451   if ( !d->mItemSyncer ) {
00452     d->mItemSyncer = new ItemSync( currentCollection() );
00453     connect( d->mItemSyncer, SIGNAL(percent(KJob*,unsigned long)), SLOT(slotPercent(KJob*,unsigned long)) );
00454     connect( d->mItemSyncer, SIGNAL(result(KJob*)), SLOT(slotItemSyncDone(KJob*)) );
00455   }
00456   d->mItemSyncer->setStreamingEnabled( enable );
00457 }
00458 
00459 void ResourceBase::itemsRetrieved( const Item::List &items )
00460 {
00461   Q_D( ResourceBase );
00462   Q_ASSERT_X( d->scheduler->currentTask().type == ResourceScheduler::SyncCollection,
00463               "ResourceBase::itemsRetrieved()",
00464               "Calling itemsRetrieved() although no item retrieval is in progress" );
00465   if ( !d->mItemSyncer ) {
00466     d->mItemSyncer = new ItemSync( currentCollection() );
00467     connect( d->mItemSyncer, SIGNAL(percent(KJob*,unsigned long)), SLOT(slotPercent(KJob*,unsigned long)) );
00468     connect( d->mItemSyncer, SIGNAL(result(KJob*)), SLOT(slotItemSyncDone(KJob*)) );
00469   }
00470   d->mItemSyncer->setFullSyncItems( items );
00471 }
00472 
00473 void ResourceBase::itemsRetrievedIncremental(const Item::List &changedItems, const Item::List &removedItems)
00474 {
00475   Q_D( ResourceBase );
00476   Q_ASSERT_X( d->scheduler->currentTask().type == ResourceScheduler::SyncCollection,
00477               "ResourceBase::itemsRetrievedIncremental()",
00478               "Calling itemsRetrievedIncremental() although no item retrieval is in progress" );
00479   if ( !d->mItemSyncer ) {
00480     d->mItemSyncer = new ItemSync( currentCollection() );
00481     connect( d->mItemSyncer, SIGNAL(percent(KJob*,unsigned long)), SLOT(slotPercent(KJob*,unsigned long)) );
00482     connect( d->mItemSyncer, SIGNAL(result(KJob*)), SLOT(slotItemSyncDone(KJob*)) );
00483   }
00484   d->mItemSyncer->setIncrementalSyncItems( changedItems, removedItems );
00485 }
00486 
00487 void ResourceBasePrivate::slotItemSyncDone( KJob *job )
00488 {
00489   mItemSyncer = 0;
00490   Q_Q( ResourceBase );
00491   if ( job->error() ) {
00492     emit q->error( job->errorString() );
00493   }
00494   if ( scheduler->isEmpty() )
00495     emit q->status( AgentBase::Idle );
00496   scheduler->taskDone();
00497 }
00498 
00499 void ResourceBasePrivate::slotPercent( KJob *job, unsigned long percent )
00500 {
00501   Q_Q( ResourceBase );
00502   Q_UNUSED( job );
00503   emit q->percent( percent );
00504 }
00505 
00506 #include "resourcebase.moc"

akonadi

Skip menu "akonadi"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • akonadi
  • kabc
  • kblog
  • kcal
  • kimap
  • kioslave
  •   imap4
  •   mbox
  • kldap
  • kmime
  • kpimidentities
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.5.6
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal