KCoreAddons

kjob.cpp
1/*
2 This file is part of the KDE project
3
4 SPDX-FileCopyrightText: 2000 Stephan Kulow <coolo@kde.org>
5 SPDX-FileCopyrightText: 2000 David Faure <faure@kde.org>
6 SPDX-FileCopyrightText: 2006 Kevin Ottens <ervin@kde.org>
7
8 SPDX-License-Identifier: LGPL-2.0-or-later
9*/
10
11#include "kjob.h"
12#include "kjob_p.h"
13
14#include "kcoreaddons_debug.h"
15#include "kjobuidelegate.h"
16
17#include <QElapsedTimer>
18#include <QEventLoop>
19#include <QTimer>
20
21KJobPrivate::KJobPrivate()
22{
23}
24
25KJobPrivate::~KJobPrivate()
26{
27}
28
30 : QObject(parent)
31 , d_ptr(new KJobPrivate)
32{
33 d_ptr->q_ptr = this;
34}
35
36KJob::KJob(KJobPrivate &dd, QObject *parent)
37 : QObject(parent)
38 , d_ptr(&dd)
39{
40 d_ptr->q_ptr = this;
41}
42
44{
45 if (!d_ptr->isFinished) {
46 d_ptr->isFinished = true;
47 Q_EMIT finished(this, QPrivateSignal());
48 }
49
50 delete d_ptr->speedTimer;
51 delete d_ptr->uiDelegate;
52}
53
55{
56 Q_D(KJob);
57 if (!delegate) {
58 delete d->uiDelegate;
59 d->uiDelegate = nullptr;
60 return;
61 }
62
63 if (delegate->setJob(this)) {
64 delete d->uiDelegate;
65 d->uiDelegate = delegate;
66 d->uiDelegate->connectJob(this);
67 }
68}
69
70qint64 KJob::elapsedTime() const
71{
72 Q_D(const KJob);
73 return d->accumulatedElapsedTime + (d->elapsedTimer ? d->elapsedTimer->elapsed() : 0);
74}
75
77{
78 Q_D(KJob);
79 if (!d->elapsedTimer) {
80 d->elapsedTimer = std::make_unique<QElapsedTimer>();
81 }
82 d->elapsedTimer->start();
83 d->accumulatedElapsedTime = 0;
84}
85
87{
88 return d_func()->uiDelegate;
89}
90
91KJob::Capabilities KJob::capabilities() const
92{
93 return d_func()->capabilities;
94}
95
97{
98 return d_func()->suspended;
99}
100
101void KJob::finishJob(bool emitResult)
102{
103 Q_D(KJob);
104 Q_ASSERT(!d->isFinished);
105 d->isFinished = true;
106
107 if (d->eventLoop) {
108 d->eventLoop->quit();
109 }
110
111 // If we are displaying a progress dialog, remove it first.
112 Q_EMIT finished(this, QPrivateSignal());
113
114 if (emitResult) {
115 Q_EMIT result(this, QPrivateSignal());
116 }
117
118 if (isAutoDelete()) {
119 deleteLater();
120 }
121}
122
123bool KJob::kill(KillVerbosity verbosity)
124{
125 Q_D(KJob);
126 if (d->isFinished) {
127 return true;
128 }
129
130 if (doKill()) {
131 // A subclass can (but should not) call emitResult() or kill()
132 // from doKill() and thus set isFinished to true.
133 if (!d->isFinished) {
134 setError(KilledJobError);
135 finishJob(verbosity != Quietly);
136 }
137 return true;
138 } else {
139 return false;
140 }
141}
142
144{
145 Q_D(KJob);
146 if (!d->suspended) {
147 if (doSuspend()) {
148 d->suspended = true;
149 if (d->elapsedTimer) {
150 d->accumulatedElapsedTime += d->elapsedTimer->elapsed();
151 }
152 d->elapsedTimer.reset();
153 Q_EMIT suspended(this, QPrivateSignal());
154
155 return true;
156 }
157 }
158
159 return false;
160}
161
163{
164 Q_D(KJob);
165 if (d->suspended) {
166 if (doResume()) {
167 d->suspended = false;
168
169 // If the timer was never started previously, the reported time is wrong, so we rather keep it at zero.
170 if (d->accumulatedElapsedTime > 0) {
171 d->elapsedTimer = std::make_unique<QElapsedTimer>();
172 d->elapsedTimer->start();
173 }
174
175 Q_EMIT resumed(this, QPrivateSignal());
176
177 return true;
178 }
179 }
180
181 return false;
182}
183
185{
186 return false;
187}
188
190{
191 return false;
192}
193
195{
196 return false;
197}
198
200{
201 Q_D(KJob);
202 d->capabilities = capabilities;
203}
204
206{
207 Q_D(KJob);
208 // Usually this job would delete itself, via deleteLater() just after
209 // emitting result() (unless configured otherwise). Since we use an event
210 // loop below, that event loop will process the deletion event and we'll
211 // have been deleted when exec() returns. This crashes, so temporarily
212 // suspend autodeletion and manually do it afterwards.
213 const bool wasAutoDelete = isAutoDelete();
214 setAutoDelete(false);
215
216 Q_ASSERT(!d->eventLoop);
217
218 QEventLoop loop(this);
219 d->eventLoop = &loop;
220
221 start();
222 if (!d->isFinished) {
223 d->m_startedWithExec = true;
224 d->eventLoop->exec(QEventLoop::ExcludeUserInputEvents);
225 }
226 d->eventLoop = nullptr;
227
228 if (wasAutoDelete) {
229 deleteLater();
230 }
231 return (d->error == NoError);
232}
233
234int KJob::error() const
235{
236 return d_func()->error;
237}
238
239QString KJob::errorText() const
240{
241 return d_func()->errorText;
242}
243
244QString KJob::errorString() const
245{
246 return d_func()->errorText;
247}
248
249qulonglong KJob::processedAmount(Unit unit) const
250{
251 if (unit >= UnitsCount) {
252 qCWarning(KCOREADDONS_DEBUG) << "KJob::processedAmount() was called on an invalid Unit" << unit;
253 return 0;
254 }
255
256 return d_func()->m_jobAmounts[unit].processedAmount;
257}
258
259qulonglong KJob::totalAmount(Unit unit) const
260{
261 if (unit >= UnitsCount) {
262 qCWarning(KCOREADDONS_DEBUG) << "KJob::totalAmount() was called on an invalid Unit" << unit;
263 return 0;
264 }
265
266 return d_func()->m_jobAmounts[unit].totalAmount;
267}
268
269unsigned long KJob::percent() const
270{
271 return d_func()->percentage;
272}
273
275{
276 return d_func()->isFinished;
277}
278
279void KJob::setError(int errorCode)
280{
281 Q_D(KJob);
282 d->error = errorCode;
283}
284
285void KJob::setErrorText(const QString &errorText)
286{
287 Q_D(KJob);
288 d->errorText = errorText;
289}
290
291void KJob::setProcessedAmount(Unit unit, qulonglong amount)
292{
293 if (unit >= UnitsCount) {
294 qCWarning(KCOREADDONS_DEBUG) << "KJob::setProcessedAmount() was called on an invalid Unit" << unit;
295 return;
296 }
297
298 Q_D(KJob);
299
300 auto &[processed, total] = d->m_jobAmounts[unit];
301
302 const bool should_emit = (processed != amount);
303
304 processed = amount;
305
306 if (should_emit) {
307 Q_EMIT processedAmountChanged(this, unit, amount, QPrivateSignal{});
308 if (unit == d->progressUnit) {
309 Q_EMIT processedSize(this, amount);
310 emitPercent(processed, total);
311 }
312 }
313}
314
315void KJob::setTotalAmount(Unit unit, qulonglong amount)
316{
317 if (unit >= UnitsCount) {
318 qCWarning(KCOREADDONS_DEBUG) << "KJob::setTotalAmount() was called on an invalid Unit" << unit;
319 return;
320 }
321
322 Q_D(KJob);
323
324 auto &[processed, total] = d->m_jobAmounts[unit];
325
326 const bool should_emit = (total != amount);
327
328 total = amount;
329
330 if (should_emit) {
331 Q_EMIT totalAmountChanged(this, unit, amount, QPrivateSignal{});
332 if (unit == d->progressUnit) {
333 Q_EMIT totalSize(this, amount);
334 emitPercent(processed, total);
335 }
336 }
337}
338
340{
341 Q_D(KJob);
342 d->progressUnit = unit;
343}
344
345void KJob::setPercent(unsigned long percentage)
346{
347 Q_D(KJob);
348 if (d->percentage != percentage) {
349 d->percentage = percentage;
350 Q_EMIT percentChanged(this, percentage, QPrivateSignal{});
351 }
352}
353
355{
356 if (!d_func()->isFinished) {
357 finishJob(true);
358 }
359}
360
361void KJob::emitPercent(qulonglong processedAmount, qulonglong totalAmount)
362{
363 if (totalAmount != 0) {
365 }
366}
367
368void KJob::emitSpeed(unsigned long value)
369{
370 Q_D(KJob);
371 if (!d->speedTimer) {
372 d->speedTimer = new QTimer(this);
373 connect(d->speedTimer, &QTimer::timeout, this, [d]() {
374 d->speedTimeout();
375 });
376 }
377
378 Q_EMIT speed(this, value);
379 d->speedTimer->start(5000); // 5 seconds interval should be enough
380}
381
382void KJobPrivate::speedTimeout()
383{
384 Q_Q(KJob);
385 // send 0 and stop the timer
386 // timer will be restarted only when we receive another speed event
387 Q_EMIT q->speed(q, 0);
388 speedTimer->stop();
389}
390
392{
393 Q_D(const KJob);
394 return d->isAutoDelete;
395}
396
397void KJob::setAutoDelete(bool autodelete)
398{
399 Q_D(KJob);
400 d->isAutoDelete = autodelete;
401}
402
404{
405 Q_D(KJob);
406 d->m_hideFinishedNotification = hide;
407}
408
410{
411 Q_D(const KJob);
412 return d->m_hideFinishedNotification;
413}
414
416{
417 Q_D(const KJob);
418 return d->m_startedWithExec;
419}
420
421#include "moc_kjob.cpp"
The base class for all KJob UI delegate.
virtual bool setJob(KJob *job)
Attach this UI delegate to a job.
The base class for all jobs.
Definition kjob.h:74
void resumed(KJob *job)
Emitted when the job is resumed.
bool exec()
Executes the job synchronously.
Definition kjob.cpp:205
void setErrorText(const QString &errorText)
Sets the error text.
Definition kjob.cpp:285
Unit
Describes the unit used in the methods that handle reporting the job progress info.
Definition kjob.h:87
@ UnitsCount
Definition kjob.h:94
bool resume()
Resumes this job.
Definition kjob.cpp:162
bool suspend()
Suspends this job.
Definition kjob.cpp:143
qint64 elapsedTime() const
The number of milliseconds the job has been running for.
Definition kjob.cpp:70
void setTotalAmount(Unit unit, qulonglong amount)
Sets the total size.
Definition kjob.cpp:315
void emitResult()
Utility function to emit the result signal, and end this job.
Definition kjob.cpp:354
Q_SCRIPTABLE qulonglong totalAmount(Unit unit) const
Returns the total amount of a given unit for this job.
Definition kjob.cpp:259
bool isFinished() const
Returns if the job has been finished and has emitted the finished() signal.
Definition kjob.cpp:274
void startElapsedTimer()
Starts the internal elapsed time measurement timer.
Definition kjob.cpp:76
void processedSize(KJob *job, qulonglong size)
Regularly emitted to show the progress of this job (current data size in bytes for transfers,...
void result(KJob *job)
Emitted when the job is finished (except when killed with KJob::Quietly).
virtual bool doKill()
Aborts this job quietly.
Definition kjob.cpp:184
bool isSuspended() const
Returns if the job was suspended with the suspend() call.
Definition kjob.cpp:96
virtual bool doSuspend()
Suspends this job.
Definition kjob.cpp:189
void totalAmountChanged(KJob *job, KJob::Unit unit, qulonglong amount)
Emitted when we know the amount the job will have to process.
void finished(KJob *job)
Emitted when the job is finished, in any case.
Q_SCRIPTABLE qulonglong processedAmount(Unit unit) const
Returns the processed amount of a given unit for this job.
Definition kjob.cpp:249
bool isFinishedNotificationHidden() const
Whether to not show a finished notification when a job's finished signal is emitted.
Definition kjob.cpp:409
void setPercent(unsigned long percentage)
Sets the overall progress of the job.
Definition kjob.cpp:345
void setError(int errorCode)
Sets the error code.
Definition kjob.cpp:279
KJobUiDelegate * uiDelegate() const
Retrieves the delegate attached to this job.
Definition kjob.cpp:86
bool isAutoDelete() const
Returns whether this job automatically deletes itself once the job is finished.
Definition kjob.cpp:391
void totalSize(KJob *job, qulonglong size)
Emitted when we know the size of this job (data size in bytes for transfers, number of entries for li...
void setCapabilities(Capabilities capabilities)
Sets the capabilities for this job.
Definition kjob.cpp:199
void setProgressUnit(Unit unit)
Sets the unit that will be used internally to calculate the progress percentage.
Definition kjob.cpp:339
void processedAmountChanged(KJob *job, KJob::Unit unit, qulonglong amount)
Regularly emitted to show the progress of this job by giving the current amount.
void suspended(KJob *job)
Emitted when the job is suspended.
bool isStartedWithExec() const
Returns true if this job was started with exec(), which starts a nested event-loop (with QEventLoop::...
Definition kjob.cpp:415
void emitPercent(qulonglong processedAmount, qulonglong totalAmount)
Utility function for inherited jobs.
Definition kjob.cpp:361
virtual Q_SCRIPTABLE void start()=0
Starts the job asynchronously.
virtual bool doResume()
Resumes this job.
Definition kjob.cpp:194
void setAutoDelete(bool autodelete)
Sets the auto-delete property of the job.
Definition kjob.cpp:397
KJob(QObject *parent=nullptr)
Creates a new KJob object.
Definition kjob.cpp:29
void setProcessedAmount(Unit unit, qulonglong amount)
Sets the processed size.
Definition kjob.cpp:291
~KJob() override
Destroys a KJob object.
Definition kjob.cpp:43
bool kill(KJob::KillVerbosity verbosity=KJob::Quietly)
Aborts this job.
Definition kjob.cpp:123
void setUiDelegate(KJobUiDelegate *delegate)
Attach a UI delegate to this job.
Definition kjob.cpp:54
void emitSpeed(unsigned long speed)
Utility function for inherited jobs.
Definition kjob.cpp:368
void percentChanged(KJob *job, unsigned long percent)
Progress signal showing the overall progress of the job.
void speed(KJob *job, unsigned long speed)
Emitted to display information about the speed of this job.
void setFinishedNotificationHidden(bool hide=true)
This method can be used to indicate to classes listening to signals from a job that they should ideal...
Definition kjob.cpp:403
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void deleteLater()
void timeout()
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Nov 22 2024 12:07:13 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.