summaryrefslogtreecommitdiffstats
path: root/src/gui/widgets/qdockwidget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/widgets/qdockwidget.cpp')
-rw-r--r--src/gui/widgets/qdockwidget.cpp1594
1 files changed, 1594 insertions, 0 deletions
diff --git a/src/gui/widgets/qdockwidget.cpp b/src/gui/widgets/qdockwidget.cpp
new file mode 100644
index 0000000..865b19c
--- /dev/null
+++ b/src/gui/widgets/qdockwidget.cpp
@@ -0,0 +1,1594 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdockwidget.h"
+
+#ifndef QT_NO_DOCKWIDGET
+#include <qaction.h>
+#include <qapplication.h>
+#include <qdesktopwidget.h>
+#include <qdrawutil.h>
+#include <qevent.h>
+#include <qfontmetrics.h>
+#include <qmainwindow.h>
+#include <qrubberband.h>
+#include <qstylepainter.h>
+#include <qtoolbutton.h>
+#include <qdebug.h>
+
+#include <private/qwidgetresizehandler_p.h>
+
+#include "qdockwidget_p.h"
+#include "qmainwindowlayout_p.h"
+#ifdef Q_WS_MAC
+#include <private/qt_mac_p.h>
+#include <qmacstyle_mac.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+extern QString qt_setWindowTitle_helperHelper(const QString&, const QWidget*); // qwidget.cpp
+
+extern QHash<QByteArray, QFont> *qt_app_fonts_hash(); // qapplication.cpp
+
+static inline bool hasFeature(const QDockWidget *dockwidget, QDockWidget::DockWidgetFeature feature)
+{ return (dockwidget->features() & feature) == feature; }
+
+
+/*
+ A Dock Window:
+
+ [+] is the float button
+ [X] is the close button
+
+ +-------------------------------+
+ | Dock Window Title [+][X]|
+ +-------------------------------+
+ | |
+ | place to put the single |
+ | QDockWidget child (this space |
+ | does not yet have a name) |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ +-------------------------------+
+
+*/
+
+/******************************************************************************
+** QDockWidgetTitleButton
+*/
+
+class QDockWidgetTitleButton : public QAbstractButton
+{
+ Q_OBJECT
+
+public:
+ QDockWidgetTitleButton(QDockWidget *dockWidget);
+
+ QSize sizeHint() const;
+ inline QSize minimumSizeHint() const
+ { return sizeHint(); }
+
+ void enterEvent(QEvent *event);
+ void leaveEvent(QEvent *event);
+ void paintEvent(QPaintEvent *event);
+};
+
+
+QDockWidgetTitleButton::QDockWidgetTitleButton(QDockWidget *dockWidget)
+ : QAbstractButton(dockWidget)
+{
+ setFocusPolicy(Qt::NoFocus);
+}
+
+QSize QDockWidgetTitleButton::sizeHint() const
+{
+ ensurePolished();
+
+ int size = 2*style()->pixelMetric(QStyle::PM_DockWidgetTitleBarButtonMargin, 0, this);
+ if (!icon().isNull()) {
+ int iconSize = style()->pixelMetric(QStyle::PM_SmallIconSize, 0, this);
+ QSize sz = icon().actualSize(QSize(iconSize, iconSize));
+ size += qMax(sz.width(), sz.height());
+ }
+
+ return QSize(size, size);
+}
+
+void QDockWidgetTitleButton::enterEvent(QEvent *event)
+{
+ if (isEnabled()) update();
+ QAbstractButton::enterEvent(event);
+}
+
+void QDockWidgetTitleButton::leaveEvent(QEvent *event)
+{
+ if (isEnabled()) update();
+ QAbstractButton::leaveEvent(event);
+}
+
+void QDockWidgetTitleButton::paintEvent(QPaintEvent *)
+{
+ QPainter p(this);
+
+ QRect r = rect();
+ QStyleOptionToolButton opt;
+ opt.init(this);
+ opt.state |= QStyle::State_AutoRaise;
+
+ if (style()->styleHint(QStyle::SH_DockWidget_ButtonsHaveFrame, 0, this))
+ {
+ if (isEnabled() && underMouse() && !isChecked() && !isDown())
+ opt.state |= QStyle::State_Raised;
+ if (isChecked())
+ opt.state |= QStyle::State_On;
+ if (isDown())
+ opt.state |= QStyle::State_Sunken;
+ style()->drawPrimitive(QStyle::PE_PanelButtonTool, &opt, &p, this);
+ }
+
+ opt.icon = icon();
+ opt.subControls = 0;
+ opt.activeSubControls = 0;
+ opt.features = QStyleOptionToolButton::None;
+ opt.arrowType = Qt::NoArrow;
+ int size = style()->pixelMetric(QStyle::PM_SmallIconSize, 0, this);
+ opt.iconSize = QSize(size, size);
+ style()->drawComplexControl(QStyle::CC_ToolButton, &opt, &p, this);
+}
+
+/******************************************************************************
+** QDockWidgetLayout
+*/
+
+QDockWidgetLayout::QDockWidgetLayout(QWidget *parent)
+ : QLayout(parent), verticalTitleBar(false), item_list(RoleCount, 0)
+{
+}
+
+QDockWidgetLayout::~QDockWidgetLayout()
+{
+ qDeleteAll(item_list);
+}
+
+bool QDockWidgetLayout::nativeWindowDeco() const
+{
+ return nativeWindowDeco(parentWidget()->isWindow());
+}
+
+bool QDockWidgetLayout::nativeWindowDeco(bool floating) const
+{
+#if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_WINCE)
+ Q_UNUSED(floating);
+ return false;
+#else
+ return floating && item_list[QDockWidgetLayout::TitleBar] == 0;
+#endif
+}
+
+
+void QDockWidgetLayout::addItem(QLayoutItem*)
+{
+ qWarning() << "QDockWidgetLayout::addItem(): please use QDockWidgetLayout::setWidget()";
+ return;
+}
+
+QLayoutItem *QDockWidgetLayout::itemAt(int index) const
+{
+ int cnt = 0;
+ foreach (QLayoutItem *item, item_list) {
+ if (item == 0)
+ continue;
+ if (index == cnt++)
+ return item;
+ }
+ return 0;
+}
+
+QLayoutItem *QDockWidgetLayout::takeAt(int index)
+{
+ int j = 0;
+ for (int i = 0; i < item_list.count(); ++i) {
+ QLayoutItem *item = item_list.at(i);
+ if (item == 0)
+ continue;
+ if (index == j) {
+ item_list[i] = 0;
+ invalidate();
+ return item;
+ }
+ ++j;
+ }
+ return 0;
+}
+
+int QDockWidgetLayout::count() const
+{
+ int result = 0;
+ foreach (QLayoutItem *item, item_list) {
+ if (item != 0)
+ ++result;
+ }
+ return result;
+}
+
+QSize QDockWidgetLayout::sizeFromContent(const QSize &content, bool floating) const
+{
+ QSize result = content;
+
+ if (verticalTitleBar) {
+ result.setHeight(qMax(result.height(), minimumTitleWidth()));
+ result.setWidth(qMax(content.width(), 0));
+ } else {
+ result.setHeight(qMax(result.height(), 0));
+ result.setWidth(qMax(content.width(), minimumTitleWidth()));
+ }
+
+ QDockWidget *w = qobject_cast<QDockWidget*>(parentWidget());
+ const bool nativeDeco = nativeWindowDeco(floating);
+
+ int fw = floating && !nativeDeco
+ ? w->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, w)
+ : 0;
+
+ const int th = titleHeight();
+ if (!nativeDeco) {
+ if (verticalTitleBar)
+ result += QSize(th + 2*fw, 2*fw);
+ else
+ result += QSize(2*fw, th + 2*fw);
+ }
+
+ result.setHeight(qMin(result.height(), (int) QWIDGETSIZE_MAX));
+ result.setWidth(qMin(result.width(), (int) QWIDGETSIZE_MAX));
+
+ if (content.width() < 0)
+ result.setWidth(-1);
+ if (content.height() < 0)
+ result.setHeight(-1);
+
+ int left, top, right, bottom;
+ w->getContentsMargins(&left, &top, &right, &bottom);
+ //we need to substract the contents margin (it will be added by the caller)
+ QSize min = w->minimumSize() - QSize(left + right, top + bottom);
+ QSize max = w->maximumSize() - QSize(left + right, top + bottom);
+
+ /* A floating dockwidget will automatically get its minimumSize set to the layout's
+ minimum size + deco. We're *not* interested in this, we only take minimumSize()
+ into account if the user set it herself. Otherwise we end up expanding the result
+ of a calculation for a non-floating dock widget to a floating dock widget's
+ minimum size + window decorations. */
+
+ uint explicitMin = 0;
+ uint explicitMax = 0;
+ if (w->d_func()->extra != 0) {
+ explicitMin = w->d_func()->extra->explicitMinSize;
+ explicitMax = w->d_func()->extra->explicitMaxSize;
+ }
+
+ if (!(explicitMin & Qt::Horizontal) || min.width() == 0)
+ min.setWidth(-1);
+ if (!(explicitMin & Qt::Vertical) || min.height() == 0)
+ min.setHeight(-1);
+
+ if (!(explicitMax & Qt::Horizontal))
+ max.setWidth(QWIDGETSIZE_MAX);
+ if (!(explicitMax & Qt::Vertical))
+ max.setHeight(QWIDGETSIZE_MAX);
+
+ return result.boundedTo(max).expandedTo(min);
+}
+
+QSize QDockWidgetLayout::sizeHint() const
+{
+ QDockWidget *w = qobject_cast<QDockWidget*>(parentWidget());
+
+ QSize content(-1, -1);
+ if (item_list[Content] != 0)
+ content = item_list[Content]->sizeHint();
+
+ return sizeFromContent(content, w->isFloating());
+}
+
+QSize QDockWidgetLayout::maximumSize() const
+{
+ if (item_list[Content] != 0) {
+ const QSize content = item_list[Content]->maximumSize();
+ return sizeFromContent(content, parentWidget()->isWindow());
+ } else {
+ return parentWidget()->maximumSize();
+ }
+
+}
+
+QSize QDockWidgetLayout::minimumSize() const
+{
+ QDockWidget *w = qobject_cast<QDockWidget*>(parentWidget());
+
+ QSize content(0, 0);
+ if (item_list[Content] != 0)
+ content = item_list[Content]->minimumSize();
+
+ return sizeFromContent(content, w->isFloating());
+}
+
+QWidget *QDockWidgetLayout::widgetForRole(Role r) const
+{
+ QLayoutItem *item = item_list.at(r);
+ return item == 0 ? 0 : item->widget();
+}
+
+QLayoutItem *QDockWidgetLayout::itemForRole(Role r) const
+{
+ return item_list.at(r);
+}
+
+void QDockWidgetLayout::setWidgetForRole(Role r, QWidget *w)
+{
+ QWidget *old = widgetForRole(r);
+ if (old != 0) {
+ old->hide();
+ removeWidget(old);
+ }
+
+ if (w != 0) {
+ addChildWidget(w);
+ item_list[r] = new QWidgetItemV2(w);
+ w->show();
+ } else {
+ item_list[r] = 0;
+ }
+
+ invalidate();
+}
+
+static inline int pick(bool vertical, const QSize &size)
+{
+ return vertical ? size.height() : size.width();
+}
+
+static inline int perp(bool vertical, const QSize &size)
+{
+ return vertical ? size.width() : size.height();
+}
+
+int QDockWidgetLayout::minimumTitleWidth() const
+{
+ QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());
+
+ if (QWidget *title = widgetForRole(TitleBar))
+ return pick(verticalTitleBar, title->minimumSizeHint());
+
+ QSize closeSize(0, 0);
+ QSize floatSize(0, 0);
+ if (QLayoutItem *item = item_list[CloseButton])
+ closeSize = item->sizeHint();
+ if (QLayoutItem *item = item_list[FloatButton])
+ floatSize = item->sizeHint();
+
+ int titleHeight = this->titleHeight();
+
+ int mw = q->style()->pixelMetric(QStyle::PM_DockWidgetTitleMargin, 0, q);
+ int fw = q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, q);
+
+ return pick(verticalTitleBar, closeSize)
+ + pick(verticalTitleBar, floatSize)
+ + titleHeight + 2*fw + 3*mw;
+}
+
+int QDockWidgetLayout::titleHeight() const
+{
+ QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());
+
+ if (QWidget *title = widgetForRole(TitleBar))
+ return perp(verticalTitleBar, title->sizeHint());
+
+ QSize closeSize(0, 0);
+ QSize floatSize(0, 0);
+ if (QLayoutItem *item = item_list[CloseButton])
+ closeSize = item->widget()->sizeHint();
+ if (QLayoutItem *item = item_list[FloatButton])
+ floatSize = item->widget()->sizeHint();
+
+ int buttonHeight = qMax(perp(verticalTitleBar, closeSize),
+ perp(verticalTitleBar, floatSize));
+
+ QFontMetrics titleFontMetrics = q->fontMetrics();
+#ifdef Q_WS_MAC
+ if (qobject_cast<QMacStyle *>(q->style())) {
+ //### this breaks on proxy styles. (But is this code still called?)
+ QFont font = qt_app_fonts_hash()->value("QToolButton", q->font());
+ titleFontMetrics = QFontMetrics(font);
+ }
+#endif
+
+ int mw = q->style()->pixelMetric(QStyle::PM_DockWidgetTitleMargin, 0, q);
+
+ return qMax(buttonHeight + 2, titleFontMetrics.lineSpacing() + 2*mw);
+}
+
+void QDockWidgetLayout::setGeometry(const QRect &geometry)
+{
+ QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());
+
+ bool nativeDeco = nativeWindowDeco();
+
+ int fw = q->isFloating() && !nativeDeco
+ ? q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, q)
+ : 0;
+
+ if (nativeDeco) {
+ if (QLayoutItem *item = item_list[Content])
+ item->setGeometry(geometry);
+ } else {
+ int titleHeight = this->titleHeight();
+
+ if (verticalTitleBar) {
+ _titleArea = QRect(QPoint(fw, fw),
+ QSize(titleHeight, geometry.height() - (fw * 2)));
+ } else {
+ _titleArea = QRect(QPoint(fw, fw),
+ QSize(geometry.width() - (fw * 2), titleHeight));
+ }
+
+ if (QLayoutItem *item = item_list[TitleBar]) {
+ item->setGeometry(_titleArea);
+ } else {
+ QStyleOptionDockWidgetV2 opt;
+ q->initStyleOption(&opt);
+
+ if (QLayoutItem *item = item_list[CloseButton]) {
+ if (!item->isEmpty()) {
+ QRect r = q->style()
+ ->subElementRect(QStyle::SE_DockWidgetCloseButton,
+ &opt, q);
+ if (!r.isNull())
+ item->setGeometry(r);
+ }
+ }
+
+ if (QLayoutItem *item = item_list[FloatButton]) {
+ if (!item->isEmpty()) {
+ QRect r = q->style()
+ ->subElementRect(QStyle::SE_DockWidgetFloatButton,
+ &opt, q);
+ if (!r.isNull())
+ item->setGeometry(r);
+ }
+ }
+ }
+
+ if (QLayoutItem *item = item_list[Content]) {
+ QRect r = geometry;
+ if (verticalTitleBar) {
+ r.setLeft(_titleArea.right() + 1);
+ r.adjust(0, fw, -fw, -fw);
+ } else {
+ r.setTop(_titleArea.bottom() + 1);
+ r.adjust(fw, 0, -fw, -fw);
+ }
+ item->setGeometry(r);
+ }
+ }
+}
+
+void QDockWidgetLayout::setVerticalTitleBar(bool b)
+{
+ if (b == verticalTitleBar)
+ return;
+ verticalTitleBar = b;
+ invalidate();
+ parentWidget()->update();
+}
+
+/******************************************************************************
+** QDockWidgetItem
+*/
+
+QDockWidgetItem::QDockWidgetItem(QDockWidget *dockWidget)
+ : QWidgetItem(dockWidget)
+{
+}
+
+QSize QDockWidgetItem::minimumSize() const
+{
+ QSize widgetMin(0, 0);
+ if (QLayoutItem *item = dockWidgetChildItem())
+ widgetMin = item->minimumSize();
+ return dockWidgetLayout()->sizeFromContent(widgetMin, false);
+}
+
+QSize QDockWidgetItem::maximumSize() const
+{
+ if (QLayoutItem *item = dockWidgetChildItem()) {
+ return dockWidgetLayout()->sizeFromContent(item->maximumSize(), false);
+ } else {
+ return QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
+ }
+}
+
+
+QSize QDockWidgetItem::sizeHint() const
+{
+ if (QLayoutItem *item = dockWidgetChildItem()) {
+ return dockWidgetLayout()->sizeFromContent(item->sizeHint(), false);
+ } else {
+ return QWidgetItem::sizeHint();
+ }
+}
+
+/******************************************************************************
+** QDockWidgetPrivate
+*/
+
+void QDockWidgetPrivate::init()
+{
+ Q_Q(QDockWidget);
+
+ QDockWidgetLayout *layout = new QDockWidgetLayout(q);
+ layout->setSizeConstraint(QLayout::SetMinAndMaxSize);
+
+ QAbstractButton *button = new QDockWidgetTitleButton(q);
+ button->setObjectName(QLatin1String("qt_dockwidget_floatbutton"));
+ QObject::connect(button, SIGNAL(clicked()), q, SLOT(_q_toggleTopLevel()));
+ layout->setWidgetForRole(QDockWidgetLayout::FloatButton, button);
+
+ button = new QDockWidgetTitleButton(q);
+ button->setObjectName(QLatin1String("qt_dockwidget_closebutton"));
+ QObject::connect(button, SIGNAL(clicked()), q, SLOT(close()));
+ layout->setWidgetForRole(QDockWidgetLayout::CloseButton, button);
+
+ resizer = new QWidgetResizeHandler(q);
+ resizer->setMovingEnabled(false);
+ resizer->setActive(false);
+
+#ifndef QT_NO_ACTION
+ toggleViewAction = new QAction(q);
+ toggleViewAction->setCheckable(true);
+ fixedWindowTitle = qt_setWindowTitle_helperHelper(q->windowTitle(), q);
+ toggleViewAction->setText(fixedWindowTitle);
+ QObject::connect(toggleViewAction, SIGNAL(triggered(bool)),
+ q, SLOT(_q_toggleView(bool)));
+#endif
+
+ updateButtons();
+}
+
+/*!
+ Initialize \a option with the values from this QDockWidget. This method
+ is useful for subclasses when they need a QStyleOptionDockWidget, but don't want
+ to fill in all the information themselves.
+
+ \sa QStyleOption::initFrom()
+*/
+void QDockWidget::initStyleOption(QStyleOptionDockWidget *option) const
+{
+ Q_D(const QDockWidget);
+
+ if (!option)
+ return;
+ QDockWidgetLayout *dwlayout = qobject_cast<QDockWidgetLayout*>(layout());
+
+ option->initFrom(this);
+ option->rect = dwlayout->titleArea();
+ option->title = d->fixedWindowTitle;
+ option->closable = hasFeature(this, QDockWidget::DockWidgetClosable);
+ option->movable = hasFeature(this, QDockWidget::DockWidgetMovable);
+ option->floatable = hasFeature(this, QDockWidget::DockWidgetFloatable);
+
+ QDockWidgetLayout *l = qobject_cast<QDockWidgetLayout*>(layout());
+ QStyleOptionDockWidgetV2 *v2
+ = qstyleoption_cast<QStyleOptionDockWidgetV2*>(option);
+ if (v2 != 0)
+ v2->verticalTitleBar = l->verticalTitleBar;
+}
+
+void QDockWidgetPrivate::_q_toggleView(bool b)
+{
+ Q_Q(QDockWidget);
+ if (b == q->isHidden()) {
+ if (b)
+ q->show();
+ else
+ q->close();
+ }
+}
+
+void QDockWidgetPrivate::updateButtons()
+{
+ Q_Q(QDockWidget);
+ QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(q->layout());
+
+ QStyleOptionDockWidget opt;
+ q->initStyleOption(&opt);
+
+ bool customTitleBar = layout->widgetForRole(QDockWidgetLayout::TitleBar) != 0;
+ bool nativeDeco = layout->nativeWindowDeco();
+ bool hideButtons = nativeDeco || customTitleBar;
+
+ bool canClose = hasFeature(q, QDockWidget::DockWidgetClosable);
+ bool canFloat = hasFeature(q, QDockWidget::DockWidgetFloatable);
+
+ QAbstractButton *button
+ = qobject_cast<QAbstractButton*>(layout->widgetForRole(QDockWidgetLayout::FloatButton));
+ button->setIcon(q->style()->standardIcon(QStyle::SP_TitleBarNormalButton, &opt, q));
+ button->setVisible(canFloat && !hideButtons);
+
+ button
+ = qobject_cast <QAbstractButton*>(layout->widgetForRole(QDockWidgetLayout::CloseButton));
+ button->setIcon(q->style()->standardIcon(QStyle::SP_TitleBarCloseButton, &opt, q));
+ button->setVisible(canClose && !hideButtons);
+
+ q->setAttribute(Qt::WA_ContentsPropagated,
+ (canFloat || canClose) && !hideButtons);
+
+ layout->invalidate();
+}
+
+void QDockWidgetPrivate::_q_toggleTopLevel()
+{
+ Q_Q(QDockWidget);
+ q->setFloating(!q->isFloating());
+}
+
+void QDockWidgetPrivate::initDrag(const QPoint &pos, bool nca)
+{
+ Q_Q(QDockWidget);
+
+ if (state != 0)
+ return;
+
+ QMainWindow *win = qobject_cast<QMainWindow*>(q->parentWidget());
+ Q_ASSERT(win != 0);
+ QMainWindowLayout *layout = qobject_cast<QMainWindowLayout*>(win->layout());
+ Q_ASSERT(layout != 0);
+ if (layout->layoutState.indexOf(q).isEmpty()) //The dock widget has not been added into the main window
+ return;
+ if (layout->pluggingWidget != 0) // the main window is animating a docking operation
+ return;
+
+ state = new QDockWidgetPrivate::DragState;
+ state->pressPos = pos;
+ state->dragging = false;
+ state->widgetItem = 0;
+ state->ownWidgetItem = false;
+ state->nca = nca;
+ state->ctrlDrag = false;
+}
+
+void QDockWidgetPrivate::startDrag()
+{
+ Q_Q(QDockWidget);
+
+ if (state == 0 || state->dragging)
+ return;
+
+ QMainWindowLayout *layout
+ = qobject_cast<QMainWindowLayout *>(q->parentWidget()->layout());
+ Q_ASSERT(layout != 0);
+
+ state->widgetItem = layout->unplug(q);
+ if (state->widgetItem == 0) {
+ /* I have a QMainWindow parent, but I was never inserted with
+ QMainWindow::addDockWidget, so the QMainWindowLayout has no
+ widget item for me. :( I have to create it myself, and then
+ delete it if I don't get dropped into a dock area. */
+ state->widgetItem = new QDockWidgetItem(q);
+ state->ownWidgetItem = true;
+ }
+
+ if (state->ctrlDrag)
+ layout->restore();
+
+ state->dragging = true;
+}
+
+void QDockWidgetPrivate::endDrag(bool abort)
+{
+ Q_Q(QDockWidget);
+ Q_ASSERT(state != 0);
+
+ q->releaseMouse();
+
+ if (state->dragging) {
+ QMainWindowLayout *layout =
+ qobject_cast<QMainWindowLayout *>(q->parentWidget()->layout());
+ Q_ASSERT(layout != 0);
+
+ if (abort || !layout->plug(state->widgetItem)) {
+ if (hasFeature(q, QDockWidget::DockWidgetFloatable)) {
+ if (state->ownWidgetItem)
+ delete state->widgetItem;
+ layout->restore();
+#ifdef Q_WS_X11
+ // get rid of the X11BypassWindowManager window flag and activate the resizer
+ Qt::WindowFlags flags = q->windowFlags();
+ flags &= ~Qt::X11BypassWindowManagerHint;
+ q->setWindowFlags(flags);
+ resizer->setActive(QWidgetResizeHandler::Resize, true);
+ q->show();
+#else
+ QDockWidgetLayout *myLayout
+ = qobject_cast<QDockWidgetLayout*>(q->layout());
+ resizer->setActive(QWidgetResizeHandler::Resize,
+ myLayout->widgetForRole(QDockWidgetLayout::TitleBar) != 0);
+#endif
+ undockedGeometry = q->geometry();
+ q->activateWindow();
+ } else {
+ layout->revert(state->widgetItem);
+ }
+ }
+ }
+ delete state;
+ state = 0;
+}
+
+bool QDockWidgetPrivate::isAnimating() const
+{
+ Q_Q(const QDockWidget);
+
+ QMainWindow *mainWin = qobject_cast<QMainWindow*>(q->parentWidget());
+ if (mainWin == 0)
+ return false;
+
+ QMainWindowLayout *mainWinLayout
+ = qobject_cast<QMainWindowLayout*>(mainWin->layout());
+ if (mainWinLayout == 0)
+ return false;
+
+ return (void*)mainWinLayout->pluggingWidget == (void*)q;
+}
+
+bool QDockWidgetPrivate::mousePressEvent(QMouseEvent *event)
+{
+#if !defined(QT_NO_MAINWINDOW)
+ Q_Q(QDockWidget);
+
+ QDockWidgetLayout *layout
+ = qobject_cast<QDockWidgetLayout*>(q->layout());
+
+ if (!layout->nativeWindowDeco()) {
+ QRect titleArea = layout->titleArea();
+
+ if (event->button() != Qt::LeftButton ||
+ !titleArea.contains(event->pos()) ||
+ // check if the tool window is movable... do nothing if it
+ // is not (but allow moving if the window is floating)
+ (!hasFeature(q, QDockWidget::DockWidgetMovable) && !q->isFloating()) ||
+ qobject_cast<QMainWindow*>(q->parentWidget()) == 0 ||
+ isAnimating() || state != 0) {
+ return false;
+ }
+
+ initDrag(event->pos(), false);
+
+ if (state)
+ state->ctrlDrag = hasFeature(q, QDockWidget::DockWidgetFloatable) && event->modifiers() & Qt::ControlModifier;
+
+ return true;
+ }
+
+#endif // !defined(QT_NO_MAINWINDOW)
+ return false;
+}
+
+bool QDockWidgetPrivate::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ Q_Q(QDockWidget);
+
+ QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(q->layout());
+
+ if (!layout->nativeWindowDeco()) {
+ QRect titleArea = layout->titleArea();
+
+ if (event->button() == Qt::LeftButton && titleArea.contains(event->pos()) &&
+ hasFeature(q, QDockWidget::DockWidgetFloatable)) {
+ _q_toggleTopLevel();
+ return true;
+ }
+ }
+ return false;
+}
+
+bool QDockWidgetPrivate::mouseMoveEvent(QMouseEvent *event)
+{
+ bool ret = false;
+#if !defined(QT_NO_MAINWINDOW)
+ Q_Q(QDockWidget);
+
+ if (!state)
+ return ret;
+
+ QDockWidgetLayout *dwlayout
+ = qobject_cast<QDockWidgetLayout*>(q->layout());
+ QMainWindowLayout *mwlayout
+ = qobject_cast<QMainWindowLayout*>(q->parentWidget()->layout());
+ if (!dwlayout->nativeWindowDeco()) {
+ if (!state->dragging
+ && mwlayout->pluggingWidget == 0
+ && (event->pos() - state->pressPos).manhattanLength()
+ > QApplication::startDragDistance()) {
+ startDrag();
+#ifdef Q_OS_WIN
+ grabMouseWhileInWindow();
+#else
+ q->grabMouse();
+#endif
+ ret = true;
+ }
+ }
+
+ if (state->dragging && !state->nca) {
+ QPoint pos = event->globalPos() - state->pressPos;
+ q->move(pos);
+
+ if (!state->ctrlDrag)
+ mwlayout->hover(state->widgetItem, event->globalPos());
+
+ ret = true;
+ }
+
+#endif // !defined(QT_NO_MAINWINDOW)
+ return ret;
+}
+
+bool QDockWidgetPrivate::mouseReleaseEvent(QMouseEvent *event)
+{
+#if !defined(QT_NO_MAINWINDOW)
+
+ if (event->button() == Qt::LeftButton && state && !state->nca) {
+ endDrag();
+ return true; //filter out the event
+ }
+
+#endif // !defined(QT_NO_MAINWINDOW)
+ return false;
+}
+
+void QDockWidgetPrivate::nonClientAreaMouseEvent(QMouseEvent *event)
+{
+ Q_Q(QDockWidget);
+
+ int fw = q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, q);
+
+ QRect geo = q->geometry();
+ QRect titleRect = q->frameGeometry();
+#ifdef Q_WS_MAC
+ if ((features & QDockWidget::DockWidgetVerticalTitleBar)) {
+ titleRect.setTop(geo.top());
+ titleRect.setBottom(geo.bottom());
+ titleRect.setRight(geo.left() - 1);
+ } else
+#endif
+ {
+ titleRect.setLeft(geo.left());
+ titleRect.setRight(geo.right());
+ titleRect.setBottom(geo.top() - 1);
+ titleRect.adjust(0, fw, 0, 0);
+ }
+
+ switch (event->type()) {
+ case QEvent::NonClientAreaMouseButtonPress:
+ if (!titleRect.contains(event->globalPos()))
+ break;
+ if (state != 0)
+ break;
+ if (qobject_cast<QMainWindow*>(q->parentWidget()) == 0)
+ break;
+ if (isAnimating())
+ break;
+ initDrag(event->pos(), true);
+ if (state == 0)
+ break;
+#ifdef Q_OS_WIN
+ // On Windows, NCA mouse events don't contain modifier info
+ state->ctrlDrag = GetKeyState(VK_CONTROL) & 0x8000;
+#else
+ state->ctrlDrag = event->modifiers() & Qt::ControlModifier;
+#endif
+ startDrag();
+ break;
+ case QEvent::NonClientAreaMouseMove:
+ if (state == 0 || !state->dragging)
+ break;
+ if (state->nca) {
+ endDrag();
+ }
+#ifdef Q_OS_MAC
+ else { // workaround for lack of mouse-grab on Mac
+ QMainWindowLayout *layout
+ = qobject_cast<QMainWindowLayout *>(q->parentWidget()->layout());
+ Q_ASSERT(layout != 0);
+
+ q->move(event->globalPos() - state->pressPos);
+ if (!state->ctrlDrag)
+ layout->hover(state->widgetItem, event->globalPos());
+ }
+#endif
+ break;
+ case QEvent::NonClientAreaMouseButtonRelease:
+#ifdef Q_OS_MAC
+ if (state)
+ endDrag();
+#endif
+ break;
+ case QEvent::NonClientAreaMouseButtonDblClick:
+ _q_toggleTopLevel();
+ break;
+ default:
+ break;
+ }
+}
+
+void QDockWidgetPrivate::moveEvent(QMoveEvent *event)
+{
+ Q_Q(QDockWidget);
+
+ if (state == 0 || !state->dragging || !state->nca || !q->isWindow())
+ return;
+
+ // When the native window frame is being dragged, all we get is these mouse
+ // move events.
+
+ if (state->ctrlDrag)
+ return;
+
+ QMainWindowLayout *layout
+ = qobject_cast<QMainWindowLayout *>(q->parentWidget()->layout());
+ Q_ASSERT(layout != 0);
+
+ QPoint globalMousePos = event->pos() + state->pressPos;
+ layout->hover(state->widgetItem, globalMousePos);
+}
+
+void QDockWidgetPrivate::unplug(const QRect &rect)
+{
+ Q_Q(QDockWidget);
+ QRect r = rect;
+ r.moveTopLeft(q->mapToGlobal(QPoint(0, 0)));
+ QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(q->layout());
+ if (layout->nativeWindowDeco(true))
+ r.adjust(0, layout->titleHeight(), 0, 0);
+ setWindowState(true, true, r);
+}
+
+void QDockWidgetPrivate::plug(const QRect &rect)
+{
+ setWindowState(false, false, rect);
+}
+
+void QDockWidgetPrivate::setWindowState(bool floating, bool unplug, const QRect &rect)
+{
+ Q_Q(QDockWidget);
+
+ bool wasFloating = q->isFloating();
+ bool hidden = q->isHidden();
+
+ if (q->isVisible())
+ q->hide();
+
+ Qt::WindowFlags flags = floating ? Qt::Tool : Qt::Widget;
+
+ QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(q->layout());
+ const bool nativeDeco = layout->nativeWindowDeco(floating);
+
+ if (nativeDeco) {
+ flags |= Qt::CustomizeWindowHint | Qt::WindowTitleHint;
+ if (hasFeature(q, QDockWidget::DockWidgetClosable))
+ flags |= Qt::WindowCloseButtonHint;
+ } else {
+ flags |= Qt::FramelessWindowHint;
+ }
+
+ if (unplug)
+ flags |= Qt::X11BypassWindowManagerHint;
+
+ q->setWindowFlags(flags);
+
+#if defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA)
+ if (floating && nativeDeco && (q->features() & QDockWidget::DockWidgetVerticalTitleBar)) {
+ ChangeWindowAttributes(HIViewGetWindow(HIViewRef(q->winId())), kWindowSideTitlebarAttribute, 0);
+ }
+#endif
+
+ if (!rect.isNull())
+ q->setGeometry(rect);
+
+ updateButtons();
+
+ if (!hidden)
+ q->show();
+
+ if (floating != wasFloating) {
+ emit q->topLevelChanged(floating);
+ if (!floating && q->parentWidget()) {
+ QMainWindowLayout *mwlayout = qobject_cast<QMainWindowLayout *>(q->parentWidget()->layout());
+ if (mwlayout)
+ emit q->dockLocationChanged(mwlayout->dockWidgetArea(q));
+ }
+ }
+
+ resizer->setActive(QWidgetResizeHandler::Resize, !unplug && floating && !nativeDeco);
+}
+
+/*!
+ \class QDockWidget
+
+ \brief The QDockWidget class provides a widget that can be docked
+ inside a QMainWindow or floated as a top-level window on the
+ desktop.
+
+ \ingroup application
+
+ QDockWidget provides the concept of dock widgets, also know as
+ tool palettes or utility windows. Dock windows are secondary
+ windows placed in the \e {dock widget area} around the
+ \l{QMainWindow::centralWidget()}{central widget} in a
+ QMainWindow.
+
+ \image mainwindow-docks.png
+
+ Dock windows can be moved inside their current area, moved into
+ new areas and floated (e.g., undocked) by the end-user. The
+ QDockWidget API allows the programmer to restrict the dock widgets
+ ability to move, float and close, as well as the areas in which
+ they can be placed.
+
+ \section1 Appearance
+
+ A QDockWidget consists of a title bar and the content area. The
+ title bar displays the dock widgets \link QWidget::windowTitle()
+ window title\endlink, a \e float button and a \e close button.
+ Depending on the state of the QDockWidget, the \e float and \e
+ close buttons may be either disabled or not shown at all.
+
+ The visual appearance of the title bar and buttons is dependent
+ on the \l{QStyle}{style} in use.
+
+ A QDockWidget acts as a wrapper for its child widget, set with setWidget().
+ Custom size hints, minimum and maximum sizes and size policies should be
+ implemented in the child widget. QDockWidget will respect them, adjusting
+ its own constraints to include the frame and title. Size constraints
+ should not be set on the QDockWidget itself, because they change depending
+ on whether it is docked; a docked QDockWidget has no frame and a smaller title
+ bar.
+
+ \sa QMainWindow, {Dock Widgets Example}
+*/
+
+/*!
+ \enum QDockWidget::DockWidgetFeature
+
+ \value DockWidgetClosable The dock widget can be closed. On some systems the dock
+ widget always has a close button when it's floating
+ (for example on MacOS 10.5).
+ \value DockWidgetMovable The dock widget can be moved between docks
+ by the user.
+ \value DockWidgetFloatable The dock widget can be detached from the
+ main window, and floated as an independent
+ window.
+ \value DockWidgetVerticalTitleBar The dock widget displays a vertical title
+ bar on its left side. This can be used to
+ increase the amount of vertical space in
+ a QMainWindow.
+ \value AllDockWidgetFeatures (Deprecated) The dock widget can be closed, moved,
+ and floated. Since new features might be added in future
+ releases, the look and behavior of dock widgets might
+ change if you use this flag. Please specify individual
+ flags instead.
+ \value NoDockWidgetFeatures The dock widget cannot be closed, moved,
+ or floated.
+
+ \omitvalue DockWidgetFeatureMask
+ \omitvalue Reserved
+*/
+
+/*!
+ \property QDockWidget::windowTitle
+ \internal
+
+ By default, this property contains an empty string.
+*/
+
+/*!
+ Constructs a QDockWidget with parent \a parent and window flags \a
+ flags. The dock widget will be placed in the left dock widget
+ area.
+*/
+QDockWidget::QDockWidget(QWidget *parent, Qt::WindowFlags flags)
+ : QWidget(*new QDockWidgetPrivate, parent, flags)
+{
+ Q_D(QDockWidget);
+ d->init();
+}
+
+/*!
+ Constructs a QDockWidget with parent \a parent and window flags \a
+ flags. The dock widget will be placed in the left dock widget
+ area.
+
+ The window title is set to \a title. This title is used when the
+ QDockWidget is docked and undocked. It is also used in the context
+ menu provided by QMainWindow.
+
+ \sa setWindowTitle()
+*/
+QDockWidget::QDockWidget(const QString &title, QWidget *parent, Qt::WindowFlags flags)
+ : QWidget(*new QDockWidgetPrivate, parent, flags)
+{
+ Q_D(QDockWidget);
+ d->init();
+ setWindowTitle(title);
+}
+
+/*!
+ Destroys the dock widget.
+*/
+QDockWidget::~QDockWidget()
+{ }
+
+/*!
+ Returns the widget for the dock widget. This function returns zero
+ if the widget has not been set.
+
+ \sa setWidget()
+*/
+QWidget *QDockWidget::widget() const
+{
+ QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(this->layout());
+ return layout->widgetForRole(QDockWidgetLayout::Content);
+}
+
+/*!
+ Sets the widget for the dock widget to \a widget.
+
+ If the dock widget is visible when \a widget is added, you must
+ \l{QWidget::}{show()} it explicitly.
+
+ Note that you must add the layout of the \a widget before you call
+ this function; if not, the \a widget will not be visible.
+
+ \sa widget()
+*/
+void QDockWidget::setWidget(QWidget *widget)
+{
+ QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(this->layout());
+ layout->setWidgetForRole(QDockWidgetLayout::Content, widget);
+}
+
+/*!
+ \property QDockWidget::features
+ \brief whether the dock widget is movable, closable, and floatable
+
+ By default, this property is set to a combination of DockWidgetClosable,
+ DockWidgetMovable and DockWidgetFloatable.
+
+ \sa DockWidgetFeature
+*/
+
+void QDockWidget::setFeatures(QDockWidget::DockWidgetFeatures features)
+{
+ Q_D(QDockWidget);
+ features &= DockWidgetFeatureMask;
+ if (d->features == features)
+ return;
+ d->features = features;
+ QDockWidgetLayout *layout
+ = qobject_cast<QDockWidgetLayout*>(this->layout());
+ layout->setVerticalTitleBar(features & DockWidgetVerticalTitleBar);
+ d->updateButtons();
+ d->toggleViewAction->setEnabled((d->features & DockWidgetClosable) == DockWidgetClosable);
+ emit featuresChanged(d->features);
+ update();
+}
+
+QDockWidget::DockWidgetFeatures QDockWidget::features() const
+{
+ Q_D(const QDockWidget);
+ return d->features;
+}
+
+/*!
+ \property QDockWidget::floating
+ \brief whether the dock widget is floating
+
+ A floating dock widget is presented to the user as an independent
+ window "on top" of its parent QMainWindow, instead of being
+ docked in the QMainWindow.
+
+ By default, this property is true.
+
+ \sa isWindow()
+*/
+void QDockWidget::setFloating(bool floating)
+{
+ Q_D(QDockWidget);
+
+ // the initial click of a double-click may have started a drag...
+ if (d->state != 0)
+ d->endDrag(true);
+
+ QRect r = d->undockedGeometry;
+
+ d->setWindowState(floating, false, floating ? r : QRect());
+ if (floating && r.isNull()) {
+ QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(this->layout());
+ QRect titleArea = layout->titleArea();
+ int h = layout->verticalTitleBar ? titleArea.width() : titleArea.height();
+ QPoint p = mapToGlobal(QPoint(h, h));
+ move(p);
+ }
+}
+
+/*!
+ \property QDockWidget::allowedAreas
+ \brief areas where the dock widget may be placed
+
+ The default is Qt::AllDockWidgetAreas.
+
+ \sa Qt::DockWidgetArea
+*/
+
+void QDockWidget::setAllowedAreas(Qt::DockWidgetAreas areas)
+{
+ Q_D(QDockWidget);
+ areas &= Qt::DockWidgetArea_Mask;
+ if (areas == d->allowedAreas)
+ return;
+ d->allowedAreas = areas;
+ emit allowedAreasChanged(d->allowedAreas);
+}
+
+Qt::DockWidgetAreas QDockWidget::allowedAreas() const
+{
+ Q_D(const QDockWidget);
+ return d->allowedAreas;
+}
+
+/*!
+ \fn bool QDockWidget::isAreaAllowed(Qt::DockWidgetArea area) const
+
+ Returns true if this dock widget can be placed in the given \a area;
+ otherwise returns false.
+*/
+
+/*! \reimp */
+void QDockWidget::changeEvent(QEvent *event)
+{
+ Q_D(QDockWidget);
+ QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(this->layout());
+
+ switch (event->type()) {
+ case QEvent::ModifiedChange:
+ case QEvent::WindowTitleChange:
+ update(layout->titleArea());
+#ifndef QT_NO_ACTION
+ d->fixedWindowTitle = qt_setWindowTitle_helperHelper(windowTitle(), this);
+ d->toggleViewAction->setText(d->fixedWindowTitle);
+#endif
+#ifndef QT_NO_TABBAR
+ {
+ QMainWindow *win = qobject_cast<QMainWindow*>(parentWidget());
+ if (QMainWindowLayout *winLayout =
+ (win ? qobject_cast<QMainWindowLayout*>(win->layout()) : 0))
+ if (QDockAreaLayoutInfo *info =
+ (winLayout ? winLayout->layoutState.dockAreaLayout.info(this) : 0))
+ info->updateTabBar();
+ }
+#endif // QT_NO_TABBAR
+ break;
+ default:
+ break;
+ }
+ QWidget::changeEvent(event);
+}
+
+/*! \reimp */
+void QDockWidget::closeEvent(QCloseEvent *event)
+{
+ Q_D(QDockWidget);
+ if (d->state)
+ d->endDrag(true);
+ QWidget::closeEvent(event);
+}
+
+/*! \reimp */
+void QDockWidget::paintEvent(QPaintEvent *event)
+{
+ Q_UNUSED(event)
+
+ QDockWidgetLayout *layout
+ = qobject_cast<QDockWidgetLayout*>(this->layout());
+ bool customTitleBar = layout->widgetForRole(QDockWidgetLayout::TitleBar) != 0;
+ bool nativeDeco = layout->nativeWindowDeco();
+
+ if (!nativeDeco && !customTitleBar) {
+ QStylePainter p(this);
+ // ### Add PixelMetric to change spacers, so style may show border
+ // when not floating.
+ if (isFloating()) {
+ QStyleOptionFrame framOpt;
+ framOpt.init(this);
+ p.drawPrimitive(QStyle::PE_FrameDockWidget, framOpt);
+ }
+
+ // Title must be painted after the frame, since the areas overlap, and
+ // the title may wish to extend out to all sides (eg. XP style)
+ QStyleOptionDockWidgetV2 titleOpt;
+ initStyleOption(&titleOpt);
+ p.drawControl(QStyle::CE_DockWidgetTitle, titleOpt);
+ }
+}
+
+/*! \reimp */
+bool QDockWidget::event(QEvent *event)
+{
+ Q_D(QDockWidget);
+
+ QMainWindow *win = qobject_cast<QMainWindow*>(parentWidget());
+ QMainWindowLayout *layout = 0;
+ if (win != 0)
+ layout = qobject_cast<QMainWindowLayout*>(win->layout());
+
+ switch (event->type()) {
+#ifndef QT_NO_ACTION
+ case QEvent::Hide:
+ if (layout != 0)
+ layout->keepSize(this);
+ d->toggleViewAction->setChecked(false);
+ emit visibilityChanged(false);
+ break;
+ case QEvent::Show:
+ d->toggleViewAction->setChecked(true);
+ emit visibilityChanged(true);
+ break;
+#endif
+ case QEvent::ApplicationLayoutDirectionChange:
+ case QEvent::LayoutDirectionChange:
+ case QEvent::StyleChange:
+ case QEvent::ParentChange:
+ d->updateButtons();
+ break;
+ case QEvent::ZOrderChange: {
+ bool onTop = false;
+ if (win != 0) {
+ const QObjectList &siblings = win->children();
+ onTop = siblings.count() > 0 && siblings.last() == (QObject*)this;
+ }
+ if (!isFloating() && layout != 0 && onTop)
+ layout->raise(this);
+ break;
+ }
+ case QEvent::WindowActivate:
+ case QEvent::WindowDeactivate:
+ update(qobject_cast<QDockWidgetLayout *>(this->layout())->titleArea());
+ break;
+ case QEvent::ContextMenu:
+ if (d->state) {
+ event->accept();
+ return true;
+ }
+ break;
+ // return true after calling the handler since we don't want
+ // them to be passed onto the default handlers
+ case QEvent::MouseButtonPress:
+ if (d->mousePressEvent(static_cast<QMouseEvent *>(event)))
+ return true;
+ break;
+ case QEvent::MouseButtonDblClick:
+ if (d->mouseDoubleClickEvent(static_cast<QMouseEvent *>(event)))
+ return true;
+ break;
+ case QEvent::MouseMove:
+ if (d->mouseMoveEvent(static_cast<QMouseEvent *>(event)))
+ return true;
+ break;
+#ifdef Q_OS_WIN
+ case QEvent::Leave:
+ if (d->state != 0 && d->state->dragging && !d->state->nca) {
+ // 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);
+ }
+ break;
+#endif
+ case QEvent::MouseButtonRelease:
+ if (d->mouseReleaseEvent(static_cast<QMouseEvent *>(event)))
+ return true;
+ break;
+ case QEvent::NonClientAreaMouseMove:
+ case QEvent::NonClientAreaMouseButtonPress:
+ case QEvent::NonClientAreaMouseButtonRelease:
+ case QEvent::NonClientAreaMouseButtonDblClick:
+ d->nonClientAreaMouseEvent(static_cast<QMouseEvent*>(event));
+ return true;
+ case QEvent::Move:
+ d->moveEvent(static_cast<QMoveEvent*>(event));
+ break;
+ case QEvent::Resize:
+ // if the mainwindow is plugging us, we don't want to update undocked geometry
+ if (isFloating() && layout != 0 && layout->pluggingWidget != this)
+ d->undockedGeometry = geometry();
+ break;
+ default:
+ break;
+ }
+ return QWidget::event(event);
+}
+
+#ifndef QT_NO_ACTION
+/*!
+ Returns a checkable action that can be used to show or close this
+ dock widget.
+
+ The action's text is set to the dock widget's window title.
+
+ \sa QAction::text QWidget::windowTitle
+ */
+QAction * QDockWidget::toggleViewAction() const
+{
+ Q_D(const QDockWidget);
+ return d->toggleViewAction;
+}
+#endif // QT_NO_ACTION
+
+/*!
+ \fn void QDockWidget::featuresChanged(QDockWidget::DockWidgetFeatures features)
+
+ This signal is emitted when the \l features property changes. The
+ \a features parameter gives the new value of the property.
+*/
+
+/*!
+ \fn void QDockWidget::topLevelChanged(bool topLevel)
+
+ This signal is emitted when the \l floating property changes.
+ The \a topLevel parameter is true if the dock widget is now floating;
+ otherwise it is false.
+
+ \sa isWindow()
+*/
+
+/*!
+ \fn void QDockWidget::allowedAreasChanged(Qt::DockWidgetAreas allowedAreas)
+
+ This signal is emitted when the \l allowedAreas property changes. The
+ \a allowedAreas parameter gives the new value of the property.
+*/
+
+/*!
+ \fn void QDockWidget::visibilityChanged(bool visible)
+ \since 4.3
+
+ This signal is emitted when the dock widget becomes \a visible (or
+ invisible). This happens when the widget is hidden or shown, as
+ well as when it is docked in a tabbed dock area and its tab
+ becomes selected or unselected.
+*/
+
+/*!
+ \fn void QDockWidget::dockLocationChanged(Qt::DockWidgetArea area)
+ \since 4.3
+
+ This signal is emitted when the dock widget is moved to another
+ dock \a area, or is moved to a different location in its current
+ dock area. This happens when the dock widget is moved
+ programmatically or is dragged to a new location by the user.
+*/
+
+/*!
+ \since 4.3
+ Sets an arbitrary \a widget as the dock widget's title bar. If \a widget
+ is 0, the title bar widget is removed, but not deleted.
+
+ If a title bar widget is set, QDockWidget will not use native window
+ decorations when it is floated.
+
+ Here are some tips for implementing custom title bars:
+
+ \list
+ \i Mouse events that are not explicitly handled by the title bar widget
+ must be ignored by calling QMouseEvent::ignore(). These events then
+ propagate to the QDockWidget parent, which handles them in the usual
+ manner, moving when the title bar is dragged, docking and undocking
+ when it is double-clicked, etc.
+
+ \i When DockWidgetVerticalTitleBar is set on QDockWidget, the title
+ bar widget is repositioned accordingly. In resizeEvent(), the title
+ bar should check what orientation it should assume:
+ \snippet doc/src/snippets/code/src_gui_widgets_qdockwidget.cpp 0
+
+ \i The title bar widget must have a valid QWidget::sizeHint() and
+ QWidget::minimumSizeHint(). These functions should take into account
+ the current orientation of the title bar.
+ \endlist
+
+ Using qobject_cast as shown above, the title bar widget has full access
+ to its parent QDockWidget. Hence it can perform such operations as docking
+ and hiding in response to user actions.
+
+ \sa titleBarWidget() DockWidgetVerticalTitleBar
+*/
+
+void QDockWidget::setTitleBarWidget(QWidget *widget)
+{
+ Q_D(QDockWidget);
+ QDockWidgetLayout *layout
+ = qobject_cast<QDockWidgetLayout*>(this->layout());
+ layout->setWidgetForRole(QDockWidgetLayout::TitleBar, widget);
+ d->updateButtons();
+ if (isWindow()) {
+ //this ensures the native decoration is drawn
+ d->setWindowState(true /*floating*/, true /*unplug*/);
+ }
+}
+
+/*!
+ \since 4.3
+ Returns the custom title bar widget set on the QDockWidget, or 0 if no
+ custom title bar has been set.
+
+ \sa setTitleBarWidget()
+*/
+
+QWidget *QDockWidget::titleBarWidget() const
+{
+ QDockWidgetLayout *layout
+ = qobject_cast<QDockWidgetLayout*>(this->layout());
+ return layout->widgetForRole(QDockWidgetLayout::TitleBar);
+}
+
+QT_END_NAMESPACE
+
+#include "qdockwidget.moc"
+#include "moc_qdockwidget.cpp"
+
+#endif // QT_NO_DOCKWIDGET