1 /*
2 This file is part of the KDE project
3 SPDX-FileCopyrightText: 2000 Matej Koss <koss@miesto.sk>
4 SPDX-FileCopyrightText: 2007 Kevin Ottens <ervin@kde.org>
5 SPDX-FileCopyrightText: 2007 Rafael Fernández López <ereslibre@kde.org>
6 SPDX-FileCopyrightText: 2009 Shaun Reich <shaun.reich@kdemail.net>
7
8 SPDX-License-Identifier: LGPL-2.0-only
9 */
10
11 #include "kwidgetjobtracker.h"
12 #include "kjobtrackerformatters_p.h"
13 #include "kwidgetjobtracker_p.h"
14
15 #include <QCoreApplication>
16 #include <QDir>
17 #include <QEvent>
18 #include <QGridLayout>
19 #include <QLabel>
20 #include <QProcess>
21 #include <QProgressBar>
22 #include <QPushButton>
23 #include <QStyle>
24 #include <QTimer>
25 #include <QVBoxLayout>
26
27 #include <KSeparator>
28 #include <KSqueezedTextLabel>
29
_k_showProgressWidget()30 void KWidgetJobTrackerPrivate::_k_showProgressWidget()
31 {
32 Q_Q(KWidgetJobTracker);
33
34 if (progressWidgetsToBeShown.isEmpty()) {
35 return;
36 }
37
38 KJob *job = progressWidgetsToBeShown.dequeue();
39
40 // If the job has been unregistered before reaching this point, widget will
41 // return 0.
42 QWidget *widget = q->widget(job);
43
44 if (widget) {
45 // Don't steal the focus from the current widget (e. g. Kate)
46 widget->setAttribute(Qt::WA_ShowWithoutActivating);
47 widget->show();
48 }
49 }
50
KWidgetJobTracker(QWidget * parent)51 KWidgetJobTracker::KWidgetJobTracker(QWidget *parent)
52 : KAbstractWidgetJobTracker(*new KWidgetJobTrackerPrivate(parent, this), parent)
53 {
54 }
55
56 KWidgetJobTracker::~KWidgetJobTracker() = default;
57
widget(KJob * job)58 QWidget *KWidgetJobTracker::widget(KJob *job)
59 {
60 Q_D(KWidgetJobTracker);
61
62 return d->progressWidget.value(job, nullptr);
63 }
64
registerJob(KJob * job)65 void KWidgetJobTracker::registerJob(KJob *job)
66 {
67 Q_D(KWidgetJobTracker);
68
69 auto *vi = new KWidgetJobTrackerPrivate::ProgressWidget(job, this, d->parent);
70 vi->jobRegistered = true;
71 vi->setAttribute(Qt::WA_DeleteOnClose);
72 d->progressWidget.insert(job, vi);
73 d->progressWidgetsToBeShown.enqueue(job);
74
75 KAbstractWidgetJobTracker::registerJob(job);
76
77 QTimer::singleShot(500, this, SLOT(_k_showProgressWidget()));
78 }
79
unregisterJob(KJob * job)80 void KWidgetJobTracker::unregisterJob(KJob *job)
81 {
82 Q_D(KWidgetJobTracker);
83
84 KAbstractWidgetJobTracker::unregisterJob(job);
85
86 d->progressWidgetsToBeShown.removeAll(job);
87 KWidgetJobTrackerPrivate::ProgressWidget *pWidget = d->progressWidget.value(job, nullptr);
88 if (!pWidget) {
89 return;
90 }
91
92 pWidget->jobRegistered = false;
93 pWidget->deref();
94 }
95
keepOpen(KJob * job) const96 bool KWidgetJobTracker::keepOpen(KJob *job) const
97 {
98 Q_D(const KWidgetJobTracker);
99
100 KWidgetJobTrackerPrivate::ProgressWidget *pWidget = d->progressWidget.value(job, nullptr);
101 if (!pWidget) {
102 return false;
103 }
104
105 return pWidget->keepOpenCheck->isChecked();
106 }
107
infoMessage(KJob * job,const QString & plain,const QString & rich)108 void KWidgetJobTracker::infoMessage(KJob *job, const QString &plain, const QString &rich)
109 {
110 Q_D(KWidgetJobTracker);
111
112 KWidgetJobTrackerPrivate::ProgressWidget *pWidget = d->progressWidget.value(job, nullptr);
113 if (!pWidget) {
114 return;
115 }
116
117 pWidget->infoMessage(plain, rich);
118 }
119
description(KJob * job,const QString & title,const QPair<QString,QString> & field1,const QPair<QString,QString> & field2)120 void KWidgetJobTracker::description(KJob *job, const QString &title, const QPair<QString, QString> &field1, const QPair<QString, QString> &field2)
121 {
122 Q_D(KWidgetJobTracker);
123
124 KWidgetJobTrackerPrivate::ProgressWidget *pWidget = d->progressWidget.value(job, nullptr);
125 if (!pWidget) {
126 return;
127 }
128
129 pWidget->description(title, field1, field2);
130 }
131
totalAmount(KJob * job,KJob::Unit unit,qulonglong amount)132 void KWidgetJobTracker::totalAmount(KJob *job, KJob::Unit unit, qulonglong amount)
133 {
134 Q_D(KWidgetJobTracker);
135
136 KWidgetJobTrackerPrivate::ProgressWidget *pWidget = d->progressWidget.value(job, nullptr);
137 if (!pWidget) {
138 return;
139 }
140
141 pWidget->totalAmount(unit, amount);
142 }
143
processedAmount(KJob * job,KJob::Unit unit,qulonglong amount)144 void KWidgetJobTracker::processedAmount(KJob *job, KJob::Unit unit, qulonglong amount)
145 {
146 Q_D(KWidgetJobTracker);
147
148 KWidgetJobTrackerPrivate::ProgressWidget *pWidget = d->progressWidget.value(job, nullptr);
149 if (!pWidget) {
150 return;
151 }
152
153 pWidget->processedAmount(unit, amount);
154 }
155
percent(KJob * job,unsigned long percent)156 void KWidgetJobTracker::percent(KJob *job, unsigned long percent)
157 {
158 Q_D(KWidgetJobTracker);
159
160 KWidgetJobTrackerPrivate::ProgressWidget *pWidget = d->progressWidget.value(job, nullptr);
161 if (!pWidget) {
162 return;
163 }
164
165 pWidget->percent(percent);
166 }
167
speed(KJob * job,unsigned long value)168 void KWidgetJobTracker::speed(KJob *job, unsigned long value)
169 {
170 Q_D(KWidgetJobTracker);
171
172 KWidgetJobTrackerPrivate::ProgressWidget *pWidget = d->progressWidget.value(job, nullptr);
173 if (!pWidget) {
174 return;
175 }
176
177 pWidget->speed(value);
178 }
179
slotClean(KJob * job)180 void KWidgetJobTracker::slotClean(KJob *job)
181 {
182 Q_D(KWidgetJobTracker);
183
184 KWidgetJobTrackerPrivate::ProgressWidget *pWidget = d->progressWidget.value(job, nullptr);
185 if (!pWidget) {
186 return;
187 }
188
189 pWidget->slotClean();
190 }
191
suspended(KJob * job)192 void KWidgetJobTracker::suspended(KJob *job)
193 {
194 Q_D(KWidgetJobTracker);
195
196 KWidgetJobTrackerPrivate::ProgressWidget *pWidget = d->progressWidget.value(job, nullptr);
197 if (!pWidget) {
198 return;
199 }
200
201 pWidget->suspended();
202 }
203
resumed(KJob * job)204 void KWidgetJobTracker::resumed(KJob *job)
205 {
206 Q_D(KWidgetJobTracker);
207
208 KWidgetJobTrackerPrivate::ProgressWidget *pWidget = d->progressWidget.value(job, nullptr);
209 if (!pWidget) {
210 return;
211 }
212
213 pWidget->resumed();
214 }
215
ref()216 void KWidgetJobTrackerPrivate::ProgressWidget::ref()
217 {
218 ++refCount;
219 }
220
deref()221 void KWidgetJobTrackerPrivate::ProgressWidget::deref()
222 {
223 if (refCount) {
224 --refCount;
225 }
226
227 if (!refCount) {
228 if (!keepOpenCheck->isChecked()) {
229 closeNow();
230 } else {
231 slotClean();
232 }
233 }
234 }
235
closeNow()236 void KWidgetJobTrackerPrivate::ProgressWidget::closeNow()
237 {
238 close();
239
240 // It might happen the next scenario:
241 // - Start a job which opens a progress widget. Keep it open. Address job is 0xdeadbeef
242 // - Start a new job, which is given address 0xdeadbeef. A new window is opened.
243 // This one will take much longer to complete. The key 0xdeadbeef on the widget map now
244 // stores the new widget address.
245 // - Close the first progress widget that was opened (and has already finished) while the
246 // last one is still running. We remove its reference on the map. Wrong.
247 // For that reason we have to check if the map stores the widget as the current one.
248 // ereslibre
249 if (tracker->d_func()->progressWidget[job] == this) {
250 tracker->d_func()->progressWidget.remove(job);
251 tracker->d_func()->progressWidgetsToBeShown.removeAll(job);
252 }
253 }
254
eventFilter(QObject * watched,QEvent * event)255 bool KWidgetJobTrackerPrivate::ProgressWidget::eventFilter(QObject *watched, QEvent *event)
256 {
257 // Handle context menu events for the source/dest labels here, so that we are ref()ed while the
258 // menu is exec()ed, to avoid a crash if the job finishes meanwhile. #159621.
259 if ((watched == sourceEdit || watched == destEdit) && event->type() == QEvent::ContextMenu) {
260 ref();
261 watched->event(event);
262 deref();
263 return true;
264 }
265
266 return QWidget::eventFilter(watched, event);
267 }
268
infoMessage(const QString & plain,const QString &)269 void KWidgetJobTrackerPrivate::ProgressWidget::infoMessage(const QString &plain, const QString & /*rich*/)
270 {
271 speedLabel->setText(plain);
272 speedLabel->setAlignment(speedLabel->alignment() & ~Qt::TextWordWrap);
273 }
274
description(const QString & title,const QPair<QString,QString> & field1,const QPair<QString,QString> & field2)275 void KWidgetJobTrackerPrivate::ProgressWidget::description(const QString &title, const QPair<QString, QString> &field1, const QPair<QString, QString> &field2)
276 {
277 setWindowTitle(title);
278 caption = title;
279 sourceInvite->setText(QCoreApplication::translate("KWidgetJobTracker", "%1:", "%1 is the label, we add a ':' to it").arg(field1.first));
280 sourceEdit->setText(field1.second);
281
282 if (field2.first.isEmpty()) {
283 setDestVisible(false);
284 } else {
285 setDestVisible(true);
286 checkDestination(QUrl::fromUserInput(field2.second)); // path or URL
287 destInvite->setText(QCoreApplication::translate("KWidgetJobTracker", "%1:", "%1 is the label, we add a ':' to it").arg(field2.first));
288 destEdit->setText(field2.second);
289 }
290 }
291
totalAmount(KJob::Unit unit,qulonglong amount)292 void KWidgetJobTrackerPrivate::ProgressWidget::totalAmount(KJob::Unit unit, qulonglong amount)
293 {
294 switch (unit) {
295 case KJob::Bytes:
296 totalSizeKnown = true;
297 // size is measured in bytes
298 if (totalSize == amount) {
299 return;
300 }
301 totalSize = amount;
302 if (!startTime.isValid()) {
303 startTime.start();
304 }
305 break;
306
307 case KJob::Files:
308 if (totalFiles == amount) {
309 return;
310 }
311 totalFiles = amount;
312 showTotals();
313 break;
314
315 case KJob::Directories:
316 if (totalDirs == amount) {
317 return;
318 }
319 totalDirs = amount;
320 showTotals();
321 break;
322
323 case KJob::Items:
324 if (totalItems == amount) {
325 return;
326 }
327 totalItems = amount;
328 showTotals();
329 break;
330 }
331 }
332
processedAmount(KJob::Unit unit,qulonglong amount)333 void KWidgetJobTrackerPrivate::ProgressWidget::processedAmount(KJob::Unit unit, qulonglong amount)
334 {
335 QString tmp;
336
337 switch (unit) {
338 case KJob::Bytes:
339 if (processedSize == amount) {
340 return;
341 }
342 processedSize = amount;
343
344 if (totalSizeKnown) {
345 //~ singular %1 of %2 complete
346 //~ plural %1 of %2 complete
347 tmp = QCoreApplication::translate("KWidgetJobTracker", "%1 of %2 complete", "", amount)
348 .arg(KJobTrackerFormatters::byteSize(amount), KJobTrackerFormatters::byteSize(totalSize));
349 } else {
350 tmp = KJobTrackerFormatters::byteSize(amount);
351 }
352 sizeLabel->setText(tmp);
353 if (!totalSizeKnown) { // update jumping progressbar
354 progressBar->setValue(amount);
355 }
356 break;
357
358 case KJob::Directories:
359 if (processedDirs == amount) {
360 return;
361 }
362 processedDirs = amount;
363
364 //~ singular %1 / %n folder
365 //~ plural %1 / %n folders
366 tmp = QCoreApplication::translate("KWidgetJobTracker", "%1 / %n folder(s)", "", totalDirs).arg(processedDirs);
367 tmp += QLatin1String(" ");
368 //~ singular %1 / %n file
369 //~ plural %1 / %n files
370 tmp += QCoreApplication::translate("KWidgetJobTracker", "%1 / %n file(s)", "", totalFiles).arg(processedFiles);
371 progressLabel->setText(tmp);
372 break;
373
374 case KJob::Files:
375 if (processedFiles == amount) {
376 return;
377 }
378 processedFiles = amount;
379
380 if (totalDirs > 1) {
381 //~ singular %1 / %n folder
382 //~ plural %1 / %n folders
383 tmp = QCoreApplication::translate("KWidgetJobTracker", "%1 / %n folder(s)", "", totalDirs).arg(processedDirs);
384 tmp += QLatin1String(" ");
385 }
386 //~ singular %1 / %n file
387 //~ plural %1 / %n files
388 tmp += QCoreApplication::translate("KWidgetJobTracker", "%1 / %n file(s)", "", totalFiles).arg(processedFiles);
389 progressLabel->setText(tmp);
390 break;
391
392 case KJob::Items:
393 if (processedItems == amount) {
394 return;
395 }
396 processedItems = amount;
397 //~ singular %1 / %n item
398 //~ plural %1 / %n items
399 tmp = QCoreApplication::translate("KWidgetJobTracker", "%1 / %n item(s)", "", totalItems).arg(processedItems);
400 progressLabel->setText(tmp);
401 break;
402 }
403 }
404
percent(unsigned long percent)405 void KWidgetJobTrackerPrivate::ProgressWidget::percent(unsigned long percent)
406 {
407 QString title = caption + QLatin1String(" (");
408
409 if (totalSizeKnown) {
410 title += QCoreApplication::translate("KWidgetJobTracker", "%1% of %2").arg(percent).arg(KJobTrackerFormatters::byteSize(totalSize));
411 } else if (totalFiles) {
412 //~ singular %1% of %n file
413 //~ plural %1% of %n files
414 title += QCoreApplication::translate("KWidgetJobTracker", "%1% of %n file(s)", "", totalFiles).arg(percent);
415 } else {
416 title += QCoreApplication::translate("KWidgetJobTracker", "%1%").arg(percent);
417 }
418
419 title += QLatin1Char(')');
420
421 progressBar->setMaximum(100);
422 progressBar->setValue(percent);
423 setWindowTitle(title);
424 }
425
speed(unsigned long value)426 void KWidgetJobTrackerPrivate::ProgressWidget::speed(unsigned long value)
427 {
428 if (value == 0) {
429 speedLabel->setText(QCoreApplication::translate("KWidgetJobTracker", "Stalled"));
430 } else {
431 const QString speedStr = KJobTrackerFormatters::byteSize(value);
432 if (totalSizeKnown) {
433 const int remaining = 1000 * (totalSize - processedSize) / value;
434 //~ singular %1/s (%2 remaining)
435 //~ plural %1/s (%2 remaining)
436 speedLabel->setText(QCoreApplication::translate("KWidgetJobTracker", "%1/s (%2 remaining)", "", remaining)
437 .arg(speedStr, KJobTrackerFormatters::duration(remaining)));
438 } else { // total size is not known (#24228)
439 speedLabel->setText(QCoreApplication::translate("KWidgetJobTracker", "%1/s", "speed in bytes per second").arg(speedStr));
440 }
441 }
442 }
443
slotClean()444 void KWidgetJobTrackerPrivate::ProgressWidget::slotClean()
445 {
446 percent(100);
447 cancelClose->setText(QCoreApplication::translate("KWidgetJobTracker", "&Close"));
448 cancelClose->setIcon(QIcon::fromTheme(QStringLiteral("window-close")));
449 cancelClose->setToolTip(QCoreApplication::translate("KWidgetJobTracker", "Close the current window or document"));
450 openFile->setEnabled(true);
451 if (!totalSizeKnown || totalSize < processedSize) {
452 totalSize = processedSize;
453 }
454 processedAmount(KJob::Bytes, totalSize);
455 keepOpenCheck->setEnabled(false);
456 pauseButton->setEnabled(false);
457 if (startTime.isValid()) {
458 int s = startTime.elapsed();
459 if (!s) {
460 s = 1;
461 }
462 speedLabel->setText(QCoreApplication::translate("KWidgetJobTracker", "%1/s (done)").arg(KJobTrackerFormatters::byteSize(1000 * totalSize / s)));
463 }
464 }
465
suspended()466 void KWidgetJobTrackerPrivate::ProgressWidget::suspended()
467 {
468 pauseButton->setText(QCoreApplication::translate("KWidgetJobTracker", "&Resume"));
469 suspendedProperty = true;
470 }
471
resumed()472 void KWidgetJobTrackerPrivate::ProgressWidget::resumed()
473 {
474 pauseButton->setText(QCoreApplication::translate("KWidgetJobTracker", "&Pause"));
475 suspendedProperty = false;
476 }
477
closeEvent(QCloseEvent * event)478 void KWidgetJobTrackerPrivate::ProgressWidget::closeEvent(QCloseEvent *event)
479 {
480 if (jobRegistered && tracker->stopOnClose(job)) {
481 tracker->slotStop(job);
482 }
483
484 QWidget::closeEvent(event);
485 }
486
init()487 void KWidgetJobTrackerPrivate::ProgressWidget::init()
488 {
489 setWindowIcon(QIcon::fromTheme(QStringLiteral("document-save"), windowIcon()));
490
491 QVBoxLayout *topLayout = new QVBoxLayout(this);
492
493 QGridLayout *grid = new QGridLayout();
494 topLayout->addLayout(grid);
495 const int horizontalSpacing = style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing);
496 grid->addItem(new QSpacerItem(horizontalSpacing, 0), 0, 1);
497 // filenames or action name
498 sourceInvite = new QLabel(QCoreApplication::translate("KWidgetJobTracker", "Source:", "The source url of a job"), this);
499 grid->addWidget(sourceInvite, 0, 0);
500
501 sourceEdit = new KSqueezedTextLabel(this);
502 sourceEdit->setTextInteractionFlags(Qt::TextSelectableByMouse);
503 sourceEdit->installEventFilter(this);
504 grid->addWidget(sourceEdit, 0, 2);
505
506 destInvite = new QLabel(QCoreApplication::translate("KWidgetJobTracker", "Destination:", "The destination url of a job"), this);
507 grid->addWidget(destInvite, 1, 0);
508
509 destEdit = new KSqueezedTextLabel(this);
510 destEdit->setTextInteractionFlags(Qt::TextSelectableByMouse);
511 destEdit->installEventFilter(this);
512 grid->addWidget(destEdit, 1, 2);
513
514 QHBoxLayout *progressHBox = new QHBoxLayout();
515 topLayout->addLayout(progressHBox);
516
517 progressBar = new QProgressBar(this);
518 progressBar->setMaximum(0); // want a jumping progress bar if percent is not emitted
519 progressHBox->addWidget(progressBar);
520
521 suspendedProperty = false;
522
523 // processed info
524 QHBoxLayout *hBox = new QHBoxLayout();
525 topLayout->addLayout(hBox);
526
527 arrowButton = new QPushButton(this);
528 arrowButton->setMaximumSize(QSize(32, 25));
529 arrowButton->setIcon(QIcon::fromTheme(QStringLiteral("arrow-down")));
530 arrowButton->setToolTip(QCoreApplication::translate("KWidgetJobTracker", "Click this to expand the dialog, to show details"));
531 arrowState = Qt::DownArrow;
532 connect(arrowButton, &QPushButton::clicked, this, &KWidgetJobTrackerPrivate::ProgressWidget::arrowClicked);
533 hBox->addWidget(arrowButton);
534 hBox->addStretch(1);
535
536 KSeparator *separator1 = new KSeparator(Qt::Horizontal, this);
537 topLayout->addWidget(separator1);
538
539 sizeLabel = new QLabel(this);
540 hBox->addWidget(sizeLabel, 0, Qt::AlignLeft);
541
542 resumeLabel = new QLabel(this);
543 hBox->addWidget(resumeLabel);
544
545 pauseButton = new QPushButton(QCoreApplication::translate("KWidgetJobTracker", "&Pause"), this);
546 pauseButton->setVisible(job && (job->capabilities() & KJob::Suspendable));
547 connect(pauseButton, &QPushButton::clicked, this, &KWidgetJobTrackerPrivate::ProgressWidget::pauseResumeClicked);
548 hBox->addWidget(pauseButton);
549
550 hBox = new QHBoxLayout();
551 topLayout->addLayout(hBox);
552
553 speedLabel = new QLabel(this);
554 hBox->addWidget(speedLabel, 1);
555 speedLabel->hide();
556
557 hBox = new QHBoxLayout();
558 topLayout->addLayout(hBox);
559
560 progressLabel = new QLabel(this);
561 progressLabel->setAlignment(Qt::AlignLeft);
562 hBox->addWidget(progressLabel);
563 progressLabel->hide();
564
565 keepOpenCheck = new QCheckBox(QCoreApplication::translate("KWidgetJobTracker", "&Keep this window open after transfer is complete"), this);
566 connect(keepOpenCheck, &QCheckBox::toggled, this, &KWidgetJobTrackerPrivate::ProgressWidget::keepOpenToggled);
567 topLayout->addWidget(keepOpenCheck);
568 keepOpenCheck->hide();
569
570 hBox = new QHBoxLayout();
571 topLayout->addLayout(hBox);
572
573 openFile = new QPushButton(QCoreApplication::translate("KWidgetJobTracker", "Open &File"), this);
574 connect(openFile, &QPushButton::clicked, this, &KWidgetJobTrackerPrivate::ProgressWidget::openFileClicked);
575 hBox->addWidget(openFile);
576 openFile->setEnabled(false);
577 openFile->hide();
578
579 openLocation = new QPushButton(QCoreApplication::translate("KWidgetJobTracker", "Open &Destination"), this);
580 connect(openLocation, &QPushButton::clicked, this, &KWidgetJobTrackerPrivate::ProgressWidget::openLocationClicked);
581 hBox->addWidget(openLocation);
582 openLocation->hide();
583
584 hBox->addStretch(1);
585
586 cancelClose = new QPushButton(this);
587 cancelClose->setText(QCoreApplication::translate("KWidgetJobTracker", "&Cancel"));
588 cancelClose->setIcon(QIcon::fromTheme(QStringLiteral("dialog-cancel")));
589 connect(cancelClose, &QPushButton::clicked, this, &KWidgetJobTrackerPrivate::ProgressWidget::cancelClicked);
590 hBox->addWidget(cancelClose);
591
592 resize(sizeHint());
593 setMaximumHeight(sizeHint().height());
594
595 setWindowTitle(QCoreApplication::translate("KWidgetJobTracker", "Progress Dialog")); // show something better than kuiserver
596 }
597
showTotals()598 void KWidgetJobTrackerPrivate::ProgressWidget::showTotals()
599 {
600 // Show the totals in the progress label, if we still haven't
601 // processed anything. This is useful when the stat'ing phase
602 // of CopyJob takes a long time (e.g. over networks).
603 if (processedFiles == 0 && processedDirs == 0 && processedItems == 0) {
604 QString total;
605 if (totalItems > 1) {
606 //~ singular %n item
607 //~ plural %n items
608 total = QCoreApplication::translate("KWidgetJobTracker", "%n item(s)", "", totalItems);
609 progressLabel->setText(total);
610 } else {
611 if (totalDirs > 1) {
612 //~ singular %n folder
613 //~ plural %n folders
614 total = QCoreApplication::translate("KWidgetJobTracker", "%n folder(s)", "", totalDirs) + QLatin1String(" ");
615 }
616 //~ singular %n file
617 //~ plural %n files
618 total += QCoreApplication::translate("KWidgetJobTracker", "%n file(s)", "", totalFiles);
619 progressLabel->setText(total);
620 }
621 }
622 }
623
setDestVisible(bool visible)624 void KWidgetJobTrackerPrivate::ProgressWidget::setDestVisible(bool visible)
625 {
626 // We can't hide the destInvite/destEdit labels,
627 // because it screws up the QGridLayout.
628 if (visible) {
629 destInvite->show();
630 destEdit->show();
631 } else {
632 destInvite->hide();
633 destEdit->hide();
634 destInvite->setText(QString());
635 destEdit->setText(QString());
636 }
637 setMaximumHeight(sizeHint().height());
638 }
639
checkDestination(const QUrl & dest)640 void KWidgetJobTrackerPrivate::ProgressWidget::checkDestination(const QUrl &dest)
641 {
642 bool ok = true;
643
644 if (dest.isLocalFile()) {
645 const QString path = dest.toLocalFile();
646 if (path.contains(QDir::tempPath())) {
647 ok = false; // it's in the tmp directory
648 }
649 }
650
651 if (ok) {
652 openFile->show();
653 openLocation->show();
654 keepOpenCheck->show();
655 setMaximumHeight(sizeHint().height());
656 location = dest;
657 }
658 }
659
keepOpenToggled(bool keepOpen)660 void KWidgetJobTrackerPrivate::ProgressWidget::keepOpenToggled(bool keepOpen)
661 {
662 if (keepOpen) {
663 Q_ASSERT(!tracker->d_func()->eventLoopLocker);
664 tracker->d_func()->eventLoopLocker = new QEventLoopLocker;
665 } else {
666 delete tracker->d_func()->eventLoopLocker;
667 tracker->d_func()->eventLoopLocker = nullptr;
668 }
669 }
670
openFileClicked()671 void KWidgetJobTrackerPrivate::ProgressWidget::openFileClicked()
672 {
673 QProcess::startDetached(QStringLiteral("kde-open"), QStringList() << location.toDisplayString());
674 }
675
openLocationClicked()676 void KWidgetJobTrackerPrivate::ProgressWidget::openLocationClicked()
677 {
678 QProcess::startDetached(QStringLiteral("kde-open"), QStringList() << location.adjusted(QUrl::RemoveFilename).toString());
679 }
680
pauseResumeClicked()681 void KWidgetJobTrackerPrivate::ProgressWidget::pauseResumeClicked()
682 {
683 if (jobRegistered && !suspendedProperty) {
684 tracker->slotSuspend(job);
685 } else if (jobRegistered) {
686 tracker->slotResume(job);
687 }
688 }
689
cancelClicked()690 void KWidgetJobTrackerPrivate::ProgressWidget::cancelClicked()
691 {
692 if (jobRegistered) {
693 tracker->slotStop(job);
694 }
695 closeNow();
696 }
697
arrowClicked()698 void KWidgetJobTrackerPrivate::ProgressWidget::arrowClicked()
699 {
700 if (arrowState == Qt::DownArrow) {
701 // The arrow is in the down position, dialog is collapsed, expand it and change icon.
702 progressLabel->show();
703 speedLabel->show();
704 arrowButton->setIcon(QIcon::fromTheme(QStringLiteral("arrow-up")));
705 arrowButton->setToolTip(QCoreApplication::translate("KWidgetJobTracker", "Click this to collapse the dialog, to hide details"));
706 arrowState = Qt::UpArrow;
707 } else {
708 // Collapse the dialog
709 progressLabel->hide();
710 speedLabel->hide();
711 arrowButton->setIcon(QIcon::fromTheme(QStringLiteral("arrow-down")));
712 arrowButton->setToolTip(QCoreApplication::translate("KWidgetJobTracker", "Click this to expand the dialog, to show details"));
713 arrowState = Qt::DownArrow;
714 }
715 setMaximumHeight(sizeHint().height());
716 }
717
718 #include "moc_kwidgetjobtracker.cpp"
719 #include "moc_kwidgetjobtracker_p.cpp"
720