source: trunk/src/gui/widgets/qtoolbar.cpp@ 769

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

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

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