00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "kwidgetjobtracker.h"
00024 #include "kwidgetjobtracker_p.h"
00025
00026 #include <QProcess>
00027 #include <QTimer>
00028 #include <QLabel>
00029 #include <QProgressBar>
00030 #include <QVBoxLayout>
00031 #include <QGridLayout>
00032 #include <QMenu>
00033 #include <QEvent>
00034
00035 #include <kurl.h>
00036 #include <kpushbutton.h>
00037 #include <ksqueezedtextlabel.h>
00038 #include <kguiitem.h>
00039 #include <kiconloader.h>
00040 #include <kdialog.h>
00041 #include <kstandarddirs.h>
00042 #include <kdebug.h>
00043 #include <klocale.h>
00044 #include <kwindowsystem.h>
00045 #include <kseparator.h>
00046
00047 void KWidgetJobTracker::Private::_k_showProgressWidget()
00048 {
00049 if (progressWidgetsToBeShown.isEmpty()) {
00050 return;
00051 }
00052
00053 KJob *job = progressWidgetsToBeShown.dequeue();
00054
00055
00056
00057 QWidget *widget = q->widget(job);
00058
00059 if (widget) {
00060 widget->show();
00061 }
00062 }
00063
00064 KWidgetJobTracker::KWidgetJobTracker(QWidget *parent)
00065 : KAbstractWidgetJobTracker(parent), d(new Private(parent, this))
00066 {
00067 }
00068
00069 KWidgetJobTracker::~KWidgetJobTracker()
00070 {
00071 delete d;
00072 }
00073
00074 QWidget *KWidgetJobTracker::widget(KJob *job)
00075 {
00076 return d->progressWidget.value(job, 0);
00077 }
00078
00079 void KWidgetJobTracker::registerJob(KJob *job)
00080 {
00081 KAbstractWidgetJobTracker::registerJob(job);
00082
00083 Private::ProgressWidget *vi = new Private::ProgressWidget(job, this, d->parent);
00084 vi->jobRegistered = true;
00085 vi->setAttribute(Qt::WA_DeleteOnClose);
00086 d->progressWidget.insert(job, vi);
00087 d->progressWidgetsToBeShown.enqueue(job);
00088
00089 QTimer::singleShot(500, this, SLOT(_k_showProgressWidget()));
00090 }
00091
00092 void KWidgetJobTracker::unregisterJob(KJob *job)
00093 {
00094 KAbstractWidgetJobTracker::unregisterJob(job);
00095
00096 KWidgetJobTracker::Private::ProgressWidget *pWidget = d->progressWidget.value(job, 0);
00097 if (!pWidget) {
00098 return;
00099 }
00100
00101 pWidget->jobRegistered = false;
00102 pWidget->deref();
00103 }
00104
00105 bool KWidgetJobTracker::keepOpen(KJob *job) const
00106 {
00107 KWidgetJobTracker::Private::ProgressWidget *pWidget = d->progressWidget.value(job, 0);
00108 if (!pWidget) {
00109 return false;
00110 }
00111
00112 return pWidget->keepOpenCheck->isChecked();
00113 }
00114
00115 void KWidgetJobTracker::infoMessage(KJob *job, const QString &plain, const QString &rich)
00116 {
00117 KWidgetJobTracker::Private::ProgressWidget *pWidget = d->progressWidget.value(job, 0);
00118 if (!pWidget) {
00119 return;
00120 }
00121
00122 pWidget->infoMessage(plain, rich);
00123 }
00124
00125 void KWidgetJobTracker::description(KJob *job, const QString &title,
00126 const QPair<QString, QString> &field1,
00127 const QPair<QString, QString> &field2)
00128 {
00129 KWidgetJobTracker::Private::ProgressWidget *pWidget = d->progressWidget.value(job, 0);
00130 if (!pWidget) {
00131 return;
00132 }
00133
00134 pWidget->description(title, field1, field2);
00135 }
00136
00137 void KWidgetJobTracker::totalAmount(KJob *job, KJob::Unit unit, qulonglong amount)
00138 {
00139 KWidgetJobTracker::Private::ProgressWidget *pWidget = d->progressWidget.value(job, 0);
00140 if (!pWidget) {
00141 return;
00142 }
00143
00144 pWidget->totalAmount(unit, amount);
00145 }
00146
00147 void KWidgetJobTracker::processedAmount(KJob *job, KJob::Unit unit, qulonglong amount)
00148 {
00149 KWidgetJobTracker::Private::ProgressWidget *pWidget = d->progressWidget.value(job, 0);
00150 if (!pWidget) {
00151 return;
00152 }
00153
00154 pWidget->processedAmount(unit, amount);
00155 }
00156
00157 void KWidgetJobTracker::percent(KJob *job, unsigned long percent)
00158 {
00159 KWidgetJobTracker::Private::ProgressWidget *pWidget = d->progressWidget.value(job, 0);
00160 if (!pWidget) {
00161 return;
00162 }
00163
00164 pWidget->percent(percent);
00165 }
00166
00167 void KWidgetJobTracker::speed(KJob *job, unsigned long value)
00168 {
00169 KWidgetJobTracker::Private::ProgressWidget *pWidget = d->progressWidget.value(job, 0);
00170 if (!pWidget) {
00171 return;
00172 }
00173
00174 pWidget->speed(value);
00175 }
00176
00177 void KWidgetJobTracker::slotClean(KJob *job)
00178 {
00179 KWidgetJobTracker::Private::ProgressWidget *pWidget = d->progressWidget.value(job, 0);
00180 if (!pWidget) {
00181 return;
00182 }
00183
00184 pWidget->slotClean();
00185 }
00186
00187 void KWidgetJobTracker::suspended(KJob *job)
00188 {
00189 KWidgetJobTracker::Private::ProgressWidget *pWidget = d->progressWidget.value(job, 0);
00190 if (!pWidget) {
00191 return;
00192 }
00193
00194 pWidget->suspended();
00195 }
00196
00197 void KWidgetJobTracker::resumed(KJob *job)
00198 {
00199 KWidgetJobTracker::Private::ProgressWidget *pWidget = d->progressWidget.value(job, 0);
00200 if (!pWidget) {
00201 return;
00202 }
00203
00204 pWidget->resumed();
00205 }
00206
00207 void KWidgetJobTracker::Private::ProgressWidget::ref()
00208 {
00209 ++refCount;
00210 }
00211
00212 void KWidgetJobTracker::Private::ProgressWidget::deref()
00213 {
00214 if (refCount) {
00215 --refCount;
00216 }
00217
00218 if (!refCount) {
00219 if (!keepOpenCheck->isChecked()) {
00220 closeNow();
00221 } else {
00222 slotClean();
00223 }
00224 }
00225 }
00226
00227 void KWidgetJobTracker::Private::ProgressWidget::closeNow()
00228 {
00229 close();
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240 if (tracker->d->progressWidget[job] == this) {
00241 tracker->d->progressWidget.remove(job);
00242 tracker->d->progressWidgetsToBeShown.removeAll(job);
00243 }
00244 }
00245
00246 bool KWidgetJobTracker::Private::ProgressWidget::eventFilter(QObject *watched, QEvent *event)
00247 {
00248
00249
00250 if ((watched == sourceEdit || watched == destEdit) && event->type() == QEvent::ContextMenu) {
00251 ref();
00252 watched->event(event);
00253 deref();
00254 return true;
00255 }
00256
00257 return QWidget::eventFilter(watched, event);
00258 }
00259
00260 void KWidgetJobTracker::Private::ProgressWidget::infoMessage(const QString &plain, const QString &)
00261 {
00262 speedLabel->setText(plain);
00263 speedLabel->setAlignment(speedLabel->alignment() & ~Qt::TextWordWrap);
00264 }
00265
00266 void KWidgetJobTracker::Private::ProgressWidget::description(const QString &title,
00267 const QPair<QString, QString> &field1,
00268 const QPair<QString, QString> &field2)
00269 {
00270 setWindowTitle(title);
00271 caption = title;
00272
00273 sourceInvite->setText(i18nc("%1 is the label, we add a ':' to it", "%1:", field1.first));
00274 sourceEdit->setText(field1.second);
00275
00276 if (field2.first.isEmpty()) {
00277 setDestVisible(false);
00278 } else {
00279 setDestVisible(true);
00280 checkDestination(KUrl(field2.second));
00281 destInvite->setText(i18nc("%1 is the label, we add a ':' to it", "%1:", field2.first));
00282 destEdit->setText(field2.second);
00283 }
00284 }
00285
00286 void KWidgetJobTracker::Private::ProgressWidget::totalAmount(KJob::Unit unit, qulonglong amount)
00287 {
00288 switch(unit)
00289 {
00290 case KJob::Bytes:
00291 totalSizeKnown = true;
00292
00293 if (totalSize == amount)
00294 return;
00295 totalSize = amount;
00296 if (startTime.isNull())
00297 startTime.start();
00298 break;
00299
00300 case KJob::Files:
00301 if (totalFiles == amount)
00302 return;
00303 totalFiles = amount;
00304 showTotals();
00305 break;
00306
00307 case KJob::Directories:
00308 if (totalDirs == amount)
00309 return;
00310 totalDirs = amount;
00311 showTotals();
00312 break;
00313 }
00314 }
00315
00316 void KWidgetJobTracker::Private::ProgressWidget::processedAmount(KJob::Unit unit, qulonglong amount)
00317 {
00318 QString tmp;
00319
00320 switch(unit)
00321 {
00322 case KJob::Bytes:
00323 if (processedSize == amount)
00324 return;
00325 processedSize = amount;
00326
00327 if (totalSizeKnown) {
00328 tmp = i18np( "%2 of %3 complete", "%2 of %3 complete",
00329 amount,
00330 KGlobal::locale()->formatByteSize(amount),
00331 KGlobal::locale()->formatByteSize(totalSize));
00332 } else {
00333 tmp = KGlobal::locale()->formatByteSize(amount);
00334 }
00335 sizeLabel->setText(tmp);
00336 if (!totalSizeKnown)
00337 progressBar->setValue(amount);
00338 break;
00339
00340 case KJob::Directories:
00341 if (processedDirs == amount)
00342 return;
00343 processedDirs = amount;
00344
00345 tmp = i18np("%2 / %1 folder", "%2 / %1 folders", totalDirs, processedDirs);
00346 tmp += " ";
00347 tmp += i18np("%2 / %1 file", "%2 / %1 files", totalFiles, processedFiles);
00348 progressLabel->setText(tmp);
00349 break;
00350
00351 case KJob::Files:
00352 if (processedFiles == amount)
00353 return;
00354 processedFiles = amount;
00355
00356 if (totalDirs > 1) {
00357 tmp = i18np("%2 / %1 folder", "%2 / %1 folders", totalDirs, processedDirs);
00358 tmp += " ";
00359 }
00360 tmp += i18np("%2 / %1 file", "%2 / %1 files", totalFiles, processedFiles);
00361 progressLabel->setText(tmp);
00362 }
00363 }
00364
00365 void KWidgetJobTracker::Private::ProgressWidget::percent(unsigned long percent)
00366 {
00367 QString title = caption + " (";
00368
00369 if (totalSizeKnown) {
00370 title += i18n("%1% of %2", percent,
00371 KGlobal::locale()->formatByteSize(totalSize));
00372 } else if (totalFiles) {
00373 title += i18np("%2% of 1 file", "%2% of %1 files", totalFiles, percent);
00374 } else {
00375 title += i18n("%1%", percent);
00376 }
00377
00378 title += ')';
00379
00380 progressBar->setMaximum(100);
00381 progressBar->setValue(percent);
00382 setWindowTitle(title);
00383 }
00384
00385 void KWidgetJobTracker::Private::ProgressWidget::speed(unsigned long value)
00386 {
00387 if (value == 0) {
00388 speedLabel->setText(i18n("Stalled"));
00389 } else {
00390 const QString speedStr = KGlobal::locale()->formatByteSize(value);
00391 if (totalSizeKnown) {
00392 const int remaining = 1000*(totalSize - processedSize)/value;
00393 speedLabel->setText(i18np("%2/s (%3 remaining)", "%2/s (%3 remaining)", remaining, speedStr,
00394 KGlobal::locale()->prettyFormatDuration(remaining)));
00395 } else {
00396 speedLabel->setText(i18nc("speed in bytes per second", "%1/s", speedStr));
00397 }
00398 }
00399 }
00400
00401 void KWidgetJobTracker::Private::ProgressWidget::slotClean()
00402 {
00403 percent(100);
00404 cancelClose->setGuiItem(KStandardGuiItem::close());
00405 openFile->setEnabled(true);
00406 if (!totalSizeKnown || totalSize < processedSize)
00407 totalSize = processedSize;
00408 processedAmount(KJob::Bytes, totalSize);
00409 keepOpenCheck->setEnabled(false);
00410 pauseButton->setEnabled(false);
00411 if (!startTime.isNull()) {
00412 int s = startTime.elapsed();
00413 if (!s)
00414 s = 1;
00415 speedLabel->setText(i18n("%1/s (done)",
00416 KGlobal::locale()->formatByteSize(1000 * totalSize / s)));
00417 }
00418 }
00419
00420 void KWidgetJobTracker::Private::ProgressWidget::suspended()
00421 {
00422 pauseButton->setText(i18n("&Resume"));
00423 suspendedProperty = true;
00424 }
00425
00426 void KWidgetJobTracker::Private::ProgressWidget::resumed()
00427 {
00428 pauseButton->setText(i18n("&Pause"));
00429 suspendedProperty = false;
00430 }
00431
00432 void KWidgetJobTracker::Private::ProgressWidget::closeEvent(QCloseEvent *event)
00433 {
00434 if (jobRegistered && tracker->stopOnClose(job)) {
00435 tracker->slotStop(job);
00436 }
00437
00438 QWidget::closeEvent(event);
00439 }
00440
00441 void KWidgetJobTracker::Private::ProgressWidget::init()
00442 {
00443
00444 KWindowSystem::setIcons( winId(),
00445 KIconLoader::global()->loadIcon( "document-save", KIconLoader::NoGroup, 32 ),
00446 KIconLoader::global()->loadIcon( "document-save", KIconLoader::NoGroup, 16 ) );
00447
00448 QVBoxLayout *topLayout = new QVBoxLayout(this);
00449
00450 QGridLayout *grid = new QGridLayout();
00451 topLayout->addLayout(grid);
00452 grid->addItem(new QSpacerItem(KDialog::spacingHint(),0),0,1);
00453
00454 sourceInvite = new QLabel(i18nc("The source url of a job", "Source:"), this);
00455 grid->addWidget(sourceInvite, 0, 0);
00456
00457 sourceEdit = new KSqueezedTextLabel(this);
00458 sourceEdit->setTextInteractionFlags(Qt::TextSelectableByMouse);
00459 sourceEdit->installEventFilter(this);
00460 grid->addWidget(sourceEdit, 0, 2);
00461
00462 destInvite = new QLabel(i18nc("The destination url of a job", "Destination:"), this);
00463 grid->addWidget(destInvite, 1, 0);
00464
00465 destEdit = new KSqueezedTextLabel(this);
00466 destEdit->setTextInteractionFlags(Qt::TextSelectableByMouse);
00467 destEdit->installEventFilter(this);
00468 grid->addWidget(destEdit, 1, 2);
00469
00470 QHBoxLayout *progressHBox = new QHBoxLayout();
00471 topLayout->addLayout(progressHBox);
00472
00473 progressBar = new QProgressBar(this);
00474 progressBar->setMaximum(0);
00475 progressHBox->addWidget(progressBar);
00476
00477 suspendedProperty = false;
00478
00479
00480 QHBoxLayout *hBox = new QHBoxLayout();
00481 topLayout->addLayout(hBox);
00482
00483 arrowButton = new KPushButton(this);
00484 arrowButton->setMaximumSize(QSize(32,25));
00485 arrowButton->setIcon(KIcon("arrow-down"));
00486 arrowButton->setToolTip(i18n("Click this to expand the dialog, to show details"));
00487 arrowState = Qt::DownArrow;
00488 connect(arrowButton, SIGNAL(clicked()), this, SLOT(_k_arrowToggled()));
00489 hBox->addWidget(arrowButton);
00490 hBox->addStretch(1);
00491
00492 KSeparator *separator1 = new KSeparator(Qt::Horizontal, this);
00493 topLayout->addWidget(separator1);
00494
00495 sizeLabel = new QLabel(this);
00496 hBox->addWidget(sizeLabel, 0, Qt::AlignLeft);
00497
00498 resumeLabel = new QLabel(this);
00499 hBox->addWidget(resumeLabel);
00500
00501 pauseButton = new KPushButton(i18n("&Pause"), this);
00502 QObject::connect(pauseButton, SIGNAL(clicked()),
00503 this, SLOT(_k_pauseResumeClicked()));
00504 hBox->addWidget(pauseButton);
00505
00506 hBox = new QHBoxLayout();
00507 topLayout->addLayout(hBox);
00508
00509 speedLabel = new QLabel(this);
00510 hBox->addWidget(speedLabel, 1);
00511 speedLabel->hide();
00512
00513 hBox = new QHBoxLayout();
00514 topLayout->addLayout(hBox);
00515
00516 progressLabel = new QLabel(this);
00517 progressLabel->setAlignment(Qt::AlignLeft);
00518 hBox->addWidget(progressLabel);
00519 progressLabel->hide();
00520
00521 keepOpenCheck = new QCheckBox(i18n("&Keep this window open after transfer is complete"), this);
00522 QObject::connect(keepOpenCheck, SIGNAL(toggled(bool)),
00523 this, SLOT(_k_keepOpenToggled(bool)));
00524 topLayout->addWidget(keepOpenCheck);
00525 keepOpenCheck->hide();
00526
00527 hBox = new QHBoxLayout();
00528 topLayout->addLayout(hBox);
00529
00530 openFile = new KPushButton(i18n("Open &File"), this);
00531 QObject::connect(openFile, SIGNAL(clicked()),
00532 this, SLOT(_k_openFile()));
00533 hBox->addWidget(openFile);
00534 openFile->setEnabled(false);
00535 openFile->hide();
00536
00537 openLocation = new KPushButton(i18n("Open &Destination"), this);
00538 QObject::connect(openLocation, SIGNAL(clicked()),
00539 this, SLOT(_k_openLocation()));
00540 hBox->addWidget(openLocation);
00541 openLocation->hide();
00542
00543 hBox->addStretch(1);
00544
00545 cancelClose = new KPushButton(KStandardGuiItem::cancel(), this);
00546 QObject::connect(cancelClose, SIGNAL(clicked()),
00547 this, SLOT(_k_stop()));
00548 hBox->addWidget(cancelClose);
00549
00550 resize(sizeHint());
00551 setMaximumHeight(sizeHint().height());
00552
00553 setWindowTitle(i18n("Progress Dialog"));
00554 }
00555
00556 void KWidgetJobTracker::Private::ProgressWidget::showTotals()
00557 {
00558
00559
00560
00561 if (processedFiles == 0 && processedDirs == 0)
00562 {
00563 QString tmps;
00564 if (totalDirs > 1)
00565
00566 tmps = i18np("%1 folder", "%1 folders", totalDirs) + " ";
00567 tmps += i18np("%1 file", "%1 files", totalFiles);
00568 progressLabel->setText( tmps );
00569 }
00570 }
00571
00572 void KWidgetJobTracker::Private::ProgressWidget::setDestVisible(bool visible)
00573 {
00574
00575
00576 if (visible)
00577 {
00578 destInvite->show();
00579 destEdit->show();
00580 }
00581 else
00582 {
00583 destInvite->hide();
00584 destEdit->hide();
00585 destInvite->setText( QString() );
00586 destEdit->setText( QString() );
00587 }
00588 }
00589
00590 void KWidgetJobTracker::Private::ProgressWidget::checkDestination(const KUrl &dest)
00591 {
00592 bool ok = true;
00593
00594 if (dest.isLocalFile()) {
00595 QString path = dest.toLocalFile( KUrl::RemoveTrailingSlash );
00596 const QStringList tmpDirs = KGlobal::dirs()->resourceDirs( "tmp" );
00597 for (QStringList::ConstIterator it = tmpDirs.begin() ; ok && it != tmpDirs.end() ; ++it)
00598 if (path.contains(*it))
00599 ok = false;
00600 }
00601
00602 if (ok) {
00603 openFile->show();
00604 openLocation->show();
00605 keepOpenCheck->show();
00606 location=dest;
00607 }
00608 }
00609
00610 void KWidgetJobTracker::Private::ProgressWidget::_k_keepOpenToggled(bool keepOpen)
00611 {
00612 if (keepOpen) {
00613 KGlobal::ref();
00614 } else {
00615 KGlobal::deref();
00616 }
00617 }
00618
00619 void KWidgetJobTracker::Private::ProgressWidget::_k_openFile()
00620 {
00621 QProcess::startDetached("kde-open", QStringList() << location.prettyUrl());
00622 }
00623
00624 void KWidgetJobTracker::Private::ProgressWidget::_k_openLocation()
00625 {
00626 KUrl dirLocation(location);
00627 dirLocation.setFileName(QString());
00628 QProcess::startDetached("kde-open", QStringList() << dirLocation.prettyUrl());
00629 }
00630
00631 void KWidgetJobTracker::Private::ProgressWidget::_k_pauseResumeClicked()
00632 {
00633 if (jobRegistered && !suspendedProperty) {
00634 tracker->slotSuspend(job);
00635 } else if (jobRegistered) {
00636 tracker->slotResume(job);
00637 }
00638 }
00639
00640 void KWidgetJobTracker::Private::ProgressWidget::_k_stop()
00641 {
00642 if (jobRegistered) {
00643 tracker->slotStop(job);
00644 }
00645 closeNow();
00646 }
00647
00648 void KWidgetJobTracker::Private::ProgressWidget::_k_arrowToggled()
00649 {
00650 if (arrowState == Qt::DownArrow) {
00651
00652 progressLabel->show();
00653 speedLabel->show();
00654 arrowButton->setIcon(KIcon("arrow-up"));
00655 arrowButton->setToolTip(i18n("Click this to collapse the dialog, to hide details"));
00656 arrowState = Qt::UpArrow;
00657 } else {
00658
00659 progressLabel->hide();
00660 speedLabel->hide();
00661 arrowButton->setIcon(KIcon("arrow-down"));
00662 arrowButton->setToolTip(i18n("Click this to expand the dialog, to show details"));
00663 arrowState = Qt::DownArrow;
00664 }
00665
00666 }
00667
00668 #include "kwidgetjobtracker.moc"
00669 #include "kwidgetjobtracker_p.moc"