1 | /* This file is part of the KDE project |
2 | Copyright (C) 2000 Stephan Kulow <coolo@kde.org> |
3 | David Faure <faure@kde.org> |
4 | Copyright (C) 2006 Kevin Ottens <ervin@kde.org> |
5 | |
6 | This library is free software; you can redistribute it and/or |
7 | modify it under the terms of the GNU Library General Public |
8 | License version 2 as published by the Free Software Foundation. |
9 | |
10 | This library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Library General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Library General Public License |
16 | along with this library; see the file COPYING.LIB. If not, write to |
17 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
18 | Boston, MA 02110-1301, USA. |
19 | |
20 | */ |
21 | |
22 | #ifndef KJOB_H |
23 | #define KJOB_H |
24 | |
25 | #include <kdecore_export.h> |
26 | #include <QtCore/QObject> |
27 | #include <QtCore/QPair> |
28 | |
29 | class KJobUiDelegate; |
30 | |
31 | class KJobPrivate; |
32 | /** |
33 | * The base class for all jobs. |
34 | * |
35 | * For all jobs created in an application, the code looks like |
36 | * \code |
37 | * void SomeClass::methodWithAsynchronousJobCall() |
38 | * { |
39 | * KJob * job = someoperation( some parameters ); |
40 | * connect( job, SIGNAL( result( KJob * ) ), |
41 | * this, SLOT( handleResult( KJob * ) ) ); |
42 | * job->start(); |
43 | * } |
44 | * \endcode |
45 | * (other connects, specific to the job) |
46 | * |
47 | * And handleResult is usually at least: |
48 | * \code |
49 | * void SomeClass::handleResult( KJob *job ) |
50 | * { |
51 | * if ( job->error() ) |
52 | * doSomething(); |
53 | * } |
54 | * \endcode |
55 | * |
56 | * With the synchronous interface the code looks like |
57 | * \code |
58 | * void SomeClass::methodWithSynchronousJobCall() |
59 | * { |
60 | * KJob *job = someoperation( some parameters ); |
61 | * if ( !job->exec() ) |
62 | * { |
63 | * // An error occurred |
64 | * } |
65 | * else |
66 | * { |
67 | * // Do something |
68 | * } |
69 | * } |
70 | * \endcode |
71 | * |
72 | * Subclasses must implement start(), which should trigger |
73 | * the execution of the job (although the work should be |
74 | * done asynchronously). errorString() should also be |
75 | * reimplemented by any subclasses that introduce new |
76 | * error codes. |
77 | * |
78 | * @note: KJob and its subclasses are meant to be used |
79 | * in a fire-and-forget way. Jobs will delete themselves |
80 | * when they finish using deleteLater() (although this |
81 | * behaviour can be changed), so a job instance will |
82 | * disappear after the next event loop run. |
83 | */ |
84 | class KDECORE_EXPORT KJob : public QObject |
85 | { |
86 | Q_OBJECT |
87 | Q_ENUMS( KillVerbosity Capability Unit ) |
88 | Q_FLAGS( Capabilities ) |
89 | |
90 | public: |
91 | enum Unit { Bytes, Files, Directories }; |
92 | |
93 | enum Capability { NoCapabilities = 0x0000, |
94 | Killable = 0x0001, |
95 | Suspendable = 0x0002 }; |
96 | |
97 | Q_DECLARE_FLAGS( Capabilities, Capability ) |
98 | |
99 | /** |
100 | * Creates a new KJob object. |
101 | * |
102 | * @param parent the parent QObject |
103 | */ |
104 | explicit KJob( QObject *parent = 0 ); |
105 | |
106 | /** |
107 | * Destroys a KJob object. |
108 | */ |
109 | virtual ~KJob(); |
110 | |
111 | /** |
112 | * Attach a UI delegate to this job. |
113 | * |
114 | * If the job had another UI delegate, it's automatically deleted. Once |
115 | * attached to the job, the UI delegate will be deleted with the job. |
116 | * |
117 | * @param delegate the new UI delegate to use |
118 | * @see KJobUiDelegate |
119 | */ |
120 | void setUiDelegate( KJobUiDelegate *delegate ); |
121 | |
122 | /** |
123 | * Retrieves the delegate attached to this job. |
124 | * |
125 | * @return the delegate attached to this job, or 0 if there's no such delegate |
126 | */ |
127 | KJobUiDelegate *uiDelegate() const; |
128 | |
129 | /** |
130 | * Returns the capabilities of this job. |
131 | * |
132 | * @return the capabilities that this job supports |
133 | * @see setCapabilities() |
134 | */ |
135 | Capabilities capabilities() const; |
136 | |
137 | /** |
138 | * Returns if the job was suspended with the suspend() call. |
139 | * |
140 | * @return if the job was suspended |
141 | * @see suspend() resume() |
142 | */ |
143 | bool isSuspended() const; |
144 | |
145 | /** |
146 | * Starts the job asynchronously. |
147 | * |
148 | * When the job is finished, result() is emitted. |
149 | * |
150 | * Warning: Never implement any synchronous workload in this method. This method |
151 | * should just trigger the job startup, not do any work itself. It is expected to |
152 | * be non-blocking. |
153 | * |
154 | * This is the method all subclasses need to implement. |
155 | * It should setup and trigger the workload of the job. It should not do any |
156 | * work itself. This includes all signals and terminating the job, e.g. by |
157 | * emitResult(). The workload, which could be another method of the |
158 | * subclass, is to be triggered using the event loop, e.g. by code like: |
159 | * \code |
160 | * void ExampleJob::start() |
161 | * { |
162 | * QTimer::singleShot( 0, this, SLOT( doWork() ) ); |
163 | * } |
164 | * \endcode |
165 | */ |
166 | virtual void start() = 0; |
167 | |
168 | enum KillVerbosity { Quietly, EmitResult }; |
169 | |
170 | public Q_SLOTS: |
171 | /** |
172 | * Aborts this job. |
173 | * |
174 | * This kills and deletes the job. |
175 | * |
176 | * @param verbosity if equals to EmitResult, Job will emit signal result |
177 | * and ask uiserver to close the progress window. |
178 | * @p verbosity is set to EmitResult for subjobs. Whether applications |
179 | * should call with Quietly or EmitResult depends on whether they rely |
180 | * on result being emitted or not. Please notice that if @p verbosity is |
181 | * set to Quietly, signal result will NOT be emitted. |
182 | * @return true if the operation is supported and succeeded, false otherwise |
183 | */ |
184 | bool kill( KillVerbosity verbosity = Quietly ); |
185 | |
186 | /** |
187 | * Suspends this job. |
188 | * The job should be kept in a state in which it is possible to resume it. |
189 | * |
190 | * @return true if the operation is supported and succeeded, false otherwise |
191 | */ |
192 | bool suspend(); |
193 | |
194 | /** |
195 | * Resumes this job. |
196 | * |
197 | * @return true if the operation is supported and succeeded, false otherwise |
198 | */ |
199 | bool resume(); |
200 | |
201 | protected: |
202 | /** |
203 | * Aborts this job quietly. |
204 | * |
205 | * This simply kills the job, no error reporting or job deletion should be involved. |
206 | * |
207 | * @return true if the operation is supported and succeeded, false otherwise |
208 | */ |
209 | virtual bool doKill(); |
210 | |
211 | /** |
212 | * Suspends this job. |
213 | * |
214 | * @return true if the operation is supported and succeeded, false otherwise |
215 | */ |
216 | virtual bool doSuspend(); |
217 | |
218 | /** |
219 | * Resumes this job. |
220 | * |
221 | * @return true if the operation is supported and succeeded, false otherwise |
222 | */ |
223 | virtual bool doResume(); |
224 | |
225 | /** |
226 | * Sets the capabilities for this job. |
227 | * |
228 | * @param capabilities are the capabilities supported by this job |
229 | * @see capabilities() |
230 | */ |
231 | void setCapabilities( Capabilities capabilities ); |
232 | |
233 | public: |
234 | /** |
235 | * Executes the job synchronously. |
236 | * |
237 | * This will start a nested QEventLoop internally. Nested event loop can be dangerous and |
238 | * can have unintended side effects, you should avoid calling exec() whenever you can and use the |
239 | * asynchronous interface of KJob instead. |
240 | * |
241 | * Should you indeed call this method, you need to make sure that all callers are reentrant, |
242 | * so that events delivered by the inner event loop don't cause non-reentrant functions to be |
243 | * called, which usually wreaks havoc. |
244 | * |
245 | * Note that the event loop started by this method does not process user input events, which means |
246 | * your user interface will effectivly be blocked. Other events like paint or network events are |
247 | * still being processed. The advantage of not processing user input events is that the chance of |
248 | * accidental reentrancy is greatly reduced. Still you should avoid calling this function. |
249 | * |
250 | * @return true if the job has been executed without error, false otherwise |
251 | */ |
252 | bool exec(); |
253 | |
254 | enum |
255 | { |
256 | /*** Indicates there is no error */ |
257 | NoError = 0, |
258 | /*** Indicates the job was killed */ |
259 | KilledJobError = 1, |
260 | /*** Subclasses should define error codes starting at this value */ |
261 | UserDefinedError = 100 |
262 | }; |
263 | |
264 | |
265 | /** |
266 | * Returns the error code, if there has been an error. |
267 | * |
268 | * Only call this method from the slot connected to result(). |
269 | * |
270 | * @return the error code for this job, 0 if no error. |
271 | */ |
272 | int error() const; |
273 | |
274 | /** |
275 | * Returns the error text if there has been an error. |
276 | * |
277 | * Only call if error is not 0. |
278 | * |
279 | * This is usually some extra data associated with the error, |
280 | * such as a URL. Use errorString() to get a human-readable, |
281 | * translated message. |
282 | * |
283 | * @return a string to help understand the error |
284 | */ |
285 | QString errorText() const; |
286 | |
287 | /** |
288 | * A human-readable error message. |
289 | * |
290 | * This provides a translated, human-readable description of the |
291 | * error. Only call if error is not 0. |
292 | * |
293 | * Subclasses should implement this to create a translated |
294 | * error message from the error code and error text. |
295 | * For example: |
296 | * \code |
297 | * if (error() == ReadFailed) |
298 | * i18n( "Could not read \"%1\"", errorText() ); |
299 | * \endcode |
300 | * |
301 | * @return a translated error message, providing error() is 0 |
302 | */ |
303 | virtual QString errorString() const; |
304 | |
305 | |
306 | /** |
307 | * Returns the processed amount of a given unit for this job. |
308 | * |
309 | * @param unit the unit of the requested amount |
310 | * @return the processed size |
311 | */ |
312 | qulonglong processedAmount(Unit unit) const; |
313 | |
314 | /** |
315 | * Returns the total amount of a given unit for this job. |
316 | * |
317 | * @param unit the unit of the requested amount |
318 | * @return the total size |
319 | */ |
320 | qulonglong totalAmount(Unit unit) const; |
321 | |
322 | /** |
323 | * Returns the overall progress of this job. |
324 | * |
325 | * @return the overall progress of this job |
326 | */ |
327 | unsigned long percent() const; |
328 | |
329 | /** |
330 | * set the auto-delete property of the job. If @p autodelete is |
331 | * set to false the job will not delete itself once it is finished. |
332 | * |
333 | * The default for any KJob is to automatically delete itself. |
334 | * |
335 | * @param autodelete set to false to disable automatic deletion |
336 | * of the job. |
337 | */ |
338 | void setAutoDelete( bool autodelete ); |
339 | |
340 | /** |
341 | * Returns whether this job automatically deletes itself once |
342 | * the job is finished. |
343 | * |
344 | * @return whether the job is deleted automatically after |
345 | * finishing. |
346 | */ |
347 | bool isAutoDelete() const; |
348 | |
349 | Q_SIGNALS: |
350 | #if !defined(Q_MOC_RUN) && !defined(DOXYGEN_SHOULD_SKIP_THIS) && !defined(IN_IDE_PARSER) |
351 | private: // don't tell moc, doxygen or kdevelop, but those signals are in fact private |
352 | #endif |
353 | /** |
354 | * Emitted when the job is finished, in any case. It is used to notify |
355 | * observers that the job is terminated and that progress can be hidden. |
356 | * |
357 | * This is a private signal, it can't be emitted directly by subclasses of |
358 | * KJob, use emitResult() instead. |
359 | * |
360 | * In general, to be notified of a job's completion, client code should connect to result() |
361 | * rather than finished(), so that kill(Quietly) is indeed quiet. |
362 | * However if you store a list of jobs and they might get killed silently, |
363 | * then you must connect to this instead of result(), to avoid dangling pointers in your list. |
364 | * |
365 | * @param job the job that emitted this signal |
366 | * @internal |
367 | * |
368 | * @see result |
369 | */ |
370 | void finished(KJob *job); |
371 | |
372 | /** |
373 | * Emitted when the job is suspended. |
374 | * |
375 | * This is a private signal, it can't be emitted directly by subclasses of |
376 | * KJob. |
377 | * |
378 | * @param job the job that emitted this signal |
379 | */ |
380 | void suspended(KJob *job); |
381 | |
382 | /** |
383 | * Emitted when the job is resumed. |
384 | * |
385 | * This is a private signal, it can't be emitted directly by subclasses of |
386 | * KJob. |
387 | * |
388 | * @param job the job that emitted this signal |
389 | */ |
390 | void resumed(KJob *job); |
391 | |
392 | /** |
393 | * Emitted when the job is finished (except when killed with KJob::Quietly). |
394 | * |
395 | * Use error to know if the job was finished with error. |
396 | * |
397 | * This is a private signal, it can't be emitted directly by subclasses of |
398 | * KJob, use emitResult() instead. |
399 | * |
400 | * Please connect to this signal instead of finished. |
401 | * |
402 | * @param job the job that emitted this signal |
403 | * |
404 | * @see kill |
405 | */ |
406 | void result(KJob *job); |
407 | |
408 | Q_SIGNALS: |
409 | /** |
410 | * Emitted to display general description of this job. A description has |
411 | * a title and two optional fields which can be used to complete the |
412 | * description. |
413 | * |
414 | * Examples of titles are "Copying", "Creating resource", etc. |
415 | * The fields of the description can be "Source" with an URL, and, |
416 | * "Destination" with an URL for a "Copying" description. |
417 | * @param job the job that emitted this signal |
418 | * @param title the general description of the job |
419 | * @param field1 first field (localized name and value) |
420 | * @param field2 second field (localized name and value) |
421 | */ |
422 | void description(KJob *job, const QString &title, |
423 | const QPair<QString, QString> &field1 = qMakePair(QString(), QString()), |
424 | const QPair<QString, QString> &field2 = qMakePair(QString(), QString())); |
425 | |
426 | /** |
427 | * Emitted to display state information about this job. |
428 | * Examples of message are "Resolving host", "Connecting to host...", etc. |
429 | * |
430 | * @param job the job that emitted this signal |
431 | * @param plain the info message |
432 | * @param rich the rich text version of the message, or QString() is none is available |
433 | */ |
434 | void infoMessage( KJob *job, const QString &plain, const QString &rich = QString() ); |
435 | |
436 | /** |
437 | * Emitted to display a warning about this job. |
438 | * |
439 | * @param job the job that emitted this signal |
440 | * @param plain the warning message |
441 | * @param rich the rich text version of the message, or QString() is none is available |
442 | */ |
443 | void warning( KJob *job, const QString &plain, const QString &rich = QString() ); |
444 | |
445 | |
446 | Q_SIGNALS: |
447 | #if !defined(Q_MOC_RUN) && !defined(DOXYGEN_SHOULD_SKIP_THIS) && !defined(IN_IDE_PARSER) |
448 | private: // don't tell moc, doxygen or kdevelop, but those signals are in fact private |
449 | #endif |
450 | /** |
451 | * Emitted when we know the amount the job will have to process. The unit of this |
452 | * amount is sent too. It can be emitted several times if the job manages several |
453 | * different units. |
454 | * |
455 | * This is a private signal, it can't be emitted directly by subclasses of |
456 | * KJob, use setTotalAmount() instead. |
457 | * |
458 | * @param job the job that emitted this signal |
459 | * @param unit the unit of the total amount |
460 | * @param amount the total amount |
461 | */ |
462 | void totalAmount(KJob *job, KJob::Unit unit, qulonglong amount); |
463 | |
464 | /** |
465 | * Regularly emitted to show the progress of this job by giving the current amount. |
466 | * The unit of this amount is sent too. It can be emitted several times if the job |
467 | * manages several different units. |
468 | * |
469 | * This is a private signal, it can't be emitted directly by subclasses of |
470 | * KJob, use setProcessedAmount() instead. |
471 | * |
472 | * @param job the job that emitted this signal |
473 | * @param unit the unit of the processed amount |
474 | * @param amount the processed amount |
475 | */ |
476 | void processedAmount(KJob *job, KJob::Unit unit, qulonglong amount); |
477 | |
478 | /** |
479 | * Emitted when we know the size of this job (data size in bytes for transfers, |
480 | * number of entries for listings, etc). |
481 | * |
482 | * This is a private signal, it can't be emitted directly by subclasses of |
483 | * KJob, use setTotalAmount() instead. |
484 | * |
485 | * @param job the job that emitted this signal |
486 | * @param size the total size |
487 | */ |
488 | void totalSize(KJob *job, qulonglong size); |
489 | |
490 | /** |
491 | * Regularly emitted to show the progress of this job |
492 | * (current data size in bytes for transfers, entries listed, etc.). |
493 | * |
494 | * This is a private signal, it can't be emitted directly by subclasses of |
495 | * KJob, use setProcessedAmount() instead. |
496 | * |
497 | * @param job the job that emitted this signal |
498 | * @param size the processed size |
499 | */ |
500 | void processedSize(KJob *job, qulonglong size); |
501 | |
502 | /** |
503 | * Progress signal showing the overall progress of the job |
504 | * This is valid for any kind of job, and allows using a |
505 | * a progress bar very easily. (see KProgressBar). |
506 | * Note that this signal is not emitted for finished jobs. |
507 | * |
508 | * This is a private signal, it can't be emitted directly by subclasses of |
509 | * KJob, use emitPercent(), setPercent() setTotalAmount() or |
510 | * setProcessedAmount() instead. |
511 | * |
512 | * @param job the job that emitted this signal |
513 | * @param percent the percentage |
514 | */ |
515 | void percent( KJob *job, unsigned long percent ); |
516 | |
517 | /** |
518 | * Emitted to display information about the speed of this job. |
519 | * |
520 | * This is a private signal, it can't be emitted directly by subclasses of |
521 | * KJob, use emitSpeed() instead. |
522 | * |
523 | * @param job the job that emitted this signal |
524 | * @param speed the speed in bytes/s |
525 | */ |
526 | void speed(KJob *job, unsigned long speed); |
527 | |
528 | protected: |
529 | /** |
530 | * Sets the error code. |
531 | * |
532 | * It should be called when an error |
533 | * is encountered in the job, just before calling emitResult(). |
534 | * |
535 | * You should define an (anonymous) enum of error codes, |
536 | * with values starting at KJob::UserDefinedError, and use |
537 | * those. For example, |
538 | * @code |
539 | * enum { |
540 | * InvalidFoo = UserDefinedError, |
541 | * BarNotFound |
542 | * }; |
543 | * @endcode |
544 | * |
545 | * @param errorCode the error code |
546 | * @see emitResult() |
547 | */ |
548 | void setError( int errorCode ); |
549 | |
550 | /** |
551 | * Sets the error text. |
552 | * |
553 | * It should be called when an error |
554 | * is encountered in the job, just before calling emitResult(). |
555 | * |
556 | * Provides extra information about the error that cannot be |
557 | * determined directly from the error code. For example, a |
558 | * URL or filename. This string is not normally translatable. |
559 | * |
560 | * @param errorText the error text |
561 | * @see emitResult(), errorString(), setError() |
562 | */ |
563 | void setErrorText( const QString &errorText ); |
564 | |
565 | |
566 | /** |
567 | * Sets the processed size. The processedAmount() and percent() signals |
568 | * are emitted if the values changed. The percent() signal is emitted |
569 | * only for the progress unit. |
570 | * |
571 | * @param unit the unit of the new processed amount |
572 | * @param amount the new processed amount |
573 | */ |
574 | void setProcessedAmount(Unit unit, qulonglong amount); |
575 | |
576 | /** |
577 | * Sets the total size. The totalSize() and percent() signals |
578 | * are emitted if the values changed. The percent() signal is emitted |
579 | * only for the progress unit. |
580 | * |
581 | * @param unit the unit of the new total amount |
582 | * @param amount the new total amount |
583 | */ |
584 | void setTotalAmount(Unit unit, qulonglong amount); |
585 | |
586 | /** |
587 | * Sets the overall progress of the job. The percent() signal |
588 | * is emitted if the value changed. |
589 | * |
590 | * @param percentage the new overall progress |
591 | */ |
592 | void setPercent( unsigned long percentage ); |
593 | |
594 | |
595 | /** |
596 | * Utility function to emit the result signal, and suicide this job. |
597 | * It first notifies the observers to hide the progress for this job using |
598 | * the finished() signal. |
599 | * |
600 | * @note: Deletes this job using deleteLater(). |
601 | * |
602 | * @see result() |
603 | * @see finished() |
604 | */ |
605 | void emitResult(); |
606 | |
607 | /** |
608 | * Utility function for inherited jobs. |
609 | * Emits the percent signal if bigger than previous value, |
610 | * after calculating it from the parameters. |
611 | * |
612 | * @param processedAmount the processed amount |
613 | * @param totalAmount the total amount |
614 | * @see percent() |
615 | */ |
616 | void emitPercent( qulonglong processedAmount, qulonglong totalAmount ); |
617 | |
618 | /** |
619 | * Utility function for inherited jobs. |
620 | * Emits the speed signal and starts the timer for removing that info |
621 | * |
622 | * @param speed the speed in bytes/s |
623 | */ |
624 | void emitSpeed(unsigned long speed); |
625 | |
626 | protected: |
627 | KJobPrivate *const d_ptr; |
628 | KJob(KJobPrivate &dd, QObject *parent); |
629 | |
630 | private: |
631 | Q_PRIVATE_SLOT(d_func(), void _k_speedTimeout()) |
632 | Q_DECLARE_PRIVATE(KJob) |
633 | }; |
634 | |
635 | Q_DECLARE_OPERATORS_FOR_FLAGS( KJob::Capabilities ) |
636 | |
637 | #endif |
638 | |