akonadi
resourcescheduler.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "resourcescheduler_p.h"
00021
00022 #include <kdebug.h>
00023 #include <klocale.h>
00024
00025 #include <QtCore/QTimer>
00026 #include <QtDBus/QDBusInterface>
00027 #include <QtDBus/QDBusConnectionInterface>
00028 #include <boost/graph/graph_concepts.hpp>
00029
00030 using namespace Akonadi;
00031
00032 qint64 ResourceScheduler::Task::latestSerial = 0;
00033 static QDBusAbstractInterface *s_resourcetracker = 0;
00034
00035
00036
00037 ResourceScheduler::ResourceScheduler( QObject *parent ) :
00038 QObject( parent ),
00039 mOnline( false )
00040 {
00041 }
00042
00043 void ResourceScheduler::scheduleFullSync()
00044 {
00045 Task t;
00046 t.type = SyncAll;
00047 if ( !mTaskList.isEmpty() && ( mTaskList.last() == t || mCurrentTask == t ) )
00048 return;
00049 mTaskList << t;
00050 signalTaskToTracker( t, "SyncAll" );
00051 scheduleNext();
00052 }
00053
00054 void ResourceScheduler::scheduleCollectionTreeSync()
00055 {
00056 Task t;
00057 t.type = SyncCollectionTree;
00058 if ( !mTaskList.isEmpty() && ( mTaskList.last() == t || mCurrentTask == t ) )
00059 return;
00060 mTaskList << t;
00061 signalTaskToTracker( t, "SyncCollectionTree" );
00062 scheduleNext();
00063 }
00064
00065 void ResourceScheduler::scheduleSync(const Collection & col)
00066 {
00067 Task t;
00068 t.type = SyncCollection;
00069 t.collection = col;
00070 if ( !mTaskList.isEmpty() && ( mTaskList.last() == t || mCurrentTask == t ) )
00071 return;
00072 mTaskList << t;
00073 signalTaskToTracker( t, "SyncCollection" );
00074 scheduleNext();
00075 }
00076
00077 void ResourceScheduler::scheduleItemFetch(const Item & item, const QSet<QByteArray> &parts, const QDBusMessage & msg)
00078 {
00079 Task t;
00080 t.type = FetchItem;
00081 t.item = item;
00082 t.itemParts = parts;
00083 t.dbusMsg = msg;
00084 if ( !mTaskList.isEmpty() && ( mTaskList.last() == t || mCurrentTask == t ) )
00085 return;
00086 mTaskList << t;
00087 signalTaskToTracker( t, "FetchItem" );
00088 scheduleNext();
00089 }
00090
00091 void ResourceScheduler::scheduleResourceCollectionDeletion()
00092 {
00093 Task t;
00094 t.type = DeleteResourceCollection;
00095 if ( !mTaskList.isEmpty() && ( mTaskList.last() == t || mCurrentTask == t ) )
00096 return;
00097 mTaskList << t;
00098 signalTaskToTracker( t, "DeleteResourceCollection" );
00099 scheduleNext();
00100 }
00101
00102 void ResourceScheduler::scheduleChangeReplay()
00103 {
00104 Task t;
00105 t.type = ChangeReplay;
00106 if ( mTaskList.contains( t ) )
00107 return;
00108
00109
00110
00111 mTaskList.prepend( t );
00112 signalTaskToTracker( t, "ChangeReplay" );
00113 scheduleNext();
00114 }
00115
00116 void Akonadi::ResourceScheduler::scheduleFullSyncCompletion()
00117 {
00118 Task t;
00119 t.type = SyncAllDone;
00120 mTaskList << t;
00121 signalTaskToTracker( t, "SyncAllDone" );
00122 scheduleNext();
00123 }
00124
00125 void Akonadi::ResourceScheduler::scheduleCustomTask( QObject *receiver, const char* methodName, const QVariant &argument, ResourceBase::SchedulePriority priority )
00126 {
00127 Task t;
00128 t.type = Custom;
00129 t.receiver = receiver;
00130 t.methodName = methodName;
00131 t.argument = argument;
00132 if ( mTaskList.contains( t ) )
00133 return;
00134
00135 switch (priority) {
00136 case ResourceBase::Prepend:
00137 mTaskList.prepend(t);
00138 break;
00139 case ResourceBase::AfterChangeReplay:
00140 {
00141 QMutableListIterator<Task> it(mTaskList);
00142 bool inserted = false;
00143 while (it.hasNext() && !inserted) {
00144 if (it.next().type != ChangeReplay) {
00145 it.previous();
00146 it.insert(t);
00147 inserted = true;
00148 }
00149 }
00150 if (!inserted)
00151 mTaskList.append(t);
00152 }
00153 break;
00154 default:
00155 mTaskList.append(t);
00156 }
00157
00158 signalTaskToTracker( t, "Custom-" + t.methodName );
00159 scheduleNext();
00160 }
00161
00162 void ResourceScheduler::taskDone()
00163 {
00164 if ( isEmpty() )
00165 emit status( AgentBase::Idle, i18nc( "@info:status Application ready for work", "Ready" ) );
00166
00167 if ( s_resourcetracker ) {
00168 QList<QVariant> argumentList;
00169 argumentList << QString::number( mCurrentTask.serial )
00170 << QString();
00171 s_resourcetracker->asyncCallWithArgumentList(QLatin1String("jobEnded"), argumentList);
00172 }
00173
00174 mCurrentTask = Task();
00175 scheduleNext();
00176 }
00177
00178 void ResourceScheduler::deferTask()
00179 {
00180 if ( s_resourcetracker ) {
00181 QList<QVariant> argumentList;
00182 argumentList << QString::number( mCurrentTask.serial )
00183 << QString();
00184 s_resourcetracker->asyncCallWithArgumentList(QLatin1String("jobEnded"), argumentList);
00185 }
00186
00187 Task t = mCurrentTask;
00188 mCurrentTask = Task();
00189 mTaskList << t;
00190 signalTaskToTracker( t, "DeferedTask" );
00191
00192 scheduleNext();
00193 }
00194
00195 bool ResourceScheduler::isEmpty()
00196 {
00197 return mTaskList.isEmpty();
00198 }
00199
00200 void ResourceScheduler::scheduleNext()
00201 {
00202 if ( mCurrentTask.type != Invalid || mTaskList.isEmpty() || !mOnline )
00203 return;
00204 QTimer::singleShot( 0, this, SLOT(executeNext()) );
00205 }
00206
00207 void ResourceScheduler::executeNext()
00208 {
00209 if( mCurrentTask.type != Invalid || mTaskList.isEmpty() )
00210 return;
00211
00212 mCurrentTask = mTaskList.takeFirst();
00213
00214 if ( s_resourcetracker ) {
00215 QList<QVariant> argumentList;
00216 argumentList << QString::number( mCurrentTask.serial );
00217 s_resourcetracker->asyncCallWithArgumentList(QLatin1String("jobStarted"), argumentList);
00218 }
00219
00220 switch ( mCurrentTask.type ) {
00221 case SyncAll:
00222 emit executeFullSync();
00223 break;
00224 case SyncCollectionTree:
00225 emit executeCollectionTreeSync();
00226 break;
00227 case SyncCollection:
00228 emit executeCollectionSync( mCurrentTask.collection );
00229 break;
00230 case FetchItem:
00231 emit executeItemFetch( mCurrentTask.item, mCurrentTask.itemParts );
00232 break;
00233 case DeleteResourceCollection:
00234 emit executeResourceCollectionDeletion();
00235 break;
00236 case ChangeReplay:
00237 emit executeChangeReplay();
00238 break;
00239 case SyncAllDone:
00240 emit fullSyncComplete();
00241 break;
00242 case Custom:
00243 {
00244 bool success = QMetaObject::invokeMethod( mCurrentTask.receiver, mCurrentTask.methodName, Q_ARG(QVariant, mCurrentTask.argument) );;
00245 if ( !success )
00246 success = QMetaObject::invokeMethod( mCurrentTask.receiver, mCurrentTask.methodName );
00247
00248 if ( !success )
00249 kError() << "Could not invoke slot" << mCurrentTask.methodName << "on" << mCurrentTask.receiver << "with argument" << mCurrentTask.argument;
00250 break;
00251 }
00252 default:
00253 Q_ASSERT( false );
00254 }
00255 }
00256
00257 ResourceScheduler::Task ResourceScheduler::currentTask() const
00258 {
00259 return mCurrentTask;
00260 }
00261
00262 void ResourceScheduler::setOnline(bool state)
00263 {
00264 if ( mOnline == state )
00265 return;
00266 mOnline = state;
00267 if ( mOnline ) {
00268 scheduleNext();
00269 } else if ( mCurrentTask.type != Invalid ) {
00270
00271 mTaskList.prepend( mCurrentTask );
00272 mCurrentTask = Task();
00273 }
00274 }
00275
00276 void ResourceScheduler::signalTaskToTracker( const Task &task, const QByteArray &taskType )
00277 {
00278
00279 if ( !s_resourcetracker && QDBusConnection::sessionBus().interface()->isServiceRegistered(QLatin1String("org.kde.akonadiconsole") ) ) {
00280 s_resourcetracker = new QDBusInterface( QLatin1String("org.kde.akonadiconsole"),
00281 QLatin1String("/resourcesJobtracker"),
00282 QLatin1String("org.freedesktop.Akonadi.JobTracker"),
00283 QDBusConnection::sessionBus(), 0 );
00284 }
00285
00286 if ( s_resourcetracker ) {
00287 QList<QVariant> argumentList;
00288 argumentList << static_cast<AgentBase*>( parent() )->identifier()
00289 << QString::number( task.serial )
00290 << QString()
00291 << QString::fromLatin1( taskType );
00292 s_resourcetracker->asyncCallWithArgumentList(QLatin1String("jobCreated"), argumentList);
00293 }
00294 }
00295
00296 void ResourceScheduler::collectionRemoved( const Akonadi::Collection &collection )
00297 {
00298 if ( !collection.isValid() )
00299 return;
00300 for ( QList<Task>::iterator it = mTaskList.begin(); it != mTaskList.end(); ) {
00301 if ( (*it).type == SyncCollection && (*it).collection == collection ) {
00302 it = mTaskList.erase( it );
00303 kDebug() << " erasing";
00304 } else
00305 ++it;
00306 }
00307 }
00308
00309
00310
00311 #include "resourcescheduler_p.moc"