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( TaskList::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( TaskList::Iterator 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 removeTask( it ); 00073 runTaskNow( task ); 00074 } 00075 return; 00076 } 00077 } 00078 // Note that scheduling an identical task as the one currently running is allowed. 00079 } 00080 if ( !mCurrentTask && immediate ) 00081 runTaskNow( task ); 00082 else { 00083 #ifdef DEBUG_SCHEDULER 00084 kdDebug(5006) << "JobScheduler: adding task " << task << " (type " << task->taskTypeId() 00085 << ") for folder " << task->folder() << " " << task->folder()->label() << endl; 00086 #endif 00087 mTaskList.append( task ); 00088 if ( immediate ) 00089 ++mPendingImmediateTasks; 00090 if ( !mCurrentTask && !mTimer.isActive() ) 00091 restartTimer(); 00092 } 00093 } 00094 00095 void JobScheduler::removeTask( TaskList::Iterator& it ) 00096 { 00097 if ( (*it)->isImmediate() ) 00098 --mPendingImmediateTasks; 00099 mTaskList.remove( it ); 00100 } 00101 00102 void JobScheduler::notifyOpeningFolder( KMFolder* folder ) 00103 { 00104 if ( mCurrentTask && mCurrentTask->folder() == folder ) { 00105 if ( mCurrentJob->isOpeningFolder() ) { // set when starting a job for this folder 00106 #ifdef DEBUG_SCHEDULER 00107 kdDebug(5006) << "JobScheduler: got the opening-notification for " << folder->label() << " as expected." << endl; 00108 #endif 00109 } else { 00110 // Jobs scheduled from here should always be cancellable. 00111 // One exception though, is when ExpireJob does its final KMMoveCommand. 00112 // Then that command shouldn't kill its own parent job just because it opens a folder... 00113 if ( mCurrentJob->isCancellable() ) 00114 interruptCurrentTask(); 00115 } 00116 } 00117 } 00118 00119 void JobScheduler::interruptCurrentTask() 00120 { 00121 Q_ASSERT( mCurrentTask ); 00122 #ifdef DEBUG_SCHEDULER 00123 kdDebug(5006) << "JobScheduler: interrupting job " << mCurrentJob << " for folder " << mCurrentTask->folder()->label() << endl; 00124 #endif 00125 // File it again. This will either delete it or put it in mTaskList. 00126 registerTask( mCurrentTask ); 00127 mCurrentTask = 0; 00128 mCurrentJob->kill(); // This deletes the job and calls slotJobFinished! 00129 } 00130 00131 void JobScheduler::slotRunNextJob() 00132 { 00133 while ( !mCurrentJob ) { 00134 #ifdef DEBUG_SCHEDULER 00135 kdDebug(5006) << "JobScheduler: slotRunNextJob" << endl; 00136 #endif 00137 Q_ASSERT( mCurrentTask == 0 ); 00138 ScheduledTask* task = 0; 00139 // Find a task suitable for being run 00140 for( TaskList::Iterator it = mTaskList.begin(); it != mTaskList.end(); ++it ) { 00141 // Remove if folder died 00142 KMFolder* folder = (*it)->folder(); 00143 if ( folder == 0 ) { 00144 #ifdef DEBUG_SCHEDULER 00145 kdDebug(5006) << " folder for task " << (*it) << " was deleted" << endl; 00146 #endif 00147 removeTask( it ); 00148 if ( !mTaskList.isEmpty() ) 00149 slotRunNextJob(); // to avoid the mess with invalid iterators :) 00150 else 00151 mTimer.stop(); 00152 return; 00153 } 00154 // The condition is that the folder must be unused (not open) 00155 // But first we ask search folders to release their access to it 00156 kmkernel->searchFolderMgr()->tryReleasingFolder( folder ); 00157 #ifdef DEBUG_SCHEDULER 00158 kdDebug(5006) << " looking at folder " << folder->label() 00159 << " " << folder->location() 00160 << " isOpened=" << (*it)->folder()->isOpened() << endl; 00161 #endif 00162 if ( !folder->isOpened() ) { 00163 task = *it; 00164 removeTask( it ); 00165 break; 00166 } 00167 } 00168 00169 if ( !task ) // found nothing to run, i.e. folder was opened 00170 return; // Timer keeps running, i.e. try again in 1 minute 00171 00172 runTaskNow( task ); 00173 } // If nothing to do for that task, loop and find another one to run 00174 } 00175 00176 void JobScheduler::restartTimer() 00177 { 00178 if ( mPendingImmediateTasks > 0 ) 00179 slotRunNextJob(); 00180 else 00181 { 00182 #ifdef DEBUG_SCHEDULER 00183 mTimer.start( 10000 ); // 10 seconds 00184 #else 00185 mTimer.start( 1 * 60000 ); // 1 minute 00186 #endif 00187 } 00188 } 00189 00190 void JobScheduler::runTaskNow( ScheduledTask* task ) 00191 { 00192 Q_ASSERT( mCurrentTask == 0 ); 00193 if ( mCurrentTask ) { 00194 interruptCurrentTask(); 00195 } 00196 mCurrentTask = task; 00197 mTimer.stop(); 00198 mCurrentJob = mCurrentTask->run(); 00199 #ifdef DEBUG_SCHEDULER 00200 kdDebug(5006) << "JobScheduler: task " << mCurrentTask 00201 << " (type " << mCurrentTask->taskTypeId() << ")" 00202 << " for folder " << mCurrentTask->folder()->label() 00203 << " returned job " << mCurrentJob << " " 00204 << ( mCurrentJob?mCurrentJob->className():0 ) << endl; 00205 #endif 00206 if ( !mCurrentJob ) { // nothing to do, e.g. folder deleted 00207 delete mCurrentTask; 00208 mCurrentTask = 0; 00209 if ( !mTaskList.isEmpty() ) 00210 restartTimer(); 00211 return; 00212 } 00213 // Register the job in the folder. This makes it autodeleted if the folder is deleted. 00214 mCurrentTask->folder()->storage()->addJob( mCurrentJob ); 00215 connect( mCurrentJob, SIGNAL( finished() ), this, SLOT( slotJobFinished() ) ); 00216 mCurrentJob->start(); 00217 } 00218 00219 void JobScheduler::slotJobFinished() 00220 { 00221 // Do we need to test for mCurrentJob->error()? What do we do then? 00222 #ifdef DEBUG_SCHEDULER 00223 kdDebug(5006) << "JobScheduler: slotJobFinished" << endl; 00224 #endif 00225 delete mCurrentTask; 00226 mCurrentTask = 0; 00227 mCurrentJob = 0; 00228 if ( !mTaskList.isEmpty() ) 00229 restartTimer(); 00230 } 00231 00233 00234 KMail::ScheduledJob::ScheduledJob( KMFolder* folder, bool immediate ) 00235 : FolderJob( 0, tOther, folder ), mImmediate( immediate ), 00236 mOpeningFolder( false ) 00237 { 00238 mCancellable = true; 00239 mSrcFolder = folder; 00240 } 00241 00242 #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 Oct 1 15:19:17 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003