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

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

trunk: Merged in qt 4.6.2 sources.

File size: 37.2 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. This is a known
445 issue which will be fixed in a future release.
446
447 \sa QToolButton, QMenu, QAction, {Application Example}
448*/
449
450/*!
451 \fn bool QToolBar::isAreaAllowed(Qt::ToolBarArea area) const
452
453 Returns true if this toolbar is dockable in the given \a area;
454 otherwise returns false.
455*/
456
457/*!
458 \fn void QToolBar::addAction(QAction *action)
459 \overload
460
461 Appends the action \a action to the toolbar's list of actions.
462
463 \sa QMenu::addAction(), QWidget::addAction()
464*/
465
466/*!
467 \fn void QToolBar::actionTriggered(QAction *action)
468
469 This signal is emitted when an action in this toolbar is triggered.
470 This happens when the action's tool button is pressed, or when the
471 action is triggered in some other way outside the tool bar. The parameter
472 holds the triggered \a action.
473*/
474
475/*!
476 \fn void QToolBar::allowedAreasChanged(Qt::ToolBarAreas allowedAreas)
477
478 This signal is emitted when the collection of allowed areas for the
479 toolbar is changed. The new areas in which the toolbar can be positioned
480 are specified by \a allowedAreas.
481
482 \sa allowedAreas
483*/
484
485/*!
486 \fn void QToolBar::iconSizeChanged(const QSize &iconSize)
487
488 This signal is emitted when the icon size is changed. The \a
489 iconSize parameter holds the toolbar's new icon size.
490
491 \sa iconSize QMainWindow::iconSize
492*/
493
494/*!
495 \fn void QToolBar::movableChanged(bool movable)
496
497 This signal is emitted when the toolbar becomes movable or fixed.
498 If the toolbar can be moved, \a movable is true; otherwise it is
499 false.
500
501 \sa movable
502*/
503
504/*!
505 \fn void QToolBar::orientationChanged(Qt::Orientation orientation)
506
507 This signal is emitted when the orientation of the toolbar changes.
508 The new orientation is specified by the \a orientation given.
509
510 \sa orientation
511*/
512
513/*!
514 \fn void QToolBar::toolButtonStyleChanged(Qt::ToolButtonStyle toolButtonStyle)
515
516 This signal is emitted when the tool button style is changed. The
517 \a toolButtonStyle parameter holds the toolbar's new tool button
518 style.
519
520 \sa toolButtonStyle QMainWindow::toolButtonStyle
521*/
522
523/*!
524 \since 4.6
525
526 \fn void QToolBar::topLevelChanged(bool topLevel)
527
528 This signal is emitted when the \l floating property changes.
529 The \a topLevel parameter is true if the toolbar is now floating;
530 otherwise it is false.
531
532 \sa isWindow()
533*/
534
535
536/*!
537 Constructs a QToolBar with the given \a parent.
538*/
539QToolBar::QToolBar(QWidget *parent)
540 : QWidget(*new QToolBarPrivate, parent, 0)
541{
542 Q_D(QToolBar);
543 d->init();
544}
545
546/*!
547 Constructs a QToolBar with the given \a parent.
548
549 The given window \a title identifies the toolbar and is shown in
550 the context menu provided by QMainWindow.
551
552 \sa setWindowTitle()
553*/
554QToolBar::QToolBar(const QString &title, QWidget *parent)
555 : QWidget(*new QToolBarPrivate, parent, 0)
556{
557 Q_D(QToolBar);
558 d->init();
559 setWindowTitle(title);
560}
561
562#ifdef QT3_SUPPORT
563/*! \obsolete
564 Constructs a QToolBar with the given \a parent and \a name.
565*/
566QToolBar::QToolBar(QWidget *parent, const char *name)
567 : QWidget(*new QToolBarPrivate, parent, 0)
568{
569 Q_D(QToolBar);
570 d->init();
571 setObjectName(QString::fromAscii(name));
572}
573#endif
574
575/*!
576 Destroys the toolbar.
577*/
578QToolBar::~QToolBar()
579{
580 // Remove the toolbar button if there is nothing left.
581 QMainWindow *mainwindow = qobject_cast<QMainWindow *>(parentWidget());
582 if (mainwindow) {
583#ifdef Q_WS_MAC
584 QMainWindowLayout *mainwin_layout = qobject_cast<QMainWindowLayout *>(mainwindow->layout());
585 if (mainwin_layout && mainwin_layout->layoutState.toolBarAreaLayout.isEmpty()
586 && mainwindow->testAttribute(Qt::WA_WState_Created))
587 macWindowToolbarShow(mainwindow, false);
588#endif
589 }
590}
591
592/*! \property QToolBar::movable
593 \brief whether the user can move the toolbar within the toolbar area,
594 or between toolbar areas
595
596 By default, this property is true.
597
598 This property only makes sense if the toolbar is in a
599 QMainWindow.
600
601 \sa allowedAreas
602*/
603
604void QToolBar::setMovable(bool movable)
605{
606 Q_D(QToolBar);
607 if (!movable == !d->movable)
608 return;
609 d->movable = movable;
610 d->layout->invalidate();
611 emit movableChanged(d->movable);
612}
613
614bool QToolBar::isMovable() const
615{
616 Q_D(const QToolBar);
617 return d->movable;
618}
619
620/*!
621 \property QToolBar::floatable
622 \brief whether the toolbar can be dragged and dropped as an independent window.
623
624 The default is true.
625*/
626bool QToolBar::isFloatable() const
627{
628 Q_D(const QToolBar);
629 return d->floatable;
630}
631
632void QToolBar::setFloatable(bool floatable)
633{
634 Q_D(QToolBar);
635 d->floatable = floatable;
636}
637
638/*!
639 \property QToolBar::floating
640 \brief whether the toolbar is an independent window.
641
642 By default, this property is true.
643
644 \sa QWidget::isWindow()
645*/
646bool QToolBar::isFloating() const
647{
648 return isWindow();
649}
650
651/*!
652 \property QToolBar::allowedAreas
653 \brief areas where the toolbar may be placed
654
655 The default is Qt::AllToolBarAreas.
656
657 This property only makes sense if the toolbar is in a
658 QMainWindow.
659
660 \sa movable
661*/
662
663void QToolBar::setAllowedAreas(Qt::ToolBarAreas areas)
664{
665 Q_D(QToolBar);
666 areas &= Qt::ToolBarArea_Mask;
667 if (areas == d->allowedAreas)
668 return;
669 d->allowedAreas = areas;
670 emit allowedAreasChanged(d->allowedAreas);
671}
672
673Qt::ToolBarAreas QToolBar::allowedAreas() const
674{
675 Q_D(const QToolBar);
676#ifdef Q_WS_MAC
677 if (QMainWindow *window = qobject_cast<QMainWindow *>(parentWidget())) {
678 if (window->unifiedTitleAndToolBarOnMac()) // Don't allow drags to the top (for now).
679 return (d->allowedAreas & ~Qt::TopToolBarArea);
680 }
681#endif
682 return d->allowedAreas;
683}
684
685/*! \property QToolBar::orientation
686 \brief orientation of the toolbar
687
688 The default is Qt::Horizontal.
689
690 This function should not be used when the toolbar is managed
691 by QMainWindow. You can use QMainWindow::addToolBar() or
692 QMainWindow::insertToolBar() if you wish to move a toolbar (that
693 is already added to a main window) to another Qt::ToolBarArea.
694*/
695
696void QToolBar::setOrientation(Qt::Orientation orientation)
697{
698 Q_D(QToolBar);
699 if (orientation == d->orientation)
700 return;
701
702 d->orientation = orientation;
703
704 if (orientation == Qt::Vertical)
705 setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred));
706 else
707 setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
708
709 d->layout->invalidate();
710 d->layout->activate();
711
712 emit orientationChanged(d->orientation);
713}
714
715Qt::Orientation QToolBar::orientation() const
716{ Q_D(const QToolBar); return d->orientation; }
717
718/*!
719 \property QToolBar::iconSize
720 \brief size of icons in the toolbar.
721
722 The default size is determined by the application's style and is
723 derived from the QStyle::PM_ToolBarIconSize pixel metric. It is
724 the maximum size an icon can have. Icons of smaller size will not
725 be scaled up.
726*/
727
728QSize QToolBar::iconSize() const
729{ Q_D(const QToolBar); return d->iconSize; }
730
731void QToolBar::setIconSize(const QSize &iconSize)
732{
733 Q_D(QToolBar);
734 QSize sz = iconSize;
735 if (!sz.isValid()) {
736 QMainWindow *mw = qobject_cast<QMainWindow *>(parentWidget());
737 if (mw && mw->layout()) {
738 QLayout *layout = mw->layout();
739 int i = 0;
740 QLayoutItem *item = 0;
741 do {
742 item = layout->itemAt(i++);
743 if (item && (item->widget() == this))
744 sz = mw->iconSize();
745 } while (!sz.isValid() && item != 0);
746 }
747 }
748 if (!sz.isValid()) {
749 const int metric = style()->pixelMetric(QStyle::PM_ToolBarIconSize, 0, this);
750 sz = QSize(metric, metric);
751 }
752 if (d->iconSize != sz) {
753 d->iconSize = sz;
754 setMinimumSize(0, 0);
755 emit iconSizeChanged(d->iconSize);
756 }
757 d->explicitIconSize = iconSize.isValid();
758
759 d->layout->invalidate();
760}
761
762/*!
763 \property QToolBar::toolButtonStyle
764 \brief the style of toolbar buttons
765
766 This property defines the style of all tool buttons that are added
767 as \l{QAction}s. Note that if you add a QToolButton with the
768 addWidget() method, it will not get this button style.
769
770 The default is Qt::ToolButtonIconOnly.
771*/
772
773Qt::ToolButtonStyle QToolBar::toolButtonStyle() const
774{ Q_D(const QToolBar); return d->toolButtonStyle; }
775
776void QToolBar::setToolButtonStyle(Qt::ToolButtonStyle toolButtonStyle)
777{
778 Q_D(QToolBar);
779 d->explicitToolButtonStyle = true;
780 if (d->toolButtonStyle == toolButtonStyle)
781 return;
782 d->toolButtonStyle = toolButtonStyle;
783 setMinimumSize(0, 0);
784 emit toolButtonStyleChanged(d->toolButtonStyle);
785}
786
787/*!
788 Removes all actions from the toolbar.
789
790 \sa removeAction()
791*/
792void QToolBar::clear()
793{
794 QList<QAction *> actions = this->actions();
795 for(int i = 0; i < actions.size(); i++)
796 removeAction(actions.at(i));
797}
798
799/*!
800 \overload
801
802 Creates a new action with the given \a text. This action is added to
803 the end of the toolbar.
804*/
805QAction *QToolBar::addAction(const QString &text)
806{
807 QAction *action = new QAction(text, this);
808 addAction(action);
809 return action;
810}
811
812/*!
813 \overload
814
815 Creates a new action with the given \a icon and \a text. This
816 action is added to the end of the toolbar.
817*/
818QAction *QToolBar::addAction(const QIcon &icon, const QString &text)
819{
820 QAction *action = new QAction(icon, text, this);
821 addAction(action);
822 return action;
823}
824
825/*!
826 \overload
827
828 Creates a new action with the given \a text. This action is added to
829 the end of the toolbar. The action's \link QAction::triggered()
830 triggered()\endlink signal is connected to \a member in \a
831 receiver.
832*/
833QAction *QToolBar::addAction(const QString &text,
834 const QObject *receiver, const char* member)
835{
836 QAction *action = new QAction(text, this);
837 QObject::connect(action, SIGNAL(triggered(bool)), receiver, member);
838 addAction(action);
839 return action;
840}
841
842/*!
843 \overload
844
845 Creates a new action with the icon \a icon and text \a text. This
846 action is added to the end of the toolbar. The action's \link
847 QAction::triggered() triggered()\endlink signal is connected to \a
848 member in \a receiver.
849*/
850QAction *QToolBar::addAction(const QIcon &icon, const QString &text,
851 const QObject *receiver, const char* member)
852{
853 QAction *action = new QAction(icon, text, this);
854 QObject::connect(action, SIGNAL(triggered(bool)), receiver, member);
855 addAction(action);
856 return action;
857}
858
859/*!
860 Adds a separator to the end of the toolbar.
861
862 \sa insertSeparator()
863*/
864QAction *QToolBar::addSeparator()
865{
866 QAction *action = new QAction(this);
867 action->setSeparator(true);
868 addAction(action);
869 return action;
870}
871
872/*!
873 Inserts a separator into the toolbar in front of the toolbar
874 item associated with the \a before action.
875
876 \sa addSeparator()
877*/
878QAction *QToolBar::insertSeparator(QAction *before)
879{
880 QAction *action = new QAction(this);
881 action->setSeparator(true);
882 insertAction(before, action);
883 return action;
884}
885
886/*!
887 Adds the given \a widget to the toolbar as the toolbar's last
888 item.
889
890 The toolbar takes ownership of \a widget.
891
892 If you add a QToolButton with this method, the tools bar's
893 Qt::ToolButtonStyle will not be respected.
894
895 \note You should use QAction::setVisible() to change the
896 visibility of the widget. Using QWidget::setVisible(),
897 QWidget::show() and QWidget::hide() does not work.
898
899 \sa insertWidget()
900*/
901QAction *QToolBar::addWidget(QWidget *widget)
902{
903 QWidgetAction *action = new QWidgetAction(this);
904 action->setDefaultWidget(widget);
905 action->d_func()->autoCreated = true;
906 addAction(action);
907 return action;
908}
909
910/*!
911 Inserts the given \a widget in front of the toolbar item
912 associated with the \a before action.
913
914 Note: You should use QAction::setVisible() to change the
915 visibility of the widget. Using QWidget::setVisible(),
916 QWidget::show() and QWidget::hide() does not work.
917
918 \sa addWidget()
919*/
920QAction *QToolBar::insertWidget(QAction *before, QWidget *widget)
921{
922 QWidgetAction *action = new QWidgetAction(this);
923 action->setDefaultWidget(widget);
924 action->d_func()->autoCreated = true;
925 insertAction(before, action);
926 return action;
927}
928
929/*!
930 \internal
931
932 Returns the geometry of the toolbar item associated with the given
933 \a action, or an invalid QRect if no matching item is found.
934*/
935QRect QToolBar::actionGeometry(QAction *action) const
936{
937 Q_D(const QToolBar);
938
939 int index = d->layout->indexOf(action);
940 if (index == -1)
941 return QRect();
942 return d->layout->itemAt(index)->widget()->geometry();
943}
944
945/*!
946 Returns the action at point \a p. This function returns zero if no
947 action was found.
948
949 \sa QWidget::childAt()
950*/
951QAction *QToolBar::actionAt(const QPoint &p) const
952{
953 Q_D(const QToolBar);
954 QWidget *widget = childAt(p);
955 int index = d->layout->indexOf(widget);
956 if (index == -1)
957 return 0;
958 QLayoutItem *item = d->layout->itemAt(index);
959 return static_cast<QToolBarItem*>(item)->action;
960}
961
962/*! \fn QAction *QToolBar::actionAt(int x, int y) const
963 \overload
964
965 Returns the action at the point \a x, \a y. This function returns
966 zero if no action was found.
967*/
968
969/*! \reimp */
970void QToolBar::actionEvent(QActionEvent *event)
971{
972 Q_D(QToolBar);
973 QAction *action = event->action();
974 QWidgetAction *widgetAction = qobject_cast<QWidgetAction *>(action);
975
976 switch (event->type()) {
977 case QEvent::ActionAdded: {
978 Q_ASSERT_X(widgetAction == 0 || d->layout->indexOf(widgetAction) == -1,
979 "QToolBar", "widgets cannot be inserted multiple times");
980
981 // reparent the action to this toolbar if it has been created
982 // using the addAction(text) etc. convenience functions, to
983 // preserve Qt 4.1.x behavior. The widget is already
984 // reparented to us due to the createWidget call inside
985 // createItem()
986 if (widgetAction != 0 && widgetAction->d_func()->autoCreated)
987 widgetAction->setParent(this);
988
989 int index = d->layout->count();
990 if (event->before()) {
991 index = d->layout->indexOf(event->before());
992 Q_ASSERT_X(index != -1, "QToolBar::insertAction", "internal error");
993 }
994 d->layout->insertAction(index, action);
995 break;
996 }
997
998 case QEvent::ActionChanged:
999 d->layout->invalidate();
1000 break;
1001
1002 case QEvent::ActionRemoved: {
1003 int index = d->layout->indexOf(action);
1004 if (index != -1) {
1005 delete d->layout->takeAt(index);
1006 }
1007 break;
1008 }
1009
1010 default:
1011 Q_ASSERT_X(false, "QToolBar::actionEvent", "internal error");
1012 }
1013}
1014
1015/*! \reimp */
1016void QToolBar::changeEvent(QEvent *event)
1017{
1018 Q_D(QToolBar);
1019 switch (event->type()) {
1020 case QEvent::WindowTitleChange:
1021 d->toggleViewAction->setText(windowTitle());
1022 break;
1023 case QEvent::StyleChange:
1024 d->layout->invalidate();
1025 if (!d->explicitIconSize)
1026 setIconSize(QSize());
1027 d->layout->updateMarginAndSpacing();
1028 break;
1029 case QEvent::LayoutDirectionChange:
1030 d->layout->invalidate();
1031 break;
1032 default:
1033 break;
1034 }
1035 QWidget::changeEvent(event);
1036}
1037
1038/*! \reimp */
1039void QToolBar::paintEvent(QPaintEvent *)
1040{
1041 Q_D(QToolBar);
1042
1043 QPainter p(this);
1044 QStyle *style = this->style();
1045 QStyleOptionToolBar opt;
1046 initStyleOption(&opt);
1047
1048 if (d->layout->expanded || d->layout->animating || isWindow()) {
1049 //if the toolbar is expended, we need to fill the background with the window color
1050 //because some styles may expects that.
1051 p.fillRect(opt.rect, palette().background());
1052 style->drawControl(QStyle::CE_ToolBar, &opt, &p, this);
1053 style->drawPrimitive(QStyle::PE_FrameMenu, &opt, &p, this);
1054 } else {
1055 style->drawControl(QStyle::CE_ToolBar, &opt, &p, this);
1056 }
1057
1058 opt.rect = style->subElementRect(QStyle::SE_ToolBarHandle, &opt, this);
1059 if (opt.rect.isValid())
1060 style->drawPrimitive(QStyle::PE_IndicatorToolBarHandle, &opt, &p, this);
1061}
1062
1063/*
1064 Checks if an expanded toolbar has to wait for this popup to close before
1065 the toolbar collapses. This is true if
1066 1) the popup has the toolbar in its parent chain,
1067 2) the popup is a menu whose menuAction is somewhere in the toolbar.
1068*/
1069static bool waitForPopup(QToolBar *tb, QWidget *popup)
1070{
1071 if (popup == 0 || popup->isHidden())
1072 return false;
1073
1074 QWidget *w = popup;
1075 while (w != 0) {
1076 if (w == tb)
1077 return true;
1078 w = w->parentWidget();
1079 }
1080
1081 QMenu *menu = qobject_cast<QMenu*>(popup);
1082 if (menu == 0)
1083 return false;
1084
1085 QAction *action = menu->menuAction();
1086 QList<QWidget*> widgets = action->associatedWidgets();
1087 for (int i = 0; i < widgets.count(); ++i) {
1088 if (waitForPopup(tb, widgets.at(i)))
1089 return true;
1090 }
1091
1092 return false;
1093}
1094
1095#if defined(Q_WS_MAC)
1096static bool toolbarInUnifiedToolBar(QToolBar *toolbar)
1097{
1098 const QMainWindow *mainWindow = qobject_cast<const QMainWindow *>(toolbar->parentWidget());
1099 return mainWindow && mainWindow->unifiedTitleAndToolBarOnMac()
1100 && mainWindow->toolBarArea(toolbar) == Qt::TopToolBarArea;
1101}
1102#endif
1103
1104/*! \reimp */
1105bool QToolBar::event(QEvent *event)
1106{
1107 Q_D(QToolBar);
1108
1109 switch (event->type()) {
1110 case QEvent::Timer:
1111 if (d->waitForPopupTimer.timerId() == static_cast<QTimerEvent*>(event)->timerId()) {
1112 QWidget *w = QApplication::activePopupWidget();
1113 if (!waitForPopup(this, w)) {
1114 d->waitForPopupTimer.stop();
1115 if (!this->underMouse())
1116 d->layout->setExpanded(false);
1117 }
1118 }
1119 break;
1120 case QEvent::Hide:
1121 if (!isHidden())
1122 break;
1123 // fallthrough intended
1124 case QEvent::Show:
1125 d->toggleViewAction->setChecked(event->type() == QEvent::Show);
1126#if defined(Q_WS_MAC)
1127 if (toolbarInUnifiedToolBar(this)) {
1128 // I can static_cast because I did the qobject_cast in the if above, therefore
1129 // we must have a QMainWindowLayout here.
1130 QMainWindowLayout *mwLayout = static_cast<QMainWindowLayout *>(parentWidget()->layout());
1131 mwLayout->fixSizeInUnifiedToolbar(this);
1132 mwLayout->syncUnifiedToolbarVisibility();
1133 }
1134# if !defined(QT_MAC_USE_COCOA)
1135 // Fall through
1136 case QEvent::LayoutRequest: {
1137 // There's currently no way to invalidate the size and let
1138 // HIToolbar know about it. This forces a re-check.
1139 int earlyResult = -1;
1140 if (QMainWindow *mainWindow = qobject_cast<QMainWindow *>(parentWidget())) {
1141 bool needUpdate = true;
1142 if (event->type() == QEvent::LayoutRequest) {
1143 QSize oldSizeHint = sizeHint();
1144 earlyResult = QWidget::event(event) ? 1 : 0;
1145 needUpdate = oldSizeHint != sizeHint();
1146 }
1147
1148 if (needUpdate) {
1149 OSWindowRef windowRef = qt_mac_window_for(mainWindow);
1150 if (toolbarInUnifiedToolBar(this)
1151 && macWindowToolbarIsVisible(windowRef)) {
1152 DisableScreenUpdates();
1153 macWindowToolbarShow(this, false);
1154 macWindowToolbarShow(this, true);
1155 EnableScreenUpdates();
1156 }
1157 }
1158
1159 if (earlyResult != -1)
1160 return earlyResult;
1161 }
1162 }
1163# endif // !QT_MAC_USE_COCOA
1164#endif // Q_WS_MAC
1165 break;
1166 case QEvent::ParentChange:
1167 d->layout->checkUsePopupMenu();
1168#if defined(Q_WS_MAC)
1169 if (parentWidget() && parentWidget()->isWindow())
1170 qt_mac_updateToolBarButtonHint(parentWidget());
1171#endif
1172 break;
1173
1174 case QEvent::MouseButtonPress: {
1175 if (d->mousePressEvent(static_cast<QMouseEvent*>(event)))
1176 return true;
1177 break;
1178 }
1179 case QEvent::MouseButtonRelease:
1180 if (d->mouseReleaseEvent(static_cast<QMouseEvent*>(event)))
1181 return true;
1182 break;
1183 case QEvent::HoverEnter:
1184 case QEvent::HoverLeave:
1185 // there's nothing special to do here and we don't want to update the whole widget
1186 return true;
1187 case QEvent::HoverMove: {
1188#ifndef QT_NO_CURSOR
1189 QHoverEvent *e = static_cast<QHoverEvent*>(event);
1190 QStyleOptionToolBar opt;
1191 initStyleOption(&opt);
1192 if (style()->subElementRect(QStyle::SE_ToolBarHandle, &opt, this).contains(e->pos()))
1193 setCursor(Qt::SizeAllCursor);
1194 else
1195 unsetCursor();
1196#endif
1197 break;
1198 }
1199 case QEvent::MouseMove:
1200 if (d->mouseMoveEvent(static_cast<QMouseEvent*>(event)))
1201 return true;
1202 break;
1203#ifdef Q_WS_WINCE
1204 case QEvent::ContextMenu:
1205 {
1206 QContextMenuEvent* contextMenuEvent = static_cast<QContextMenuEvent*>(event);
1207 QWidget* child = childAt(contextMenuEvent->pos());
1208 QAbstractButton* button = qobject_cast<QAbstractButton*>(child);
1209 if (button)
1210 button->setDown(false);
1211 }
1212 break;
1213#endif
1214 case QEvent::Leave:
1215 if (d->state != 0 && d->state->dragging) {
1216#ifdef Q_OS_WIN
1217 // This is a workaround for loosing the mouse on Vista.
1218 QPoint pos = QCursor::pos();
1219 QMouseEvent fake(QEvent::MouseMove, mapFromGlobal(pos), pos, Qt::NoButton,
1220 QApplication::mouseButtons(), QApplication::keyboardModifiers());
1221 d->mouseMoveEvent(&fake);
1222#endif
1223 } else {
1224 if (!d->layout->expanded)
1225 break;
1226
1227 QWidget *w = QApplication::activePopupWidget();
1228 if (waitForPopup(this, w)) {
1229 d->waitForPopupTimer.start(POPUP_TIMER_INTERVAL, this);
1230 break;
1231 }
1232
1233 d->waitForPopupTimer.stop();
1234 d->layout->setExpanded(false);
1235 break;
1236 }
1237 default:
1238 break;
1239 }
1240 return QWidget::event(event);
1241}
1242
1243/*!
1244 Returns a checkable action that can be used to show or hide this
1245 toolbar.
1246
1247 The action's text is set to the toolbar's window title.
1248
1249 \sa QAction::text QWidget::windowTitle
1250*/
1251QAction *QToolBar::toggleViewAction() const
1252{ Q_D(const QToolBar); return d->toggleViewAction; }
1253
1254/*!
1255 \fn void QToolBar::setLabel(const QString &label)
1256
1257 Use setWindowTitle() instead.
1258*/
1259
1260/*!
1261 \fn QString QToolBar::label() const
1262
1263 Use windowTitle() instead.
1264*/
1265
1266/*!
1267 \since 4.2
1268
1269 Returns the widget associated with the specified \a action.
1270
1271 \sa addWidget()
1272*/
1273QWidget *QToolBar::widgetForAction(QAction *action) const
1274{
1275 Q_D(const QToolBar);
1276
1277 int index = d->layout->indexOf(action);
1278 if (index == -1)
1279 return 0;
1280
1281 return d->layout->itemAt(index)->widget();
1282}
1283
1284/*!
1285 \internal
1286*/
1287void QToolBar::initStyleOption(QStyleOptionToolBar *option) const
1288{
1289 Q_D(const QToolBar);
1290
1291 if (!option)
1292 return;
1293
1294 option->initFrom(this);
1295 if (orientation() == Qt::Horizontal)
1296 option->state |= QStyle::State_Horizontal;
1297 option->lineWidth = style()->pixelMetric(QStyle::PM_ToolBarFrameWidth, 0, this);
1298 option->features = d->layout->movable()
1299 ? QStyleOptionToolBar::Movable
1300 : QStyleOptionToolBar::None;
1301 // if the tool bar is not in a QMainWindow, this will make the painting right
1302 option->toolBarArea = Qt::NoToolBarArea;
1303
1304 // Add more styleoptions if the toolbar has been added to a mainwindow.
1305 QMainWindow *mainWindow = qobject_cast<QMainWindow *>(parentWidget());
1306
1307 if (!mainWindow)
1308 return;
1309
1310 QMainWindowLayout *layout = qobject_cast<QMainWindowLayout *>(mainWindow->layout());
1311 Q_ASSERT_X(layout != 0, "QToolBar::initStyleOption()",
1312 "QMainWindow->layout() != QMainWindowLayout");
1313
1314 layout->getStyleOptionInfo(option, const_cast<QToolBar *>(this));
1315}
1316
1317/*!
1318 \reimp
1319*/
1320void QToolBar::childEvent(QChildEvent *event) // ### remove me in 5.0
1321{
1322 QWidget::childEvent(event);
1323}
1324
1325/*!
1326 \reimp
1327*/
1328void QToolBar::resizeEvent(QResizeEvent *event) // ### remove me in 5.0
1329{
1330 QWidget::resizeEvent(event);
1331}
1332
1333QT_END_NAMESPACE
1334
1335#include "moc_qtoolbar.cpp"
1336
1337#endif // QT_NO_TOOLBAR
Note: See TracBrowser for help on using the repository browser.