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

Last change on this file since 324 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 17.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** 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 are unsure which license is appropriate for your use, please
37** contact the sales department 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 \mainclass
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 indicator
194 instead of a percentage of steps. This is useful, for example, when using
195 QFtp or QHttp to download items when they are unable to determine the
196 size of the item being downloaded.
197
198 \table
199 \row \o \inlineimage macintosh-progressbar.png Screenshot of a Macintosh style progress bar
200 \o A progress bar shown in the Macintosh widget style.
201 \row \o \inlineimage windowsxp-progressbar.png Screenshot of a Windows XP style progress bar
202 \o A progress bar shown in the Windows XP widget style.
203 \row \o \inlineimage plastique-progressbar.png Screenshot of a Plastique style progress bar
204 \o A progress bar shown in the Plastique widget style.
205 \endtable
206
207 \sa QTimeLine, QProgressDialog, {fowler}{GUI Design Handbook: Progress Indicator}
208*/
209
210/*!
211 \since 4.1
212 \enum QProgressBar::Direction
213 \brief Specifies the reading direction of the \l text for vertical progress bars.
214
215 \value TopToBottom The text is rotated 90 degrees clockwise.
216 \value BottomToTop The text is rotated 90 degrees counter-clockwise.
217
218 Note that whether or not the text is drawn is dependent on the style.
219 Currently CDE, CleanLooks, Motif, and Plastique draw the text. Mac, Windows
220 and WindowsXP style do not.
221
222 \sa textDirection
223*/
224
225/*!
226 \fn void QProgressBar::valueChanged(int value)
227
228 This signal is emitted when the value shown in the progress bar changes.
229 \a value is the new value shown by the progress bar.
230*/
231
232/*!
233 Constructs a progress bar with the given \a parent.
234
235 By default, the minimum step value is set to 0, and the maximum to 100.
236
237 \sa setRange()
238*/
239
240QProgressBar::QProgressBar(QWidget *parent)
241 : QWidget(*(new QProgressBarPrivate), parent, 0)
242{
243 d_func()->init();
244}
245
246/*!
247 Reset the progress bar. The progress bar "rewinds" and shows no
248 progress.
249*/
250
251void QProgressBar::reset()
252{
253 Q_D(QProgressBar);
254 d->value = d->minimum - 1;
255 if (d->minimum == INT_MIN)
256 d->value = INT_MIN;
257 repaint();
258}
259
260/*!
261 \property QProgressBar::minimum
262 \brief the progress bar's minimum value
263
264 When setting this property, the \l maximum is adjusted if
265 necessary to ensure that the range remains valid. If the
266 current value falls outside the new range, the progress bar is reset
267 with reset().
268*/
269void QProgressBar::setMinimum(int minimum)
270{
271 setRange(minimum, qMax(d_func()->maximum, minimum));
272}
273
274int QProgressBar::minimum() const
275{
276 return d_func()->minimum;
277}
278
279
280/*!
281 \property QProgressBar::maximum
282 \brief the progress bar's maximum value
283
284 When setting this property, the \l minimum is adjusted if
285 necessary to ensure that the range remains valid. If the
286 current value falls outside the new range, the progress bar is reset
287 with reset().
288*/
289
290void QProgressBar::setMaximum(int maximum)
291{
292 setRange(qMin(d_func()->minimum, maximum), maximum);
293}
294
295int QProgressBar::maximum() const
296{
297 return d_func()->maximum;
298}
299
300/*!
301 \property QProgressBar::value
302 \brief the progress bar's current value
303
304 Attempting to change the current value to one outside
305 the minimum-maximum range has no effect on the current value.
306*/
307void QProgressBar::setValue(int value)
308{
309 Q_D(QProgressBar);
310 if (d->value == value
311 || ((value > d->maximum || value < d->minimum)
312 && (d->maximum != 0 || d->minimum != 0)))
313 return;
314 d->value = value;
315 emit valueChanged(value);
316#ifndef QT_NO_ACCESSIBILITY
317 QAccessible::updateAccessibility(this, 0, QAccessible::ValueChanged);
318#endif
319 if (d->repaintRequired())
320 repaint();
321}
322
323int QProgressBar::value() const
324{
325 return d_func()->value;
326}
327
328/*!
329 Sets the progress bar's minimum and maximum values to \a minimum and
330 \a maximum respectively.
331
332 If \a maximum is smaller than \a minimum, \a minimum becomes the only
333 legal value.
334
335 If the current value falls outside the new range, the progress bar is reset
336 with reset().
337
338 \sa minimum maximum
339*/
340void QProgressBar::setRange(int minimum, int maximum)
341{
342 Q_D(QProgressBar);
343 d->minimum = minimum;
344 d->maximum = qMax(minimum, maximum);
345 if ( d->value <(d->minimum-1) || d->value > d->maximum)
346 reset();
347}
348/*!
349 \property QProgressBar::textVisible
350 \brief whether the current completed percentage should be displayed
351
352 \sa textDirection
353*/
354void QProgressBar::setTextVisible(bool visible)
355{
356 Q_D(QProgressBar);
357 if (d->textVisible != visible) {
358 d->textVisible = visible;
359 repaint();
360 }
361}
362
363bool QProgressBar::isTextVisible() const
364{
365 return d_func()->textVisible;
366}
367
368/*!
369 \property QProgressBar::alignment
370 \brief the alignment of the progress bar
371*/
372void QProgressBar::setAlignment(Qt::Alignment alignment)
373{
374 if (d_func()->alignment != alignment) {
375 d_func()->alignment = alignment;
376 repaint();
377 }
378}
379
380Qt::Alignment QProgressBar::alignment() const
381{
382 return d_func()->alignment;
383}
384
385/*!
386 \reimp
387*/
388void QProgressBar::paintEvent(QPaintEvent *)
389{
390 QStylePainter paint(this);
391 QStyleOptionProgressBarV2 opt;
392 initStyleOption(&opt);
393 paint.drawControl(QStyle::CE_ProgressBar, opt);
394 d_func()->lastPaintedValue = d_func()->value;
395}
396
397/*!
398 \reimp
399*/
400QSize QProgressBar::sizeHint() const
401{
402 ensurePolished();
403 QFontMetrics fm = fontMetrics();
404 QStyleOptionProgressBarV2 opt;
405 initStyleOption(&opt);
406 int cw = style()->pixelMetric(QStyle::PM_ProgressBarChunkWidth, &opt, this);
407 QSize size = QSize(qMax(9, cw) * 7 + fm.width(QLatin1Char('0')) * 4, fm.height() + 8);
408 if (opt.orientation == Qt::Vertical)
409 size.transpose();
410 return style()->sizeFromContents(QStyle::CT_ProgressBar, &opt, size, this);
411}
412
413/*!
414 \reimp
415*/
416QSize QProgressBar::minimumSizeHint() const
417{
418 QSize size;
419 if (orientation() == Qt::Horizontal)
420 size = QSize(sizeHint().width(), fontMetrics().height() + 2);
421 else
422 size = QSize(fontMetrics().height() + 2, sizeHint().height());
423 return size;
424}
425
426/*!
427 \property QProgressBar::text
428 \brief the descriptive text shown with the progress bar
429
430 The text returned is the same as the text displayed in the center
431 (or in some styles, to the left) of the progress bar.
432
433 The progress shown in the text may be smaller than the minimum value,
434 indicating that the progress bar is in the "reset" state before any
435 progress is set.
436
437 In the default implementation, the text either contains a percentage
438 value that indicates the progress so far, or it is blank because the
439 progress bar is in the reset state.
440*/
441QString QProgressBar::text() const
442{
443 Q_D(const QProgressBar);
444 if (d->maximum == 0 || d->value < d->minimum
445 || (d->value == INT_MIN && d->minimum == INT_MIN))
446 return QString();
447
448 qint64 totalSteps = qint64(d->maximum) - qint64(d->minimum);
449
450 QString result = d->format;
451 result.replace(QLatin1String("%m"), QString::fromLatin1("%1").arg(totalSteps));
452 result.replace(QLatin1String("%v"), QString::fromLatin1("%1").arg(d->value));
453
454 // If max and min are equal and we get this far, it means that the
455 // progress bar has one step and that we are on that step. Return
456 // 100% here in order to avoid division by zero further down.
457 if (totalSteps == 0) {
458 result.replace(QLatin1String("%p"), QString::fromLatin1("%1").arg(100));
459 return result;
460 }
461
462 int progress = int(((qreal(d->value) - qreal(d->minimum)) * 100.0) / totalSteps);
463 result.replace(QLatin1String("%p"), QString::fromLatin1("%1").arg(progress));
464 return result;
465}
466
467/*!
468 \since 4.1
469 \property QProgressBar::orientation
470 \brief the orientation of the progress bar
471
472 The orientation must be \l Qt::Horizontal (the default) or \l
473 Qt::Vertical.
474
475 \sa invertedAppearance, textDirection
476*/
477
478void QProgressBar::setOrientation(Qt::Orientation orientation)
479{
480 Q_D(QProgressBar);
481 if (d->orientation == orientation)
482 return;
483 d->orientation = orientation;
484 if (!testAttribute(Qt::WA_WState_OwnSizePolicy)) {
485 QSizePolicy sp = sizePolicy();
486 sp.transpose();
487 setSizePolicy(sp);
488 setAttribute(Qt::WA_WState_OwnSizePolicy, false);
489 }
490 d->resetLayoutItemMargins();
491 update();
492 updateGeometry();
493}
494
495Qt::Orientation QProgressBar::orientation() const
496{
497 Q_D(const QProgressBar);
498 return d->orientation;
499}
500
501/*!
502 \since 4.1
503 \property QProgressBar::invertedAppearance
504 \brief whether or not a progress bar shows its progress inverted
505
506 If this property is false, the progress bar grows in the other
507 direction (e.g. from right to left). By default, the progress bar
508 is not inverted.
509
510 \sa orientation, layoutDirection
511*/
512
513void QProgressBar::setInvertedAppearance(bool invert)
514{
515 Q_D(QProgressBar);
516 d->invertedAppearance = invert;
517 update();
518}
519
520bool QProgressBar::invertedAppearance()
521{
522 Q_D(QProgressBar);
523 return d->invertedAppearance;
524}
525
526/*!
527 \since 4.1
528 \property QProgressBar::textDirection
529 \brief the reading direction of the \l text for vertical progress bars
530
531 This property has no impact on horizontal progress bars.
532 By default, the reading direction is QProgressBar::TopToBottom.
533
534 \sa orientation, textVisible
535*/
536void QProgressBar::setTextDirection(QProgressBar::Direction textDirection)
537{
538 Q_D(QProgressBar);
539 d->textDirection = textDirection;
540 update();
541}
542
543QProgressBar::Direction QProgressBar::textDirection()
544{
545 Q_D(QProgressBar);
546 return d->textDirection;
547}
548
549/*! \reimp */
550bool QProgressBar::event(QEvent *e)
551{
552 Q_D(QProgressBar);
553 if (e->type() == QEvent::StyleChange
554#ifdef Q_WS_MAC
555 || e->type() == QEvent::MacSizeChange
556#endif
557 )
558 d->resetLayoutItemMargins();
559 return QWidget::event(e);
560}
561
562/*!
563 \since 4.2
564 \property QProgressBar::format
565 \brief the string used to generate the current text
566
567 %p - is replaced by the percentage completed.
568 %v - is replaced by the current value.
569 %m - is replaced by the total number of steps.
570
571 The default value is "%p%".
572
573 \sa text()
574*/
575void QProgressBar::setFormat(const QString &format)
576{
577 Q_D(QProgressBar);
578 if (d->format == format)
579 return;
580 d->format = format;
581 update();
582}
583
584QString QProgressBar::format() const
585{
586 Q_D(const QProgressBar);
587 return d->format;
588}
589
590QT_END_NAMESPACE
591
592#endif // QT_NO_PROGRESSBAR
Note: See TracBrowser for help on using the repository browser.