util/src/gui/widgets/qdockwidget.cpp
changeset 7 f7bc934e204c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    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 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    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 
       
    67 QT_BEGIN_NAMESPACE
       
    68 
       
    69 extern QString qt_setWindowTitle_helperHelper(const QString&, const QWidget*); // qwidget.cpp
       
    70 
       
    71 static inline bool hasFeature(const QDockWidgetPrivate *priv, QDockWidget::DockWidgetFeature feature)
       
    72 { return (priv->features & feature) == feature; }
       
    73 
       
    74 static 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 
       
   108 class QDockWidgetTitleButton : public QAbstractButton
       
   109 {
       
   110     Q_OBJECT
       
   111 
       
   112 public:
       
   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 
       
   125 QDockWidgetTitleButton::QDockWidgetTitleButton(QDockWidget *dockWidget)
       
   126     : QAbstractButton(dockWidget)
       
   127 {
       
   128     setFocusPolicy(Qt::NoFocus);
       
   129 }
       
   130 
       
   131 QSize 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 
       
   145 void QDockWidgetTitleButton::enterEvent(QEvent *event)
       
   146 {
       
   147     if (isEnabled()) update();
       
   148     QAbstractButton::enterEvent(event);
       
   149 }
       
   150 
       
   151 void QDockWidgetTitleButton::leaveEvent(QEvent *event)
       
   152 {
       
   153     if (isEnabled()) update();
       
   154     QAbstractButton::leaveEvent(event);
       
   155 }
       
   156 
       
   157 void 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 
       
   191 QDockWidgetLayout::QDockWidgetLayout(QWidget *parent)
       
   192     : QLayout(parent), verticalTitleBar(false), item_list(RoleCount, 0)
       
   193 {
       
   194 }
       
   195 
       
   196 QDockWidgetLayout::~QDockWidgetLayout()
       
   197 {
       
   198     qDeleteAll(item_list);
       
   199 }
       
   200 
       
   201 bool QDockWidgetLayout::nativeWindowDeco() const
       
   202 {
       
   203     return nativeWindowDeco(parentWidget()->isWindow());
       
   204 }
       
   205 
       
   206 bool 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 
       
   217 void QDockWidgetLayout::addItem(QLayoutItem*)
       
   218 {
       
   219     qWarning() << "QDockWidgetLayout::addItem(): please use QDockWidgetLayout::setWidget()";
       
   220     return;
       
   221 }
       
   222 
       
   223 QLayoutItem *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 
       
   236 QLayoutItem *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 
       
   253 int 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 
       
   263 QSize 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 
       
   330 QSize 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 
       
   341 QSize 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 
       
   352 QSize 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 
       
   363 QWidget *QDockWidgetLayout::widgetForRole(Role r) const
       
   364 {
       
   365     QLayoutItem *item = item_list.at(r);
       
   366     return item == 0 ? 0 : item->widget();
       
   367 }
       
   368 
       
   369 QLayoutItem *QDockWidgetLayout::itemForRole(Role r) const
       
   370 {
       
   371     return item_list.at(r);
       
   372 }
       
   373 
       
   374 void 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 
       
   393 static inline int pick(bool vertical, const QSize &size)
       
   394 {
       
   395     return vertical ? size.height() : size.width();
       
   396 }
       
   397 
       
   398 static inline int perp(bool vertical, const QSize &size)
       
   399 {
       
   400     return vertical ? size.width() : size.height();
       
   401 }
       
   402 
       
   403 int 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 
       
   431 int 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 
       
   462 void 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 
       
   527 void 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 
       
   540 QDockWidgetItem::QDockWidgetItem(QDockWidget *dockWidget)
       
   541     : QWidgetItem(dockWidget)
       
   542 {
       
   543 }
       
   544 
       
   545 QSize 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 
       
   553 QSize 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 
       
   563 QSize 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 
       
   576 void 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 */
       
   616 void 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 
       
   638 void 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 
       
   649 void 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 
       
   680 void QDockWidgetPrivate::_q_toggleTopLevel()
       
   681 {
       
   682     Q_Q(QDockWidget);
       
   683     q->setFloating(!q->isFloating());
       
   684 }
       
   685 
       
   686 void 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 
       
   707 void 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 
       
   734 void 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 
       
   775 bool 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 
       
   791 bool 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 
       
   824 bool 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 
       
   840 bool 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 
       
   882 bool 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 
       
   895 void 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 
       
   970 void 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 
       
   991 void 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 
       
  1002 void QDockWidgetPrivate::plug(const QRect &rect)
       
  1003 {
       
  1004     setWindowState(false, false, rect);
       
  1005 }
       
  1006 
       
  1007 void 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 */
       
  1151 QDockWidget::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 */
       
  1169 QDockWidget::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 */
       
  1180 QDockWidget::~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 */
       
  1189 QWidget *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 */
       
  1206 void 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 
       
  1222 void 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 
       
  1243 QDockWidget::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 */
       
  1261 void 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 
       
  1290 void 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 
       
  1300 Qt::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 */
       
  1314 void 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 */
       
  1344 void 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 */
       
  1353 void 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 */
       
  1381 bool 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  */
       
  1487 QAction * 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 
       
  1572 void 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 
       
  1593 QWidget *QDockWidget::titleBarWidget() const
       
  1594 {
       
  1595     QDockWidgetLayout *layout
       
  1596         = qobject_cast<QDockWidgetLayout*>(this->layout());
       
  1597     return layout->widgetForRole(QDockWidgetLayout::TitleBar);
       
  1598 }
       
  1599 
       
  1600 QT_END_NAMESPACE
       
  1601 
       
  1602 #include "qdockwidget.moc"
       
  1603 #include "moc_qdockwidget.cpp"
       
  1604 
       
  1605 #endif // QT_NO_DOCKWIDGET