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