File indexing completed on 2024-04-21 03:56:19

0001 /*
0002     This file is part of the KDE project
0003     SPDX-FileCopyrightText: 2000 Matej Koss <koss@miesto.sk>
0004     SPDX-FileCopyrightText: 2007 Kevin Ottens <ervin@kde.org>
0005     SPDX-FileCopyrightText: 2007 Rafael Fernández López <ereslibre@kde.org>
0006     SPDX-FileCopyrightText: 2009 Shaun Reich <shaun.reich@kdemail.net>
0007 
0008     SPDX-License-Identifier: LGPL-2.0-only
0009 */
0010 
0011 #include "kwidgetjobtracker.h"
0012 #include "debug.h"
0013 #include "kjobtrackerformatters_p.h"
0014 #include "kwidgetjobtracker_p.h"
0015 
0016 #include <QCoreApplication>
0017 #include <QDir>
0018 #include <QEvent>
0019 #include <QGridLayout>
0020 #include <QLabel>
0021 #include <QProcess>
0022 #include <QProgressBar>
0023 #include <QPushButton>
0024 #include <QStandardPaths>
0025 #include <QStyle>
0026 #include <QTimer>
0027 #include <QVBoxLayout>
0028 
0029 #include <KSeparator>
0030 #include <KSqueezedTextLabel>
0031 
0032 void KWidgetJobTrackerPrivate::_k_showProgressWidget()
0033 {
0034     Q_Q(KWidgetJobTracker);
0035 
0036     if (progressWidgetsToBeShown.isEmpty()) {
0037         return;
0038     }
0039 
0040     KJob *job = progressWidgetsToBeShown.dequeue();
0041 
0042     // If the job has been unregistered before reaching this point, widget will
0043     // return 0.
0044     QWidget *widget = q->widget(job);
0045 
0046     if (widget) {
0047         // Don't steal the focus from the current widget (e. g. Kate)
0048         widget->setAttribute(Qt::WA_ShowWithoutActivating);
0049         widget->show();
0050     }
0051 }
0052 
0053 KWidgetJobTracker::KWidgetJobTracker(QWidget *parent)
0054     : KAbstractWidgetJobTracker(*new KWidgetJobTrackerPrivate(parent, this), parent)
0055 {
0056 }
0057 
0058 KWidgetJobTracker::~KWidgetJobTracker() = default;
0059 
0060 QWidget *KWidgetJobTracker::widget(KJob *job)
0061 {
0062     Q_D(KWidgetJobTracker);
0063 
0064     return d->progressWidget.value(job, nullptr);
0065 }
0066 
0067 void KWidgetJobTracker::registerJob(KJob *job)
0068 {
0069     Q_D(KWidgetJobTracker);
0070 
0071     auto *vi = new KWidgetJobTrackerPrivate::ProgressWidget(job, this, d->parent);
0072     vi->jobRegistered = true;
0073     vi->setAttribute(Qt::WA_DeleteOnClose);
0074     d->progressWidget.insert(job, vi);
0075     d->progressWidgetsToBeShown.enqueue(job);
0076 
0077     KAbstractWidgetJobTracker::registerJob(job);
0078 
0079     QTimer::singleShot(500, this, SLOT(_k_showProgressWidget()));
0080 }
0081 
0082 void KWidgetJobTracker::unregisterJob(KJob *job)
0083 {
0084     Q_D(KWidgetJobTracker);
0085 
0086     KAbstractWidgetJobTracker::unregisterJob(job);
0087 
0088     d->progressWidgetsToBeShown.removeAll(job);
0089     KWidgetJobTrackerPrivate::ProgressWidget *pWidget = d->progressWidget.value(job, nullptr);
0090     if (!pWidget) {
0091         return;
0092     }
0093 
0094     pWidget->jobRegistered = false;
0095     pWidget->deref();
0096 }
0097 
0098 bool KWidgetJobTracker::keepOpen(KJob *job) const
0099 {
0100     Q_D(const KWidgetJobTracker);
0101 
0102     KWidgetJobTrackerPrivate::ProgressWidget *pWidget = d->progressWidget.value(job, nullptr);
0103     if (!pWidget) {
0104         return false;
0105     }
0106 
0107     return pWidget->keepOpenCheck->isChecked();
0108 }
0109 
0110 void KWidgetJobTracker::infoMessage(KJob *job, const QString &message)
0111 {
0112     Q_D(KWidgetJobTracker);
0113 
0114     KWidgetJobTrackerPrivate::ProgressWidget *pWidget = d->progressWidget.value(job, nullptr);
0115     if (!pWidget) {
0116         return;
0117     }
0118 
0119     pWidget->infoMessage(message);
0120 }
0121 
0122 void KWidgetJobTracker::description(KJob *job, const QString &title, const QPair<QString, QString> &field1, const QPair<QString, QString> &field2)
0123 {
0124     Q_D(KWidgetJobTracker);
0125 
0126     KWidgetJobTrackerPrivate::ProgressWidget *pWidget = d->progressWidget.value(job, nullptr);
0127     if (!pWidget) {
0128         return;
0129     }
0130 
0131     pWidget->description(title, field1, field2);
0132 }
0133 
0134 void KWidgetJobTracker::totalAmount(KJob *job, KJob::Unit unit, qulonglong amount)
0135 {
0136     Q_D(KWidgetJobTracker);
0137 
0138     KWidgetJobTrackerPrivate::ProgressWidget *pWidget = d->progressWidget.value(job, nullptr);
0139     if (!pWidget) {
0140         return;
0141     }
0142 
0143     pWidget->totalAmount(unit, amount);
0144 }
0145 
0146 void KWidgetJobTracker::processedAmount(KJob *job, KJob::Unit unit, qulonglong amount)
0147 {
0148     Q_D(KWidgetJobTracker);
0149 
0150     KWidgetJobTrackerPrivate::ProgressWidget *pWidget = d->progressWidget.value(job, nullptr);
0151     if (!pWidget) {
0152         return;
0153     }
0154 
0155     pWidget->processedAmount(unit, amount);
0156 }
0157 
0158 void KWidgetJobTracker::percent(KJob *job, unsigned long percent)
0159 {
0160     Q_D(KWidgetJobTracker);
0161 
0162     KWidgetJobTrackerPrivate::ProgressWidget *pWidget = d->progressWidget.value(job, nullptr);
0163     if (!pWidget) {
0164         return;
0165     }
0166 
0167     pWidget->percent(percent);
0168 }
0169 
0170 void KWidgetJobTracker::speed(KJob *job, unsigned long value)
0171 {
0172     Q_D(KWidgetJobTracker);
0173 
0174     KWidgetJobTrackerPrivate::ProgressWidget *pWidget = d->progressWidget.value(job, nullptr);
0175     if (!pWidget) {
0176         return;
0177     }
0178 
0179     pWidget->speed(value);
0180 }
0181 
0182 void KWidgetJobTracker::slotClean(KJob *job)
0183 {
0184     Q_D(KWidgetJobTracker);
0185 
0186     KWidgetJobTrackerPrivate::ProgressWidget *pWidget = d->progressWidget.value(job, nullptr);
0187     if (!pWidget) {
0188         return;
0189     }
0190 
0191     pWidget->slotClean();
0192 }
0193 
0194 void KWidgetJobTracker::suspended(KJob *job)
0195 {
0196     Q_D(KWidgetJobTracker);
0197 
0198     KWidgetJobTrackerPrivate::ProgressWidget *pWidget = d->progressWidget.value(job, nullptr);
0199     if (!pWidget) {
0200         return;
0201     }
0202 
0203     pWidget->suspended();
0204 }
0205 
0206 void KWidgetJobTracker::resumed(KJob *job)
0207 {
0208     Q_D(KWidgetJobTracker);
0209 
0210     KWidgetJobTrackerPrivate::ProgressWidget *pWidget = d->progressWidget.value(job, nullptr);
0211     if (!pWidget) {
0212         return;
0213     }
0214 
0215     pWidget->resumed();
0216 }
0217 
0218 void KWidgetJobTrackerPrivate::ProgressWidget::ref()
0219 {
0220     ++refCount;
0221 }
0222 
0223 void KWidgetJobTrackerPrivate::ProgressWidget::deref()
0224 {
0225     if (refCount) {
0226         --refCount;
0227     }
0228 
0229     if (!refCount) {
0230         if (!keepOpenCheck->isChecked()) {
0231             closeNow();
0232         } else {
0233             slotClean();
0234         }
0235     }
0236 }
0237 
0238 void KWidgetJobTrackerPrivate::ProgressWidget::closeNow()
0239 {
0240     close();
0241 
0242     // It might happen the next scenario:
0243     // - Start a job which opens a progress widget. Keep it open. Address job is 0xdeadbeef
0244     // - Start a new job, which is given address 0xdeadbeef. A new window is opened.
0245     //   This one will take much longer to complete. The key 0xdeadbeef on the widget map now
0246     //   stores the new widget address.
0247     // - Close the first progress widget that was opened (and has already finished) while the
0248     //   last one is still running. We remove its reference on the map. Wrong.
0249     // For that reason we have to check if the map stores the widget as the current one.
0250     // ereslibre
0251     if (tracker->d_func()->progressWidget[job] == this) {
0252         tracker->d_func()->progressWidget.remove(job);
0253         tracker->d_func()->progressWidgetsToBeShown.removeAll(job);
0254     }
0255 }
0256 
0257 bool KWidgetJobTrackerPrivate::ProgressWidget::eventFilter(QObject *watched, QEvent *event)
0258 {
0259     // Handle context menu events for the source/dest labels here, so that we are ref()ed while the
0260     // menu is exec()ed, to avoid a crash if the job finishes meanwhile. #159621.
0261     if ((watched == sourceEdit || watched == destEdit) && event->type() == QEvent::ContextMenu) {
0262         ref();
0263         watched->event(event);
0264         deref();
0265         return true;
0266     }
0267 
0268     return QWidget::eventFilter(watched, event);
0269 }
0270 
0271 void KWidgetJobTrackerPrivate::ProgressWidget::infoMessage(const QString &message)
0272 {
0273     speedLabel->setText(message);
0274     speedLabel->setAlignment(speedLabel->alignment() & ~Qt::TextWordWrap);
0275 }
0276 
0277 void KWidgetJobTrackerPrivate::ProgressWidget::description(const QString &title, const QPair<QString, QString> &field1, const QPair<QString, QString> &field2)
0278 {
0279     setWindowTitle(title);
0280     caption = title;
0281     sourceInvite->setText(QCoreApplication::translate("KWidgetJobTracker", "%1:", "%1 is the label, we add a ':' to it").arg(field1.first));
0282     sourceEdit->setText(field1.second);
0283 
0284     if (field2.first.isEmpty()) {
0285         setDestVisible(false);
0286     } else {
0287         setDestVisible(true);
0288         checkDestination(QUrl::fromUserInput(field2.second)); // path or URL
0289         destInvite->setText(QCoreApplication::translate("KWidgetJobTracker", "%1:", "%1 is the label, we add a ':' to it").arg(field2.first));
0290         destEdit->setText(field2.second);
0291     }
0292 }
0293 
0294 void KWidgetJobTrackerPrivate::ProgressWidget::totalAmount(KJob::Unit unit, qulonglong amount)
0295 {
0296     switch (unit) {
0297     case KJob::Bytes:
0298         totalSizeKnown = true;
0299         // size is measured in bytes
0300         if (totalSize == amount) {
0301             return;
0302         }
0303         totalSize = amount;
0304         if (!startTime.isValid()) {
0305             startTime.start();
0306         }
0307         break;
0308 
0309     case KJob::Files:
0310         if (totalFiles == amount) {
0311             return;
0312         }
0313         totalFiles = amount;
0314         showTotals();
0315         break;
0316 
0317     case KJob::Directories:
0318         if (totalDirs == amount) {
0319             return;
0320         }
0321         totalDirs = amount;
0322         showTotals();
0323         break;
0324 
0325     case KJob::Items:
0326         if (totalItems == amount) {
0327             return;
0328         }
0329         totalItems = amount;
0330         showTotals();
0331         break;
0332 
0333     case KJob::UnitsCount:
0334         Q_UNREACHABLE();
0335         break;
0336     }
0337 }
0338 
0339 void KWidgetJobTrackerPrivate::ProgressWidget::processedAmount(KJob::Unit unit, qulonglong amount)
0340 {
0341     QString tmp;
0342 
0343     switch (unit) {
0344     case KJob::Bytes:
0345         if (processedSize == amount) {
0346             return;
0347         }
0348         processedSize = amount;
0349 
0350         if (totalSizeKnown) {
0351             //~ singular %1 of %2 complete
0352             //~ plural %1 of %2 complete
0353             tmp = QCoreApplication::translate("KWidgetJobTracker", "%1 of %2 complete", "", amount)
0354                       .arg(KJobTrackerFormatters::byteSize(amount), KJobTrackerFormatters::byteSize(totalSize));
0355         } else {
0356             tmp = KJobTrackerFormatters::byteSize(amount);
0357         }
0358         sizeLabel->setText(tmp);
0359         if (!totalSizeKnown) { // update jumping progressbar
0360             progressBar->setValue(amount);
0361         }
0362         break;
0363 
0364     case KJob::Directories:
0365         if (processedDirs == amount) {
0366             return;
0367         }
0368         processedDirs = amount;
0369 
0370         //~ singular %1 / %n folder
0371         //~ plural %1 / %n folders
0372         tmp = QCoreApplication::translate("KWidgetJobTracker", "%1 / %n folder(s)", "", totalDirs).arg(processedDirs);
0373         tmp += QLatin1String("   ");
0374         //~ singular %1 / %n file
0375         //~ plural %1 / %n files
0376         tmp += QCoreApplication::translate("KWidgetJobTracker", "%1 / %n file(s)", "", totalFiles).arg(processedFiles);
0377         progressLabel->setText(tmp);
0378         break;
0379 
0380     case KJob::Files:
0381         if (processedFiles == amount) {
0382             return;
0383         }
0384         processedFiles = amount;
0385 
0386         if (totalDirs > 1) {
0387             //~ singular %1 / %n folder
0388             //~ plural %1 / %n folders
0389             tmp = QCoreApplication::translate("KWidgetJobTracker", "%1 / %n folder(s)", "", totalDirs).arg(processedDirs);
0390             tmp += QLatin1String("   ");
0391         }
0392         //~ singular %1 / %n file
0393         //~ plural %1 / %n files
0394         tmp += QCoreApplication::translate("KWidgetJobTracker", "%1 / %n file(s)", "", totalFiles).arg(processedFiles);
0395         progressLabel->setText(tmp);
0396         break;
0397 
0398     case KJob::Items:
0399         if (processedItems == amount) {
0400             return;
0401         }
0402         processedItems = amount;
0403         //~ singular %1 / %n item
0404         //~ plural %1 / %n items
0405         tmp = QCoreApplication::translate("KWidgetJobTracker", "%1 / %n item(s)", "", totalItems).arg(processedItems);
0406         progressLabel->setText(tmp);
0407         break;
0408 
0409     case KJob::UnitsCount:
0410         Q_UNREACHABLE();
0411         break;
0412     }
0413 }
0414 
0415 void KWidgetJobTrackerPrivate::ProgressWidget::percent(unsigned long percent)
0416 {
0417     QString title = caption + QLatin1String(" (");
0418 
0419     if (totalSizeKnown) {
0420         title += QCoreApplication::translate("KWidgetJobTracker", "%1% of %2").arg(percent).arg(KJobTrackerFormatters::byteSize(totalSize));
0421     } else if (totalFiles) {
0422         //~ singular %1% of %n file
0423         //~ plural %1% of %n files
0424         title += QCoreApplication::translate("KWidgetJobTracker", "%1% of %n file(s)", "", totalFiles).arg(percent);
0425     } else {
0426         title += QCoreApplication::translate("KWidgetJobTracker", "%1%").arg(percent);
0427     }
0428 
0429     title += QLatin1Char(')');
0430 
0431     progressBar->setMaximum(100);
0432     progressBar->setValue(percent);
0433     setWindowTitle(title);
0434 }
0435 
0436 void KWidgetJobTrackerPrivate::ProgressWidget::speed(unsigned long value)
0437 {
0438     if (value == 0) {
0439         speedLabel->setText(QCoreApplication::translate("KWidgetJobTracker", "Stalled"));
0440     } else {
0441         const QString speedStr = KJobTrackerFormatters::byteSize(value);
0442         if (totalSizeKnown) {
0443             const int remaining = 1000 * (totalSize - processedSize) / value;
0444             //~ singular %1/s (%2 remaining)
0445             //~ plural %1/s (%2 remaining)
0446             speedLabel->setText(QCoreApplication::translate("KWidgetJobTracker", "%1/s (%2 remaining)", "", remaining)
0447                                     .arg(speedStr, KJobTrackerFormatters::duration(remaining)));
0448         } else { // total size is not known (#24228)
0449             speedLabel->setText(QCoreApplication::translate("KWidgetJobTracker", "%1/s", "speed in bytes per second").arg(speedStr));
0450         }
0451     }
0452 }
0453 
0454 void KWidgetJobTrackerPrivate::ProgressWidget::slotClean()
0455 {
0456     percent(100);
0457     cancelClose->setText(QCoreApplication::translate("KWidgetJobTracker", "&Close"));
0458     cancelClose->setIcon(QIcon::fromTheme(QStringLiteral("window-close")));
0459     cancelClose->setToolTip(QCoreApplication::translate("KWidgetJobTracker", "Close the current window or document"));
0460     openFile->setEnabled(true);
0461     if (!totalSizeKnown || totalSize < processedSize) {
0462         totalSize = processedSize;
0463     }
0464     processedAmount(KJob::Bytes, totalSize);
0465     keepOpenCheck->setEnabled(false);
0466     pauseButton->setEnabled(false);
0467     if (startTime.isValid()) {
0468         int s = startTime.elapsed();
0469         if (!s) {
0470             s = 1;
0471         }
0472         speedLabel->setText(QCoreApplication::translate("KWidgetJobTracker", "%1/s (done)").arg(KJobTrackerFormatters::byteSize(1000 * totalSize / s)));
0473     }
0474 }
0475 
0476 void KWidgetJobTrackerPrivate::ProgressWidget::suspended()
0477 {
0478     pauseButton->setText(QCoreApplication::translate("KWidgetJobTracker", "&Resume"));
0479     suspendedProperty = true;
0480 }
0481 
0482 void KWidgetJobTrackerPrivate::ProgressWidget::resumed()
0483 {
0484     pauseButton->setText(QCoreApplication::translate("KWidgetJobTracker", "&Pause"));
0485     suspendedProperty = false;
0486 }
0487 
0488 void KWidgetJobTrackerPrivate::ProgressWidget::closeEvent(QCloseEvent *event)
0489 {
0490     if (jobRegistered && tracker->stopOnClose(job)) {
0491         tracker->slotStop(job);
0492     }
0493 
0494     QWidget::closeEvent(event);
0495 }
0496 
0497 void KWidgetJobTrackerPrivate::ProgressWidget::init()
0498 {
0499     setWindowIcon(QIcon::fromTheme(QStringLiteral("document-save"), windowIcon()));
0500 
0501     QVBoxLayout *topLayout = new QVBoxLayout(this);
0502 
0503     QGridLayout *grid = new QGridLayout();
0504     topLayout->addLayout(grid);
0505     const int horizontalSpacing = style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing);
0506     grid->addItem(new QSpacerItem(horizontalSpacing, 0), 0, 1);
0507     // filenames or action name
0508     sourceInvite = new QLabel(QCoreApplication::translate("KWidgetJobTracker", "Source:", "The source url of a job"), this);
0509     grid->addWidget(sourceInvite, 0, 0);
0510 
0511     sourceEdit = new KSqueezedTextLabel(this);
0512     sourceEdit->setTextInteractionFlags(Qt::TextSelectableByMouse);
0513     sourceEdit->installEventFilter(this);
0514     grid->addWidget(sourceEdit, 0, 2);
0515 
0516     destInvite = new QLabel(QCoreApplication::translate("KWidgetJobTracker", "Destination:", "The destination url of a job"), this);
0517     grid->addWidget(destInvite, 1, 0);
0518 
0519     destEdit = new KSqueezedTextLabel(this);
0520     destEdit->setTextInteractionFlags(Qt::TextSelectableByMouse);
0521     destEdit->installEventFilter(this);
0522     grid->addWidget(destEdit, 1, 2);
0523 
0524     QHBoxLayout *progressHBox = new QHBoxLayout();
0525     topLayout->addLayout(progressHBox);
0526 
0527     progressBar = new QProgressBar(this);
0528     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."));
0529     progressBar->setMaximum(0); // want a jumping progress bar if percent is not emitted
0530     progressHBox->addWidget(progressBar);
0531 
0532     suspendedProperty = false;
0533 
0534     // processed info
0535     QHBoxLayout *hBox = new QHBoxLayout();
0536     topLayout->addLayout(hBox);
0537 
0538     arrowButton = new QPushButton(this);
0539     arrowButton->setMaximumSize(QSize(32, 25));
0540     arrowButton->setIcon(QIcon::fromTheme(QStringLiteral("arrow-down")));
0541     arrowButton->setToolTip(QCoreApplication::translate("KWidgetJobTracker", "Click this to expand the dialog, to show details"));
0542     arrowState = Qt::DownArrow;
0543     connect(arrowButton, &QPushButton::clicked, this, &KWidgetJobTrackerPrivate::ProgressWidget::arrowClicked);
0544     hBox->addWidget(arrowButton);
0545     hBox->addStretch(1);
0546 
0547     KSeparator *separator1 = new KSeparator(Qt::Horizontal, this);
0548     topLayout->addWidget(separator1);
0549 
0550     sizeLabel = new QLabel(this);
0551     hBox->addWidget(sizeLabel, 0, Qt::AlignLeft);
0552 
0553     resumeLabel = new QLabel(this);
0554     hBox->addWidget(resumeLabel);
0555 
0556     pauseButton = new QPushButton(QCoreApplication::translate("KWidgetJobTracker", "&Pause"), this);
0557     pauseButton->setVisible(job && (job->capabilities() & KJob::Suspendable));
0558     connect(pauseButton, &QPushButton::clicked, this, &KWidgetJobTrackerPrivate::ProgressWidget::pauseResumeClicked);
0559     hBox->addWidget(pauseButton);
0560 
0561     hBox = new QHBoxLayout();
0562     topLayout->addLayout(hBox);
0563 
0564     speedLabel = new QLabel(this);
0565     hBox->addWidget(speedLabel, 1);
0566     speedLabel->hide();
0567 
0568     hBox = new QHBoxLayout();
0569     topLayout->addLayout(hBox);
0570 
0571     progressLabel = new QLabel(this);
0572     progressLabel->setAlignment(Qt::AlignLeft);
0573     hBox->addWidget(progressLabel);
0574     progressLabel->hide();
0575 
0576     keepOpenCheck = new QCheckBox(QCoreApplication::translate("KWidgetJobTracker", "&Keep this window open after transfer is complete"), this);
0577     connect(keepOpenCheck, &QCheckBox::toggled, this, &KWidgetJobTrackerPrivate::ProgressWidget::keepOpenToggled);
0578     topLayout->addWidget(keepOpenCheck);
0579     keepOpenCheck->hide();
0580 
0581     hBox = new QHBoxLayout();
0582     topLayout->addLayout(hBox);
0583 
0584     openFile = new QPushButton(QCoreApplication::translate("KWidgetJobTracker", "Open &File"), this);
0585     connect(openFile, &QPushButton::clicked, this, &KWidgetJobTrackerPrivate::ProgressWidget::openFileClicked);
0586     hBox->addWidget(openFile);
0587     openFile->setEnabled(false);
0588     openFile->hide();
0589 
0590     openLocation = new QPushButton(QCoreApplication::translate("KWidgetJobTracker", "Open &Destination"), this);
0591     connect(openLocation, &QPushButton::clicked, this, &KWidgetJobTrackerPrivate::ProgressWidget::openLocationClicked);
0592     hBox->addWidget(openLocation);
0593     openLocation->hide();
0594 
0595     hBox->addStretch(1);
0596 
0597     cancelClose = new QPushButton(this);
0598     cancelClose->setText(QCoreApplication::translate("KWidgetJobTracker", "&Cancel"));
0599     cancelClose->setIcon(QIcon::fromTheme(QStringLiteral("dialog-cancel")));
0600     connect(cancelClose, &QPushButton::clicked, this, &KWidgetJobTrackerPrivate::ProgressWidget::cancelClicked);
0601     hBox->addWidget(cancelClose);
0602 
0603     resize(sizeHint());
0604     setMaximumHeight(sizeHint().height());
0605 
0606     setWindowTitle(QCoreApplication::translate("KWidgetJobTracker", "Progress Dialog")); // show something better than kuiserver
0607 }
0608 
0609 void KWidgetJobTrackerPrivate::ProgressWidget::showTotals()
0610 {
0611     // Show the totals in the progress label, if we still haven't
0612     // processed anything. This is useful when the stat'ing phase
0613     // of CopyJob takes a long time (e.g. over networks).
0614     if (processedFiles == 0 && processedDirs == 0 && processedItems == 0) {
0615         QString total;
0616         if (totalItems > 1) {
0617             //~ singular %n item
0618             //~ plural %n items
0619             total = QCoreApplication::translate("KWidgetJobTracker", "%n item(s)", "", totalItems);
0620             progressLabel->setText(total);
0621         } else {
0622             if (totalDirs > 1) {
0623                 //~ singular %n folder
0624                 //~ plural %n folders
0625                 total = QCoreApplication::translate("KWidgetJobTracker", "%n folder(s)", "", totalDirs) + QLatin1String("   ");
0626             }
0627             //~ singular %n file
0628             //~ plural %n files
0629             total += QCoreApplication::translate("KWidgetJobTracker", "%n file(s)", "", totalFiles);
0630             progressLabel->setText(total);
0631         }
0632     }
0633 }
0634 
0635 void KWidgetJobTrackerPrivate::ProgressWidget::setDestVisible(bool visible)
0636 {
0637     // We can't hide the destInvite/destEdit labels,
0638     // because it screws up the QGridLayout.
0639     if (visible) {
0640         destInvite->show();
0641         destEdit->show();
0642     } else {
0643         destInvite->hide();
0644         destEdit->hide();
0645         destInvite->setText(QString());
0646         destEdit->setText(QString());
0647     }
0648     setMaximumHeight(sizeHint().height());
0649 }
0650 
0651 void KWidgetJobTrackerPrivate::ProgressWidget::checkDestination(const QUrl &dest)
0652 {
0653     bool ok = true;
0654 
0655     if (dest.isLocalFile()) {
0656         const QString path = dest.toLocalFile();
0657         if (path.contains(QDir::tempPath())) {
0658             ok = false; // it's in the tmp directory
0659         }
0660     }
0661 
0662     if (ok) {
0663         openFile->show();
0664         openLocation->show();
0665         keepOpenCheck->show();
0666         setMaximumHeight(sizeHint().height());
0667         location = dest;
0668     }
0669 }
0670 
0671 void KWidgetJobTrackerPrivate::ProgressWidget::keepOpenToggled(bool keepOpen)
0672 {
0673     if (keepOpen) {
0674         Q_ASSERT(!tracker->d_func()->eventLoopLocker);
0675         tracker->d_func()->eventLoopLocker = new QEventLoopLocker;
0676     } else {
0677         delete tracker->d_func()->eventLoopLocker;
0678         tracker->d_func()->eventLoopLocker = nullptr;
0679     }
0680 }
0681 
0682 static QString findKdeOpen()
0683 {
0684     const QString exec = QStandardPaths::findExecutable(QStringLiteral("kde-open"));
0685     if (exec.isEmpty()) {
0686         qCWarning(KJOBWIDGETS) << "Could not find kde-open executable in PATH";
0687     }
0688     return exec;
0689 }
0690 
0691 void KWidgetJobTrackerPrivate::ProgressWidget::openFileClicked()
0692 {
0693     const QString exec = findKdeOpen();
0694     if (!exec.isEmpty()) {
0695         QProcess::startDetached(exec, QStringList() << location.toDisplayString());
0696     }
0697 }
0698 
0699 void KWidgetJobTrackerPrivate::ProgressWidget::openLocationClicked()
0700 {
0701     const QString exec = findKdeOpen();
0702     if (!exec.isEmpty()) {
0703         QProcess::startDetached(exec, QStringList() << location.adjusted(QUrl::RemoveFilename).toString());
0704     }
0705 }
0706 
0707 void KWidgetJobTrackerPrivate::ProgressWidget::pauseResumeClicked()
0708 {
0709     if (jobRegistered && !suspendedProperty) {
0710         tracker->slotSuspend(job);
0711     } else if (jobRegistered) {
0712         tracker->slotResume(job);
0713     }
0714 }
0715 
0716 void KWidgetJobTrackerPrivate::ProgressWidget::cancelClicked()
0717 {
0718     if (jobRegistered) {
0719         tracker->slotStop(job);
0720     }
0721     closeNow();
0722 }
0723 
0724 void KWidgetJobTrackerPrivate::ProgressWidget::arrowClicked()
0725 {
0726     if (arrowState == Qt::DownArrow) {
0727         // The arrow is in the down position, dialog is collapsed, expand it and change icon.
0728         progressLabel->show();
0729         speedLabel->show();
0730         arrowButton->setIcon(QIcon::fromTheme(QStringLiteral("arrow-up")));
0731         arrowButton->setToolTip(QCoreApplication::translate("KWidgetJobTracker", "Click this to collapse the dialog, to hide details"));
0732         arrowState = Qt::UpArrow;
0733     } else {
0734         // Collapse the dialog
0735         progressLabel->hide();
0736         speedLabel->hide();
0737         arrowButton->setIcon(QIcon::fromTheme(QStringLiteral("arrow-down")));
0738         arrowButton->setToolTip(QCoreApplication::translate("KWidgetJobTracker", "Click this to expand the dialog, to show details"));
0739         arrowState = Qt::DownArrow;
0740     }
0741     setMaximumHeight(sizeHint().height());
0742 }
0743 
0744 #include "moc_kwidgetjobtracker.cpp"
0745 #include "moc_kwidgetjobtracker_p.cpp"