kmail

jobscheduler.cpp
1
29#include "jobscheduler.h"
30#include "kmfolder.h"
31#include "folderstorage.h"
32#include "kmfoldermgr.h"
33#include <kdebug.h>
34
35using namespace KMail;
36
37JobScheduler::JobScheduler( TQObject* parent, const char* name )
38 : TQObject( parent, name ), mTimer( this, "mTimer" ),
39 mPendingImmediateTasks( 0 ),
40 mCurrentTask( 0 ), mCurrentJob( 0 )
41{
42 connect( &mTimer, TQ_SIGNAL( timeout() ), TQ_SLOT( slotRunNextJob() ) );
43 // No need to start the internal timer yet, we wait for a task to be scheduled
44}
45
46
47JobScheduler::~JobScheduler()
48{
49 // delete tasks in tasklist (no autodelete for TQValueList)
50 for( TaskList::Iterator it = mTaskList.begin(); it != mTaskList.end(); ++it ) {
51 delete (*it);
52 }
53 delete mCurrentTask;
54 delete mCurrentJob;
55}
56
58{
59 bool immediate = task->isImmediate();
60 int typeId = task->taskTypeId();
61 if ( typeId ) {
62 KMFolder* folder = task->folder();
63 // Search for an identical task already scheduled
64 for( TaskList::Iterator it = mTaskList.begin(); it != mTaskList.end(); ++it ) {
65 if ( (*it)->taskTypeId() == typeId && (*it)->folder() == folder ) {
66#ifdef DEBUG_SCHEDULER
67 kdDebug(5006) << "JobScheduler: already having task type " << typeId << " for folder " << folder->label() << endl;
68#endif
69 delete task;
70 if ( !mCurrentTask && immediate ) {
71 ScheduledTask* task = *it;
72 removeTask( it );
73 runTaskNow( task );
74 }
75 return;
76 }
77 }
78 // Note that scheduling an identical task as the one currently running is allowed.
79 }
80 if ( !mCurrentTask && immediate )
81 runTaskNow( task );
82 else {
83#ifdef DEBUG_SCHEDULER
84 kdDebug(5006) << "JobScheduler: adding task " << task << " (type " << task->taskTypeId()
85 << ") for folder " << task->folder() << " " << task->folder()->label() << endl;
86#endif
87 mTaskList.append( task );
88 if ( immediate )
89 ++mPendingImmediateTasks;
90 if ( !mCurrentTask && !mTimer.isActive() )
91 restartTimer();
92 }
93}
94
95void JobScheduler::removeTask( TaskList::Iterator& it )
96{
97 if ( (*it)->isImmediate() )
98 --mPendingImmediateTasks;
99 mTaskList.remove( it );
100}
101
103{
104 if ( mCurrentTask && mCurrentTask->folder() == folder ) {
105 if ( mCurrentJob->isOpeningFolder() ) { // set when starting a job for this folder
106#ifdef DEBUG_SCHEDULER
107 kdDebug(5006) << "JobScheduler: got the opening-notification for " << folder->label() << " as expected." << endl;
108#endif
109 } else {
110 // Jobs scheduled from here should always be cancellable.
111 // One exception though, is when ExpireJob does its final KMMoveCommand.
112 // Then that command shouldn't kill its own parent job just because it opens a folder...
113 if ( mCurrentJob->isCancellable() )
114 interruptCurrentTask();
115 }
116 }
117}
118
119void JobScheduler::interruptCurrentTask()
120{
121 Q_ASSERT( mCurrentTask );
122#ifdef DEBUG_SCHEDULER
123 kdDebug(5006) << "JobScheduler: interrupting job " << mCurrentJob << " for folder " << mCurrentTask->folder()->label() << endl;
124#endif
125 // File it again. This will either delete it or put it in mTaskList.
126 registerTask( mCurrentTask );
127 mCurrentTask = 0;
128 mCurrentJob->kill(); // This deletes the job and calls slotJobFinished!
129}
130
131void JobScheduler::slotRunNextJob()
132{
133 while ( !mCurrentJob ) {
134#ifdef DEBUG_SCHEDULER
135 kdDebug(5006) << "JobScheduler: slotRunNextJob" << endl;
136#endif
137 Q_ASSERT( mCurrentTask == 0 );
138 ScheduledTask* task = 0;
139 // Find a task suitable for being run
140 for( TaskList::Iterator it = mTaskList.begin(); it != mTaskList.end(); ++it ) {
141 // Remove if folder died
142 KMFolder* folder = (*it)->folder();
143 if ( folder == 0 ) {
144#ifdef DEBUG_SCHEDULER
145 kdDebug(5006) << " folder for task " << (*it) << " was deleted" << endl;
146#endif
147 removeTask( it );
148 if ( !mTaskList.isEmpty() )
149 slotRunNextJob(); // to avoid the mess with invalid iterators :)
150 else
151 mTimer.stop();
152 return;
153 }
154 // The condition is that the folder must be unused (not open)
155 // But first we ask search folders to release their access to it
156 kmkernel->searchFolderMgr()->tryReleasingFolder( folder );
157#ifdef DEBUG_SCHEDULER
158 kdDebug(5006) << " looking at folder " << folder->label()
159 << " " << folder->location()
160 << " isOpened=" << (*it)->folder()->isOpened() << endl;
161#endif
162 if ( !folder->isOpened() ) {
163 task = *it;
164 removeTask( it );
165 break;
166 }
167 }
168
169 if ( !task ) // found nothing to run, i.e. folder was opened
170 return; // Timer keeps running, i.e. try again in 1 minute
171
172 runTaskNow( task );
173 } // If nothing to do for that task, loop and find another one to run
174}
175
176void JobScheduler::restartTimer()
177{
178 if ( mPendingImmediateTasks > 0 )
179 slotRunNextJob();
180 else
181 {
182#ifdef DEBUG_SCHEDULER
183 mTimer.start( 10000 ); // 10 seconds
184#else
185 mTimer.start( 1 * 60000 ); // 1 minute
186#endif
187 }
188}
189
190void JobScheduler::runTaskNow( ScheduledTask* task )
191{
192 Q_ASSERT( mCurrentTask == 0 );
193 if ( mCurrentTask ) {
194 interruptCurrentTask();
195 }
196 mCurrentTask = task;
197 mTimer.stop();
198 mCurrentJob = mCurrentTask->run();
199#ifdef DEBUG_SCHEDULER
200 kdDebug(5006) << "JobScheduler: task " << mCurrentTask
201 << " (type " << mCurrentTask->taskTypeId() << ")"
202 << " for folder " << mCurrentTask->folder()->label()
203 << " returned job " << mCurrentJob << " "
204 << ( mCurrentJob?mCurrentJob->className():0 ) << endl;
205#endif
206 if ( !mCurrentJob ) { // nothing to do, e.g. folder deleted
207 delete mCurrentTask;
208 mCurrentTask = 0;
209 if ( !mTaskList.isEmpty() )
210 restartTimer();
211 return;
212 }
213 // Register the job in the folder. This makes it autodeleted if the folder is deleted.
214 mCurrentTask->folder()->storage()->addJob( mCurrentJob );
215 connect( mCurrentJob, TQ_SIGNAL( finished() ), this, TQ_SLOT( slotJobFinished() ) );
216 mCurrentJob->start();
217}
218
219void JobScheduler::slotJobFinished()
220{
221 // Do we need to test for mCurrentJob->error()? What do we do then?
222#ifdef DEBUG_SCHEDULER
223 kdDebug(5006) << "JobScheduler: slotJobFinished" << endl;
224#endif
225 delete mCurrentTask;
226 mCurrentTask = 0;
227 mCurrentJob = 0;
228 if ( !mTaskList.isEmpty() )
229 restartTimer();
230}
231
232// DCOP call to pause any background jobs
233void JobScheduler::pause()
234{
235 mPendingImmediateTasks = 0;
236 if ( mCurrentJob && mCurrentJob->isCancellable() )
237 interruptCurrentTask();
238 mTimer.stop();
239}
240
241void JobScheduler::resume()
242{
243 restartTimer();
244}
245
247
248KMail::ScheduledJob::ScheduledJob( KMFolder* folder, bool immediate )
249 : FolderJob( 0, tOther, folder ), mImmediate( immediate ),
250 mOpeningFolder( false )
251{
252 mCancellable = true;
253 mSrcFolder = folder;
254}
255
256#include "jobscheduler.moc"
void addJob(FolderJob *) const
Add job for this folder.
Mail folder.
Definition: kmfolder.h:69
bool isOpened() const
Test if folder is opened.
Definition: kmfolder.cpp:500
virtual TQString label() const
Returns the label of the folder for visualization.
Definition: kmfolder.cpp:581
TQString location() const
Returns full path to folder file.
Definition: kmfolder.cpp:243
void notifyOpeningFolder(KMFolder *folder)
Called by [implementations of] FolderStorage::open() Interrupt any running job for this folder and re...
void registerTask(ScheduledTask *task)
Register a task to be done for a given folder The ownership of the task is transferred to the JobSche...
A scheduled task is some information about a folder job that should be run later.
Definition: jobscheduler.h:54
virtual ScheduledJob * run()=0
Run this task, i.e.
KMFolder * folder() const
The folder which this task is about, 0 if it was deleted meanwhile.
Definition: jobscheduler.h:79
virtual int taskTypeId() const =0
An identifier for the type of task (a bit like TQListViewItem::rtti) This allows to automatically pre...
folderdiaquotatab.h
Definition: aboutdata.cpp:40