source: trunk/src/gui/widgets/qdockwidget.cpp@ 871

Last change on this file since 871 was 846, checked in by Dmitry A. Kuminov, 14 years ago

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

File size: 48.6 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 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 "qdockwidget.h"
43
44#ifndef QT_NO_DOCKWIDGET
45#include <qaction.h>
46#include <qapplication.h>
47#include <qdesktopwidget.h>
48#include <qdrawutil.h>
49#include <qevent.h>
50#include <qfontmetrics.h>
51#include <qmainwindow.h>
52#include <qrubberband.h>
53#include <qstylepainter.h>
54#include <qtoolbutton.h>
55#include <qdebug.h>
56
57#include <private/qwidgetresizehandler_p.h>
58
59#include "qdockwidget_p.h"
60#include "qmainwindowlayout_p.h"
61#ifdef Q_WS_MAC
62#include <private/qapplication_p.h>
63#include <private/qt_mac_p.h>
64#include <qmacstyle_mac.h>
65#endif
66
67QT_BEGIN_NAMESPACE
68
69extern QString qt_setWindowTitle_helperHelper(const QString&, const QWidget*); // qwidget.cpp
70
71// qmainwindow.cpp
72extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *window);
73
74static inline bool hasFeature(const QDockWidgetPrivate *priv, QDockWidget::DockWidgetFeature feature)
75{ return (priv->features & feature) == feature; }
76
77static inline bool hasFeature(const QDockWidget *dockwidget, QDockWidget::DockWidgetFeature feature)
78{ return (dockwidget->features() & feature) == feature; }
79
80
81/*
82 A Dock Window:
83
84 [+] is the float button
85 [X] is the close button
86
87 +-------------------------------+
88 | Dock Window Title [+][X]|
89 +-------------------------------+
90 | |
91 | place to put the single |
92 | QDockWidget child (this space |
93 | does not yet have a name) |
94 | |
95 | |
96 | |
97 | |
98 | |
99 | |
100 | |
101 | |
102 | |
103 +-------------------------------+
104
105*/
106
107/******************************************************************************
108** QDockWidgetTitleButton
109*/
110
111class QDockWidgetTitleButton : public QAbstractButton
112{
113 Q_OBJECT
114
115public:
116 QDockWidgetTitleButton(QDockWidget *dockWidget);
117
118 QSize sizeHint() const;
119 inline QSize minimumSizeHint() const
120 { return sizeHint(); }
121
122 void enterEvent(QEvent *event);
123 void leaveEvent(QEvent *event);
124 void paintEvent(QPaintEvent *event);
125};
126
127
128QDockWidgetTitleButton::QDockWidgetTitleButton(QDockWidget *dockWidget)
129 : QAbstractButton(dockWidget)
130{
131 setFocusPolicy(Qt::NoFocus);
132}
133
134QSize QDockWidgetTitleButton::sizeHint() const
135{
136 ensurePolished();
137
138 int size = 2*style()->pixelMetric(QStyle::PM_DockWidgetTitleBarButtonMargin, 0, this);
139 if (!icon().isNull()) {
140 int iconSize = style()->pixelMetric(QStyle::PM_SmallIconSize, 0, this);
141 QSize sz = icon().actualSize(QSize(iconSize, iconSize));
142 size += qMax(sz.width(), sz.height());
143 }
144
145 return QSize(size, size);
146}
147
148void QDockWidgetTitleButton::enterEvent(QEvent *event)
149{
150 if (isEnabled()) update();
151 QAbstractButton::enterEvent(event);
152}
153
154void QDockWidgetTitleButton::leaveEvent(QEvent *event)
155{
156 if (isEnabled()) update();
157 QAbstractButton::leaveEvent(event);
158}
159
160void QDockWidgetTitleButton::paintEvent(QPaintEvent *)
161{
162 QPainter p(this);
163
164 QRect r = rect();
165 QStyleOptionToolButton opt;
166 opt.init(this);
167 opt.state |= QStyle::State_AutoRaise;
168
169 if (style()->styleHint(QStyle::SH_DockWidget_ButtonsHaveFrame, 0, this))
170 {
171 if (isEnabled() && underMouse() && !isChecked() && !isDown())
172 opt.state |= QStyle::State_Raised;
173 if (isChecked())
174 opt.state |= QStyle::State_On;
175 if (isDown())
176 opt.state |= QStyle::State_Sunken;
177 style()->drawPrimitive(QStyle::PE_PanelButtonTool, &opt, &p, this);
178 }
179
180 opt.icon = icon();
181 opt.subControls = 0;
182 opt.activeSubControls = 0;
183 opt.features = QStyleOptionToolButton::None;
184 opt.arrowType = Qt::NoArrow;
185 int size = style()->pixelMetric(QStyle::PM_SmallIconSize, 0, this);
186 opt.iconSize = QSize(size, size);
187 style()->drawComplexControl(QStyle::CC_ToolButton, &opt, &p, this);
188}
189
190/******************************************************************************
191** QDockWidgetLayout
192*/
193
194QDockWidgetLayout::QDockWidgetLayout(QWidget *parent)
195 : QLayout(parent), verticalTitleBar(false), item_list(RoleCount, 0)
196{
197}
198
199QDockWidgetLayout::~QDockWidgetLayout()
200{
201 qDeleteAll(item_list);
202}
203
204bool QDockWidgetLayout::nativeWindowDeco() const
205{
206 return nativeWindowDeco(parentWidget()->isWindow());
207}
208
209bool QDockWidgetLayout::nativeWindowDeco(bool floating) const
210{
211#if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_WS_WINCE)
212 Q_UNUSED(floating);
213 return false;
214#else
215 return floating && item_list[QDockWidgetLayout::TitleBar] == 0;
216#endif
217}
218
219
220void QDockWidgetLayout::addItem(QLayoutItem*)
221{
222 qWarning() << "QDockWidgetLayout::addItem(): please use QDockWidgetLayout::setWidget()";
223 return;
224}
225
226QLayoutItem *QDockWidgetLayout::itemAt(int index) const
227{
228 int cnt = 0;
229 for (int i = 0; i < item_list.count(); ++i) {
230 QLayoutItem *item = item_list.at(i);
231 if (item == 0)
232 continue;
233 if (index == cnt++)
234 return item;
235 }
236 return 0;
237}
238
239QLayoutItem *QDockWidgetLayout::takeAt(int index)
240{
241 int j = 0;
242 for (int i = 0; i < item_list.count(); ++i) {
243 QLayoutItem *item = item_list.at(i);
244 if (item == 0)
245 continue;
246 if (index == j) {
247 item_list[i] = 0;
248 invalidate();
249 return item;
250 }
251 ++j;
252 }
253 return 0;
254}
255
256int QDockWidgetLayout::count() const
257{
258 int result = 0;
259 for (int i = 0; i < item_list.count(); ++i) {
260 if (item_list.at(i))
261 ++result;
262 }
263 return result;
264}
265
266QSize QDockWidgetLayout::sizeFromContent(const QSize &content, bool floating) const
267{
268 QSize result = content;
269
270 if (verticalTitleBar) {
271 result.setHeight(qMax(result.height(), minimumTitleWidth()));
272 result.setWidth(qMax(content.width(), 0));
273 } else {
274 result.setHeight(qMax(result.height(), 0));
275 result.setWidth(qMax(content.width(), minimumTitleWidth()));
276 }
277
278 QDockWidget *w = qobject_cast<QDockWidget*>(parentWidget());
279 const bool nativeDeco = nativeWindowDeco(floating);
280
281 int fw = floating && !nativeDeco
282 ? w->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, w)
283 : 0;
284
285 const int th = titleHeight();
286 if (!nativeDeco) {
287 if (verticalTitleBar)
288 result += QSize(th + 2*fw, 2*fw);
289 else
290 result += QSize(2*fw, th + 2*fw);
291 }
292
293 result.setHeight(qMin(result.height(), (int) QWIDGETSIZE_MAX));
294 result.setWidth(qMin(result.width(), (int) QWIDGETSIZE_MAX));
295
296 if (content.width() < 0)
297 result.setWidth(-1);
298 if (content.height() < 0)
299 result.setHeight(-1);
300
301 int left, top, right, bottom;
302 w->getContentsMargins(&left, &top, &right, &bottom);
303 //we need to substract the contents margin (it will be added by the caller)
304 QSize min = w->minimumSize() - QSize(left + right, top + bottom);
305 QSize max = w->maximumSize() - QSize(left + right, top + bottom);
306
307 /* A floating dockwidget will automatically get its minimumSize set to the layout's
308 minimum size + deco. We're *not* interested in this, we only take minimumSize()
309 into account if the user set it herself. Otherwise we end up expanding the result
310 of a calculation for a non-floating dock widget to a floating dock widget's
311 minimum size + window decorations. */
312
313 uint explicitMin = 0;
314 uint explicitMax = 0;
315 if (w->d_func()->extra != 0) {
316 explicitMin = w->d_func()->extra->explicitMinSize;
317 explicitMax = w->d_func()->extra->explicitMaxSize;
318 }
319
320 if (!(explicitMin & Qt::Horizontal) || min.width() == 0)
321 min.setWidth(-1);
322 if (!(explicitMin & Qt::Vertical) || min.height() == 0)
323 min.setHeight(-1);
324
325 if (!(explicitMax & Qt::Horizontal))
326 max.setWidth(QWIDGETSIZE_MAX);
327 if (!(explicitMax & Qt::Vertical))
328 max.setHeight(QWIDGETSIZE_MAX);
329
330 return result.boundedTo(max).expandedTo(min);
331}
332
333QSize QDockWidgetLayout::sizeHint() const
334{
335 QDockWidget *w = qobject_cast<QDockWidget*>(parentWidget());
336
337 QSize content(-1, -1);
338 if (item_list[Content] != 0)
339 content = item_list[Content]->sizeHint();
340
341 return sizeFromContent(content, w->isFloating());
342}
343
344QSize QDockWidgetLayout::maximumSize() const
345{
346 if (item_list[Content] != 0) {
347 const QSize content = item_list[Content]->maximumSize();
348 return sizeFromContent(content, parentWidget()->isWindow());
349 } else {
350 return parentWidget()->maximumSize();
351 }
352
353}
354
355QSize QDockWidgetLayout::minimumSize() const
356{
357 QDockWidget *w = qobject_cast<QDockWidget*>(parentWidget());
358
359 QSize content(0, 0);
360 if (item_list[Content] != 0)
361 content = item_list[Content]->minimumSize();
362
363 return sizeFromContent(content, w->isFloating());
364}
365
366QWidget *QDockWidgetLayout::widgetForRole(Role r) const
367{
368 QLayoutItem *item = item_list.at(r);
369 return item == 0 ? 0 : item->widget();
370}
371
372QLayoutItem *QDockWidgetLayout::itemForRole(Role r) const
373{
374 return item_list.at(r);
375}
376
377void QDockWidgetLayout::setWidgetForRole(Role r, QWidget *w)
378{
379 QWidget *old = widgetForRole(r);
380 if (old != 0) {
381 old->hide();
382 removeWidget(old);
383 }
384
385 if (w != 0) {
386 addChildWidget(w);
387 item_list[r] = new QWidgetItemV2(w);
388 w->show();
389 } else {
390 item_list[r] = 0;
391 }
392
393 invalidate();
394}
395
396static inline int pick(bool vertical, const QSize &size)
397{
398 return vertical ? size.height() : size.width();
399}
400
401static inline int perp(bool vertical, const QSize &size)
402{
403 return vertical ? size.width() : size.height();
404}
405
406int QDockWidgetLayout::minimumTitleWidth() const
407{
408 QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());
409
410 if (QWidget *title = widgetForRole(TitleBar))
411 return pick(verticalTitleBar, title->minimumSizeHint());
412
413 QSize closeSize(0, 0);
414 QSize floatSize(0, 0);
415 if (hasFeature(q, QDockWidget::DockWidgetClosable)) {
416 if (QLayoutItem *item = item_list[CloseButton])
417 closeSize = item->widget()->sizeHint();
418 }
419 if (hasFeature(q, QDockWidget::DockWidgetFloatable)) {
420 if (QLayoutItem *item = item_list[FloatButton])
421 floatSize = item->widget()->sizeHint();
422 }
423
424 int titleHeight = this->titleHeight();
425
426 int mw = q->style()->pixelMetric(QStyle::PM_DockWidgetTitleMargin, 0, q);
427 int fw = q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, q);
428
429 return pick(verticalTitleBar, closeSize)
430 + pick(verticalTitleBar, floatSize)
431 + titleHeight + 2*fw + 3*mw;
432}
433
434int QDockWidgetLayout::titleHeight() const
435{
436 QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());
437
438 if (QWidget *title = widgetForRole(TitleBar))
439 return perp(verticalTitleBar, title->sizeHint());
440
441 QSize closeSize(0, 0);
442 QSize floatSize(0, 0);
443 if (QLayoutItem *item = item_list[CloseButton])
444 closeSize = item->widget()->sizeHint();
445 if (QLayoutItem *item = item_list[FloatButton])
446 floatSize = item->widget()->sizeHint();
447
448 int buttonHeight = qMax(perp(verticalTitleBar, closeSize),
449 perp(verticalTitleBar, floatSize));
450
451 QFontMetrics titleFontMetrics = q->fontMetrics();
452#ifdef Q_WS_MAC
453 if (qobject_cast<QMacStyle *>(q->style())) {
454 //### this breaks on proxy styles. (But is this code still called?)
455 QFont font = qt_app_fonts_hash()->value("QToolButton", q->font());
456 titleFontMetrics = QFontMetrics(font);
457 }
458#endif
459
460 int mw = q->style()->pixelMetric(QStyle::PM_DockWidgetTitleMargin, 0, q);
461
462 return qMax(buttonHeight + 2, titleFontMetrics.height() + 2*mw);
463}
464
465void QDockWidgetLayout::setGeometry(const QRect &geometry)
466{
467 QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());
468
469 bool nativeDeco = nativeWindowDeco();
470
471 int fw = q->isFloating() && !nativeDeco
472 ? q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, q)
473 : 0;
474
475 if (nativeDeco) {
476 if (QLayoutItem *item = item_list[Content])
477 item->setGeometry(geometry);
478 } else {
479 int titleHeight = this->titleHeight();
480
481 if (verticalTitleBar) {
482 _titleArea = QRect(QPoint(fw, fw),
483 QSize(titleHeight, geometry.height() - (fw * 2)));
484 } else {
485 _titleArea = QRect(QPoint(fw, fw),
486 QSize(geometry.width() - (fw * 2), titleHeight));
487 }
488
489 if (QLayoutItem *item = item_list[TitleBar]) {
490 item->setGeometry(_titleArea);
491 } else {
492 QStyleOptionDockWidgetV2 opt;
493 q->initStyleOption(&opt);
494
495 if (QLayoutItem *item = item_list[CloseButton]) {
496 if (!item->isEmpty()) {
497 QRect r = q->style()
498 ->subElementRect(QStyle::SE_DockWidgetCloseButton,
499 &opt, q);
500 if (!r.isNull())
501 item->setGeometry(r);
502 }
503 }
504
505 if (QLayoutItem *item = item_list[FloatButton]) {
506 if (!item->isEmpty()) {
507 QRect r = q->style()
508 ->subElementRect(QStyle::SE_DockWidgetFloatButton,
509 &opt, q);
510 if (!r.isNull())
511 item->setGeometry(r);
512 }
513 }
514 }
515
516 if (QLayoutItem *item = item_list[Content]) {
517 QRect r = geometry;
518 if (verticalTitleBar) {
519 r.setLeft(_titleArea.right() + 1);
520 r.adjust(0, fw, -fw, -fw);
521 } else {
522 r.setTop(_titleArea.bottom() + 1);
523 r.adjust(fw, 0, -fw, -fw);
524 }
525 item->setGeometry(r);
526 }
527 }
528}
529
530void QDockWidgetLayout::setVerticalTitleBar(bool b)
531{
532 if (b == verticalTitleBar)
533 return;
534 verticalTitleBar = b;
535 invalidate();
536 parentWidget()->update();
537}
538
539/******************************************************************************
540** QDockWidgetItem
541*/
542
543QDockWidgetItem::QDockWidgetItem(QDockWidget *dockWidget)
544 : QWidgetItem(dockWidget)
545{
546}
547
548QSize QDockWidgetItem::minimumSize() const
549{
550 QSize widgetMin(0, 0);
551 if (QLayoutItem *item = dockWidgetChildItem())
552 widgetMin = item->minimumSize();
553 return dockWidgetLayout()->sizeFromContent(widgetMin, false);
554}
555
556QSize QDockWidgetItem::maximumSize() const
557{
558 if (QLayoutItem *item = dockWidgetChildItem()) {
559 return dockWidgetLayout()->sizeFromContent(item->maximumSize(), false);
560 } else {
561 return QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
562 }
563}
564
565
566QSize QDockWidgetItem::sizeHint() const
567{
568 if (QLayoutItem *item = dockWidgetChildItem()) {
569 return dockWidgetLayout()->sizeFromContent(item->sizeHint(), false);
570 } else {
571 return QWidgetItem::sizeHint();
572 }
573}
574
575/******************************************************************************
576** QDockWidgetPrivate
577*/
578
579void QDockWidgetPrivate::init()
580{
581 Q_Q(QDockWidget);
582
583 QDockWidgetLayout *layout = new QDockWidgetLayout(q);
584 layout->setSizeConstraint(QLayout::SetMinAndMaxSize);
585
586 QAbstractButton *button = new QDockWidgetTitleButton(q);
587 button->setObjectName(QLatin1String("qt_dockwidget_floatbutton"));
588 QObject::connect(button, SIGNAL(clicked()), q, SLOT(_q_toggleTopLevel()));
589 layout->setWidgetForRole(QDockWidgetLayout::FloatButton, button);
590
591 button = new QDockWidgetTitleButton(q);
592 button->setObjectName(QLatin1String("qt_dockwidget_closebutton"));
593 QObject::connect(button, SIGNAL(clicked()), q, SLOT(close()));
594 layout->setWidgetForRole(QDockWidgetLayout::CloseButton, button);
595
596 resizer = new QWidgetResizeHandler(q);
597 resizer->setMovingEnabled(false);
598 resizer->setActive(false);
599
600#ifndef QT_NO_ACTION
601 toggleViewAction = new QAction(q);
602 toggleViewAction->setCheckable(true);
603 fixedWindowTitle = qt_setWindowTitle_helperHelper(q->windowTitle(), q);
604 toggleViewAction->setText(fixedWindowTitle);
605 QObject::connect(toggleViewAction, SIGNAL(triggered(bool)),
606 q, SLOT(_q_toggleView(bool)));
607#endif
608
609 updateButtons();
610}
611
612/*!
613 Initialize \a option with the values from this QDockWidget. This method
614 is useful for subclasses when they need a QStyleOptionDockWidget, but don't want
615 to fill in all the information themselves.
616
617 \sa QStyleOption::initFrom()
618*/
619void QDockWidget::initStyleOption(QStyleOptionDockWidget *option) const
620{
621 Q_D(const QDockWidget);
622
623 if (!option)
624 return;
625 QDockWidgetLayout *dwlayout = qobject_cast<QDockWidgetLayout*>(layout());
626
627 option->initFrom(this);
628 option->rect = dwlayout->titleArea();
629 option->title = d->fixedWindowTitle;
630 option->closable = hasFeature(this, QDockWidget::DockWidgetClosable);
631 option->movable = hasFeature(this, QDockWidget::DockWidgetMovable);
632 option->floatable = hasFeature(this, QDockWidget::DockWidgetFloatable);
633
634 QDockWidgetLayout *l = qobject_cast<QDockWidgetLayout*>(layout());
635 QStyleOptionDockWidgetV2 *v2
636 = qstyleoption_cast<QStyleOptionDockWidgetV2*>(option);
637 if (v2 != 0)
638 v2->verticalTitleBar = l->verticalTitleBar;
639}
640
641void QDockWidgetPrivate::_q_toggleView(bool b)
642{
643 Q_Q(QDockWidget);
644 if (b == q->isHidden()) {
645 if (b)
646 q->show();
647 else
648 q->close();
649 }
650}
651
652void QDockWidgetPrivate::updateButtons()
653{
654 Q_Q(QDockWidget);
655 QDockWidgetLayout *dwLayout = qobject_cast<QDockWidgetLayout*>(layout);
656
657 QStyleOptionDockWidget opt;
658 q->initStyleOption(&opt);
659
660 bool customTitleBar = dwLayout->widgetForRole(QDockWidgetLayout::TitleBar) != 0;
661 bool nativeDeco = dwLayout->nativeWindowDeco();
662 bool hideButtons = nativeDeco || customTitleBar;
663
664 bool canClose = hasFeature(this, QDockWidget::DockWidgetClosable);
665 bool canFloat = hasFeature(this, QDockWidget::DockWidgetFloatable);
666
667 QAbstractButton *button
668 = qobject_cast<QAbstractButton*>(dwLayout->widgetForRole(QDockWidgetLayout::FloatButton));
669 button->setIcon(q->style()->standardIcon(QStyle::SP_TitleBarNormalButton, &opt, q));
670 button->setVisible(canFloat && !hideButtons);
671
672 button
673 = qobject_cast <QAbstractButton*>(dwLayout->widgetForRole(QDockWidgetLayout::CloseButton));
674 button->setIcon(q->style()->standardIcon(QStyle::SP_TitleBarCloseButton, &opt, q));
675 button->setVisible(canClose && !hideButtons);
676
677 q->setAttribute(Qt::WA_ContentsPropagated,
678 (canFloat || canClose) && !hideButtons);
679
680 layout->invalidate();
681}
682
683void QDockWidgetPrivate::_q_toggleTopLevel()
684{
685 Q_Q(QDockWidget);
686 q->setFloating(!q->isFloating());
687}
688
689void QDockWidgetPrivate::initDrag(const QPoint &pos, bool nca)
690{
691 if (state != 0)
692 return;
693
694 QMainWindow *win = qobject_cast<QMainWindow*>(parent);
695 Q_ASSERT(win != 0);
696 QMainWindowLayout *layout = qt_mainwindow_layout(win);
697 Q_ASSERT(layout != 0);
698 if (layout->pluggingWidget != 0) // the main window is animating a docking operation
699 return;
700
701 state = new QDockWidgetPrivate::DragState;
702 state->pressPos = pos;
703 state->dragging = false;
704 state->widgetItem = 0;
705 state->ownWidgetItem = false;
706 state->nca = nca;
707 state->ctrlDrag = false;
708}
709
710void QDockWidgetPrivate::startDrag()
711{
712 Q_Q(QDockWidget);
713
714 if (state == 0 || state->dragging)
715 return;
716
717 QMainWindowLayout *layout = qt_mainwindow_layout(qobject_cast<QMainWindow *>(q->parentWidget()));
718 Q_ASSERT(layout != 0);
719
720 state->widgetItem = layout->unplug(q);
721 if (state->widgetItem == 0) {
722 /* I have a QMainWindow parent, but I was never inserted with
723 QMainWindow::addDockWidget, so the QMainWindowLayout has no
724 widget item for me. :( I have to create it myself, and then
725 delete it if I don't get dropped into a dock area. */
726 state->widgetItem = new QDockWidgetItem(q);
727 state->ownWidgetItem = true;
728 }
729
730 if (state->ctrlDrag)
731 layout->restore();
732
733 state->dragging = true;
734}
735
736void QDockWidgetPrivate::endDrag(bool abort)
737{
738 Q_Q(QDockWidget);
739 Q_ASSERT(state != 0);
740
741 q->releaseMouse();
742
743 if (state->dragging) {
744 QMainWindowLayout *mwLayout = qt_mainwindow_layout(qobject_cast<QMainWindow *>(q->parentWidget()));
745 Q_ASSERT(mwLayout != 0);
746
747 if (abort || !mwLayout->plug(state->widgetItem)) {
748 if (hasFeature(this, QDockWidget::DockWidgetFloatable)) {
749 if (state->ownWidgetItem)
750 delete state->widgetItem;
751 mwLayout->restore();
752#ifdef Q_WS_X11
753 // get rid of the X11BypassWindowManager window flag and activate the resizer
754 Qt::WindowFlags flags = q->windowFlags();
755 flags &= ~Qt::X11BypassWindowManagerHint;
756 q->setWindowFlags(flags);
757 resizer->setActive(QWidgetResizeHandler::Resize, true);
758 q->show();
759#else
760 QDockWidgetLayout *myLayout
761 = qobject_cast<QDockWidgetLayout*>(layout);
762 resizer->setActive(QWidgetResizeHandler::Resize,
763 myLayout->widgetForRole(QDockWidgetLayout::TitleBar) != 0);
764#endif
765 undockedGeometry = q->geometry();
766 q->activateWindow();
767 } else {
768 mwLayout->revert(state->widgetItem);
769 }
770 }
771 }
772 delete state;
773 state = 0;
774}
775
776bool QDockWidgetPrivate::isAnimating() const
777{
778 Q_Q(const QDockWidget);
779
780 QMainWindow *mainWin = qobject_cast<QMainWindow*>(parent);
781 if (mainWin == 0)
782 return false;
783
784 QMainWindowLayout *mainWinLayout = qt_mainwindow_layout(mainWin);
785 if (mainWinLayout == 0)
786 return false;
787
788 return (void*)mainWinLayout->pluggingWidget == (void*)q;
789}
790
791bool QDockWidgetPrivate::mousePressEvent(QMouseEvent *event)
792{
793#if !defined(QT_NO_MAINWINDOW)
794 Q_Q(QDockWidget);
795
796 QDockWidgetLayout *dwLayout
797 = qobject_cast<QDockWidgetLayout*>(layout);
798
799 if (!dwLayout->nativeWindowDeco()) {
800 QRect titleArea = dwLayout->titleArea();
801
802 if (event->button() != Qt::LeftButton ||
803 !titleArea.contains(event->pos()) ||
804 // check if the tool window is movable... do nothing if it
805 // is not (but allow moving if the window is floating)
806 (!hasFeature(this, QDockWidget::DockWidgetMovable) && !q->isFloating()) ||
807 qobject_cast<QMainWindow*>(parent) == 0 ||
808 isAnimating() || state != 0) {
809 return false;
810 }
811
812 initDrag(event->pos(), false);
813
814 if (state)
815 state->ctrlDrag = hasFeature(this, QDockWidget::DockWidgetFloatable) && event->modifiers() & Qt::ControlModifier;
816
817 return true;
818 }
819
820#endif // !defined(QT_NO_MAINWINDOW)
821 return false;
822}
823
824bool QDockWidgetPrivate::mouseDoubleClickEvent(QMouseEvent *event)
825{
826 QDockWidgetLayout *dwLayout = qobject_cast<QDockWidgetLayout*>(layout);
827
828 if (!dwLayout->nativeWindowDeco()) {
829 QRect titleArea = dwLayout->titleArea();
830
831 if (event->button() == Qt::LeftButton && titleArea.contains(event->pos()) &&
832 hasFeature(this, QDockWidget::DockWidgetFloatable)) {
833 _q_toggleTopLevel();
834 return true;
835 }
836 }
837 return false;
838}
839
840bool QDockWidgetPrivate::mouseMoveEvent(QMouseEvent *event)
841{
842 bool ret = false;
843#if !defined(QT_NO_MAINWINDOW)
844 Q_Q(QDockWidget);
845
846 if (!state)
847 return ret;
848
849 QDockWidgetLayout *dwlayout
850 = qobject_cast<QDockWidgetLayout *>(layout);
851 QMainWindowLayout *mwlayout = qt_mainwindow_layout(qobject_cast<QMainWindow *>(q->parentWidget()));
852 if (!dwlayout->nativeWindowDeco()) {
853 if (!state->dragging
854 && mwlayout->pluggingWidget == 0
855 && (event->pos() - state->pressPos).manhattanLength()
856 > QApplication::startDragDistance()) {
857 startDrag();
858#ifdef Q_OS_WIN
859 grabMouseWhileInWindow();
860#else
861 q->grabMouse();
862#endif
863 ret = true;
864 }
865 }
866
867 if (state->dragging && !state->nca) {
868 QPoint pos = event->globalPos() - state->pressPos;
869 q->move(pos);
870
871 if (!state->ctrlDrag)
872 mwlayout->hover(state->widgetItem, event->globalPos());
873
874 ret = true;
875 }
876
877#endif // !defined(QT_NO_MAINWINDOW)
878 return ret;
879}
880
881bool QDockWidgetPrivate::mouseReleaseEvent(QMouseEvent *event)
882{
883#if !defined(QT_NO_MAINWINDOW)
884
885 if (event->button() == Qt::LeftButton && state && !state->nca) {
886 endDrag();
887 return true; //filter out the event
888 }
889
890#endif // !defined(QT_NO_MAINWINDOW)
891 return false;
892}
893
894void QDockWidgetPrivate::nonClientAreaMouseEvent(QMouseEvent *event)
895{
896 Q_Q(QDockWidget);
897
898 int fw = q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, q);
899
900 QRect geo = q->geometry();
901 QRect titleRect = q->frameGeometry();
902#ifdef Q_WS_MAC
903 if ((features & QDockWidget::DockWidgetVerticalTitleBar)) {
904 titleRect.setTop(geo.top());
905 titleRect.setBottom(geo.bottom());
906 titleRect.setRight(geo.left() - 1);
907 } else
908#endif
909 {
910 titleRect.setLeft(geo.left());
911 titleRect.setRight(geo.right());
912 titleRect.setBottom(geo.top() - 1);
913 titleRect.adjust(0, fw, 0, 0);
914 }
915
916 switch (event->type()) {
917 case QEvent::NonClientAreaMouseButtonPress:
918 if (!titleRect.contains(event->globalPos()))
919 break;
920 if (state != 0)
921 break;
922 if (qobject_cast<QMainWindow*>(parent) == 0)
923 break;
924 if (isAnimating())
925 break;
926 initDrag(event->pos(), true);
927 if (state == 0)
928 break;
929#ifdef Q_OS_WIN
930 // On Windows, NCA mouse events don't contain modifier info
931 state->ctrlDrag = GetKeyState(VK_CONTROL) & 0x8000;
932#else
933 state->ctrlDrag = event->modifiers() & Qt::ControlModifier;
934#endif
935 startDrag();
936 break;
937 case QEvent::NonClientAreaMouseMove:
938 if (state == 0 || !state->dragging)
939 break;
940 if (state->nca) {
941 endDrag();
942 }
943#ifdef Q_OS_MAC
944 else { // workaround for lack of mouse-grab on Mac
945 QMainWindowLayout *layout = qt_mainwindow_layout(qobject_cast<QMainWindow *>(q->parentWidget()));
946 Q_ASSERT(layout != 0);
947
948 q->move(event->globalPos() - state->pressPos);
949 if (!state->ctrlDrag)
950 layout->hover(state->widgetItem, event->globalPos());
951 }
952#endif
953 break;
954 case QEvent::NonClientAreaMouseButtonRelease:
955#ifdef Q_OS_MAC
956 if (state)
957 endDrag();
958#endif
959 break;
960 case QEvent::NonClientAreaMouseButtonDblClick:
961 _q_toggleTopLevel();
962 break;
963 default:
964 break;
965 }
966}
967
968void QDockWidgetPrivate::moveEvent(QMoveEvent *event)
969{
970 Q_Q(QDockWidget);
971
972 if (state == 0 || !state->dragging || !state->nca || !q->isWindow())
973 return;
974
975 // When the native window frame is being dragged, all we get is these mouse
976 // move events.
977
978 if (state->ctrlDrag)
979 return;
980
981 QMainWindowLayout *layout = qt_mainwindow_layout(qobject_cast<QMainWindow *>(q->parentWidget()));
982 Q_ASSERT(layout != 0);
983
984 QPoint globalMousePos = event->pos() + state->pressPos;
985 layout->hover(state->widgetItem, globalMousePos);
986}
987
988void QDockWidgetPrivate::unplug(const QRect &rect)
989{
990 Q_Q(QDockWidget);
991 QRect r = rect;
992 r.moveTopLeft(q->mapToGlobal(QPoint(0, 0)));
993 QDockWidgetLayout *dwLayout = qobject_cast<QDockWidgetLayout*>(layout);
994 if (dwLayout->nativeWindowDeco(true))
995 r.adjust(0, dwLayout->titleHeight(), 0, 0);
996 setWindowState(true, true, r);
997}
998
999void QDockWidgetPrivate::plug(const QRect &rect)
1000{
1001 setWindowState(false, false, rect);
1002}
1003
1004void QDockWidgetPrivate::setWindowState(bool floating, bool unplug, const QRect &rect)
1005{
1006 Q_Q(QDockWidget);
1007
1008 if (!floating && parent) {
1009 QMainWindowLayout *mwlayout = qt_mainwindow_layout(qobject_cast<QMainWindow *>(q->parentWidget()));
1010 if (mwlayout && mwlayout->dockWidgetArea(q) == Qt::NoDockWidgetArea)
1011 return; // this dockwidget can't be redocked
1012 }
1013
1014 bool wasFloating = q->isFloating();
1015 bool hidden = q->isHidden();
1016
1017 if (q->isVisible())
1018 q->hide();
1019
1020 Qt::WindowFlags flags = floating ? Qt::Tool : Qt::Widget;
1021
1022 QDockWidgetLayout *dwLayout = qobject_cast<QDockWidgetLayout*>(layout);
1023 const bool nativeDeco = dwLayout->nativeWindowDeco(floating);
1024
1025 if (nativeDeco) {
1026 flags |= Qt::CustomizeWindowHint | Qt::WindowTitleHint;
1027 if (hasFeature(this, QDockWidget::DockWidgetClosable))
1028 flags |= Qt::WindowCloseButtonHint;
1029 } else {
1030 flags |= Qt::FramelessWindowHint;
1031 }
1032
1033 if (unplug)
1034 flags |= Qt::X11BypassWindowManagerHint;
1035
1036 q->setWindowFlags(flags);
1037
1038#if defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA)
1039 if (floating && nativeDeco && (q->features() & QDockWidget::DockWidgetVerticalTitleBar)) {
1040 ChangeWindowAttributes(HIViewGetWindow(HIViewRef(q->winId())), kWindowSideTitlebarAttribute, 0);
1041 }
1042#endif
1043
1044 if (!rect.isNull())
1045 q->setGeometry(rect);
1046
1047 updateButtons();
1048
1049 if (!hidden)
1050 q->show();
1051
1052 if (floating != wasFloating) {
1053 emit q->topLevelChanged(floating);
1054 if (!floating && parent) {
1055 QMainWindowLayout *mwlayout = qt_mainwindow_layout(qobject_cast<QMainWindow *>(q->parentWidget()));
1056 if (mwlayout)
1057 emit q->dockLocationChanged(mwlayout->dockWidgetArea(q));
1058 }
1059 }
1060
1061 resizer->setActive(QWidgetResizeHandler::Resize, !unplug && floating && !nativeDeco);
1062}
1063
1064/*!
1065 \class QDockWidget
1066
1067 \brief The QDockWidget class provides a widget that can be docked
1068 inside a QMainWindow or floated as a top-level window on the
1069 desktop.
1070
1071 \ingroup mainwindow-classes
1072
1073 QDockWidget provides the concept of dock widgets, also know as
1074 tool palettes or utility windows. Dock windows are secondary
1075 windows placed in the \e {dock widget area} around the
1076 \l{QMainWindow::centralWidget()}{central widget} in a
1077 QMainWindow.
1078
1079 \image mainwindow-docks.png
1080
1081 Dock windows can be moved inside their current area, moved into
1082 new areas and floated (e.g., undocked) by the end-user. The
1083 QDockWidget API allows the programmer to restrict the dock widgets
1084 ability to move, float and close, as well as the areas in which
1085 they can be placed.
1086
1087 \section1 Appearance
1088
1089 A QDockWidget consists of a title bar and the content area. The
1090 title bar displays the dock widgets \link QWidget::windowTitle()
1091 window title\endlink, a \e float button and a \e close button.
1092 Depending on the state of the QDockWidget, the \e float and \e
1093 close buttons may be either disabled or not shown at all.
1094
1095 The visual appearance of the title bar and buttons is dependent
1096 on the \l{QStyle}{style} in use.
1097
1098 A QDockWidget acts as a wrapper for its child widget, set with setWidget().
1099 Custom size hints, minimum and maximum sizes and size policies should be
1100 implemented in the child widget. QDockWidget will respect them, adjusting
1101 its own constraints to include the frame and title. Size constraints
1102 should not be set on the QDockWidget itself, because they change depending
1103 on whether it is docked; a docked QDockWidget has no frame and a smaller title
1104 bar.
1105
1106 \sa QMainWindow, {Dock Widgets Example}
1107*/
1108
1109/*!
1110 \enum QDockWidget::DockWidgetFeature
1111
1112 \value DockWidgetClosable The dock widget can be closed. On some systems the dock
1113 widget always has a close button when it's floating
1114 (for example on MacOS 10.5).
1115 \value DockWidgetMovable The dock widget can be moved between docks
1116 by the user.
1117 \value DockWidgetFloatable The dock widget can be detached from the
1118 main window, and floated as an independent
1119 window.
1120 \value DockWidgetVerticalTitleBar The dock widget displays a vertical title
1121 bar on its left side. This can be used to
1122 increase the amount of vertical space in
1123 a QMainWindow.
1124 \value AllDockWidgetFeatures (Deprecated) The dock widget can be closed, moved,
1125 and floated. Since new features might be added in future
1126 releases, the look and behavior of dock widgets might
1127 change if you use this flag. Please specify individual
1128 flags instead.
1129 \value NoDockWidgetFeatures The dock widget cannot be closed, moved,
1130 or floated.
1131
1132 \omitvalue DockWidgetFeatureMask
1133 \omitvalue Reserved
1134*/
1135
1136/*!
1137 \property QDockWidget::windowTitle
1138 \brief the dock widget title (caption)
1139
1140 By default, this property contains an empty string.
1141*/
1142
1143/*!
1144 Constructs a QDockWidget with parent \a parent and window flags \a
1145 flags. The dock widget will be placed in the left dock widget
1146 area.
1147*/
1148QDockWidget::QDockWidget(QWidget *parent, Qt::WindowFlags flags)
1149 : QWidget(*new QDockWidgetPrivate, parent, flags)
1150{
1151 Q_D(QDockWidget);
1152 d->init();
1153}
1154
1155/*!
1156 Constructs a QDockWidget with parent \a parent and window flags \a
1157 flags. The dock widget will be placed in the left dock widget
1158 area.
1159
1160 The window title is set to \a title. This title is used when the
1161 QDockWidget is docked and undocked. It is also used in the context
1162 menu provided by QMainWindow.
1163
1164 \sa setWindowTitle()
1165*/
1166QDockWidget::QDockWidget(const QString &title, QWidget *parent, Qt::WindowFlags flags)
1167 : QWidget(*new QDockWidgetPrivate, parent, flags)
1168{
1169 Q_D(QDockWidget);
1170 d->init();
1171 setWindowTitle(title);
1172}
1173
1174/*!
1175 Destroys the dock widget.
1176*/
1177QDockWidget::~QDockWidget()
1178{ }
1179
1180/*!
1181 Returns the widget for the dock widget. This function returns zero
1182 if the widget has not been set.
1183
1184 \sa setWidget()
1185*/
1186QWidget *QDockWidget::widget() const
1187{
1188 QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(this->layout());
1189 return layout->widgetForRole(QDockWidgetLayout::Content);
1190}
1191
1192/*!
1193 Sets the widget for the dock widget to \a widget.
1194
1195 If the dock widget is visible when \a widget is added, you must
1196 \l{QWidget::}{show()} it explicitly.
1197
1198 Note that you must add the layout of the \a widget before you call
1199 this function; if not, the \a widget will not be visible.
1200
1201 \sa widget()
1202*/
1203void QDockWidget::setWidget(QWidget *widget)
1204{
1205 QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(this->layout());
1206 layout->setWidgetForRole(QDockWidgetLayout::Content, widget);
1207}
1208
1209/*!
1210 \property QDockWidget::features
1211 \brief whether the dock widget is movable, closable, and floatable
1212
1213 By default, this property is set to a combination of DockWidgetClosable,
1214 DockWidgetMovable and DockWidgetFloatable.
1215
1216 \sa DockWidgetFeature
1217*/
1218
1219void QDockWidget::setFeatures(QDockWidget::DockWidgetFeatures features)
1220{
1221 Q_D(QDockWidget);
1222 features &= DockWidgetFeatureMask;
1223 if (d->features == features)
1224 return;
1225 const bool closableChanged = (d->features ^ features) & DockWidgetClosable;
1226 d->features = features;
1227 QDockWidgetLayout *layout
1228 = qobject_cast<QDockWidgetLayout*>(this->layout());
1229 layout->setVerticalTitleBar(features & DockWidgetVerticalTitleBar);
1230 d->updateButtons();
1231 d->toggleViewAction->setEnabled((d->features & DockWidgetClosable) == DockWidgetClosable);
1232 emit featuresChanged(d->features);
1233 update();
1234 if (closableChanged && layout->nativeWindowDeco()) {
1235 //this ensures the native decoration is drawn
1236 d->setWindowState(true /*floating*/, true /*unplug*/);
1237 }
1238}
1239
1240QDockWidget::DockWidgetFeatures QDockWidget::features() const
1241{
1242 Q_D(const QDockWidget);
1243 return d->features;
1244}
1245
1246/*!
1247 \property QDockWidget::floating
1248 \brief whether the dock widget is floating
1249
1250 A floating dock widget is presented to the user as an independent
1251 window "on top" of its parent QMainWindow, instead of being
1252 docked in the QMainWindow.
1253
1254 By default, this property is true.
1255
1256 \sa isWindow()
1257*/
1258void QDockWidget::setFloating(bool floating)
1259{
1260 Q_D(QDockWidget);
1261
1262 // the initial click of a double-click may have started a drag...
1263 if (d->state != 0)
1264 d->endDrag(true);
1265
1266 QRect r = d->undockedGeometry;
1267
1268 d->setWindowState(floating, false, floating ? r : QRect());
1269
1270 if (floating && r.isNull()) {
1271 if (x() < 0 || y() < 0) //may happen if we have been hidden
1272 move(QPoint());
1273 setAttribute(Qt::WA_Moved, false); //we want it at the default position
1274 }
1275}
1276
1277/*!
1278 \property QDockWidget::allowedAreas
1279 \brief areas where the dock widget may be placed
1280
1281 The default is Qt::AllDockWidgetAreas.
1282
1283 \sa Qt::DockWidgetArea
1284*/
1285
1286void QDockWidget::setAllowedAreas(Qt::DockWidgetAreas areas)
1287{
1288 Q_D(QDockWidget);
1289 areas &= Qt::DockWidgetArea_Mask;
1290 if (areas == d->allowedAreas)
1291 return;
1292 d->allowedAreas = areas;
1293 emit allowedAreasChanged(d->allowedAreas);
1294}
1295
1296Qt::DockWidgetAreas QDockWidget::allowedAreas() const
1297{
1298 Q_D(const QDockWidget);
1299 return d->allowedAreas;
1300}
1301
1302/*!
1303 \fn bool QDockWidget::isAreaAllowed(Qt::DockWidgetArea area) const
1304
1305 Returns true if this dock widget can be placed in the given \a area;
1306 otherwise returns false.
1307*/
1308
1309/*! \reimp */
1310void QDockWidget::changeEvent(QEvent *event)
1311{
1312 Q_D(QDockWidget);
1313 QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(this->layout());
1314
1315 switch (event->type()) {
1316 case QEvent::ModifiedChange:
1317 case QEvent::WindowTitleChange:
1318 update(layout->titleArea());
1319#ifndef QT_NO_ACTION
1320 d->fixedWindowTitle = qt_setWindowTitle_helperHelper(windowTitle(), this);
1321 d->toggleViewAction->setText(d->fixedWindowTitle);
1322#endif
1323#ifndef QT_NO_TABBAR
1324 {
1325 QMainWindow *win = qobject_cast<QMainWindow*>(parentWidget());
1326 if (QMainWindowLayout *winLayout = qt_mainwindow_layout(win)) {
1327 if (QDockAreaLayoutInfo *info = winLayout->layoutState.dockAreaLayout.info(this))
1328 info->updateTabBar();
1329 }
1330 }
1331#endif // QT_NO_TABBAR
1332 break;
1333 default:
1334 break;
1335 }
1336 QWidget::changeEvent(event);
1337}
1338
1339/*! \reimp */
1340void QDockWidget::closeEvent(QCloseEvent *event)
1341{
1342 Q_D(QDockWidget);
1343 if (d->state)
1344 d->endDrag(true);
1345 QWidget::closeEvent(event);
1346}
1347
1348/*! \reimp */
1349void QDockWidget::paintEvent(QPaintEvent *event)
1350{
1351 Q_UNUSED(event)
1352
1353 QDockWidgetLayout *layout
1354 = qobject_cast<QDockWidgetLayout*>(this->layout());
1355 bool customTitleBar = layout->widgetForRole(QDockWidgetLayout::TitleBar) != 0;
1356 bool nativeDeco = layout->nativeWindowDeco();
1357
1358 if (!nativeDeco && !customTitleBar) {
1359 QStylePainter p(this);
1360 // ### Add PixelMetric to change spacers, so style may show border
1361 // when not floating.
1362 if (isFloating()) {
1363 QStyleOptionFrame framOpt;
1364 framOpt.init(this);
1365 p.drawPrimitive(QStyle::PE_FrameDockWidget, framOpt);
1366 }
1367
1368 // Title must be painted after the frame, since the areas overlap, and
1369 // the title may wish to extend out to all sides (eg. XP style)
1370 QStyleOptionDockWidgetV2 titleOpt;
1371 initStyleOption(&titleOpt);
1372 p.drawControl(QStyle::CE_DockWidgetTitle, titleOpt);
1373 }
1374}
1375
1376/*! \reimp */
1377bool QDockWidget::event(QEvent *event)
1378{
1379 Q_D(QDockWidget);
1380
1381 QMainWindow *win = qobject_cast<QMainWindow*>(parentWidget());
1382 QMainWindowLayout *layout = qt_mainwindow_layout(win);
1383
1384 switch (event->type()) {
1385#ifndef QT_NO_ACTION
1386 case QEvent::Hide:
1387 if (layout != 0)
1388 layout->keepSize(this);
1389 d->toggleViewAction->setChecked(false);
1390 emit visibilityChanged(false);
1391 break;
1392 case QEvent::Show:
1393 d->toggleViewAction->setChecked(true);
1394 emit visibilityChanged(geometry().right() >= 0 && geometry().bottom() >= 0);
1395 break;
1396#endif
1397 case QEvent::ApplicationLayoutDirectionChange:
1398 case QEvent::LayoutDirectionChange:
1399 case QEvent::StyleChange:
1400 case QEvent::ParentChange:
1401 d->updateButtons();
1402 break;
1403 case QEvent::ZOrderChange: {
1404 bool onTop = false;
1405 if (win != 0) {
1406 const QObjectList &siblings = win->children();
1407 onTop = siblings.count() > 0 && siblings.last() == (QObject*)this;
1408 }
1409 if (!isFloating() && layout != 0 && onTop)
1410 layout->raise(this);
1411 break;
1412 }
1413 case QEvent::WindowActivate:
1414 case QEvent::WindowDeactivate:
1415 update(qobject_cast<QDockWidgetLayout *>(this->layout())->titleArea());
1416 break;
1417 case QEvent::ContextMenu:
1418 if (d->state) {
1419 event->accept();
1420 return true;
1421 }
1422 break;
1423 // return true after calling the handler since we don't want
1424 // them to be passed onto the default handlers
1425 case QEvent::MouseButtonPress:
1426 if (d->mousePressEvent(static_cast<QMouseEvent *>(event)))
1427 return true;
1428 break;
1429 case QEvent::MouseButtonDblClick:
1430 if (d->mouseDoubleClickEvent(static_cast<QMouseEvent *>(event)))
1431 return true;
1432 break;
1433 case QEvent::MouseMove:
1434 if (d->mouseMoveEvent(static_cast<QMouseEvent *>(event)))
1435 return true;
1436 break;
1437#ifdef Q_OS_WIN
1438 case QEvent::Leave:
1439 if (d->state != 0 && d->state->dragging && !d->state->nca) {
1440 // This is a workaround for loosing the mouse on Vista.
1441 QPoint pos = QCursor::pos();
1442 QMouseEvent fake(QEvent::MouseMove, mapFromGlobal(pos), pos, Qt::NoButton,
1443 QApplication::mouseButtons(), QApplication::keyboardModifiers());
1444 d->mouseMoveEvent(&fake);
1445 }
1446 break;
1447#endif
1448 case QEvent::MouseButtonRelease:
1449 if (d->mouseReleaseEvent(static_cast<QMouseEvent *>(event)))
1450 return true;
1451 break;
1452 case QEvent::NonClientAreaMouseMove:
1453 case QEvent::NonClientAreaMouseButtonPress:
1454 case QEvent::NonClientAreaMouseButtonRelease:
1455 case QEvent::NonClientAreaMouseButtonDblClick:
1456 d->nonClientAreaMouseEvent(static_cast<QMouseEvent*>(event));
1457 return true;
1458 case QEvent::Move:
1459 d->moveEvent(static_cast<QMoveEvent*>(event));
1460 break;
1461 case QEvent::Resize:
1462 // if the mainwindow is plugging us, we don't want to update undocked geometry
1463 if (isFloating() && layout != 0 && layout->pluggingWidget != this)
1464 d->undockedGeometry = geometry();
1465 break;
1466 default:
1467 break;
1468 }
1469 return QWidget::event(event);
1470}
1471
1472#ifndef QT_NO_ACTION
1473/*!
1474 Returns a checkable action that can be used to show or close this
1475 dock widget.
1476
1477 The action's text is set to the dock widget's window title.
1478
1479 \sa QAction::text QWidget::windowTitle
1480 */
1481QAction * QDockWidget::toggleViewAction() const
1482{
1483 Q_D(const QDockWidget);
1484 return d->toggleViewAction;
1485}
1486#endif // QT_NO_ACTION
1487
1488/*!
1489 \fn void QDockWidget::featuresChanged(QDockWidget::DockWidgetFeatures features)
1490
1491 This signal is emitted when the \l features property changes. The
1492 \a features parameter gives the new value of the property.
1493*/
1494
1495/*!
1496 \fn void QDockWidget::topLevelChanged(bool topLevel)
1497
1498 This signal is emitted when the \l floating property changes.
1499 The \a topLevel parameter is true if the dock widget is now floating;
1500 otherwise it is false.
1501
1502 \sa isWindow()
1503*/
1504
1505/*!
1506 \fn void QDockWidget::allowedAreasChanged(Qt::DockWidgetAreas allowedAreas)
1507
1508 This signal is emitted when the \l allowedAreas property changes. The
1509 \a allowedAreas parameter gives the new value of the property.
1510*/
1511
1512/*!
1513 \fn void QDockWidget::visibilityChanged(bool visible)
1514 \since 4.3
1515
1516 This signal is emitted when the dock widget becomes \a visible (or
1517 invisible). This happens when the widget is hidden or shown, as
1518 well as when it is docked in a tabbed dock area and its tab
1519 becomes selected or unselected.
1520*/
1521
1522/*!
1523 \fn void QDockWidget::dockLocationChanged(Qt::DockWidgetArea area)
1524 \since 4.3
1525
1526 This signal is emitted when the dock widget is moved to another
1527 dock \a area, or is moved to a different location in its current
1528 dock area. This happens when the dock widget is moved
1529 programmatically or is dragged to a new location by the user.
1530*/
1531
1532/*!
1533 \since 4.3
1534
1535 Sets an arbitrary \a widget as the dock widget's title bar. If \a widget
1536 is 0, any custom title bar widget previously set on the dock widget is
1537 removed, but not deleted, and the default title bar will be used
1538 instead.
1539
1540 If a title bar widget is set, QDockWidget will not use native window
1541 decorations when it is floated.
1542
1543 Here are some tips for implementing custom title bars:
1544
1545 \list
1546 \o Mouse events that are not explicitly handled by the title bar widget
1547 must be ignored by calling QMouseEvent::ignore(). These events then
1548 propagate to the QDockWidget parent, which handles them in the usual
1549 manner, moving when the title bar is dragged, docking and undocking
1550 when it is double-clicked, etc.
1551
1552 \o When DockWidgetVerticalTitleBar is set on QDockWidget, the title
1553 bar widget is repositioned accordingly. In resizeEvent(), the title
1554 bar should check what orientation it should assume:
1555 \snippet doc/src/snippets/code/src_gui_widgets_qdockwidget.cpp 0
1556
1557 \o The title bar widget must have a valid QWidget::sizeHint() and
1558 QWidget::minimumSizeHint(). These functions should take into account
1559 the current orientation of the title bar.
1560
1561 \o It is not possible to remove a title bar from a dock widget. However,
1562 a similar effect can be achieved by setting a default constructed
1563 QWidget as the title bar widget.
1564 \endlist
1565
1566 Using qobject_cast() as shown above, the title bar widget has full access
1567 to its parent QDockWidget. Hence it can perform such operations as docking
1568 and hiding in response to user actions.
1569
1570 \sa titleBarWidget() DockWidgetVerticalTitleBar
1571*/
1572
1573void QDockWidget::setTitleBarWidget(QWidget *widget)
1574{
1575 Q_D(QDockWidget);
1576 QDockWidgetLayout *layout
1577 = qobject_cast<QDockWidgetLayout*>(this->layout());
1578 layout->setWidgetForRole(QDockWidgetLayout::TitleBar, widget);
1579 d->updateButtons();
1580 if (isWindow()) {
1581 //this ensures the native decoration is drawn
1582 d->setWindowState(true /*floating*/, true /*unplug*/);
1583 }
1584}
1585
1586/*!
1587 \since 4.3
1588 Returns the custom title bar widget set on the QDockWidget, or 0 if no
1589 custom title bar has been set.
1590
1591 \sa setTitleBarWidget()
1592*/
1593
1594QWidget *QDockWidget::titleBarWidget() const
1595{
1596 QDockWidgetLayout *layout
1597 = qobject_cast<QDockWidgetLayout*>(this->layout());
1598 return layout->widgetForRole(QDockWidgetLayout::TitleBar);
1599}
1600
1601QT_END_NAMESPACE
1602
1603#include "qdockwidget.moc"
1604#include "moc_qdockwidget.cpp"
1605
1606#endif // QT_NO_DOCKWIDGET
Note: See TracBrowser for help on using the repository browser.