src/gui/widgets/qdockwidget.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 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.lineSpacing() + 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     Q_Q(QDockWidget);
       
   689 
       
   690     if (state != 0)
       
   691         return;
       
   692 
       
   693     QMainWindow *win = qobject_cast<QMainWindow*>(parent);
       
   694     Q_ASSERT(win != 0);
       
   695     QMainWindowLayout *layout = qobject_cast<QMainWindowLayout*>(win->layout());
       
   696     Q_ASSERT(layout != 0);
       
   697     if (layout->layoutState.indexOf(q).isEmpty()) //The dock widget has not been added into the main window
       
   698         return;
       
   699     if (layout->pluggingWidget != 0) // the main window is animating a docking operation
       
   700         return;
       
   701 
       
   702     state = new QDockWidgetPrivate::DragState;
       
   703     state->pressPos = pos;
       
   704     state->dragging = false;
       
   705     state->widgetItem = 0;
       
   706     state->ownWidgetItem = false;
       
   707     state->nca = nca;
       
   708     state->ctrlDrag = false;
       
   709 }
       
   710 
       
   711 void QDockWidgetPrivate::startDrag()
       
   712 {
       
   713     Q_Q(QDockWidget);
       
   714 
       
   715     if (state == 0 || state->dragging)
       
   716         return;
       
   717 
       
   718     QMainWindowLayout *layout
       
   719         = qobject_cast<QMainWindowLayout *>(q->parentWidget()->layout());
       
   720     Q_ASSERT(layout != 0);
       
   721 
       
   722     state->widgetItem = layout->unplug(q);
       
   723     if (state->widgetItem == 0) {
       
   724         /* I have a QMainWindow parent, but I was never inserted with
       
   725             QMainWindow::addDockWidget, so the QMainWindowLayout has no
       
   726             widget item for me. :( I have to create it myself, and then
       
   727             delete it if I don't get dropped into a dock area. */
       
   728         state->widgetItem = new QDockWidgetItem(q);
       
   729         state->ownWidgetItem = true;
       
   730     }
       
   731 
       
   732     if (state->ctrlDrag)
       
   733         layout->restore();
       
   734 
       
   735     state->dragging = true;
       
   736 }
       
   737 
       
   738 void QDockWidgetPrivate::endDrag(bool abort)
       
   739 {
       
   740     Q_Q(QDockWidget);
       
   741     Q_ASSERT(state != 0);
       
   742 
       
   743     q->releaseMouse();
       
   744 
       
   745     if (state->dragging) {
       
   746         QMainWindowLayout *mwLayout =
       
   747             qobject_cast<QMainWindowLayout *>(q->parentWidget()->layout());
       
   748         Q_ASSERT(mwLayout != 0);
       
   749 
       
   750         if (abort || !mwLayout->plug(state->widgetItem)) {
       
   751             if (hasFeature(this, QDockWidget::DockWidgetFloatable)) {
       
   752                 if (state->ownWidgetItem)
       
   753                     delete state->widgetItem;
       
   754                 mwLayout->restore();
       
   755 #ifdef Q_WS_X11
       
   756                 // get rid of the X11BypassWindowManager window flag and activate the resizer
       
   757                 Qt::WindowFlags flags = q->windowFlags();
       
   758                 flags &= ~Qt::X11BypassWindowManagerHint;
       
   759                 q->setWindowFlags(flags);
       
   760                 resizer->setActive(QWidgetResizeHandler::Resize, true);
       
   761                 q->show();
       
   762 #else
       
   763                 QDockWidgetLayout *myLayout
       
   764                     = qobject_cast<QDockWidgetLayout*>(layout);
       
   765                 resizer->setActive(QWidgetResizeHandler::Resize,
       
   766                                     myLayout->widgetForRole(QDockWidgetLayout::TitleBar) != 0);
       
   767 #endif
       
   768                 undockedGeometry = q->geometry();
       
   769                 q->activateWindow();
       
   770             } else {
       
   771                 mwLayout->revert(state->widgetItem);
       
   772             }
       
   773         }
       
   774     }
       
   775     delete state;
       
   776     state = 0;
       
   777 }
       
   778 
       
   779 bool QDockWidgetPrivate::isAnimating() const
       
   780 {
       
   781     Q_Q(const QDockWidget);
       
   782 
       
   783     QMainWindow *mainWin = qobject_cast<QMainWindow*>(parent);
       
   784     if (mainWin == 0)
       
   785         return false;
       
   786 
       
   787     QMainWindowLayout *mainWinLayout
       
   788         = qobject_cast<QMainWindowLayout*>(mainWin->layout());
       
   789     if (mainWinLayout == 0)
       
   790         return false;
       
   791 
       
   792     return (void*)mainWinLayout->pluggingWidget == (void*)q;
       
   793 }
       
   794 
       
   795 bool QDockWidgetPrivate::mousePressEvent(QMouseEvent *event)
       
   796 {
       
   797 #if !defined(QT_NO_MAINWINDOW)
       
   798     Q_Q(QDockWidget);
       
   799 
       
   800     QDockWidgetLayout *dwLayout
       
   801         = qobject_cast<QDockWidgetLayout*>(layout);
       
   802 
       
   803     if (!dwLayout->nativeWindowDeco()) {
       
   804         QRect titleArea = dwLayout->titleArea();
       
   805 
       
   806         if (event->button() != Qt::LeftButton ||
       
   807             !titleArea.contains(event->pos()) ||
       
   808             // check if the tool window is movable... do nothing if it
       
   809             // is not (but allow moving if the window is floating)
       
   810             (!hasFeature(this, QDockWidget::DockWidgetMovable) && !q->isFloating()) ||
       
   811             qobject_cast<QMainWindow*>(parent) == 0 ||
       
   812             isAnimating() || state != 0) {
       
   813             return false;
       
   814         }
       
   815 
       
   816         initDrag(event->pos(), false);
       
   817 
       
   818         if (state)
       
   819             state->ctrlDrag = hasFeature(this, QDockWidget::DockWidgetFloatable) && event->modifiers() & Qt::ControlModifier;
       
   820 
       
   821         return true;
       
   822     }
       
   823 
       
   824 #endif // !defined(QT_NO_MAINWINDOW)
       
   825     return false;
       
   826 }
       
   827 
       
   828 bool QDockWidgetPrivate::mouseDoubleClickEvent(QMouseEvent *event)
       
   829 {
       
   830     QDockWidgetLayout *dwLayout = qobject_cast<QDockWidgetLayout*>(layout);
       
   831 
       
   832     if (!dwLayout->nativeWindowDeco()) {
       
   833         QRect titleArea = dwLayout->titleArea();
       
   834 
       
   835         if (event->button() == Qt::LeftButton && titleArea.contains(event->pos()) &&
       
   836             hasFeature(this, QDockWidget::DockWidgetFloatable)) {
       
   837             _q_toggleTopLevel();
       
   838             return true;
       
   839         }
       
   840     }
       
   841     return false;
       
   842 }
       
   843 
       
   844 bool QDockWidgetPrivate::mouseMoveEvent(QMouseEvent *event)
       
   845 {
       
   846     bool ret = false;
       
   847 #if !defined(QT_NO_MAINWINDOW)
       
   848     Q_Q(QDockWidget);
       
   849 
       
   850     if (!state)
       
   851         return ret;
       
   852 
       
   853     QDockWidgetLayout *dwlayout
       
   854         = qobject_cast<QDockWidgetLayout*>(layout);
       
   855     QMainWindowLayout *mwlayout
       
   856         = qobject_cast<QMainWindowLayout*>(q->parentWidget()->layout());
       
   857     if (!dwlayout->nativeWindowDeco()) {
       
   858         if (!state->dragging
       
   859             && mwlayout->pluggingWidget == 0
       
   860             && (event->pos() - state->pressPos).manhattanLength()
       
   861                 > QApplication::startDragDistance()) {
       
   862             startDrag();
       
   863 #ifdef Q_OS_WIN
       
   864             grabMouseWhileInWindow();
       
   865 #else
       
   866             q->grabMouse();
       
   867 #endif
       
   868             ret = true;
       
   869         }
       
   870     }
       
   871 
       
   872     if (state->dragging && !state->nca) {
       
   873         QPoint pos = event->globalPos() - state->pressPos;
       
   874         q->move(pos);
       
   875 
       
   876         if (!state->ctrlDrag)
       
   877             mwlayout->hover(state->widgetItem, event->globalPos());
       
   878 
       
   879         ret = true;
       
   880     }
       
   881 
       
   882 #endif // !defined(QT_NO_MAINWINDOW)
       
   883     return ret;
       
   884 }
       
   885 
       
   886 bool QDockWidgetPrivate::mouseReleaseEvent(QMouseEvent *event)
       
   887 {
       
   888 #if !defined(QT_NO_MAINWINDOW)
       
   889 
       
   890     if (event->button() == Qt::LeftButton && state && !state->nca) {
       
   891         endDrag();
       
   892         return true; //filter out the event
       
   893     }
       
   894 
       
   895 #endif // !defined(QT_NO_MAINWINDOW)
       
   896     return false;
       
   897 }
       
   898 
       
   899 void QDockWidgetPrivate::nonClientAreaMouseEvent(QMouseEvent *event)
       
   900 {
       
   901     Q_Q(QDockWidget);
       
   902 
       
   903     int fw = q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, q);
       
   904 
       
   905     QRect geo = q->geometry();
       
   906     QRect titleRect = q->frameGeometry();
       
   907 #ifdef Q_WS_MAC
       
   908     if ((features & QDockWidget::DockWidgetVerticalTitleBar)) {
       
   909         titleRect.setTop(geo.top());
       
   910         titleRect.setBottom(geo.bottom());
       
   911         titleRect.setRight(geo.left() - 1);
       
   912     } else
       
   913 #endif
       
   914     {
       
   915         titleRect.setLeft(geo.left());
       
   916         titleRect.setRight(geo.right());
       
   917         titleRect.setBottom(geo.top() - 1);
       
   918         titleRect.adjust(0, fw, 0, 0);
       
   919     }
       
   920 
       
   921     switch (event->type()) {
       
   922         case QEvent::NonClientAreaMouseButtonPress:
       
   923             if (!titleRect.contains(event->globalPos()))
       
   924                 break;
       
   925             if (state != 0)
       
   926                 break;
       
   927             if (qobject_cast<QMainWindow*>(parent) == 0)
       
   928                 break;
       
   929             if (isAnimating())
       
   930                 break;
       
   931             initDrag(event->pos(), true);
       
   932             if (state == 0)
       
   933                 break;
       
   934 #ifdef Q_OS_WIN
       
   935             // On Windows, NCA mouse events don't contain modifier info
       
   936             state->ctrlDrag = GetKeyState(VK_CONTROL) & 0x8000;
       
   937 #else
       
   938             state->ctrlDrag = event->modifiers() & Qt::ControlModifier;
       
   939 #endif
       
   940             startDrag();
       
   941             break;
       
   942         case QEvent::NonClientAreaMouseMove:
       
   943             if (state == 0 || !state->dragging)
       
   944                 break;
       
   945             if (state->nca) {
       
   946                 endDrag();
       
   947             }
       
   948 #ifdef Q_OS_MAC
       
   949             else { // workaround for lack of mouse-grab on Mac
       
   950                 QMainWindowLayout *layout
       
   951                     = qobject_cast<QMainWindowLayout *>(q->parentWidget()->layout());
       
   952                 Q_ASSERT(layout != 0);
       
   953 
       
   954                 q->move(event->globalPos() - state->pressPos);
       
   955                 if (!state->ctrlDrag)
       
   956                     layout->hover(state->widgetItem, event->globalPos());
       
   957             }
       
   958 #endif
       
   959             break;
       
   960         case QEvent::NonClientAreaMouseButtonRelease:
       
   961 #ifdef Q_OS_MAC
       
   962                         if (state)
       
   963                                 endDrag();
       
   964 #endif
       
   965                         break;
       
   966         case QEvent::NonClientAreaMouseButtonDblClick:
       
   967             _q_toggleTopLevel();
       
   968             break;
       
   969         default:
       
   970             break;
       
   971     }
       
   972 }
       
   973 
       
   974 void QDockWidgetPrivate::moveEvent(QMoveEvent *event)
       
   975 {
       
   976     Q_Q(QDockWidget);
       
   977 
       
   978     if (state == 0 || !state->dragging || !state->nca || !q->isWindow())
       
   979         return;
       
   980 
       
   981     // When the native window frame is being dragged, all we get is these mouse
       
   982     // move events.
       
   983 
       
   984     if (state->ctrlDrag)
       
   985         return;
       
   986 
       
   987     QMainWindowLayout *layout
       
   988         = qobject_cast<QMainWindowLayout *>(q->parentWidget()->layout());
       
   989     Q_ASSERT(layout != 0);
       
   990 
       
   991     QPoint globalMousePos = event->pos() + state->pressPos;
       
   992     layout->hover(state->widgetItem, globalMousePos);
       
   993 }
       
   994 
       
   995 void QDockWidgetPrivate::unplug(const QRect &rect)
       
   996 {
       
   997     Q_Q(QDockWidget);
       
   998     QRect r = rect;
       
   999     r.moveTopLeft(q->mapToGlobal(QPoint(0, 0)));
       
  1000     QDockWidgetLayout *dwLayout = qobject_cast<QDockWidgetLayout*>(layout);
       
  1001     if (dwLayout->nativeWindowDeco(true))
       
  1002         r.adjust(0, dwLayout->titleHeight(), 0, 0);
       
  1003     setWindowState(true, true, r);
       
  1004 }
       
  1005 
       
  1006 void QDockWidgetPrivate::plug(const QRect &rect)
       
  1007 {
       
  1008     setWindowState(false, false, rect);
       
  1009 }
       
  1010 
       
  1011 void QDockWidgetPrivate::setWindowState(bool floating, bool unplug, const QRect &rect)
       
  1012 {
       
  1013     Q_Q(QDockWidget);
       
  1014 
       
  1015     bool wasFloating = q->isFloating();
       
  1016     bool hidden = q->isHidden();
       
  1017 
       
  1018     if (q->isVisible())
       
  1019         q->hide();
       
  1020 
       
  1021     Qt::WindowFlags flags = floating ? Qt::Tool : Qt::Widget;
       
  1022 
       
  1023     QDockWidgetLayout *dwLayout = qobject_cast<QDockWidgetLayout*>(layout);
       
  1024     const bool nativeDeco = dwLayout->nativeWindowDeco(floating);
       
  1025 
       
  1026     if (nativeDeco) {
       
  1027         flags |= Qt::CustomizeWindowHint | Qt::WindowTitleHint;
       
  1028         if (hasFeature(this, QDockWidget::DockWidgetClosable))
       
  1029             flags |= Qt::WindowCloseButtonHint;
       
  1030     } else {
       
  1031         flags |= Qt::FramelessWindowHint;
       
  1032     }
       
  1033 
       
  1034     if (unplug)
       
  1035         flags |= Qt::X11BypassWindowManagerHint;
       
  1036 
       
  1037     q->setWindowFlags(flags);
       
  1038 
       
  1039 #if defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA)
       
  1040     if (floating && nativeDeco && (q->features() & QDockWidget::DockWidgetVerticalTitleBar)) {
       
  1041         ChangeWindowAttributes(HIViewGetWindow(HIViewRef(q->winId())), kWindowSideTitlebarAttribute, 0);
       
  1042     }
       
  1043 #endif
       
  1044 
       
  1045     if (!rect.isNull())
       
  1046         q->setGeometry(rect);
       
  1047 
       
  1048     updateButtons();
       
  1049 
       
  1050     if (!hidden)
       
  1051         q->show();
       
  1052 
       
  1053     if (floating != wasFloating) {
       
  1054         emit q->topLevelChanged(floating);
       
  1055         if (!floating && parent) {
       
  1056             QMainWindowLayout *mwlayout = qobject_cast<QMainWindowLayout *>(q->parentWidget()->layout());
       
  1057             if (mwlayout)
       
  1058                 emit q->dockLocationChanged(mwlayout->dockWidgetArea(q));
       
  1059         }
       
  1060     }
       
  1061 
       
  1062     resizer->setActive(QWidgetResizeHandler::Resize, !unplug && floating && !nativeDeco);
       
  1063 }
       
  1064 
       
  1065 /*!
       
  1066     \class QDockWidget
       
  1067 
       
  1068     \brief The QDockWidget class provides a widget that can be docked
       
  1069     inside a QMainWindow or floated as a top-level window on the
       
  1070     desktop.
       
  1071 
       
  1072     \ingroup mainwindow-classes
       
  1073 
       
  1074     QDockWidget provides the concept of dock widgets, also know as
       
  1075     tool palettes or utility windows.  Dock windows are secondary
       
  1076     windows placed in the \e {dock widget area} around the
       
  1077     \l{QMainWindow::centralWidget()}{central widget} in a
       
  1078     QMainWindow.
       
  1079 
       
  1080     \image mainwindow-docks.png
       
  1081 
       
  1082     Dock windows can be moved inside their current area, moved into
       
  1083     new areas and floated (e.g., undocked) by the end-user.  The
       
  1084     QDockWidget API allows the programmer to restrict the dock widgets
       
  1085     ability to move, float and close, as well as the areas in which
       
  1086     they can be placed.
       
  1087 
       
  1088     \section1 Appearance
       
  1089 
       
  1090     A QDockWidget consists of a title bar and the content area.  The
       
  1091     title bar displays the dock widgets \link QWidget::windowTitle()
       
  1092     window title\endlink, a \e float button and a \e close button.
       
  1093     Depending on the state of the QDockWidget, the \e float and \e
       
  1094     close buttons may be either disabled or not shown at all.
       
  1095 
       
  1096     The visual appearance of the title bar and buttons is dependent
       
  1097     on the \l{QStyle}{style} in use.
       
  1098 
       
  1099     A QDockWidget acts as a wrapper for its child widget, set with setWidget().
       
  1100     Custom size hints, minimum and maximum sizes and size policies should be
       
  1101     implemented in the child widget. QDockWidget will respect them, adjusting
       
  1102     its own constraints to include the frame and title. Size constraints
       
  1103     should not be set on the QDockWidget itself, because they change depending
       
  1104     on whether it is docked; a docked QDockWidget has no frame and a smaller title
       
  1105     bar.
       
  1106 
       
  1107     \sa QMainWindow, {Dock Widgets Example}
       
  1108 */
       
  1109 
       
  1110 /*!
       
  1111     \enum QDockWidget::DockWidgetFeature
       
  1112 
       
  1113     \value DockWidgetClosable   The dock widget can be closed. On some systems the dock
       
  1114 	                            widget always has a close button when it's floating
       
  1115 								(for example on MacOS 10.5).
       
  1116     \value DockWidgetMovable    The dock widget can be moved between docks
       
  1117                                 by the user.
       
  1118     \value DockWidgetFloatable  The dock widget can be detached from the
       
  1119                                 main window, and floated as an independent
       
  1120                                 window.
       
  1121     \value DockWidgetVerticalTitleBar The dock widget displays a vertical title
       
  1122                                   bar on its left side. This can be used to
       
  1123                                   increase the amount of vertical space in
       
  1124                                   a QMainWindow.
       
  1125     \value AllDockWidgetFeatures  (Deprecated) The dock widget can be closed, moved,
       
  1126                                   and floated. Since new features might be added in future
       
  1127                                   releases, the look and behavior of dock widgets might
       
  1128                                   change if you use this flag. Please specify individual
       
  1129                                   flags instead.
       
  1130     \value NoDockWidgetFeatures   The dock widget cannot be closed, moved,
       
  1131                                   or floated.
       
  1132 
       
  1133     \omitvalue DockWidgetFeatureMask
       
  1134     \omitvalue Reserved
       
  1135 */
       
  1136 
       
  1137 /*!
       
  1138     \property QDockWidget::windowTitle
       
  1139     \brief the dock widget title (caption)
       
  1140 
       
  1141     By default, this property contains an empty string.
       
  1142 */
       
  1143 
       
  1144 /*!
       
  1145     Constructs a QDockWidget with parent \a parent and window flags \a
       
  1146     flags. The dock widget will be placed in the left dock widget
       
  1147     area.
       
  1148 */
       
  1149 QDockWidget::QDockWidget(QWidget *parent, Qt::WindowFlags flags)
       
  1150     : QWidget(*new QDockWidgetPrivate, parent, flags)
       
  1151 {
       
  1152     Q_D(QDockWidget);
       
  1153     d->init();
       
  1154 }
       
  1155 
       
  1156 /*!
       
  1157     Constructs a QDockWidget with parent \a parent and window flags \a
       
  1158     flags. The dock widget will be placed in the left dock widget
       
  1159     area.
       
  1160 
       
  1161     The window title is set to \a title. This title is used when the
       
  1162     QDockWidget is docked and undocked. It is also used in the context
       
  1163     menu provided by QMainWindow.
       
  1164 
       
  1165     \sa setWindowTitle()
       
  1166 */
       
  1167 QDockWidget::QDockWidget(const QString &title, QWidget *parent, Qt::WindowFlags flags)
       
  1168     : QWidget(*new QDockWidgetPrivate, parent, flags)
       
  1169 {
       
  1170     Q_D(QDockWidget);
       
  1171     d->init();
       
  1172     setWindowTitle(title);
       
  1173 }
       
  1174 
       
  1175 /*!
       
  1176     Destroys the dock widget.
       
  1177 */
       
  1178 QDockWidget::~QDockWidget()
       
  1179 { }
       
  1180 
       
  1181 /*!
       
  1182     Returns the widget for the dock widget. This function returns zero
       
  1183     if the widget has not been set.
       
  1184 
       
  1185     \sa setWidget()
       
  1186 */
       
  1187 QWidget *QDockWidget::widget() const
       
  1188 {
       
  1189     QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(this->layout());
       
  1190     return layout->widgetForRole(QDockWidgetLayout::Content);
       
  1191 }
       
  1192 
       
  1193 /*!
       
  1194     Sets the widget for the dock widget to \a widget.
       
  1195 
       
  1196     If the dock widget is visible when \a widget is added, you must
       
  1197     \l{QWidget::}{show()} it explicitly.
       
  1198 
       
  1199     Note that you must add the layout of the \a widget before you call
       
  1200     this function; if not, the \a widget will not be visible.
       
  1201 
       
  1202     \sa widget()
       
  1203 */
       
  1204 void QDockWidget::setWidget(QWidget *widget)
       
  1205 {
       
  1206     QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(this->layout());
       
  1207     layout->setWidgetForRole(QDockWidgetLayout::Content, widget);
       
  1208 }
       
  1209 
       
  1210 /*!
       
  1211     \property QDockWidget::features
       
  1212     \brief whether the dock widget is movable, closable, and floatable
       
  1213 
       
  1214     By default, this property is set to a combination of DockWidgetClosable,
       
  1215     DockWidgetMovable and DockWidgetFloatable.
       
  1216 
       
  1217     \sa DockWidgetFeature
       
  1218 */
       
  1219 
       
  1220 void QDockWidget::setFeatures(QDockWidget::DockWidgetFeatures features)
       
  1221 {
       
  1222     Q_D(QDockWidget);
       
  1223     features &= DockWidgetFeatureMask;
       
  1224     if (d->features == features)
       
  1225         return;
       
  1226     d->features = features;
       
  1227     QDockWidgetLayout *layout
       
  1228         = qobject_cast<QDockWidgetLayout*>(this->layout());
       
  1229     layout->setVerticalTitleBar(features & DockWidgetVerticalTitleBar);
       
  1230     d->updateButtons();
       
  1231     d->toggleViewAction->setEnabled((d->features & DockWidgetClosable) == DockWidgetClosable);
       
  1232     emit featuresChanged(d->features);
       
  1233     update();
       
  1234 }
       
  1235 
       
  1236 QDockWidget::DockWidgetFeatures QDockWidget::features() const
       
  1237 {
       
  1238     Q_D(const QDockWidget);
       
  1239     return d->features;
       
  1240 }
       
  1241 
       
  1242 /*!
       
  1243     \property QDockWidget::floating
       
  1244     \brief whether the dock widget is floating
       
  1245 
       
  1246     A floating dock widget is presented to the user as an independent
       
  1247     window "on top" of its parent QMainWindow, instead of being
       
  1248     docked in the QMainWindow.
       
  1249 
       
  1250     By default, this property is true.
       
  1251 
       
  1252     \sa isWindow()
       
  1253 */
       
  1254 void QDockWidget::setFloating(bool floating)
       
  1255 {
       
  1256     Q_D(QDockWidget);
       
  1257 
       
  1258     // the initial click of a double-click may have started a drag...
       
  1259     if (d->state != 0)
       
  1260         d->endDrag(true);
       
  1261 
       
  1262     QRect r = d->undockedGeometry;
       
  1263 
       
  1264     d->setWindowState(floating, false, floating ? r : QRect());
       
  1265     if (floating && r.isNull()) {
       
  1266         QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(this->layout());
       
  1267         QRect titleArea = layout->titleArea();
       
  1268         int h = layout->verticalTitleBar ? titleArea.width() : titleArea.height();
       
  1269         QPoint p = mapToGlobal(QPoint(h, h));
       
  1270         move(p);
       
  1271     }
       
  1272 }
       
  1273 
       
  1274 /*!
       
  1275     \property QDockWidget::allowedAreas
       
  1276     \brief areas where the dock widget may be placed
       
  1277 
       
  1278     The default is Qt::AllDockWidgetAreas.
       
  1279 
       
  1280     \sa Qt::DockWidgetArea
       
  1281 */
       
  1282 
       
  1283 void QDockWidget::setAllowedAreas(Qt::DockWidgetAreas areas)
       
  1284 {
       
  1285     Q_D(QDockWidget);
       
  1286     areas &= Qt::DockWidgetArea_Mask;
       
  1287     if (areas == d->allowedAreas)
       
  1288         return;
       
  1289     d->allowedAreas = areas;
       
  1290     emit allowedAreasChanged(d->allowedAreas);
       
  1291 }
       
  1292 
       
  1293 Qt::DockWidgetAreas QDockWidget::allowedAreas() const
       
  1294 {
       
  1295     Q_D(const QDockWidget);
       
  1296     return d->allowedAreas;
       
  1297 }
       
  1298 
       
  1299 /*!
       
  1300     \fn bool QDockWidget::isAreaAllowed(Qt::DockWidgetArea area) const
       
  1301 
       
  1302     Returns true if this dock widget can be placed in the given \a area;
       
  1303     otherwise returns false.
       
  1304 */
       
  1305 
       
  1306 /*! \reimp */
       
  1307 void QDockWidget::changeEvent(QEvent *event)
       
  1308 {
       
  1309     Q_D(QDockWidget);
       
  1310     QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(this->layout());
       
  1311 
       
  1312     switch (event->type()) {
       
  1313     case QEvent::ModifiedChange:
       
  1314     case QEvent::WindowTitleChange:
       
  1315         update(layout->titleArea());
       
  1316 #ifndef QT_NO_ACTION
       
  1317         d->fixedWindowTitle = qt_setWindowTitle_helperHelper(windowTitle(), this);
       
  1318         d->toggleViewAction->setText(d->fixedWindowTitle);
       
  1319 #endif
       
  1320 #ifndef QT_NO_TABBAR
       
  1321         {
       
  1322             QMainWindow *win = qobject_cast<QMainWindow*>(parentWidget());
       
  1323             if (QMainWindowLayout *winLayout =
       
  1324                 (win ? qobject_cast<QMainWindowLayout*>(win->layout()) : 0))
       
  1325                 if (QDockAreaLayoutInfo *info = winLayout->layoutState.dockAreaLayout.info(this))
       
  1326                     info->updateTabBar();
       
  1327         }
       
  1328 #endif // QT_NO_TABBAR
       
  1329         break;
       
  1330     default:
       
  1331         break;
       
  1332     }
       
  1333     QWidget::changeEvent(event);
       
  1334 }
       
  1335 
       
  1336 /*! \reimp */
       
  1337 void 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 */
       
  1346 void 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 */
       
  1374 bool 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(geometry().right() >= 0 && geometry().bottom() >= 0);
       
  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  */
       
  1480 QAction * 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 
       
  1565 void 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 
       
  1586 QWidget *QDockWidget::titleBarWidget() const
       
  1587 {
       
  1588     QDockWidgetLayout *layout
       
  1589         = qobject_cast<QDockWidgetLayout*>(this->layout());
       
  1590     return layout->widgetForRole(QDockWidgetLayout::TitleBar);
       
  1591 }
       
  1592 
       
  1593 QT_END_NAMESPACE
       
  1594 
       
  1595 #include "qdockwidget.moc"
       
  1596 #include "moc_qdockwidget.cpp"
       
  1597 
       
  1598 #endif // QT_NO_DOCKWIDGET