KCoreAddons

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

KDE's Doxygen guidelines are available online.