~ubuntu-branches/ubuntu/wily/qtbase-opensource-src/wily

« back to all changes in this revision

Viewing changes to src/widgets/widgets/qdockwidget.cpp

  • Committer: Package Import Robot
  • Author(s): Timo Jyrinki
  • Date: 2013-02-05 12:46:17 UTC
  • Revision ID: package-import@ubuntu.com-20130205124617-c8jouts182j002fx
Tags: upstream-5.0.1+dfsg
ImportĀ upstreamĀ versionĀ 5.0.1+dfsg

Show diffs side-by-side

added added

removed removed

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