kmail Library API Documentation

jobscheduler.cpp

00001 00029 #include "jobscheduler.h" 00030 #include "kmfolder.h" 00031 #include "folderstorage.h" 00032 #include "kmfoldermgr.h" 00033 #include <kdebug.h> 00034 00035 using namespace KMail; 00036 00037 JobScheduler::JobScheduler( QObject* parent, const char* name ) 00038 : QObject( parent, name ), mTimer( this ), 00039 mPendingImmediateTasks( 0 ), 00040 mCurrentTask( 0 ), mCurrentJob( 0 ) 00041 { 00042 connect( &mTimer, SIGNAL( timeout() ), SLOT( slotRunNextJob() ) ); 00043 // No need to start the internal timer yet, we wait for a task to be scheduled 00044 } 00045 00046 00047 JobScheduler::~JobScheduler() 00048 { 00049 // delete tasks in tasklist (no autodelete for QValueList) 00050 for( QValueList<ScheduledTask *>::Iterator it = mTaskList.begin(); it != mTaskList.end(); ++it ) { 00051 delete (*it); 00052 } 00053 delete mCurrentTask; 00054 delete mCurrentJob; 00055 } 00056 00057 void JobScheduler::registerTask( ScheduledTask* task ) 00058 { 00059 bool immediate = task->isImmediate(); 00060 int typeId = task->taskTypeId(); 00061 if ( typeId ) { 00062 KMFolder* folder = task->folder(); 00063 // Search for an identical task already scheduled 00064 for( QValueList<ScheduledTask *>::ConstIterator it = mTaskList.begin(); it != mTaskList.end(); ++it ) { 00065 if ( (*it)->taskTypeId() == typeId && (*it)->folder() == folder ) { 00066 #ifdef DEBUG_SCHEDULER 00067 kdDebug(5006) << "JobScheduler: already having task type " << typeId << " for folder " << folder->label() << endl; 00068 #endif 00069 delete task; 00070 if ( !mCurrentTask && immediate ) { 00071 ScheduledTask* task = *it; 00072 runTaskNow( task ); 00073 } 00074 return; 00075 } 00076 } 00077 // Note that scheduling an identical task as the one currently running is allowed. 00078 } 00079 if ( !mCurrentTask && immediate ) 00080 runTaskNow( task ); 00081 else { 00082 #ifdef DEBUG_SCHEDULER 00083 kdDebug(5006) << "JobScheduler: adding task " << task << " (type " << task->taskTypeId() 00084 << ") for folder " << task->folder() << " " << task->folder()->label() << endl; 00085 #endif 00086 mTaskList.append( task ); 00087 if ( immediate ) 00088 ++mPendingImmediateTasks; 00089 if ( !mCurrentTask && !mTimer.isActive() ) 00090 restartTimer(); 00091 } 00092 } 00093 00094 void JobScheduler::notifyOpeningFolder( KMFolder* folder ) 00095 { 00096 if ( mCurrentTask && mCurrentTask->folder() == folder ) { 00097 if ( mCurrentJob->isOpeningFolder() ) { // set when starting a job for this folder 00098 #ifdef DEBUG_SCHEDULER 00099 kdDebug(5006) << "JobScheduler: got the opening-notification for " << folder->label() << " as expected." << endl; 00100 #endif 00101 } else { 00102 // Jobs scheduled from here should always be cancellable. 00103 // One exception though, is when ExpireJob does its final KMMoveCommand. 00104 // Then that command shouldn't kill its own parent job just because it opens a folder... 00105 if ( mCurrentJob->isCancellable() ) 00106 interruptCurrentTask(); 00107 } 00108 } 00109 } 00110 00111 void JobScheduler::interruptCurrentTask() 00112 { 00113 Q_ASSERT( mCurrentTask ); 00114 #ifdef DEBUG_SCHEDULER 00115 kdDebug(5006) << "JobScheduler: interrupting job " << mCurrentJob << " for folder " << mCurrentTask->folder()->label() << endl; 00116 #endif 00117 // File it again. This will either delete it or put it in mTaskList. 00118 registerTask( mCurrentTask ); 00119 mCurrentTask = 0; 00120 mCurrentJob->kill(); // This deletes the job and calls slotJobFinished! 00121 } 00122 00123 void JobScheduler::slotRunNextJob() 00124 { 00125 while ( !mCurrentJob ) { 00126 #ifdef DEBUG_SCHEDULER 00127 kdDebug(5006) << "JobScheduler: slotRunNextJob" << endl; 00128 #endif 00129 Q_ASSERT( mCurrentTask == 0 ); 00130 ScheduledTask* task = 0; 00131 // Find a task suitable for being run 00132 for( QValueList<ScheduledTask *>::Iterator it = mTaskList.begin(); it != mTaskList.end(); ++it ) { 00133 // Remove if folder died 00134 KMFolder* folder = (*it)->folder(); 00135 if ( folder == 0 ) { 00136 #ifdef DEBUG_SCHEDULER 00137 kdDebug(5006) << " folder for task " << (*it) << " was deleted" << endl; 00138 #endif 00139 if ( (*it)->isImmediate() ) 00140 --mPendingImmediateTasks; 00141 mTaskList.remove( it ); 00142 if ( !mTaskList.isEmpty() ) 00143 slotRunNextJob(); // to avoid the mess with invalid iterators :) 00144 else 00145 mTimer.stop(); 00146 return; 00147 } 00148 // The condition is that the folder must be unused (not open) 00149 // But first we ask search folders to release their access to it 00150 kmkernel->searchFolderMgr()->tryReleasingFolder( folder ); 00151 #ifdef DEBUG_SCHEDULER 00152 kdDebug(5006) << " looking at folder " << folder->label() 00153 << " " << folder->location() 00154 << " isOpened=" << (*it)->folder()->isOpened() << endl; 00155 #endif 00156 if ( !folder->isOpened() ) { 00157 task = *it; 00158 mTaskList.remove( it ); 00159 if ( task->isImmediate() ) 00160 --mPendingImmediateTasks; 00161 break; 00162 } 00163 } 00164 00165 if ( !task ) // found nothing to run, i.e. folder was opened 00166 return; // Timer keeps running, i.e. try again in 1 minute 00167 00168 runTaskNow( task ); 00169 } // If nothing to do for that task, loop and find another one to run 00170 } 00171 00172 void JobScheduler::restartTimer() 00173 { 00174 if ( mPendingImmediateTasks > 0 ) 00175 slotRunNextJob(); 00176 else 00177 { 00178 #ifdef DEBUG_SCHEDULER 00179 mTimer.start( 10000 ); // 10 seconds 00180 #else 00181 mTimer.start( 1 * 60000 ); // 1 minute 00182 #endif 00183 } 00184 } 00185 00186 void JobScheduler::runTaskNow( ScheduledTask* task ) 00187 { 00188 Q_ASSERT( mCurrentTask == 0 ); 00189 if ( mCurrentTask ) { 00190 interruptCurrentTask(); 00191 } 00192 mCurrentTask = task; 00193 mTimer.stop(); 00194 mCurrentJob = mCurrentTask->run(); 00195 #ifdef DEBUG_SCHEDULER 00196 kdDebug(5006) << "JobScheduler: task " << mCurrentTask 00197 << " (type " << mCurrentTask->taskTypeId() << ")" 00198 << " for folder " << mCurrentTask->folder()->label() 00199 << " returned job " << mCurrentJob << " " 00200 << ( mCurrentJob?mCurrentJob->className():0 ) << endl; 00201 #endif 00202 if ( !mCurrentJob ) { // nothing to do, e.g. folder deleted 00203 delete mCurrentTask; 00204 mCurrentTask = 0; 00205 if ( !mTaskList.isEmpty() ) 00206 restartTimer(); 00207 return; 00208 } 00209 // Register the job in the folder. This makes it autodeleted if the folder is deleted. 00210 mCurrentTask->folder()->storage()->addJob( mCurrentJob ); 00211 connect( mCurrentJob, SIGNAL( finished() ), this, SLOT( slotJobFinished() ) ); 00212 mCurrentJob->start(); 00213 } 00214 00215 void JobScheduler::slotJobFinished() 00216 { 00217 // Do we need to test for mCurrentJob->error()? What do we do then? 00218 #ifdef DEBUG_SCHEDULER 00219 kdDebug(5006) << "JobScheduler: slotJobFinished" << endl; 00220 #endif 00221 delete mCurrentTask; 00222 mCurrentTask = 0; 00223 mCurrentJob = 0; 00224 if ( !mTaskList.isEmpty() ) 00225 restartTimer(); 00226 } 00227 00229 00230 KMail::ScheduledJob::ScheduledJob( KMFolder* folder, bool immediate ) 00231 : FolderJob( 0, tOther, folder ), mImmediate( immediate ), 00232 mOpeningFolder( false ) 00233 { 00234 mCancellable = true; 00235 mSrcFolder = folder; 00236 } 00237 00238 #include "jobscheduler.moc"
KDE Logo
This file is part of the documentation for kmail Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Aug 27 12:52:17 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003