File indexing completed on 2024-10-06 06:42:09
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"