From f67b8df3ebdba2d398b9cce686b7c644adffff08 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Sat, 7 May 2011 00:02:01 +0200 Subject: library split --- src/widgets/widgets/qtoolbar.cpp | 1349 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 1349 insertions(+) create mode 100644 src/widgets/widgets/qtoolbar.cpp (limited to 'src/widgets/widgets/qtoolbar.cpp') diff --git a/src/widgets/widgets/qtoolbar.cpp b/src/widgets/widgets/qtoolbar.cpp new file mode 100644 index 0000000000..e19ef69442 --- /dev/null +++ b/src/widgets/widgets/qtoolbar.cpp @@ -0,0 +1,1349 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtoolbar.h" + +#ifndef QT_NO_TOOLBAR + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef Q_WS_MAC +#include +#include +#endif + +#include + +#include "qtoolbar_p.h" +#include "qtoolbarseparator_p.h" +#include "qtoolbarlayout_p.h" + +#include "qdebug.h" + +#define POPUP_TIMER_INTERVAL 500 + +QT_BEGIN_NAMESPACE + +#ifdef Q_WS_MAC +static void qt_mac_updateToolBarButtonHint(QWidget *parentWidget) +{ + if (!(parentWidget->windowFlags() & Qt::CustomizeWindowHint)) + parentWidget->setWindowFlags(parentWidget->windowFlags() | Qt::MacWindowToolBarButtonHint); +} +#endif + +// qmainwindow.cpp +extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *window); + +/****************************************************************************** +** QToolBarPrivate +*/ + +void QToolBarPrivate::init() +{ + Q_Q(QToolBar); + q->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed)); + q->setBackgroundRole(QPalette::Button); + q->setAttribute(Qt::WA_Hover); + q->setAttribute(Qt::WA_X11NetWmWindowTypeToolBar); + + QStyle *style = q->style(); + int e = style->pixelMetric(QStyle::PM_ToolBarIconSize, 0, q); + iconSize = QSize(e, e); + + layout = new QToolBarLayout(q); + layout->updateMarginAndSpacing(); + +#ifdef Q_WS_MAC + if (q->parentWidget() && q->parentWidget()->isWindow()) { + // Make sure that the window has the "toolbar" button. + QWidget *parentWidget = q->parentWidget(); + qt_mac_updateToolBarButtonHint(parentWidget); + reinterpret_cast(parentWidget)->d_func()->createWinId(); // Please let me create your winId... + extern OSWindowRef qt_mac_window_for(const QWidget *); // qwidget_mac.cpp + macWindowToolbarShow(q->parentWidget(), true); + } +#endif + + toggleViewAction = new QAction(q); + toggleViewAction->setCheckable(true); + q->setMovable(q->style()->styleHint(QStyle::SH_ToolBar_Movable, 0, q )); + QObject::connect(toggleViewAction, SIGNAL(triggered(bool)), q, SLOT(_q_toggleView(bool))); +} + +void QToolBarPrivate::_q_toggleView(bool b) +{ + Q_Q(QToolBar); + if (b == q->isHidden()) { + if (b) + q->show(); + else + q->close(); + } +} + +void QToolBarPrivate::_q_updateIconSize(const QSize &sz) +{ + Q_Q(QToolBar); + if (!explicitIconSize) { + // iconSize not explicitly set + q->setIconSize(sz); + explicitIconSize = false; + } +} + +void QToolBarPrivate::_q_updateToolButtonStyle(Qt::ToolButtonStyle style) +{ + Q_Q(QToolBar); + if (!explicitToolButtonStyle) { + q->setToolButtonStyle(style); + explicitToolButtonStyle = false; + } +} + +void QToolBarPrivate::updateWindowFlags(bool floating, bool unplug) +{ + Q_Q(QToolBar); + Qt::WindowFlags flags = floating ? Qt::Tool : Qt::Widget; + + flags |= Qt::FramelessWindowHint; + + if (unplug) { + flags |= Qt::X11BypassWindowManagerHint; +#ifdef Q_WS_MAC + flags |= Qt::WindowStaysOnTopHint; +#endif + } + + q->setWindowFlags(flags); +} + +void QToolBarPrivate::setWindowState(bool floating, bool unplug, const QRect &rect) +{ + Q_Q(QToolBar); + bool visible = !q->isHidden(); + bool wasFloating = q->isFloating(); // ...is also currently using popup menus + + q->hide(); + + updateWindowFlags(floating, unplug); + + if (floating != wasFloating) + layout->checkUsePopupMenu(); + + if (!rect.isNull()) + q->setGeometry(rect); + + if (visible) + q->show(); + + if (floating != wasFloating) + emit q->topLevelChanged(floating); +} + +void QToolBarPrivate::initDrag(const QPoint &pos) +{ + Q_Q(QToolBar); + + if (state != 0) + return; + + QMainWindow *win = qobject_cast(parent); + Q_ASSERT(win != 0); + QMainWindowLayout *layout = qt_mainwindow_layout(win); + Q_ASSERT(layout != 0); + if (layout->pluggingWidget != 0) // the main window is animating a docking operation + return; + + state = new DragState; + state->pressPos = pos; + state->dragging = false; + state->moving = false; + state->widgetItem = 0; + + if (q->isRightToLeft()) + state->pressPos = QPoint(q->width() - state->pressPos.x(), state->pressPos.y()); +} + +void QToolBarPrivate::startDrag(bool moving) +{ + Q_Q(QToolBar); + + Q_ASSERT(state != 0); + + if ((moving && state->moving) || state->dragging) + return; + + QMainWindow *win = qobject_cast(parent); + Q_ASSERT(win != 0); + QMainWindowLayout *layout = qt_mainwindow_layout(win); + Q_ASSERT(layout != 0); + + if (!moving) { + state->widgetItem = layout->unplug(q); +#if defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA) + if (q->isWindow()) { + setWindowState(true, true); //set it to floating + } +#endif + Q_ASSERT(state->widgetItem != 0); + } + state->dragging = !moving; + state->moving = moving; +} + +void QToolBarPrivate::endDrag() +{ + Q_Q(QToolBar); + Q_ASSERT(state != 0); + + q->releaseMouse(); + + if (state->dragging) { + QMainWindowLayout *layout = qt_mainwindow_layout(qobject_cast(q->parentWidget())); + Q_ASSERT(layout != 0); + + if (!layout->plug(state->widgetItem)) { + if (q->isFloatable()) { + layout->restore(); +#if defined(Q_WS_X11) || defined(Q_WS_MAC) + setWindowState(true); // gets rid of the X11BypassWindowManager window flag + // and activates the resizer +#endif + q->activateWindow(); + } else { + layout->revert(state->widgetItem); + } + } + } + + delete state; + state = 0; +} + +bool QToolBarPrivate::mousePressEvent(QMouseEvent *event) +{ + Q_Q(QToolBar); + QStyleOptionToolBar opt; + q->initStyleOption(&opt); + if (q->style()->subElementRect(QStyle::SE_ToolBarHandle, &opt, q).contains(event->pos()) == false) { +#ifdef Q_WS_MAC + // When using the unified toolbar on Mac OS X the user can can click and + // drag between toolbar contents to move the window. Make this work by + // implementing the standard mouse-dragging code and then call + // window->move() in mouseMoveEvent below. + if (QMainWindow *mainWindow = qobject_cast(parent)) { + if (mainWindow->toolBarArea(q) == Qt::TopToolBarArea + && mainWindow->unifiedTitleAndToolBarOnMac() + && q->childAt(event->pos()) == 0) { + macWindowDragging = true; + macWindowDragPressPosition = event->pos(); + return true; + } + } +#endif + return false; + } + + if (event->button() != Qt::LeftButton) + return true; + + if (!layout->movable()) + return true; + + initDrag(event->pos()); + return true; +} + +bool QToolBarPrivate::mouseReleaseEvent(QMouseEvent*) +{ + if (state != 0) { + endDrag(); + return true; + } else { +#ifdef Q_WS_MAC + if (!macWindowDragging) + return false; + macWindowDragging = false; + macWindowDragPressPosition = QPoint(); + return true; +#endif + return false; + } +} + +bool QToolBarPrivate::mouseMoveEvent(QMouseEvent *event) +{ + Q_Q(QToolBar); + + if (!state) { +#ifdef Q_WS_MAC + if (!macWindowDragging) + return false; + QWidget *w = q->window(); + const QPoint delta = event->pos() - macWindowDragPressPosition; + w->move(w->pos() + delta); + return true; +#endif + return false; + } + + QMainWindow *win = qobject_cast(parent); + if (win == 0) + return true; + + QMainWindowLayout *layout = qt_mainwindow_layout(win); + Q_ASSERT(layout != 0); + + if (layout->pluggingWidget == 0 + && (event->pos() - state->pressPos).manhattanLength() > QApplication::startDragDistance()) { + const bool wasDragging = state->dragging; + const bool moving = !q->isWindow() && (orientation == Qt::Vertical ? + event->x() >= 0 && event->x() < q->width() : + event->y() >= 0 && event->y() < q->height()); + + startDrag(moving); + if (!moving && !wasDragging) { +#ifdef Q_OS_WIN + grabMouseWhileInWindow(); +#else + q->grabMouse(); +#endif + } + } + + if (state->dragging) { + QPoint pos = event->globalPos(); + // if we are right-to-left, we move so as to keep the right edge the same distance + // from the mouse + if (q->isLeftToRight()) + pos -= state->pressPos; + else + pos += QPoint(state->pressPos.x() - q->width(), -state->pressPos.y()); + + q->move(pos); + layout->hover(state->widgetItem, event->globalPos()); + } else if (state->moving) { + + const QPoint rtl(q->width() - state->pressPos.x(), state->pressPos.y()); //for RTL + const QPoint globalPressPos = q->mapToGlobal(q->isRightToLeft() ? rtl : state->pressPos); + int pos = 0; + + QPoint delta = event->globalPos() - globalPressPos; + if (orientation == Qt::Vertical) { + pos = q->y() + delta.y(); + } else { + if (q->isRightToLeft()) { + pos = win->width() - q->width() - q->x() - delta.x(); + } else { + pos = q->x() + delta.x(); + } + } + + layout->moveToolBar(q, pos); + } + return true; +} + +void QToolBarPrivate::unplug(const QRect &_r) +{ + Q_Q(QToolBar); + QRect r = _r; + r.moveTopLeft(q->mapToGlobal(QPoint(0, 0))); + setWindowState(true, true, r); + layout->setExpanded(false); +} + +void QToolBarPrivate::plug(const QRect &r) +{ + setWindowState(false, false, r); +} + +/****************************************************************************** +** QToolBar +*/ + +/*! + \class QToolBar + + \brief The QToolBar class provides a movable panel that contains a + set of controls. + + \ingroup mainwindow-classes + + + Toolbar buttons are added by adding \e actions, using addAction() + or insertAction(). Groups of buttons can be separated using + addSeparator() or insertSeparator(). If a toolbar button is not + appropriate, a widget can be inserted instead using addWidget() or + insertWidget(); examples of suitable widgets are QSpinBox, + QDoubleSpinBox, and QComboBox. When a toolbar button is pressed it + emits the actionTriggered() signal. + + A toolbar can be fixed in place in a particular area (e.g. at the + top of the window), or it can be movable (isMovable()) between + toolbar areas; see allowedAreas() and isAreaAllowed(). + + When a toolbar is resized in such a way that it is too small to + show all the items it contains, an extension button will appear as + the last item in the toolbar. Pressing the extension button will + pop up a menu containing the items that does not currently fit in + the toolbar. + + When a QToolBar is not a child of a QMainWindow, it looses the ability + to populate the extension pop up with widgets added to the toolbar using + addWidget(). Please use widget actions created by inheriting QWidgetAction + and implementing QWidgetAction::createWidget() instead. + + \sa QToolButton, QMenu, QAction, {Application Example} +*/ + +/*! + \fn bool QToolBar::isAreaAllowed(Qt::ToolBarArea area) const + + Returns true if this toolbar is dockable in the given \a area; + otherwise returns false. +*/ + +/*! + \fn void QToolBar::addAction(QAction *action) + \overload + + Appends the action \a action to the toolbar's list of actions. + + \sa QMenu::addAction(), QWidget::addAction() +*/ + +/*! + \fn void QToolBar::actionTriggered(QAction *action) + + This signal is emitted when an action in this toolbar is triggered. + This happens when the action's tool button is pressed, or when the + action is triggered in some other way outside the tool bar. The parameter + holds the triggered \a action. +*/ + +/*! + \fn void QToolBar::allowedAreasChanged(Qt::ToolBarAreas allowedAreas) + + This signal is emitted when the collection of allowed areas for the + toolbar is changed. The new areas in which the toolbar can be positioned + are specified by \a allowedAreas. + + \sa allowedAreas +*/ + +/*! + \fn void QToolBar::iconSizeChanged(const QSize &iconSize) + + This signal is emitted when the icon size is changed. The \a + iconSize parameter holds the toolbar's new icon size. + + \sa iconSize QMainWindow::iconSize +*/ + +/*! + \fn void QToolBar::movableChanged(bool movable) + + This signal is emitted when the toolbar becomes movable or fixed. + If the toolbar can be moved, \a movable is true; otherwise it is + false. + + \sa movable +*/ + +/*! + \fn void QToolBar::orientationChanged(Qt::Orientation orientation) + + This signal is emitted when the orientation of the toolbar changes. + The new orientation is specified by the \a orientation given. + + \sa orientation +*/ + +/*! + \fn void QToolBar::toolButtonStyleChanged(Qt::ToolButtonStyle toolButtonStyle) + + This signal is emitted when the tool button style is changed. The + \a toolButtonStyle parameter holds the toolbar's new tool button + style. + + \sa toolButtonStyle QMainWindow::toolButtonStyle +*/ + +/*! + \since 4.6 + + \fn void QToolBar::topLevelChanged(bool topLevel) + + This signal is emitted when the \l floating property changes. + The \a topLevel parameter is true if the toolbar is now floating; + otherwise it is false. + + \sa isWindow() +*/ + + +/*! + \fn void QToolBar::visibilityChanged(bool visible) + \since 4.7 + + This signal is emitted when the toolbar becomes \a visible (or + invisible). This happens when the widget is hidden or shown. +*/ + +/*! + Constructs a QToolBar with the given \a parent. +*/ +QToolBar::QToolBar(QWidget *parent) + : QWidget(*new QToolBarPrivate, parent, 0) +{ + Q_D(QToolBar); + d->init(); +} + +/*! + Constructs a QToolBar with the given \a parent. + + The given window \a title identifies the toolbar and is shown in + the context menu provided by QMainWindow. + + \sa setWindowTitle() +*/ +QToolBar::QToolBar(const QString &title, QWidget *parent) + : QWidget(*new QToolBarPrivate, parent, 0) +{ + Q_D(QToolBar); + d->init(); + setWindowTitle(title); +} + +#ifdef QT3_SUPPORT +/*! \obsolete + Constructs a QToolBar with the given \a parent and \a name. +*/ +QToolBar::QToolBar(QWidget *parent, const char *name) + : QWidget(*new QToolBarPrivate, parent, 0) +{ + Q_D(QToolBar); + d->init(); + setObjectName(QString::fromAscii(name)); +} +#endif + +/*! + Destroys the toolbar. +*/ +QToolBar::~QToolBar() +{ + // Remove the toolbar button if there is nothing left. + QMainWindow *mainwindow = qobject_cast(parentWidget()); + if (mainwindow) { +#ifdef Q_WS_MAC + QMainWindowLayout *mainwin_layout = qt_mainwindow_layout(mainwindow); + if (mainwin_layout && mainwin_layout->layoutState.toolBarAreaLayout.isEmpty() + && mainwindow->testAttribute(Qt::WA_WState_Created)) + macWindowToolbarShow(mainwindow, false); +#endif + } +} + +/*! \property QToolBar::movable + \brief whether the user can move the toolbar within the toolbar area, + or between toolbar areas + + By default, this property is true. + + This property only makes sense if the toolbar is in a + QMainWindow. + + \sa allowedAreas +*/ + +void QToolBar::setMovable(bool movable) +{ + Q_D(QToolBar); + if (!movable == !d->movable) + return; + d->movable = movable; + d->layout->invalidate(); + emit movableChanged(d->movable); +} + +bool QToolBar::isMovable() const +{ + Q_D(const QToolBar); + return d->movable; +} + +/*! + \property QToolBar::floatable + \brief whether the toolbar can be dragged and dropped as an independent window. + + The default is true. +*/ +bool QToolBar::isFloatable() const +{ + Q_D(const QToolBar); + return d->floatable; +} + +void QToolBar::setFloatable(bool floatable) +{ + Q_D(QToolBar); + d->floatable = floatable; +} + +/*! + \property QToolBar::floating + \brief whether the toolbar is an independent window. + + By default, this property is true. + + \sa QWidget::isWindow() +*/ +bool QToolBar::isFloating() const +{ + return isWindow(); +} + +/*! + \property QToolBar::allowedAreas + \brief areas where the toolbar may be placed + + The default is Qt::AllToolBarAreas. + + This property only makes sense if the toolbar is in a + QMainWindow. + + \sa movable +*/ + +void QToolBar::setAllowedAreas(Qt::ToolBarAreas areas) +{ + Q_D(QToolBar); + areas &= Qt::ToolBarArea_Mask; + if (areas == d->allowedAreas) + return; + d->allowedAreas = areas; + emit allowedAreasChanged(d->allowedAreas); +} + +Qt::ToolBarAreas QToolBar::allowedAreas() const +{ + Q_D(const QToolBar); +#ifdef Q_WS_MAC + if (QMainWindow *window = qobject_cast(parentWidget())) { + if (window->unifiedTitleAndToolBarOnMac()) // Don't allow drags to the top (for now). + return (d->allowedAreas & ~Qt::TopToolBarArea); + } +#endif + return d->allowedAreas; +} + +/*! \property QToolBar::orientation + \brief orientation of the toolbar + + The default is Qt::Horizontal. + + This function should not be used when the toolbar is managed + by QMainWindow. You can use QMainWindow::addToolBar() or + QMainWindow::insertToolBar() if you wish to move a toolbar (that + is already added to a main window) to another Qt::ToolBarArea. +*/ + +void QToolBar::setOrientation(Qt::Orientation orientation) +{ + Q_D(QToolBar); + if (orientation == d->orientation) + return; + + d->orientation = orientation; + + if (orientation == Qt::Vertical) + setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred)); + else + setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed)); + + d->layout->invalidate(); + d->layout->activate(); + + emit orientationChanged(d->orientation); +} + +Qt::Orientation QToolBar::orientation() const +{ Q_D(const QToolBar); return d->orientation; } + +/*! + \property QToolBar::iconSize + \brief size of icons in the toolbar. + + The default size is determined by the application's style and is + derived from the QStyle::PM_ToolBarIconSize pixel metric. It is + the maximum size an icon can have. Icons of smaller size will not + be scaled up. +*/ + +QSize QToolBar::iconSize() const +{ Q_D(const QToolBar); return d->iconSize; } + +void QToolBar::setIconSize(const QSize &iconSize) +{ + Q_D(QToolBar); + QSize sz = iconSize; + if (!sz.isValid()) { + QMainWindow *mw = qobject_cast(parentWidget()); + if (mw && mw->layout()) { + QLayout *layout = mw->layout(); + int i = 0; + QLayoutItem *item = 0; + do { + item = layout->itemAt(i++); + if (item && (item->widget() == this)) + sz = mw->iconSize(); + } while (!sz.isValid() && item != 0); + } + } + if (!sz.isValid()) { + const int metric = style()->pixelMetric(QStyle::PM_ToolBarIconSize, 0, this); + sz = QSize(metric, metric); + } + if (d->iconSize != sz) { + d->iconSize = sz; + setMinimumSize(0, 0); + emit iconSizeChanged(d->iconSize); + } + d->explicitIconSize = iconSize.isValid(); + + d->layout->invalidate(); +} + +/*! + \property QToolBar::toolButtonStyle + \brief the style of toolbar buttons + + This property defines the style of all tool buttons that are added + as \l{QAction}s. Note that if you add a QToolButton with the + addWidget() method, it will not get this button style. + + The default is Qt::ToolButtonIconOnly. +*/ + +Qt::ToolButtonStyle QToolBar::toolButtonStyle() const +{ Q_D(const QToolBar); return d->toolButtonStyle; } + +void QToolBar::setToolButtonStyle(Qt::ToolButtonStyle toolButtonStyle) +{ + Q_D(QToolBar); + d->explicitToolButtonStyle = true; + if (d->toolButtonStyle == toolButtonStyle) + return; + d->toolButtonStyle = toolButtonStyle; + setMinimumSize(0, 0); + emit toolButtonStyleChanged(d->toolButtonStyle); +} + +/*! + Removes all actions from the toolbar. + + \sa removeAction() +*/ +void QToolBar::clear() +{ + QList actions = this->actions(); + for(int i = 0; i < actions.size(); i++) + removeAction(actions.at(i)); +} + +/*! + \overload + + Creates a new action with the given \a text. This action is added to + the end of the toolbar. +*/ +QAction *QToolBar::addAction(const QString &text) +{ + QAction *action = new QAction(text, this); + addAction(action); + return action; +} + +/*! + \overload + + Creates a new action with the given \a icon and \a text. This + action is added to the end of the toolbar. +*/ +QAction *QToolBar::addAction(const QIcon &icon, const QString &text) +{ + QAction *action = new QAction(icon, text, this); + addAction(action); + return action; +} + +/*! + \overload + + Creates a new action with the given \a text. This action is added to + the end of the toolbar. The action's \link QAction::triggered() + triggered()\endlink signal is connected to \a member in \a + receiver. +*/ +QAction *QToolBar::addAction(const QString &text, + const QObject *receiver, const char* member) +{ + QAction *action = new QAction(text, this); + QObject::connect(action, SIGNAL(triggered(bool)), receiver, member); + addAction(action); + return action; +} + +/*! + \overload + + Creates a new action with the icon \a icon and text \a text. This + action is added to the end of the toolbar. The action's \link + QAction::triggered() triggered()\endlink signal is connected to \a + member in \a receiver. +*/ +QAction *QToolBar::addAction(const QIcon &icon, const QString &text, + const QObject *receiver, const char* member) +{ + QAction *action = new QAction(icon, text, this); + QObject::connect(action, SIGNAL(triggered(bool)), receiver, member); + addAction(action); + return action; +} + +/*! + Adds a separator to the end of the toolbar. + + \sa insertSeparator() +*/ +QAction *QToolBar::addSeparator() +{ + QAction *action = new QAction(this); + action->setSeparator(true); + addAction(action); + return action; +} + +/*! + Inserts a separator into the toolbar in front of the toolbar + item associated with the \a before action. + + \sa addSeparator() +*/ +QAction *QToolBar::insertSeparator(QAction *before) +{ + QAction *action = new QAction(this); + action->setSeparator(true); + insertAction(before, action); + return action; +} + +/*! + Adds the given \a widget to the toolbar as the toolbar's last + item. + + The toolbar takes ownership of \a widget. + + If you add a QToolButton with this method, the tools bar's + Qt::ToolButtonStyle will not be respected. + + \note You should use QAction::setVisible() to change the + visibility of the widget. Using QWidget::setVisible(), + QWidget::show() and QWidget::hide() does not work. + + \sa insertWidget() +*/ +QAction *QToolBar::addWidget(QWidget *widget) +{ + QWidgetAction *action = new QWidgetAction(this); + action->setDefaultWidget(widget); + action->d_func()->autoCreated = true; + addAction(action); + return action; +} + +/*! + Inserts the given \a widget in front of the toolbar item + associated with the \a before action. + + Note: You should use QAction::setVisible() to change the + visibility of the widget. Using QWidget::setVisible(), + QWidget::show() and QWidget::hide() does not work. + + \sa addWidget() +*/ +QAction *QToolBar::insertWidget(QAction *before, QWidget *widget) +{ + QWidgetAction *action = new QWidgetAction(this); + action->setDefaultWidget(widget); + action->d_func()->autoCreated = true; + insertAction(before, action); + return action; +} + +/*! + \internal + + Returns the geometry of the toolbar item associated with the given + \a action, or an invalid QRect if no matching item is found. +*/ +QRect QToolBar::actionGeometry(QAction *action) const +{ + Q_D(const QToolBar); + + int index = d->layout->indexOf(action); + if (index == -1) + return QRect(); + return d->layout->itemAt(index)->widget()->geometry(); +} + +/*! + Returns the action at point \a p. This function returns zero if no + action was found. + + \sa QWidget::childAt() +*/ +QAction *QToolBar::actionAt(const QPoint &p) const +{ + Q_D(const QToolBar); + QWidget *widget = childAt(p); + int index = d->layout->indexOf(widget); + if (index == -1) + return 0; + QLayoutItem *item = d->layout->itemAt(index); + return static_cast(item)->action; +} + +/*! \fn QAction *QToolBar::actionAt(int x, int y) const + \overload + + Returns the action at the point \a x, \a y. This function returns + zero if no action was found. +*/ + +/*! \reimp */ +void QToolBar::actionEvent(QActionEvent *event) +{ + Q_D(QToolBar); + QAction *action = event->action(); + QWidgetAction *widgetAction = qobject_cast(action); + + switch (event->type()) { + case QEvent::ActionAdded: { + Q_ASSERT_X(widgetAction == 0 || d->layout->indexOf(widgetAction) == -1, + "QToolBar", "widgets cannot be inserted multiple times"); + + // reparent the action to this toolbar if it has been created + // using the addAction(text) etc. convenience functions, to + // preserve Qt 4.1.x behavior. The widget is already + // reparented to us due to the createWidget call inside + // createItem() + if (widgetAction != 0 && widgetAction->d_func()->autoCreated) + widgetAction->setParent(this); + + int index = d->layout->count(); + if (event->before()) { + index = d->layout->indexOf(event->before()); + Q_ASSERT_X(index != -1, "QToolBar::insertAction", "internal error"); + } + d->layout->insertAction(index, action); + break; + } + + case QEvent::ActionChanged: + d->layout->invalidate(); + break; + + case QEvent::ActionRemoved: { + int index = d->layout->indexOf(action); + if (index != -1) { + delete d->layout->takeAt(index); + } + break; + } + + default: + Q_ASSERT_X(false, "QToolBar::actionEvent", "internal error"); + } +} + +/*! \reimp */ +void QToolBar::changeEvent(QEvent *event) +{ + Q_D(QToolBar); + switch (event->type()) { + case QEvent::WindowTitleChange: + d->toggleViewAction->setText(windowTitle()); + break; + case QEvent::StyleChange: + d->layout->invalidate(); + if (!d->explicitIconSize) + setIconSize(QSize()); + d->layout->updateMarginAndSpacing(); + break; + case QEvent::LayoutDirectionChange: + d->layout->invalidate(); + break; + default: + break; + } + QWidget::changeEvent(event); +} + +/*! \reimp */ +void QToolBar::paintEvent(QPaintEvent *) +{ + Q_D(QToolBar); + + QPainter p(this); + QStyle *style = this->style(); + QStyleOptionToolBar opt; + initStyleOption(&opt); + + if (d->layout->expanded || d->layout->animating || isWindow()) { + //if the toolbar is expended, we need to fill the background with the window color + //because some styles may expects that. + p.fillRect(opt.rect, palette().background()); + style->drawControl(QStyle::CE_ToolBar, &opt, &p, this); + style->drawPrimitive(QStyle::PE_FrameMenu, &opt, &p, this); + } else { + style->drawControl(QStyle::CE_ToolBar, &opt, &p, this); + } + + opt.rect = style->subElementRect(QStyle::SE_ToolBarHandle, &opt, this); + if (opt.rect.isValid()) + style->drawPrimitive(QStyle::PE_IndicatorToolBarHandle, &opt, &p, this); +} + +/* + Checks if an expanded toolbar has to wait for this popup to close before + the toolbar collapses. This is true if + 1) the popup has the toolbar in its parent chain, + 2) the popup is a menu whose menuAction is somewhere in the toolbar. +*/ +static bool waitForPopup(QToolBar *tb, QWidget *popup) +{ + if (popup == 0 || popup->isHidden()) + return false; + + QWidget *w = popup; + while (w != 0) { + if (w == tb) + return true; + w = w->parentWidget(); + } + + QMenu *menu = qobject_cast(popup); + if (menu == 0) + return false; + + QAction *action = menu->menuAction(); + QList widgets = action->associatedWidgets(); + for (int i = 0; i < widgets.count(); ++i) { + if (waitForPopup(tb, widgets.at(i))) + return true; + } + + return false; +} + +#if defined(Q_WS_MAC) +static bool toolbarInUnifiedToolBar(QToolBar *toolbar) +{ + const QMainWindow *mainWindow = qobject_cast(toolbar->parentWidget()); + return mainWindow && mainWindow->unifiedTitleAndToolBarOnMac() + && mainWindow->toolBarArea(toolbar) == Qt::TopToolBarArea; +} +#endif + +/*! \reimp */ +bool QToolBar::event(QEvent *event) +{ + Q_D(QToolBar); + + switch (event->type()) { + case QEvent::Timer: + if (d->waitForPopupTimer.timerId() == static_cast(event)->timerId()) { + QWidget *w = QApplication::activePopupWidget(); + if (!waitForPopup(this, w)) { + d->waitForPopupTimer.stop(); + if (!this->underMouse()) + d->layout->setExpanded(false); + } + } + break; + case QEvent::Hide: + if (!isHidden()) + break; + // fallthrough intended + case QEvent::Show: + d->toggleViewAction->setChecked(event->type() == QEvent::Show); + emit visibilityChanged(event->type() == QEvent::Show); +#if defined(Q_WS_MAC) + if (toolbarInUnifiedToolBar(this)) { + // I can static_cast because I did the qobject_cast in the if above, therefore + // we must have a QMainWindowLayout here. + QMainWindowLayout *mwLayout = qt_mainwindow_layout(qobject_cast(parentWidget())); + mwLayout->fixSizeInUnifiedToolbar(this); + mwLayout->syncUnifiedToolbarVisibility(); + } +# if !defined(QT_MAC_USE_COCOA) + // Fall through + case QEvent::LayoutRequest: { + // There's currently no way to invalidate the size and let + // HIToolbar know about it. This forces a re-check. + int earlyResult = -1; + if (QMainWindow *mainWindow = qobject_cast(parentWidget())) { + bool needUpdate = true; + if (event->type() == QEvent::LayoutRequest) { + QSize oldSizeHint = sizeHint(); + earlyResult = QWidget::event(event) ? 1 : 0; + needUpdate = oldSizeHint != sizeHint(); + } + + if (needUpdate) { + OSWindowRef windowRef = qt_mac_window_for(mainWindow); + if (toolbarInUnifiedToolBar(this) + && macWindowToolbarIsVisible(windowRef)) { + DisableScreenUpdates(); + macWindowToolbarShow(this, false); + macWindowToolbarShow(this, true); + EnableScreenUpdates(); + } + } + + if (earlyResult != -1) + return earlyResult; + } + } +# endif // !QT_MAC_USE_COCOA +#endif // Q_WS_MAC + break; + case QEvent::ParentChange: + d->layout->checkUsePopupMenu(); +#if defined(Q_WS_MAC) + if (parentWidget() && parentWidget()->isWindow()) + qt_mac_updateToolBarButtonHint(parentWidget()); +#endif + break; + + case QEvent::MouseButtonPress: { + if (d->mousePressEvent(static_cast(event))) + return true; + break; + } + case QEvent::MouseButtonRelease: + if (d->mouseReleaseEvent(static_cast(event))) + return true; + break; + case QEvent::HoverEnter: + case QEvent::HoverLeave: + // there's nothing special to do here and we don't want to update the whole widget + return true; + case QEvent::HoverMove: { +#ifndef QT_NO_CURSOR + QHoverEvent *e = static_cast(event); + QStyleOptionToolBar opt; + initStyleOption(&opt); + if (style()->subElementRect(QStyle::SE_ToolBarHandle, &opt, this).contains(e->pos())) + setCursor(Qt::SizeAllCursor); + else + unsetCursor(); +#endif + break; + } + case QEvent::MouseMove: + if (d->mouseMoveEvent(static_cast(event))) + return true; + break; +#ifdef Q_WS_WINCE + case QEvent::ContextMenu: + { + QContextMenuEvent* contextMenuEvent = static_cast(event); + QWidget* child = childAt(contextMenuEvent->pos()); + QAbstractButton* button = qobject_cast(child); + if (button) + button->setDown(false); + } + break; +#endif + case QEvent::Leave: + if (d->state != 0 && d->state->dragging) { +#ifdef Q_OS_WIN + // This is a workaround for loosing the mouse on Vista. + QPoint pos = QCursor::pos(); + QMouseEvent fake(QEvent::MouseMove, mapFromGlobal(pos), pos, Qt::NoButton, + QApplication::mouseButtons(), QApplication::keyboardModifiers()); + d->mouseMoveEvent(&fake); +#endif + } else { + if (!d->layout->expanded) + break; + + QWidget *w = QApplication::activePopupWidget(); + if (waitForPopup(this, w)) { + d->waitForPopupTimer.start(POPUP_TIMER_INTERVAL, this); + break; + } + + d->waitForPopupTimer.stop(); + d->layout->setExpanded(false); + break; + } + default: + break; + } + return QWidget::event(event); +} + +/*! + Returns a checkable action that can be used to show or hide this + toolbar. + + The action's text is set to the toolbar's window title. + + \sa QAction::text QWidget::windowTitle +*/ +QAction *QToolBar::toggleViewAction() const +{ Q_D(const QToolBar); return d->toggleViewAction; } + +/*! + \fn void QToolBar::setLabel(const QString &label) + + Use setWindowTitle() instead. +*/ + +/*! + \fn QString QToolBar::label() const + + Use windowTitle() instead. +*/ + +/*! + \since 4.2 + + Returns the widget associated with the specified \a action. + + \sa addWidget() +*/ +QWidget *QToolBar::widgetForAction(QAction *action) const +{ + Q_D(const QToolBar); + + int index = d->layout->indexOf(action); + if (index == -1) + return 0; + + return d->layout->itemAt(index)->widget(); +} + +extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *window); + +/*! + \internal +*/ +void QToolBar::initStyleOption(QStyleOptionToolBar *option) const +{ + Q_D(const QToolBar); + + if (!option) + return; + + option->initFrom(this); + if (orientation() == Qt::Horizontal) + option->state |= QStyle::State_Horizontal; + option->lineWidth = style()->pixelMetric(QStyle::PM_ToolBarFrameWidth, 0, this); + option->features = d->layout->movable() + ? QStyleOptionToolBar::Movable + : QStyleOptionToolBar::None; + // if the tool bar is not in a QMainWindow, this will make the painting right + option->toolBarArea = Qt::NoToolBarArea; + + // Add more styleoptions if the toolbar has been added to a mainwindow. + QMainWindow *mainWindow = qobject_cast(parentWidget()); + + if (!mainWindow) + return; + + QMainWindowLayout *layout = qt_mainwindow_layout(mainWindow); + Q_ASSERT_X(layout != 0, "QToolBar::initStyleOption()", + "QMainWindow->layout() != QMainWindowLayout"); + + layout->getStyleOptionInfo(option, const_cast(this)); +} + +/*! + \reimp +*/ +void QToolBar::childEvent(QChildEvent *event) // ### remove me in 5.0 +{ + QWidget::childEvent(event); +} + +/*! + \reimp +*/ +void QToolBar::resizeEvent(QResizeEvent *event) // ### remove me in 5.0 +{ + QWidget::resizeEvent(event); +} + +QT_END_NAMESPACE + +#include "moc_qtoolbar.cpp" + +#endif // QT_NO_TOOLBAR -- cgit v1.2.3