1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the Qt3Support 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 The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "q3dockwindow.h"
43 
44 #ifndef QT_NO_MAINWINDOW
45 #include "qapplication.h"
46 #include "qcursor.h"
47 #include "qdesktopwidget.h"
48 #include "q3dockarea.h"
49 #include "qevent.h"
50 #include "qlayout.h"
51 #include "q3mainwindow.h"
52 #include "qpainter.h"
53 #include "qpointer.h"
54 #include "qstyle.h"
55 #include "qstyleoption.h"
56 #include "qtimer.h"
57 #include "q3toolbar.h"
58 #include "qtoolbutton.h"
59 #include "qtooltip.h"
60 #include <private/q3titlebar_p.h>
61 #include <private/qwidgetresizehandler_p.h>
62 #include <qrubberband.h>
63 #include <qdebug.h>
64 
65 QT_BEGIN_NAMESPACE
66 
67 #ifdef Q_WS_MAC
68 static bool default_opaque = true;
69 #else
70 static bool default_opaque = false;
71 #endif
72 
73 class Q3DockWindowPrivate
74 {
75 };
76 
77 class Q3DockWindowResizeHandle : public QWidget
78 {
79     Q_OBJECT
80 
81 public:
82     Q3DockWindowResizeHandle(Qt::Orientation o, QWidget *parent, Q3DockWindow *w, const char* /*name*/=0);
83     void setOrientation(Qt::Orientation o);
orientation() const84     Qt::Orientation orientation() const { return orient; }
85 
86     QSize sizeHint() const;
87 
88 protected:
89     void paintEvent(QPaintEvent *);
90     void mouseMoveEvent(QMouseEvent *);
91     void mousePressEvent(QMouseEvent *);
92     void mouseReleaseEvent(QMouseEvent *);
93     bool event(QEvent *event);
94 
95 private:
96     void startLineDraw();
97     void endLineDraw();
98     void drawLine(const QPoint &globalPos);
99 
100 private:
101     Qt::Orientation orient;
102     bool mousePressed;
103     QRubberBand *rubberBand;
104     QPoint lastPos, firstPos;
105     Q3DockWindow *dockWindow;
106     bool mouseOver;
107 };
108 
Q3DockWindowResizeHandle(Qt::Orientation o,QWidget * parent,Q3DockWindow * w,const char *)109 Q3DockWindowResizeHandle::Q3DockWindowResizeHandle(Qt::Orientation o, QWidget *parent,
110                                                   Q3DockWindow *w, const char *)
111     : QWidget(parent, "qt_dockwidget_internal"), mousePressed(false), rubberBand(0), dockWindow(w),
112       mouseOver(false)
113 {
114     setOrientation(o);
115 }
116 
sizeHint() const117 QSize Q3DockWindowResizeHandle::sizeHint() const
118 {
119     QStyleOptionQ3DockWindow opt;
120     opt.init(this);
121     if (!dockWindow->area() || dockWindow->area()->orientation() == Qt::Horizontal)
122         opt.state |= QStyle::State_Horizontal;
123 
124     opt.rect = rect();
125     opt.docked = dockWindow->area();
126     opt.closeEnabled = dockWindow->isCloseEnabled();
127     int sw = 2 * style()->pixelMetric(QStyle::PM_SplitterWidth, &opt, this) / 3;
128     return (style()->sizeFromContents(QStyle::CT_Q3DockWindow, &opt, QSize(sw, sw), this).expandedTo(QApplication::globalStrut()));
129 }
130 
setOrientation(Qt::Orientation o)131 void Q3DockWindowResizeHandle::setOrientation(Qt::Orientation o)
132 {
133     orient = o;
134     if (o == Qt::Horizontal) {
135 #ifndef QT_NO_CURSOR
136         setCursor(Qt::splitVCursor);
137 #endif
138         setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
139     } else {
140 #ifndef QT_NO_CURSOR
141         setCursor(Qt::splitHCursor);
142 #endif
143         setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding));
144     }
145 }
146 
mousePressEvent(QMouseEvent * e)147 void Q3DockWindowResizeHandle::mousePressEvent(QMouseEvent *e)
148 {
149     e->ignore();
150     if (e->button() != Qt::LeftButton)
151         return;
152     e->accept();
153     mousePressed = true;
154     if (!dockWindow->opaqueMoving())
155         startLineDraw();
156     lastPos = firstPos = e->globalPos();
157     if (!dockWindow->opaqueMoving())
158         drawLine(e->globalPos());
159 }
160 
mouseMoveEvent(QMouseEvent * e)161 void Q3DockWindowResizeHandle::mouseMoveEvent(QMouseEvent *e)
162 {
163     if (!mousePressed)
164         return;
165     if (!dockWindow->opaqueMoving()) {
166         if (orientation() != dockWindow->area()->orientation()) {
167             if (orientation() == Qt::Horizontal) {
168                 int minpos = dockWindow->area()->mapToGlobal(QPoint(0, 0)).y();
169                 int maxpos = dockWindow->area()->mapToGlobal(QPoint(0, 0)).y() + dockWindow->area()->height();
170                 if (e->globalPos().y() < minpos || e->globalPos().y() > maxpos)
171                     return;
172             } else {
173                 int minpos = dockWindow->area()->mapToGlobal(QPoint(0, 0)).x();
174                 int maxpos = dockWindow->area()->mapToGlobal(QPoint(0, 0)).x() + dockWindow->area()->width();
175                 if (e->globalPos().x() < minpos || e->globalPos().x() > maxpos)
176                     return;
177             }
178         } else {
179             QWidget *w = dockWindow->area()->window();
180             if (w) {
181                 if (orientation() == Qt::Horizontal) {
182                     int minpos = w->mapToGlobal(QPoint(0, 0)).y();
183                     int maxpos = w->mapToGlobal(QPoint(0, 0)).y() + w->height();
184                     if (e->globalPos().y() < minpos || e->globalPos().y() > maxpos)
185                         return;
186                 } else {
187                     int minpos = w->mapToGlobal(QPoint(0, 0)).x();
188                     int maxpos = w->mapToGlobal(QPoint(0, 0)).x() + w->width();
189                     if (e->globalPos().x() < minpos || e->globalPos().x() > maxpos)
190                         return;
191                 }
192             }
193         }
194     }
195 
196     if (!dockWindow->opaqueMoving())
197         drawLine(lastPos);
198     lastPos = e->globalPos();
199     if (dockWindow->opaqueMoving()) {
200         mouseReleaseEvent(e);
201         mousePressed = true;
202         firstPos = e->globalPos();
203     }
204     if (!dockWindow->opaqueMoving())
205         drawLine(e->globalPos());
206 }
207 
mouseReleaseEvent(QMouseEvent * e)208 void Q3DockWindowResizeHandle::mouseReleaseEvent(QMouseEvent *e)
209 {
210     if (mousePressed) {
211         if (!dockWindow->opaqueMoving()) {
212             drawLine(lastPos);
213             endLineDraw();
214         }
215         if (orientation() != dockWindow->area()->orientation())
216             dockWindow->area()->invalidNextOffset(dockWindow);
217         if (orientation() == Qt::Horizontal) {
218             int dy;
219             if (dockWindow->area()->handlePosition() == Q3DockArea::Normal || orientation() != dockWindow->area()->orientation())
220                 dy = e->globalPos().y() - firstPos.y();
221             else
222                 dy =  firstPos.y() - e->globalPos().y();
223             int d = dockWindow->height() + dy;
224             if (orientation() != dockWindow->area()->orientation()) {
225                 dockWindow->setFixedExtentHeight(-1);
226                 d = qMax(d, dockWindow->minimumHeight());
227                 int ms = dockWindow->area()->maxSpace(d, dockWindow);
228                 d = qMin(d, ms);
229                 dockWindow->setFixedExtentHeight(d);
230             } else {
231                 dockWindow->area()->setFixedExtent(d, dockWindow);
232             }
233         } else {
234             int dx;
235             if (dockWindow->area()->handlePosition() == Q3DockArea::Normal || orientation() != dockWindow->area()->orientation())
236                 dx = e->globalPos().x() - firstPos.x();
237             else
238                 dx = firstPos.x() - e->globalPos().x();
239             int d = dockWindow->width() + dx;
240             if (orientation() != dockWindow->area()->orientation()) {
241                 dockWindow->setFixedExtentWidth(-1);
242                 d = qMax(d, dockWindow->minimumWidth());
243                 int ms = dockWindow->area()->maxSpace(d, dockWindow);
244                 d = qMin(d, ms);
245                 dockWindow->setFixedExtentWidth(d);
246             } else {
247                 dockWindow->area()->setFixedExtent(d, dockWindow);
248             }
249         }
250     }
251 
252     QApplication::postEvent(dockWindow->area(), new QEvent(QEvent::LayoutHint));
253     mousePressed = false;
254 }
255 
event(QEvent * event)256 bool Q3DockWindowResizeHandle::event(QEvent *event)
257 {
258     switch (event->type()) {
259     case QEvent::HoverEnter:
260         if (!mouseOver) {
261             mouseOver = true;
262             update();
263         }
264         break;
265     case QEvent::HoverLeave:
266         if (mouseOver) {
267             mouseOver = false;
268             update();
269         }
270         break;
271     default:
272         break;
273     }
274     return QWidget::event(event);
275 }
276 
paintEvent(QPaintEvent *)277 void Q3DockWindowResizeHandle::paintEvent(QPaintEvent *)
278 {
279     QPainter p(this);
280     QStyleOption opt(0);
281     opt.init(this);
282     if (orientation() == Qt::Horizontal)
283         opt.state |= QStyle::State_Horizontal;
284     style()->drawPrimitive(QStyle::PE_IndicatorDockWidgetResizeHandle, &opt, &p, this);
285 }
286 
startLineDraw()287 void Q3DockWindowResizeHandle::startLineDraw()
288 {
289     if (rubberBand)
290         endLineDraw();
291     rubberBand = new QRubberBand(QRubberBand::Line);
292     rubberBand->setGeometry(-1, -1, 1, 1);
293     rubberBand->show();
294 }
295 
endLineDraw()296 void Q3DockWindowResizeHandle::endLineDraw()
297 {
298     delete rubberBand;
299     rubberBand = 0;
300 }
301 
drawLine(const QPoint & globalPos)302 void Q3DockWindowResizeHandle::drawLine(const QPoint &globalPos)
303 {
304     QPoint start = mapToGlobal(QPoint(0, 0));
305     QPoint starta = dockWindow->area()->mapToGlobal(QPoint(0, 0));
306     QPoint end = globalPos;
307     if (orientation() == Qt::Horizontal) {
308         if (orientation() == dockWindow->orientation())
309             rubberBand->setGeometry(starta.x(), end.y(), dockWindow->area()->width(), height());
310         else
311             rubberBand->setGeometry(start.x(), end.y(), width(), height());
312     } else {
313         if (orientation() == dockWindow->orientation())
314             rubberBand->setGeometry(end.x(), starta.y(), width(), dockWindow->area()->height());
315         else
316             rubberBand->setGeometry(end.x(), start.y(), width(), height());
317     }
318 }
319 
realWidgetPos(Q3DockWindow * w)320 static QPoint realWidgetPos(Q3DockWindow *w)
321 {
322     if (!w->parentWidget() || w->place() == Q3DockWindow::OutsideDock)
323         return w->pos();
324     return w->parentWidget()->mapToGlobal(w->geometry().topLeft());
325 }
326 
327 class Q3DockWindowHandle : public QWidget
328 {
329     Q_OBJECT
330     Q_PROPERTY(QString windowTitle READ windowTitle)
331     friend class Q3DockWindow;
332     friend class Q3DockWindowTitleBar;
333 
334 public:
335     Q3DockWindowHandle(Q3DockWindow *dw);
336     void updateGui();
337 
338     QSize minimumSizeHint() const;
minimumSize() const339     QSize minimumSize() const { return minimumSizeHint(); }
sizeHint() const340     QSize sizeHint() const { return minimumSize(); }
setOpaqueMoving(bool b)341     void setOpaqueMoving(bool b) { opaque = b; }
342 
windowTitle() const343     QString windowTitle() const { return dockWindow->windowTitle(); }
344 
345 signals:
346     void doubleClicked();
347 
348 protected:
349     void paintEvent(QPaintEvent *e);
350     void resizeEvent(QResizeEvent *e);
351     void mousePressEvent(QMouseEvent *e);
352     void mouseMoveEvent(QMouseEvent *e);
353     void mouseReleaseEvent(QMouseEvent *e);
354     void mouseDoubleClickEvent(QMouseEvent *e);
355     void keyPressEvent(QKeyEvent *e);
356     void keyReleaseEvent(QKeyEvent *e);
357     void changeEvent(QEvent *);
358 
359 private slots:
360     void minimize();
361 
362 private:
363     Q3DockWindow *dockWindow;
364     QPoint offset;
365     QToolButton *closeButton;
366     QTimer *timer;
367     uint opaque                : 1;
368     uint mousePressed        : 1;
369     uint hadDblClick        : 1;
370     uint ctrlDown : 1;
371     QPointer<QWidget> oldFocus;
372 };
373 
374 class Q3DockWindowTitleBar : public Q3TitleBar
375 {
376     Q_OBJECT
377     friend class Q3DockWindow;
378     friend class Q3DockWindowHandle;
379 
380 public:
381     Q3DockWindowTitleBar(Q3DockWindow *dw);
382     void updateGui();
setOpaqueMoving(bool b)383     void setOpaqueMoving(bool b) { opaque = b; }
384 
385 protected:
386     void resizeEvent(QResizeEvent *e);
387     void mousePressEvent(QMouseEvent *e);
388     void mouseMoveEvent(QMouseEvent *e);
389     void mouseReleaseEvent(QMouseEvent *e);
390     void mouseDoubleClickEvent(QMouseEvent *e);
391     void keyPressEvent(QKeyEvent *e);
392     void keyReleaseEvent(QKeyEvent *e);
393 
394 private:
395     Q3DockWindow *dockWindow;
396     QPoint offset;
397     uint mousePressed : 1;
398     uint hadDblClick : 1;
399     uint opaque : 1;
400     uint ctrlDown : 1;
401     QPointer<QWidget> oldFocus;
402 
403 };
404 
Q3DockWindowHandle(Q3DockWindow * dw)405 Q3DockWindowHandle::Q3DockWindowHandle(Q3DockWindow *dw)
406     : QWidget(dw, "qt_dockwidget_internal"), dockWindow(dw),
407       closeButton(0), opaque(default_opaque), mousePressed(false)
408 {
409     ctrlDown = false;
410     timer = new QTimer(this);
411     connect(timer, SIGNAL(timeout()), this, SLOT(minimize()));
412 #if defined(Q_WS_WIN) && !defined(QT_NO_CURSOR)
413     setCursor(Qt::SizeAllCursor);
414 #endif
415 }
416 
paintEvent(QPaintEvent * e)417 void Q3DockWindowHandle::paintEvent(QPaintEvent *e)
418 {
419     if (!dockWindow->dockArea && !opaque)
420         return;
421     QPainter p(this);
422     QStyleOptionQ3DockWindow opt;
423     opt.init(this);
424     if (!dockWindow->area() || dockWindow->area()->orientation() == Qt::Horizontal)
425         opt.state |= QStyle::State_Horizontal;
426 
427     opt.rect = rect();
428     opt.docked = dockWindow->area();
429     opt.closeEnabled = dockWindow->isCloseEnabled();
430     opt.rect = QStyle::visualRect(opt.direction, opt.rect,
431                                   style()->subElementRect(QStyle::SE_Q3DockWindowHandleRect, &opt, this));
432     style()->drawPrimitive(QStyle::PE_IndicatorToolBarHandle, &opt, &p, this);
433     QWidget::paintEvent(e);
434 }
435 
keyPressEvent(QKeyEvent * e)436 void Q3DockWindowHandle::keyPressEvent(QKeyEvent *e)
437 {
438     if (!mousePressed)
439         return;
440     if (e->key() == Qt::Key_Control) {
441         ctrlDown = true;
442         dockWindow->handleMove(mapFromGlobal(QCursor::pos()) - offset, QCursor::pos(), !opaque);
443     }
444 }
445 
keyReleaseEvent(QKeyEvent * e)446 void Q3DockWindowHandle::keyReleaseEvent(QKeyEvent *e)
447 {
448     if (!mousePressed)
449         return;
450     if (e->key() == Qt::Key_Control) {
451         ctrlDown = false;
452         dockWindow->handleMove(mapFromGlobal(QCursor::pos()) - offset, QCursor::pos(), !opaque);
453     }
454 }
455 
mousePressEvent(QMouseEvent * e)456 void Q3DockWindowHandle::mousePressEvent(QMouseEvent *e)
457 {
458     if (!dockWindow->dockArea)
459         return;
460     ctrlDown = (e->state() & Qt::ControlButton) == Qt::ControlButton;
461     oldFocus = qApp->focusWidget();
462     setFocus();
463     e->ignore();
464     if (e->button() != Qt::LeftButton)
465         return;
466     e->accept();
467     hadDblClick = false;
468     mousePressed = true;
469     offset = e->pos();
470     dockWindow->startRectDraw(mapToGlobal(e->pos()), !opaque);
471     if (!opaque)
472         qApp->installEventFilter(dockWindow);
473 }
474 
mouseMoveEvent(QMouseEvent * e)475 void Q3DockWindowHandle::mouseMoveEvent(QMouseEvent *e)
476 {
477     if (!mousePressed || e->pos() == offset)
478         return;
479     ctrlDown = (e->state() & Qt::ControlButton) == Qt::ControlButton;
480     dockWindow->handleMove(e->pos() - offset, e->globalPos(), !opaque);
481     if (opaque)
482         dockWindow->updatePosition(e->globalPos());
483 }
484 
mouseReleaseEvent(QMouseEvent * e)485 void Q3DockWindowHandle::mouseReleaseEvent(QMouseEvent *e)
486 {
487     ctrlDown = false;
488     qApp->removeEventFilter(dockWindow);
489     if (oldFocus)
490         oldFocus->setFocus();
491     if (!mousePressed)
492         return;
493     dockWindow->endRectDraw(!opaque);
494     mousePressed = false;
495 #ifdef Q_WS_MAC
496     releaseMouse();
497 #endif
498     if (!hadDblClick && offset == e->pos()) {
499         timer->start(QApplication::doubleClickInterval(), true);
500     } else if (!hadDblClick) {
501         dockWindow->updatePosition(e->globalPos());
502     }
503     if (opaque)
504         dockWindow->titleBar->mousePressed = false;
505     if (dockWindow->parentWidget())
506         QApplication::postEvent(dockWindow->parentWidget(), new QEvent(QEvent::LayoutHint));
507 }
508 
minimize()509 void Q3DockWindowHandle::minimize()
510 {
511     if (!dockWindow->area())
512         return;
513 
514     Q3MainWindow *mw = qobject_cast<Q3MainWindow*>(dockWindow->area()->parentWidget());
515     if (mw && mw->isDockEnabled(dockWindow, Qt::DockMinimized))
516         mw->moveDockWindow(dockWindow, Qt::DockMinimized);
517 }
518 
resizeEvent(QResizeEvent *)519 void Q3DockWindowHandle::resizeEvent(QResizeEvent *)
520 {
521     updateGui();
522 }
523 
updateGui()524 void Q3DockWindowHandle::updateGui()
525 {
526     updateGeometry();
527 
528     if (!closeButton) {
529         closeButton = new QToolButton(this, "qt_close_button1");
530 #ifndef QT_NO_CURSOR
531         closeButton->setCursor(Qt::ArrowCursor);
532 #endif
533         QStyleOption opt(0);
534         opt.init(closeButton);
535         closeButton->setIcon(style()->standardIcon(QStyle::SP_DockWidgetCloseButton, &opt,
536                                                     closeButton));
537         closeButton->setFixedSize(12, 12);
538         connect(closeButton, SIGNAL(clicked()),
539                  dockWindow, SLOT(hide()));
540     }
541 
542     if (dockWindow->isCloseEnabled() && dockWindow->area())
543         closeButton->show();
544     else
545         closeButton->hide();
546 
547     if (!dockWindow->area())
548         return;
549 
550     if (dockWindow->area()->orientation() == Qt::Horizontal) {
551         int off = (width() - closeButton->width() - 1) / 2;
552         closeButton->move(off, 2);
553     } else {
554         int off = (height() - closeButton->height() - 1) / 2;
555         int x = QApplication::reverseLayout() ? 2 : width() - closeButton->width() - 2;
556         closeButton->move(x, off);
557     }
558 }
559 
changeEvent(QEvent * ev)560 void Q3DockWindowHandle::changeEvent(QEvent *ev)
561 {
562     if(ev->type() == QEvent::StyleChange) {
563         if (closeButton) {
564             QStyleOption opt(0);
565             opt.init(closeButton);
566             closeButton->setIcon(style()->standardIcon(QStyle::SP_DockWidgetCloseButton,
567                                                         &opt, closeButton));
568         }
569     }
570     QWidget::changeEvent(ev);
571 }
572 
minimumSizeHint() const573 QSize Q3DockWindowHandle::minimumSizeHint() const
574 {
575     if (!dockWindow->dockArea)
576         return QSize(0, 0);
577     int wh = dockWindow->isCloseEnabled() ? 17 : style()->pixelMetric(QStyle::PM_ToolBarHandleExtent, 0, this);
578     if (dockWindow->orientation() == Qt::Horizontal)
579         return QSize(wh, 0);
580     return QSize(0, wh);
581 }
582 
mouseDoubleClickEvent(QMouseEvent * e)583 void Q3DockWindowHandle::mouseDoubleClickEvent(QMouseEvent *e)
584 {
585     e->ignore();
586     if (e->button() != Qt::LeftButton)
587         return;
588     e->accept();
589     timer->stop();
590     emit doubleClicked();
591     hadDblClick = true;
592     if (dockWindow->parentWidget())
593         QApplication::postEvent(dockWindow->parentWidget(), new QEvent(QEvent::LayoutHint));
594 }
595 
Q3DockWindowTitleBar(Q3DockWindow * dw)596 Q3DockWindowTitleBar::Q3DockWindowTitleBar(Q3DockWindow *dw)
597     : Q3TitleBar(0, dw), dockWindow(dw),
598       mousePressed(false), hadDblClick(false), opaque(default_opaque)
599 {
600     setObjectName(QLatin1String("qt_dockwidget_internal"));
601     ctrlDown = false;
602     setMouseTracking(true);
603     QStyleOptionTitleBar opt = getStyleOption();
604     setFixedHeight(style()->pixelMetric(QStyle::PM_TitleBarHeight, &opt, this));
605     connect(this, SIGNAL(doClose()), dockWindow, SLOT(hide()));
606 }
607 
keyPressEvent(QKeyEvent * e)608 void Q3DockWindowTitleBar::keyPressEvent(QKeyEvent *e)
609 {
610     if (!mousePressed)
611         return;
612     if (e->key() == Qt::Key_Control) {
613         ctrlDown = true;
614         dockWindow->handleMove(mapFromGlobal(QCursor::pos()) - offset, QCursor::pos(), !opaque);
615     }
616 }
617 
keyReleaseEvent(QKeyEvent * e)618 void Q3DockWindowTitleBar::keyReleaseEvent(QKeyEvent *e)
619 {
620     if (!mousePressed)
621         return;
622     if (e->key() == Qt::Key_Control) {
623         ctrlDown = false;
624         dockWindow->handleMove(mapFromGlobal(QCursor::pos()) - offset, QCursor::pos(), !opaque);
625     }
626 }
627 
mousePressEvent(QMouseEvent * e)628 void Q3DockWindowTitleBar::mousePressEvent(QMouseEvent *e)
629 {
630     QStyleOptionTitleBar opt;
631     opt.init(this);
632     opt.subControls = QStyle::SC_All;
633     opt.activeSubControls = QStyle::SC_None;
634     opt.text = windowTitle();
635     //################
636     QIcon icon = windowIcon();
637     QSize s = icon.actualSize(QSize(64, 64));
638     opt.icon = icon.pixmap(s);
639     opt.titleBarState = window() ? window()->windowState() : static_cast<Qt::WindowStates>(Qt::WindowNoState);
640     opt.titleBarFlags = fakeWindowFlags();
641     QStyle::SubControl tbctrl = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt,
642                                                                e->pos(), this);
643 
644     if (tbctrl < QStyle::SC_TitleBarLabel && tbctrl != QStyle::SC_None) {
645         Q3TitleBar::mousePressEvent(e);
646         return;
647     }
648 
649     ctrlDown = (e->state() & Qt::ControlButton) == Qt::ControlButton;
650     oldFocus = qApp->focusWidget();
651 // setFocus activates the window, which deactivates the main window
652 // not what we want, and not required anyway on Windows
653 #ifndef Q_WS_WIN
654     setFocus();
655 #endif
656 
657     e->ignore();
658     if (e->button() != Qt::LeftButton)
659         return;
660     if (e->y() < 3 && dockWindow->isResizeEnabled())
661         return;
662 
663     e->accept();
664     bool oldPressed = mousePressed;
665     mousePressed = true;
666     hadDblClick = false;
667     offset = e->pos();
668     dockWindow->startRectDraw(mapToGlobal(e->pos()), !opaque);
669 // grabMouse resets the Windows mouse press count, so we never receive a double click on Windows
670 // not required on Windows, and did work on X11, too, but no problem there in the first place
671 #ifndef Q_WS_WIN
672     if(!oldPressed && dockWindow->opaqueMoving())
673         grabMouse();
674 #else
675     Q_UNUSED(oldPressed);
676 #endif
677 }
678 
mouseMoveEvent(QMouseEvent * e)679 void Q3DockWindowTitleBar::mouseMoveEvent(QMouseEvent *e)
680 {
681     if (!mousePressed) {
682         Q3TitleBar::mouseMoveEvent(e);
683         return;
684     }
685 
686     ctrlDown = (e->state() & Qt::ControlButton) == Qt::ControlButton;
687     e->accept();
688     dockWindow->handleMove(e->pos() - offset, e->globalPos(), !opaque);
689 }
690 
mouseReleaseEvent(QMouseEvent * e)691 void Q3DockWindowTitleBar::mouseReleaseEvent(QMouseEvent *e)
692 {
693     if (!mousePressed) {
694         Q3TitleBar::mouseReleaseEvent(e);
695         return;
696     }
697 
698     ctrlDown = false;
699     qApp->removeEventFilter(dockWindow);
700     if (oldFocus)
701         oldFocus->setFocus();
702 
703     if (dockWindow->place() == Q3DockWindow::OutsideDock)
704         dockWindow->raise();
705 
706     if(dockWindow->opaqueMoving())
707         releaseMouse();
708     if (!mousePressed)
709         return;
710     dockWindow->endRectDraw(!opaque);
711     mousePressed = false;
712     if (!hadDblClick)
713         dockWindow->updatePosition(e->globalPos());
714     if (opaque) {
715         dockWindow->horHandle->mousePressed = false;
716         dockWindow->verHandle->mousePressed = false;
717     }
718     if (dockWindow->parentWidget())
719         QApplication::postEvent(dockWindow->parentWidget(), new QEvent(QEvent::LayoutHint));
720 }
721 
resizeEvent(QResizeEvent * e)722 void Q3DockWindowTitleBar::resizeEvent(QResizeEvent *e)
723 {
724     updateGui();
725     Q3TitleBar::resizeEvent(e);
726 }
727 
updateGui()728 void Q3DockWindowTitleBar::updateGui()
729 {
730     if (dockWindow->isCloseEnabled()) {
731         setFakeWindowFlags(fakeWindowFlags() | Qt::WStyle_SysMenu);
732     } else {
733         setFakeWindowFlags(fakeWindowFlags() & ~Qt::WStyle_SysMenu);
734     }
735 }
736 
mouseDoubleClickEvent(QMouseEvent *)737 void Q3DockWindowTitleBar::mouseDoubleClickEvent(QMouseEvent *)
738 {
739     emit doubleClicked();
740     hadDblClick = true;
741     if (dockWindow->parentWidget())
742         QApplication::postEvent(dockWindow->parentWidget(), new QEvent(QEvent::LayoutHint));
743 }
744 
745 /*!
746     \class Q3DockWindow
747     \brief The Q3DockWindow class provides a widget which can be docked
748     inside a Q3DockArea or floated as a top level window on the
749     desktop.
750 
751     \compat
752 
753     This class handles moving, resizing, docking and undocking dock
754     windows. Q3ToolBar is a subclass of Q3DockWindow so the
755     functionality provided for dock windows is available with the same
756     API for toolbars.
757 
758     \img qmainwindow-qdockareas.png Q3DockWindows in a Q3DockArea
759     \caption Two Q3DockWindows (\l{Q3ToolBar}s) in a \l Q3DockArea
760 
761     \img qdockwindow.png A Q3DockWindow
762     \caption A Floating Q3DockWindow
763 
764     If the user drags the dock window into the dock area the dock
765     window will be docked. If the user drags the dock area outside any
766     dock areas the dock window will be undocked (floated) and will
767     become a top level window. Double clicking a floating dock
768     window's title bar will dock the dock window to the last dock area
769     it was docked in. Double clicking a docked dock window's handle
770     will undock (float) the dock window.
771     \omit
772     Single clicking a docked dock window's handle will minimize the
773     dock window (only its handle will appear, below the menu bar).
774     Single clicking the minimized handle will restore the dock window
775     to the last dock area that it was docked in.
776     \endomit
777     If the user clicks the close button (which appears on floating
778     dock windows by default) the dock window will disappear. You can
779     control whether or not a dock window has a close button with
780     setCloseMode().
781 
782     Q3MainWindow provides four dock areas (top, left, right and bottom)
783     which can be used by dock windows. For many applications using the
784     dock areas provided by Q3MainWindow is sufficient. (See the \l
785     Q3DockArea documentation if you want to create your own dock
786     areas.) In Q3MainWindow a right-click popup menu (the dock window
787     menu) is available which lists dock windows and can be used to
788     show or hide them. (The popup menu only lists dock windows that
789     have a \link QWidget::setWindowTitle() caption\endlink.)
790 
791     When you construct a dock window you \e must pass it a Q3DockArea
792     or a Q3MainWindow as its parent if you want it docked. Pass 0 for
793     the parent if you want it floated.
794 
795     \snippet doc/src/snippets/code/src_qt3support_widgets_q3dockwindow.cpp 0
796 
797     In the example above we create a new Q3ToolBar in the constructor
798     of a Q3MainWindow subclass (so that the \e this pointer points to
799     the Q3MainWindow). By default the toolbar will be added to the \c
800     Top dock area, but we've moved it to the \c Left dock area.
801 
802     A dock window is often used to contain a single widget. In these
803     cases the widget can be set by calling setWidget(). If you're
804     constructing a dock window that contains multiple widgets, e.g. a
805     toolbar, arrange the widgets within a box layout inside the dock
806     window. To do this use the boxLayout() function to get a pointer
807     to the dock window's box layout, then add widgets to the layout
808     using the box layout's QBoxLayout::addWidget() function. The dock
809     window will dynamically set the orientation of the layout to be
810     vertical or horizontal as necessary, although you can control this
811     yourself with setOrientation().
812 
813     Although a common use of dock windows is for toolbars, they can be
814     used with any widgets. When using larger
815     widgets it may make sense for the dock window to be resizable by
816     calling setResizeEnabled(). Resizable dock windows are given
817     splitter-like handles to allow the user to resize them within
818     their dock area. When resizable dock windows are undocked they
819     become top level windows and can be resized like any other top
820     level windows, e.g. by dragging a corner or edge.
821 
822     Qt::Dock windows can be docked and undocked using dock() and undock().
823     A dock window's orientation can be set with setOrientation(). You
824     can also use Q3DockArea::moveDockWindow(). If you're using a
825     Q3MainWindow, Q3MainWindow::moveDockWindow() and
826     Q3MainWindow::removeDockWindow() are available.
827 
828     A dock window can have some preferred settings, for example, you
829     can set a preferred offset from the left edge (or top edge for
830     vertical dock areas) of the dock area using setOffset(). If you'd
831     prefer a dock window to start on a new line when it is docked use
832     setNewLine(). The setFixedExtentWidth() and setFixedExtentHeight()
833     functions can be used to define the dock window's preferred size,
834     and the setHorizontallyStretchable() and setVerticallyStretchable()
835     functions set whether the dock window can be stretched or not.
836     Dock windows can be moved by default, but this can be changed with
837     setMovingEnabled(). When a dock window is moved it is shown as a
838     rectangular outline, but it can be shown normally using
839     setOpaqueMoving().
840 
841     When a dock window's visibility changes, i.e. it is shown or
842     hidden, the visibilityChanged() signal is emitted. When a dock
843     window is docked, undocked or moved inside the dock area the
844     placeChanged() signal is emitted.
845 */
846 
847 /*!
848     \enum Q3DockWindow::Place
849 
850     This enum specifies the possible locations for a Q3DockWindow:
851 
852     \value InDock  Inside a Q3DockArea.
853     \value OutsideDock  Floating as a top level window on the desktop.
854 */
855 
856 /*!
857     \enum Q3DockWindow::CloseMode
858 
859     This enum type specifies when (if ever) a dock window has a close
860     button.
861 
862     \value Never  The dock window never has a close button and cannot
863     be closed by the user.
864     \value Docked  The dock window has a close button only when
865     docked.
866     \value Undocked  The dock window has a close button only when
867     floating.
868     \value Always The dock window always has a close button.
869     \omit
870     Note that dock windows can always be minimized if the user clicks
871     their dock window handle when they are docked.
872     \endomit
873 */
874 
875 /*!
876     \fn void Q3DockWindow::setHorizontalStretchable(bool b)
877 
878     If \a b is true the dock window is set to be horizontally
879     stretchable.
880 */
881 /*!
882     \fn void Q3DockWindow::setVerticalStretchable(bool b)
883 
884     If \a b is true the dock window is set to be vertically
885     stretchable.
886 */
887 /*!
888     \fn bool Q3DockWindow::isHorizontalStretchable() const
889 
890     Returns true if the dock window can be stretched horizontally;
891     otherwise returns false.
892 */
893 /*!
894     \fn bool Q3DockWindow::isVerticalStretchable() const
895 
896     Returns true if the dock window can be stretched vertically;
897     otherwise returns false.
898 */
899 /*!
900     \fn void Q3DockWindow::orientationChanged(Qt::Orientation o)
901 
902     This signal is emitted when the orientation of the dock window is
903     changed. The new orientation is \a o.
904 */
905 
906 /*!
907     \fn void Q3DockWindow::placeChanged(Q3DockWindow::Place p)
908 
909     This signal is emitted when the dock window is docked (\a p is \c
910     InDock), undocked (\a p is \c OutsideDock) or moved inside the
911     the dock area.
912 
913     \sa Q3DockArea::moveDockWindow(), Q3DockArea::removeDockWindow(),
914     Q3MainWindow::moveDockWindow(), Q3MainWindow::removeDockWindow()
915 */
916 
917 /*!
918     \fn void Q3DockWindow::visibilityChanged(bool visible)
919 
920     This signal is emitted when the visibility of the dock window
921     relatively to its dock area is changed. If \a visible is true, the
922     Q3DockWindow is now visible to the dock area, otherwise it has been
923     hidden.
924 
925     A dock window can be hidden if it has a close button which the
926     user has clicked. In the case of a Q3MainWindow a dock window can
927     have its visibility changed (hidden or shown) by clicking its name
928     in the dock window menu that lists the Q3MainWindow's dock windows.
929 */
930 
931 /*!
932     \fn Q3DockArea *Q3DockWindow::area() const
933 
934     Returns the dock area in which this dock window is docked, or 0 if
935     the dock window is floating.
936 */
937 
938 /*!
939     \property Q3DockWindow::place
940     \brief the location where the dock window is placed
941 
942     This is either \c InDock or \c OutsideDock.
943 
944     \sa Q3DockArea::moveDockWindow(), Q3DockArea::removeDockWindow(),
945         Q3MainWindow::moveDockWindow(), Q3MainWindow::removeDockWindow()
946 */
947 
948 /*!
949     Constructs a Q3DockWindow with parent \a parent, called \a name and
950     with widget flags \a f.
951 */
952 
Q3DockWindow(QWidget * parent,const char * name,Qt::WindowFlags f)953 Q3DockWindow::Q3DockWindow(QWidget* parent, const char* name, Qt::WindowFlags f)
954     : Q3Frame(parent, name, f | Qt::WType_Dialog | Qt::WStyle_Customize | Qt::WStyle_NoBorder)
955 {
956     curPlace = InDock;
957     isToolbar = false;
958     init();
959 }
960 
961 /*!
962     Constructs a Q3DockWindow with parent \a parent, called \a name and
963     with widget flags \a f.
964 
965     If \a p is \c InDock, the dock window is docked into a dock area
966     and \a parent \e must be a Q3DockArea or a Q3MainWindow. If the \a
967     parent is a Q3MainWindow the dock window will be docked in the main
968     window's \c Top dock area.
969 
970     If \a p is \c OutsideDock, the dock window is created as a floating
971     window.
972 
973     We recommend creating the dock area \c InDock with a Q3MainWindow
974     as parent then calling Q3MainWindow::moveDockWindow() to move the
975     dock window where you want it.
976 */
977 
Q3DockWindow(Place p,QWidget * parent,const char * name,Qt::WindowFlags f)978 Q3DockWindow::Q3DockWindow(Place p, QWidget *parent, const char *name, Qt::WindowFlags f)
979     : Q3Frame(parent, name, f | Qt::WType_Dialog | Qt::WStyle_Customize | Qt::WStyle_NoBorder)
980 {
981     curPlace = p;
982     isToolbar = false;
983     init();
984 }
985 
986 /*! \internal
987 */
988 
Q3DockWindow(Place p,QWidget * parent,const char * name,Qt::WindowFlags f,bool toolbar)989 Q3DockWindow::Q3DockWindow(Place p, QWidget *parent, const char *name, Qt::WindowFlags f, bool toolbar)
990     : Q3Frame(parent, name, f | Qt::WType_Dialog | Qt::WStyle_Customize | Qt::WStyle_NoBorder)
991 {
992     curPlace = p;
993     isToolbar = toolbar;
994     init();
995 }
996 
997 class Q3DockWindowGridLayout : public QGridLayout
998 {
999 public:
Q3DockWindowGridLayout(QWidget * parent,int nRows,int nCols)1000     Q3DockWindowGridLayout(QWidget *parent, int nRows, int nCols)
1001         : QGridLayout(parent, nRows, nCols) {};
1002 
expandingDirections() const1003     Qt::Orientations expandingDirections() const
1004     {
1005         return 0;
1006     }
1007 };
1008 
init()1009 void Q3DockWindow::init()
1010 {
1011     wid = 0;
1012     rubberBand = 0;
1013     dockArea = 0;
1014     tmpDockArea = 0;
1015     resizeEnabled = false;
1016     moveEnabled = true;
1017     nl = false;
1018     opaque = default_opaque;
1019     cMode = Never;
1020     offs = 0;
1021     fExtent = QSize(-1, -1);
1022     dockWindowData = 0;
1023     lastPos = QPoint(-1, -1);
1024     lastSize = QSize(-1, -1);
1025     stretchable[Qt::Horizontal] = false;
1026     stretchable[Qt::Vertical] = false;
1027 
1028     widgetResizeHandler = new QWidgetResizeHandler(this);
1029     widgetResizeHandler->setMovingEnabled(false);
1030 
1031     titleBar      = new Q3DockWindowTitleBar(this);
1032     verHandle     = new Q3DockWindowHandle(this);
1033     verHandle->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred));
1034     horHandle     = new Q3DockWindowHandle(this);
1035     horHandle->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
1036 
1037     vHandleLeft   = new Q3DockWindowResizeHandle(Qt::Vertical, this, this, "vert. handle");
1038     vHandleRight  = new Q3DockWindowResizeHandle(Qt::Vertical, this, this, "vert. handle");
1039     hHandleTop    = new Q3DockWindowResizeHandle(Qt::Horizontal, this, this, "horz. handle");
1040     hHandleBottom = new Q3DockWindowResizeHandle(Qt::Horizontal, this, this, "horz. handle");
1041 
1042     // Creating inner layout
1043     hbox          = new QVBoxLayout();
1044     vbox          = new QHBoxLayout();
1045     childBox          = new QBoxLayout(QBoxLayout::LeftToRight);
1046     vbox->addSpacing(2);
1047     vbox->addWidget(verHandle);
1048     vbox->addStretch(0);
1049     vbox->addLayout(childBox, 1);
1050     vbox->addStretch(0);
1051 
1052     hbox->setResizeMode(QLayout::FreeResize);
1053     hbox->setMargin(isResizeEnabled() || curPlace == OutsideDock ? 2 : 0);
1054     hbox->setSpacing(1);
1055     hbox->addWidget(titleBar);
1056     hbox->addWidget(horHandle);
1057     hbox->addLayout(vbox);
1058 
1059     // Set up the initial handle layout for Qt::Vertical
1060     // Handle layout will change on calls to setOrienation()
1061     QGridLayout *glayout = new Q3DockWindowGridLayout(this, 3, 3);
1062     glayout->setResizeMode(QLayout::Minimum);
1063     glayout->addMultiCellWidget(hHandleTop,    0, 0, 1, 1);
1064     glayout->addMultiCellWidget(hHandleBottom, 2, 2, 1, 1);
1065     glayout->addMultiCellWidget(vHandleLeft,   0, 2, 0, 0);
1066     glayout->addMultiCellWidget(vHandleRight,  0, 2, 2, 2);
1067     glayout->addLayout(hbox, 1, 1);
1068     glayout->setRowStretch(1, 1);
1069     glayout->setColStretch(1, 1);
1070 
1071     hHandleBottom->hide();
1072     vHandleRight->hide();
1073     hHandleTop->hide();
1074     vHandleLeft->hide();
1075     setFrameStyle(Q3Frame::StyledPanel | Q3Frame::Raised);
1076     setLineWidth(2);
1077 
1078     if (parentWidget())
1079         parentWidget()->installEventFilter(this);
1080     QWidget *mw = parentWidget();
1081     Q3DockArea *da = qobject_cast<Q3DockArea*>(parentWidget());
1082     if (da) {
1083         if (curPlace == InDock)
1084             da->moveDockWindow(this);
1085         mw = da->parentWidget();
1086     }
1087     if (qobject_cast<Q3MainWindow*>(mw)) {
1088         if (place() == InDock) {
1089             Qt::Dock myDock = Qt::DockTop;
1090             // make sure we put the window in the correct dock.
1091             if (dockArea) {
1092                 Q3MainWindow *mainw = (Q3MainWindow*)mw;
1093                 // I'm not checking if it matches the top because I've
1094                 // done the assignment to it above.
1095                 if (dockArea == mainw->leftDock())
1096                     myDock = Qt::DockLeft;
1097                 else if (dockArea == mainw->rightDock())
1098                     myDock = Qt::DockRight;
1099                 else if (dockArea == mainw->bottomDock())
1100                     myDock = Qt::DockBottom;
1101             }
1102             ((Q3MainWindow*)mw)->addDockWindow(this, myDock);
1103         }
1104         moveEnabled = ((Q3MainWindow*)mw)->dockWindowsMovable();
1105         opaque = ((Q3MainWindow*)mw)->opaqueMoving();
1106     }
1107 
1108     updateGui();
1109 
1110     connect(titleBar, SIGNAL(doubleClicked()), this, SLOT(dock()));
1111     connect(verHandle, SIGNAL(doubleClicked()), this, SLOT(undock()));
1112     connect(horHandle, SIGNAL(doubleClicked()), this, SLOT(undock()));
1113     connect(this, SIGNAL(orientationChanged(Qt::Orientation)),
1114              this, SLOT(setOrientation(Qt::Orientation)));
1115 }
1116 
1117 /*!
1118     Sets the orientation of the dock window to \a o. The orientation
1119     is propagated to the layout boxLayout().
1120 
1121     \warning All undocked Q3ToolBars will always have a horizontal orientation.
1122 */
1123 
setOrientation(Qt::Orientation o)1124 void Q3DockWindow::setOrientation(Qt::Orientation o)
1125 {
1126     QGridLayout *glayout = (QGridLayout*)layout();
1127     glayout->removeWidget(hHandleTop);
1128     glayout->removeWidget(hHandleBottom);
1129     glayout->removeWidget(vHandleLeft);
1130     glayout->removeWidget(vHandleRight);
1131 
1132     if (o == Qt::Horizontal) {
1133         // Set up the new layout as
1134         //   3 3 3      1 = vHandleLeft   4 = hHandleBottom
1135         //   1 X 2      2 = vHandleRight  X = Inner Layout
1136         //   4 4 4      3 = hHandleTop
1137         glayout->addMultiCellWidget(hHandleTop,    0, 0, 0, 2);
1138         glayout->addMultiCellWidget(hHandleBottom, 2, 2, 0, 2);
1139         glayout->addMultiCellWidget(vHandleLeft,   1, 1, 0, 0);
1140         glayout->addMultiCellWidget(vHandleRight,  1, 1, 2, 2);
1141     } else {
1142         // Set up the new layout as
1143         //   1 3 2      1 = vHandleLeft   4 = hHandleBottom
1144         //   1 X 2      2 = vHandleRight  X = Inner Layout
1145         //   1 4 2      3 = hHandleTop
1146         glayout->addMultiCellWidget(hHandleTop,    0, 0, 1, 1);
1147         glayout->addMultiCellWidget(hHandleBottom, 2, 2, 1, 1);
1148         glayout->addMultiCellWidget(vHandleLeft,   0, 2, 0, 0);
1149         glayout->addMultiCellWidget(vHandleRight,  0, 2, 2, 2);
1150     }
1151     boxLayout()->setDirection(o == Qt::Horizontal ? QBoxLayout::LeftToRight : QBoxLayout::TopToBottom);
1152     QApplication::sendPostedEvents(this, QEvent::LayoutHint);
1153     QEvent *e = new QEvent(QEvent::LayoutHint);
1154     QApplication::postEvent(this, e);
1155 }
1156 
1157 /*!
1158     Destroys the dock window and its child widgets.
1159 */
1160 
~Q3DockWindow()1161 Q3DockWindow::~Q3DockWindow()
1162 {
1163     qApp->removeEventFilter(this);
1164     if (area())
1165         area()->removeDockWindow(this, false, false);
1166     Q3DockArea *a = area();
1167     if (!a && dockWindowData)
1168         a = ((Q3DockArea::DockWindowData*)dockWindowData)->area;
1169     Q3MainWindow *mw = a ? qobject_cast<Q3MainWindow*>(a->parentWidget()) : 0;
1170     if (mw)
1171         mw->removeDockWindow(this);
1172 
1173     delete (Q3DockArea::DockWindowData*)dockWindowData;
1174 }
1175 
1176 /*!  \reimp
1177 */
1178 
resizeEvent(QResizeEvent * e)1179 void Q3DockWindow::resizeEvent(QResizeEvent *e)
1180 {
1181     Q3Frame::resizeEvent(e);
1182     updateGui();
1183 }
1184 
1185 
swapRect(QRect & r,Qt::Orientation o,const QPoint & offset,Q3DockArea *)1186 void Q3DockWindow::swapRect(QRect &r, Qt::Orientation o, const QPoint &offset, Q3DockArea *)
1187 {
1188     r.setSize(QSize(r.height(), r.width()));
1189     bool reverse = QApplication::reverseLayout();
1190     if (o == Qt::Horizontal)
1191         r.moveBy(-r.width()/2, 0);
1192     else
1193         r.moveBy(reverse ? - r.width() : 0, -r.height() / 2 );
1194     r.moveBy(offset.x(), offset.y());
1195 }
1196 
areaAt(const QPoint & gp)1197 QWidget *Q3DockWindow::areaAt(const QPoint &gp)
1198 {
1199     QWidget *w = qApp->widgetAt(gp);
1200 
1201     if (w && (w == this || w == titleBar) && parentWidget())
1202         w = parentWidget()->childAt(parentWidget()->mapFromGlobal(gp));
1203 
1204     while (w) {
1205         if (qobject_cast<Q3DockArea*>(w)) {
1206             Q3DockArea *a = (Q3DockArea*)w;
1207             if (a->isDockWindowAccepted(this))
1208                 return w;
1209         }
1210         if (qobject_cast<Q3MainWindow*>(w)) {
1211             Q3MainWindow *mw = (Q3MainWindow*)w;
1212             Q3DockArea *a = mw->dockingArea(mw->mapFromGlobal(gp));
1213             if (a && a->isDockWindowAccepted(this))
1214                 return a;
1215         }
1216         w = w->isWindow() ? 0 : (QWidget *)w->parent();
1217     }
1218     return 0;
1219 }
1220 
handleMove(const QPoint & pos,const QPoint & gp,bool drawRect)1221 void Q3DockWindow::handleMove(const QPoint &pos, const QPoint &gp, bool drawRect)
1222 {
1223     if (!rubberBand)
1224         return;
1225 
1226     currRect = QRect(realWidgetPos(this), size());
1227     QWidget *w = areaAt(gp);
1228     if (titleBar->ctrlDown || horHandle->ctrlDown || verHandle->ctrlDown)
1229         w = 0;
1230     currRect.moveBy(pos.x(), pos.y());
1231     if (!qobject_cast<Q3DockArea*>(w)) {
1232         if (startOrientation != Qt::Horizontal && qobject_cast<Q3ToolBar*>(this))
1233             swapRect(currRect, Qt::Horizontal, startOffset, (Q3DockArea*)w);
1234         if (drawRect) {
1235             rubberBand->setGeometry(currRect);
1236         } else {
1237             QPoint mp(mapToGlobal(pos));
1238             if(place() == InDock) {
1239                 undock();
1240                 if(titleBar) {
1241                     mp = QPoint(titleBar->width() / 2, titleBar->height() / 2);
1242                     QMouseEvent me(QEvent::MouseButtonPress, mp, Qt::LeftButton, 0);
1243                     QApplication::sendEvent(titleBar, &me);
1244                     mp = titleBar->mapToGlobal(mp);
1245                 }
1246             }
1247             move(mp);
1248         }
1249         state = OutsideDock;
1250         return;
1251     }
1252 
1253     Q3DockArea *area = (Q3DockArea*)w;
1254     if(area->isVisible()) {
1255         state = InDock;
1256         Qt::Orientation o = (area ? area->orientation() :
1257                           (boxLayout()->direction() == QBoxLayout::LeftToRight ||
1258                             boxLayout()->direction() == QBoxLayout::RightToLeft ?
1259                             Qt::Horizontal : Qt::Vertical));
1260         if (startOrientation != o)
1261             swapRect(currRect, o, startOffset, area);
1262         if (drawRect) {
1263             rubberBand->setGeometry(currRect);
1264         }
1265         tmpDockArea = area;
1266     }
1267 }
1268 
updateGui()1269 void Q3DockWindow::updateGui()
1270 {
1271     if (curPlace == OutsideDock) {
1272         hbox->setMargin(2);
1273         horHandle->hide();
1274         verHandle->hide();
1275         if (moveEnabled)
1276             titleBar->show();
1277         else
1278             titleBar->hide();
1279         titleBar->updateGui();
1280         hHandleTop->hide();
1281         vHandleLeft->hide();
1282         hHandleBottom->hide();
1283         vHandleRight->hide();
1284         setLineWidth(2);
1285         widgetResizeHandler->setActive(isResizeEnabled());
1286     } else {
1287         hbox->setMargin(0);
1288         titleBar->hide();
1289         if (orientation() == Qt::Horizontal) {
1290             horHandle->hide();
1291             if (moveEnabled)
1292                 verHandle->show();
1293             else
1294                 verHandle->hide();
1295 #ifdef Q_WS_MAC
1296             if(horHandle->mousePressed) {
1297                 horHandle->mousePressed = false;
1298                 verHandle->mousePressed = true;
1299                 verHandle->grabMouse();
1300             }
1301 #endif
1302             verHandle->updateGui();
1303         } else {
1304             if (moveEnabled)
1305                 horHandle->show();
1306             else
1307                 horHandle->hide();
1308             horHandle->updateGui();
1309 #ifdef Q_WS_MAC
1310             if(verHandle->mousePressed) {
1311                 verHandle->mousePressed = false;
1312                 horHandle->mousePressed = true;
1313                 horHandle->grabMouse();
1314             }
1315 #endif
1316             verHandle->hide();
1317         }
1318         if (isResizeEnabled()) {
1319             if (orientation() == Qt::Horizontal) {
1320                 hHandleBottom->raise();
1321                 hHandleTop->raise();
1322             } else {
1323                 vHandleRight->raise();
1324                 vHandleLeft->raise();
1325             }
1326 
1327             if (area()) {
1328                 if (orientation() == Qt::Horizontal) {
1329                     if (area()->handlePosition() == Q3DockArea::Normal) {
1330                         hHandleBottom->show();
1331                         hHandleTop->hide();
1332                     } else {
1333                         hHandleTop->show();
1334                         hHandleBottom->hide();
1335                     }
1336                     if (!area()->isLastDockWindow(this))
1337                         vHandleRight->show();
1338                     else
1339                         vHandleRight->hide();
1340                     vHandleLeft->hide();
1341                 } else {
1342                     if ((area()->handlePosition() == Q3DockArea::Normal) != QApplication::reverseLayout()) {
1343                         vHandleRight->show();
1344                         vHandleLeft->hide();
1345                     } else {
1346                         vHandleLeft->show();
1347                         vHandleRight->hide();
1348                     }
1349                     if (!area()->isLastDockWindow(this))
1350                         hHandleBottom->show();
1351                     else
1352                         hHandleBottom->hide();
1353                     hHandleTop->hide();
1354                 }
1355             }
1356         }
1357 #ifndef Q_OS_WINCE
1358         if (moveEnabled)
1359             setLineWidth(1);
1360         else
1361             setLineWidth(0);
1362 #endif
1363         widgetResizeHandler->setActive(false);
1364     }
1365 }
1366 
updatePosition(const QPoint & globalPos)1367 void Q3DockWindow::updatePosition(const QPoint &globalPos)
1368 {
1369     if (curPlace == OutsideDock && state == InDock)
1370         lastSize = size();
1371 
1372     bool doAdjustSize = curPlace != state && state == OutsideDock;
1373     bool doUpdate = true;
1374     bool doOrientationChange = true;
1375     if (state != curPlace && state == InDock) {
1376         doUpdate = false;
1377         curPlace = state;
1378         updateGui();
1379         QApplication::sendPostedEvents();
1380     }
1381     Qt::Orientation oo = orientation();
1382 
1383     if (state == InDock) {
1384         if (tmpDockArea) {
1385             bool differentDocks = false;
1386             if (dockArea && dockArea != tmpDockArea) {
1387                 differentDocks = true;
1388                 delete (Q3DockArea::DockWindowData*)dockWindowData;
1389                 dockWindowData = dockArea->dockWindowData(this);
1390                 dockArea->removeDockWindow(this, false, false);
1391             }
1392             dockArea = tmpDockArea;
1393             if (differentDocks) {
1394                 if (doUpdate) {
1395                     doUpdate = false;
1396                     curPlace = state;
1397                     updateGui();
1398                 }
1399                 emit orientationChanged(tmpDockArea->orientation());
1400                 doOrientationChange = false;
1401             } else {
1402                 updateGui();
1403             }
1404             dockArea->moveDockWindow(this, globalPos, currRect, startOrientation != oo);
1405         }
1406     } else {
1407         if (dockArea) {
1408             Q3MainWindow *mw = (Q3MainWindow*)dockArea->parentWidget();
1409             if (qobject_cast<Q3MainWindow*>(mw) &&
1410                  (!mw->isDockEnabled(Qt::DockTornOff) ||
1411                    !mw->isDockEnabled(this, Qt::DockTornOff)))
1412                 return;
1413             delete (Q3DockArea::DockWindowData*)dockWindowData;
1414             dockWindowData = dockArea->dockWindowData(this);
1415             dockArea->removeDockWindow(this, true,
1416                 startOrientation != Qt::Horizontal && qobject_cast<Q3ToolBar*>(this));
1417         }
1418         dockArea = 0;
1419         QPoint topLeft = currRect.topLeft();
1420         QRect screen = qApp->desktop()->availableGeometry(topLeft);
1421         if (!screen.contains(topLeft)) {
1422             topLeft.setY(qMax(topLeft.y(), screen.top()));
1423             topLeft.setY(qMin(topLeft.y(), screen.bottom()-height()));
1424             topLeft.setX(qMax(topLeft.x(), screen.left()));
1425             topLeft.setX(qMin(topLeft.x(), screen.right()-width()));
1426         }
1427         move(topLeft);
1428     }
1429 
1430     if (curPlace == InDock && state == OutsideDock && !qobject_cast<Q3ToolBar*>(this)) {
1431         if (lastSize != QSize(-1, -1))
1432             resize(lastSize);
1433     }
1434 
1435     if (doUpdate) {
1436         curPlace = state;
1437         updateGui();
1438     }
1439     if (doOrientationChange)
1440         emit orientationChanged(orientation());
1441     tmpDockArea = 0;
1442     if (doAdjustSize) {
1443         QApplication::sendPostedEvents(this, QEvent::LayoutHint);
1444         if (qobject_cast<Q3ToolBar*>(this))
1445             adjustSize();
1446         if (lastSize == QSize(-1, -1))
1447             setAttribute(Qt::WA_Resized, false); // Ensures size is recalculated (non-opaque).
1448         show();
1449         if (parentWidget() && isWindow())
1450             parentWidget()->setActiveWindow();
1451 
1452     }
1453 
1454     emit placeChanged(curPlace);
1455 }
1456 
1457 /*!
1458     Sets the dock window's main widget to \a w.
1459 
1460     \sa boxLayout()
1461 */
1462 
setWidget(QWidget * w)1463 void Q3DockWindow::setWidget(QWidget *w)
1464 {
1465     wid = w;
1466     boxLayout()->addWidget(w);
1467     updateGui();
1468 }
1469 
1470 /*!
1471     Returns the dock window's main widget.
1472 
1473     \sa setWidget()
1474 */
1475 
widget() const1476 QWidget *Q3DockWindow::widget() const
1477 {
1478     return wid;
1479 }
1480 
startRectDraw(const QPoint & so,bool drawRect)1481 void Q3DockWindow::startRectDraw(const QPoint &so, bool drawRect)
1482 {
1483     state = place();
1484     if (rubberBand)
1485         endRectDraw(!opaque);
1486     rubberBand = new QRubberBand(QRubberBand::Rectangle);
1487     currRect = QRect(realWidgetPos(this), size());
1488     if (drawRect) {
1489         rubberBand->setGeometry(currRect);
1490     }
1491     startOrientation = orientation();
1492     startOffset = mapFromGlobal(so);
1493     rubberBand->show();
1494 }
1495 
endRectDraw(bool)1496 void Q3DockWindow::endRectDraw(bool)
1497 {
1498     delete rubberBand;
1499     rubberBand = 0;
1500 }
1501 
1502 /*!
1503   \reimp
1504 */
drawFrame(QPainter * p)1505 void Q3DockWindow::drawFrame(QPainter *p)
1506 {
1507     if (place() == InDock) {
1508         Q3Frame::drawFrame(p);
1509         return;
1510     }
1511 
1512     QStyleOptionFrame opt;
1513     opt.rect = rect();
1514     opt.palette = palette();
1515     opt.state = QStyle::State_None;
1516     if (titleBar->isActive())
1517         opt.state |= QStyle::State_Active;
1518     opt.lineWidth = lineWidth();
1519     opt.midLineWidth = midLineWidth();
1520 
1521     style()->drawPrimitive(QStyle::PE_FrameWindow, &opt, p, this);
1522 }
1523 
1524 /*!
1525   \reimp
1526 */
drawContents(QPainter * p)1527 void Q3DockWindow::drawContents(QPainter *p)
1528 {
1529     // This is only used by the PocketPC style. We probably need to revist later.
1530     QStyleOption opt(0, QStyleOption::SO_Default);
1531     opt.init(this);
1532     if (titleBar->isActive())
1533         opt.state |= QStyle::State_Active;
1534     style()->drawControl(QStyle::CE_Q3DockWindowEmptyArea, &opt, p, this);
1535 }
1536 
1537 /*!
1538     \property Q3DockWindow::resizeEnabled
1539     \brief whether the dock window is resizeable
1540 
1541     A resizeable dock window can be resized using splitter-like
1542     handles inside a dock area and like every other top level window
1543     when floating.
1544 
1545     A dock window is both horizontally and vertically stretchable if
1546     you call setResizeEnabled(true).
1547 
1548     This property is false by default.
1549 
1550     \sa setVerticallyStretchable() setHorizontallyStretchable()
1551 */
1552 
setResizeEnabled(bool b)1553 void Q3DockWindow::setResizeEnabled(bool b)
1554 {
1555     resizeEnabled = b;
1556     updateGui();
1557 }
1558 
1559 /*!
1560     \property Q3DockWindow::movingEnabled
1561     \brief whether the user can move the dock window within the dock
1562     area, move the dock window to another dock area, or float the dock
1563     window.
1564 
1565     This property is true by default.
1566 */
1567 
setMovingEnabled(bool b)1568 void Q3DockWindow::setMovingEnabled(bool b)
1569 {
1570     moveEnabled = b;
1571     updateGui();
1572 }
1573 
isResizeEnabled() const1574 bool Q3DockWindow::isResizeEnabled() const
1575 {
1576     return resizeEnabled;
1577 }
1578 
isMovingEnabled() const1579 bool Q3DockWindow::isMovingEnabled() const
1580 {
1581     return moveEnabled;
1582 }
1583 
1584 /*!
1585     \property Q3DockWindow::closeMode
1586     \brief the close mode of a dock window
1587 
1588     Defines when (if ever) the dock window has a close button. The
1589     choices are \c Never, \c Docked (i.e. only when docked), \c
1590     Undocked (only when undocked, i.e. floated) or \c Always.
1591 
1592     The default is \c Never.
1593 */
1594 
setCloseMode(int m)1595 void Q3DockWindow::setCloseMode(int m)
1596 {
1597     cMode = m;
1598     if (place() == InDock) {
1599         horHandle->updateGui();
1600         verHandle->updateGui();
1601     } else {
1602         titleBar->updateGui();
1603     }
1604 }
1605 
1606 /*!
1607     Returns true if the dock window has a close button; otherwise
1608     returns false. The result depends on the dock window's \l Place
1609     and its \l CloseMode.
1610 
1611     \sa setCloseMode()
1612 */
1613 
isCloseEnabled() const1614 bool Q3DockWindow::isCloseEnabled() const
1615 {
1616     return  (((cMode & Docked) == Docked && place() == InDock) ||
1617               ((cMode & Undocked) == Undocked && place() == OutsideDock));
1618 }
1619 
closeMode() const1620 int Q3DockWindow::closeMode() const
1621 {
1622     return cMode;
1623 }
1624 
1625 /*!
1626     \property Q3DockWindow::horizontallyStretchable
1627     \brief whether the dock window is horizontally stretchable.
1628 
1629     A dock window is horizontally stretchable if you call
1630     setHorizontallyStretchable(true) or setResizeEnabled(true).
1631 
1632     \warning Stretchability is broken. You must call
1633     setResizeEnabled(true) to get proper behavior and even then
1634     Q3DockWindow does not limit stretchablilty.
1635 
1636     \sa setResizeEnabled()
1637 */
1638 
setHorizontallyStretchable(bool b)1639 void Q3DockWindow::setHorizontallyStretchable(bool b)
1640 {
1641     stretchable[Qt::Horizontal] = b;
1642 }
1643 
1644 /*!
1645     \property Q3DockWindow::verticallyStretchable
1646     \brief whether the dock window is vertically stretchable.
1647 
1648     A dock window is vertically stretchable if you call
1649     setVerticallyStretchable(true) or setResizeEnabled(true).
1650 
1651     \sa setResizeEnabled()
1652 
1653     \warning Stretchability is broken. You must call
1654     setResizeEnabled(true) to get proper behavior and even then
1655     Q3DockWindow does not limit stretchablilty.
1656 */
1657 
setVerticallyStretchable(bool b)1658 void Q3DockWindow::setVerticallyStretchable(bool b)
1659 {
1660     stretchable[Qt::Vertical] = b;
1661 }
1662 
isHorizontallyStretchable() const1663 bool Q3DockWindow::isHorizontallyStretchable() const
1664 {
1665     return isResizeEnabled() || stretchable[Qt::Horizontal];
1666 }
1667 
isVerticallyStretchable() const1668 bool Q3DockWindow::isVerticallyStretchable() const
1669 {
1670     return isResizeEnabled() || stretchable[Qt::Vertical];
1671 }
1672 
1673 /*!
1674     \property Q3DockWindow::stretchable
1675     \brief whether the dock window is stretchable in the current
1676     orientation()
1677 
1678     This property can be set using setHorizontallyStretchable() and
1679     setVerticallyStretchable(), or with setResizeEnabled().
1680 
1681     \warning Stretchability is broken. You must call
1682     setResizeEnabled(true) to get proper behavior and even then
1683     Q3DockWindow does not limit stretchablilty.
1684 
1685     \sa setResizeEnabled()
1686 */
1687 
isStretchable() const1688 bool Q3DockWindow::isStretchable() const
1689 {
1690     if (orientation() == Qt::Horizontal)
1691         return isHorizontallyStretchable();
1692     return isVerticallyStretchable();
1693 }
1694 
1695 /*!
1696     Returns the orientation of the dock window.
1697 
1698     \sa orientationChanged()
1699 */
1700 
orientation() const1701 Qt::Orientation Q3DockWindow::orientation() const
1702 {
1703     if (dockArea)
1704         return dockArea->orientation();
1705     if (qobject_cast<const Q3ToolBar*>(this))
1706         return Qt::Horizontal;
1707     return (((Q3DockWindow*)this)->boxLayout()->direction() == QBoxLayout::LeftToRight ||
1708              ((Q3DockWindow*)this)->boxLayout()->direction() == QBoxLayout::RightToLeft ?
1709              Qt::Horizontal : Qt::Vertical);
1710 }
1711 
offset() const1712 int Q3DockWindow::offset() const
1713 {
1714     return offs;
1715 }
1716 
1717 /*!
1718     \property Q3DockWindow::offset
1719     \brief the dock window's preferred offset from the dock area's
1720     left edge (top edge for vertical dock areas)
1721 
1722     The default is 0.
1723 */
1724 
setOffset(int o)1725 void Q3DockWindow::setOffset(int o)
1726 {
1727     offs = o;
1728 }
1729 
1730 /*!
1731     Returns the dock window's preferred size (fixed extent).
1732 
1733     \sa setFixedExtentWidth() setFixedExtentHeight()
1734 */
1735 
fixedExtent() const1736 QSize Q3DockWindow::fixedExtent() const
1737 {
1738     return fExtent;
1739 }
1740 
1741 /*!
1742     Sets the dock window's preferred width for its fixed extent (size)
1743     to \a w.
1744 
1745     \sa setFixedExtentHeight()
1746 */
1747 
setFixedExtentWidth(int w)1748 void Q3DockWindow::setFixedExtentWidth(int w)
1749 {
1750     fExtent.setWidth(w);
1751 }
1752 
1753 /*!
1754     Sets the dock window's preferred height for its fixed extent
1755     (size) to \a h.
1756 
1757     \sa setFixedExtentWidth()
1758 */
1759 
setFixedExtentHeight(int h)1760 void Q3DockWindow::setFixedExtentHeight(int h)
1761 {
1762     fExtent.setHeight(h);
1763 }
1764 
1765 /*!
1766     \property Q3DockWindow::newLine
1767     \brief whether the dock window prefers to start a new line in the
1768     dock area.
1769 
1770     The default is false, i.e. the dock window doesn't require a new
1771     line in the dock area.
1772 */
1773 
setNewLine(bool b)1774 void Q3DockWindow::setNewLine(bool b)
1775 {
1776     nl = b;
1777 }
1778 
newLine() const1779 bool Q3DockWindow::newLine() const
1780 {
1781     return nl;
1782 }
1783 
1784 /*!
1785     Returns the layout which is used for adding widgets to the dock
1786     window. The layout's orientation is set automatically to match the
1787     orientation of the dock window. You can add widgets to the layout
1788     using the box layout's QBoxLayout::addWidget() function.
1789 
1790     If the dock window only needs to contain a single widget use
1791     setWidget() instead.
1792 
1793     \sa setWidget() setOrientation()
1794 */
1795 
boxLayout()1796 QBoxLayout *Q3DockWindow::boxLayout()
1797 {
1798     return childBox;
1799 }
1800 
1801 /*! \reimp
1802  */
1803 
sizeHint() const1804 QSize Q3DockWindow::sizeHint() const
1805 {
1806     QSize sh(Q3Frame::sizeHint());
1807     if (place() == InDock)
1808         sh = sh.expandedTo(fixedExtent());
1809     sh = sh.expandedTo(QSize(16, 16));
1810     if (area()) {
1811         if (area()->orientation() == Qt::Horizontal && !vHandleRight->isVisible())
1812             sh.setWidth(sh.width() + 2 * style()->pixelMetric(QStyle::PM_SplitterWidth, 0, this) / 3);
1813         else if (area()->orientation() == Qt::Vertical && !hHandleBottom->isVisible())
1814             sh.setHeight(sh.height() + 2 * style()->pixelMetric(QStyle::PM_SplitterWidth, 0, this) / 3);
1815     }
1816     return sh;
1817 }
1818 
1819 /*! \internal
1820  */
1821 
minimumSize() const1822 QSize Q3DockWindow::minimumSize() const
1823 {
1824     QSize ms(Q3Frame::minimumSize());
1825     if (place() == InDock)
1826         ms = ms.expandedTo(fixedExtent());
1827     ms = ms.expandedTo(QSize(16, 16));
1828     if (area()) {
1829         if (area()->orientation() == Qt::Horizontal && !vHandleRight->isVisible())
1830             ms.setWidth(ms.width() + 2 * style()->pixelMetric(QStyle::PM_SplitterWidth, 0, this) / 3);
1831         else if (area()->orientation() == Qt::Vertical && !hHandleBottom->isVisible())
1832             ms.setHeight(ms.height() + 2 * style()->pixelMetric(QStyle::PM_SplitterWidth, 0, this) / 3);
1833     }
1834     return ms;
1835 }
1836 
1837 /*! \reimp
1838  */
1839 
minimumSizeHint() const1840 QSize Q3DockWindow::minimumSizeHint() const
1841 {
1842     QSize msh(Q3Frame::minimumSize());
1843     if (place() == InDock)
1844         msh = msh.expandedTo(fixedExtent());
1845     msh = msh.expandedTo(QSize(16, 16));
1846     if (area()) {
1847         if (area()->orientation() == Qt::Horizontal && !vHandleRight->isVisible())
1848             msh.setWidth(msh.width() + 2 * style()->pixelMetric(QStyle::PM_SplitterWidth, 0, this) / 3);
1849         else if (area()->orientation() == Qt::Vertical && !hHandleBottom->isVisible())
1850             msh.setHeight(msh.height() + 2 * style()->pixelMetric(QStyle::PM_SplitterWidth, 0, this) / 3);
1851     }
1852     return msh;
1853 }
1854 
1855 /*!
1856     \fn void Q3DockWindow::undock()
1857 
1858     Undocks the Q3DockWindow from its current dock area if it is
1859     docked; otherwise does nothing.
1860 
1861     \sa dock() Q3DockArea::moveDockWindow(),
1862     Q3DockArea::removeDockWindow(), Q3MainWindow::moveDockWindow(),
1863     Q3MainWindow::removeDockWindow()
1864 */
1865 
1866 /*!
1867     \fn void Q3DockWindow::undock(QWidget *widget)
1868 
1869     Undocks the specified \a widget from its current dock area if it is
1870     docked; otherwise does nothing.
1871 
1872     \sa dock() Q3DockArea::moveDockWindow(),
1873     Q3DockArea::removeDockWindow(), Q3MainWindow::moveDockWindow(),
1874     Q3MainWindow::removeDockWindow()
1875 */
undock(QWidget * w)1876 void Q3DockWindow::undock(QWidget *w)
1877 {
1878     Q3MainWindow *mw = 0;
1879     if (area())
1880         mw = qobject_cast<Q3MainWindow*>(area()->parentWidget());
1881     if (mw && !mw->isDockEnabled(this, Qt::DockTornOff))
1882         return;
1883     if ((place() == OutsideDock && !w))
1884         return;
1885 
1886     QPoint p(50, 50);
1887     if (window())
1888         p = window()->pos() + QPoint(20, 20);
1889     if (dockArea) {
1890         delete (Q3DockArea::DockWindowData*)dockWindowData;
1891         dockWindowData = dockArea->dockWindowData(this);
1892         dockArea->removeDockWindow(this, true, orientation() != Qt::Horizontal && qobject_cast<Q3ToolBar*>(this));
1893     }
1894     dockArea = 0;
1895     if (lastPos != QPoint(-1, -1) && lastPos.x() > 0 && lastPos.y() > 0)
1896         move(lastPos);
1897     else
1898         move(p);
1899     if (lastSize != QSize(-1, -1))
1900         resize(lastSize);
1901     curPlace = OutsideDock;
1902     updateGui();
1903     emit orientationChanged(orientation());
1904     QApplication::sendPostedEvents(this, QEvent::LayoutHint);
1905     if (qobject_cast<Q3ToolBar*>(this))
1906         adjustSize();
1907     if (!w) {
1908         if (!parentWidget() || parentWidget()->isVisible()) {
1909             if (lastSize == QSize(-1, -1))
1910                 setAttribute(Qt::WA_Resized, false);// Ensures size is recalculated (opaque).
1911             show();
1912         }
1913     } else {
1914         setParent(w, 0);
1915         move(-width() - 5, -height() - 5);
1916         resize(1, 1);
1917         show();
1918     }
1919     if (parentWidget() && isWindow())
1920         parentWidget()->setActiveWindow();
1921     emit placeChanged(place());
1922 }
1923 
removeFromDock(bool fixNewLines)1924 void Q3DockWindow::removeFromDock(bool fixNewLines)
1925 {
1926     if (dockArea)
1927         dockArea->removeDockWindow(this, false, false, fixNewLines);
1928 }
1929 
1930 /*!
1931     Docks the dock window into the last dock area in which it was
1932     docked.
1933 
1934     If the dock window has no last dock area (e.g. it was created as a
1935     floating window and has never been docked), or if the last dock
1936     area it was docked in does not exist (e.g. the dock area has been
1937     deleted), nothing happens.
1938 
1939     The dock window will dock with the dock area regardless of the return value
1940     of Q3DockArea::isDockWindowAccepted().
1941 
1942     \sa undock() Q3DockArea::moveDockWindow(),
1943     Q3DockArea::removeDockWindow(), Q3MainWindow::moveDockWindow(),
1944     Q3MainWindow::removeDockWindow(), Q3DockArea::isDockWindowAccepted()
1945 
1946 */
1947 
dock()1948 void Q3DockWindow::dock()
1949 {
1950     if (!(Q3DockArea::DockWindowData*)dockWindowData ||
1951          !((Q3DockArea::DockWindowData*)dockWindowData)->area)
1952         return;
1953     curPlace = InDock;
1954     lastPos = pos();
1955     lastSize = size();
1956     ((Q3DockArea::DockWindowData*)dockWindowData)->
1957         area->dockWindow(this, (Q3DockArea::DockWindowData*)dockWindowData);
1958     emit orientationChanged(orientation());
1959     emit placeChanged(place());
1960 }
1961 
1962 /*! \reimp
1963  */
1964 
hideEvent(QHideEvent * e)1965 void Q3DockWindow::hideEvent(QHideEvent *e)
1966 {
1967     Q3Frame::hideEvent(e);
1968 }
1969 
1970 /*! \reimp
1971  */
1972 
showEvent(QShowEvent * e)1973 void Q3DockWindow::showEvent(QShowEvent *e)
1974 {
1975     if (curPlace == OutsideDock && (parent() && parent()->objectName() == QLatin1String("qt_hide_dock"))) {
1976         QRect sr = qApp->desktop()->availableGeometry(this);
1977         if (!sr.contains(pos())) {
1978             int nx = qMin(qMax(x(), sr.x()), sr.right()-width());
1979             int ny = qMin(qMax(y(), sr.y()), sr.bottom()-height());
1980             move(nx, ny);
1981         }
1982     }
1983 
1984     Q3Frame::showEvent(e);
1985 }
1986 
1987 /*!
1988     \property Q3DockWindow::opaqueMoving
1989     \brief whether the dock window will be shown normally whilst it is
1990     being moved.
1991 
1992     If this property is false, (the default), the dock window will be
1993     represented by an outline rectangle whilst it is being moved.
1994 
1995     \warning Currently opaque moving has some problems and we do not
1996     recommend using it at this time. We expect to fix these problems
1997     in a future release.
1998 */
1999 
setOpaqueMoving(bool b)2000 void Q3DockWindow::setOpaqueMoving(bool b)
2001 {
2002     opaque = b;
2003     horHandle->setOpaqueMoving(b);
2004     verHandle->setOpaqueMoving(b);
2005     titleBar->setOpaqueMoving(b);
2006 }
2007 
opaqueMoving() const2008 bool Q3DockWindow::opaqueMoving() const
2009 {
2010     return opaque;
2011 }
2012 
updateSplitterVisibility(bool visible)2013 void Q3DockWindow::updateSplitterVisibility(bool visible)
2014 {
2015     if (area() && isResizeEnabled()) {
2016         if (orientation() == Qt::Horizontal) {
2017             if (visible)
2018                 vHandleRight->show();
2019             else
2020                 vHandleRight->hide();
2021             vHandleLeft->hide();
2022         } else {
2023             if (visible)
2024                 hHandleBottom->show();
2025             else
2026                 hHandleBottom->hide();
2027             hHandleTop->hide();
2028         }
2029     }
2030 }
2031 
2032 /*! \reimp */
eventFilter(QObject * o,QEvent * e)2033 bool Q3DockWindow::eventFilter(QObject * o, QEvent *e)
2034 {
2035     if (!o->isWidgetType())
2036         return false;
2037 
2038     if (e->type() == QEvent::KeyPress &&
2039         (horHandle->mousePressed ||
2040           verHandle->mousePressed ||
2041           titleBar->mousePressed)) {
2042         QKeyEvent *ke = (QKeyEvent*)e;
2043         if (ke->key() == Qt::Key_Escape) {
2044             horHandle->mousePressed =
2045                 verHandle->mousePressed =
2046                     titleBar->mousePressed = false;
2047             endRectDraw(!opaque);
2048             qApp->removeEventFilter(this);
2049             return true;
2050         }
2051     } else if (((QWidget*)o)->window() != this && place() == OutsideDock && isWindow()) {
2052         if ((e->type() == QEvent::WindowDeactivate ||
2053             e->type() == QEvent::WindowActivate))
2054             event(e);
2055     }
2056     return false;
2057 }
2058 
2059 /*! \reimp */
event(QEvent * e)2060 bool Q3DockWindow::event(QEvent *e)
2061 {
2062     switch (e->type()) {
2063     case QEvent::WindowDeactivate:
2064         if (place() == OutsideDock && isWindow() && parentWidget()
2065              && parentWidget()->isActiveWindow())
2066             return true;
2067         break;
2068     case QEvent::HideToParent:
2069         emit visibilityChanged(false);
2070         break;
2071     case QEvent::ShowToParent:
2072         emit visibilityChanged(true);
2073         break;
2074     case QEvent::WindowTitleChange:
2075     {
2076         QString s = Q3Frame::windowTitle();
2077         titleBar->setWindowTitle(s);
2078 #ifndef QT_NO_TOOLTIP
2079         horHandle->setToolTip(s);
2080         verHandle->setToolTip(s);
2081 #endif
2082         break;
2083     }
2084     default:
2085         break;
2086     }
2087     return Q3Frame::event(e);
2088 }
2089 
2090 /*!
2091     Returns the dock window's title.
2092 */
windowTitle() const2093 QString Q3DockWindow::windowTitle() const
2094 {
2095     return titleBar->windowTitle();
2096 }
2097 
2098 /*! \reimp */
contextMenuEvent(QContextMenuEvent * e)2099 void Q3DockWindow::contextMenuEvent(QContextMenuEvent *e)
2100 {
2101     QObject *o = this;
2102     while (o) {
2103         if (qobject_cast<Q3MainWindow*>(o))
2104             break;
2105         o = o->parent();
2106     }
2107     if (!o || ! ((Q3MainWindow*)o)->showDockMenu(e->globalPos()))
2108         e->ignore();
2109 }
2110 
2111 QT_END_NAMESPACE
2112 
2113 #include "q3dockwindow.moc"
2114 
2115 #endif //QT_NO_MAINWINDOW
2116