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

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

trunk: Merged in qt 4.6.2 sources.

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