source: trunk/src/gui/widgets/qprogressbar.cpp@ 728

Last change on this file since 728 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 17.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 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 QtGui 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 "qprogressbar.h"
43#ifndef QT_NO_PROGRESSBAR
44#include <qevent.h>
45#include <qpainter.h>
46#include <qstylepainter.h>
47#include <qstyleoption.h>
48#include <private/qwidget_p.h>
49#ifndef QT_NO_ACCESSIBILITY
50#include <qaccessible.h>
51#endif
52#include <limits.h>
53
54QT_BEGIN_NAMESPACE
55
56class QProgressBarPrivate : public QWidgetPrivate
57{
58 Q_DECLARE_PUBLIC(QProgressBar)
59
60public:
61 QProgressBarPrivate();
62
63 void init();
64 inline void resetLayoutItemMargins();
65
66 int minimum;
67 int maximum;
68 int value;
69 Qt::Alignment alignment;
70 uint textVisible : 1;
71 int lastPaintedValue;
72 Qt::Orientation orientation;
73 bool invertedAppearance;
74 QProgressBar::Direction textDirection;
75 QString format;
76 inline int bound(int val) const { return qMax(minimum-1, qMin(maximum, val)); }
77 bool repaintRequired() const;
78};
79
80QProgressBarPrivate::QProgressBarPrivate()
81 : minimum(0), maximum(100), value(-1), alignment(Qt::AlignLeft), textVisible(true),
82 lastPaintedValue(-1), orientation(Qt::Horizontal), invertedAppearance(false),
83 textDirection(QProgressBar::TopToBottom), format(QLatin1String("%p%"))
84{
85}
86
87void QProgressBarPrivate::init()
88{
89 Q_Q(QProgressBar);
90 QSizePolicy sp(QSizePolicy::Expanding, QSizePolicy::Fixed);
91 if (orientation == Qt::Vertical)
92 sp.transpose();
93 q->setSizePolicy(sp);
94 q->setAttribute(Qt::WA_WState_OwnSizePolicy, false);
95 resetLayoutItemMargins();
96}
97
98void QProgressBarPrivate::resetLayoutItemMargins()
99{
100 Q_Q(QProgressBar);
101 QStyleOptionProgressBar option;
102 q->initStyleOption(&option);
103 setLayoutItemMargins(QStyle::SE_ProgressBarLayoutItem, &option);
104}
105
106/*!
107 Initialize \a option with the values from this QProgressBar. This method is useful
108 for subclasses when they need a QStyleOptionProgressBar or QStyleOptionProgressBarV2,
109 but don't want to fill in all the information themselves. This function will check the version
110 of the QStyleOptionProgressBar and fill in the additional values for a
111 QStyleOptionProgressBarV2.
112
113 \sa QStyleOption::initFrom()
114*/
115void QProgressBar::initStyleOption(QStyleOptionProgressBar *option) const
116{
117 if (!option)
118 return;
119 Q_D(const QProgressBar);
120 option->initFrom(this);
121
122 if (d->orientation == Qt::Horizontal)
123 option->state |= QStyle::State_Horizontal;
124 option->minimum = d->minimum;
125 option->maximum = d->maximum;
126 option->progress = d->value;
127 option->textAlignment = d->alignment;
128 option->textVisible = d->textVisible;
129 option->text = text();
130
131 if (QStyleOptionProgressBarV2 *optionV2
132 = qstyleoption_cast<QStyleOptionProgressBarV2 *>(option)) {
133 optionV2->orientation = d->orientation; // ### Qt 5: use State_Horizontal instead
134 optionV2->invertedAppearance = d->invertedAppearance;
135 optionV2->bottomToTop = (d->textDirection == QProgressBar::BottomToTop);
136 }
137}
138
139bool QProgressBarPrivate::repaintRequired() const
140{
141 Q_Q(const QProgressBar);
142 if (value == lastPaintedValue)
143 return false;
144
145 int valueDifference = qAbs(value - lastPaintedValue);
146
147 // Check if the text needs to be repainted
148 if (value == minimum || value == maximum)
149 return true;
150 if (textVisible) {
151 if ((format.contains(QLatin1String("%v"))))
152 return true;
153 if ((format.contains(QLatin1String("%p"))
154 && valueDifference >= qAbs((maximum - minimum) / 100)))
155 return true;
156 }
157
158 // Check if the bar needs to be repainted
159 QStyleOptionProgressBarV2 opt;
160 q->initStyleOption(&opt);
161 int cw = q->style()->pixelMetric(QStyle::PM_ProgressBarChunkWidth, &opt, q);
162 QRect groove = q->style()->subElementRect(QStyle::SE_ProgressBarGroove, &opt, q);
163 // This expression is basically
164 // (valueDifference / (maximum - minimum) > cw / groove.width())
165 // transformed to avoid integer division.
166 int grooveBlock = (q->orientation() == Qt::Horizontal) ? groove.width() : groove.height();
167 return (valueDifference * grooveBlock > cw * (maximum - minimum));
168}
169
170/*!
171 \class QProgressBar
172 \brief The QProgressBar widget provides a horizontal or vertical progress bar.
173
174 \ingroup basicwidgets
175
176
177 A progress bar is used to give the user an indication of the
178 progress of an operation and to reassure them that the application
179 is still running.
180
181 The progress bar uses the concept of \e steps. You set it up by
182 specifying the minimum and maximum possible step values, and it
183 will display the percentage of steps that have been completed
184 when you later give it the current step value. The percentage is
185 calculated by dividing the progress (value() - minimum()) divided
186 by maximum() - minimum().
187
188 You can specify the minimum and maximum number of steps with
189 setMinimum() and setMaximum. The current number of steps is set
190 with setValue(). The progress bar can be rewound to the
191 beginning with reset().
192
193 If minimum and maximum both are set to 0, the bar shows a busy
194 indicator instead of a percentage of steps. This is useful, for
195 example, when using QFtp or QNetworkAccessManager to download
196 items when they are unable to determine the size of the item being
197 downloaded.
198
199 \table
200 \row \o \inlineimage macintosh-progressbar.png Screenshot of a Macintosh style progress bar
201 \o A progress bar shown in the Macintosh widget style.
202 \row \o \inlineimage windowsxp-progressbar.png Screenshot of a Windows XP style progress bar
203 \o A progress bar shown in the Windows XP widget style.
204 \row \o \inlineimage plastique-progressbar.png Screenshot of a Plastique style progress bar
205 \o A progress bar shown in the Plastique widget style.
206 \endtable
207
208 \sa QProgressDialog, {fowler}{GUI Design Handbook: Progress Indicator}
209*/
210
211/*!
212 \since 4.1
213 \enum QProgressBar::Direction
214 \brief Specifies the reading direction of the \l text for vertical progress bars.
215
216 \value TopToBottom The text is rotated 90 degrees clockwise.
217 \value BottomToTop The text is rotated 90 degrees counter-clockwise.
218
219 Note that whether or not the text is drawn is dependent on the style.
220 Currently CDE, CleanLooks, Motif, and Plastique draw the text. Mac, Windows
221 and WindowsXP style do not.
222
223 \sa textDirection
224*/
225
226/*!
227 \fn void QProgressBar::valueChanged(int value)
228
229 This signal is emitted when the value shown in the progress bar changes.
230 \a value is the new value shown by the progress bar.
231*/
232
233/*!
234 Constructs a progress bar with the given \a parent.
235
236 By default, the minimum step value is set to 0, and the maximum to 100.
237
238 \sa setRange()
239*/
240
241QProgressBar::QProgressBar(QWidget *parent)
242 : QWidget(*(new QProgressBarPrivate), parent, 0)
243{
244 d_func()->init();
245}
246
247/*!
248 Reset the progress bar. The progress bar "rewinds" and shows no
249 progress.
250*/
251
252void QProgressBar::reset()
253{
254 Q_D(QProgressBar);
255 d->value = d->minimum - 1;
256 if (d->minimum == INT_MIN)
257 d->value = INT_MIN;
258 repaint();
259}
260
261/*!
262 \property QProgressBar::minimum
263 \brief the progress bar's minimum value
264
265 When setting this property, the \l maximum is adjusted if
266 necessary to ensure that the range remains valid. If the
267 current value falls outside the new range, the progress bar is reset
268 with reset().
269*/
270void QProgressBar::setMinimum(int minimum)
271{
272 setRange(minimum, qMax(d_func()->maximum, minimum));
273}
274
275int QProgressBar::minimum() const
276{
277 return d_func()->minimum;
278}
279
280
281/*!
282 \property QProgressBar::maximum
283 \brief the progress bar's maximum value
284
285 When setting this property, the \l minimum is adjusted if
286 necessary to ensure that the range remains valid. If the
287 current value falls outside the new range, the progress bar is reset
288 with reset().
289*/
290
291void QProgressBar::setMaximum(int maximum)
292{
293 setRange(qMin(d_func()->minimum, maximum), maximum);
294}
295
296int QProgressBar::maximum() const
297{
298 return d_func()->maximum;
299}
300
301/*!
302 \property QProgressBar::value
303 \brief the progress bar's current value
304
305 Attempting to change the current value to one outside
306 the minimum-maximum range has no effect on the current value.
307*/
308void QProgressBar::setValue(int value)
309{
310 Q_D(QProgressBar);
311 if (d->value == value
312 || ((value > d->maximum || value < d->minimum)
313 && (d->maximum != 0 || d->minimum != 0)))
314 return;
315 d->value = value;
316 emit valueChanged(value);
317#ifndef QT_NO_ACCESSIBILITY
318 QAccessible::updateAccessibility(this, 0, QAccessible::ValueChanged);
319#endif
320 if (d->repaintRequired())
321 repaint();
322}
323
324int QProgressBar::value() const
325{
326 return d_func()->value;
327}
328
329/*!
330 Sets the progress bar's minimum and maximum values to \a minimum and
331 \a maximum respectively.
332
333 If \a maximum is smaller than \a minimum, \a minimum becomes the only
334 legal value.
335
336 If the current value falls outside the new range, the progress bar is reset
337 with reset().
338
339 \sa minimum maximum
340*/
341void QProgressBar::setRange(int minimum, int maximum)
342{
343 Q_D(QProgressBar);
344 d->minimum = minimum;
345 d->maximum = qMax(minimum, maximum);
346 if ( d->value <(d->minimum-1) || d->value > d->maximum)
347 reset();
348}
349/*!
350 \property QProgressBar::textVisible
351 \brief whether the current completed percentage should be displayed
352
353 This property may be ignored by the style (e.g., QMacStyle never draws the text).
354
355 \sa textDirection
356*/
357void QProgressBar::setTextVisible(bool visible)
358{
359 Q_D(QProgressBar);
360 if (d->textVisible != visible) {
361 d->textVisible = visible;
362 repaint();
363 }
364}
365
366bool QProgressBar::isTextVisible() const
367{
368 return d_func()->textVisible;
369}
370
371/*!
372 \property QProgressBar::alignment
373 \brief the alignment of the progress bar
374*/
375void QProgressBar::setAlignment(Qt::Alignment alignment)
376{
377 if (d_func()->alignment != alignment) {
378 d_func()->alignment = alignment;
379 repaint();
380 }
381}
382
383Qt::Alignment QProgressBar::alignment() const
384{
385 return d_func()->alignment;
386}
387
388/*!
389 \reimp
390*/
391void QProgressBar::paintEvent(QPaintEvent *)
392{
393 QStylePainter paint(this);
394 QStyleOptionProgressBarV2 opt;
395 initStyleOption(&opt);
396 paint.drawControl(QStyle::CE_ProgressBar, opt);
397 d_func()->lastPaintedValue = d_func()->value;
398}
399
400/*!
401 \reimp
402*/
403QSize QProgressBar::sizeHint() const
404{
405 ensurePolished();
406 QFontMetrics fm = fontMetrics();
407 QStyleOptionProgressBarV2 opt;
408 initStyleOption(&opt);
409 int cw = style()->pixelMetric(QStyle::PM_ProgressBarChunkWidth, &opt, this);
410 QSize size = QSize(qMax(9, cw) * 7 + fm.width(QLatin1Char('0')) * 4, fm.height() + 8);
411 if (opt.orientation == Qt::Vertical)
412 size.transpose();
413 return style()->sizeFromContents(QStyle::CT_ProgressBar, &opt, size, this);
414}
415
416/*!
417 \reimp
418*/
419QSize QProgressBar::minimumSizeHint() const
420{
421 QSize size;
422 if (orientation() == Qt::Horizontal)
423 size = QSize(sizeHint().width(), fontMetrics().height() + 2);
424 else
425 size = QSize(fontMetrics().height() + 2, sizeHint().height());
426 return size;
427}
428
429/*!
430 \property QProgressBar::text
431 \brief the descriptive text shown with the progress bar
432
433 The text returned is the same as the text displayed in the center
434 (or in some styles, to the left) of the progress bar.
435
436 The progress shown in the text may be smaller than the minimum value,
437 indicating that the progress bar is in the "reset" state before any
438 progress is set.
439
440 In the default implementation, the text either contains a percentage
441 value that indicates the progress so far, or it is blank because the
442 progress bar is in the reset state.
443*/
444QString QProgressBar::text() const
445{
446 Q_D(const QProgressBar);
447 if ((d->maximum == 0 && d->minimum == 0) || d->value < d->minimum
448 || (d->value == INT_MIN && d->minimum == INT_MIN))
449 return QString();
450
451 qint64 totalSteps = qint64(d->maximum) - d->minimum;
452
453 QString result = d->format;
454 result.replace(QLatin1String("%m"), QString::number(totalSteps));
455 result.replace(QLatin1String("%v"), QString::number(d->value));
456
457 // If max and min are equal and we get this far, it means that the
458 // progress bar has one step and that we are on that step. Return
459 // 100% here in order to avoid division by zero further down.
460 if (totalSteps == 0) {
461 result.replace(QLatin1String("%p"), QString::number(100));
462 return result;
463 }
464
465 int progress = (qreal(d->value) - d->minimum) * 100.0 / totalSteps;
466 result.replace(QLatin1String("%p"), QString::number(progress));
467 return result;
468}
469
470/*!
471 \since 4.1
472 \property QProgressBar::orientation
473 \brief the orientation of the progress bar
474
475 The orientation must be \l Qt::Horizontal (the default) or \l
476 Qt::Vertical.
477
478 \sa invertedAppearance, textDirection
479*/
480
481void QProgressBar::setOrientation(Qt::Orientation orientation)
482{
483 Q_D(QProgressBar);
484 if (d->orientation == orientation)
485 return;
486 d->orientation = orientation;
487 if (!testAttribute(Qt::WA_WState_OwnSizePolicy)) {
488 QSizePolicy sp = sizePolicy();
489 sp.transpose();
490 setSizePolicy(sp);
491 setAttribute(Qt::WA_WState_OwnSizePolicy, false);
492 }
493 d->resetLayoutItemMargins();
494 update();
495 updateGeometry();
496}
497
498Qt::Orientation QProgressBar::orientation() const
499{
500 Q_D(const QProgressBar);
501 return d->orientation;
502}
503
504/*!
505 \since 4.1
506 \property QProgressBar::invertedAppearance
507 \brief whether or not a progress bar shows its progress inverted
508
509 If this property is false, the progress bar grows in the other
510 direction (e.g. from right to left). By default, the progress bar
511 is not inverted.
512
513 \sa orientation, layoutDirection
514*/
515
516void QProgressBar::setInvertedAppearance(bool invert)
517{
518 Q_D(QProgressBar);
519 d->invertedAppearance = invert;
520 update();
521}
522
523bool QProgressBar::invertedAppearance()
524{
525 Q_D(QProgressBar);
526 return d->invertedAppearance;
527}
528
529/*!
530 \since 4.1
531 \property QProgressBar::textDirection
532 \brief the reading direction of the \l text for vertical progress bars
533
534 This property has no impact on horizontal progress bars.
535 By default, the reading direction is QProgressBar::TopToBottom.
536
537 \sa orientation, textVisible
538*/
539void QProgressBar::setTextDirection(QProgressBar::Direction textDirection)
540{
541 Q_D(QProgressBar);
542 d->textDirection = textDirection;
543 update();
544}
545
546QProgressBar::Direction QProgressBar::textDirection()
547{
548 Q_D(QProgressBar);
549 return d->textDirection;
550}
551
552/*! \reimp */
553bool QProgressBar::event(QEvent *e)
554{
555 Q_D(QProgressBar);
556 if (e->type() == QEvent::StyleChange
557#ifdef Q_WS_MAC
558 || e->type() == QEvent::MacSizeChange
559#endif
560 )
561 d->resetLayoutItemMargins();
562 return QWidget::event(e);
563}
564
565/*!
566 \since 4.2
567 \property QProgressBar::format
568 \brief the string used to generate the current text
569
570 %p - is replaced by the percentage completed.
571 %v - is replaced by the current value.
572 %m - is replaced by the total number of steps.
573
574 The default value is "%p%".
575
576 \sa text()
577*/
578void QProgressBar::setFormat(const QString &format)
579{
580 Q_D(QProgressBar);
581 if (d->format == format)
582 return;
583 d->format = format;
584 update();
585}
586
587QString QProgressBar::format() const
588{
589 Q_D(const QProgressBar);
590 return d->format;
591}
592
593QT_END_NAMESPACE
594
595#endif // QT_NO_PROGRESSBAR
Note: See TracBrowser for help on using the repository browser.