Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qstatusbar.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#include "qstatusbar.h"
6
7#include "qlist.h"
8#include "qdebug.h"
9#include "qevent.h"
10#include "qlayout.h"
11#include "qpainter.h"
12#include "qtimer.h"
13#include "qstyle.h"
14#include "qstyleoption.h"
15#if QT_CONFIG(sizegrip)
16#include "qsizegrip.h"
17#endif
18#if QT_CONFIG(mainwindow)
19#include "qmainwindow.h"
20#endif
21
22#if QT_CONFIG(accessibility)
23#include "qaccessible.h"
24#endif
25
26#include <private/qlayoutengine_p.h>
27#include <private/qwidget_p.h>
28
30
32{
33 Q_DECLARE_PUBLIC(QStatusBar)
34public:
36
42
43 struct SBItem {
44 QWidget *widget = nullptr;
45 int stretch = 0;
47 bool isPermanent() const { return category == Permanent; }
48 };
49
52
55
56#if QT_CONFIG(sizegrip)
58 bool showSizeGrip;
59#endif
60
62
64 {
65 int i = items.size() - 1;
66 for (; i >= 0; --i) {
67 const SBItem &item = items.at(i);
68 if (!item.isPermanent())
69 break;
70 }
71 return i;
72 }
73
74#if QT_CONFIG(sizegrip)
76 {
77 if (!showSizeGrip)
78 return;
79 showSizeGrip = false;
80 if (!resizer || resizer->isVisible())
81 return;
83 QMetaObject::invokeMethod(resizer, "_q_showIfNotHidden", Qt::DirectConnection);
85 }
86#endif
87
89};
90
91
93{
94 Q_Q(const QStatusBar);
95 const bool rtl = q->layoutDirection() == Qt::RightToLeft;
96
97 int left = 6;
98 int right = q->width() - 12;
99
100#if QT_CONFIG(sizegrip)
101 if (resizer && resizer->isVisible()) {
102 if (rtl)
103 left = resizer->x() + resizer->width();
104 else
105 right = resizer->x();
106 }
107#endif
108
109 for (const auto &item : items) {
110 if (item.isPermanent() && item.widget->isVisible()) {
111 if (rtl)
112 left = qMax(left, item.widget->x() + item.widget->width() + 2);
113 else
114 right = qMin(right, item.widget->x() - 2);
115 break;
116 }
117 }
118 return QRect(left, 0, right-left, q->height());
119}
120
121
122/*!
123 \class QStatusBar
124 \brief The QStatusBar class provides a horizontal bar suitable for
125 presenting status information.
126
127 \ingroup mainwindow-classes
128 \ingroup helpsystem
129 \inmodule QtWidgets
130
131 Each status indicator falls into one of three categories:
132
133 \list
134 \li \e Temporary - briefly occupies most of the status bar. Used
135 to explain tool tip texts or menu entries, for example.
136 \li \e Normal - occupies part of the status bar and may be hidden
137 by temporary messages. Used to display the page and line
138 number in a word processor, for example.
139 \li \e Permanent - is never hidden. Used for important mode
140 indications, for example, some applications put a Caps Lock
141 indicator in the status bar.
142 \endlist
143
144 QStatusBar lets you display all three types of indicators.
145
146 Typically, a request for the status bar functionality occurs in
147 relation to a QMainWindow object. QMainWindow provides a main
148 application window, with a menu bar, tool bars, dock widgets \e
149 and a status bar around a large central widget. The status bar can
150 be retrieved using the QMainWindow::statusBar() function, and
151 replaced using the QMainWindow::setStatusBar() function.
152
153 Use the showMessage() slot to display a \e temporary message:
154
155 \snippet code/src_gui_widgets_qstatusbar.cpp 1
156
157 To remove a temporary message, use the clearMessage() slot, or set
158 a time limit when calling showMessage(). For example:
159
160 \snippet code/src_gui_widgets_qstatusbar.cpp 2
161
162 Use the currentMessage() function to retrieve the temporary
163 message currently shown. The QStatusBar class also provide the
164 messageChanged() signal which is emitted whenever the temporary
165 status message changes.
166
167 \target permanent message
168 \e Normal and \e Permanent messages are displayed by creating a
169 small widget (QLabel, QProgressBar or even QToolButton) and then
170 adding it to the status bar using the addWidget() or the
171 addPermanentWidget() function. Use the removeWidget() function to
172 remove such messages from the status bar.
173
174 \snippet code/src_gui_widgets_qstatusbar.cpp 0
175
176 By default QStatusBar provides a QSizeGrip in the lower-right
177 corner. You can disable it using the setSizeGripEnabled()
178 function. Use the isSizeGripEnabled() function to determine the
179 current status of the size grip.
180
181 \image fusion-statusbar-sizegrip.png A status bar shown in the Fusion widget style
182
183 \sa QMainWindow, QStatusTipEvent
184*/
185
186
187/*!
188 Constructs a status bar with a size grip and the given \a parent.
189
190 \sa setSizeGripEnabled()
191*/
192QStatusBar::QStatusBar(QWidget * parent)
193 : QWidget(*new QStatusBarPrivate, parent, { })
194{
195 Q_D(QStatusBar);
196 d->box = nullptr;
197 d->timer = nullptr;
198
199#if QT_CONFIG(sizegrip)
200 d->resizer = nullptr;
201 setSizeGripEnabled(true); // causes reformat()
202#else
203 reformat();
204#endif
205}
206
207/*!
208 Destroys this status bar and frees any allocated resources and
209 child widgets.
210*/
211QStatusBar::~QStatusBar()
212{
213}
214
215
216/*!
217 Adds the given \a widget to this status bar, reparenting the
218 widget if it isn't already a child of this QStatusBar object. The
219 \a stretch parameter is used to compute a suitable size for the
220 given \a widget as the status bar grows and shrinks. The default
221 stretch factor is 0, i.e giving the widget a minimum of space.
222
223 The widget is located to the far left of the first permanent
224 widget (see addPermanentWidget()) and may be obscured by temporary
225 messages.
226
227 \sa insertWidget(), removeWidget(), addPermanentWidget()
228*/
229
230void QStatusBar::addWidget(QWidget * widget, int stretch)
231{
232 if (!widget)
233 return;
234 insertWidget(d_func()->indexToLastNonPermanentWidget() + 1, widget, stretch);
235}
236
237/*!
238 \since 4.2
239
240 Inserts the given \a widget at the given \a index to this status bar,
241 reparenting the widget if it isn't already a child of this
242 QStatusBar object. If \a index is out of range, the widget is appended
243 (in which case it is the actual index of the widget that is returned).
244
245 The \a stretch parameter is used to compute a suitable size for
246 the given \a widget as the status bar grows and shrinks. The
247 default stretch factor is 0, i.e giving the widget a minimum of
248 space.
249
250 The widget is located to the far left of the first permanent
251 widget (see addPermanentWidget()) and may be obscured by temporary
252 messages.
253
254 \sa addWidget(), removeWidget(), addPermanentWidget()
255*/
256int QStatusBar::insertWidget(int index, QWidget *widget, int stretch)
257{
258 if (!widget)
259 return -1;
260
261 Q_D(QStatusBar);
262 QStatusBarPrivate::SBItem item{widget, stretch, QStatusBarPrivate::Normal};
263
264 int idx = d->indexToLastNonPermanentWidget();
265 if (Q_UNLIKELY(index < 0 || index > d->items.size() || (idx >= 0 && index > idx + 1))) {
266 qWarning("QStatusBar::insertWidget: Index out of range (%d), appending widget", index);
267 index = idx + 1;
268 }
269 d->items.insert(index, item);
270
271 if (!d->tempItem.isEmpty())
272 widget->hide();
273
274 reformat();
275 if (!QWidgetPrivate::get(widget)->isExplicitlyHidden())
276 widget->show();
277
278 return index;
279}
280
281/*!
282 Adds the given \a widget permanently to this status bar,
283 reparenting the widget if it isn't already a child of this
284 QStatusBar object. The \a stretch parameter is used to compute a
285 suitable size for the given \a widget as the status bar grows and
286 shrinks. The default stretch factor is 0, i.e giving the widget a
287 minimum of space.
288
289 Permanently means that the widget may not be obscured by temporary
290 messages. It is located at the far right of the status bar.
291
292 \sa insertPermanentWidget(), removeWidget(), addWidget()
293*/
294
295void QStatusBar::addPermanentWidget(QWidget * widget, int stretch)
296{
297 if (!widget)
298 return;
299 insertPermanentWidget(d_func()->items.size(), widget, stretch);
300}
301
302/*!
303 \since 4.2
304
305 Inserts the given \a widget at the given \a index permanently to this status bar,
306 reparenting the widget if it isn't already a child of this
307 QStatusBar object. If \a index is out of range, the widget is appended
308 (in which case it is the actual index of the widget that is returned).
309
310 The \a stretch parameter is used to compute a
311 suitable size for the given \a widget as the status bar grows and
312 shrinks. The default stretch factor is 0, i.e giving the widget a
313 minimum of space.
314
315 Permanently means that the widget may not be obscured by temporary
316 messages. It is located at the far right of the status bar.
317
318 \sa addPermanentWidget(), removeWidget(), addWidget()
319*/
320int QStatusBar::insertPermanentWidget(int index, QWidget *widget, int stretch)
321{
322 if (!widget)
323 return -1;
324
325 Q_D(QStatusBar);
326 QStatusBarPrivate::SBItem item{widget, stretch, QStatusBarPrivate::Permanent};
327
328 int idx = d->indexToLastNonPermanentWidget();
329 if (Q_UNLIKELY(index < 0 || index > d->items.size() || (idx >= 0 && index <= idx))) {
330 qWarning("QStatusBar::insertPermanentWidget: Index out of range (%d), appending widget", index);
331 index = d->items.size();
332 }
333 d->items.insert(index, item);
334
335 reformat();
336 if (!QWidgetPrivate::get(widget)->isExplicitlyHidden())
337 widget->show();
338
339 return index;
340}
341
342/*!
343 Removes the specified \a widget from the status bar.
344
345 \note This function does not delete the widget but \e hides it.
346 To add the widget again, you must call both the addWidget() and
347 show() functions.
348
349 \sa addWidget(), addPermanentWidget(), clearMessage()
350*/
351
352void QStatusBar::removeWidget(QWidget *widget)
353{
354 if (!widget)
355 return;
356
357 Q_D(QStatusBar);
358 if (d->items.removeIf([widget](const auto &item) { return item.widget == widget; })) {
359 widget->hide();
360 reformat();
361 }
362#if defined(QT_DEBUG)
363 else
364 qDebug("QStatusBar::removeWidget(): Widget not found.");
365#endif
366}
367
368/*!
369 \property QStatusBar::sizeGripEnabled
370
371 \brief whether the QSizeGrip in the bottom-right corner of the
372 status bar is enabled
373
374 The size grip is enabled by default.
375*/
376
377bool QStatusBar::isSizeGripEnabled() const
378{
379#if !QT_CONFIG(sizegrip)
380 return false;
381#else
382 Q_D(const QStatusBar);
383 return !!d->resizer;
384#endif
385}
386
387void QStatusBar::setSizeGripEnabled(bool enabled)
388{
389#if !QT_CONFIG(sizegrip)
390 Q_UNUSED(enabled);
391#else
392 Q_D(QStatusBar);
393 if (!enabled != !d->resizer) {
394 if (enabled) {
395 d->resizer = new QSizeGrip(this);
396 d->resizer->hide();
397 d->resizer->installEventFilter(this);
398 d->showSizeGrip = true;
399 } else {
400 delete d->resizer;
401 d->resizer = nullptr;
402 d->showSizeGrip = false;
403 }
404 reformat();
405 if (d->resizer && isVisible())
406 d->tryToShowSizeGrip();
407 }
408#endif
409}
410
411
412/*!
413 Changes the status bar's appearance to account for item changes.
414
415 Special subclasses may need this function, but geometry management
416 will usually take care of any necessary rearrangements.
417*/
418void QStatusBar::reformat()
419{
420 Q_D(QStatusBar);
421 if (d->box)
422 delete d->box;
423
424 QBoxLayout *vbox;
425#if QT_CONFIG(sizegrip)
426 if (d->resizer) {
427 d->box = new QHBoxLayout(this);
428 d->box->setContentsMargins(QMargins());
429 vbox = new QVBoxLayout;
430 d->box->addLayout(vbox);
431 } else
432#endif
433 {
434 vbox = d->box = new QVBoxLayout(this);
435 d->box->setContentsMargins(QMargins());
436 }
437 vbox->addSpacing(3);
438 QBoxLayout* l = new QHBoxLayout;
439 vbox->addLayout(l);
440 l->addSpacing(2);
441 l->setSpacing(6);
442
443 int maxH = fontMetrics().height();
444
445 qsizetype i;
446 for (i = 0; i < d->items.size(); ++i) {
447 const auto &item = d->items.at(i);
448 if (item.isPermanent())
449 break;
450 l->addWidget(item.widget, item.stretch);
451 int itemH = qMin(qSmartMinSize(item.widget).height(), item.widget->maximumHeight());
452 maxH = qMax(maxH, itemH);
453 }
454
455 l->addStretch(0);
456
457 for (; i < d->items.size(); ++i) {
458 const auto &item = d->items.at(i);
459 l->addWidget(item.widget, item.stretch);
460 int itemH = qMin(qSmartMinSize(item.widget).height(), item.widget->maximumHeight());
461 maxH = qMax(maxH, itemH);
462 }
463#if QT_CONFIG(sizegrip)
464 if (d->resizer) {
465 maxH = qMax(maxH, d->resizer->sizeHint().height());
466 d->box->addSpacing(1);
467 d->box->addWidget(d->resizer, 0, Qt::AlignBottom);
468 }
469#endif
470 l->addStrut(maxH);
471 d->savedStrut = maxH;
472 vbox->addSpacing(2);
473 d->box->activate();
474 update();
475}
476
477/*!
478
479 Hides the normal status indications and displays the given \a
480 message for the specified number of milli-seconds (\a{timeout}). If
481 \a{timeout} is 0 (default), the \a {message} remains displayed until
482 the clearMessage() slot is called or until the showMessage() slot is
483 called again to change the message.
484
485 Note that showMessage() is called to show temporary explanations of
486 tool tip texts, so passing a \a{timeout} of 0 is not sufficient to
487 display a \l{permanent message}{permanent message}.
488
489 \sa messageChanged(), currentMessage(), clearMessage()
490*/
491void QStatusBar::showMessage(const QString &message, int timeout)
492{
493 Q_D(QStatusBar);
494
495 if (timeout > 0) {
496 if (!d->timer) {
497 d->timer = new QTimer(this);
498 connect(d->timer, &QTimer::timeout, this, &QStatusBar::clearMessage);
499 }
500 d->timer->start(timeout);
501 } else if (d->timer) {
502 delete d->timer;
503 d->timer = nullptr;
504 }
505 if (d->tempItem == message)
506 return;
507 d->tempItem = message;
508
509 hideOrShow();
510}
511
512/*!
513 Removes any temporary message being shown.
514
515 \sa currentMessage(), showMessage(), removeWidget()
516*/
517
518void QStatusBar::clearMessage()
519{
520 Q_D(QStatusBar);
521 if (d->tempItem.isEmpty())
522 return;
523 if (d->timer) {
524 delete d->timer;
525 d->timer = nullptr;
526 }
527 d->tempItem.clear();
528 hideOrShow();
529}
530
531/*!
532 Returns the temporary message currently shown,
533 or an empty string if there is no such message.
534
535 \sa showMessage()
536*/
537QString QStatusBar::currentMessage() const
538{
539 Q_D(const QStatusBar);
540 return d->tempItem;
541}
542
543/*!
544 \fn void QStatusBar::messageChanged(const QString &message)
545
546 This signal is emitted whenever the temporary status message
547 changes. The new temporary message is passed in the \a message
548 parameter which is a null-string when the message has been
549 removed.
550
551 \sa showMessage(), clearMessage()
552*/
553
554/*!
555 Ensures that the right widgets are visible.
556
557 Used by the showMessage() and clearMessage() functions.
558*/
559void QStatusBar::hideOrShow()
560{
561 Q_D(QStatusBar);
562 bool haveMessage = !d->tempItem.isEmpty();
563
564 for (const auto &item : std::as_const(d->items)) {
565 if (item.isPermanent())
566 break;
567 if (haveMessage && item.widget->isVisible()) {
568 item.widget->hide();
569 item.widget->setAttribute(Qt::WA_WState_ExplicitShowHide, false);
570 } else if (!haveMessage && !item.widget->testAttribute(Qt::WA_WState_ExplicitShowHide)) {
571 item.widget->show();
572 }
573 }
574
575 emit messageChanged(d->tempItem);
576
577#if QT_CONFIG(accessibility)
578 if (QAccessible::isActive()) {
579 QAccessibleEvent event(this, QAccessible::NameChanged);
580 QAccessible::updateAccessibility(&event);
581 }
582#endif
583
584 update(d->messageRect());
585}
586
587/*!
588 \reimp
589 */
590void QStatusBar::showEvent(QShowEvent *)
591{
592#if QT_CONFIG(sizegrip)
593 Q_D(QStatusBar);
594 if (d->resizer && d->showSizeGrip)
595 d->tryToShowSizeGrip();
596#endif
597}
598
599/*!
600 \reimp
601 \fn void QStatusBar::paintEvent(QPaintEvent *event)
602
603 Shows the temporary message, if appropriate, in response to the
604 paint \a event.
605*/
606void QStatusBar::paintEvent(QPaintEvent *event)
607{
608 Q_D(QStatusBar);
609 bool haveMessage = !d->tempItem.isEmpty();
610
611 QPainter p(this);
612 QStyleOption opt;
613 opt.initFrom(this);
614 style()->drawPrimitive(QStyle::PE_PanelStatusBar, &opt, &p, this);
615
616 for (const auto &item : std::as_const(d->items)) {
617 if (item.widget->isVisible() && (!haveMessage || item.isPermanent())) {
618 QRect ir = item.widget->geometry().adjusted(-2, -1, 2, 1);
619 if (event->rect().intersects(ir)) {
620 QStyleOption opt(0);
621 opt.rect = ir;
622 opt.palette = palette();
623 opt.state = QStyle::State_None;
624 style()->drawPrimitive(QStyle::PE_FrameStatusBarItem, &opt, &p, item.widget);
625 }
626 }
627 }
628 if (haveMessage) {
629 p.setPen(palette().windowText().color());
630 p.drawText(d->messageRect(), Qt::AlignLeading | Qt::AlignVCenter | Qt::TextSingleLine, d->tempItem);
631 }
632}
633
634/*!
635 \reimp
636*/
637void QStatusBar::resizeEvent(QResizeEvent * e)
638{
639 QWidget::resizeEvent(e);
640}
641
642/*!
643 \reimp
644*/
645
646bool QStatusBar::event(QEvent *e)
647{
648 Q_D(QStatusBar);
649
650 switch (e->type()) {
651 case QEvent::LayoutRequest: {
652 // Calculate new strut height and call reformat() if it has changed
653 int maxH = fontMetrics().height();
654
655 for (const auto &item : std::as_const(d->items)) {
656 const int itemH = qMin(qSmartMinSize(item.widget).height(), item.widget->maximumHeight());
657 maxH = qMax(maxH, itemH);
658 }
659
660#if QT_CONFIG(sizegrip)
661 if (d->resizer)
662 maxH = qMax(maxH, d->resizer->sizeHint().height());
663#endif
664
665 if (maxH != d->savedStrut)
666 reformat();
667 else
668 update();
669 break;
670 }
671 case QEvent::ChildRemoved:
672 for (int i = 0; i < d->items.size(); ++i) {
673 const auto &item = d->items.at(i);
674 if (item.widget == static_cast<QChildEvent *>(e)->child())
675 d->items.removeAt(i);
676 }
677 break;
678 default:
679 break;
680 }
681
682 return QWidget::event(e);
683}
684
685QT_END_NAMESPACE
686
687#include "moc_qstatusbar.cpp"
Definition qlist.h:80
friend class QWidget
Definition qpainter.h:431
QRect messageRect() const
int indexToLastNonPermanentWidget() const
QList< SBItem > items
QBoxLayout * box