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

Last change on this file since 64 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 48.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** 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 are unsure which license is appropriate for your use, please
37** contact the sales department 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/qt_mac_p.h>
63#include <qmacstyle_mac.h>
64#endif
65
66QT_BEGIN_NAMESPACE
67
68extern QString qt_setWindowTitle_helperHelper(const QString&, const QWidget*); // qwidget.cpp
69
70extern QHash<QByteArray, QFont> *qt_app_fonts_hash(); // qapplication.cpp
71
72static inline bool hasFeature(const QDockWidget *dockwidget, QDockWidget::DockWidgetFeature feature)
73{ return (dockwidget->features() & feature) == feature; }
74
75
76/*
77 A Dock Window:
78
79 [+] is the float button
80 [X] is the close button
81
82 +-------------------------------+
83 | Dock Window Title [+][X]|
84 +-------------------------------+
85 | |
86 | place to put the single |
87 | QDockWidget child (this space |
88 | does not yet have a name) |
89 | |
90 | |
91 | |
92 | |
93 | |
94 | |
95 | |
96 | |
97 | |
98 +-------------------------------+
99
100*/
101
102/******************************************************************************
103** QDockWidgetTitleButton
104*/
105
106class QDockWidgetTitleButton : public QAbstractButton
107{
108 Q_OBJECT
109
110public:
111 QDockWidgetTitleButton(QDockWidget *dockWidget);
112
113 QSize sizeHint() const;
114 inline QSize minimumSizeHint() const
115 { return sizeHint(); }
116
117 void enterEvent(QEvent *event);
118 void leaveEvent(QEvent *event);
119 void paintEvent(QPaintEvent *event);
120};
121
122
123QDockWidgetTitleButton::QDockWidgetTitleButton(QDockWidget *dockWidget)
124 : QAbstractButton(dockWidget)
125{
126 setFocusPolicy(Qt::NoFocus);
127}
128
129QSize QDockWidgetTitleButton::sizeHint() const
130{
131 ensurePolished();
132
133 int size = 2*style()->pixelMetric(QStyle::PM_DockWidgetTitleBarButtonMargin, 0, this);
134 if (!icon().isNull()) {
135 int iconSize = style()->pixelMetric(QStyle::PM_SmallIconSize, 0, this);
136 QSize sz = icon().actualSize(QSize(iconSize, iconSize));
137 size += qMax(sz.width(), sz.height());
138 }
139
140 return QSize(size, size);
141}
142
143void QDockWidgetTitleButton::enterEvent(QEvent *event)
144{
145 if (isEnabled()) update();
146 QAbstractButton::enterEvent(event);
147}
148
149void QDockWidgetTitleButton::leaveEvent(QEvent *event)
150{
151 if (isEnabled()) update();
152 QAbstractButton::leaveEvent(event);
153}
154
155void QDockWidgetTitleButton::paintEvent(QPaintEvent *)
156{
157 QPainter p(this);
158
159 QRect r = rect();
160 QStyleOptionToolButton opt;
161 opt.init(this);
162 opt.state |= QStyle::State_AutoRaise;
163
164 if (style()->styleHint(QStyle::SH_DockWidget_ButtonsHaveFrame, 0, this))
165 {
166 if (isEnabled() && underMouse() && !isChecked() && !isDown())
167 opt.state |= QStyle::State_Raised;
168 if (isChecked())
169 opt.state |= QStyle::State_On;
170 if (isDown())
171 opt.state |= QStyle::State_Sunken;
172 style()->drawPrimitive(QStyle::PE_PanelButtonTool, &opt, &p, this);
173 }
174
175 opt.icon = icon();
176 opt.subControls = 0;
177 opt.activeSubControls = 0;
178 opt.features = QStyleOptionToolButton::None;
179 opt.arrowType = Qt::NoArrow;
180 int size = style()->pixelMetric(QStyle::PM_SmallIconSize, 0, this);
181 opt.iconSize = QSize(size, size);
182 style()->drawComplexControl(QStyle::CC_ToolButton, &opt, &p, this);
183}
184
185/******************************************************************************
186** QDockWidgetLayout
187*/
188
189QDockWidgetLayout::QDockWidgetLayout(QWidget *parent)
190 : QLayout(parent), verticalTitleBar(false), item_list(RoleCount, 0)
191{
192}
193
194QDockWidgetLayout::~QDockWidgetLayout()
195{
196 qDeleteAll(item_list);
197}
198
199bool QDockWidgetLayout::nativeWindowDeco() const
200{
201 return nativeWindowDeco(parentWidget()->isWindow());
202}
203
204bool QDockWidgetLayout::nativeWindowDeco(bool floating) const
205{
206#if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_WINCE)
207 Q_UNUSED(floating);
208 return false;
209#else
210 return floating && item_list[QDockWidgetLayout::TitleBar] == 0;
211#endif
212}
213
214
215void QDockWidgetLayout::addItem(QLayoutItem*)
216{
217 qWarning() << "QDockWidgetLayout::addItem(): please use QDockWidgetLayout::setWidget()";
218 return;
219}
220
221QLayoutItem *QDockWidgetLayout::itemAt(int index) const
222{
223 int cnt = 0;
224 foreach (QLayoutItem *item, item_list) {
225 if (item == 0)
226 continue;
227 if (index == cnt++)
228 return item;
229 }
230 return 0;
231}
232
233QLayoutItem *QDockWidgetLayout::takeAt(int index)
234{
235 int j = 0;
236 for (int i = 0; i < item_list.count(); ++i) {
237 QLayoutItem *item = item_list.at(i);
238 if (item == 0)
239 continue;
240 if (index == j) {
241 item_list[i] = 0;
242 invalidate();
243 return item;
244 }
245 ++j;
246 }
247 return 0;
248}
249
250int QDockWidgetLayout::count() const
251{
252 int result = 0;
253 foreach (QLayoutItem *item, item_list) {
254 if (item != 0)
255 ++result;
256 }
257 return result;
258}
259
260QSize QDockWidgetLayout::sizeFromContent(const QSize &content, bool floating) const
261{
262 QSize result = content;
263
264 if (verticalTitleBar) {
265 result.setHeight(qMax(result.height(), minimumTitleWidth()));
266 result.setWidth(qMax(content.width(), 0));
267 } else {
268 result.setHeight(qMax(result.height(), 0));
269 result.setWidth(qMax(content.width(), minimumTitleWidth()));
270 }
271
272 QDockWidget *w = qobject_cast<QDockWidget*>(parentWidget());
273 const bool nativeDeco = nativeWindowDeco(floating);
274
275 int fw = floating && !nativeDeco
276 ? w->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, w)
277 : 0;
278
279 const int th = titleHeight();
280 if (!nativeDeco) {
281 if (verticalTitleBar)
282 result += QSize(th + 2*fw, 2*fw);
283 else
284 result += QSize(2*fw, th + 2*fw);
285 }
286
287 result.setHeight(qMin(result.height(), (int) QWIDGETSIZE_MAX));
288 result.setWidth(qMin(result.width(), (int) QWIDGETSIZE_MAX));
289
290 if (content.width() < 0)
291 result.setWidth(-1);
292 if (content.height() < 0)
293 result.setHeight(-1);
294
295 int left, top, right, bottom;
296 w->getContentsMargins(&left, &top, &right, &bottom);
297 //we need to substract the contents margin (it will be added by the caller)
298 QSize min = w->minimumSize() - QSize(left + right, top + bottom);
299 QSize max = w->maximumSize() - QSize(left + right, top + bottom);
300
301 /* A floating dockwidget will automatically get its minimumSize set to the layout's
302 minimum size + deco. We're *not* interested in this, we only take minimumSize()
303 into account if the user set it herself. Otherwise we end up expanding the result
304 of a calculation for a non-floating dock widget to a floating dock widget's
305 minimum size + window decorations. */
306
307 uint explicitMin = 0;
308 uint explicitMax = 0;
309 if (w->d_func()->extra != 0) {
310 explicitMin = w->d_func()->extra->explicitMinSize;
311 explicitMax = w->d_func()->extra->explicitMaxSize;
312 }
313
314 if (!(explicitMin & Qt::Horizontal) || min.width() == 0)
315 min.setWidth(-1);
316 if (!(explicitMin & Qt::Vertical) || min.height() == 0)
317 min.setHeight(-1);
318
319 if (!(explicitMax & Qt::Horizontal))
320 max.setWidth(QWIDGETSIZE_MAX);
321 if (!(explicitMax & Qt::Vertical))
322 max.setHeight(QWIDGETSIZE_MAX);
323
324 return result.boundedTo(max).expandedTo(min);
325}
326
327QSize QDockWidgetLayout::sizeHint() const
328{
329 QDockWidget *w = qobject_cast<QDockWidget*>(parentWidget());
330
331 QSize content(-1, -1);
332 if (item_list[Content] != 0)
333 content = item_list[Content]->sizeHint();
334
335 return sizeFromContent(content, w->isFloating());
336}
337
338QSize QDockWidgetLayout::maximumSize() const
339{
340 if (item_list[Content] != 0) {
341 const QSize content = item_list[Content]->maximumSize();
342 return sizeFromContent(content, parentWidget()->isWindow());
343 } else {
344 return parentWidget()->maximumSize();
345 }
346
347}
348
349QSize QDockWidgetLayout::minimumSize() const
350{
351 QDockWidget *w = qobject_cast<QDockWidget*>(parentWidget());
352
353 QSize content(0, 0);
354 if (item_list[Content] != 0)
355 content = item_list[Content]->minimumSize();
356
357 return sizeFromContent(content, w->isFloating());
358}
359
360QWidget *QDockWidgetLayout::widgetForRole(Role r) const
361{
362 QLayoutItem *item = item_list.at(r);
363 return item == 0 ? 0 : item->widget();
364}
365
366QLayoutItem *QDockWidgetLayout::itemForRole(Role r) const
367{
368 return item_list.at(r);
369}
370
371void QDockWidgetLayout::setWidgetForRole(Role r, QWidget *w)
372{
373 QWidget *old = widgetForRole(r);
374 if (old != 0) {
375 old->hide();
376 removeWidget(old);
377 }
378
379 if (w != 0) {
380 addChildWidget(w);
381 item_list[r] = new QWidgetItemV2(w);
382 w->show();
383 } else {
384 item_list[r] = 0;
385 }
386
387 invalidate();
388}
389
390static inline int pick(bool vertical, const QSize &size)
391{
392 return vertical ? size.height() : size.width();
393}
394
395static inline int perp(bool vertical, const QSize &size)
396{
397 return vertical ? size.width() : size.height();
398}
399
400int QDockWidgetLayout::minimumTitleWidth() const
401{
402 QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());
403
404 if (QWidget *title = widgetForRole(TitleBar))
405 return pick(verticalTitleBar, title->minimumSizeHint());
406
407 QSize closeSize(0, 0);
408 QSize floatSize(0, 0);
409 if (hasFeature(q, QDockWidget::DockWidgetClosable)) {
410 if (QLayoutItem *item = item_list[CloseButton])
411 closeSize = item->widget()->sizeHint();
412 }
413 if (hasFeature(q, QDockWidget::DockWidgetFloatable)) {
414 if (QLayoutItem *item = item_list[FloatButton])
415 floatSize = item->widget()->sizeHint();
416 }
417
418 int titleHeight = this->titleHeight();
419
420 int mw = q->style()->pixelMetric(QStyle::PM_DockWidgetTitleMargin, 0, q);
421 int fw = q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, q);
422
423 return pick(verticalTitleBar, closeSize)
424 + pick(verticalTitleBar, floatSize)
425 + titleHeight + 2*fw + 3*mw;
426}
427
428int QDockWidgetLayout::titleHeight() const
429{
430 QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());
431
432 if (QWidget *title = widgetForRole(TitleBar))
433 return perp(verticalTitleBar, title->sizeHint());
434
435 QSize closeSize(0, 0);
436 QSize floatSize(0, 0);
437 if (QLayoutItem *item = item_list[CloseButton])
438 closeSize = item->widget()->sizeHint();
439 if (QLayoutItem *item = item_list[FloatButton])
440 floatSize = item->widget()->sizeHint();
441
442 int buttonHeight = qMax(perp(verticalTitleBar, closeSize),
443 perp(verticalTitleBar, floatSize));
444
445 QFontMetrics titleFontMetrics = q->fontMetrics();
446#ifdef Q_WS_MAC
447 if (qobject_cast<QMacStyle *>(q->style())) {
448 //### this breaks on proxy styles. (But is this code still called?)
449 QFont font = qt_app_fonts_hash()->value("QToolButton", q->font());
450 titleFontMetrics = QFontMetrics(font);
451 }
452#endif
453
454 int mw = q->style()->pixelMetric(QStyle::PM_DockWidgetTitleMargin, 0, q);
455
456 return qMax(buttonHeight + 2, titleFontMetrics.lineSpacing() + 2*mw);
457}
458
459void QDockWidgetLayout::setGeometry(const QRect &geometry)
460{
461 QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());
462
463 bool nativeDeco = nativeWindowDeco();
464
465 int fw = q->isFloating() && !nativeDeco
466 ? q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, q)
467 : 0;
468
469 if (nativeDeco) {
470 if (QLayoutItem *item = item_list[Content])
471 item->setGeometry(geometry);
472 } else {
473 int titleHeight = this->titleHeight();
474
475 if (verticalTitleBar) {
476 _titleArea = QRect(QPoint(fw, fw),
477 QSize(titleHeight, geometry.height() - (fw * 2)));
478 } else {
479 _titleArea = QRect(QPoint(fw, fw),
480 QSize(geometry.width() - (fw * 2), titleHeight));
481 }
482
483 if (QLayoutItem *item = item_list[TitleBar]) {
484 item->setGeometry(_titleArea);
485 } else {
486 QStyleOptionDockWidgetV2 opt;
487 q->initStyleOption(&opt);
488
489 if (QLayoutItem *item = item_list[CloseButton]) {
490 if (!item->isEmpty()) {
491 QRect r = q->style()
492 ->subElementRect(QStyle::SE_DockWidgetCloseButton,
493 &opt, q);
494 if (!r.isNull())
495 item->setGeometry(r);
496 }
497 }
498
499 if (QLayoutItem *item = item_list[FloatButton]) {
500 if (!item->isEmpty()) {
501 QRect r = q->style()
502 ->subElementRect(QStyle::SE_DockWidgetFloatButton,
503 &opt, q);
504 if (!r.isNull())
505 item->setGeometry(r);
506 }
507 }
508 }
509
510 if (QLayoutItem *item = item_list[Content]) {
511 QRect r = geometry;
512 if (verticalTitleBar) {
513 r.setLeft(_titleArea.right() + 1);
514 r.adjust(0, fw, -fw, -fw);
515 } else {
516 r.setTop(_titleArea.bottom() + 1);
517 r.adjust(fw, 0, -fw, -fw);
518 }
519 item->setGeometry(r);
520 }
521 }
522}
523
524void QDockWidgetLayout::setVerticalTitleBar(bool b)
525{
526 if (b == verticalTitleBar)
527 return;
528 verticalTitleBar = b;
529 invalidate();
530 parentWidget()->update();
531}
532
533/******************************************************************************
534** QDockWidgetItem
535*/
536
537QDockWidgetItem::QDockWidgetItem(QDockWidget *dockWidget)
538 : QWidgetItem(dockWidget)
539{
540}
541
542QSize QDockWidgetItem::minimumSize() const
543{
544 QSize widgetMin(0, 0);
545 if (QLayoutItem *item = dockWidgetChildItem())
546 widgetMin = item->minimumSize();
547 return dockWidgetLayout()->sizeFromContent(widgetMin, false);
548}
549
550QSize QDockWidgetItem::maximumSize() const
551{
552 if (QLayoutItem *item = dockWidgetChildItem()) {
553 return dockWidgetLayout()->sizeFromContent(item->maximumSize(), false);
554 } else {
555 return QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
556 }
557}
558
559
560QSize QDockWidgetItem::sizeHint() const
561{
562 if (QLayoutItem *item = dockWidgetChildItem()) {
563 return dockWidgetLayout()->sizeFromContent(item->sizeHint(), false);
564 } else {
565 return QWidgetItem::sizeHint();
566 }
567}
568
569/******************************************************************************
570** QDockWidgetPrivate
571*/
572
573void QDockWidgetPrivate::init()
574{
575 Q_Q(QDockWidget);
576
577 QDockWidgetLayout *layout = new QDockWidgetLayout(q);
578 layout->setSizeConstraint(QLayout::SetMinAndMaxSize);
579
580 QAbstractButton *button = new QDockWidgetTitleButton(q);
581 button->setObjectName(QLatin1String("qt_dockwidget_floatbutton"));
582 QObject::connect(button, SIGNAL(clicked()), q, SLOT(_q_toggleTopLevel()));
583 layout->setWidgetForRole(QDockWidgetLayout::FloatButton, button);
584
585 button = new QDockWidgetTitleButton(q);
586 button->setObjectName(QLatin1String("qt_dockwidget_closebutton"));
587 QObject::connect(button, SIGNAL(clicked()), q, SLOT(close()));
588 layout->setWidgetForRole(QDockWidgetLayout::CloseButton, button);
589
590 resizer = new QWidgetResizeHandler(q);
591 resizer->setMovingEnabled(false);
592 resizer->setActive(false);
593
594#ifndef QT_NO_ACTION
595 toggleViewAction = new QAction(q);
596 toggleViewAction->setCheckable(true);
597 fixedWindowTitle = qt_setWindowTitle_helperHelper(q->windowTitle(), q);
598 toggleViewAction->setText(fixedWindowTitle);
599 QObject::connect(toggleViewAction, SIGNAL(triggered(bool)),
600 q, SLOT(_q_toggleView(bool)));
601#endif
602
603 updateButtons();
604}
605
606/*!
607 Initialize \a option with the values from this QDockWidget. This method
608 is useful for subclasses when they need a QStyleOptionDockWidget, but don't want
609 to fill in all the information themselves.
610
611 \sa QStyleOption::initFrom()
612*/
613void QDockWidget::initStyleOption(QStyleOptionDockWidget *option) const
614{
615 Q_D(const QDockWidget);
616
617 if (!option)
618 return;
619 QDockWidgetLayout *dwlayout = qobject_cast<QDockWidgetLayout*>(layout());
620
621 option->initFrom(this);
622 option->rect = dwlayout->titleArea();
623 option->title = d->fixedWindowTitle;
624 option->closable = hasFeature(this, QDockWidget::DockWidgetClosable);
625 option->movable = hasFeature(this, QDockWidget::DockWidgetMovable);
626 option->floatable = hasFeature(this, QDockWidget::DockWidgetFloatable);
627
628 QDockWidgetLayout *l = qobject_cast<QDockWidgetLayout*>(layout());
629 QStyleOptionDockWidgetV2 *v2
630 = qstyleoption_cast<QStyleOptionDockWidgetV2*>(option);
631 if (v2 != 0)
632 v2->verticalTitleBar = l->verticalTitleBar;
633}
634
635void QDockWidgetPrivate::_q_toggleView(bool b)
636{
637 Q_Q(QDockWidget);
638 if (b == q->isHidden()) {
639 if (b)
640 q->show();
641 else
642 q->close();
643 }
644}
645
646void QDockWidgetPrivate::updateButtons()
647{
648 Q_Q(QDockWidget);
649 QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(q->layout());
650
651 QStyleOptionDockWidget opt;
652 q->initStyleOption(&opt);
653
654 bool customTitleBar = layout->widgetForRole(QDockWidgetLayout::TitleBar) != 0;
655 bool nativeDeco = layout->nativeWindowDeco();
656 bool hideButtons = nativeDeco || customTitleBar;
657
658 bool canClose = hasFeature(q, QDockWidget::DockWidgetClosable);
659 bool canFloat = hasFeature(q, QDockWidget::DockWidgetFloatable);
660
661 QAbstractButton *button
662 = qobject_cast<QAbstractButton*>(layout->widgetForRole(QDockWidgetLayout::FloatButton));
663 button->setIcon(q->style()->standardIcon(QStyle::SP_TitleBarNormalButton, &opt, q));
664 button->setVisible(canFloat && !hideButtons);
665
666 button
667 = qobject_cast <QAbstractButton*>(layout->widgetForRole(QDockWidgetLayout::CloseButton));
668 button->setIcon(q->style()->standardIcon(QStyle::SP_TitleBarCloseButton, &opt, q));
669 button->setVisible(canClose && !hideButtons);
670
671 q->setAttribute(Qt::WA_ContentsPropagated,
672 (canFloat || canClose) && !hideButtons);
673
674 layout->invalidate();
675}
676
677void QDockWidgetPrivate::_q_toggleTopLevel()
678{
679 Q_Q(QDockWidget);
680 q->setFloating(!q->isFloating());
681}
682
683void QDockWidgetPrivate::initDrag(const QPoint &pos, bool nca)
684{
685 Q_Q(QDockWidget);
686
687 if (state != 0)
688 return;
689
690 QMainWindow *win = qobject_cast<QMainWindow*>(q->parentWidget());
691 Q_ASSERT(win != 0);
692 QMainWindowLayout *layout = qobject_cast<QMainWindowLayout*>(win->layout());
693 Q_ASSERT(layout != 0);
694 if (layout->layoutState.indexOf(q).isEmpty()) //The dock widget has not been added into the main window
695 return;
696 if (layout->pluggingWidget != 0) // the main window is animating a docking operation
697 return;
698
699 state = new QDockWidgetPrivate::DragState;
700 state->pressPos = pos;
701 state->dragging = false;
702 state->widgetItem = 0;
703 state->ownWidgetItem = false;
704 state->nca = nca;
705 state->ctrlDrag = false;
706}
707
708void QDockWidgetPrivate::startDrag()
709{
710 Q_Q(QDockWidget);
711
712 if (state == 0 || state->dragging)
713 return;
714
715 QMainWindowLayout *layout
716 = qobject_cast<QMainWindowLayout *>(q->parentWidget()->layout());
717 Q_ASSERT(layout != 0);
718
719 state->widgetItem = layout->unplug(q);
720 if (state->widgetItem == 0) {
721 /* I have a QMainWindow parent, but I was never inserted with
722 QMainWindow::addDockWidget, so the QMainWindowLayout has no
723 widget item for me. :( I have to create it myself, and then
724 delete it if I don't get dropped into a dock area. */
725 state->widgetItem = new QDockWidgetItem(q);
726 state->ownWidgetItem = true;
727 }
728
729 if (state->ctrlDrag)
730 layout->restore();
731
732 state->dragging = true;
733}
734
735void QDockWidgetPrivate::endDrag(bool abort)
736{
737 Q_Q(QDockWidget);
738 Q_ASSERT(state != 0);
739
740 q->releaseMouse();
741
742 if (state->dragging) {
743 QMainWindowLayout *layout =
744 qobject_cast<QMainWindowLayout *>(q->parentWidget()->layout());
745 Q_ASSERT(layout != 0);
746
747 if (abort || !layout->plug(state->widgetItem)) {
748 if (hasFeature(q, QDockWidget::DockWidgetFloatable)) {
749 if (state->ownWidgetItem)
750 delete state->widgetItem;
751 layout->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*>(q->layout());
762 resizer->setActive(QWidgetResizeHandler::Resize,
763 myLayout->widgetForRole(QDockWidgetLayout::TitleBar) != 0);
764#endif
765 undockedGeometry = q->geometry();
766 q->activateWindow();
767 } else {
768 layout->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*>(q->parentWidget());
781 if (mainWin == 0)
782 return false;
783
784 QMainWindowLayout *mainWinLayout
785 = qobject_cast<QMainWindowLayout*>(mainWin->layout());
786 if (mainWinLayout == 0)
787 return false;
788
789 return (void*)mainWinLayout->pluggingWidget == (void*)q;
790}
791
792bool QDockWidgetPrivate::mousePressEvent(QMouseEvent *event)
793{
794#if !defined(QT_NO_MAINWINDOW)
795 Q_Q(QDockWidget);
796
797 QDockWidgetLayout *layout
798 = qobject_cast<QDockWidgetLayout*>(q->layout());
799
800 if (!layout->nativeWindowDeco()) {
801 QRect titleArea = layout->titleArea();
802
803 if (event->button() != Qt::LeftButton ||
804 !titleArea.contains(event->pos()) ||
805 // check if the tool window is movable... do nothing if it
806 // is not (but allow moving if the window is floating)
807 (!hasFeature(q, QDockWidget::DockWidgetMovable) && !q->isFloating()) ||
808 qobject_cast<QMainWindow*>(q->parentWidget()) == 0 ||
809 isAnimating() || state != 0) {
810 return false;
811 }
812
813 initDrag(event->pos(), false);
814
815 if (state)
816 state->ctrlDrag = hasFeature(q, QDockWidget::DockWidgetFloatable) && event->modifiers() & Qt::ControlModifier;
817
818 return true;
819 }
820
821#endif // !defined(QT_NO_MAINWINDOW)
822 return false;
823}
824
825bool QDockWidgetPrivate::mouseDoubleClickEvent(QMouseEvent *event)
826{
827 Q_Q(QDockWidget);
828
829 QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(q->layout());
830
831 if (!layout->nativeWindowDeco()) {
832 QRect titleArea = layout->titleArea();
833
834 if (event->button() == Qt::LeftButton && titleArea.contains(event->pos()) &&
835 hasFeature(q, QDockWidget::DockWidgetFloatable)) {
836 _q_toggleTopLevel();
837 return true;
838 }
839 }
840 return false;
841}
842
843bool QDockWidgetPrivate::mouseMoveEvent(QMouseEvent *event)
844{
845 bool ret = false;
846#if !defined(QT_NO_MAINWINDOW)
847 Q_Q(QDockWidget);
848
849 if (!state)
850 return ret;
851
852 QDockWidgetLayout *dwlayout
853 = qobject_cast<QDockWidgetLayout*>(q->layout());
854 QMainWindowLayout *mwlayout
855 = qobject_cast<QMainWindowLayout*>(q->parentWidget()->layout());
856 if (!dwlayout->nativeWindowDeco()) {
857 if (!state->dragging
858 && mwlayout->pluggingWidget == 0
859 && (event->pos() - state->pressPos).manhattanLength()
860 > QApplication::startDragDistance()) {
861 startDrag();
862#ifdef Q_OS_WIN
863 grabMouseWhileInWindow();
864#else
865 q->grabMouse();
866#endif
867 ret = true;
868 }
869 }
870
871 if (state->dragging && !state->nca) {
872 QPoint pos = event->globalPos() - state->pressPos;
873 q->move(pos);
874
875 if (!state->ctrlDrag)
876 mwlayout->hover(state->widgetItem, event->globalPos());
877
878 ret = true;
879 }
880
881#endif // !defined(QT_NO_MAINWINDOW)
882 return ret;
883}
884
885bool QDockWidgetPrivate::mouseReleaseEvent(QMouseEvent *event)
886{
887#if !defined(QT_NO_MAINWINDOW)
888
889 if (event->button() == Qt::LeftButton && state && !state->nca) {
890 endDrag();
891 return true; //filter out the event
892 }
893
894#endif // !defined(QT_NO_MAINWINDOW)
895 return false;
896}
897
898void QDockWidgetPrivate::nonClientAreaMouseEvent(QMouseEvent *event)
899{
900 Q_Q(QDockWidget);
901
902 int fw = q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, q);
903
904 QRect geo = q->geometry();
905 QRect titleRect = q->frameGeometry();
906#ifdef Q_WS_MAC
907 if ((features & QDockWidget::DockWidgetVerticalTitleBar)) {
908 titleRect.setTop(geo.top());
909 titleRect.setBottom(geo.bottom());
910 titleRect.setRight(geo.left() - 1);
911 } else
912#endif
913 {
914 titleRect.setLeft(geo.left());
915 titleRect.setRight(geo.right());
916 titleRect.setBottom(geo.top() - 1);
917 titleRect.adjust(0, fw, 0, 0);
918 }
919
920 switch (event->type()) {
921 case QEvent::NonClientAreaMouseButtonPress:
922 if (!titleRect.contains(event->globalPos()))
923 break;
924 if (state != 0)
925 break;
926 if (qobject_cast<QMainWindow*>(q->parentWidget()) == 0)
927 break;
928 if (isAnimating())
929 break;
930 initDrag(event->pos(), true);
931 if (state == 0)
932 break;
933#ifdef Q_OS_WIN
934 // On Windows, NCA mouse events don't contain modifier info
935 state->ctrlDrag = GetKeyState(VK_CONTROL) & 0x8000;
936#else
937 state->ctrlDrag = event->modifiers() & Qt::ControlModifier;
938#endif
939 startDrag();
940 break;
941 case QEvent::NonClientAreaMouseMove:
942 if (state == 0 || !state->dragging)
943 break;
944 if (state->nca) {
945 endDrag();
946 }
947#ifdef Q_OS_MAC
948 else { // workaround for lack of mouse-grab on Mac
949 QMainWindowLayout *layout
950 = qobject_cast<QMainWindowLayout *>(q->parentWidget()->layout());
951 Q_ASSERT(layout != 0);
952
953 q->move(event->globalPos() - state->pressPos);
954 if (!state->ctrlDrag)
955 layout->hover(state->widgetItem, event->globalPos());
956 }
957#endif
958 break;
959 case QEvent::NonClientAreaMouseButtonRelease:
960#ifdef Q_OS_MAC
961 if (state)
962 endDrag();
963#endif
964 break;
965 case QEvent::NonClientAreaMouseButtonDblClick:
966 _q_toggleTopLevel();
967 break;
968 default:
969 break;
970 }
971}
972
973void QDockWidgetPrivate::moveEvent(QMoveEvent *event)
974{
975 Q_Q(QDockWidget);
976
977 if (state == 0 || !state->dragging || !state->nca || !q->isWindow())
978 return;
979
980 // When the native window frame is being dragged, all we get is these mouse
981 // move events.
982
983 if (state->ctrlDrag)
984 return;
985
986 QMainWindowLayout *layout
987 = qobject_cast<QMainWindowLayout *>(q->parentWidget()->layout());
988 Q_ASSERT(layout != 0);
989
990 QPoint globalMousePos = event->pos() + state->pressPos;
991 layout->hover(state->widgetItem, globalMousePos);
992}
993
994void QDockWidgetPrivate::unplug(const QRect &rect)
995{
996 Q_Q(QDockWidget);
997 QRect r = rect;
998 r.moveTopLeft(q->mapToGlobal(QPoint(0, 0)));
999 QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(q->layout());
1000 if (layout->nativeWindowDeco(true))
1001 r.adjust(0, layout->titleHeight(), 0, 0);
1002 setWindowState(true, true, r);
1003}
1004
1005void QDockWidgetPrivate::plug(const QRect &rect)
1006{
1007 setWindowState(false, false, rect);
1008}
1009
1010void QDockWidgetPrivate::setWindowState(bool floating, bool unplug, const QRect &rect)
1011{
1012 Q_Q(QDockWidget);
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 *layout = qobject_cast<QDockWidgetLayout*>(q->layout());
1023 const bool nativeDeco = layout->nativeWindowDeco(floating);
1024
1025 if (nativeDeco) {
1026 flags |= Qt::CustomizeWindowHint | Qt::WindowTitleHint;
1027 if (hasFeature(q, 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 && q->parentWidget()) {
1055 QMainWindowLayout *mwlayout = qobject_cast<QMainWindowLayout *>(q->parentWidget()->layout());
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 application
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 \internal
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 d->features = features;
1226 QDockWidgetLayout *layout
1227 = qobject_cast<QDockWidgetLayout*>(this->layout());
1228 layout->setVerticalTitleBar(features & DockWidgetVerticalTitleBar);
1229 d->updateButtons();
1230 d->toggleViewAction->setEnabled((d->features & DockWidgetClosable) == DockWidgetClosable);
1231 emit featuresChanged(d->features);
1232 update();
1233}
1234
1235QDockWidget::DockWidgetFeatures QDockWidget::features() const
1236{
1237 Q_D(const QDockWidget);
1238 return d->features;
1239}
1240
1241/*!
1242 \property QDockWidget::floating
1243 \brief whether the dock widget is floating
1244
1245 A floating dock widget is presented to the user as an independent
1246 window "on top" of its parent QMainWindow, instead of being
1247 docked in the QMainWindow.
1248
1249 By default, this property is true.
1250
1251 \sa isWindow()
1252*/
1253void QDockWidget::setFloating(bool floating)
1254{
1255 Q_D(QDockWidget);
1256
1257 // the initial click of a double-click may have started a drag...
1258 if (d->state != 0)
1259 d->endDrag(true);
1260
1261 QRect r = d->undockedGeometry;
1262
1263 d->setWindowState(floating, false, floating ? r : QRect());
1264 if (floating && r.isNull()) {
1265 QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(this->layout());
1266 QRect titleArea = layout->titleArea();
1267 int h = layout->verticalTitleBar ? titleArea.width() : titleArea.height();
1268 QPoint p = mapToGlobal(QPoint(h, h));
1269 move(p);
1270 }
1271}
1272
1273/*!
1274 \property QDockWidget::allowedAreas
1275 \brief areas where the dock widget may be placed
1276
1277 The default is Qt::AllDockWidgetAreas.
1278
1279 \sa Qt::DockWidgetArea
1280*/
1281
1282void QDockWidget::setAllowedAreas(Qt::DockWidgetAreas areas)
1283{
1284 Q_D(QDockWidget);
1285 areas &= Qt::DockWidgetArea_Mask;
1286 if (areas == d->allowedAreas)
1287 return;
1288 d->allowedAreas = areas;
1289 emit allowedAreasChanged(d->allowedAreas);
1290}
1291
1292Qt::DockWidgetAreas QDockWidget::allowedAreas() const
1293{
1294 Q_D(const QDockWidget);
1295 return d->allowedAreas;
1296}
1297
1298/*!
1299 \fn bool QDockWidget::isAreaAllowed(Qt::DockWidgetArea area) const
1300
1301 Returns true if this dock widget can be placed in the given \a area;
1302 otherwise returns false.
1303*/
1304
1305/*! \reimp */
1306void QDockWidget::changeEvent(QEvent *event)
1307{
1308 Q_D(QDockWidget);
1309 QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(this->layout());
1310
1311 switch (event->type()) {
1312 case QEvent::ModifiedChange:
1313 case QEvent::WindowTitleChange:
1314 update(layout->titleArea());
1315#ifndef QT_NO_ACTION
1316 d->fixedWindowTitle = qt_setWindowTitle_helperHelper(windowTitle(), this);
1317 d->toggleViewAction->setText(d->fixedWindowTitle);
1318#endif
1319#ifndef QT_NO_TABBAR
1320 {
1321 QMainWindow *win = qobject_cast<QMainWindow*>(parentWidget());
1322 if (QMainWindowLayout *winLayout =
1323 (win ? qobject_cast<QMainWindowLayout*>(win->layout()) : 0))
1324 if (QDockAreaLayoutInfo *info =
1325 (winLayout ? winLayout->layoutState.dockAreaLayout.info(this) : 0))
1326 info->updateTabBar();
1327 }
1328#endif // QT_NO_TABBAR
1329 break;
1330 default:
1331 break;
1332 }
1333 QWidget::changeEvent(event);
1334}
1335
1336/*! \reimp */
1337void QDockWidget::closeEvent(QCloseEvent *event)
1338{
1339 Q_D(QDockWidget);
1340 if (d->state)
1341 d->endDrag(true);
1342 QWidget::closeEvent(event);
1343}
1344
1345/*! \reimp */
1346void QDockWidget::paintEvent(QPaintEvent *event)
1347{
1348 Q_UNUSED(event)
1349
1350 QDockWidgetLayout *layout
1351 = qobject_cast<QDockWidgetLayout*>(this->layout());
1352 bool customTitleBar = layout->widgetForRole(QDockWidgetLayout::TitleBar) != 0;
1353 bool nativeDeco = layout->nativeWindowDeco();
1354
1355 if (!nativeDeco && !customTitleBar) {
1356 QStylePainter p(this);
1357 // ### Add PixelMetric to change spacers, so style may show border
1358 // when not floating.
1359 if (isFloating()) {
1360 QStyleOptionFrame framOpt;
1361 framOpt.init(this);
1362 p.drawPrimitive(QStyle::PE_FrameDockWidget, framOpt);
1363 }
1364
1365 // Title must be painted after the frame, since the areas overlap, and
1366 // the title may wish to extend out to all sides (eg. XP style)
1367 QStyleOptionDockWidgetV2 titleOpt;
1368 initStyleOption(&titleOpt);
1369 p.drawControl(QStyle::CE_DockWidgetTitle, titleOpt);
1370 }
1371}
1372
1373/*! \reimp */
1374bool QDockWidget::event(QEvent *event)
1375{
1376 Q_D(QDockWidget);
1377
1378 QMainWindow *win = qobject_cast<QMainWindow*>(parentWidget());
1379 QMainWindowLayout *layout = 0;
1380 if (win != 0)
1381 layout = qobject_cast<QMainWindowLayout*>(win->layout());
1382
1383 switch (event->type()) {
1384#ifndef QT_NO_ACTION
1385 case QEvent::Hide:
1386 if (layout != 0)
1387 layout->keepSize(this);
1388 d->toggleViewAction->setChecked(false);
1389 emit visibilityChanged(false);
1390 break;
1391 case QEvent::Show:
1392 d->toggleViewAction->setChecked(true);
1393 emit visibilityChanged(true);
1394 break;
1395#endif
1396 case QEvent::ApplicationLayoutDirectionChange:
1397 case QEvent::LayoutDirectionChange:
1398 case QEvent::StyleChange:
1399 case QEvent::ParentChange:
1400 d->updateButtons();
1401 break;
1402 case QEvent::ZOrderChange: {
1403 bool onTop = false;
1404 if (win != 0) {
1405 const QObjectList &siblings = win->children();
1406 onTop = siblings.count() > 0 && siblings.last() == (QObject*)this;
1407 }
1408 if (!isFloating() && layout != 0 && onTop)
1409 layout->raise(this);
1410 break;
1411 }
1412 case QEvent::WindowActivate:
1413 case QEvent::WindowDeactivate:
1414 update(qobject_cast<QDockWidgetLayout *>(this->layout())->titleArea());
1415 break;
1416 case QEvent::ContextMenu:
1417 if (d->state) {
1418 event->accept();
1419 return true;
1420 }
1421 break;
1422 // return true after calling the handler since we don't want
1423 // them to be passed onto the default handlers
1424 case QEvent::MouseButtonPress:
1425 if (d->mousePressEvent(static_cast<QMouseEvent *>(event)))
1426 return true;
1427 break;
1428 case QEvent::MouseButtonDblClick:
1429 if (d->mouseDoubleClickEvent(static_cast<QMouseEvent *>(event)))
1430 return true;
1431 break;
1432 case QEvent::MouseMove:
1433 if (d->mouseMoveEvent(static_cast<QMouseEvent *>(event)))
1434 return true;
1435 break;
1436#ifdef Q_OS_WIN
1437 case QEvent::Leave:
1438 if (d->state != 0 && d->state->dragging && !d->state->nca) {
1439 // This is a workaround for loosing the mouse on Vista.
1440 QPoint pos = QCursor::pos();
1441 QMouseEvent fake(QEvent::MouseMove, mapFromGlobal(pos), pos, Qt::NoButton,
1442 QApplication::mouseButtons(), QApplication::keyboardModifiers());
1443 d->mouseMoveEvent(&fake);
1444 }
1445 break;
1446#endif
1447 case QEvent::MouseButtonRelease:
1448 if (d->mouseReleaseEvent(static_cast<QMouseEvent *>(event)))
1449 return true;
1450 break;
1451 case QEvent::NonClientAreaMouseMove:
1452 case QEvent::NonClientAreaMouseButtonPress:
1453 case QEvent::NonClientAreaMouseButtonRelease:
1454 case QEvent::NonClientAreaMouseButtonDblClick:
1455 d->nonClientAreaMouseEvent(static_cast<QMouseEvent*>(event));
1456 return true;
1457 case QEvent::Move:
1458 d->moveEvent(static_cast<QMoveEvent*>(event));
1459 break;
1460 case QEvent::Resize:
1461 // if the mainwindow is plugging us, we don't want to update undocked geometry
1462 if (isFloating() && layout != 0 && layout->pluggingWidget != this)
1463 d->undockedGeometry = geometry();
1464 break;
1465 default:
1466 break;
1467 }
1468 return QWidget::event(event);
1469}
1470
1471#ifndef QT_NO_ACTION
1472/*!
1473 Returns a checkable action that can be used to show or close this
1474 dock widget.
1475
1476 The action's text is set to the dock widget's window title.
1477
1478 \sa QAction::text QWidget::windowTitle
1479 */
1480QAction * QDockWidget::toggleViewAction() const
1481{
1482 Q_D(const QDockWidget);
1483 return d->toggleViewAction;
1484}
1485#endif // QT_NO_ACTION
1486
1487/*!
1488 \fn void QDockWidget::featuresChanged(QDockWidget::DockWidgetFeatures features)
1489
1490 This signal is emitted when the \l features property changes. The
1491 \a features parameter gives the new value of the property.
1492*/
1493
1494/*!
1495 \fn void QDockWidget::topLevelChanged(bool topLevel)
1496
1497 This signal is emitted when the \l floating property changes.
1498 The \a topLevel parameter is true if the dock widget is now floating;
1499 otherwise it is false.
1500
1501 \sa isWindow()
1502*/
1503
1504/*!
1505 \fn void QDockWidget::allowedAreasChanged(Qt::DockWidgetAreas allowedAreas)
1506
1507 This signal is emitted when the \l allowedAreas property changes. The
1508 \a allowedAreas parameter gives the new value of the property.
1509*/
1510
1511/*!
1512 \fn void QDockWidget::visibilityChanged(bool visible)
1513 \since 4.3
1514
1515 This signal is emitted when the dock widget becomes \a visible (or
1516 invisible). This happens when the widget is hidden or shown, as
1517 well as when it is docked in a tabbed dock area and its tab
1518 becomes selected or unselected.
1519*/
1520
1521/*!
1522 \fn void QDockWidget::dockLocationChanged(Qt::DockWidgetArea area)
1523 \since 4.3
1524
1525 This signal is emitted when the dock widget is moved to another
1526 dock \a area, or is moved to a different location in its current
1527 dock area. This happens when the dock widget is moved
1528 programmatically or is dragged to a new location by the user.
1529*/
1530
1531/*!
1532 \since 4.3
1533 Sets an arbitrary \a widget as the dock widget's title bar. If \a widget
1534 is 0, the title bar widget is removed, but not deleted.
1535
1536 If a title bar widget is set, QDockWidget will not use native window
1537 decorations when it is floated.
1538
1539 Here are some tips for implementing custom title bars:
1540
1541 \list
1542 \i Mouse events that are not explicitly handled by the title bar widget
1543 must be ignored by calling QMouseEvent::ignore(). These events then
1544 propagate to the QDockWidget parent, which handles them in the usual
1545 manner, moving when the title bar is dragged, docking and undocking
1546 when it is double-clicked, etc.
1547
1548 \i When DockWidgetVerticalTitleBar is set on QDockWidget, the title
1549 bar widget is repositioned accordingly. In resizeEvent(), the title
1550 bar should check what orientation it should assume:
1551 \snippet doc/src/snippets/code/src_gui_widgets_qdockwidget.cpp 0
1552
1553 \i The title bar widget must have a valid QWidget::sizeHint() and
1554 QWidget::minimumSizeHint(). These functions should take into account
1555 the current orientation of the title bar.
1556 \endlist
1557
1558 Using qobject_cast as shown above, the title bar widget has full access
1559 to its parent QDockWidget. Hence it can perform such operations as docking
1560 and hiding in response to user actions.
1561
1562 \sa titleBarWidget() DockWidgetVerticalTitleBar
1563*/
1564
1565void QDockWidget::setTitleBarWidget(QWidget *widget)
1566{
1567 Q_D(QDockWidget);
1568 QDockWidgetLayout *layout
1569 = qobject_cast<QDockWidgetLayout*>(this->layout());
1570 layout->setWidgetForRole(QDockWidgetLayout::TitleBar, widget);
1571 d->updateButtons();
1572 if (isWindow()) {
1573 //this ensures the native decoration is drawn
1574 d->setWindowState(true /*floating*/, true /*unplug*/);
1575 }
1576}
1577
1578/*!
1579 \since 4.3
1580 Returns the custom title bar widget set on the QDockWidget, or 0 if no
1581 custom title bar has been set.
1582
1583 \sa setTitleBarWidget()
1584*/
1585
1586QWidget *QDockWidget::titleBarWidget() const
1587{
1588 QDockWidgetLayout *layout
1589 = qobject_cast<QDockWidgetLayout*>(this->layout());
1590 return layout->widgetForRole(QDockWidgetLayout::TitleBar);
1591}
1592
1593QT_END_NAMESPACE
1594
1595#include "qdockwidget.moc"
1596#include "moc_qdockwidget.cpp"
1597
1598#endif // QT_NO_DOCKWIDGET
Note: See TracBrowser for help on using the repository browser.