1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qtoolbar.h"
43
44 #ifndef QT_NO_TOOLBAR
45
46 #include <qapplication.h>
47 #include <qcombobox.h>
48 #include <qevent.h>
49 #include <qlayout.h>
50 #include <qmainwindow.h>
51 #include <qmenu.h>
52 #include <qmenubar.h>
53 #include <qrubberband.h>
54 #include <qsignalmapper.h>
55 #include <qstylepainter.h>
56 #include <qtoolbutton.h>
57 #include <qwidgetaction.h>
58 #include <qtimer.h>
59 #include <private/qwidgetaction_p.h>
60 #ifdef Q_WS_MAC
61 #include <private/qt_mac_p.h>
62 #include <private/qt_cocoa_helpers_mac_p.h>
63 #endif
64
65 #include <private/qmainwindowlayout_p.h>
66
67 #include "qtoolbar_p.h"
68 #include "qtoolbarseparator_p.h"
69 #include "qtoolbarlayout_p.h"
70
71 #include "qdebug.h"
72
73 #define POPUP_TIMER_INTERVAL 500
74
75 QT_BEGIN_NAMESPACE
76
77 #ifdef Q_WS_MAC
qt_mac_updateToolBarButtonHint(QWidget * parentWidget)78 static void qt_mac_updateToolBarButtonHint(QWidget *parentWidget)
79 {
80 if (!(parentWidget->windowFlags() & Qt::CustomizeWindowHint))
81 parentWidget->setWindowFlags(parentWidget->windowFlags() | Qt::MacWindowToolBarButtonHint);
82 }
83 #endif
84
85 // qmainwindow.cpp
86 extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *window);
87
88 /******************************************************************************
89 ** QToolBarPrivate
90 */
91
init()92 void QToolBarPrivate::init()
93 {
94 Q_Q(QToolBar);
95 q->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
96 q->setBackgroundRole(QPalette::Button);
97 q->setAttribute(Qt::WA_Hover);
98 q->setAttribute(Qt::WA_X11NetWmWindowTypeToolBar);
99
100 QStyle *style = q->style();
101 int e = style->pixelMetric(QStyle::PM_ToolBarIconSize, 0, q);
102 iconSize = QSize(e, e);
103
104 layout = new QToolBarLayout(q);
105 layout->updateMarginAndSpacing();
106
107 #ifdef Q_WS_MAC
108 if (q->parentWidget() && q->parentWidget()->isWindow()) {
109 // Make sure that the window has the "toolbar" button.
110 QWidget *parentWidget = q->parentWidget();
111 qt_mac_updateToolBarButtonHint(parentWidget);
112 reinterpret_cast<QToolBar *>(parentWidget)->d_func()->createWinId(); // Please let me create your winId...
113 extern OSWindowRef qt_mac_window_for(const QWidget *); // qwidget_mac.cpp
114 macWindowToolbarShow(q->parentWidget(), true);
115 }
116 #endif
117
118 toggleViewAction = new QAction(q);
119 toggleViewAction->setCheckable(true);
120 q->setMovable(q->style()->styleHint(QStyle::SH_ToolBar_Movable, 0, q ));
121 QObject::connect(toggleViewAction, SIGNAL(triggered(bool)), q, SLOT(_q_toggleView(bool)));
122 }
123
_q_toggleView(bool b)124 void QToolBarPrivate::_q_toggleView(bool b)
125 {
126 Q_Q(QToolBar);
127 if (b == q->isHidden()) {
128 if (b)
129 q->show();
130 else
131 q->close();
132 }
133 }
134
_q_updateIconSize(const QSize & sz)135 void QToolBarPrivate::_q_updateIconSize(const QSize &sz)
136 {
137 Q_Q(QToolBar);
138 if (!explicitIconSize) {
139 // iconSize not explicitly set
140 q->setIconSize(sz);
141 explicitIconSize = false;
142 }
143 }
144
_q_updateToolButtonStyle(Qt::ToolButtonStyle style)145 void QToolBarPrivate::_q_updateToolButtonStyle(Qt::ToolButtonStyle style)
146 {
147 Q_Q(QToolBar);
148 if (!explicitToolButtonStyle) {
149 q->setToolButtonStyle(style);
150 explicitToolButtonStyle = false;
151 }
152 }
153
updateWindowFlags(bool floating,bool unplug)154 void QToolBarPrivate::updateWindowFlags(bool floating, bool unplug)
155 {
156 Q_Q(QToolBar);
157 Qt::WindowFlags flags = floating ? Qt::Tool : Qt::Widget;
158
159 flags |= Qt::FramelessWindowHint;
160
161 if (unplug) {
162 flags |= Qt::X11BypassWindowManagerHint;
163 #ifdef Q_WS_MAC
164 flags |= Qt::WindowStaysOnTopHint;
165 #endif
166 }
167
168 q->setWindowFlags(flags);
169 }
170
setWindowState(bool floating,bool unplug,const QRect & rect)171 void QToolBarPrivate::setWindowState(bool floating, bool unplug, const QRect &rect)
172 {
173 Q_Q(QToolBar);
174 bool visible = !q->isHidden();
175 bool wasFloating = q->isFloating(); // ...is also currently using popup menus
176
177 q->hide();
178
179 updateWindowFlags(floating, unplug);
180
181 if (floating != wasFloating)
182 layout->checkUsePopupMenu();
183
184 if (!rect.isNull())
185 q->setGeometry(rect);
186
187 if (visible)
188 q->show();
189
190 if (floating != wasFloating)
191 emit q->topLevelChanged(floating);
192 }
193
initDrag(const QPoint & pos)194 void QToolBarPrivate::initDrag(const QPoint &pos)
195 {
196 Q_Q(QToolBar);
197
198 if (state != 0)
199 return;
200
201 QMainWindow *win = qobject_cast<QMainWindow*>(parent);
202 Q_ASSERT(win != 0);
203 QMainWindowLayout *layout = qt_mainwindow_layout(win);
204 Q_ASSERT(layout != 0);
205 if (layout->pluggingWidget != 0) // the main window is animating a docking operation
206 return;
207
208 state = new DragState;
209 state->pressPos = pos;
210 state->dragging = false;
211 state->moving = false;
212 state->widgetItem = 0;
213
214 if (q->isRightToLeft())
215 state->pressPos = QPoint(q->width() - state->pressPos.x(), state->pressPos.y());
216 }
217
startDrag(bool moving)218 void QToolBarPrivate::startDrag(bool moving)
219 {
220 Q_Q(QToolBar);
221
222 Q_ASSERT(state != 0);
223
224 if ((moving && state->moving) || state->dragging)
225 return;
226
227 QMainWindow *win = qobject_cast<QMainWindow*>(parent);
228 Q_ASSERT(win != 0);
229 QMainWindowLayout *layout = qt_mainwindow_layout(win);
230 Q_ASSERT(layout != 0);
231
232 if (!moving) {
233 state->widgetItem = layout->unplug(q);
234 #if defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA)
235 if (q->isWindow()) {
236 setWindowState(true, true); //set it to floating
237 }
238 #endif
239 Q_ASSERT(state->widgetItem != 0);
240 }
241 state->dragging = !moving;
242 state->moving = moving;
243 }
244
endDrag()245 void QToolBarPrivate::endDrag()
246 {
247 Q_Q(QToolBar);
248 Q_ASSERT(state != 0);
249
250 q->releaseMouse();
251
252 if (state->dragging) {
253 QMainWindowLayout *layout = qt_mainwindow_layout(qobject_cast<QMainWindow *>(q->parentWidget()));
254 Q_ASSERT(layout != 0);
255
256 if (!layout->plug(state->widgetItem)) {
257 if (q->isFloatable()) {
258 layout->restore();
259 #if defined(Q_WS_X11) || defined(Q_WS_MAC)
260 setWindowState(true); // gets rid of the X11BypassWindowManager window flag
261 // and activates the resizer
262 #endif
263 q->activateWindow();
264 } else {
265 layout->revert(state->widgetItem);
266 }
267 }
268 }
269
270 delete state;
271 state = 0;
272 }
273
mousePressEvent(QMouseEvent * event)274 bool QToolBarPrivate::mousePressEvent(QMouseEvent *event)
275 {
276 Q_Q(QToolBar);
277 QStyleOptionToolBar opt;
278 q->initStyleOption(&opt);
279 if (q->style()->subElementRect(QStyle::SE_ToolBarHandle, &opt, q).contains(event->pos()) == false) {
280 #ifdef Q_WS_MAC
281 // When using the unified toolbar on Mac OS X the user can can click and
282 // drag between toolbar contents to move the window. Make this work by
283 // implementing the standard mouse-dragging code and then call
284 // window->move() in mouseMoveEvent below.
285 if (QMainWindow *mainWindow = qobject_cast<QMainWindow *>(parent)) {
286 if (mainWindow->toolBarArea(q) == Qt::TopToolBarArea
287 && mainWindow->unifiedTitleAndToolBarOnMac()
288 && q->childAt(event->pos()) == 0) {
289 macWindowDragging = true;
290 macWindowDragPressPosition = event->pos();
291 return true;
292 }
293 }
294 #endif
295 return false;
296 }
297
298 if (event->button() != Qt::LeftButton)
299 return true;
300
301 if (!layout->movable())
302 return true;
303
304 initDrag(event->pos());
305 return true;
306 }
307
mouseReleaseEvent(QMouseEvent *)308 bool QToolBarPrivate::mouseReleaseEvent(QMouseEvent*)
309 {
310 if (state != 0) {
311 endDrag();
312 return true;
313 } else {
314 #ifdef Q_WS_MAC
315 if (!macWindowDragging)
316 return false;
317 macWindowDragging = false;
318 macWindowDragPressPosition = QPoint();
319 return true;
320 #endif
321 return false;
322 }
323 }
324
mouseMoveEvent(QMouseEvent * event)325 bool QToolBarPrivate::mouseMoveEvent(QMouseEvent *event)
326 {
327 Q_Q(QToolBar);
328
329 if (!state) {
330 #ifdef Q_WS_MAC
331 if (!macWindowDragging)
332 return false;
333 QWidget *w = q->window();
334 const QPoint delta = event->pos() - macWindowDragPressPosition;
335 w->move(w->pos() + delta);
336 return true;
337 #endif
338 return false;
339 }
340
341 QMainWindow *win = qobject_cast<QMainWindow*>(parent);
342 if (win == 0)
343 return true;
344
345 QMainWindowLayout *layout = qt_mainwindow_layout(win);
346 Q_ASSERT(layout != 0);
347
348 if (layout->pluggingWidget == 0
349 && (event->pos() - state->pressPos).manhattanLength() > QApplication::startDragDistance()) {
350 const bool wasDragging = state->dragging;
351 const bool moving = !q->isWindow() && (orientation == Qt::Vertical ?
352 event->x() >= 0 && event->x() < q->width() :
353 event->y() >= 0 && event->y() < q->height());
354
355 startDrag(moving);
356 if (!moving && !wasDragging) {
357 #ifdef Q_OS_WIN
358 grabMouseWhileInWindow();
359 #else
360 q->grabMouse();
361 #endif
362 }
363 }
364
365 if (state->dragging) {
366 QPoint pos = event->globalPos();
367 // if we are right-to-left, we move so as to keep the right edge the same distance
368 // from the mouse
369 if (q->isLeftToRight())
370 pos -= state->pressPos;
371 else
372 pos += QPoint(state->pressPos.x() - q->width(), -state->pressPos.y());
373
374 q->move(pos);
375 layout->hover(state->widgetItem, event->globalPos());
376 } else if (state->moving) {
377
378 const QPoint rtl(q->width() - state->pressPos.x(), state->pressPos.y()); //for RTL
379 const QPoint globalPressPos = q->mapToGlobal(q->isRightToLeft() ? rtl : state->pressPos);
380 int pos = 0;
381
382 QPoint delta = event->globalPos() - globalPressPos;
383 if (orientation == Qt::Vertical) {
384 pos = q->y() + delta.y();
385 } else {
386 if (q->isRightToLeft()) {
387 pos = win->width() - q->width() - q->x() - delta.x();
388 } else {
389 pos = q->x() + delta.x();
390 }
391 }
392
393 layout->moveToolBar(q, pos);
394 }
395 return true;
396 }
397
unplug(const QRect & _r)398 void QToolBarPrivate::unplug(const QRect &_r)
399 {
400 Q_Q(QToolBar);
401 QRect r = _r;
402 r.moveTopLeft(q->mapToGlobal(QPoint(0, 0)));
403 setWindowState(true, true, r);
404 layout->setExpanded(false);
405 }
406
plug(const QRect & r)407 void QToolBarPrivate::plug(const QRect &r)
408 {
409 setWindowState(false, false, r);
410 }
411
412 /******************************************************************************
413 ** QToolBar
414 */
415
416 /*!
417 \class QToolBar
418
419 \brief The QToolBar class provides a movable panel that contains a
420 set of controls.
421
422 \ingroup mainwindow-classes
423
424
425 Toolbar buttons are added by adding \e actions, using addAction()
426 or insertAction(). Groups of buttons can be separated using
427 addSeparator() or insertSeparator(). If a toolbar button is not
428 appropriate, a widget can be inserted instead using addWidget() or
429 insertWidget(); examples of suitable widgets are QSpinBox,
430 QDoubleSpinBox, and QComboBox. When a toolbar button is pressed it
431 emits the actionTriggered() signal.
432
433 A toolbar can be fixed in place in a particular area (e.g. at the
434 top of the window), or it can be movable (isMovable()) between
435 toolbar areas; see allowedAreas() and isAreaAllowed().
436
437 When a toolbar is resized in such a way that it is too small to
438 show all the items it contains, an extension button will appear as
439 the last item in the toolbar. Pressing the extension button will
440 pop up a menu containing the items that does not currently fit in
441 the toolbar.
442
443 When a QToolBar is not a child of a QMainWindow, it loses the ability
444 to populate the extension pop up with widgets added to the toolbar using
445 addWidget(). Please use widget actions created by inheriting QWidgetAction
446 and implementing QWidgetAction::createWidget() instead.
447
448 \sa QToolButton, QMenu, QAction, {Application Example}
449 */
450
451 /*!
452 \fn bool QToolBar::isAreaAllowed(Qt::ToolBarArea area) const
453
454 Returns true if this toolbar is dockable in the given \a area;
455 otherwise returns false.
456 */
457
458 /*!
459 \fn void QToolBar::addAction(QAction *action)
460 \overload
461
462 Appends the action \a action to the toolbar's list of actions.
463
464 \sa QMenu::addAction(), QWidget::addAction()
465 */
466
467 /*!
468 \fn void QToolBar::actionTriggered(QAction *action)
469
470 This signal is emitted when an action in this toolbar is triggered.
471 This happens when the action's tool button is pressed, or when the
472 action is triggered in some other way outside the tool bar. The parameter
473 holds the triggered \a action.
474 */
475
476 /*!
477 \fn void QToolBar::allowedAreasChanged(Qt::ToolBarAreas allowedAreas)
478
479 This signal is emitted when the collection of allowed areas for the
480 toolbar is changed. The new areas in which the toolbar can be positioned
481 are specified by \a allowedAreas.
482
483 \sa allowedAreas
484 */
485
486 /*!
487 \fn void QToolBar::iconSizeChanged(const QSize &iconSize)
488
489 This signal is emitted when the icon size is changed. The \a
490 iconSize parameter holds the toolbar's new icon size.
491
492 \sa iconSize QMainWindow::iconSize
493 */
494
495 /*!
496 \fn void QToolBar::movableChanged(bool movable)
497
498 This signal is emitted when the toolbar becomes movable or fixed.
499 If the toolbar can be moved, \a movable is true; otherwise it is
500 false.
501
502 \sa movable
503 */
504
505 /*!
506 \fn void QToolBar::orientationChanged(Qt::Orientation orientation)
507
508 This signal is emitted when the orientation of the toolbar changes.
509 The new orientation is specified by the \a orientation given.
510
511 \sa orientation
512 */
513
514 /*!
515 \fn void QToolBar::toolButtonStyleChanged(Qt::ToolButtonStyle toolButtonStyle)
516
517 This signal is emitted when the tool button style is changed. The
518 \a toolButtonStyle parameter holds the toolbar's new tool button
519 style.
520
521 \sa toolButtonStyle QMainWindow::toolButtonStyle
522 */
523
524 /*!
525 \since 4.6
526
527 \fn void QToolBar::topLevelChanged(bool topLevel)
528
529 This signal is emitted when the \l floating property changes.
530 The \a topLevel parameter is true if the toolbar is now floating;
531 otherwise it is false.
532
533 \sa isWindow()
534 */
535
536
537 /*!
538 \fn void QToolBar::visibilityChanged(bool visible)
539 \since 4.7
540
541 This signal is emitted when the toolbar becomes \a visible (or
542 invisible). This happens when the widget is hidden or shown.
543 */
544
545 /*!
546 Constructs a QToolBar with the given \a parent.
547 */
QToolBar(QWidget * parent)548 QToolBar::QToolBar(QWidget *parent)
549 : QWidget(*new QToolBarPrivate, parent, 0)
550 {
551 Q_D(QToolBar);
552 d->init();
553 }
554
555 /*!
556 Constructs a QToolBar with the given \a parent.
557
558 The given window \a title identifies the toolbar and is shown in
559 the context menu provided by QMainWindow.
560
561 \sa setWindowTitle()
562 */
QToolBar(const QString & title,QWidget * parent)563 QToolBar::QToolBar(const QString &title, QWidget *parent)
564 : QWidget(*new QToolBarPrivate, parent, 0)
565 {
566 Q_D(QToolBar);
567 d->init();
568 setWindowTitle(title);
569 }
570
571 #ifdef QT3_SUPPORT
572 /*! \obsolete
573 Constructs a QToolBar with the given \a parent and \a name.
574 */
QToolBar(QWidget * parent,const char * name)575 QToolBar::QToolBar(QWidget *parent, const char *name)
576 : QWidget(*new QToolBarPrivate, parent, 0)
577 {
578 Q_D(QToolBar);
579 d->init();
580 setObjectName(QString::fromAscii(name));
581 }
582 #endif
583
584 /*!
585 Destroys the toolbar.
586 */
~QToolBar()587 QToolBar::~QToolBar()
588 {
589 // Remove the toolbar button if there is nothing left.
590 QMainWindow *mainwindow = qobject_cast<QMainWindow *>(parentWidget());
591 if (mainwindow) {
592 #ifdef Q_WS_MAC
593 QMainWindowLayout *mainwin_layout = qt_mainwindow_layout(mainwindow);
594 if (mainwin_layout && mainwin_layout->layoutState.toolBarAreaLayout.isEmpty()
595 && mainwindow->testAttribute(Qt::WA_WState_Created))
596 macWindowToolbarShow(mainwindow, false);
597 #endif
598 }
599 }
600
601 /*! \property QToolBar::movable
602 \brief whether the user can move the toolbar within the toolbar area,
603 or between toolbar areas
604
605 By default, this property is true.
606
607 This property only makes sense if the toolbar is in a
608 QMainWindow.
609
610 \sa allowedAreas
611 */
612
setMovable(bool movable)613 void QToolBar::setMovable(bool movable)
614 {
615 Q_D(QToolBar);
616 if (!movable == !d->movable)
617 return;
618 d->movable = movable;
619 d->layout->invalidate();
620 emit movableChanged(d->movable);
621 }
622
isMovable() const623 bool QToolBar::isMovable() const
624 {
625 Q_D(const QToolBar);
626 return d->movable;
627 }
628
629 /*!
630 \property QToolBar::floatable
631 \brief whether the toolbar can be dragged and dropped as an independent window.
632
633 The default is true.
634 */
isFloatable() const635 bool QToolBar::isFloatable() const
636 {
637 Q_D(const QToolBar);
638 return d->floatable;
639 }
640
setFloatable(bool floatable)641 void QToolBar::setFloatable(bool floatable)
642 {
643 Q_D(QToolBar);
644 d->floatable = floatable;
645 }
646
647 /*!
648 \property QToolBar::floating
649 \brief whether the toolbar is an independent window.
650
651 By default, this property is true.
652
653 \sa QWidget::isWindow()
654 */
isFloating() const655 bool QToolBar::isFloating() const
656 {
657 return isWindow();
658 }
659
660 /*!
661 \property QToolBar::allowedAreas
662 \brief areas where the toolbar may be placed
663
664 The default is Qt::AllToolBarAreas.
665
666 This property only makes sense if the toolbar is in a
667 QMainWindow.
668
669 \sa movable
670 */
671
setAllowedAreas(Qt::ToolBarAreas areas)672 void QToolBar::setAllowedAreas(Qt::ToolBarAreas areas)
673 {
674 Q_D(QToolBar);
675 areas &= Qt::ToolBarArea_Mask;
676 if (areas == d->allowedAreas)
677 return;
678 d->allowedAreas = areas;
679 emit allowedAreasChanged(d->allowedAreas);
680 }
681
allowedAreas() const682 Qt::ToolBarAreas QToolBar::allowedAreas() const
683 {
684 Q_D(const QToolBar);
685 #ifdef Q_WS_MAC
686 if (QMainWindow *window = qobject_cast<QMainWindow *>(parentWidget())) {
687 if (window->unifiedTitleAndToolBarOnMac()) // Don't allow drags to the top (for now).
688 return (d->allowedAreas & ~Qt::TopToolBarArea);
689 }
690 #endif
691 return d->allowedAreas;
692 }
693
694 /*! \property QToolBar::orientation
695 \brief orientation of the toolbar
696
697 The default is Qt::Horizontal.
698
699 This function should not be used when the toolbar is managed
700 by QMainWindow. You can use QMainWindow::addToolBar() or
701 QMainWindow::insertToolBar() if you wish to move a toolbar (that
702 is already added to a main window) to another Qt::ToolBarArea.
703 */
704
setOrientation(Qt::Orientation orientation)705 void QToolBar::setOrientation(Qt::Orientation orientation)
706 {
707 Q_D(QToolBar);
708 if (orientation == d->orientation)
709 return;
710
711 d->orientation = orientation;
712
713 if (orientation == Qt::Vertical)
714 setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred));
715 else
716 setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
717
718 d->layout->invalidate();
719 d->layout->activate();
720
721 emit orientationChanged(d->orientation);
722 }
723
orientation() const724 Qt::Orientation QToolBar::orientation() const
725 { Q_D(const QToolBar); return d->orientation; }
726
727 /*!
728 \property QToolBar::iconSize
729 \brief size of icons in the toolbar.
730
731 The default size is determined by the application's style and is
732 derived from the QStyle::PM_ToolBarIconSize pixel metric. It is
733 the maximum size an icon can have. Icons of smaller size will not
734 be scaled up.
735 */
736
iconSize() const737 QSize QToolBar::iconSize() const
738 { Q_D(const QToolBar); return d->iconSize; }
739
setIconSize(const QSize & iconSize)740 void QToolBar::setIconSize(const QSize &iconSize)
741 {
742 Q_D(QToolBar);
743 QSize sz = iconSize;
744 if (!sz.isValid()) {
745 QMainWindow *mw = qobject_cast<QMainWindow *>(parentWidget());
746 if (mw && mw->layout()) {
747 QLayout *layout = mw->layout();
748 int i = 0;
749 QLayoutItem *item = 0;
750 do {
751 item = layout->itemAt(i++);
752 if (item && (item->widget() == this))
753 sz = mw->iconSize();
754 } while (!sz.isValid() && item != 0);
755 }
756 }
757 if (!sz.isValid()) {
758 const int metric = style()->pixelMetric(QStyle::PM_ToolBarIconSize, 0, this);
759 sz = QSize(metric, metric);
760 }
761 if (d->iconSize != sz) {
762 d->iconSize = sz;
763 setMinimumSize(0, 0);
764 emit iconSizeChanged(d->iconSize);
765 }
766 d->explicitIconSize = iconSize.isValid();
767
768 d->layout->invalidate();
769 }
770
771 /*!
772 \property QToolBar::toolButtonStyle
773 \brief the style of toolbar buttons
774
775 This property defines the style of all tool buttons that are added
776 as \l{QAction}s. Note that if you add a QToolButton with the
777 addWidget() method, it will not get this button style.
778
779 The default is Qt::ToolButtonIconOnly.
780 */
781
toolButtonStyle() const782 Qt::ToolButtonStyle QToolBar::toolButtonStyle() const
783 { Q_D(const QToolBar); return d->toolButtonStyle; }
784
setToolButtonStyle(Qt::ToolButtonStyle toolButtonStyle)785 void QToolBar::setToolButtonStyle(Qt::ToolButtonStyle toolButtonStyle)
786 {
787 Q_D(QToolBar);
788 d->explicitToolButtonStyle = true;
789 if (d->toolButtonStyle == toolButtonStyle)
790 return;
791 d->toolButtonStyle = toolButtonStyle;
792 setMinimumSize(0, 0);
793 emit toolButtonStyleChanged(d->toolButtonStyle);
794 }
795
796 /*!
797 Removes all actions from the toolbar.
798
799 \sa removeAction()
800 */
clear()801 void QToolBar::clear()
802 {
803 QList<QAction *> actions = this->actions();
804 for(int i = 0; i < actions.size(); i++)
805 removeAction(actions.at(i));
806 }
807
808 /*!
809 \overload
810
811 Creates a new action with the given \a text. This action is added to
812 the end of the toolbar.
813 */
addAction(const QString & text)814 QAction *QToolBar::addAction(const QString &text)
815 {
816 QAction *action = new QAction(text, this);
817 addAction(action);
818 return action;
819 }
820
821 /*!
822 \overload
823
824 Creates a new action with the given \a icon and \a text. This
825 action is added to the end of the toolbar.
826 */
addAction(const QIcon & icon,const QString & text)827 QAction *QToolBar::addAction(const QIcon &icon, const QString &text)
828 {
829 QAction *action = new QAction(icon, text, this);
830 addAction(action);
831 return action;
832 }
833
834 /*!
835 \overload
836
837 Creates a new action with the given \a text. This action is added to
838 the end of the toolbar. The action's \link QAction::triggered()
839 triggered()\endlink signal is connected to \a member in \a
840 receiver.
841 */
addAction(const QString & text,const QObject * receiver,const char * member)842 QAction *QToolBar::addAction(const QString &text,
843 const QObject *receiver, const char* member)
844 {
845 QAction *action = new QAction(text, this);
846 QObject::connect(action, SIGNAL(triggered(bool)), receiver, member);
847 addAction(action);
848 return action;
849 }
850
851 /*!
852 \overload
853
854 Creates a new action with the icon \a icon and text \a text. This
855 action is added to the end of the toolbar. The action's \link
856 QAction::triggered() triggered()\endlink signal is connected to \a
857 member in \a receiver.
858 */
addAction(const QIcon & icon,const QString & text,const QObject * receiver,const char * member)859 QAction *QToolBar::addAction(const QIcon &icon, const QString &text,
860 const QObject *receiver, const char* member)
861 {
862 QAction *action = new QAction(icon, text, this);
863 QObject::connect(action, SIGNAL(triggered(bool)), receiver, member);
864 addAction(action);
865 return action;
866 }
867
868 /*!
869 Adds a separator to the end of the toolbar.
870
871 \sa insertSeparator()
872 */
addSeparator()873 QAction *QToolBar::addSeparator()
874 {
875 QAction *action = new QAction(this);
876 action->setSeparator(true);
877 addAction(action);
878 return action;
879 }
880
881 /*!
882 Inserts a separator into the toolbar in front of the toolbar
883 item associated with the \a before action.
884
885 \sa addSeparator()
886 */
insertSeparator(QAction * before)887 QAction *QToolBar::insertSeparator(QAction *before)
888 {
889 QAction *action = new QAction(this);
890 action->setSeparator(true);
891 insertAction(before, action);
892 return action;
893 }
894
895 /*!
896 Adds the given \a widget to the toolbar as the toolbar's last
897 item.
898
899 The toolbar takes ownership of \a widget.
900
901 If you add a QToolButton with this method, the tools bar's
902 Qt::ToolButtonStyle will not be respected.
903
904 \note You should use QAction::setVisible() to change the
905 visibility of the widget. Using QWidget::setVisible(),
906 QWidget::show() and QWidget::hide() does not work.
907
908 \sa insertWidget()
909 */
addWidget(QWidget * widget)910 QAction *QToolBar::addWidget(QWidget *widget)
911 {
912 QWidgetAction *action = new QWidgetAction(this);
913 action->setDefaultWidget(widget);
914 action->d_func()->autoCreated = true;
915 addAction(action);
916 return action;
917 }
918
919 /*!
920 Inserts the given \a widget in front of the toolbar item
921 associated with the \a before action.
922
923 Note: You should use QAction::setVisible() to change the
924 visibility of the widget. Using QWidget::setVisible(),
925 QWidget::show() and QWidget::hide() does not work.
926
927 \sa addWidget()
928 */
insertWidget(QAction * before,QWidget * widget)929 QAction *QToolBar::insertWidget(QAction *before, QWidget *widget)
930 {
931 QWidgetAction *action = new QWidgetAction(this);
932 action->setDefaultWidget(widget);
933 action->d_func()->autoCreated = true;
934 insertAction(before, action);
935 return action;
936 }
937
938 /*!
939 \internal
940
941 Returns the geometry of the toolbar item associated with the given
942 \a action, or an invalid QRect if no matching item is found.
943 */
actionGeometry(QAction * action) const944 QRect QToolBar::actionGeometry(QAction *action) const
945 {
946 Q_D(const QToolBar);
947
948 int index = d->layout->indexOf(action);
949 if (index == -1)
950 return QRect();
951 return d->layout->itemAt(index)->widget()->geometry();
952 }
953
954 /*!
955 Returns the action at point \a p. This function returns zero if no
956 action was found.
957
958 \sa QWidget::childAt()
959 */
actionAt(const QPoint & p) const960 QAction *QToolBar::actionAt(const QPoint &p) const
961 {
962 Q_D(const QToolBar);
963 QWidget *widget = childAt(p);
964 int index = d->layout->indexOf(widget);
965 if (index == -1)
966 return 0;
967 QLayoutItem *item = d->layout->itemAt(index);
968 return static_cast<QToolBarItem*>(item)->action;
969 }
970
971 /*! \fn QAction *QToolBar::actionAt(int x, int y) const
972 \overload
973
974 Returns the action at the point \a x, \a y. This function returns
975 zero if no action was found.
976 */
977
978 /*! \reimp */
actionEvent(QActionEvent * event)979 void QToolBar::actionEvent(QActionEvent *event)
980 {
981 Q_D(QToolBar);
982 QAction *action = event->action();
983 QWidgetAction *widgetAction = qobject_cast<QWidgetAction *>(action);
984
985 switch (event->type()) {
986 case QEvent::ActionAdded: {
987 Q_ASSERT_X(widgetAction == 0 || d->layout->indexOf(widgetAction) == -1,
988 "QToolBar", "widgets cannot be inserted multiple times");
989
990 // reparent the action to this toolbar if it has been created
991 // using the addAction(text) etc. convenience functions, to
992 // preserve Qt 4.1.x behavior. The widget is already
993 // reparented to us due to the createWidget call inside
994 // createItem()
995 if (widgetAction != 0 && widgetAction->d_func()->autoCreated)
996 widgetAction->setParent(this);
997
998 int index = d->layout->count();
999 if (event->before()) {
1000 index = d->layout->indexOf(event->before());
1001 Q_ASSERT_X(index != -1, "QToolBar::insertAction", "internal error");
1002 }
1003 d->layout->insertAction(index, action);
1004 break;
1005 }
1006
1007 case QEvent::ActionChanged:
1008 d->layout->invalidate();
1009 break;
1010
1011 case QEvent::ActionRemoved: {
1012 int index = d->layout->indexOf(action);
1013 if (index != -1) {
1014 delete d->layout->takeAt(index);
1015 }
1016 break;
1017 }
1018
1019 default:
1020 Q_ASSERT_X(false, "QToolBar::actionEvent", "internal error");
1021 }
1022 }
1023
1024 /*! \reimp */
changeEvent(QEvent * event)1025 void QToolBar::changeEvent(QEvent *event)
1026 {
1027 Q_D(QToolBar);
1028 switch (event->type()) {
1029 case QEvent::WindowTitleChange:
1030 d->toggleViewAction->setText(windowTitle());
1031 break;
1032 case QEvent::StyleChange:
1033 d->layout->invalidate();
1034 if (!d->explicitIconSize)
1035 setIconSize(QSize());
1036 d->layout->updateMarginAndSpacing();
1037 break;
1038 case QEvent::LayoutDirectionChange:
1039 d->layout->invalidate();
1040 break;
1041 default:
1042 break;
1043 }
1044 QWidget::changeEvent(event);
1045 }
1046
1047 /*! \reimp */
paintEvent(QPaintEvent *)1048 void QToolBar::paintEvent(QPaintEvent *)
1049 {
1050 Q_D(QToolBar);
1051
1052 QPainter p(this);
1053 QStyle *style = this->style();
1054 QStyleOptionToolBar opt;
1055 initStyleOption(&opt);
1056
1057 if (d->layout->expanded || d->layout->animating || isWindow()) {
1058 //if the toolbar is expended, we need to fill the background with the window color
1059 //because some styles may expects that.
1060 p.fillRect(opt.rect, palette().background());
1061 style->drawControl(QStyle::CE_ToolBar, &opt, &p, this);
1062 style->drawPrimitive(QStyle::PE_FrameMenu, &opt, &p, this);
1063 } else {
1064 style->drawControl(QStyle::CE_ToolBar, &opt, &p, this);
1065 }
1066
1067 opt.rect = style->subElementRect(QStyle::SE_ToolBarHandle, &opt, this);
1068 if (opt.rect.isValid())
1069 style->drawPrimitive(QStyle::PE_IndicatorToolBarHandle, &opt, &p, this);
1070 }
1071
1072 /*
1073 Checks if an expanded toolbar has to wait for this popup to close before
1074 the toolbar collapses. This is true if
1075 1) the popup has the toolbar in its parent chain,
1076 2) the popup is a menu whose menuAction is somewhere in the toolbar.
1077 */
waitForPopup(QToolBar * tb,QWidget * popup)1078 static bool waitForPopup(QToolBar *tb, QWidget *popup)
1079 {
1080 if (popup == 0 || popup->isHidden())
1081 return false;
1082
1083 QWidget *w = popup;
1084 while (w != 0) {
1085 if (w == tb)
1086 return true;
1087 w = w->parentWidget();
1088 }
1089
1090 QMenu *menu = qobject_cast<QMenu*>(popup);
1091 if (menu == 0)
1092 return false;
1093
1094 QAction *action = menu->menuAction();
1095 QList<QWidget*> widgets = action->associatedWidgets();
1096 for (int i = 0; i < widgets.count(); ++i) {
1097 if (waitForPopup(tb, widgets.at(i)))
1098 return true;
1099 }
1100
1101 return false;
1102 }
1103
1104 #if defined(Q_WS_MAC)
toolbarInUnifiedToolBar(QToolBar * toolbar)1105 static bool toolbarInUnifiedToolBar(QToolBar *toolbar)
1106 {
1107 const QMainWindow *mainWindow = qobject_cast<const QMainWindow *>(toolbar->parentWidget());
1108 return mainWindow && mainWindow->unifiedTitleAndToolBarOnMac()
1109 && mainWindow->toolBarArea(toolbar) == Qt::TopToolBarArea;
1110 }
1111 #endif
1112
1113 /*! \reimp */
event(QEvent * event)1114 bool QToolBar::event(QEvent *event)
1115 {
1116 Q_D(QToolBar);
1117
1118 switch (event->type()) {
1119 case QEvent::Timer:
1120 if (d->waitForPopupTimer.timerId() == static_cast<QTimerEvent*>(event)->timerId()) {
1121 QWidget *w = QApplication::activePopupWidget();
1122 if (!waitForPopup(this, w)) {
1123 d->waitForPopupTimer.stop();
1124 if (!this->underMouse())
1125 d->layout->setExpanded(false);
1126 }
1127 }
1128 break;
1129 case QEvent::Hide:
1130 if (!isHidden())
1131 break;
1132 // fallthrough intended
1133 case QEvent::Show:
1134 d->toggleViewAction->setChecked(event->type() == QEvent::Show);
1135 emit visibilityChanged(event->type() == QEvent::Show);
1136 #if defined(Q_WS_MAC)
1137 if (toolbarInUnifiedToolBar(this)) {
1138 // I can static_cast because I did the qobject_cast in the if above, therefore
1139 // we must have a QMainWindowLayout here.
1140 QMainWindowLayout *mwLayout = qt_mainwindow_layout(qobject_cast<QMainWindow *>(parentWidget()));
1141 mwLayout->fixSizeInUnifiedToolbar(this);
1142 mwLayout->syncUnifiedToolbarVisibility();
1143 }
1144 # if !defined(QT_MAC_USE_COCOA)
1145 // Fall through
1146 case QEvent::LayoutRequest: {
1147 // There's currently no way to invalidate the size and let
1148 // HIToolbar know about it. This forces a re-check.
1149 int earlyResult = -1;
1150 if (QMainWindow *mainWindow = qobject_cast<QMainWindow *>(parentWidget())) {
1151 bool needUpdate = true;
1152 if (event->type() == QEvent::LayoutRequest) {
1153 QSize oldSizeHint = sizeHint();
1154 earlyResult = QWidget::event(event) ? 1 : 0;
1155 needUpdate = oldSizeHint != sizeHint();
1156 }
1157
1158 if (needUpdate) {
1159 OSWindowRef windowRef = qt_mac_window_for(mainWindow);
1160 if (toolbarInUnifiedToolBar(this)
1161 && macWindowToolbarIsVisible(windowRef)) {
1162 DisableScreenUpdates();
1163 macWindowToolbarShow(this, false);
1164 macWindowToolbarShow(this, true);
1165 EnableScreenUpdates();
1166 }
1167 }
1168
1169 if (earlyResult != -1)
1170 return earlyResult;
1171 }
1172 }
1173 # endif // !QT_MAC_USE_COCOA
1174 #endif // Q_WS_MAC
1175 break;
1176 case QEvent::ParentChange:
1177 d->layout->checkUsePopupMenu();
1178 #if defined(Q_WS_MAC)
1179 if (parentWidget() && parentWidget()->isWindow())
1180 qt_mac_updateToolBarButtonHint(parentWidget());
1181 #endif
1182 break;
1183
1184 case QEvent::MouseButtonPress: {
1185 if (d->mousePressEvent(static_cast<QMouseEvent*>(event)))
1186 return true;
1187 break;
1188 }
1189 case QEvent::MouseButtonRelease:
1190 if (d->mouseReleaseEvent(static_cast<QMouseEvent*>(event)))
1191 return true;
1192 break;
1193 case QEvent::HoverEnter:
1194 case QEvent::HoverLeave:
1195 // there's nothing special to do here and we don't want to update the whole widget
1196 return true;
1197 case QEvent::HoverMove: {
1198 #ifndef QT_NO_CURSOR
1199 QHoverEvent *e = static_cast<QHoverEvent*>(event);
1200 QStyleOptionToolBar opt;
1201 initStyleOption(&opt);
1202 if (style()->subElementRect(QStyle::SE_ToolBarHandle, &opt, this).contains(e->pos()))
1203 setCursor(Qt::SizeAllCursor);
1204 else
1205 unsetCursor();
1206 #endif
1207 break;
1208 }
1209 case QEvent::MouseMove:
1210 if (d->mouseMoveEvent(static_cast<QMouseEvent*>(event)))
1211 return true;
1212 break;
1213 #ifdef Q_WS_WINCE
1214 case QEvent::ContextMenu:
1215 {
1216 QContextMenuEvent* contextMenuEvent = static_cast<QContextMenuEvent*>(event);
1217 QWidget* child = childAt(contextMenuEvent->pos());
1218 QAbstractButton* button = qobject_cast<QAbstractButton*>(child);
1219 if (button)
1220 button->setDown(false);
1221 }
1222 break;
1223 #endif
1224 case QEvent::Leave:
1225 if (d->state != 0 && d->state->dragging) {
1226 #ifdef Q_OS_WIN
1227 // This is a workaround for loosing the mouse on Vista.
1228 QPoint pos = QCursor::pos();
1229 QMouseEvent fake(QEvent::MouseMove, mapFromGlobal(pos), pos, Qt::NoButton,
1230 QApplication::mouseButtons(), QApplication::keyboardModifiers());
1231 d->mouseMoveEvent(&fake);
1232 #endif
1233 } else {
1234 if (!d->layout->expanded)
1235 break;
1236
1237 QWidget *w = QApplication::activePopupWidget();
1238 if (waitForPopup(this, w)) {
1239 d->waitForPopupTimer.start(POPUP_TIMER_INTERVAL, this);
1240 break;
1241 }
1242
1243 d->waitForPopupTimer.stop();
1244 d->layout->setExpanded(false);
1245 break;
1246 }
1247 default:
1248 break;
1249 }
1250 return QWidget::event(event);
1251 }
1252
1253 /*!
1254 Returns a checkable action that can be used to show or hide this
1255 toolbar.
1256
1257 The action's text is set to the toolbar's window title.
1258
1259 \sa QAction::text QWidget::windowTitle
1260 */
toggleViewAction() const1261 QAction *QToolBar::toggleViewAction() const
1262 { Q_D(const QToolBar); return d->toggleViewAction; }
1263
1264 /*!
1265 \fn void QToolBar::setLabel(const QString &label)
1266
1267 Use setWindowTitle() instead.
1268 */
1269
1270 /*!
1271 \fn QString QToolBar::label() const
1272
1273 Use windowTitle() instead.
1274 */
1275
1276 /*!
1277 \since 4.2
1278
1279 Returns the widget associated with the specified \a action.
1280
1281 \sa addWidget()
1282 */
widgetForAction(QAction * action) const1283 QWidget *QToolBar::widgetForAction(QAction *action) const
1284 {
1285 Q_D(const QToolBar);
1286
1287 int index = d->layout->indexOf(action);
1288 if (index == -1)
1289 return 0;
1290
1291 return d->layout->itemAt(index)->widget();
1292 }
1293
1294 extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *window);
1295
1296 /*!
1297 \internal
1298 */
initStyleOption(QStyleOptionToolBar * option) const1299 void QToolBar::initStyleOption(QStyleOptionToolBar *option) const
1300 {
1301 Q_D(const QToolBar);
1302
1303 if (!option)
1304 return;
1305
1306 option->initFrom(this);
1307 if (orientation() == Qt::Horizontal)
1308 option->state |= QStyle::State_Horizontal;
1309 option->lineWidth = style()->pixelMetric(QStyle::PM_ToolBarFrameWidth, 0, this);
1310 option->features = d->layout->movable()
1311 ? QStyleOptionToolBar::Movable
1312 : QStyleOptionToolBar::None;
1313 // if the tool bar is not in a QMainWindow, this will make the painting right
1314 option->toolBarArea = Qt::NoToolBarArea;
1315
1316 // Add more styleoptions if the toolbar has been added to a mainwindow.
1317 QMainWindow *mainWindow = qobject_cast<QMainWindow *>(parentWidget());
1318
1319 if (!mainWindow)
1320 return;
1321
1322 QMainWindowLayout *layout = qt_mainwindow_layout(mainWindow);
1323 Q_ASSERT_X(layout != 0, "QToolBar::initStyleOption()",
1324 "QMainWindow->layout() != QMainWindowLayout");
1325
1326 layout->getStyleOptionInfo(option, const_cast<QToolBar *>(this));
1327 }
1328
1329 /*!
1330 \reimp
1331 */
childEvent(QChildEvent * event)1332 void QToolBar::childEvent(QChildEvent *event) // ### remove me in 5.0
1333 {
1334 QWidget::childEvent(event);
1335 }
1336
1337 /*!
1338 \reimp
1339 */
resizeEvent(QResizeEvent * event)1340 void QToolBar::resizeEvent(QResizeEvent *event) // ### remove me in 5.0
1341 {
1342 QWidget::resizeEvent(event);
1343 }
1344
1345 QT_END_NAMESPACE
1346
1347 #include "moc_qtoolbar.cpp"
1348
1349 #endif // QT_NO_TOOLBAR
1350