source: trunk/src/qt3support/dialogs/q3progressdialog.cpp@ 846

Last change on this file since 846 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 23.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the Qt3Support module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "q3progressdialog.h"
43
44#ifndef QT_NO_PROGRESSDIALOG
45
46#include "q3progressbar.h"
47#include "qapplication.h"
48#include "qcursor.h"
49#include "qdatetime.h"
50#include "qlabel.h"
51#include "qpainter.h"
52#include "qpushbutton.h"
53#include "qshortcut.h"
54#include "qstyle.h"
55#include "qtimer.h"
56#include <limits.h>
57
58QT_BEGIN_NAMESPACE
59
60// If the operation is expected to take this long (as predicted by
61// progress time), show the progress dialog.
62static const int defaultShowTime = 4000;
63// Wait at least this long before attempting to make a prediction.
64static const int minWaitTime = 50;
65
66// Various layout values
67static const int margin_lr = 10;
68static const int margin_tb = 10;
69static const int spacing = 4;
70
71
72class Q3ProgressDialogData
73{
74public:
75 Q3ProgressDialogData(Q3ProgressDialog* that, QWidget* parent,
76 const QString& labelText,
77 int totalSteps) :
78 creator(parent),
79 label(new QLabel(labelText,that)),
80 cancel(0),
81 bar(new Q3ProgressBar(totalSteps, that)),
82 shown_once(false),
83 cancellation_flag(false),
84 showTime(defaultShowTime)
85 {
86 int align = that->style()->styleHint(QStyle::SH_ProgressDialog_TextLabelAlignment, 0, that);
87 label->setAlignment(Qt::Alignment(align));
88 }
89
90 QWidget *creator;
91 QLabel *label;
92 QPushButton *cancel;
93 Q3ProgressBar *bar;
94 bool shown_once;
95 bool cancellation_flag;
96 QTime starttime;
97#ifndef QT_NO_CURSOR
98 QCursor parentCursor;
99#endif
100 int showTime;
101 bool autoClose;
102 bool autoReset;
103 bool forceHide;
104};
105
106
107/*!
108 \class Q3ProgressDialog
109 \brief The Q3ProgressDialog class provides feedback on the progress of a slow operation.
110
111 \compat
112
113 A progress dialog is used to give the user an indication of how long
114 an operation is going to take, and to demonstrate that the
115 application has not frozen. It can also give the user an opportunity
116 to abort the operation.
117
118 A common problem with progress dialogs is that it is difficult to know
119 when to use them; operations take different amounts of time on different
120 hardware. Q3ProgressDialog offers a solution to this problem:
121 it estimates the time the operation will take (based on time for
122 steps), and only shows itself if that estimate is beyond minimumDuration()
123 (4 seconds by default).
124
125 Use setTotalSteps() (or the constructor) to set the number of
126 "steps" in the operation and call setProgress() as the operation
127 progresses. The step value can be chosen arbitrarily. It can be the
128 number of files copied, the number of bytes received, the number of
129 iterations through the main loop of your algorithm, or some other
130 suitable unit. Progress starts at 0, and the progress dialog shows
131 that the operation has finished when you call setProgress() with
132 totalSteps() as its argument.
133
134 The dialog automatically resets and hides itself at the end of the
135 operation. Use setAutoReset() and setAutoClose() to change this
136 behavior.
137
138 There are two ways of using Q3ProgressDialog: modal and modeless.
139
140 Using a modal Q3ProgressDialog is simpler for the programmer, but you
141 must call QApplication::processEvents() or
142 QEventLoop::processEvents(ExcludeUserInput) to keep the event loop
143 running to ensure that the application doesn't freeze. Do the
144 operation in a loop, call \l setProgress() at intervals, and check
145 for cancellation with wasCanceled(). For example:
146\snippet doc/src/snippets/code/src_qt3support_dialogs_q3progressdialog.cpp 0
147
148 A modeless progress dialog is suitable for operations that take
149 place in the background, where the user is able to interact with the
150 application. Such operations are typically based on QTimer (or
151 QObject::timerEvent()), QSocketNotifier, or QUrlOperator; or performed
152 in a separate thread. A Q3ProgressBar in the status bar of your main window
153 is often an alternative to a modeless progress dialog.
154
155 You need to have an event loop to be running, connect the
156 canceled() signal to a slot that stops the operation, and call \l
157 setProgress() at intervals. For example:
158\snippet doc/src/snippets/code/src_qt3support_dialogs_q3progressdialog.cpp 1
159
160
161 In both modes the progress dialog may be customized by
162 replacing the child widgets with custom widgets by using setLabel(),
163 setBar(), and setCancelButton().
164 The functions setLabelText() and setCancelButtonText()
165 set the texts shown.
166
167 \inlineimage qprogdlg-m.png Screenshot in Motif style
168 \inlineimage qprogdlg-w.png Screenshot in Windows style
169
170 \sa QDialog, Q3ProgressBar, {fowler}{GUI Design Handbook: Progress Indicator}
171*/
172
173
174/*!
175 Returns the QLabel currently being displayed above the progress bar.
176 This QLabel is owned by the Q3ProgressDialog.
177
178 \sa setLabel()
179*/
180QLabel *Q3ProgressDialog::label() const
181{
182 return d->label;
183}
184
185/*!
186 Returns the Q3ProgressBar currently being used to display progress.
187 This Q3ProgressBar is owned by the Q3ProgressDialog.
188
189 \sa setBar()
190*/
191Q3ProgressBar *Q3ProgressDialog::bar() const
192{
193 return d->bar;
194}
195
196
197/*!
198 Constructs a progress dialog.
199
200 Default settings:
201 \list
202 \i The label text is empty.
203 \i The cancel button text is (translated) "Cancel".
204 \i The total number of steps is 100.
205 \endlist
206
207 The \a creator argument is the widget to use as the dialog's parent.
208 The \a name, \a modal, and the widget flags, \a f, are
209 passed to the QDialog::QDialog() constructor. If \a modal is false (the
210 default), you must have an event loop proceeding for any redrawing
211 of the dialog to occur. If \a modal is true, the dialog ensures that
212 events are processed when needed.
213
214 \sa setLabelText(), setLabel(), setCancelButtonText(), setCancelButton(),
215 setTotalSteps()
216*/
217
218Q3ProgressDialog::Q3ProgressDialog(QWidget *creator, const char *name,
219 bool modal, Qt::WindowFlags f)
220 : QDialog(creator, f)
221{
222 setObjectName(QLatin1String(name));
223 setModal(modal);
224 init(creator, QString::fromLatin1(""), tr("Cancel"), 100);
225}
226
227/*!
228 Constructs a progress dialog.
229
230 The \a labelText is text used to remind the user what is progressing.
231
232 The \a cancelButtonText is the text to display on the cancel button,
233 or 0 if no cancel button is to be shown.
234
235 The \a totalSteps is the total number of steps in the operation for
236 which this progress dialog shows progress. For example, if the
237 operation is to examine 50 files, this value would be 50. Before
238 examining the first file, call setProgress(0). As each file is
239 processed call setProgress(1), setProgress(2), etc., finally
240 calling setProgress(50) after examining the last file.
241
242 The \a creator argument is the widget to use as the dialog's parent.
243 The \a name, \a modal, and widget flags, \a f, are passed to the
244 QDialog::QDialog() constructor. If \a modal is false (the default),
245 you will must have an event loop proceeding for any redrawing of
246 the dialog to occur. If \a modal is true, the dialog ensures that
247 events are processed when needed.
248
249
250 \sa setLabelText(), setLabel(), setCancelButtonText(), setCancelButton(),
251 setTotalSteps()
252*/
253
254Q3ProgressDialog::Q3ProgressDialog(const QString &labelText,
255 const QString &cancelButtonText,
256 int totalSteps,
257 QWidget *creator, const char *name,
258 bool modal, Qt::WindowFlags f)
259 : QDialog(creator, f)
260{
261 setObjectName(QLatin1String(name));
262 setModal(modal);
263 init(creator, labelText, cancelButtonText, totalSteps);
264}
265
266/*!
267 Constructs a progress dialog.
268
269 Default settings:
270 \list
271 \i The label text is empty.
272 \i The cancel button text is (translated) "Cancel".
273 \i The total number of steps is 100.
274 \endlist
275
276 The \a creator argument is the widget to use as the dialog's parent.
277 The widget flags, \a f, are passed to the QDialog::QDialog() constructor.
278
279 \sa setLabelText(), setLabel(), setCancelButtonText(), setCancelButton(),
280 setTotalSteps()
281*/
282Q3ProgressDialog::Q3ProgressDialog(QWidget *creator, Qt::WindowFlags f)
283 : QDialog(creator, f)
284{
285 init(creator, QString::fromLatin1(""), tr("Cancel"), 100);
286}
287
288/*!
289 Constructs a progress dialog.
290
291 The \a labelText is text used to remind the user what is progressing.
292
293 The \a cancelButtonText is the text to display on the cancel button,
294 or 0 if no cancel button is to be shown.
295
296 The \a totalSteps is the total number of steps in the operation for
297 which this progress dialog shows progress. For example, if the
298 operation is to examine 50 files, this value would be 50. Before
299 examining the first file, call setProgress(0). As each file is
300 processed call setProgress(1), setProgress(2), etc., finally
301 calling setProgress(50) after examining the last file.
302
303 The \a creator argument is the widget to use as the dialog's parent.
304 The widget flags, \a f, are passed to the
305 QDialog::QDialog() constructor.
306
307 \sa setLabelText(), setLabel(), setCancelButtonText(), setCancelButton(),
308 setTotalSteps()
309*/
310Q3ProgressDialog::Q3ProgressDialog(const QString &labelText,
311 const QString &cancelButtonText,
312 int totalSteps, QWidget *creator, Qt::WindowFlags f)
313 : QDialog(creator, f)
314{
315 init(creator, labelText, cancelButtonText, totalSteps);
316}
317
318/*!
319 Destroys the progress dialog.
320*/
321
322Q3ProgressDialog::~Q3ProgressDialog()
323{
324#ifndef QT_NO_CURSOR
325 if (d->creator)
326 d->creator->setCursor(d->parentCursor);
327#endif
328 delete d;
329}
330
331void Q3ProgressDialog::init(QWidget *creator,
332 const QString& lbl, const QString& canc,
333 int totstps)
334{
335 d = new Q3ProgressDialogData(this, creator, lbl, totstps);
336 d->autoClose = true;
337 d->autoReset = true;
338 d->forceHide = false;
339 setCancelButtonText(canc);
340 connect(this, SIGNAL(canceled()), this, SIGNAL(cancelled()));
341 connect(this, SIGNAL(canceled()), this, SLOT(cancel()));
342 forceTimer = new QTimer(this);
343 connect(forceTimer, SIGNAL(timeout()), this, SLOT(forceShow()));
344 layout();
345}
346
347/*!
348 \fn void Q3ProgressDialog::canceled()
349
350 This signal is emitted when the cancel button is clicked.
351 It is connected to the cancel() slot by default.
352
353 \sa wasCanceled()
354*/
355
356/*!
357 \fn void Q3ProgressDialog::cancelled()
358
359 Use canceled() instead.
360*/
361
362/*!
363 Sets the label to \a label. The progress dialog resizes to fit. The
364 label becomes owned by the progress dialog and will be deleted when
365 necessary, so do not pass the address of an object on the stack.
366
367 \sa setLabelText()
368*/
369
370void Q3ProgressDialog::setLabel(QLabel *label)
371{
372 delete d->label;
373 d->label = label;
374 if (label) {
375 if (label->parentWidget() == this) {
376 label->hide(); // until we resize
377 } else {
378 label->setParent(this, 0);
379 }
380 }
381 int w = qMax(isVisible() ? width() : 0, sizeHint().width());
382 int h = qMax(isVisible() ? height() : 0, sizeHint().height());
383 resize(w, h);
384 if (label)
385 label->show();
386}
387
388
389/*!
390 \property Q3ProgressDialog::labelText
391 \brief the label's text
392
393 The default text is an empty string.
394*/
395
396QString Q3ProgressDialog::labelText() const
397{
398 if (label())
399 return label()->text();
400 return QString();
401}
402
403void Q3ProgressDialog::setLabelText(const QString &text)
404{
405 if (label()) {
406 label()->setText(text);
407 int w = qMax(isVisible() ? width() : 0, sizeHint().width());
408 int h = qMax(isVisible() ? height() : 0, sizeHint().height());
409 resize(w, h);
410 }
411}
412
413
414/*!
415 Sets the cancel button to the push button, \a cancelButton. The
416 progress dialog takes ownership of this button which will be deleted
417 when necessary, so do not pass the address of an object that is on
418 the stack, i.e. use new() to create the button.
419
420 \sa setCancelButtonText()
421*/
422
423void Q3ProgressDialog::setCancelButton(QPushButton *cancelButton)
424{
425 delete d->cancel;
426 d->cancel = cancelButton;
427 if (cancelButton) {
428 if (cancelButton->parentWidget() == this) {
429 cancelButton->hide(); // until we resize
430 } else {
431 cancelButton->setParent(this, 0);
432 }
433 connect(d->cancel, SIGNAL(clicked()), this, SIGNAL(canceled()));
434 new QShortcut(Qt::Key_Escape, this, SIGNAL(canceled()));
435 }
436 int w = qMax(isVisible() ? width() : 0, sizeHint().width());
437 int h = qMax(isVisible() ? height() : 0, sizeHint().height());
438 resize(w, h);
439 if (cancelButton)
440 cancelButton->show();
441}
442
443/*!
444 Sets the cancel button's text to \a cancelButtonText.
445 \sa setCancelButton()
446*/
447
448void Q3ProgressDialog::setCancelButtonText(const QString &cancelButtonText)
449{
450 if (!cancelButtonText.isNull()) {
451 if (d->cancel)
452 d->cancel->setText(cancelButtonText);
453 else
454 setCancelButton(new QPushButton(cancelButtonText, this));
455 } else {
456 setCancelButton(0);
457 }
458 int w = qMax(isVisible() ? width() : 0, sizeHint().width());
459 int h = qMax(isVisible() ? height() : 0, sizeHint().height());
460 resize(w, h);
461}
462
463
464/*!
465 Sets the progress bar widget to \a bar. The progress dialog resizes to
466 fit. The progress dialog takes ownership of the progress \a bar which
467 will be deleted when necessary, so do not use a progress bar
468 allocated on the stack.
469*/
470
471void Q3ProgressDialog::setBar(Q3ProgressBar *bar)
472{
473#ifndef QT_NO_DEBUG
474 if (progress() > 0)
475 qWarning("Q3ProgressDialog::setBar: Cannot set a new progress bar "
476 "while the old one is active");
477#endif
478 delete d->bar;
479 d->bar = bar;
480 int w = qMax(isVisible() ? width() : 0, sizeHint().width());
481 int h = qMax(isVisible() ? height() : 0, sizeHint().height());
482 resize(w, h);
483}
484
485
486/*!
487 \property Q3ProgressDialog::wasCanceled
488 \brief whether the dialog was canceled
489
490 \sa setProgress()
491*/
492
493bool Q3ProgressDialog::wasCanceled() const
494{
495 return d->cancellation_flag;
496}
497
498/*!
499 \property Q3ProgressDialog::wasCancelled
500 \brief whether the dialog was canceled
501 \since 4.2
502
503 Use \l wasCanceled instead.
504*/
505