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 "q3mainwindow.h"
43 #ifndef QT_NO_MAINWINDOW
44 
45 #include "qapplication.h"
46 #include "qbitmap.h"
47 #include "qcursor.h"
48 #include "qdatetime.h"
49 #include "q3dockarea.h"
50 #include "qevent.h"
51 #include "qlayout.h"
52 #include "qmap.h"
53 #include "qmenubar.h"
54 #include "qpainter.h"
55 #include "q3popupmenu.h"
56 #include "q3scrollview.h"
57 #include "qstatusbar.h"
58 #include "qstringlist.h"
59 #include "qstyle.h"
60 #include "qstyleoption.h"
61 #include "qtimer.h"
62 #include "q3toolbar.h"
63 #include "qtooltip.h"
64 #include "qwhatsthis.h"
65 #ifdef Q_WS_MAC
66 #  include <private/qt_mac_p.h>
67 #endif
68 
69 #include <private/q3mainwindow_p.h>
70 
71 QT_BEGIN_NAMESPACE
72 
73 class QHideDock;
74 
75 /* Q3MainWindowLayout, respects widthForHeight layouts (like the left
76   and right docks are)
77 */
78 
79 class Q3MainWindowLayout : public QLayout
80 {
81     Q_OBJECT
82 
83 public:
84     Q3MainWindowLayout(Q3MainWindow *mw);
~Q3MainWindowLayout()85     ~Q3MainWindowLayout() {}
86 
87     void addItem(QLayoutItem *);
88     void setLeftDock(Q3DockArea *l);
89     void setRightDock(Q3DockArea *r);
90     void setCentralWidget(QWidget *w);
hasHeightForWidth() const91     bool hasHeightForWidth() const { return false; }
92     QSize sizeHint() const;
93     QSize minimumSize() const;
itemAt(int) const94     QLayoutItem *itemAt(int) const { return 0; } //###
takeAt(int)95     QLayoutItem *takeAt(int) { return 0; } //###
count() const96     int count() const { return 0; } //###
97 
98 protected:
setGeometry(const QRect & r)99     void setGeometry(const QRect &r) {
100         QLayout::setGeometry(r);
101         layoutItems(r);
102     }
103 
104 private:
105     int layoutItems(const QRect&, bool testonly = false);
106     int extraPixels() const;
107 
108     Q3DockArea *left, *right;
109     QWidget *central;
110     Q3MainWindow *mainWindow;
111 
112 };
113 
sizeHint() const114 QSize Q3MainWindowLayout::sizeHint() const
115 {
116     int w = 0;
117     int h = 0;
118 
119     if (left) {
120         w += left->sizeHint().width();
121         h = qMax(h, left->sizeHint().height());
122     }
123     if (right) {
124         w += right->sizeHint().width();
125         h = qMax(h, right->sizeHint().height());
126     }
127     if (central) {
128         w += central->sizeHint().width();
129         int diff = extraPixels();
130         h = qMax(h, central->sizeHint().height() + diff);
131     }
132     return QSize(w, h);
133 }
134 
minimumSize() const135 QSize Q3MainWindowLayout::minimumSize() const
136 {
137     int w = 0;
138     int h = 0;
139 
140     if (left) {
141         QSize ms = left->minimumSizeHint().expandedTo(left->minimumSize());
142         w += ms.width();
143         h = qMax(h, ms.height());
144     }
145     if (right) {
146         QSize ms = right->minimumSizeHint().expandedTo(right->minimumSize());
147         w += ms.width();
148         h = qMax(h, ms.height());
149     }
150     if (central) {
151         QSize min = central->minimumSize().isNull() ?
152                     central->minimumSizeHint() : central->minimumSize();
153         w += min.width();
154         int diff = extraPixels();
155         h = qMax(h, min.height() + diff);
156     }
157     return QSize(w, h);
158 }
159 
Q3MainWindowLayout(Q3MainWindow * mw)160 Q3MainWindowLayout::Q3MainWindowLayout(Q3MainWindow *mw)
161     : left(0), right(0), central(0)
162 {
163     mainWindow = mw;
164 }
165 
setLeftDock(Q3DockArea * l)166 void Q3MainWindowLayout::setLeftDock(Q3DockArea *l)
167 {
168     left = l;
169 }
170 
setRightDock(Q3DockArea * r)171 void Q3MainWindowLayout::setRightDock(Q3DockArea *r)
172 {
173     right = r;
174 }
175 
setCentralWidget(QWidget * w)176 void Q3MainWindowLayout::setCentralWidget(QWidget *w)
177 {
178     central = w;
179 }
180 
layoutItems(const QRect & r,bool testonly)181 int Q3MainWindowLayout::layoutItems(const QRect &r, bool testonly)
182 {
183     if (!left && !central && !right)
184         return 0;
185 
186     int wl = 0, wr = 0;
187     if (left)
188         wl = ((Q3DockAreaLayout*)left->QWidget::layout())->widthForHeight(r.height());
189     if (right)
190         wr = ((Q3DockAreaLayout*)right->QWidget::layout())->widthForHeight(r.height());
191     int w = r.width() - wr - wl;
192     if (w < 0)
193         w = 0;
194 
195     int diff = extraPixels();
196     if (!testonly) {
197         QRect g(geometry());
198         if (left)
199             left->setGeometry(QRect(g.x(), g.y() + diff, wl, r.height() - diff));
200         if (right)
201             right->setGeometry(QRect(g.x() + g.width() - wr, g.y() + diff, wr, r.height() - diff));
202         if (central)
203             central->setGeometry(g.x() + wl, g.y() + diff, w, r.height() - diff);
204     }
205 
206     w = wl + wr;
207     if (central)
208         w += central->minimumSize().width();
209     return w;
210 }
211 
extraPixels() const212 int Q3MainWindowLayout::extraPixels() const
213 {
214     if (mainWindow->d_func()->topDock->isEmpty() &&
215          !(mainWindow->d_func()->leftDock->isEmpty() &&
216            mainWindow->d_func()->rightDock->isEmpty())) {
217         return 2;
218     } else {
219         return 0;
220     }
221 }
222 
addItem(QLayoutItem *)223 void Q3MainWindowLayout::addItem(QLayoutItem * /* item */)
224 {
225 }
226 
227 /*
228   QHideToolTip and QHideDock - minimized dock
229 */
230 
231 #if 0
232 class QHideToolTip : public QToolTip
233 {
234 public:
235     QHideToolTip(QWidget *parent) : QToolTip(parent) {}
236 
237     void maybeTip(const QPoint &pos);
238 };
239 #endif
240 
241 
242 class QHideDock : public QWidget
243 {
244     Q_OBJECT
245 
246 public:
QHideDock(Q3MainWindow * parent)247     QHideDock(Q3MainWindow *parent) : QWidget(parent, "qt_hide_dock") {
248         hide();
249         setFixedHeight(style()->pixelMetric(QStyle::PM_DockWidgetHandleExtent, 0, this) + 3);
250         pressedHandle = -1;
251         pressed = false;
252         setMouseTracking(true);
253         win = parent;
254 #if 0
255         tip = new QHideToolTip(this);
256 #endif
257     }
~QHideDock()258     ~QHideDock()
259     {
260 #if 0
261         delete tip;
262 #endif
263     }
264 
265 protected:
paintEvent(QPaintEvent * e)266     void paintEvent(QPaintEvent *e) {
267         QObjectList childList = children();
268         if (childList.isEmpty())
269             return;
270         QPainter p(this);
271         p.setClipRegion(e->rect());
272         p.fillRect(e->rect(), palette().brush(QPalette::Window));
273         int x = 0;
274         for (int i = 0; i < childList.size(); ++i) {
275             QObject *o = childList.at(i);
276             Q3DockWindow *dw = qobject_cast<Q3DockWindow*>(o);
277             if (!dw || !dw->isVisible())
278                 continue;
279             QStyleOptionQ3DockWindow opt;
280             opt.rect.setRect(x, 0, 30, 10);
281             opt.palette = palette();
282             opt.docked = dw->area();
283             opt.closeEnabled = dw->isCloseEnabled();
284             opt.state = QStyle::State_None;
285             if (i == pressedHandle)
286                 opt.state |= QStyle::State_On;
287 
288             style()->drawPrimitive(QStyle::PE_IndicatorToolBarHandle, &opt, &p, this);
289             x += 30;
290         }
291     }
292 
mousePressEvent(QMouseEvent * e)293     void mousePressEvent(QMouseEvent *e) {
294         pressed = true;
295         QObjectList childList = children();
296         if (childList.isEmpty())
297             return;
298         mouseMoveEvent(e);
299         pressedHandle = -1;
300 
301         if (e->button() == Qt::RightButton && win->isDockMenuEnabled()) {
302             // ### TODO: HideDock menu
303         } else {
304             mouseMoveEvent(e);
305         }
306     }
307 
mouseMoveEvent(QMouseEvent * e)308     void mouseMoveEvent(QMouseEvent *e) {
309         QObjectList childList = children();
310         if (childList.isEmpty())
311             return;
312         if (!pressed)
313             return;
314         int x = 0;
315         if (e->y() >= 0 && e->y() <= height()) {
316             for (int i = 0; i < childList.size(); ++i) {
317                 QObject *o = childList.at(i);
318                 Q3DockWindow *dw = qobject_cast<Q3DockWindow*>(o);
319                 if (!dw || !dw->isVisible())
320                     continue;
321                 if (e->x() >= x && e->x() <= x + 30) {
322                     int old = pressedHandle;
323                     pressedHandle = i;
324                     if (pressedHandle != old)
325                         repaint();
326                     return;
327                 }
328                 x += 30;
329             }
330         }
331         int old = pressedHandle;
332         pressedHandle = -1;
333         if (old != -1)
334             repaint();
335     }
336 
mouseReleaseEvent(QMouseEvent * e)337     void mouseReleaseEvent(QMouseEvent *e) {
338         pressed = false;
339         if (pressedHandle == -1)
340             return;
341         QObjectList childList = children();
342         if (childList.isEmpty())
343             return;
344         if (e->button() == Qt::LeftButton) {
345             if (e->y() >= 0 && e->y() <= height()) {
346                 QObject *o = childList.at(pressedHandle);
347                 Q3DockWindow *dw = qobject_cast<Q3DockWindow*>(o);
348                 if (dw) {
349                     dw->show();
350                     dw->dock();
351                 }
352             }
353         }
354         pressedHandle = -1;
355         repaint();
356     }
357 
eventFilter(QObject * o,QEvent * e)358     bool eventFilter(QObject *o, QEvent *e) {
359         if (o == this || !o->isWidgetType())
360             return QWidget::eventFilter(o, e);
361         if (e->type() == QEvent::HideToParent ||
362              e->type() == QEvent::ShowToParent)
363             updateState();
364         return QWidget::eventFilter(o, e);
365     }
366 
updateState()367     void updateState() {
368         bool visible = true;
369         QObjectList childList = children();
370         if (childList.isEmpty())
371             return;
372         for (int i = 0; i < childList.size(); ++i) {
373             QObject *o = childList.at(i);
374             Q3DockWindow *dw = qobject_cast<Q3DockWindow*>(o);
375             if (!dw)
376                 continue;
377             if (dw->isHidden()) {
378                 visible = false;
379                 continue;
380             }
381             if (!dw->isVisible())
382                 continue;
383             visible = true;
384             break;
385         }
386 
387         if (visible)
388             show();
389         else
390             hide();
391         win->triggerLayout(false);
392         update();
393     }
394 
childEvent(QChildEvent * e)395     void childEvent(QChildEvent *e) {
396         QWidget::childEvent(e);
397         if (e->type() == QEvent::ChildInserted)
398             e->child()->installEventFilter(this);
399         else
400             e->child()->removeEventFilter(this);
401         updateState();
402     }
403 
404 private:
405     Q3MainWindow *win;
406     int pressedHandle;
407     bool pressed;
408 #if 0
409     QHideToolTip *tip;
410     friend class QHideToolTip;
411 #endif
412 };
413 
414 #if 0
415 void QHideToolTip::maybeTip(const QPoint &pos)
416 {
417     if (!parentWidget())
418         return;
419     QHideDock *dock = (QHideDock*)parentWidget();
420 
421     QObjectList dchilds = dock->children();
422     if (dchilds.isEmpty())
423         return;
424     int x = 0;
425     for (int i = 0; i < dchilds.size(); ++i) {
426         QObject *o = dchilds.at(i);
427         Q3DockWindow *dw = qobject_cast<Q3DockWindow*>(o);
428         if (!dw || !dw->isVisible())
429             continue;
430         if (pos.x() >= x && pos.x() <= x + 30) {
431             Q3DockWindow *dw = (Q3DockWindow*)o;
432             if (!dw->windowTitle().isEmpty())
433                 tip(QRect(x, 0, 30, dock->height()), dw->windowTitle());
434             return;
435         }
436         x += 30;
437     }
438 }
439 #endif
440 
441 /*!
442     \class Q3MainWindow
443     \brief The Q3MainWindow class provides a main application window,
444     with a menu bar, dock windows (e.g. for toolbars), and a status
445     bar.
446 
447     \compat
448 
449     Main windows are most often used to provide menus, toolbars and a
450     status bar around a large central widget, such as a text edit,
451     drawing canvas or QWorkspace (for MDI applications). Q3MainWindow
452     is usually subclassed since this makes it easier to encapsulate
453     the central widget, menus and toolbars as well as the window's
454     state. Subclassing makes it possible to create the slots that are
455     called when the user clicks menu items or toolbar buttons.
456 
457     We'll briefly review adding menu items and
458     toolbar buttons then describe the facilities of Q3MainWindow
459     itself.
460 
461     \snippet doc/src/snippets/code/src_qt3support_widgets_q3mainwindow.cpp 0
462 
463     Q3MainWindows may be created in their own right as shown above.
464     The central widget is set with setCentralWidget(). Popup menus can
465     be added to the default menu bar, widgets can be added to the
466     status bar, toolbars and dock windows can be added to any of the
467     dock areas.
468 
469     The main window will take care of the dock areas, and the geometry
470     of the central widget, but all other aspects of the central widget
471     are left to you. Q3MainWindow automatically detects the creation of
472     a menu bar or status bar if you specify the Q3MainWindow as parent,
473     or you can use the provided menuBar() and statusBar() functions.
474     The functions menuBar() and statusBar() create a suitable widget
475     if one doesn't exist, and update the window's layout to make
476     space.
477 
478     New dock windows and toolbars can be added to a Q3MainWindow using
479     addDockWindow(). Qt::Dock windows can be moved using moveDockWindow()
480     and removed with removeDockWindow(). Q3MainWindow allows default
481     dock window (toolbar) docking in all its dock areas (\c Top, \c
482     Left, \c Right, \c Bottom). You can use setDockEnabled() to
483     enable and disable docking areas for dock windows. When adding or
484     moving dock windows you can specify their 'edge' (dock area). The
485     currently available edges are: \c Top, \c Left, \c Right, \c
486     Bottom, \c Minimized (effectively a 'hidden' dock area) and \c
487     TornOff (floating). See \l Qt::Dock for an explanation of these
488     areas. Note that the *ToolBar functions are included for backward
489     compatibility; all new code should use the *DockWindow functions.
490     QToolbar is a subclass of Q3DockWindow so all functions that work
491     with dock windows work on toolbars in the same way.
492 
493     \target dwm
494     If the user clicks the close button, then the dock window is
495     hidden. A dock window can be hidden or unhidden by the user by
496     right clicking a dock area and clicking the name of the relevant
497     dock window on the pop up dock window menu. This menu lists the
498     names of every dock window; visible dock windows have a tick
499     beside their names. The dock window menu is created automatically
500     as required by createDockWindowMenu(). Since it may not always be
501     appropriate for a dock window to appear on this menu the
502     setAppropriate() function is used to inform the main window
503     whether or not the dock window menu should include a particular
504     dock window. Double clicking a dock window handle (usually on the
505     left-hand side of the dock window) undocks (floats) the dock
506     window. Double clicking a floating dock window's title bar will
507     dock the floating dock window. (See also
508     \l{Q3MainWindow::DockWindows}.)
509 
510     Some functions change the appearance of a Q3MainWindow globally:
511     \list
512     \i Q3DockWindow::setHorizontalStretchable() and
513     Q3DockWindow::setVerticalStretchable() are used to make specific dock
514     windows or toolbars stretchable.
515     \i setUsesBigPixmaps() is used to set whether tool buttons should
516     draw small or large pixmaps (see QIcon for more information).
517     \i setUsesTextLabel() is used to set whether tool buttons
518     should display a textual label in addition to pixmaps
519     (see QToolButton for more information).
520     \endlist
521 
522     The user can drag dock windows into any enabled docking area. Qt::Dock
523     windows can also be dragged \e within a docking area, for example
524     to rearrange the order of some toolbars. Qt::Dock windows can also be
525     dragged outside any docking area (undocked or 'floated'). Being
526     able to drag dock windows can be enabled (the default) and
527     disabled using setDockWindowsMovable().
528 
529     The \c Minimized edge is a hidden dock area. If this dock area is
530     enabled the user can hide (minimize) a dock window or show (restore)
531     a minimized dock window by clicking the dock window handle. If the
532     user hovers the mouse cursor over one of the handles, the caption of
533     the dock window is displayed in a tool tip (see
534     Q3DockWindow::windowTitle() or Q3ToolBar::label()), so if you enable the
535     \c Minimized dock area, it is best to specify a meaningful caption
536     or label for each dock window. To minimize a dock window
537     programmatically use moveDockWindow() with an edge of \c Minimized.
538 
539     Qt::Dock windows are moved transparently by default, i.e. during the
540     drag an outline rectangle is drawn on the screen representing the
541     position of the dock window as it moves. If you want the dock
542     window to be shown normally whilst it is moved use
543     setOpaqueMoving().
544 
545     The location of a dock window, i.e. its dock area and position
546     within the dock area, can be determined by calling getLocation().
547     Movable dock windows can be lined up to minimize wasted space with
548     lineUpDockWindows(). Pointers to the dock areas are available from
549     topDock(), leftDock(), rightDock() and bottomDock(). A customize
550     menu item is added to the pop up dock window menu if
551     isCustomizable() returns true; it returns false by default.
552     Reimplement isCustomizable() and customize() if you want to offer
553     this extra menu item, for example, to allow the user to change
554     settings relating to the main window and its toolbars and dock
555     windows.
556 
557     The main window's menu bar is fixed (at the top) by default. If
558     you want a movable menu bar, create a QMenuBar as a stretchable
559     widget inside its own movable dock window and restrict this dock
560     window to only live within the \c Top or \c Bottom dock:
561 
562     \snippet doc/src/snippets/code/src_qt3support_widgets_q3mainwindow.cpp 1
563 
564     An application with multiple dock windows can choose to save the
565     current dock window layout in order to restore it later, e.g. in
566     the next session. You can do this by using the streaming operators
567     for Q3MainWindow.
568 
569     To save the layout and positions of all the dock windows do this:
570 
571     \snippet doc/src/snippets/code/src_qt3support_widgets_q3mainwindow.cpp 2
572 
573     To restore the dock window positions and sizes (normally when the
574     application is next started), do the following:
575 
576     \snippet doc/src/snippets/code/src_qt3support_widgets_q3mainwindow.cpp 3
577 
578     The QSettings class can be used in conjunction with the streaming
579     operators to store the application's settings.
580 
581     Q3MainWindow's management of dock windows and toolbars is done
582     transparently behind-the-scenes by Q3DockArea.
583 
584     For multi-document interfaces (MDI), use a QWorkspace as the
585     central widget.
586 
587     Adding dock windows, e.g. toolbars, to Q3MainWindow's dock areas is
588     straightforward. If the supplied dock areas are not sufficient for
589     your application we suggest that you create a QWidget subclass and
590     add your own dock areas (see \l Q3DockArea) to the subclass since
591     Q3MainWindow provides functionality specific to the standard dock
592     areas it provides.
593 
594     \sa Q3ToolBar Q3DockWindow QStatusBar QAction QMenuBar Q3PopupMenu QDialog
595 */
596 
597 /*!
598     \enum Q3MainWindow::DockWindows
599 
600     Right-clicking a dock area will pop-up the dock window menu
601     (createDockWindowMenu() is called automatically). When called in
602     code you can specify what items should appear on the menu with
603     this enum.
604 
605     \value OnlyToolBars The menu will list all the toolbars, but not
606     any other dock windows.
607 
608     \value NoToolBars The menu will list dock windows but not
609     toolbars.
610 
611     \value AllDockWindows The menu will list all toolbars and other
612     dock windows. (This is the default.)
613 */
614 
615 /*!
616     \fn void Q3MainWindow::addToolBar(Q3DockWindow *dockWindow,
617     Qt::Dock position, bool newLine);
618 
619     Adds a new toolbar to the \a dockWindow. The toolbar is placed in
620     the given \a position. If \a newLine is true the toolbar is put on
621     a new line.
622 */
623 
624 /*!
625     \fn void Q3MainWindow::addToolBar(Q3DockWindow *dockWindow, const
626     QString &label, Qt::Dock position, bool newLine)
627     \overload
628 
629     The toolbar has the caption \a label and is placed in the given \a
630     position.
631 */
632 
633 /*!
634     \fn void Q3MainWindow::moveToolBar(Q3DockWindow *dockWindow, Qt::Dock position);
635 
636     Moves the given \a dockWindow into the given \a position.
637 */
638 
639 /*!
640     \fn void Q3MainWindow::moveToolBar(Q3DockWindow *dockWindow,
641     Qt::Dock position, bool nl, int index, int extraOffset)
642     \overload
643 
644     The \a dockWindow is made the \a{index}-th item in the toolbar,
645     moved over by \a extraOffset. If \a nl is true, the dock window is
646     put on a new line.
647 */
648 
649 /*!
650     \fn void Q3MainWindow::removeToolBar(Q3DockWindow *dockWindow);
651 
652     Removes the toolbar from the given \a dockWindow.
653 */
654 
655 /*!
656     \fn void Q3MainWindow::lineUpToolBars(bool keepNewLines);
657 
658     Lines up the toolbars. Line breaks are preserved if \a
659     keepNewLines is true.
660 */
661 
662 /*!
663     \fn void Q3MainWindow::toolBarPositionChanged(Q3ToolBar *toolbar);
664 
665     This signal is emitted when a \a toolbar is moved.
666 */
667 
668 /*!
669     \fn bool Q3MainWindow::toolBarsMovable() const
670 
671     Returns true if the window allows its toolbars to be moved; otherwise
672     returns false.
673 */
674 
675 /*!
676     \fn void Q3MainWindow::setToolBarsMovable(bool b)
677     If \a b is true the tool bars can be moved.
678 */
679 
680 /*!
681     Constructs an empty main window. The \a parent, \a name and widget
682     flags \a f, are passed on to the QWidget constructor.
683 
684     By default, the widget flags are set to Qt::WType_TopLevel rather
685     than 0 as they are with QWidget. If you don't want your
686     Q3MainWindow to be a top level widget then you will need to set \a
687     f to 0.
688 */
689 
Q3MainWindow(QWidget * parent,const char * name,Qt::WindowFlags f)690 Q3MainWindow::Q3MainWindow(QWidget * parent, const char * name, Qt::WindowFlags f)
691     : QWidget(*new Q3MainWindowPrivate, parent, f)
692 {
693     Q_D(Q3MainWindow);
694     setObjectName(QLatin1String(name));
695 #ifdef Q_WS_MAC
696     d->opaque = true;
697 #else
698     d->opaque = false;
699 #endif
700     installEventFilter(this);
701     d->topDock = new Q3DockArea(Qt::Horizontal, Q3DockArea::Normal, this, "qt_top_dock");
702     d->topDock->installEventFilter(this);
703     d->bottomDock = new Q3DockArea(Qt::Horizontal, Q3DockArea::Reverse, this, "qt_bottom_dock");
704     d->bottomDock->installEventFilter(this);
705     d->leftDock = new Q3DockArea(Qt::Vertical, Q3DockArea::Normal, this, "qt_left_dock");
706     d->leftDock->installEventFilter(this);
707     d->rightDock = new Q3DockArea(Qt::Vertical, Q3DockArea::Reverse, this, "qt_right_dock");
708     d->rightDock->installEventFilter(this);
709     d->hideDock = new QHideDock(this);
710 }
711 
712 
713 /*!
714     Destroys the object and frees any allocated resources.
715 */
716 
~Q3MainWindow()717 Q3MainWindow::~Q3MainWindow()
718 {
719     delete layout();
720 }
721 
722 #ifndef QT_NO_MENUBAR
723 /*!
724     Sets this main window to use the menu bar \a newMenuBar.
725 
726     The existing menu bar (if any) is deleted along with its contents.
727 
728     \sa menuBar()
729 */
730 
setMenuBar(QMenuBar * newMenuBar)731 void Q3MainWindow::setMenuBar(QMenuBar * newMenuBar)
732 {
733     Q_D(Q3MainWindow);
734     if (!newMenuBar)
735         return;
736     if (d->mb)
737         delete d->mb;
738     d->mb = newMenuBar;
739     d->mb->installEventFilter(this);
740     triggerLayout();
741 }
742 
743 
744 /*!
745     Returns the menu bar for this window.
746 
747     If there isn't one, then menuBar() creates an empty menu bar.
748 
749     \sa statusBar()
750 */
751 
menuBar() const752 QMenuBar * Q3MainWindow::menuBar() const
753 {
754     Q_D(const Q3MainWindow);
755     if (d->mb)
756         return d->mb;
757 
758     QObjectList l = queryList("QMenuBar", 0, false, false);
759     QMenuBar * b;
760     if (l.size()) {
761         b = static_cast<QMenuBar *>(l.at(0));
762     } else {
763         b = new QMenuBar((Q3MainWindow *)this);
764         b->setObjectName(QLatin1String("automatic menu bar"));
765         b->show();
766     }
767     d->mb = b;
768     d->mb->installEventFilter(const_cast<Q3MainWindow *>(this));
769     ((Q3MainWindow *)this)->triggerLayout();
770     return b;
771 }
772 #endif // QT_NO_MENUBAR
773 
774 /*!
775     Sets this main window to use the status bar \a newStatusBar.
776 
777     The existing status bar (if any) is deleted along with its
778     contents.
779 
780     Note that \a newStatusBar \e must be a child of this main window,
781     and that it is not automatically displayed. If you call this
782     function after show(), you will probably also need to call
783     newStatusBar->show().
784 
785     \sa setMenuBar() statusBar()
786 */
787 
setStatusBar(QStatusBar * newStatusBar)788 void Q3MainWindow::setStatusBar(QStatusBar * newStatusBar)
789 {
790     Q_D(Q3MainWindow);
791     if (!newStatusBar || newStatusBar == d->sb)
792         return;
793     if (d->sb)
794         delete d->sb;
795     d->sb = newStatusBar;
796 #if 0
797     // ### this code can cause unnecessary creation of a tool tip group
798     connect(toolTipGroup(), SIGNAL(showTip(QString)),
799              d->sb, SLOT(showMessage(QString)));
800     connect(toolTipGroup(), SIGNAL(removeTip()),
801              d->sb, SLOT(clearMessage()));
802 #endif
803     d->sb->installEventFilter(this);
804     triggerLayout();
805 }
806 
807 
808 /*!
809     Returns this main window's status bar. If there isn't one,
810     statusBar() creates an empty status bar, and if necessary a tool
811     tip group too.
812 
813     \sa menuBar()
814 */
815 
statusBar() const816 QStatusBar * Q3MainWindow::statusBar() const
817 {
818     Q_D(const Q3MainWindow);
819     if (d->sb)
820         return d->sb;
821 
822     QObjectList l = queryList("QStatusBar", 0, false, false);
823     QStatusBar * s;
824     if (l.size()) {
825         s = (QStatusBar *)l.at(0);
826     } else {
827         s = new QStatusBar((Q3MainWindow *)this, "automatic status bar");
828         s->show();
829     }
830     ((Q3MainWindow *)this)->setStatusBar(s);
831     ((Q3MainWindow *)this)->triggerLayout(true);
832     return s;
833 }
834 
835 
836 #if 0
837 /*!
838     Sets this main window to use the tool tip group \a
839     newToolTipGroup.
840 
841     The existing tool tip group (if any) is deleted along with its
842     contents. All the tool tips connected to it lose the ability to
843     display the group texts.
844 
845     \sa menuBar()
846 */
847 
848 void Q3MainWindow::setToolTipGroup(QToolTipGroup * newToolTipGroup)
849 {
850     Q_D(Q3MainWindow);
851     if (!newToolTipGroup || newToolTipGroup == d->ttg)
852         return;
853     if (d->ttg)
854         delete d->ttg;
855     d->ttg = newToolTipGroup;
856 
857     connect(toolTipGroup(), SIGNAL(showTip(QString)),
858             statusBar(), SLOT(showMessage(QString)));
859     connect(toolTipGroup(), SIGNAL(removeTip()),
860             statusBar(), SLOT(clearMessage()));
861 }
862 
863 
864 /*!
865     Returns this main window's tool tip group. If there isn't one,
866     toolTipGroup() creates an empty tool tip group.
867 
868     \sa menuBar() statusBar()
869 */
870 QToolTipGroup * Q3MainWindow::toolTipGroup() const
871 {
872     Q_D(const Q3MainWindow);
873     if (d->ttg)
874         return d->ttg;
875 
876     QToolTipGroup * t = new QToolTipGroup((Q3MainWindow*)this,
877                                            "automatic tool tip group");
878     ((Q3MainWindowPrivate*)d)->ttg = t;
879     return t;
880 }
881 #endif
882 
883 
884 /*!
885     If \a enable is true then users can dock windows in the \a dock
886     area. If \a enable is false users cannot dock windows in the \a
887     dock dock area.
888 
889     Users can dock (drag) dock windows into any enabled dock area.
890 */
891 
setDockEnabled(Qt::Dock dock,bool enable)892 void Q3MainWindow::setDockEnabled(Qt::Dock dock, bool enable)
893 {
894     d_func()->docks.insert(dock, enable);
895 }
896 
897 
898 /*!
899     Returns true if the \a dock dock area is enabled, i.e. it can
900     accept user dragged dock windows; otherwise returns false.
901 
902     \sa setDockEnabled()
903 */
904 
isDockEnabled(Qt::Dock dock) const905 bool Q3MainWindow::isDockEnabled(Qt::Dock dock) const
906 {
907     return d_func()->docks[dock];
908 }
909 
910 /*!
911     \overload
912 
913     Returns true if dock area \a area is enabled, i.e. it can accept
914     user dragged dock windows; otherwise returns false.
915 
916     \sa setDockEnabled()
917 */
918 
isDockEnabled(Q3DockArea * area) const919 bool Q3MainWindow::isDockEnabled(Q3DockArea *area) const
920 {
921     Q_D(const Q3MainWindow);
922     if (area == d->leftDock)
923         return d->docks[Qt::DockLeft];
924     if (area == d->rightDock)
925         return d->docks[Qt::DockRight];
926     if (area == d->topDock)
927         return d->docks[Qt::DockTop];
928     if (area == d->bottomDock)
929         return d->docks[Qt::DockBottom];
930     return false;
931 }
932 
933 /*!
934     \overload
935 
936     If \a enable is true then users can dock the \a dw dock window in
937     the \a dock area. If \a enable is false users cannot dock the \a
938     dw dock window in the \a dock area.
939 
940     In general users can dock (drag) dock windows into any enabled
941     dock area. Using this function particular dock areas can be
942     enabled (or disabled) as docking points for particular dock
943     windows.
944 */
945 
946 
setDockEnabled(Q3DockWindow * dw,Qt::Dock dock,bool enable)947 void Q3MainWindow::setDockEnabled(Q3DockWindow *dw, Qt::Dock dock, bool enable)
948 {
949     Q_D(Q3MainWindow);
950     if (!d->dockWindows.contains(dw)) {
951         d->dockWindows.append(dw);
952         connect(dw, SIGNAL(placeChanged(Q3DockWindow::Place)),
953                  this, SLOT(slotPlaceChanged()));
954     }
955     QString s;
956     s.sprintf("%p_%d", (void*)dw, (int)dock);
957     if (enable)
958         d->disabledDocks.removeAll(s);
959     else if (!d->disabledDocks.contains(s))
960         d->disabledDocks << s;
961     switch (dock) {
962         case Qt::DockTop:
963             topDock()->setAcceptDockWindow(dw, enable);
964             break;
965         case Qt::DockLeft:
966             leftDock()->setAcceptDockWindow(dw, enable);
967             break;
968         case Qt::DockRight:
969             rightDock()->setAcceptDockWindow(dw, enable);
970             break;
971         case Qt::DockBottom:
972             bottomDock()->setAcceptDockWindow(dw, enable);
973             break;
974         default:
975             break;
976     }
977 }
978 
979 /*!
980     \overload
981 
982     Returns true if dock area \a area is enabled for the dock window
983     \a dw; otherwise returns false.
984 
985     \sa setDockEnabled()
986 */
987 
isDockEnabled(Q3DockWindow * dw,Q3DockArea * area) const988 bool Q3MainWindow::isDockEnabled(Q3DockWindow *dw, Q3DockArea *area) const
989 {
990     Q_D(const Q3MainWindow);
991     if (!isDockEnabled(area))
992         return false;
993     Qt::Dock dock;
994     if (area == d->leftDock)
995         dock = Qt::DockLeft;
996     else if (area == d->rightDock)
997         dock = Qt::DockRight;
998     else if (area == d->topDock)
999         dock = Qt::DockTop;
1000     else if (area == d->bottomDock)
1001         dock = Qt::DockBottom;
1002     else
1003         return false;
1004     return isDockEnabled(dw, dock);
1005 }
1006 
1007 /*!
1008     \overload
1009 
1010     Returns true if dock area \a dock is enabled for the dock window
1011     \a tb; otherwise returns false.
1012 
1013     \sa setDockEnabled()
1014 */
1015 
isDockEnabled(Q3DockWindow * tb,Qt::Dock dock) const1016 bool Q3MainWindow::isDockEnabled(Q3DockWindow *tb, Qt::Dock dock) const
1017 {
1018     if (!isDockEnabled(dock))
1019         return false;
1020     QString s;
1021     s.sprintf("%p_%d", (void*)tb, (int)dock);
1022     return !d_func()->disabledDocks.contains(s);
1023 }
1024 
1025 
1026 
1027 /*!
1028     Adds \a dockWindow to the \a edge dock area.
1029 
1030     If \a newLine is false (the default) then the \a dockWindow is
1031     added at the end of the \a edge. For vertical edges the end is at
1032     the bottom, for horizontal edges (including \c Minimized) the end
1033     is at the right. If \a newLine is true a new line of dock windows
1034     is started with \a dockWindow as the first (left-most and
1035     top-most) dock window.
1036 
1037     If \a dockWindow is managed by another main window, it is first
1038     removed from that window.
1039 */
1040 
addDockWindow(Q3DockWindow * dockWindow,Qt::Dock edge,bool newLine)1041 void Q3MainWindow::addDockWindow(Q3DockWindow *dockWindow,
1042                               Qt::Dock edge, bool newLine)
1043 {
1044     Q_D(Q3MainWindow);
1045 #if defined (Q_WS_MAC) && !defined(QT_MAC_USE_COCOA)
1046     extern WindowPtr qt_mac_window_for(const QWidget*); //qwidget_mac.cpp
1047     if(isWindow() && edge == Qt::DockTop) {
1048         d->createWinId();
1049         ChangeWindowAttributes(qt_mac_window_for(this), kWindowToolbarButtonAttribute, 0);
1050     }
1051 #endif
1052     moveDockWindow(dockWindow, edge);
1053     dockWindow->setNewLine(newLine);
1054     if (!d->dockWindows.contains(dockWindow)) {
1055         d->dockWindows.append(dockWindow);
1056         connect(dockWindow, SIGNAL(placeChanged(Q3DockWindow::Place)),
1057                  this, SLOT(slotPlaceChanged()));
1058         dockWindow->installEventFilter(this);
1059     }
1060     dockWindow->setOpaqueMoving(d->opaque);
1061 }
1062 
1063 
1064 /*!
1065     \overload
1066 
1067     Adds \a dockWindow to the dock area with label \a label.
1068 
1069     If \a newLine is false (the default) the \a dockWindow is added at
1070     the end of the \a edge. For vertical edges the end is at the
1071     bottom, for horizontal edges (including \c Minimized) the end is
1072     at the right. If \a newLine is true a new line of dock windows is
1073     started with \a dockWindow as the first (left-most and top-most)
1074     dock window.
1075 
1076     If \a dockWindow is managed by another main window, it is first
1077     removed from that window.
1078 */
1079 
addDockWindow(Q3DockWindow * dockWindow,const QString & label,Qt::Dock edge,bool newLine)1080 void Q3MainWindow::addDockWindow(Q3DockWindow * dockWindow, const QString &label,
1081                               Qt::Dock edge, bool newLine)
1082 {
1083     addDockWindow(dockWindow, edge, newLine);
1084 #ifndef QT_NO_TOOLBAR
1085     Q3ToolBar *tb = qobject_cast<Q3ToolBar*>(dockWindow);
1086     if (tb)
1087         tb->setLabel(label);
1088 #endif
1089 }
1090 
1091 /*!
1092     Moves \a dockWindow to the end of the \a edge.
1093 
1094     For vertical edges the end is at the bottom, for horizontal edges
1095     (including \c Minimized) the end is at the right.
1096 
1097     If \a dockWindow is managed by another main window, it is first
1098     removed from that window.
1099 */
1100 
moveDockWindow(Q3DockWindow * dockWindow,Qt::Dock edge)1101 void Q3MainWindow::moveDockWindow(Q3DockWindow * dockWindow, Qt::Dock edge)
1102 {
1103     Q_D(Q3MainWindow);
1104     Qt::Orientation oo = dockWindow->orientation();
1105     switch (edge) {
1106     case Qt::DockTop:
1107         if (dockWindow->area() != d->topDock)
1108             dockWindow->removeFromDock(false);
1109         d->topDock->moveDockWindow(dockWindow);
1110         emit dockWindowPositionChanged(dockWindow);
1111         break;
1112     case Qt::DockBottom:
1113         if (dockWindow->area() != d->bottomDock)
1114             dockWindow->removeFromDock(false);
1115         d->bottomDock->moveDockWindow(dockWindow);
1116         emit dockWindowPositionChanged(dockWindow);
1117         break;
1118     case Qt::DockRight:
1119         if (dockWindow->area() != d->rightDock)
1120             dockWindow->removeFromDock(false);
1121         d->rightDock->moveDockWindow(dockWindow);
1122         emit dockWindowPositionChanged(dockWindow);
1123         break;
1124     case Qt::DockLeft:
1125         if (dockWindow->area() != d->leftDock)
1126             dockWindow->removeFromDock(false);
1127         d->leftDock->moveDockWindow(dockWindow);
1128         emit dockWindowPositionChanged(dockWindow);
1129         break;
1130     case Qt::DockTornOff:
1131         dockWindow->undock();
1132         break;
1133     case Qt::DockMinimized:
1134         dockWindow->undock(d->hideDock);
1135         break;
1136     case Qt::DockUnmanaged:
1137         break;
1138     }
1139 
1140     if (oo != dockWindow->orientation())
1141         dockWindow->setOrientation(dockWindow->orientation());
1142 }
1143 
1144 /*!
1145     \overload
1146 
1147     Moves \a dockWindow to position \a index within the \a edge dock
1148     area.
1149 
1150     Any dock windows with positions \a index or higher have their
1151     position number incremented and any of these on the same line are
1152     moved right (down for vertical dock areas) to make room.
1153 
1154     If \a nl is true, a new dock window line is created below the line
1155     in which the moved dock window appears and the moved dock window,
1156     with any others with higher positions on the same line, is moved
1157     to this new line.
1158 
1159     The \a extraOffset is the space to put between the left side of
1160     the dock area (top side for vertical dock areas) and the dock
1161     window. (This is mostly used for restoring dock windows to the
1162     positions the user has dragged them to.)
1163 
1164     If \a dockWindow is managed by another main window, it is first
1165     removed from that window.
1166 */
1167 
moveDockWindow(Q3DockWindow * dockWindow,Qt::Dock edge,bool nl,int index,int extraOffset)1168 void Q3MainWindow::moveDockWindow(Q3DockWindow * dockWindow, Qt::Dock edge, bool nl, int index, int extraOffset)
1169 {
1170     Q_D(Q3MainWindow);
1171     Qt::Orientation oo = dockWindow->orientation();
1172 
1173     dockWindow->setNewLine(nl);
1174     dockWindow->setOffset(extraOffset);
1175     switch (edge) {
1176     case Qt::DockTop:
1177         if (dockWindow->area() != d->topDock)
1178             dockWindow->removeFromDock(false);
1179         d->topDock->moveDockWindow(dockWindow, index);
1180         break;
1181     case Qt::DockBottom:
1182         if (dockWindow->area() != d->bottomDock)
1183             dockWindow->removeFromDock(false);
1184         d->bottomDock->moveDockWindow(dockWindow, index);
1185         break;
1186     case Qt::DockRight:
1187         if (dockWindow->area() != d->rightDock)
1188             dockWindow->removeFromDock(false);
1189         d->rightDock->moveDockWindow(dockWindow, index);
1190         break;
1191     case Qt::DockLeft:
1192         if (dockWindow->area() != d->leftDock)
1193             dockWindow->removeFromDock(false);
1194         d->leftDock->moveDockWindow(dockWindow, index);
1195         break;
1196     case Qt::DockTornOff:
1197         dockWindow->undock();
1198         break;
1199     case Qt::DockMinimized:
1200         dockWindow->undock(d->hideDock);
1201         break;
1202     case Qt::DockUnmanaged:
1203         break;
1204     }
1205 
1206     if (oo != dockWindow->orientation())
1207         dockWindow->setOrientation(dockWindow->orientation());
1208 }
1209 
1210 /*!
1211     Removes \a dockWindow from the main window's docking area,
1212     provided \a dockWindow is non-null and managed by this main
1213     window.
1214 */
1215 
removeDockWindow(Q3DockWindow * dockWindow)1216 void Q3MainWindow::removeDockWindow(Q3DockWindow * dockWindow)
1217 {
1218     Q_D(Q3MainWindow);
1219 
1220 #if defined (Q_WS_MAC) && !defined (QT_MAC_USE_COCOA)
1221     extern WindowPtr qt_mac_window_for(const QWidget*); //qwidget_mac.cpp
1222     if(isWindow() && dockWindow->area() == topDock() && !dockWindows(Qt::DockTop).count())
1223         ChangeWindowAttributes(qt_mac_window_for(this), 0, kWindowToolbarButtonAttribute);
1224 #endif
1225 
1226     dockWindow->hide();
1227     d->dockWindows.removeAll(dockWindow);
1228     disconnect(dockWindow, SIGNAL(placeChanged(Q3DockWindow::Place)),
1229                 this, SLOT(slotPlaceChanged()));
1230     dockWindow->removeEventFilter(this);
1231 }
1232 
1233 /*!
1234     Sets up the geometry management of the window. It is called
1235     automatically when needed, so you shouldn't need to call it.
1236 */
1237 
setUpLayout()1238 void Q3MainWindow::setUpLayout()
1239 {
1240     Q_D(Q3MainWindow);
1241 #ifndef QT_NO_MENUBAR
1242     if (!d->mb) {
1243         // slightly evil hack here.  reconsider this
1244         QObjectList l = queryList("QMenuBar", 0, false, false);
1245         if (l.size())
1246             d->mb = menuBar();
1247     }
1248 #endif
1249     if (!d->sb) {
1250         // as above.
1251         QObjectList l = queryList("QStatusBar", 0, false, false);
1252         if (l.size())
1253             d->sb = statusBar();
1254     }
1255 
1256     if (!d->tll) {
1257         d->tll = new QBoxLayout(this, QBoxLayout::Down);
1258         d->tll->setResizeMode(minimumSize().isNull() ? QLayout::Minimum : QLayout::FreeResize);
1259         d->mwl = new Q3MainWindowLayout(this);
1260     } else {
1261         d->tll->setMenuBar(0);
1262         QLayoutItem *item;
1263         while ((item = d->tll->takeAt(0))) {
1264             if (item != d->mwl)
1265                 delete item;
1266         }
1267     }
1268 
1269 #ifndef QT_NO_MENUBAR
1270     if (d->mb && d->mb->isVisibleTo(this)) {
1271         d->tll->setMenuBar(d->mb);
1272         if (style()->styleHint(QStyle::SH_MainWindow_SpaceBelowMenuBar, 0, this))
1273             d->tll->addSpacing(d->movable ? 1 : 2);
1274     }
1275 #endif
1276 
1277     d->tll->addWidget(d->hideDock);
1278     if(d->topDock->parentWidget() == this)
1279         d->tll->addWidget(d->topDock);
1280 
1281     Q3MainWindowLayout *mwl = d->mwl;
1282     d->tll->addItem(mwl);
1283     d->tll->setStretchFactor(mwl, 1);
1284 
1285     if(d->leftDock->parentWidget() == this)
1286         mwl->setLeftDock(d->leftDock);
1287     if (centralWidget())
1288         mwl->setCentralWidget(centralWidget());
1289     if(d->rightDock->parentWidget() == this)
1290         mwl->setRightDock(d->rightDock);
1291 
1292     if(d->bottomDock->parentWidget() == this)
1293         d->tll->addWidget(d->bottomDock);
1294 
1295     if (d->sb && d->sb->parentWidget() == this) {
1296         d->tll->addWidget(d->sb, 0);
1297         // make the sb stay on top of tool bars if there isn't enough space
1298         d->sb->raise();
1299     }
1300 }
1301 
1302 /*! \reimp */
setVisible(bool visible)1303 void Q3MainWindow::setVisible(bool visible)
1304 {
1305     Q_D(Q3MainWindow);
1306     if (visible) {
1307         if (!d->tll)
1308             setUpLayout();
1309 
1310         // show all floating dock windows not explicitly hidden
1311         if (!isVisible()) {
1312             for (int i = 0; i < d->dockWindows.size(); ++i) {
1313                 Q3DockWindow *dw = d->dockWindows.at(i);
1314                 if (dw->isWindow() && !dw->isVisible() && !dw->testAttribute(Qt::WA_WState_Hidden)) {
1315                     reinterpret_cast<Q3MainWindow *>(dw)->setAttribute(Qt::WA_WState_Hidden);
1316                     dw->show();
1317                 }
1318             }
1319         }
1320     } else if (isVisible()) {
1321         for (int i = 0; i < d->dockWindows.size(); ++i) {
1322             Q3DockWindow *dw = d->dockWindows.at(i);
1323             if (dw->isWindow() && dw->isVisible()) {
1324                 dw->hide(); // implicit hide, so clear forcehide
1325                 reinterpret_cast<Q3MainWindow *>(dw)->setAttribute(Qt::WA_WState_Hidden, false);
1326             }
1327         }
1328     }
1329     QWidget::setVisible(visible);
1330 }
1331 
1332 
1333 /*!  \reimp */
sizeHint() const1334 QSize Q3MainWindow::sizeHint() const
1335 {
1336     Q3MainWindow* that = (Q3MainWindow*) this;
1337     // Workaround: because d->tll get's deleted in
1338     // totalSizeHint->polish->sendPostedEvents->childEvent->triggerLayout
1339     QApplication::sendPostedEvents(that, QEvent::ChildInserted);
1340     if (!that->d_func()->tll)
1341         that->setUpLayout();
1342     return that->d_func()->tll->totalSizeHint();
1343 }
1344 
1345 /*!  \reimp */
minimumSizeHint() const1346 QSize Q3MainWindow::minimumSizeHint() const
1347 {
1348     Q_D(const Q3MainWindow);
1349     if (!d->tll) {
1350         Q3MainWindow* that = (Q3MainWindow*) this;
1351         that->setUpLayout();
1352     }
1353     return d->tll->totalMinimumSize();
1354 }
1355 
1356 /*!
1357     Sets the central widget for this main window to \a w.
1358 
1359     The central widget is surrounded by the left, top, right and
1360     bottom dock areas. The menu bar is above the top dock area.
1361 
1362     \sa centralWidget()
1363 */
1364 
setCentralWidget(QWidget * w)1365 void Q3MainWindow::setCentralWidget(QWidget * w)
1366 {
1367     Q_D(Q3MainWindow);
1368     if (d->mc)
1369         d->mc->removeEventFilter(this);
1370     d->mc = w;
1371     if (d->mc)
1372         d->mc->installEventFilter(this);
1373     triggerLayout();
1374 }
1375 
1376 
1377 /*!
1378     Returns a pointer to the main window's central widget.
1379 
1380     The central widget is surrounded by the left, top, right and
1381     bottom dock areas. The menu bar is above the top dock area.
1382 
1383     \sa setCentralWidget()
1384 */
1385 
centralWidget() const1386 QWidget * Q3MainWindow::centralWidget() const
1387 {
1388     return d_func()->mc;
1389 }
1390 
1391 
1392 /*! \reimp */
1393 
paintEvent(QPaintEvent *)1394 void Q3MainWindow::paintEvent(QPaintEvent *)
1395 {
1396     Q_D(Q3MainWindow);
1397     if (d->mb &&
1398         style()->styleHint(QStyle::SH_MainWindow_SpaceBelowMenuBar, 0, this)) {
1399         QPainter p(this);
1400         int y = d->mb->height() + 1;
1401         QStyleOption opt(0, QStyleOption::SO_Default);
1402         opt.rect.setRect(0, y, width(), 1);
1403         opt.palette = palette();
1404         opt.state = QStyle::State_Sunken;
1405         style()->drawPrimitive(QStyle::PE_Q3Separator, &opt, &p, this);
1406     }
1407 }
1408 
1409 
dockMainWindow(QObject * dock) const1410 bool Q3MainWindow::dockMainWindow(QObject *dock) const
1411 {
1412     while (dock) {
1413         if (dock->parent() &&
1414             dock->parent() == const_cast<Q3MainWindow*>(this))
1415             return true;
1416         if (qobject_cast<Q3MainWindow*>(dock->parent()))
1417             return false;
1418         dock = dock->parent();
1419     }
1420     return false;
1421 }
1422 
1423 /*!
1424     \reimp
1425 */
1426 
eventFilter(QObject * o,QEvent * e)1427 bool Q3MainWindow::eventFilter(QObject* o, QEvent *e)
1428 {
1429     Q_D(Q3MainWindow);
1430     if (e->type() == QEvent::Show && o == this) {
1431         if (!d->tll)
1432             setUpLayout();
1433         d->tll->activate();
1434     } else if (e->type() == QEvent::ContextMenu && d->dockMenu &&
1435                 ((qobject_cast<Q3DockArea*>(o) && dockMainWindow(o)) || o == d->hideDock || o == d->mb)) {
1436         if (showDockMenu(((QMouseEvent*)e)->globalPos())) {
1437             ((QContextMenuEvent*)e)->accept();
1438             return true;
1439         }
1440     }
1441 
1442     return QWidget::eventFilter(o, e);
1443 }
1444 
1445 
1446 /*!
1447     Monitors events, received in \a e, to ensure the layout is updated.
1448 */
childEvent(QChildEvent * e)1449 void Q3MainWindow::childEvent(QChildEvent* e)
1450 {
1451     Q_D(Q3MainWindow);
1452     if (e->type() == QEvent::ChildRemoved) {
1453         if (e->child() == 0 ||
1454              !e->child()->isWidgetType() ||
1455              ((QWidget*)e->child())->isWindow()) {
1456             // nothing
1457         } else if (e->child() == d->sb) {
1458             d->sb = 0;
1459             triggerLayout();
1460         } else if (e->child() == d->mb) {
1461             d->mb = 0;
1462             triggerLayout();
1463         } else if (e->child() == d->mc) {
1464             d->mc = 0;
1465             d->mwl->setCentralWidget(0);
1466             triggerLayout();
1467         } else if (qobject_cast<Q3DockWindow*>(e->child())) {
1468             removeDockWindow((Q3DockWindow *)(e->child()));
1469             d->appropriate.remove((Q3DockWindow*)e->child());
1470             triggerLayout();
1471         }
1472     } else if (e->type() == QEvent::ChildInserted && !d->sb) {
1473         d->sb = qobject_cast<QStatusBar*>(e->child());
1474         if (d->sb) {
1475             if (d->tll) {
1476                 if (!d->tll->findWidget(d->sb))
1477                     d->tll->addWidget(d->sb);
1478             } else {
1479                 triggerLayout();
1480             }
1481         }
1482     }
1483 }
1484 
1485 /*!
1486     \reimp
1487 */
1488 
event(QEvent * e)1489 bool Q3MainWindow::event(QEvent * e)
1490 {
1491     Q_D(Q3MainWindow);
1492 #ifndef QT_NO_STATUSTIP
1493     if (e->type() == QEvent::StatusTip) {
1494         if (d->sb) {
1495             d->sb->showMessage(static_cast<QStatusTipEvent*>(e)->tip());
1496             return true;
1497         }
1498     }
1499 #endif
1500     if (e->type() == QEvent::ToolBarChange) {
1501         // Keep compatibility with the Qt 3 main window, use the real main window
1502         // or reimplement if you want proper handling.
1503         int deltaH = 0;
1504         Q3DockArea *area = topDock();
1505         if (area->width() >= area->height()) {
1506             deltaH = area->sizeHint().height();
1507             if (!area->isVisible()) {
1508                 area->show();
1509             } else {
1510                 area->hide();
1511                 deltaH = -deltaH;
1512             }
1513         }
1514 
1515         if (deltaH) {
1516             QApplication::sendPostedEvents(this, QEvent::LayoutRequest);
1517             resize(width(), height() + deltaH);
1518         }
1519         return true;
1520     }
1521     if (e->type() == QEvent::ChildRemoved && ((QChildEvent*)e)->child() == d->mc) {
1522         d->mc->removeEventFilter(this);
1523         d->mc = 0;
1524         d->mwl->setCentralWidget(0);
1525     }
1526 
1527     if (e->type() == QEvent::MenubarUpdated) {
1528         QMenubarUpdatedEvent * const event = static_cast<QMenubarUpdatedEvent *>(e);
1529         if (event->menuBar() && event->menuBar()->parent() == this) {
1530             triggerLayout();
1531             update();
1532         }
1533     }
1534     return QWidget::event(e);
1535 }
1536 
1537 
1538 /*!
1539     \property Q3MainWindow::usesBigPixmaps
1540     \brief whether big pixmaps are enabled
1541 
1542     If false (the default), the tool buttons will use small pixmaps;
1543     otherwise big pixmaps will be used.
1544 
1545     Tool buttons and other widgets that wish to respond to this
1546     setting are responsible for reading the correct state on startup,
1547     and for connecting to the main window's widget's
1548     pixmapSizeChanged() signal.
1549 */
1550 
usesBigPixmaps() const1551 bool Q3MainWindow::usesBigPixmaps() const
1552 {
1553     return d_func()->ubp;
1554 }
1555 
setUsesBigPixmaps(bool enable)1556 void Q3MainWindow::setUsesBigPixmaps(bool enable)
1557 {
1558     Q_D(Q3MainWindow);
1559     if (enable == (bool)d->ubp)
1560         return;
1561 
1562     d->ubp = enable;
1563     emit pixmapSizeChanged(enable);
1564 
1565     QObjectList l = queryList("QLayout");
1566     for (int i = 0; i < l.size(); ++i)
1567             static_cast<QLayout *>(l.at(i))->activate();
1568 }
1569 
1570 /*!
1571     \property Q3MainWindow::usesTextLabel
1572     \brief whether text labels for toolbar buttons are enabled
1573 
1574     If disabled (the default), the tool buttons will not use text
1575     labels. If enabled, text labels will be used.
1576 
1577     Tool buttons and other widgets that wish to respond to this
1578     setting are responsible for reading the correct state on startup,
1579     and for connecting to the main window's widget's
1580     usesTextLabelChanged() signal.
1581 
1582     \sa QToolButton::setUsesTextLabel()
1583 */
1584 
usesTextLabel() const1585 bool Q3MainWindow::usesTextLabel() const
1586 {
1587     return d_func()->utl;
1588 }
1589 
1590 
setUsesTextLabel(bool enable)1591 void Q3MainWindow::setUsesTextLabel(bool enable)
1592 {
1593     Q_D(Q3MainWindow);
1594     if (enable == (bool)d->utl)
1595         return;
1596 
1597     d->utl = enable;
1598     emit usesTextLabelChanged(enable);
1599 
1600     QObjectList l = queryList("QLayout");
1601     for (int i = 0; i < l.size(); ++i)
1602             static_cast<QLayout *>(l.at(i))->activate();
1603     triggerLayout(false);
1604 }
1605 
1606 
1607 /*!
1608     \fn void Q3MainWindow::pixmapSizeChanged(bool b)
1609 
1610     This signal is emitted whenever the setUsesBigPixmaps() is called
1611     with a value different to the current setting. The new value is
1612     passed in \a b. All widgets that should respond to such changes,
1613     e.g. toolbar buttons, must connect to this signal.
1614 */
1615 
1616 /*!
1617     \fn void Q3MainWindow::usesTextLabelChanged(bool b)
1618 
1619     This signal is emitted whenever the setUsesTextLabel() is called
1620     with a value different to the current setting. The new value is
1621     passed in \a b. All widgets that should respond to such changes,
1622     e.g. toolbar buttons, must connect to this signal.
1623 */
1624 
1625 /*!
1626     \fn void Q3MainWindow::dockWindowPositionChanged(Q3DockWindow *dockWindow)
1627 
1628     This signal is emitted when the \a dockWindow has changed its
1629     position. A change in position occurs when a dock window is moved
1630     within its dock area or moved to another dock area (including the
1631     \c Minimized and \c TearOff dock areas).
1632 
1633     \sa getLocation()
1634 */
1635 
setRightJustification(bool enable)1636 void Q3MainWindow::setRightJustification(bool enable)
1637 {
1638     Q_D(Q3MainWindow);
1639     if (enable == (bool)d->justify)
1640         return;
1641     d->justify = enable;
1642     triggerLayout(true);
1643 }
1644 
1645 
1646 /*!
1647     \property Q3MainWindow::rightJustification
1648     \brief whether the main window right-justifies its dock windows
1649 
1650     If disabled (the default), stretchable dock windows are expanded,
1651     and non-stretchable dock windows are given the minimum space they
1652     need. Since most dock windows are not stretchable, this usually
1653     results in an unjustified right edge (or unjustified bottom edge
1654     for a vertical dock area). If enabled, the main window will
1655     right-justify its dock windows.
1656 
1657     \sa Q3DockWindow::setVerticalStretchable(), Q3DockWindow::setHorizontalStretchable()
1658 */
1659 
rightJustification() const1660 bool Q3MainWindow::rightJustification() const
1661 {
1662     return d_func()->justify;
1663 }
1664 
1665 /*! \internal
1666  */
1667 
triggerLayout(bool deleteLayout)1668 void Q3MainWindow::triggerLayout(bool deleteLayout)
1669 {
1670     Q_D(Q3MainWindow);
1671     if (deleteLayout || !d->tll)
1672         setUpLayout();
1673     QApplication::postEvent(this, new QEvent(QEvent::LayoutHint));
1674 }
1675 
1676 /*!
1677     Enters 'What's This?' mode and returns immediately.
1678 
1679     This is the same as QWhatsThis::enterWhatsThisMode(), but
1680     implemented as a main window object's slot. This way it can easily
1681     be used for popup menus, for example:
1682 
1683     \snippet doc/src/snippets/code/src_qt3support_widgets_q3mainwindow.cpp 4
1684 
1685     \sa Q3WhatsThis::enterWhatsThisMode()
1686 */
whatsThis()1687 void Q3MainWindow::whatsThis()
1688 {
1689 #ifndef QT_NO_WHATSTHIS
1690     QWhatsThis::enterWhatsThisMode();
1691 #endif
1692 }
1693 
1694 /*!
1695     Finds the location of the dock window \a dw.
1696 
1697     If the \a dw dock window is found in the main window the function
1698     returns true and populates the \a dock variable with the dw's dock
1699     area and the \a index with the dw's position within the dock area.
1700     It also sets \a nl to true if the \a dw begins a new line
1701     (otherwise false), and \a extraOffset with the dock window's offset.
1702 
1703     If the \a dw dock window is not found then the function returns
1704     false and the state of \a dock, \a index, \a nl and \a extraOffset
1705     is undefined.
1706 
1707     If you want to save and restore dock window positions then use
1708     operator>>() and operator<<().
1709 */
1710 
getLocation(Q3DockWindow * dw,Qt::Dock & dock,int & index,bool & nl,int & extraOffset) const1711 bool Q3MainWindow::getLocation(Q3DockWindow *dw, Qt::Dock &dock, int &index, bool &nl, int &extraOffset) const
1712 {
1713     Q_D(const Q3MainWindow);
1714     dock = Qt::DockTornOff;
1715     if (d->topDock->hasDockWindow(dw, &index))
1716         dock = Qt::DockTop;
1717     else if (d->bottomDock->hasDockWindow(dw, &index))
1718         dock = Qt::DockBottom;
1719     else if (d->leftDock->hasDockWindow(dw, &index))
1720         dock = Qt::DockLeft;
1721     else if (d->rightDock->hasDockWindow(dw, &index))
1722         dock = Qt::DockRight;
1723     else if (dw->parentWidget() == d->hideDock) {
1724         index = 0;
1725         dock = Qt::DockMinimized;
1726     } else {
1727         index = 0;
1728     }
1729     nl = dw->newLine();
1730     extraOffset = dw->offset();
1731     return true;
1732 }
1733 
1734 #ifndef QT_NO_TOOLBAR
1735 /*!
1736     Returns a list of all the toolbars which are in the \a dock dock
1737     area, regardless of their state.
1738 
1739     For example, the \c TornOff dock area may contain closed toolbars
1740     but these are returned along with the visible toolbars.
1741 
1742     \sa dockWindows()
1743 */
1744 
toolBars(Qt::Dock dock) const1745 QList<Q3ToolBar *> Q3MainWindow::toolBars(Qt::Dock dock) const
1746 {
1747     QList<Q3DockWindow *> lst = dockWindows(dock);
1748     QList<Q3ToolBar *> tbl;
1749     for (int i = 0; i < lst.size(); ++i) {
1750         Q3ToolBar *tb = qobject_cast<Q3ToolBar *>(lst.at(i));
1751         if (tb)
1752             tbl.append(tb);
1753     }
1754     return tbl;
1755 }
1756 #endif
1757 
1758 /*!
1759     Returns a list of all the dock windows which are in the \a dock
1760     dock area, regardless of their state.
1761 
1762     For example, the Qt::DockTornOff dock area may contain closed dock
1763     windows but these are returned along with the visible dock
1764     windows.
1765 */
1766 
dockWindows(Qt::Dock dock) const1767 QList<Q3DockWindow *> Q3MainWindow::dockWindows(Qt::Dock dock) const
1768 {
1769     Q_D(const Q3MainWindow);
1770     QList<Q3DockWindow *> lst;
1771     switch (dock) {
1772     case Qt::DockTop:
1773         return d->topDock->dockWindowList();
1774     case Qt::DockBottom:
1775         return d->bottomDock->dockWindowList();
1776     case Qt::DockLeft:
1777         return d->leftDock->dockWindowList();
1778     case Qt::DockRight:
1779         return d->rightDock->dockWindowList();
1780     case Qt::DockTornOff: {
1781         for (int i = 0; i < d->dockWindows.size(); ++i) {
1782             Q3DockWindow *w = d->dockWindows.at(i);
1783             if (!w->area() && w->place() == Q3DockWindow::OutsideDock)
1784                 lst.append(w);
1785         }
1786     }
1787     return lst;
1788     case Qt::DockMinimized: {
1789         QObjectList childList = d->hideDock->children();
1790         for (int i = 0; i < childList.size(); ++i) {
1791             Q3DockWindow *dw = qobject_cast<Q3DockWindow*>(childList.at(i));
1792             if (dw)
1793                 lst.append(dw);
1794         }
1795     }
1796     return lst;
1797     default:
1798         break;
1799     }
1800     return lst;
1801 }
1802 
1803 /*!
1804     \overload
1805 
1806     Returns the list of dock windows which belong to this main window,
1807     regardless of which dock area they are in or what their state is,
1808     (e.g. irrespective of whether they are visible or not).
1809 */
1810 
dockWindows() const1811 QList<Q3DockWindow *> Q3MainWindow::dockWindows() const
1812 {
1813     return d_func()->dockWindows;
1814 }
1815 
setDockWindowsMovable(bool enable)1816 void Q3MainWindow::setDockWindowsMovable(bool enable)
1817 {
1818     Q_D(Q3MainWindow);
1819     d->movable = enable;
1820     QObjectList l = queryList("Q3DockWindow");
1821     for (int i = 0; i < l.size(); ++i)
1822         static_cast<Q3DockWindow*>(l.at(i))->setMovingEnabled(enable);
1823 }
1824 
1825 /*!
1826     \property Q3MainWindow::dockWindowsMovable
1827     \brief whether the dock windows are movable
1828 
1829     If true (the default), the user will be able to move movable dock
1830     windows from one Q3MainWindow dock area to another, including the
1831     \c TearOff area (i.e. where the dock window floats freely as a
1832     window in its own right), and the \c Minimized area (where only
1833     the dock window's handle is shown below the menu bar). Movable
1834     dock windows can also be moved within Q3MainWindow dock areas, i.e.
1835     to rearrange them within a dock area.
1836 
1837     If false the user will not be able to move any dock windows.
1838 
1839     By default dock windows are moved transparently (i.e. only an
1840     outline rectangle is shown during the drag), but this setting can
1841     be changed with setOpaqueMoving().
1842 
1843     \sa setDockEnabled(), setOpaqueMoving()
1844 */
1845 
dockWindowsMovable() const1846 bool Q3MainWindow::dockWindowsMovable() const
1847 {
1848     return d_func()->movable;
1849 }
1850 
setOpaqueMoving(bool b)1851 void Q3MainWindow::setOpaqueMoving(bool b)
1852 {
1853     Q_D(Q3MainWindow);
1854     d->opaque = b;
1855     QObjectList l = queryList("Q3DockWindow");
1856     for (int i = 0; i < l.size(); ++i)
1857         static_cast<Q3DockWindow*>(l.at(i))->setOpaqueMoving(b);
1858 }
1859 
1860 /*!
1861     \property Q3MainWindow::opaqueMoving
1862     \brief whether dock windows are moved opaquely
1863 
1864     If true the dock windows of the main window are shown opaquely
1865     (i.e. it shows the toolbar as it looks when docked) whilst it is
1866     being moved. If false (the default) they are shown transparently,
1867     (i.e. as an outline rectangle).
1868 
1869     \warning Opaque moving of toolbars and dockwindows is known to
1870     have several problems. We recommend avoiding the use of this
1871     feature for the time being. We intend fixing the problems in a
1872     future release.
1873 */
1874 
opaqueMoving() const1875 bool Q3MainWindow::opaqueMoving() const
1876 {
1877     return d_func()->opaque;
1878 }
1879 
1880 /*!
1881     This function will line up dock windows within the visible dock
1882     areas (\c Top, \c Left, \c Right and \c Bottom) as compactly as
1883     possible.
1884 
1885     If \a keepNewLines is true, all dock windows stay on their
1886     original lines. If \a keepNewLines is false then newlines may be
1887     removed to achieve the most compact layout possible.
1888 
1889     The method only works if dockWindowsMovable() returns true.
1890 */
1891 
lineUpDockWindows(bool keepNewLines)1892 void Q3MainWindow::lineUpDockWindows(bool keepNewLines)
1893 {
1894     Q_D(const Q3MainWindow);
1895     if (!dockWindowsMovable())
1896         return;
1897     d->topDock->lineUp(keepNewLines);
1898     d->leftDock->lineUp(keepNewLines);
1899     d->rightDock->lineUp(keepNewLines);
1900     d->bottomDock->lineUp(keepNewLines);
1901 }
1902 
1903 /*!
1904     Returns true, if the dock window menu is enabled; otherwise
1905     returns false.
1906 
1907     The menu lists the (appropriate()) dock windows (which may be
1908     shown or hidden), and has a "Line Up Dock Windows" menu item. It
1909     will also have a "Customize" menu item if isCustomizable() returns
1910     true.
1911 
1912     \sa setDockEnabled(), lineUpDockWindows() appropriate()
1913     setAppropriate()
1914 */
1915 
isDockMenuEnabled() const1916 bool Q3MainWindow::isDockMenuEnabled() const
1917 {
1918     return d_func()->dockMenu;
1919 }
1920 
1921 /*!
1922     If \a b is true, then right clicking on a dock window or dock area
1923     will pop up the dock window menu. If \a b is false, right clicking
1924     a dock window or dock area will not pop up the menu.
1925 
1926     The menu lists the (appropriate()) dock windows (which may be
1927     shown or hidden), and has a "Line Up Dock Windows" item. It will
1928     also have a "Customize" menu item if isCustomizable() returns
1929     true.
1930 
1931     \sa lineUpDockWindows(), isDockMenuEnabled()
1932 */
1933 
setDockMenuEnabled(bool b)1934 void Q3MainWindow::setDockMenuEnabled(bool b)
1935 {
1936     d_func()->dockMenu = b;
1937 }
1938 
1939 /*!
1940     Creates the dock window menu which contains all toolbars (if \a
1941     dockWindows is \c OnlyToolBars), all dock windows (if \a
1942     dockWindows is \c NoToolBars) or all toolbars and dock windows (if
1943     \a dockWindows is \c AllDockWindows - the default).
1944 
1945     This function is called internally when necessary, e.g. when the
1946     user right clicks a dock area (providing isDockMenuEnabled()
1947     returns true). You can reimplement this function if you wish to
1948     customize the behavior.
1949 
1950     The menu items representing the toolbars and dock windows are
1951     checkable. The visible dock windows are checked and the hidden
1952     dock windows are unchecked. The user can click a menu item to
1953     change its state (show or hide the dock window).
1954 
1955     The list and the state are always kept up-to-date.
1956 
1957     Toolbars and dock windows which are not appropriate in the current
1958     context (see setAppropriate()) are not listed in the menu.
1959 
1960     The menu also has a menu item for lining up the dock windows.
1961 
1962     If isCustomizable() returns true, a Customize menu item is added
1963     to the menu, which if clicked will call customize(). The
1964     isCustomizable() function we provide returns false and customize()
1965     does nothing, so they must be reimplemented in a subclass to be
1966     useful.
1967 */
1968 
createDockWindowMenu(DockWindows dockWindows) const1969 Q3PopupMenu *Q3MainWindow::createDockWindowMenu(DockWindows dockWindows) const
1970 {
1971     Q_D(const Q3MainWindow);
1972     QObjectList l = queryList("Q3DockWindow");
1973     if (l.isEmpty())
1974         return 0;
1975 
1976     Q3PopupMenu *menu = new Q3PopupMenu((Q3MainWindow*)this);
1977     menu->setObjectName(QLatin1String("qt_customize_menu"));
1978     d->dockWindowModes.replace( menu, dockWindows );
1979     menu->setCheckable(true);
1980     connect( menu, SIGNAL(aboutToShow()), this, SLOT(menuAboutToShow()) );
1981     return menu;
1982 }
1983 
1984 /*!
1985     This slot is called from the aboutToShow() signal of the default
1986     dock menu of the mainwindow. The default implementation
1987     initializes the menu with all dock windows and toolbars in this
1988     slot.
1989 */
1990 
menuAboutToShow()1991 void Q3MainWindow::menuAboutToShow()
1992 {
1993     Q_D(Q3MainWindow);
1994     Q3PopupMenu *menu = (Q3PopupMenu*)sender();
1995     menu->clear();
1996 
1997     DockWindows dockWindows;
1998     {
1999         QMap<Q3PopupMenu*, DockWindows>::Iterator it = d->dockWindowModes.find( menu );
2000         if ( it == d->dockWindowModes.end() )
2001             return;
2002         dockWindows = (*it);
2003     }
2004 
2005     QObjectList l = queryList("Q3DockWindow");
2006     bool empty = true;
2007     if (!l.isEmpty()) {
2008         if (dockWindows == AllDockWindows || dockWindows == NoToolBars) {
2009             for (int i = 0; i < l.size(); ++i) {
2010                 Q3DockWindow *dw = (Q3DockWindow*)l.at(i);
2011                 if (!appropriate(dw) || qobject_cast<Q3ToolBar*>(dw) || !dockMainWindow(dw))
2012                     continue;
2013                 QString label = dw->windowTitle();
2014                 if (!label.isEmpty()) {
2015                     QAction *act = menu->addAction(label);
2016                     act->setCheckable(true);
2017                     act->setChecked(dw->isVisible());
2018                     QObject::connect(act, SIGNAL(triggered()), dw, SLOT(toggleVisible()));
2019                     empty = false;
2020                 }
2021             }
2022         }
2023         if (!empty) {
2024             menu->addSeparator();
2025             empty = true;
2026         }
2027 #ifndef QT_NO_TOOLBAR
2028         if (dockWindows == AllDockWindows || dockWindows == OnlyToolBars) {
2029             for (int i = 0; i < l.size(); ++i) {
2030                 Q3ToolBar *tb = qobject_cast<Q3ToolBar*>(l.at(i));
2031                 if (!tb || !appropriate(tb) || !dockMainWindow(tb))
2032                     continue;
2033                 QString label = tb->label();
2034                 if (!label.isEmpty()) {
2035                     QAction *act = menu->addAction(label);
2036                     act->setCheckable(true);
2037                     act->setChecked(tb->isVisible());
2038                     QObject::connect(act, SIGNAL(triggered()), tb, SLOT(toggleVisible()));
2039                     empty = false;
2040                 }
2041             }
2042         }
2043 #endif
2044     }
2045     if (!empty) {
2046         menu->addSeparator();
2047         empty = true;
2048     }
2049 
2050     if (dockWindowsMovable())
2051         menu->addAction(tr("Line up"), this, SLOT(doLineUp()));
2052     if (isCustomizable())
2053         menu->addAction(tr("Customize..."), this, SLOT(customize()));
2054 }
2055 
2056 
2057 /*!
2058     Shows the dock menu at the position \a globalPos. The menu lists
2059     the dock windows so that they can be shown (or hidden), lined up,
2060     and possibly customized. Returns true if the menu is shown;
2061     otherwise returns false.
2062 
2063     If you want a custom menu, reimplement this function. You can
2064     create the menu from scratch or call createDockWindowMenu() and
2065     modify the result.
2066 
2067     The default implementation uses the dock window menu which gets
2068     created by createDockWindowMenu(). You can reimplement
2069     createDockWindowMenu() if you want to use your own specialized
2070     popup menu.
2071 */
2072 
showDockMenu(const QPoint & globalPos)2073 bool Q3MainWindow::showDockMenu(const QPoint &globalPos)
2074 {
2075     Q_D(Q3MainWindow);
2076     if (!d->dockMenu)
2077         return false;
2078 
2079     if(Q3PopupMenu *ret = createDockWindowMenu()) {
2080         ret->exec(globalPos);
2081         delete ret;
2082         return true;
2083     }
2084     return false;
2085 }
2086 
slotPlaceChanged()2087 void Q3MainWindow::slotPlaceChanged()
2088 {
2089     QObject* obj = (QObject*)sender();
2090     Q3DockWindow *dw = qobject_cast<Q3DockWindow*>(obj);
2091     if (dw)
2092         emit dockWindowPositionChanged(dw);
2093 #ifndef QT_NO_TOOLBAR
2094     Q3ToolBar *tb = qobject_cast<Q3ToolBar*>(obj);
2095     if (tb)
2096         emit toolBarPositionChanged(tb);
2097 #endif
2098 }
2099 
2100 /*!
2101     \internal
2102     For internal use of Q3DockWindow only.
2103  */
2104 
dockingArea(const QPoint & p)2105 Q3DockArea *Q3MainWindow::dockingArea(const QPoint &p)
2106 {
2107     Q_D(Q3MainWindow);
2108     int mh = d->mb ? d->mb->height() : 0;
2109     int sh = d->sb ? d->sb->height() : 0;
2110     if (p.x() >= -5 && p.x() <= 100 && p.y() > mh && p.y() - height() - sh)
2111         return d->leftDock;
2112     if (p.x() >= width() - 100 && p.x() <= width() + 5 && p.y() > mh && p.y() - height() - sh)
2113         return d->rightDock;
2114     if (p.y() >= -5 && p.y() < mh + 100 && p.x() >= 0 && p.x() <= width())
2115         return d->topDock;
2116     if (p.y() >= height() - sh - 100 && p.y() <= height() + 5 && p.x() >= 0 && p.x() <= width())
2117         return d->bottomDock;
2118     return 0;
2119 }
2120 
2121 /*!
2122     Returns true if \a dw is a dock window known to the main window;
2123     otherwise returns false.
2124 */
2125 
hasDockWindow(Q3DockWindow * dw)2126 bool Q3MainWindow::hasDockWindow(Q3DockWindow *dw)
2127 {
2128     return d_func()->dockWindows.contains(dw);
2129 }
2130 
2131 /*!
2132     Returns the \c Left dock area
2133 
2134     \sa rightDock() topDock() bottomDock()
2135 */
2136 
leftDock() const2137 Q3DockArea *Q3MainWindow::leftDock() const
2138 {
2139     return d_func()->leftDock;
2140 }
2141 
2142 /*!
2143     Returns the \c Right dock area
2144 
2145     \sa leftDock() topDock() bottomDock()
2146 */
2147 
rightDock() const2148 Q3DockArea *Q3MainWindow::rightDock() const
2149 {
2150     return d_func()->rightDock;
2151 }
2152 
2153 /*!
2154     Returns the \c Top dock area
2155 
2156     \sa bottomDock() leftDock() rightDock()
2157 */
2158 
topDock() const2159 Q3DockArea *Q3MainWindow::topDock() const
2160 {
2161     return d_func()->topDock;
2162 }
2163 
2164 /*!
2165     Returns a pointer the \c Bottom dock area
2166 
2167     \sa topDock() leftDock() rightDock()
2168 */
2169 
bottomDock() const2170 Q3DockArea *Q3MainWindow::bottomDock() const
2171 {
2172     return d_func()->bottomDock;
2173 }
2174 
2175 /*!
2176     This function is called when the user clicks the Customize menu
2177     item on the dock window menu.
2178 
2179     The customize menu item will only appear if isCustomizable()
2180     returns true (it returns false by default).
2181 
2182     The function is intended, for example, to provide the user with a
2183     means of telling the application that they wish to customize the
2184     main window, dock windows or dock areas.
2185 
2186     The default implementation does nothing and the Customize menu
2187     item is not shown on the right-click menu by default. If you want
2188     the item to appear then reimplement isCustomizable() to return
2189     true, and reimplement this function to do whatever you want.
2190 
2191     \sa isCustomizable()
2192 */
2193 
customize()2194 void Q3MainWindow::customize()
2195 {
2196 }
2197 
2198 /*!
2199     Returns true if the dock area dock window menu includes the
2200     Customize menu item (which calls customize() when clicked).
2201     Returns false by default, i.e. the popup menu will not contain a
2202     Customize menu item. You will need to reimplement this function
2203     and set it to return true if you wish the user to be able to see
2204     the dock window menu.
2205 
2206     \sa customize()
2207 */
2208 
isCustomizable() const2209 bool Q3MainWindow::isCustomizable() const
2210 {
2211     return false;
2212 }
2213 
2214 /*!
2215     Returns true if it is appropriate to include a menu item for the
2216     \a dw dock window in the dock window menu; otherwise returns
2217     false.
2218 
2219     The user is able to change the state (show or hide) a dock window
2220     that has a menu item by clicking the item.
2221 
2222     Call setAppropriate() to indicate whether or not a particular dock
2223     window should appear on the popup menu.
2224 
2225     \sa setAppropriate()
2226 */
2227 
appropriate(Q3DockWindow * dw) const2228 bool Q3MainWindow::appropriate(Q3DockWindow *dw) const
2229 {
2230     Q_D(const Q3MainWindow);
2231     QMap<Q3DockWindow*, bool>::ConstIterator it = d->appropriate.find(dw);
2232     if (it == d->appropriate.end())
2233         return true;
2234     return *it;
2235 }
2236 
2237 /*!
2238     Use this function to control whether or not the \a dw dock
2239     window's caption should appear as a menu item on the dock window
2240     menu that lists the dock windows.
2241 
2242     If \a a is true then the \a dw will appear as a menu item on the
2243     dock window menu. The user is able to change the state (show or
2244     hide) a dock window that has a menu item by clicking the item;
2245     depending on the state of your application, this may or may not be
2246     appropriate. If \a a is false the \a dw will not appear on the
2247     popup menu.
2248 
2249     \sa showDockMenu() isCustomizable() customize()
2250 */
2251 
setAppropriate(Q3DockWindow * dw,bool a)2252 void Q3MainWindow::setAppropriate(Q3DockWindow *dw, bool a)
2253 {
2254     d_func()->appropriate.insert(dw, a);
2255 }
2256 
2257 #ifndef QT_NO_TEXTSTREAM
saveDockArea(QTextStream & ts,Q3DockArea * a)2258 static void saveDockArea(QTextStream &ts, Q3DockArea *a)
2259 {
2260     QList<Q3DockWindow *> l = a->dockWindowList();
2261     for (int i = 0; i < l.size(); ++i) {
2262         Q3DockWindow *dw = l.at(i);
2263         ts << QString(dw->windowTitle());
2264         ts << ',';
2265     }
2266     ts << endl;
2267     ts << *a;
2268 }
2269 
2270 /*!
2271     \relates Q3MainWindow
2272 
2273     Writes the layout (sizes and positions) of the dock windows in the
2274     dock areas of the Q3MainWindow \a mainWindow, including \c
2275     Minimized and \c TornOff dock windows, to the text stream \a ts.
2276 
2277     This can be used, for example, in conjunction with QSettings to
2278     save the user's layout when the \a mainWindow receives a
2279     close event.
2280 
2281     \sa QWidget::closeEvent()
2282 */
2283 
operator <<(QTextStream & ts,const Q3MainWindow & mainWindow)2284 QTextStream &operator<<(QTextStream &ts, const Q3MainWindow &mainWindow)
2285 {
2286     QList<Q3DockWindow *> l = mainWindow.dockWindows(Qt::DockMinimized);
2287     for (int i = 0; i < l.size(); ++i) {
2288         Q3DockWindow *dw = l.at(i);
2289         ts << dw->windowTitle();
2290         ts << ',';
2291     }
2292     ts << endl;
2293 
2294     l = mainWindow.dockWindows(Qt::DockTornOff);
2295     for (int i = 0; i < l.size(); ++i) {
2296         Q3DockWindow *dw = l.at(i);
2297         ts << dw->windowTitle();
2298         ts << ',';
2299     }
2300     ts << endl;
2301     for (int i = 0; i < l.size(); ++i) {
2302         Q3DockWindow *dw = l.at(i);
2303         ts << '[' << dw->windowTitle() << ','
2304            << (int)dw->geometry().x() << ','
2305            << (int)dw->geometry().y() << ','
2306            << (int)dw->geometry().width() << ','
2307            << (int)dw->geometry().height() << ','
2308            << (int)dw->isVisible() << ']';
2309     }
2310     ts << endl;
2311 
2312     saveDockArea(ts, mainWindow.topDock());
2313     saveDockArea(ts, mainWindow.bottomDock());
2314     saveDockArea(ts, mainWindow.rightDock());
2315     saveDockArea(ts, mainWindow.leftDock());
2316     return ts;
2317 }
2318 
loadDockArea(const QStringList & names,Q3DockArea * a,Qt::Dock dl,QList<Q3DockWindow * > & l,Q3MainWindow * mw,QTextStream & ts)2319 static void loadDockArea(const QStringList &names, Q3DockArea *a, Qt::Dock dl, QList<Q3DockWindow *> &l, Q3MainWindow *mw, QTextStream &ts)
2320 {
2321     for (QStringList::ConstIterator it = names.begin(); it != names.end(); ++it) {
2322         for (int i = 0; i < l.size(); ++i) {
2323             Q3DockWindow *dw = l.at(i);
2324             if (dw->windowTitle() == *it) {
2325                 mw->addDockWindow(dw, dl);
2326                 break;
2327             }
2328         }
2329     }
2330     if (a) {
2331         ts >> *a;
2332     } else if (dl == Qt::DockTornOff) {
2333         QString s = ts.readLine();
2334         enum State { Pre, Name, X, Y, Width, Height, Visible, Post };
2335         int state = Pre;
2336         QString name, x, y, w, h, visible;
2337         QChar c;
2338         for (int i = 0; i < (int)s.length(); ++i) {
2339             c = s[i];
2340             if (state == Pre && c == QLatin1Char('[')) {
2341                 state++;
2342                 continue;
2343             }
2344             if (c == QLatin1Char(',') &&
2345                  (state == Name || state == X || state == Y || state == Width || state == Height)) {
2346                 state++;
2347                 continue;
2348             }
2349             if (state == Visible && c == QLatin1Char(']')) {
2350                 for (int i = 0; i < l.size(); ++i) {
2351                     Q3DockWindow *dw = l.at(i);
2352                     if (QString(dw->windowTitle()) == name) {
2353                         if (!qobject_cast<Q3ToolBar*>(dw))
2354                             dw->setGeometry(x.toInt(), y.toInt(), w.toInt(), h.toInt());
2355                         else
2356                             dw->setGeometry(x.toInt(), y.toInt(), dw->width(), dw->height());
2357                         if (!(bool)visible.toInt())
2358                             dw->hide();
2359                         else
2360                             dw->show();
2361                         break;
2362                     }
2363                 }
2364 
2365                 name = x = y = w = h = visible = QLatin1String("");
2366 
2367                 state = Pre;
2368                 continue;
2369             }
2370             if (state == Name)
2371                 name += c;
2372             else if (state == X)
2373                 x += c;
2374             else if (state == Y)
2375                 y += c;
2376             else if (state == Width)
2377                 w += c;
2378             else if (state == Height)
2379                 h += c;
2380             else if (state == Visible)
2381                 visible += c;
2382         }
2383     }
2384 }
2385 
2386 /*!
2387     \relates Q3MainWindow
2388 
2389     Reads the layout (sizes and positions) of the dock windows in the
2390     dock areas of the Q3MainWindow \a mainWindow from the text stream,
2391     \a ts, including \c Minimized and \c TornOff dock windows.
2392     Restores the dock windows and dock areas to these sizes and
2393     positions. The layout information must be in the format produced
2394     by operator<<().
2395 
2396     This can be used, for example, in conjunction with QSettings to
2397     restore the user's layout.
2398 */
2399 
operator >>(QTextStream & ts,Q3MainWindow & mainWindow)2400 QTextStream &operator>>(QTextStream &ts, Q3MainWindow &mainWindow)
2401 {
2402     QList<Q3DockWindow *> l = mainWindow.dockWindows();
2403 
2404     QString s = ts.readLine();
2405     QStringList names = s.split(QLatin1Char(','));
2406     loadDockArea(names, 0, Qt::DockMinimized, l, &mainWindow, ts);
2407 
2408     s = ts.readLine();
2409     names = s.split(QLatin1Char(','));
2410     loadDockArea(names, 0, Qt::DockTornOff, l, &mainWindow, ts);
2411 
2412     int i = 0;
2413     Q3DockArea *areas[] = { mainWindow.topDock(), mainWindow.bottomDock(), mainWindow.rightDock(), mainWindow.leftDock() };
2414     for (int dl = (int)Qt::DockTop; dl != (int)Qt::DockMinimized; ++dl, ++i) {
2415         s = ts.readLine();
2416         names = s.split(QLatin1Char(','));
2417         loadDockArea(names, areas[i], (Qt::Dock)dl, l, &mainWindow, ts);
2418     }
2419     return ts;
2420 }
2421 #endif
2422 
2423 QT_END_NAMESPACE
2424 
2425 #include "q3mainwindow.moc"
2426 
2427 #endif
2428