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 
7     SPDX-License-Identifier: LGPL-2.0-only
8 */
9 
10 #include "kstatusbarjobtracker.h"
11 #include "kjobtrackerformatters_p.h"
12 #include "kstatusbarjobtracker_p.h"
13 
14 #include <QCoreApplication>
15 #include <QLabel>
16 #include <QMouseEvent>
17 #include <QObject>
18 #include <QProgressBar>
19 #include <QPushButton>
20 #include <QStackedWidget>
21 #include <QWidget>
22 
KStatusBarJobTracker(QWidget * parent,bool button)23 KStatusBarJobTracker::KStatusBarJobTracker(QWidget *parent, bool button)
24     : KAbstractWidgetJobTracker(*new KStatusBarJobTrackerPrivate(this, parent, button), parent)
25 {
26 }
27 
28 KStatusBarJobTracker::~KStatusBarJobTracker() = default;
29 
registerJob(KJob * job)30 void KStatusBarJobTracker::registerJob(KJob *job)
31 {
32     Q_D(KStatusBarJobTracker);
33 
34     KAbstractWidgetJobTracker::registerJob(job);
35 
36     if (d->progressWidget.contains(job)) {
37         return;
38     }
39 
40     auto *vi = new KStatusBarJobTrackerPrivate::ProgressWidget(job, this, d->parent);
41     d->currentProgressWidget = vi;
42 
43     d->progressWidget.insert(job, vi);
44 }
45 
unregisterJob(KJob * job)46 void KStatusBarJobTracker::unregisterJob(KJob *job)
47 {
48     Q_D(KStatusBarJobTracker);
49 
50     KAbstractWidgetJobTracker::unregisterJob(job);
51 
52     if (!d->progressWidget.contains(job)) {
53         return;
54     }
55 
56     if (d->currentProgressWidget == d->progressWidget[job]) {
57         d->currentProgressWidget = nullptr;
58     }
59 
60     if (!d->progressWidget[job]->beingDeleted) {
61         delete d->progressWidget[job];
62     }
63 
64     d->progressWidget.remove(job);
65 }
66 
widget(KJob * job)67 QWidget *KStatusBarJobTracker::widget(KJob *job)
68 {
69     Q_D(KStatusBarJobTracker);
70 
71     if (!d->progressWidget.contains(job)) {
72         return nullptr;
73     }
74 
75     return d->progressWidget[job];
76 }
77 
setStatusBarMode(StatusBarModes statusBarMode)78 void KStatusBarJobTracker::setStatusBarMode(StatusBarModes statusBarMode)
79 {
80     Q_D(KStatusBarJobTracker);
81 
82     if (!d->currentProgressWidget) {
83         return;
84     }
85 
86     d->currentProgressWidget->setMode(statusBarMode);
87 }
88 
description(KJob * job,const QString & title,const QPair<QString,QString> & field1,const QPair<QString,QString> & field2)89 void KStatusBarJobTracker::description(KJob *job, const QString &title, const QPair<QString, QString> &field1, const QPair<QString, QString> &field2)
90 {
91     Q_D(KStatusBarJobTracker);
92 
93     if (!d->progressWidget.contains(job)) {
94         return;
95     }
96 
97     d->progressWidget[job]->description(title, field1, field2);
98 }
99 
totalAmount(KJob * job,KJob::Unit unit,qulonglong amount)100 void KStatusBarJobTracker::totalAmount(KJob *job, KJob::Unit unit, qulonglong amount)
101 {
102     Q_D(KStatusBarJobTracker);
103 
104     if (!d->progressWidget.contains(job)) {
105         return;
106     }
107 
108     d->progressWidget[job]->totalAmount(unit, amount);
109 }
110 
percent(KJob * job,unsigned long percent)111 void KStatusBarJobTracker::percent(KJob *job, unsigned long percent)
112 {
113     Q_D(KStatusBarJobTracker);
114 
115     if (!d->progressWidget.contains(job)) {
116         return;
117     }
118 
119     d->progressWidget[job]->percent(percent);
120 }
121 
speed(KJob * job,unsigned long value)122 void KStatusBarJobTracker::speed(KJob *job, unsigned long value)
123 {
124     Q_D(KStatusBarJobTracker);
125 
126     if (!d->progressWidget.contains(job)) {
127         return;
128     }
129 
130     d->progressWidget[job]->speed(value);
131 }
132 
slotClean(KJob * job)133 void KStatusBarJobTracker::slotClean(KJob *job)
134 {
135     Q_D(KStatusBarJobTracker);
136 
137     if (!d->progressWidget.contains(job)) {
138         return;
139     }
140 
141     d->progressWidget[job]->slotClean();
142 }
143 
killJob()144 void KStatusBarJobTrackerPrivate::ProgressWidget::killJob()
145 {
146     job->kill(KJob::EmitResult); // notify that the job has been killed
147 }
148 
init(KJob * job,QWidget * parent)149 void KStatusBarJobTrackerPrivate::ProgressWidget::init(KJob *job, QWidget *parent)
150 {
151     widget = new QWidget(parent);
152     int w = fontMetrics().horizontalAdvance(QStringLiteral(" 999.9 kB/s 00:00:01 ")) + 8;
153     box = new QHBoxLayout(widget);
154     box->setContentsMargins(0, 0, 0, 0);
155     box->setSpacing(0);
156 
157     stack = new QStackedWidget(widget);
158     box->addWidget(stack);
159 
160     if (q->d_func()->showStopButton) {
161         button = new QPushButton(QCoreApplication::translate("KStatusBarJobTracker", "Stop"), widget);
162         box->addWidget(button);
163         connect(button, &QPushButton::clicked, this, &KStatusBarJobTrackerPrivate::ProgressWidget::killJob);
164     } else {
165         button = nullptr;
166     }
167 
168     progressBar = new QProgressBar(widget);
169     progressBar->installEventFilter(this);
170     progressBar->setMinimumWidth(w);
171     stack->insertWidget(1, progressBar);
172 
173     label = new QLabel(widget);
174     label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
175     label->installEventFilter(this);
176     label->setMinimumWidth(w);
177     stack->insertWidget(2, label);
178     setMinimumSize(sizeHint());
179 
180     setMode(KStatusBarJobTracker::LabelOnly);
181 
182     q->setAutoDelete(job, true);
183 
184     QVBoxLayout *layout = new QVBoxLayout(this);
185     layout->addWidget(widget);
186 }
187 
setMode(KStatusBarJobTracker::StatusBarModes newMode)188 void KStatusBarJobTrackerPrivate::ProgressWidget::setMode(KStatusBarJobTracker::StatusBarModes newMode)
189 {
190     mode = newMode;
191 
192     if (newMode == KStatusBarJobTracker::NoInformation) {
193         stack->hide();
194 
195         return;
196     }
197 
198     if (newMode & KStatusBarJobTracker::LabelOnly) {
199         stack->show();
200         stack->setCurrentWidget(label);
201 
202         return; // TODO: we should make possible to show an informative label and the progress bar
203     }
204 
205     if (newMode & KStatusBarJobTracker::ProgressOnly) {
206         stack->show();
207         stack->setCurrentWidget(progressBar);
208     }
209 }
210 
description(const QString & title,const QPair<QString,QString> & field1,const QPair<QString,QString> & field2)211 void KStatusBarJobTrackerPrivate::ProgressWidget::description(const QString &title,
212                                                               const QPair<QString, QString> &field1,
213                                                               const QPair<QString, QString> &field2)
214 {
215     Q_UNUSED(field1);
216     Q_UNUSED(field2);
217 
218     label->setText(title);
219 }
220 
totalAmount(KJob::Unit unit,qulonglong amount)221 void KStatusBarJobTrackerPrivate::ProgressWidget::totalAmount(KJob::Unit unit, qulonglong amount)
222 {
223     Q_UNUSED(unit);
224     Q_UNUSED(amount);
225 #if 0 // currently unused
226     if (unit == KJob::Bytes) {
227         totalSize = amount;
228     }
229 #endif
230 }
231 
percent(unsigned long percent)232 void KStatusBarJobTrackerPrivate::ProgressWidget::percent(unsigned long percent)
233 {
234     progressBar->setValue(percent);
235 }
236 
speed(unsigned long value)237 void KStatusBarJobTrackerPrivate::ProgressWidget::speed(unsigned long value)
238 {
239     if (value == 0) { // speed is measured in bytes-per-second
240         label->setText(QCoreApplication::translate("KStatusBarJobTracker", " Stalled "));
241     } else {
242         label->setText(QCoreApplication::translate("KStatusBarJobTracker", " %1/s ").arg(KJobTrackerFormatters::byteSize(value)));
243     }
244 }
245 
slotClean()246 void KStatusBarJobTrackerPrivate::ProgressWidget::slotClean()
247 {
248     // we don't want to delete this widget, only clean
249     progressBar->setValue(0);
250     label->clear();
251 
252     setMode(KStatusBarJobTracker::NoInformation);
253 }
254 
eventFilter(QObject * obj,QEvent * event)255 bool KStatusBarJobTrackerPrivate::ProgressWidget::eventFilter(QObject *obj, QEvent *event)
256 {
257     if (obj == progressBar || obj == label) {
258         if (event->type() == QEvent::MouseButtonPress) {
259             QMouseEvent *e = static_cast<QMouseEvent *>(event);
260 
261             // TODO: we should make possible to show an informative label and the progress bar
262             if (e->button() == Qt::LeftButton) { // toggle view on left mouse button
263                 if (mode == KStatusBarJobTracker::LabelOnly) {
264                     setMode(KStatusBarJobTracker::ProgressOnly);
265                 } else if (mode == KStatusBarJobTracker::ProgressOnly) {
266                     setMode(KStatusBarJobTracker::LabelOnly);
267                 }
268                 return true;
269             }
270         }
271 
272         return false;
273     }
274 
275     return QWidget::eventFilter(obj, event);
276 }
277 
278 #include "moc_kstatusbarjobtracker.cpp"
279 #include "moc_kstatusbarjobtracker_p.cpp"
280