KJobWidgets

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

KDE's Doxygen guidelines are available online.