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
29class KJobUiDelegate;
30
31class 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 */
84class KDECORE_EXPORT KJob : public QObject
85{
86 Q_OBJECT
87 Q_ENUMS( KillVerbosity Capability Unit )
88 Q_FLAGS( Capabilities )
89
90public:
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
170public 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
201protected:
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
233public:
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
349Q_SIGNALS:
350#if !defined(Q_MOC_RUN) && !defined(DOXYGEN_SHOULD_SKIP_THIS) && !defined(IN_IDE_PARSER)
351private: // 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
408Q_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
446Q_SIGNALS:
447#if !defined(Q_MOC_RUN) && !defined(DOXYGEN_SHOULD_SKIP_THIS) && !defined(IN_IDE_PARSER)
448private: // 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
528protected:
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
626protected:
627 KJobPrivate *const d_ptr;
628 KJob(KJobPrivate &dd, QObject *parent);
629
630private:
631 Q_PRIVATE_SLOT(d_func(), void _k_speedTimeout())
632 Q_DECLARE_PRIVATE(KJob)
633};
634
635Q_DECLARE_OPERATORS_FOR_FLAGS( KJob::Capabilities )
636
637#endif
638