Libkdepim

statusbarprogresswidget.cpp
1/*
2 statusbarprogresswidget.cpp
3
4 SPDX-FileCopyrightText: 2004 Till Adam <adam@kde.org>
5 SPDX-FileCopyrightText: 2004 Don Sanders
6 SPDX-FileCopyrightText: 2004 David Faure <faure@kde.org>
7
8 Includes StatusbarProgressWidget which is based on KIOLittleProgressDlg
9 by SPDX-FileCopyrightText: Matt Koss <koss@miesto.sk>
10
11 SPDX-License-Identifier: GPL-2.0-or-later
12*/
13
14#include "statusbarprogresswidget.h"
15#include "progressdialog.h"
16#include "ssllabel.h"
17using KPIM::SSLLabel;
18#include "progressmanager.h"
21
22#include <KLocalizedString>
23
24#include <QEvent>
25#include <QHBoxLayout>
26#include <QLabel>
27#include <QMouseEvent>
28#include <QProgressBar>
29#include <QPushButton>
30#include <QStackedWidget>
31#include <QTimer>
32#include <chrono>
33
34using namespace std::chrono_literals;
35
36using namespace KPIM;
37
38//-----------------------------------------------------------------------------
39StatusbarProgressWidget::StatusbarProgressWidget(ProgressDialog *progressDialog, QWidget *parent, bool button)
40 : QFrame(parent)
41 , mButton(new QPushButton(this))
42 , mShowButton(button)
43 , mProgressDialog(progressDialog)
44{
45 int w = fontMetrics().boundingRect(QStringLiteral(" 999.9 kB/s 00:00:01 ")).width() + 8;
46 auto boxLayout = new QHBoxLayout(this);
47 boxLayout->setObjectName(QLatin1StringView("boxLayout"));
48 boxLayout->setContentsMargins(0, 0, 0, 0);
49 boxLayout->setSpacing(0);
50
51 mButton->setObjectName(QLatin1StringView("button"));
53 mButton->setIcon(QIcon::fromTheme(QStringLiteral("go-up")));
54 boxLayout->addWidget(mButton);
55 mStackedWidget = new QStackedWidget(this);
56 mStackedWidget->setObjectName(QLatin1StringView("stackedwidget"));
57 int maximumHeight = qMax(mButton->iconSize().height(), fontMetrics().height());
58 mStackedWidget->setMaximumHeight(maximumHeight);
59 boxLayout->addWidget(mStackedWidget);
60
61 mSslLabel = new SSLLabel(this);
62 mSslLabel->setObjectName(QLatin1StringView("ssllabel"));
63 boxLayout->addWidget(mSslLabel);
64
65 mButton->setToolTip(i18n("Open detailed progress dialog"));
66
67 mProgressBar = new QProgressBar(this);
68 mProgressBar->setObjectName(QLatin1StringView("progressbar"));
69 mProgressBar->installEventFilter(this);
70 mProgressBar->setMinimumWidth(w);
71 mProgressBar->setFormat(i18nc("Percent value; %p is the value, % is the percent sign", "%p%"));
72 mStackedWidget->insertWidget(1, mProgressBar);
73
74 mLabel = new QLabel(QString(), this);
75 mLabel->setObjectName(QLatin1StringView("emptylabel"));
76 mLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
77 mLabel->installEventFilter(this);
78 mLabel->setMinimumWidth(w);
79 mStackedWidget->insertWidget(2, mLabel);
80 mButton->setMaximumHeight(maximumHeight);
81 setFixedWidth(600);
82
83 mMode = Progress; // so the call below works
84 setMode(Clean);
85
86 connect(mButton, &QAbstractButton::clicked, this, &StatusbarProgressWidget::slotProgressButtonClicked);
87
88 connect(ProgressManager::instance(), &ProgressManager::progressItemAdded, this, &StatusbarProgressWidget::slotProgressItemAdded);
89 connect(ProgressManager::instance(), &ProgressManager::progressItemCompleted, this, &StatusbarProgressWidget::slotProgressItemCompleted);
90 connect(ProgressManager::instance(), &ProgressManager::progressItemUsesBusyIndicator, this, &StatusbarProgressWidget::updateBusyMode);
91
92 connect(progressDialog, &ProgressDialog::visibilityChanged, this, &StatusbarProgressWidget::slotProgressDialogVisible);
93
94 mDelayTimer = new QTimer(this);
95 mDelayTimer->setSingleShot(true);
96 connect(mDelayTimer, &QTimer::timeout, this, &StatusbarProgressWidget::slotShowItemDelayed);
97
98 mCleanTimer = new QTimer(this);
99 mCleanTimer->setSingleShot(true);
100 connect(mCleanTimer, &QTimer::timeout, this, &StatusbarProgressWidget::slotClean);
101}
102
103void StatusbarProgressWidget::setShowTypeProgressItem(unsigned int type)
104{
105 mShowTypeProgressItem = type;
106}
107
108// There are three cases: no progressitem, one progressitem (connect to it directly),
109// or many progressitems (display busy indicator). Let's call them 0,1,N.
110// In slot..Added we can only end up in 1 or N.
111// In slot..Removed we can end up in 0, 1, or we can stay in N if we were already.
112
113void StatusbarProgressWidget::updateBusyMode(KPIM::ProgressItem *item)
114{
115 if (item->typeProgressItem() == mShowTypeProgressItem) {
116 connectSingleItem(); // if going to 1 item
117 if (mCurrentItem) { // Exactly one item
118 delete mBusyTimer;
119 mBusyTimer = nullptr;
120 mDelayTimer->start(1s);
121 } else { // N items
122 if (!mBusyTimer) {
123 mBusyTimer = new QTimer(this);
124 connect(mBusyTimer, &QTimer::timeout, this, &StatusbarProgressWidget::slotBusyIndicator);
125 mDelayTimer->start(1s);
126 }
127 }
128 }
129}
130
131void StatusbarProgressWidget::slotProgressItemAdded(ProgressItem *item)
132{
133 if (item->parent()) {
134 return; // we are only interested in top level items
135 }
136
137 updateBusyMode(item);
138}
139
140void StatusbarProgressWidget::slotProgressItemCompleted(ProgressItem *item)
141{
142 if (item->parent()) {
143 item->deleteLater();
144 item = nullptr;
145 return; // we are only interested in top level items
146 }
147 item->deleteLater();
148 item = nullptr;
149 connectSingleItem(); // if going back to 1 item
150 if (ProgressManager::instance()->isEmpty()) { // No item
151 // Done. In 5s the progress-widget will close, then we can clean up the statusbar
152 mCleanTimer->start(5s);
153 } else if (mCurrentItem) { // Exactly one item
154 delete mBusyTimer;
155 mBusyTimer = nullptr;
156 activateSingleItemMode();
157 }
158}
159
160void StatusbarProgressWidget::connectSingleItem()
161{
162 if (mCurrentItem) {
163 disconnect(mCurrentItem, &ProgressItem::progressItemProgress, this, &StatusbarProgressWidget::slotProgressItemProgress);
164 mCurrentItem = nullptr;
165 }
166 mCurrentItem = ProgressManager::instance()->singleItem();
167 if (mCurrentItem) {
168 connect(mCurrentItem, &ProgressItem::progressItemProgress, this, &StatusbarProgressWidget::slotProgressItemProgress);
169 }
170}
171
172void StatusbarProgressWidget::activateSingleItemMode()
173{
174 mProgressBar->setMaximum(100);
175 mProgressBar->setValue(mCurrentItem->progress());
176 mProgressBar->setTextVisible(true);
177}
178
179void StatusbarProgressWidget::slotShowItemDelayed()
180{
181 bool noItems = ProgressManager::instance()->isEmpty();
182 if (mCurrentItem) {
183 activateSingleItemMode();
184 } else if (!noItems) { // N items
185 mProgressBar->setMaximum(0);
186 mProgressBar->setTextVisible(false);
187 Q_ASSERT(mBusyTimer);
188 if (mBusyTimer) {
189 mBusyTimer->start(100ms);
190 }
191 }
192
193 if (!noItems) {
194 setMode(Progress);
195 }
196}
197
198void StatusbarProgressWidget::slotBusyIndicator()
199{
200 const int p = mProgressBar->value();
201 mProgressBar->setValue(p + 10);
202}
203
204void StatusbarProgressWidget::slotProgressItemProgress(ProgressItem *item, unsigned int value)
205{
206 Q_ASSERT(item == mCurrentItem); // the only one we should be connected to
207 Q_UNUSED(item)
208 mProgressBar->setValue(value);
209}
210
211void StatusbarProgressWidget::setMode(Mode mode)
212{
213 if (mMode == mode) {
214 return;
215 }
216 mMode = mode;
217 switch (mMode) {
218 case Clean:
219 if (mShowButton) {
220 mButton->hide();
221 }
222 mSslLabel->setState(SSLLabel::Done);
223 // show the empty label in order to make the status bar look better
224 mStackedWidget->show();
225 mStackedWidget->setCurrentWidget(mLabel);
226 break;
227 case Progress:
228 mStackedWidget->show();
229 mStackedWidget->setCurrentWidget(mProgressBar);
230 if (mShowButton) {
231 mShowDetailedProgress = mProgressDialog->wasLastShown();
232 updateProgressButton(mShowDetailedProgress);
233 mButton->show();
234 }
235 mSslLabel->setState(mSslLabel->lastState());
236 break;
237 }
238}
239
240void StatusbarProgressWidget::slotClean()
241{
242 // check if a new item showed up since we started the timer. If not, clear
243 if (ProgressManager::instance()->isEmpty()) {
244 mProgressBar->setValue(0);
245 setMode(Clean);
246 }
247}
248
249bool StatusbarProgressWidget::eventFilter(QObject *obj, QEvent *ev)
250{
251 if (ev->type() == QEvent::MouseButtonPress) {
252 auto e = static_cast<QMouseEvent *>(ev);
253
254 if (e->button() == Qt::LeftButton && mMode == Progress) { // toggle view on left mouse button
255 // Consensus seems to be that we should show/hide the fancy dialog when the user
256 // clicks anywhere in the small one.
257 slotProgressButtonClicked();
258 return true;
259 }
260 }
261 return QFrame::eventFilter(obj, ev);
262}
263
264void StatusbarProgressWidget::updateProgressButton(bool showingProgress)
265{
266 if (!showingProgress) {
267 mButton->setIcon(QIcon::fromTheme(QStringLiteral("go-up")));
268 mButton->setToolTip(i18n("Show detailed progress window"));
269 } else {
270 mButton->setIcon(QIcon::fromTheme(QStringLiteral("go-down")));
271 mButton->setToolTip(i18n("Hide detailed progress window"));
272 }
273}
274
275void StatusbarProgressWidget::slotProgressButtonClicked()
276{
277 mProgressDialog->slotToggleVisibility();
278 mShowDetailedProgress = !mProgressDialog->isHidden();
279 setFixedWidth(qMax(600, mProgressDialog->width()));
280}
281
282void StatusbarProgressWidget::slotProgressDialogVisible(bool b)
283{
284 // Show the hide/show button (mButton) as soon as the progress dialog is shown
285 // (StatusbarProgressWidget::slotShowItemDelayed happens later)
286 if (b) {
287 setMode(Progress);
288 }
289
290 updateProgressButton(b);
291}
292
293#include "moc_statusbarprogresswidget.cpp"
The ProgressItem class.
unsigned int progress() const
ProgressItem * parent() const
void progressItemProgress(KPIM::ProgressItem *, unsigned int)
Emitted when the progress value of an item changes.
The ProgressManager singleton keeps track of all ongoing transactions and notifies observers (progres...
void progressItemAdded(KPIM::ProgressItem *)
static ProgressManager * instance()
ProgressItem * singleItem() const
void progressItemUsesBusyIndicator(KPIM::ProgressItem *, bool)
void progressItemCompleted(KPIM::ProgressItem *)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
Type type(const QSqlDatabase &db)
Class KCheckComboBox::KCheckComboBoxPrivate.
void clicked(bool checked)
void setIcon(const QIcon &icon)
MouseButtonPress
Type type() const const
QIcon fromTheme(const QString &name)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void deleteLater()
bool disconnect(const QMetaObject::Connection &connection)
virtual bool eventFilter(QObject *watched, QEvent *event)
void setMaximum(int maximum)
void setTextVisible(bool visible)
void setValue(int value)
void setCurrentWidget(QWidget *widget)
AlignHCenter
LeftButton
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void start()
void timeout()
void hide()
bool isHidden() const const
void setFixedWidth(int w)
void show()
void setToolTip(const QString &)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:20:19 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.