1551c01f96bdb8d093e9e578b22d3e25dceb65e1
[gd/wireshark/.git] / ui / qt / progress_frame.cpp
1 /* progress_frame.cpp
2  *
3  * Wireshark - Network traffic analyzer
4  * By Gerald Combs <gerald@wireshark.org>
5  * Copyright 1998 Gerald Combs
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later*/
8
9 #include "config.h"
10
11 #include "progress_frame.h"
12 #include <ui_progress_frame.h>
13
14 #include "ui/progress_dlg.h"
15
16 #include <QDialogButtonBox>
17 #include <QGraphicsOpacityEffect>
18 #include <QBoxLayout>
19 #include <QPropertyAnimation>
20
21 #include <ui/qt/widgets/stock_icon_tool_button.h>
22 #include "wireshark_application.h"
23
24 // To do:
25 // - Add an NSProgressIndicator to the dock icon on macOS.
26 // - Start adding the progress bar to dialogs.
27 // - Don't complain so loudly when the user stops a capture.
28
29 progdlg_t *
30 create_progress_dlg(gpointer top_level_window, const gchar *, const gchar *,
31                                gboolean terminate_is_stop, gboolean *stop_flag) {
32     ProgressFrame *pf;
33     QWidget *main_window;
34
35     if (!top_level_window) {
36         return NULL;
37     }
38
39     main_window = qobject_cast<QWidget *>((QObject *)top_level_window);
40
41     if (!main_window) {
42         return NULL;
43     }
44
45     pf = main_window->findChild<ProgressFrame *>();
46
47     if (!pf) {
48         return NULL;
49     }
50     return pf->showProgress(true, terminate_is_stop, stop_flag, 0);
51 }
52
53 progdlg_t *
54 delayed_create_progress_dlg(gpointer top_level_window, const gchar *task_title, const gchar *item_title,
55                             gboolean terminate_is_stop, gboolean *stop_flag,
56                             const GTimeVal *, gfloat progress)
57 {
58     progdlg_t *progress_dialog = create_progress_dlg(top_level_window, task_title, item_title, terminate_is_stop, stop_flag);
59     update_progress_dlg(progress_dialog, progress, item_title);
60     return progress_dialog;
61 }
62
63 /*
64  * Update the progress information of the progress bar box.
65  */
66 void
67 update_progress_dlg(progdlg_t *dlg, gfloat percentage, const gchar *)
68 {
69     if (!dlg) return;
70
71     dlg->progress_frame->setValue(percentage * 100);
72
73     /*
74      * Flush out the update and process any input events.
75      */
76     WiresharkApplication::processEvents();
77 }
78
79 /*
80  * Destroy the progress bar.
81  */
82 void
83 destroy_progress_dlg(progdlg_t *dlg)
84 {
85     dlg->progress_frame->hide();
86 }
87
88 ProgressFrame::ProgressFrame(QWidget *parent) :
89     QFrame(parent),
90     ui(new Ui::ProgressFrame)
91   , terminate_is_stop_(false)
92   , stop_flag_(NULL)
93   , show_timer_(-1)
94   , effect_(NULL)
95   , animation_(NULL)
96 #ifdef QWINTASKBARPROGRESS_H
97   , update_taskbar_(false)
98   , taskbar_progress_(NULL)
99 #endif
100 {
101     ui->setupUi(this);
102
103     progress_dialog_.progress_frame = this;
104     progress_dialog_.top_level_window = window();
105
106     ui->progressBar->setStyleSheet(QString(
107             "QProgressBar {"
108             "  max-width: 20em;"
109             "  min-height: 0.5em;"
110             "  max-height: 1em;"
111             "  border-bottom: 0px;"
112             "  border-top: 0px;"
113             "  background: transparent;"
114             "}"));
115
116     ui->stopButton->setStockIcon("x-filter-clear");
117     ui->stopButton->setIconSize(QSize(14, 14));
118     ui->stopButton->setStyleSheet(
119             "QToolButton {"
120             "  border: none;"
121             "  background: transparent;" // Disables platform style on Windows.
122             "  padding: 0px;"
123             "  margin: 0px;"
124             "  min-height: 0.8em;"
125             "  max-height: 1em;"
126             "  min-width: 0.8em;"
127             "  max-width: 1em;"
128             "}"
129             );
130
131     effect_ = new QGraphicsOpacityEffect(this);
132     animation_ = new QPropertyAnimation(effect_, "opacity", this);
133     connect(this, SIGNAL(showRequested(bool,bool,gboolean*)),
134             this, SLOT(show(bool,bool,gboolean*)));
135     hide();
136 }
137
138 ProgressFrame::~ProgressFrame()
139 {
140     delete ui;
141 }
142
143 struct progdlg *ProgressFrame::showProgress(bool animate, bool terminate_is_stop, gboolean *stop_flag, int value)
144 {
145     setMaximumValue(100);
146     ui->progressBar->setValue(value);
147     emit showRequested(animate, terminate_is_stop, stop_flag);
148     return &progress_dialog_;
149 }
150
151 progdlg *ProgressFrame::showBusy(bool animate, bool terminate_is_stop, gboolean *stop_flag)
152 {
153     setMaximumValue(0);
154     emit showRequested(animate, terminate_is_stop, stop_flag);
155     return &progress_dialog_;
156 }
157
158 void ProgressFrame::addToButtonBox(QDialogButtonBox *button_box, QObject *main_window)
159 {
160     // We have a ProgressFrame in the main status bar which is controlled
161     // from the capture file and other parts of the application via
162     // create_progress_dlg and delayed_create_progress_dlg.
163     // Create a new ProgressFrame and pair it with the main instance.
164     ProgressFrame *main_progress_frame = main_window->findChild<ProgressFrame *>();
165     if (!button_box || !main_progress_frame) return;
166
167     QBoxLayout *layout = qobject_cast<QBoxLayout *>(button_box->layout());
168     if (!layout) return;
169
170     ProgressFrame *progress_frame = new ProgressFrame(button_box);
171
172     // Insert ourselves after the first spacer we find, otherwise the
173     // far right of the button box.
174     int idx = layout->count();
175     for (int i = 0; i < layout->count(); i++) {
176         if (layout->itemAt(i)->spacerItem()) {
177             idx = i + 1;
178             break;
179         }
180     }
181     layout->insertWidget(idx, progress_frame);
182
183     int one_em = progress_frame->fontMetrics().height();
184     progress_frame->setMaximumWidth(one_em * 8);
185     connect(main_progress_frame, SIGNAL(showRequested(bool,bool,gboolean*)),
186             progress_frame, SLOT(show(bool,bool,gboolean*)));
187     connect(main_progress_frame, SIGNAL(maximumValueChanged(int)),
188             progress_frame, SLOT(setMaximumValue(int)));
189     connect(main_progress_frame, SIGNAL(valueChanged(int)),
190             progress_frame, SLOT(setValue(int)));
191     connect(main_progress_frame, SIGNAL(setHidden()),
192             progress_frame, SLOT(hide()));
193
194     connect(progress_frame, SIGNAL(stopLoading()),
195             main_progress_frame, SIGNAL(stopLoading()));
196 }
197
198 void ProgressFrame::captureFileClosing()
199 {
200     // Hide any paired ProgressFrames and disconnect from them.
201     emit setHidden();
202     disconnect(SIGNAL(showRequested(bool,bool,gboolean*)));
203     disconnect(SIGNAL(maximumValueChanged(int)));
204     disconnect(SIGNAL(valueChanged(int)));
205
206     connect(this, SIGNAL(showRequested(bool,bool,gboolean*)),
207             this, SLOT(show(bool,bool,gboolean*)));
208 }
209
210 void ProgressFrame::setValue(int value)
211 {
212     ui->progressBar->setValue(value);
213     emit valueChanged(value);
214 }
215
216 void ProgressFrame::timerEvent(QTimerEvent *event)
217 {
218     if (event->timerId() == show_timer_) {
219         killTimer(show_timer_);
220         show_timer_ = -1;
221
222         this->setGraphicsEffect(effect_);
223
224         animation_->setDuration(750);
225         animation_->setStartValue(0.1);
226         animation_->setEndValue(1.0);
227         animation_->setEasingCurve(QEasingCurve::InOutQuad);
228         animation_->start();
229
230         QFrame::show();
231     } else {
232         QFrame::timerEvent(event);
233     }
234 }
235
236 void ProgressFrame::hide()
237 {
238     show_timer_ = -1;
239     emit setHidden();
240     QFrame::hide();
241 #ifdef QWINTASKBARPROGRESS_H
242     if (taskbar_progress_) {
243         disconnect(this, SIGNAL(valueChanged(int)), taskbar_progress_, SLOT(setValue(int)));
244         taskbar_progress_->reset();
245         taskbar_progress_->hide();
246     }
247 #endif
248 }
249
250 void ProgressFrame::on_stopButton_clicked()
251 {
252     emit stopLoading();
253 }
254
255 const int show_delay_ = 500; // ms
256
257 void ProgressFrame::show(bool animate, bool terminate_is_stop, gboolean *stop_flag)
258 {
259     terminate_is_stop_ = terminate_is_stop;
260     stop_flag_ = stop_flag;
261
262     if (stop_flag) {
263         ui->stopButton->show();
264     } else {
265         ui->stopButton->hide();
266     }
267
268     if (animate) {
269         show_timer_ = startTimer(show_delay_);
270     } else {
271         QFrame::show();
272     }
273
274 #ifdef QWINTASKBARPROGRESS_H
275     // windowHandle() is picky about returning a non-NULL value so we check it
276     // each time.
277     if (update_taskbar_ && !taskbar_progress_ && window()->windowHandle()) {
278         QWinTaskbarButton *taskbar_button = new QWinTaskbarButton(this);
279         if (taskbar_button) {
280             taskbar_button->setWindow(window()->windowHandle());
281             taskbar_progress_ = taskbar_button->progress();
282         }
283     }
284     if (taskbar_progress_) {
285         taskbar_progress_->show();
286         taskbar_progress_->reset();
287         connect(this, SIGNAL(valueChanged(int)), taskbar_progress_, SLOT(setValue(int)));
288     }
289 #endif
290 }
291
292 void ProgressFrame::setMaximumValue(int value)
293 {
294     ui->progressBar->setMaximum(value);
295     emit maximumValueChanged(value);
296 }
297
298 /*
299  * Editor modelines
300  *
301  * Local Variables:
302  * c-basic-offset: 4
303  * tab-width: 8
304  * indent-tabs-mode: nil
305  * End:
306  *
307  * ex: set shiftwidth=4 tabstop=8 expandtab:
308  * :indentSize=4:tabSize=8:noTabs=true:
309  */