1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtWidgets 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 https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://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 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 //#define QT_EXPERIMENTAL_CLIENT_DECORATIONS
41 
42 #include "qmainwindow.h"
43 #include "qmainwindowlayout_p.h"
44 
45 #if QT_CONFIG(dockwidget)
46 #include "qdockwidget.h"
47 #endif
48 #if QT_CONFIG(toolbar)
49 #include "qtoolbar.h"
50 #endif
51 
52 #include <qapplication.h>
53 #include <qmenu.h>
54 #if QT_CONFIG(menubar)
55 #include <qmenubar.h>
56 #endif
57 #if QT_CONFIG(statusbar)
58 #include <qstatusbar.h>
59 #endif
60 #include <qevent.h>
61 #include <qstyle.h>
62 #include <qdebug.h>
63 #include <qpainter.h>
64 
65 #include <private/qwidget_p.h>
66 #if QT_CONFIG(toolbar)
67 #include "qtoolbar_p.h"
68 #endif
69 #include "qwidgetanimator_p.h"
70 #ifdef Q_OS_MACOS
71 #include <qpa/qplatformnativeinterface.h>
72 #endif
73 
74 QT_BEGIN_NAMESPACE
75 
76 class QMainWindowPrivate : public QWidgetPrivate
77 {
78     Q_DECLARE_PUBLIC(QMainWindow)
79 public:
QMainWindowPrivate()80     inline QMainWindowPrivate()
81         : layout(nullptr), explicitIconSize(false), toolButtonStyle(Qt::ToolButtonIconOnly)
82 #ifdef Q_OS_MACOS
83             , useUnifiedToolBar(false)
84 #endif
85     { }
86     QMainWindowLayout *layout;
87     QSize iconSize;
88     bool explicitIconSize;
89     Qt::ToolButtonStyle toolButtonStyle;
90 #ifdef Q_OS_MACOS
91     bool useUnifiedToolBar;
92 #endif
93     void init();
94 
mainWindowLayout(const QMainWindow * mainWindow)95     static inline QMainWindowLayout *mainWindowLayout(const QMainWindow *mainWindow)
96     {
97         return mainWindow ? mainWindow->d_func()->layout : static_cast<QMainWindowLayout *>(nullptr);
98     }
99 };
100 
qt_mainwindow_layout(const QMainWindow * mainWindow)101 QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *mainWindow)
102 {
103     return QMainWindowPrivate::mainWindowLayout(mainWindow);
104 }
105 
106 #ifdef QT_EXPERIMENTAL_CLIENT_DECORATIONS
qt_setMainWindowTitleWidget(QMainWindow * mainWindow,Qt::DockWidgetArea area,QWidget * widget)107 Q_WIDGETS_EXPORT void qt_setMainWindowTitleWidget(QMainWindow *mainWindow, Qt::DockWidgetArea area, QWidget *widget)
108 {
109     QGridLayout *topLayout = qobject_cast<QGridLayout *>(mainWindow->layout());
110     Q_ASSERT(topLayout);
111 
112     int row = 0;
113     int column = 0;
114 
115     switch (area) {
116     case Qt::LeftDockWidgetArea:
117         row = 1;
118         column = 0;
119         break;
120     case Qt::TopDockWidgetArea:
121         row = 0;
122         column = 1;
123         break;
124     case Qt::BottomDockWidgetArea:
125         row = 2;
126         column = 1;
127         break;
128     case Qt::RightDockWidgetArea:
129         row = 1;
130         column = 2;
131         break;
132     default:
133         Q_ASSERT_X(false, "qt_setMainWindowTitleWidget", "Unknown area");
134         return;
135     }
136 
137     if (QLayoutItem *oldItem = topLayout->itemAtPosition(row, column))
138         delete oldItem->widget();
139     topLayout->addWidget(widget, row, column);
140 }
141 #endif
142 
init()143 void QMainWindowPrivate::init()
144 {
145     Q_Q(QMainWindow);
146 
147 #ifdef QT_EXPERIMENTAL_CLIENT_DECORATIONS
148     QGridLayout *topLayout = new QGridLayout(q);
149     topLayout->setContentsMargins(0, 0, 0, 0);
150 
151     layout = new QMainWindowLayout(q, topLayout);
152 
153     topLayout->addItem(layout, 1, 1);
154 #else
155     layout = new QMainWindowLayout(q, nullptr);
156 #endif
157 
158     const int metric = q->style()->pixelMetric(QStyle::PM_ToolBarIconSize, nullptr, q);
159     iconSize = QSize(metric, metric);
160     q->setAttribute(Qt::WA_Hover);
161 }
162 
163 /*
164     The Main Window:
165 
166     +----------------------------------------------------------+
167     | Menu Bar                                                 |
168     +----------------------------------------------------------+
169     | Tool Bar Area                                            |
170     |   +--------------------------------------------------+   |
171     |   | Dock Window Area                                 |   |
172     |   |   +------------------------------------------+   |   |
173     |   |   |                                          |   |   |
174     |   |   | Central Widget                           |   |   |
175     |   |   |                                          |   |   |
176     |   |   |                                          |   |   |
177     |   |   |                                          |   |   |
178     |   |   |                                          |   |   |
179     |   |   |                                          |   |   |
180     |   |   |                                          |   |   |
181     |   |   |                                          |   |   |
182     |   |   |                                          |   |   |
183     |   |   |                                          |   |   |
184     |   |   |                                          |   |   |
185     |   |   +------------------------------------------+   |   |
186     |   |                                                  |   |
187     |   +--------------------------------------------------+   |
188     |                                                          |
189     +----------------------------------------------------------+
190     | Status Bar                                               |
191     +----------------------------------------------------------+
192 
193 */
194 
195 /*!
196     \class QMainWindow
197     \brief The QMainWindow class provides a main application
198            window.
199     \ingroup mainwindow-classes
200     \inmodule QtWidgets
201 
202     \tableofcontents
203 
204     \section1 Qt Main Window Framework
205 
206     A main window provides a framework for building an
207     application's user interface. Qt has QMainWindow and its \l{Main
208     Window and Related Classes}{related classes} for main window
209     management. QMainWindow has its own layout to which you can add
210     \l{QToolBar}s, \l{QDockWidget}s, a
211     QMenuBar, and a QStatusBar. The layout has a center area that can
212     be occupied by any kind of widget. You can see an image of the
213     layout below.
214 
215     \image mainwindowlayout.png
216 
217     \note Creating a main window without a central widget is not supported.
218     You must have a central widget even if it is just a placeholder.
219 
220     \section1 Creating Main Window Components
221 
222     A central widget will typically be a standard Qt widget such
223     as a QTextEdit or a QGraphicsView. Custom widgets can also be
224     used for advanced applications. You set the central widget with \c
225     setCentralWidget().
226 
227     Main windows have either a single (SDI) or multiple (MDI)
228     document interface. You create MDI applications in Qt by using a
229     QMdiArea as the central widget.
230 
231     We will now examine each of the other widgets that can be
232     added to a main window. We give examples on how to create and add
233     them.
234 
235     \section2 Creating Menus
236 
237     Qt implements menus in QMenu and QMainWindow keeps them in a
238     QMenuBar. \l{QAction}{QAction}s are added to the menus, which
239     display them as menu items.
240 
241     You can add new menus to the main window's menu bar by calling
242     \c menuBar(), which returns the QMenuBar for the window, and then
243     add a menu with QMenuBar::addMenu().
244 
245     QMainWindow comes with a default menu bar, but you can also
246     set one yourself with \c setMenuBar(). If you wish to implement a
247     custom menu bar (i.e., not use the QMenuBar widget), you can set it
248     with \c setMenuWidget().
249 
250     An example of how to create menus follows:
251 
252     \snippet code/src_widgets_widgets_qmainwindow.cpp 0
253 
254     The \c createPopupMenu() function creates popup menus when the
255     main window receives context menu events.  The default
256     implementation generates a menu with the checkable actions from
257     the dock widgets and toolbars. You can reimplement \c
258     createPopupMenu() for a custom menu.
259 
260     \section2 Creating Toolbars
261 
262     Toolbars are implemented in the QToolBar class.  You add a
263     toolbar to a main window with \c addToolBar().
264 
265     You control the initial position of toolbars by assigning them
266     to a specific Qt::ToolBarArea. You can split an area by inserting
267     a toolbar break - think of this as a line break in text editing -
268     with \c addToolBarBreak() or \c insertToolBarBreak(). You can also
269     restrict placement by the user with QToolBar::setAllowedAreas()
270     and QToolBar::setMovable().
271 
272     The size of toolbar icons can be retrieved with \c iconSize().
273     The sizes are platform dependent; you can set a fixed size with \c
274     setIconSize(). You can alter the appearance of all tool buttons in
275     the toolbars with \c setToolButtonStyle().
276 
277     An example of toolbar creation follows:
278 
279     \snippet code/src_widgets_widgets_qmainwindow.cpp 1
280 
281     \section2 Creating Dock Widgets
282 
283     Dock widgets are implemented in the QDockWidget class. A dock
284     widget is a window that can be docked into the main window.  You
285     add dock widgets to a main window with \c addDockWidget().
286 
287     There are four dock widget areas as given by the
288     Qt::DockWidgetArea enum: left, right, top, and bottom. You can
289     specify which dock widget area that should occupy the corners
290     where the areas overlap with \c setCorner(). By default
291     each area can only contain one row (vertical or horizontal) of
292     dock widgets, but if you enable nesting with \c
293     setDockNestingEnabled(), dock widgets can be added in either
294     direction.
295 
296     Two dock widgets may also be stacked on top of each other. A
297     QTabBar is then used to select which of the widgets should be
298     displayed.
299 
300     We give an example of how to create and add dock widgets to a
301     main window:
302 
303     \snippet mainwindowsnippet.cpp 0
304 
305     \section2 The Status Bar
306 
307     You can set a status bar with \c setStatusBar(), but one is
308     created the first time \c statusBar() (which returns the main
309     window's status bar) is called. See QStatusBar for information on
310     how to use it.
311 
312     \section1 Storing State
313 
314     QMainWindow can store the state of its layout with \c
315     saveState(); it can later be retrieved with \c restoreState(). It
316     is the position and size (relative to the size of the main window)
317     of the toolbars and dock widgets that are stored.
318 
319     \sa QMenuBar, QToolBar, QStatusBar, QDockWidget, {Application
320     Example}, {Dock Widgets Example}, {MDI Example}, {SDI Example},
321     {Menus Example}
322 */
323 
324 /*!
325     \fn void QMainWindow::iconSizeChanged(const QSize &iconSize)
326 
327     This signal is emitted when the size of the icons used in the
328     window is changed. The new icon size is passed in \a iconSize.
329 
330     You can connect this signal to other components to help maintain
331     a consistent appearance for your application.
332 
333     \sa setIconSize()
334 */
335 
336 /*!
337     \fn void QMainWindow::toolButtonStyleChanged(Qt::ToolButtonStyle toolButtonStyle)
338 
339     This signal is emitted when the style used for tool buttons in the
340     window is changed. The new style is passed in \a toolButtonStyle.
341 
342     You can connect this signal to other components to help maintain
343     a consistent appearance for your application.
344 
345     \sa setToolButtonStyle()
346 */
347 
348 #if QT_CONFIG(dockwidget)
349 /*!
350     \fn void QMainWindow::tabifiedDockWidgetActivated(QDockWidget *dockWidget)
351 
352     This signal is emitted when the tabified dock widget is activated by
353     selecting the tab. The activated dock widget is passed in \a dockWidget.
354 
355     \since 5.8
356     \sa tabifyDockWidget(), tabifiedDockWidgets()
357 */
358 #endif
359 
360 /*!
361     Constructs a QMainWindow with the given \a parent and the specified
362     widget \a flags.
363 
364     QMainWindow sets the Qt::Window flag itself, and will hence
365     always be created as a top-level widget.
366  */
QMainWindow(QWidget * parent,Qt::WindowFlags flags)367 QMainWindow::QMainWindow(QWidget *parent, Qt::WindowFlags flags)
368     : QWidget(*(new QMainWindowPrivate()), parent, flags | Qt::Window)
369 {
370     d_func()->init();
371 }
372 
373 
374 /*!
375     Destroys the main window.
376  */
~QMainWindow()377 QMainWindow::~QMainWindow()
378 { }
379 
380 /*! \property QMainWindow::iconSize
381     \brief size of toolbar icons in this mainwindow.
382 
383     The default is the default tool bar icon size of the GUI style.
384     Note that the icons used must be at least of this size as the
385     icons are only scaled down.
386 */
387 
388 /*!
389     \property QMainWindow::dockOptions
390     \brief the docking behavior of QMainWindow
391     \since 4.3
392 
393     The default value is AnimatedDocks | AllowTabbedDocks.
394 */
395 
396 /*!
397     \enum QMainWindow::DockOption
398     \since 4.3
399 
400     This enum contains flags that specify the docking behavior of QMainWindow.
401 
402     \value AnimatedDocks    Identical to the \l animated property.
403 
404     \value AllowNestedDocks Identical to the \l dockNestingEnabled property.
405 
406     \value AllowTabbedDocks The user can drop one dock widget "on top" of
407                             another. The two widgets are stacked and a tab
408                             bar appears for selecting which one is visible.
409 
410     \value ForceTabbedDocks Each dock area contains a single stack of tabbed
411                             dock widgets. In other words, dock widgets cannot
412                             be placed next to each other in a dock area. If
413                             this option is set, AllowNestedDocks has no effect.
414 
415     \value VerticalTabs     The two vertical dock areas on the sides of the
416                             main window show their tabs vertically. If this
417                             option is not set, all dock areas show their tabs
418                             at the bottom. Implies AllowTabbedDocks. See also
419                             \l setTabPosition().
420 
421     \value GroupedDragging  When dragging the titlebar of a dock, all the tabs
422                             that are tabbed with it are going to be dragged.
423                             Implies AllowTabbedDocks. Does not work well if
424                             some QDockWidgets have restrictions in which area
425                             they are allowed. (This enum value was added in Qt
426                             5.6.)
427 
428     These options only control how dock widgets may be dropped in a QMainWindow.
429     They do not re-arrange the dock widgets to conform with the specified
430     options. For this reason they should be set before any dock widgets
431     are added to the main window. Exceptions to this are the AnimatedDocks and
432     VerticalTabs options, which may be set at any time.
433 */
434 
setDockOptions(DockOptions opt)435 void QMainWindow::setDockOptions(DockOptions opt)
436 {
437     Q_D(QMainWindow);
438     d->layout->setDockOptions(opt);
439 }
440 
dockOptions() const441 QMainWindow::DockOptions QMainWindow::dockOptions() const
442 {
443     Q_D(const QMainWindow);
444     return d->layout->dockOptions;
445 }
446 
iconSize() const447 QSize QMainWindow::iconSize() const
448 { return d_func()->iconSize; }
449 
setIconSize(const QSize & iconSize)450 void QMainWindow::setIconSize(const QSize &iconSize)
451 {
452     Q_D(QMainWindow);
453     QSize sz = iconSize;
454     if (!sz.isValid()) {
455         const int metric = style()->pixelMetric(QStyle::PM_ToolBarIconSize, nullptr, this);
456         sz = QSize(metric, metric);
457     }
458     if (d->iconSize != sz) {
459         d->iconSize = sz;
460         emit iconSizeChanged(d->iconSize);
461     }
462     d->explicitIconSize = iconSize.isValid();
463 }
464 
465 /*! \property QMainWindow::toolButtonStyle
466     \brief style of toolbar buttons in this mainwindow.
467 
468     To have the style of toolbuttons follow the system settings, set this property to Qt::ToolButtonFollowStyle.
469     On Unix, the user settings from the desktop environment will be used.
470     On other platforms, Qt::ToolButtonFollowStyle means icon only.
471 
472     The default is Qt::ToolButtonIconOnly.
473 */
474 
toolButtonStyle() const475 Qt::ToolButtonStyle QMainWindow::toolButtonStyle() const
476 { return d_func()->toolButtonStyle; }
477 
setToolButtonStyle(Qt::ToolButtonStyle toolButtonStyle)478 void QMainWindow::setToolButtonStyle(Qt::ToolButtonStyle toolButtonStyle)
479 {
480     Q_D(QMainWindow);
481     if (d->toolButtonStyle == toolButtonStyle)
482         return;
483     d->toolButtonStyle = toolButtonStyle;
484     emit toolButtonStyleChanged(d->toolButtonStyle);
485 }
486 
487 #if QT_CONFIG(menubar)
488 /*!
489     Returns the menu bar for the main window. This function creates
490     and returns an empty menu bar if the menu bar does not exist.
491 
492     If you want all windows in a Mac application to share one menu
493     bar, don't use this function to create it, because the menu bar
494     created here will have this QMainWindow as its parent.  Instead,
495     you must create a menu bar that does not have a parent, which you
496     can then share among all the Mac windows. Create a parent-less
497     menu bar this way:
498 
499     \snippet code/src_gui_widgets_qmenubar.cpp 1
500 
501     \sa setMenuBar()
502 */
menuBar() const503 QMenuBar *QMainWindow::menuBar() const
504 {
505     QMenuBar *menuBar = qobject_cast<QMenuBar *>(layout()->menuBar());
506     if (!menuBar) {
507         QMainWindow *self = const_cast<QMainWindow *>(this);
508         menuBar = new QMenuBar(self);
509         self->setMenuBar(menuBar);
510     }
511     return menuBar;
512 }
513 
514 /*!
515     Sets the menu bar for the main window to \a menuBar.
516 
517     Note: QMainWindow takes ownership of the \a menuBar pointer and
518     deletes it at the appropriate time.
519 
520     \sa menuBar()
521 */
setMenuBar(QMenuBar * menuBar)522 void QMainWindow::setMenuBar(QMenuBar *menuBar)
523 {
524     QLayout *topLayout = layout();
525 
526     if (topLayout->menuBar() && topLayout->menuBar() != menuBar) {
527         // Reparent corner widgets before we delete the old menu bar.
528         QMenuBar *oldMenuBar = qobject_cast<QMenuBar *>(topLayout->menuBar());
529         if (menuBar) {
530             // TopLeftCorner widget.
531             QWidget *cornerWidget = oldMenuBar->cornerWidget(Qt::TopLeftCorner);
532             if (cornerWidget)
533                 menuBar->setCornerWidget(cornerWidget, Qt::TopLeftCorner);
534             // TopRightCorner widget.
535             cornerWidget = oldMenuBar->cornerWidget(Qt::TopRightCorner);
536             if (cornerWidget)
537                 menuBar->setCornerWidget(cornerWidget, Qt::TopRightCorner);
538         }
539         oldMenuBar->hide();
540         oldMenuBar->setParent(nullptr);
541         oldMenuBar->deleteLater();
542     }
543     topLayout->setMenuBar(menuBar);
544 }
545 
546 /*!
547     \since 4.2
548 
549     Returns the menu bar for the main window. This function returns
550     null if a menu bar hasn't been constructed yet.
551 */
menuWidget() const552 QWidget *QMainWindow::menuWidget() const
553 {
554     QWidget *menuBar = d_func()->layout->menuBar();
555     return menuBar;
556 }
557 
558 /*!
559     \since 4.2
560 
561     Sets the menu bar for the main window to \a menuBar.
562 
563     QMainWindow takes ownership of the \a menuBar pointer and
564     deletes it at the appropriate time.
565 */
setMenuWidget(QWidget * menuBar)566 void QMainWindow::setMenuWidget(QWidget *menuBar)
567 {
568     Q_D(QMainWindow);
569     if (d->layout->menuBar() && d->layout->menuBar() != menuBar) {
570         d->layout->menuBar()->hide();
571         d->layout->menuBar()->deleteLater();
572     }
573     d->layout->setMenuBar(menuBar);
574 }
575 #endif // QT_CONFIG(menubar)
576 
577 #if QT_CONFIG(statusbar)
578 /*!
579     Returns the status bar for the main window. This function creates
580     and returns an empty status bar if the status bar does not exist.
581 
582     \sa setStatusBar()
583 */
statusBar() const584 QStatusBar *QMainWindow::statusBar() const
585 {
586     QStatusBar *statusbar = d_func()->layout->statusBar();
587     if (!statusbar) {
588         QMainWindow *self = const_cast<QMainWindow *>(this);
589         statusbar = new QStatusBar(self);
590         statusbar->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
591         self->setStatusBar(statusbar);
592     }
593     return statusbar;
594 }
595 
596 /*!
597     Sets the status bar for the main window to \a statusbar.
598 
599     Setting the status bar to \nullptr will remove it from the main window.
600     Note that QMainWindow takes ownership of the \a statusbar pointer
601     and deletes it at the appropriate time.
602 
603     \sa statusBar()
604 */
setStatusBar(QStatusBar * statusbar)605 void QMainWindow::setStatusBar(QStatusBar *statusbar)
606 {
607     Q_D(QMainWindow);
608     if (d->layout->statusBar() && d->layout->statusBar() != statusbar) {
609         d->layout->statusBar()->hide();
610         d->layout->statusBar()->deleteLater();
611     }
612     d->layout->setStatusBar(statusbar);
613 }
614 #endif // QT_CONFIG(statusbar)
615 
616 /*!
617     Returns the central widget for the main window. This function
618     returns zero if the central widget has not been set.
619 
620     \sa setCentralWidget()
621 */
centralWidget() const622 QWidget *QMainWindow::centralWidget() const
623 { return d_func()->layout->centralWidget(); }
624 
625 /*!
626     Sets the given \a widget to be the main window's central widget.
627 
628     Note: QMainWindow takes ownership of the \a widget pointer and
629     deletes it at the appropriate time.
630 
631     \sa centralWidget()
632 */
setCentralWidget(QWidget * widget)633 void QMainWindow::setCentralWidget(QWidget *widget)
634 {
635     Q_D(QMainWindow);
636     if (d->layout->centralWidget() && d->layout->centralWidget() != widget) {
637         d->layout->centralWidget()->hide();
638         d->layout->centralWidget()->deleteLater();
639     }
640     d->layout->setCentralWidget(widget);
641 }
642 
643 /*!
644     Removes the central widget from this main window.
645 
646     The ownership of the removed widget is passed to the caller.
647 
648     \since 5.2
649 */
takeCentralWidget()650 QWidget *QMainWindow::takeCentralWidget()
651 {
652     Q_D(QMainWindow);
653     QWidget *oldcentralwidget = d->layout->centralWidget();
654     if (oldcentralwidget) {
655         oldcentralwidget->setParent(nullptr);
656         d->layout->setCentralWidget(nullptr);
657     }
658     return oldcentralwidget;
659 }
660 
661 #if QT_CONFIG(dockwidget)
662 /*!
663     Sets the given dock widget \a area to occupy the specified \a
664     corner.
665 
666     \sa corner()
667 */
setCorner(Qt::Corner corner,Qt::DockWidgetArea area)668 void QMainWindow::setCorner(Qt::Corner corner, Qt::DockWidgetArea area)
669 {
670     bool valid = false;
671     switch (corner) {
672     case Qt::TopLeftCorner:
673         valid = (area == Qt::TopDockWidgetArea || area == Qt::LeftDockWidgetArea);
674         break;
675     case Qt::TopRightCorner:
676         valid = (area == Qt::TopDockWidgetArea || area == Qt::RightDockWidgetArea);
677         break;
678     case Qt::BottomLeftCorner:
679         valid = (area == Qt::BottomDockWidgetArea || area == Qt::LeftDockWidgetArea);
680         break;
681     case Qt::BottomRightCorner:
682         valid = (area == Qt::BottomDockWidgetArea || area == Qt::RightDockWidgetArea);
683         break;
684     }
685     if (Q_UNLIKELY(!valid))
686         qWarning("QMainWindow::setCorner(): 'area' is not valid for 'corner'");
687     else
688         d_func()->layout->setCorner(corner, area);
689 }
690 
691 /*!
692     Returns the dock widget area that occupies the specified \a
693     corner.
694 
695     \sa setCorner()
696 */
corner(Qt::Corner corner) const697 Qt::DockWidgetArea QMainWindow::corner(Qt::Corner corner) const
698 { return d_func()->layout->corner(corner); }
699 #endif
700 
701 #if QT_CONFIG(toolbar)
702 
checkToolBarArea(Qt::ToolBarArea area,const char * where)703 static bool checkToolBarArea(Qt::ToolBarArea area, const char *where)
704 {
705     switch (area) {
706     case Qt::LeftToolBarArea:
707     case Qt::RightToolBarArea:
708     case Qt::TopToolBarArea:
709     case Qt::BottomToolBarArea:
710         return true;
711     default:
712         break;
713     }
714     qWarning("%s: invalid 'area' argument", where);
715     return false;
716 }
717 
718 /*!
719     Adds a toolbar break to the given \a area after all the other
720     objects that are present.
721 */
addToolBarBreak(Qt::ToolBarArea area)722 void QMainWindow::addToolBarBreak(Qt::ToolBarArea area)
723 {
724     if (!checkToolBarArea(area, "QMainWindow::addToolBarBreak"))
725         return;
726     d_func()->layout->addToolBarBreak(area);
727 }
728 
729 /*!
730     Inserts a toolbar break before the toolbar specified by \a before.
731 */
insertToolBarBreak(QToolBar * before)732 void QMainWindow::insertToolBarBreak(QToolBar *before)
733 { d_func()->layout->insertToolBarBreak(before); }
734 
735 /*!
736     Removes a toolbar break previously inserted before the toolbar specified by \a before.
737 */
738 
removeToolBarBreak(QToolBar * before)739 void QMainWindow::removeToolBarBreak(QToolBar *before)
740 {
741     Q_D(QMainWindow);
742     d->layout->removeToolBarBreak(before);
743 }
744 
745 /*!
746     Adds the \a toolbar into the specified \a area in this main
747     window. The \a toolbar is placed at the end of the current tool
748     bar block (i.e. line). If the main window already manages \a toolbar
749     then it will only move the toolbar to \a area.
750 
751     \sa insertToolBar(), addToolBarBreak(), insertToolBarBreak()
752 */
addToolBar(Qt::ToolBarArea area,QToolBar * toolbar)753 void QMainWindow::addToolBar(Qt::ToolBarArea area, QToolBar *toolbar)
754 {
755     if (!checkToolBarArea(area, "QMainWindow::addToolBar"))
756         return;
757 
758     Q_D(QMainWindow);
759 
760     disconnect(this, SIGNAL(iconSizeChanged(QSize)),
761                toolbar, SLOT(_q_updateIconSize(QSize)));
762     disconnect(this, SIGNAL(toolButtonStyleChanged(Qt::ToolButtonStyle)),
763                toolbar, SLOT(_q_updateToolButtonStyle(Qt::ToolButtonStyle)));
764 
765     if(toolbar->d_func()->state && toolbar->d_func()->state->dragging) {
766         //removing a toolbar which is dragging will cause crash
767 #if QT_CONFIG(dockwidget)
768         bool animated = isAnimated();
769         setAnimated(false);
770 #endif
771         toolbar->d_func()->endDrag();
772 #if QT_CONFIG(dockwidget)
773         setAnimated(animated);
774 #endif
775     }
776 
777     d->layout->removeToolBar(toolbar);
778 
779     toolbar->d_func()->_q_updateIconSize(d->iconSize);
780     toolbar->d_func()->_q_updateToolButtonStyle(d->toolButtonStyle);
781     connect(this, SIGNAL(iconSizeChanged(QSize)),
782             toolbar, SLOT(_q_updateIconSize(QSize)));
783     connect(this, SIGNAL(toolButtonStyleChanged(Qt::ToolButtonStyle)),
784             toolbar, SLOT(_q_updateToolButtonStyle(Qt::ToolButtonStyle)));
785 
786     d->layout->addToolBar(area, toolbar);
787 }
788 
789 /*! \overload
790     Equivalent of calling addToolBar(Qt::TopToolBarArea, \a toolbar)
791 */
addToolBar(QToolBar * toolbar)792 void QMainWindow::addToolBar(QToolBar *toolbar)
793 { addToolBar(Qt::TopToolBarArea, toolbar); }
794 
795 /*!
796     \overload
797 
798     Creates a QToolBar object, setting its window title to \a title,
799     and inserts it into the top toolbar area.
800 
801     \sa setWindowTitle()
802 */
addToolBar(const QString & title)803 QToolBar *QMainWindow::addToolBar(const QString &title)
804 {
805     QToolBar *toolBar = new QToolBar(this);
806     toolBar->setWindowTitle(title);
807     addToolBar(toolBar);
808     return toolBar;
809 }
810 
811 /*!
812     Inserts the \a toolbar into the area occupied by the \a before toolbar
813     so that it appears before it. For example, in normal left-to-right
814     layout operation, this means that \a toolbar will appear to the left
815     of the toolbar specified by \a before in a horizontal toolbar area.
816 
817     \sa insertToolBarBreak(), addToolBar(), addToolBarBreak()
818 */
insertToolBar(QToolBar * before,QToolBar * toolbar)819 void QMainWindow::insertToolBar(QToolBar *before, QToolBar *toolbar)
820 {
821     Q_D(QMainWindow);
822 
823     d->layout->removeToolBar(toolbar);
824 
825     toolbar->d_func()->_q_updateIconSize(d->iconSize);
826     toolbar->d_func()->_q_updateToolButtonStyle(d->toolButtonStyle);
827     connect(this, SIGNAL(iconSizeChanged(QSize)),
828             toolbar, SLOT(_q_updateIconSize(QSize)));
829     connect(this, SIGNAL(toolButtonStyleChanged(Qt::ToolButtonStyle)),
830             toolbar, SLOT(_q_updateToolButtonStyle(Qt::ToolButtonStyle)));
831 
832     d->layout->insertToolBar(before, toolbar);
833 }
834 
835 /*!
836     Removes the \a toolbar from the main window layout and hides
837     it. Note that the \a toolbar is \e not deleted.
838 */
removeToolBar(QToolBar * toolbar)839 void QMainWindow::removeToolBar(QToolBar *toolbar)
840 {
841     if (toolbar) {
842         d_func()->layout->removeToolBar(toolbar);
843         toolbar->hide();
844     }
845 }
846 
847 /*!
848     Returns the Qt::ToolBarArea for \a toolbar. If \a toolbar has not
849     been added to the main window, this function returns \c
850     Qt::NoToolBarArea.
851 
852     \sa addToolBar(), addToolBarBreak(), Qt::ToolBarArea
853 */
toolBarArea(const QToolBar * toolbar) const854 Qt::ToolBarArea QMainWindow::toolBarArea(
855 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
856     const
857 #endif
858     QToolBar *toolbar) const
859 { return d_func()->layout->toolBarArea(toolbar); }
860 
861 /*!
862 
863     Returns whether there is a toolbar
864     break before the \a toolbar.
865 
866     \sa addToolBarBreak(), insertToolBarBreak()
867 */
toolBarBreak(QToolBar * toolbar) const868 bool QMainWindow::toolBarBreak(QToolBar *toolbar) const
869 {
870     return d_func()->layout->toolBarBreak(toolbar);
871 }
872 
873 #endif // QT_CONFIG(toolbar)
874 
875 #if QT_CONFIG(dockwidget)
876 
877 /*! \property QMainWindow::animated
878     \brief whether manipulating dock widgets and tool bars is animated
879     \since 4.2
880 
881     When a dock widget or tool bar is dragged over the
882     main window, the main window adjusts its contents
883     to indicate where the dock widget or tool bar will
884     be docked if it is dropped. Setting this property
885     causes QMainWindow to move its contents in a smooth
886     animation. Clearing this property causes the contents
887     to snap into their new positions.
888 
889     By default, this property is set. It may be cleared if
890     the main window contains widgets which are slow at resizing
891     or repainting themselves.
892 
893     Setting this property is identical to setting the AnimatedDocks
894     option using setDockOptions().
895 */
896 
isAnimated() const897 bool QMainWindow::isAnimated() const
898 {
899     Q_D(const QMainWindow);
900     return d->layout->dockOptions & AnimatedDocks;
901 }
902 
setAnimated(bool enabled)903 void QMainWindow::setAnimated(bool enabled)
904 {
905     Q_D(QMainWindow);
906 
907     DockOptions opts = d->layout->dockOptions;
908     opts.setFlag(AnimatedDocks, enabled);
909 
910     d->layout->setDockOptions(opts);
911 }
912 
913 /*! \property QMainWindow::dockNestingEnabled
914     \brief whether docks can be nested
915     \since 4.2
916 
917     If this property is \c false, dock areas can only contain a single row
918     (horizontal or vertical) of dock widgets. If this property is \c true,
919     the area occupied by a dock widget can be split in either direction to contain
920     more dock widgets.
921 
922     Dock nesting is only necessary in applications that contain a lot of
923     dock widgets. It gives the user greater freedom in organizing their
924     main window. However, dock nesting leads to more complex
925     (and less intuitive) behavior when a dock widget is dragged over the
926     main window, since there are more ways in which a dropped dock widget
927     may be placed in the dock area.
928 
929     Setting this property is identical to setting the AllowNestedDocks option
930     using setDockOptions().
931 */
932 
isDockNestingEnabled() const933 bool QMainWindow::isDockNestingEnabled() const
934 {
935     Q_D(const QMainWindow);
936     return d->layout->dockOptions & AllowNestedDocks;
937 }
938 
setDockNestingEnabled(bool enabled)939 void QMainWindow::setDockNestingEnabled(bool enabled)
940 {
941     Q_D(QMainWindow);
942 
943     DockOptions opts = d->layout->dockOptions;
944     opts.setFlag(AllowNestedDocks, enabled);
945 
946     d->layout->setDockOptions(opts);
947 }
948 
949 #if 0
950 // If added back in, add the '!' to the qdoc comment marker as well.
951 /*
952     \property QMainWindow::verticalTabsEnabled
953     \brief whether left and right dock areas use vertical tabs
954     \since 4.2
955 
956     If this property is set to false, dock areas containing tabbed dock widgets
957     display horizontal tabs, simmilar to Visual Studio.
958 
959     If this property is set to true, then the right and left dock areas display vertical
960     tabs, simmilar to KDevelop.
961 
962     This property should be set before any dock widgets are added to the main window.
963 */
964 
965 bool QMainWindow::verticalTabsEnabled() const
966 {
967     return d_func()->layout->verticalTabsEnabled();
968 }
969 
970 void QMainWindow::setVerticalTabsEnabled(bool enabled)
971 {
972     d_func()->layout->setVerticalTabsEnabled(enabled);
973 }
974 #endif
975 
checkDockWidgetArea(Qt::DockWidgetArea area,const char * where)976 static bool checkDockWidgetArea(Qt::DockWidgetArea area, const char *where)
977 {
978     switch (area) {
979     case Qt::LeftDockWidgetArea:
980     case Qt::RightDockWidgetArea:
981     case Qt::TopDockWidgetArea:
982     case Qt::BottomDockWidgetArea:
983         return true;
984     default:
985         break;
986     }
987     qWarning("%s: invalid 'area' argument", where);
988     return false;
989 }
990 
991 #if QT_CONFIG(tabbar)
992 /*!
993     \property QMainWindow::documentMode
994     \brief whether the tab bar for tabbed dockwidgets is set to document mode.
995     \since 4.5
996 
997     The default is false.
998 
999     \sa QTabBar::documentMode
1000 */
documentMode() const1001 bool QMainWindow::documentMode() const
1002 {
1003     return d_func()->layout->documentMode();
1004 }
1005 
setDocumentMode(bool enabled)1006 void QMainWindow::setDocumentMode(bool enabled)
1007 {
1008     d_func()->layout->setDocumentMode(enabled);
1009 }
1010 #endif // QT_CONFIG(tabbar)
1011 
1012 #if QT_CONFIG(tabwidget)
1013 /*!
1014     \property QMainWindow::tabShape
1015     \brief the tab shape used for tabbed dock widgets.
1016     \since 4.5
1017 
1018     The default is \l QTabWidget::Rounded.
1019 
1020     \sa setTabPosition()
1021 */
tabShape() const1022 QTabWidget::TabShape QMainWindow::tabShape() const
1023 {
1024     return d_func()->layout->tabShape();
1025 }
1026 
setTabShape(QTabWidget::TabShape tabShape)1027 void QMainWindow::setTabShape(QTabWidget::TabShape tabShape)
1028 {
1029     d_func()->layout->setTabShape(tabShape);
1030 }
1031 
1032 /*!
1033     \since 4.5
1034 
1035     Returns the tab position for \a area.
1036 
1037     \note The \l VerticalTabs dock option overrides the tab positions returned
1038     by this function.
1039 
1040     \sa setTabPosition(), tabShape()
1041 */
tabPosition(Qt::DockWidgetArea area) const1042 QTabWidget::TabPosition QMainWindow::tabPosition(Qt::DockWidgetArea area) const
1043 {
1044     if (!checkDockWidgetArea(area, "QMainWindow::tabPosition"))
1045         return QTabWidget::South;
1046     return d_func()->layout->tabPosition(area);
1047 }
1048 
1049 /*!
1050     \since 4.5
1051 
1052     Sets the tab position for the given dock widget \a areas to the specified
1053     \a tabPosition. By default, all dock areas show their tabs at the bottom.
1054 
1055     \note The \l VerticalTabs dock option overrides the tab positions set by
1056     this method.
1057 
1058     \sa tabPosition(), setTabShape()
1059 */
setTabPosition(Qt::DockWidgetAreas areas,QTabWidget::TabPosition tabPosition)1060 void QMainWindow::setTabPosition(Qt::DockWidgetAreas areas, QTabWidget::TabPosition tabPosition)
1061 {
1062     d_func()->layout->setTabPosition(areas, tabPosition);
1063 }
1064 #endif // QT_CONFIG(tabwidget)
1065 
1066 /*!
1067     Adds the given \a dockwidget to the specified \a area.
1068 */
addDockWidget(Qt::DockWidgetArea area,QDockWidget * dockwidget)1069 void QMainWindow::addDockWidget(Qt::DockWidgetArea area, QDockWidget *dockwidget)
1070 {
1071     if (!checkDockWidgetArea(area, "QMainWindow::addDockWidget"))
1072         return;
1073 
1074     Qt::Orientation orientation = Qt::Vertical;
1075     switch (area) {
1076     case Qt::TopDockWidgetArea:
1077     case Qt::BottomDockWidgetArea:
1078         orientation = Qt::Horizontal;
1079         break;
1080     default:
1081         break;
1082     }
1083     d_func()->layout->removeWidget(dockwidget); // in case it was already in here
1084     addDockWidget(area, dockwidget, orientation);
1085 }
1086 
1087 /*!
1088     Restores the state of \a dockwidget if it is created after the call
1089     to restoreState(). Returns \c true if the state was restored; otherwise
1090     returns \c false.
1091 
1092     \sa restoreState(), saveState()
1093 */
1094 
restoreDockWidget(QDockWidget * dockwidget)1095 bool QMainWindow::restoreDockWidget(QDockWidget *dockwidget)
1096 {
1097     return d_func()->layout->restoreDockWidget(dockwidget);
1098 }
1099 
1100 /*!
1101     Adds \a dockwidget into the given \a area in the direction
1102     specified by the \a orientation.
1103 */
addDockWidget(Qt::DockWidgetArea area,QDockWidget * dockwidget,Qt::Orientation orientation)1104 void QMainWindow::addDockWidget(Qt::DockWidgetArea area, QDockWidget *dockwidget,
1105                                 Qt::Orientation orientation)
1106 {
1107     if (!checkDockWidgetArea(area, "QMainWindow::addDockWidget"))
1108         return;
1109 
1110     // add a window to an area, placing done relative to the previous
1111     d_func()->layout->addDockWidget(area, dockwidget, orientation);
1112 }
1113 
1114 /*!
1115     \fn void QMainWindow::splitDockWidget(QDockWidget *first, QDockWidget *second, Qt::Orientation orientation)
1116 
1117     Splits the space covered by the \a first dock widget into two parts,
1118     moves the \a first dock widget into the first part, and moves the
1119     \a second dock widget into the second part.
1120 
1121     The \a orientation specifies how the space is divided: A Qt::Horizontal
1122     split places the second dock widget to the right of the first; a
1123     Qt::Vertical split places the second dock widget below the first.
1124 
1125     \e Note: if \a first is currently in a tabbed docked area, \a second will
1126     be added as a new tab, not as a neighbor of \a first. This is because a
1127     single tab can contain only one dock widget.
1128 
1129     \e Note: The Qt::LayoutDirection influences the order of the dock widgets
1130     in the two parts of the divided area. When right-to-left layout direction
1131     is enabled, the placing of the dock widgets will be reversed.
1132 
1133     \sa tabifyDockWidget(), addDockWidget(), removeDockWidget()
1134 */
splitDockWidget(QDockWidget * after,QDockWidget * dockwidget,Qt::Orientation orientation)1135 void QMainWindow::splitDockWidget(QDockWidget *after, QDockWidget *dockwidget,
1136                                   Qt::Orientation orientation)
1137 {
1138     d_func()->layout->splitDockWidget(after, dockwidget, orientation);
1139 }
1140 
1141 #if QT_CONFIG(tabbar)
1142 /*!
1143     \fn void QMainWindow::tabifyDockWidget(QDockWidget *first, QDockWidget *second)
1144 
1145     Moves \a second dock widget on top of \a first dock widget, creating a tabbed
1146     docked area in the main window.
1147 
1148     \sa tabifiedDockWidgets()
1149 */
tabifyDockWidget(QDockWidget * first,QDockWidget * second)1150 void QMainWindow::tabifyDockWidget(QDockWidget *first, QDockWidget *second)
1151 {
1152     d_func()->layout->tabifyDockWidget(first, second);
1153 }
1154 
1155 
1156 /*!
1157     \fn QList<QDockWidget*> QMainWindow::tabifiedDockWidgets(QDockWidget *dockwidget) const
1158 
1159     Returns the dock widgets that are tabified together with \a dockwidget.
1160 
1161     \since 4.5
1162     \sa tabifyDockWidget()
1163 */
1164 
tabifiedDockWidgets(QDockWidget * dockwidget) const1165 QList<QDockWidget*> QMainWindow::tabifiedDockWidgets(QDockWidget *dockwidget) const
1166 {
1167     QList<QDockWidget*> ret;
1168     const QDockAreaLayoutInfo *info = d_func()->layout->layoutState.dockAreaLayout.info(dockwidget);
1169     if (info && info->tabbed && info->tabBar) {
1170         for(int i = 0; i < info->item_list.count(); ++i) {
1171             const QDockAreaLayoutItem &item = info->item_list.at(i);
1172             if (item.widgetItem) {
1173                 if (QDockWidget *dock = qobject_cast<QDockWidget*>(item.widgetItem->widget())) {
1174                     if (dock != dockwidget) {
1175                         ret += dock;
1176                     }
1177                 }
1178             }
1179         }
1180     }
1181     return ret;
1182 }
1183 #endif // QT_CONFIG(tabbar)
1184 
1185 
1186 /*!
1187     Removes the \a dockwidget from the main window layout and hides
1188     it. Note that the \a dockwidget is \e not deleted.
1189 */
removeDockWidget(QDockWidget * dockwidget)1190 void QMainWindow::removeDockWidget(QDockWidget *dockwidget)
1191 {
1192     if (dockwidget) {
1193         d_func()->layout->removeWidget(dockwidget);
1194         dockwidget->hide();
1195     }
1196 }
1197 
1198 /*!
1199     Returns the Qt::DockWidgetArea for \a dockwidget. If \a dockwidget
1200     has not been added to the main window, this function returns \c
1201     Qt::NoDockWidgetArea.
1202 
1203     \sa addDockWidget(), splitDockWidget(), Qt::DockWidgetArea
1204 */
dockWidgetArea(QDockWidget * dockwidget) const1205 Qt::DockWidgetArea QMainWindow::dockWidgetArea(QDockWidget *dockwidget) const
1206 { return d_func()->layout->dockWidgetArea(dockwidget); }
1207 
1208 
1209 /*!
1210     \since 5.6
1211     Resizes the dock widgets in the list \a docks to the corresponding size in
1212     pixels from the list \a sizes. If \a orientation is Qt::Horizontal, adjusts
1213     the width, otherwise adjusts the height of the dock widgets.
1214     The sizes will be adjusted such that the maximum and the minimum sizes are
1215     respected and the QMainWindow itself will not be resized.
1216     Any additional/missing space is distributed amongst the widgets according
1217     to the relative weight of the sizes.
1218 
1219     Example:
1220     \snippet code/src_widgets_widgets_qmainwindow.cpp 2
1221 
1222     If the blue and the yellow widget are nested on the same level they will be
1223     resized such that the yellowWidget is twice as big as the blueWidget
1224 
1225     If some widgets are grouped in tabs, only one widget per group should be
1226     specified. Widgets not in the list might be changed to repect the constraints.
1227 */
resizeDocks(const QList<QDockWidget * > & docks,const QList<int> & sizes,Qt::Orientation orientation)1228 void QMainWindow::resizeDocks(const QList<QDockWidget *> &docks,
1229                               const QList<int> &sizes, Qt::Orientation orientation)
1230 {
1231     d_func()->layout->layoutState.dockAreaLayout.resizeDocks(docks, sizes, orientation);
1232     d_func()->layout->invalidate();
1233 }
1234 
1235 
1236 #endif // QT_CONFIG(dockwidget)
1237 
1238 /*!
1239     Saves the current state of this mainwindow's toolbars and
1240     dockwidgets. This includes the corner settings which can
1241     be set with setCorner(). The \a version number is stored
1242     as part of the data.
1243 
1244     The \l{QObject::objectName}{objectName} property is used
1245     to identify each QToolBar and QDockWidget.  You should make sure
1246     that this property is unique for each QToolBar and QDockWidget you
1247     add to the QMainWindow
1248 
1249     To restore the saved state, pass the return value and \a version
1250     number to restoreState().
1251 
1252     To save the geometry when the window closes, you can
1253     implement a close event like this:
1254 
1255     \snippet code/src_gui_widgets_qmainwindow.cpp 0
1256 
1257     \sa restoreState(), QWidget::saveGeometry(), QWidget::restoreGeometry()
1258 */
saveState(int version) const1259 QByteArray QMainWindow::saveState(int version) const
1260 {
1261     QByteArray data;
1262     QDataStream stream(&data, QIODevice::WriteOnly);
1263     stream << QMainWindowLayout::VersionMarker;
1264     stream << version;
1265     d_func()->layout->saveState(stream);
1266     return data;
1267 }
1268 
1269 /*!
1270     Restores the \a state of this mainwindow's toolbars and
1271     dockwidgets. Also restores the corner settings too. The
1272     \a version number is compared with that stored in \a state.
1273     If they do not match, the mainwindow's state is left
1274     unchanged, and this function returns \c false; otherwise, the state
1275     is restored, and this function returns \c true.
1276 
1277     To restore geometry saved using QSettings, you can use code like
1278     this:
1279 
1280     \snippet code/src_gui_widgets_qmainwindow.cpp 1
1281 
1282     \sa saveState(), QWidget::saveGeometry(),
1283     QWidget::restoreGeometry(), restoreDockWidget()
1284 */
restoreState(const QByteArray & state,int version)1285 bool QMainWindow::restoreState(const QByteArray &state, int version)
1286 {
1287     if (state.isEmpty())
1288         return false;
1289     QByteArray sd = state;
1290     QDataStream stream(&sd, QIODevice::ReadOnly);
1291     int marker, v;
1292     stream >> marker;
1293     stream >> v;
1294     if (stream.status() != QDataStream::Ok || marker != QMainWindowLayout::VersionMarker || v != version)
1295         return false;
1296     bool restored = d_func()->layout->restoreState(stream);
1297     return restored;
1298 }
1299 
1300 /*! \reimp */
event(QEvent * event)1301 bool QMainWindow::event(QEvent *event)
1302 {
1303     Q_D(QMainWindow);
1304 
1305 #if QT_CONFIG(dockwidget)
1306     if (d->layout && d->layout->windowEvent(event))
1307         return true;
1308 #endif
1309 
1310     switch (event->type()) {
1311 
1312 #if QT_CONFIG(toolbar)
1313         case QEvent::ToolBarChange: {
1314             d->layout->toggleToolBarsVisible();
1315             return true;
1316         }
1317 #endif
1318 
1319 #if QT_CONFIG(statustip)
1320         case QEvent::StatusTip:
1321 #if QT_CONFIG(statusbar)
1322             if (QStatusBar *sb = d->layout->statusBar())
1323                 sb->showMessage(static_cast<QStatusTipEvent*>(event)->tip());
1324             else
1325 #endif
1326                 static_cast<QStatusTipEvent*>(event)->ignore();
1327             return true;
1328 #endif // QT_CONFIG(statustip)
1329 
1330         case QEvent::StyleChange:
1331 #if QT_CONFIG(dockwidget)
1332             d->layout->layoutState.dockAreaLayout.styleChangedEvent();
1333 #endif
1334             if (!d->explicitIconSize)
1335                 setIconSize(QSize());
1336             break;
1337         default:
1338             break;
1339     }
1340 
1341     return QWidget::event(event);
1342 }
1343 
1344 #if QT_CONFIG(toolbar)
1345 
1346 /*!
1347     \property QMainWindow::unifiedTitleAndToolBarOnMac
1348     \brief whether the window uses the unified title and toolbar look on \macos
1349 
1350     Note that the Qt 5 implementation has several limitations compared to Qt 4:
1351     \list
1352         \li Use in windows with OpenGL content is not supported. This includes QGLWidget and QOpenGLWidget.
1353         \li Using dockable or movable toolbars may result in painting errors and is not recommended
1354     \endlist
1355 
1356     \since 5.2
1357 */
setUnifiedTitleAndToolBarOnMac(bool set)1358 void QMainWindow::setUnifiedTitleAndToolBarOnMac(bool set)
1359 {
1360 #ifdef Q_OS_MACOS
1361     Q_D(QMainWindow);
1362     if (isWindow()) {
1363         d->useUnifiedToolBar = set;
1364         createWinId();
1365 
1366         QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
1367         if (!nativeInterface)
1368             return; // Not Cocoa platform plugin.
1369         QPlatformNativeInterface::NativeResourceForIntegrationFunction function =
1370             nativeInterface->nativeResourceFunctionForIntegration("setContentBorderEnabled");
1371         if (!function)
1372             return; // Not Cocoa platform plugin.
1373 
1374         typedef void (*SetContentBorderEnabledFunction)(QWindow *window, bool enable);
1375         (reinterpret_cast<SetContentBorderEnabledFunction>(function))(window()->windowHandle(), set);
1376         update();
1377     }
1378 #else
1379     Q_UNUSED(set)
1380 #endif
1381 }
1382 
unifiedTitleAndToolBarOnMac() const1383 bool QMainWindow::unifiedTitleAndToolBarOnMac() const
1384 {
1385 #ifdef Q_OS_MACOS
1386     return d_func()->useUnifiedToolBar;
1387 #endif
1388     return false;
1389 }
1390 
1391 #endif // QT_CONFIG(toolbar)
1392 
1393 /*!
1394     \internal
1395 */
isSeparator(const QPoint & pos) const1396 bool QMainWindow::isSeparator(const QPoint &pos) const
1397 {
1398 #if QT_CONFIG(dockwidget)
1399     Q_D(const QMainWindow);
1400     return !d->layout->layoutState.dockAreaLayout.findSeparator(pos).isEmpty();
1401 #else
1402     Q_UNUSED(pos);
1403     return false;
1404 #endif
1405 }
1406 
1407 #ifndef QT_NO_CONTEXTMENU
1408 /*!
1409     \reimp
1410 */
contextMenuEvent(QContextMenuEvent * event)1411 void QMainWindow::contextMenuEvent(QContextMenuEvent *event)
1412 {
1413     event->ignore();
1414     // only show the context menu for direct QDockWidget and QToolBar
1415     // children and for the menu bar as well
1416     QWidget *child = childAt(event->pos());
1417     while (child && child != this) {
1418 #if QT_CONFIG(menubar)
1419         if (QMenuBar *mb = qobject_cast<QMenuBar *>(child)) {
1420             if (mb->parentWidget() != this)
1421                 return;
1422             break;
1423         }
1424 #endif
1425 #if QT_CONFIG(dockwidget)
1426         if (QDockWidget *dw = qobject_cast<QDockWidget *>(child)) {
1427             if (dw->parentWidget() != this)
1428                 return;
1429             if (dw->widget()
1430                 && dw->widget()->geometry().contains(child->mapFrom(this, event->pos()))) {
1431                 // ignore the event if the mouse is over the QDockWidget contents
1432                 return;
1433             }
1434             break;
1435         }
1436 #endif // QT_CONFIG(dockwidget)
1437 #if QT_CONFIG(toolbar)
1438         if (QToolBar *tb = qobject_cast<QToolBar *>(child)) {
1439             if (tb->parentWidget() != this)
1440                 return;
1441             break;
1442         }
1443 #endif
1444         child = child->parentWidget();
1445     }
1446     if (child == this)
1447         return;
1448 
1449 #if QT_CONFIG(menu)
1450     QMenu *popup = createPopupMenu();
1451     if (popup) {
1452         if (!popup->isEmpty()) {
1453             popup->setAttribute(Qt::WA_DeleteOnClose);
1454             popup->popup(event->globalPos());
1455             event->accept();
1456         } else {
1457             delete popup;
1458         }
1459     }
1460 #endif
1461 }
1462 #endif // QT_NO_CONTEXTMENU
1463 
1464 #if QT_CONFIG(menu)
1465 /*!
1466     Returns a popup menu containing checkable entries for the toolbars and
1467     dock widgets present in the main window. If there are no toolbars and
1468     dock widgets present, this function returns \nullptr.
1469 
1470     By default, this function is called by the main window when the user
1471     activates a context menu, typically by right-clicking on a toolbar or a dock
1472     widget.
1473 
1474     If you want to create a custom popup menu, reimplement this function and
1475     return a newly-created popup menu. Ownership of the popup menu is transferred
1476     to the caller.
1477 
1478     \sa addDockWidget(), addToolBar(), menuBar()
1479 */
createPopupMenu()1480 QMenu *QMainWindow::createPopupMenu()
1481 {
1482     Q_D(QMainWindow);
1483     QMenu *menu = nullptr;
1484 #if QT_CONFIG(dockwidget)
1485     QList<QDockWidget *> dockwidgets = findChildren<QDockWidget *>();
1486     if (dockwidgets.size()) {
1487         menu = new QMenu(this);
1488         for (int i = 0; i < dockwidgets.size(); ++i) {
1489             QDockWidget *dockWidget = dockwidgets.at(i);
1490             // filter to find out if we own this QDockWidget
1491             if (dockWidget->parentWidget() == this) {
1492                 if (d->layout->layoutState.dockAreaLayout.indexOf(dockWidget).isEmpty())
1493                     continue;
1494             } else if (QDockWidgetGroupWindow *dwgw =
1495                            qobject_cast<QDockWidgetGroupWindow *>(dockWidget->parentWidget())) {
1496                 if (dwgw->parentWidget() != this)
1497                     continue;
1498                 if (dwgw->layoutInfo()->indexOf(dockWidget).isEmpty())
1499                     continue;
1500             } else {
1501                 continue;
1502             }
1503             menu->addAction(dockwidgets.at(i)->toggleViewAction());
1504         }
1505         menu->addSeparator();
1506     }
1507 #endif // QT_CONFIG(dockwidget)
1508 #if QT_CONFIG(toolbar)
1509     QList<QToolBar *> toolbars = findChildren<QToolBar *>();
1510     if (toolbars.size()) {
1511         if (!menu)
1512             menu = new QMenu(this);
1513         for (int i = 0; i < toolbars.size(); ++i) {
1514             QToolBar *toolBar = toolbars.at(i);
1515             if (toolBar->parentWidget() == this
1516                 && (!d->layout->layoutState.toolBarAreaLayout.indexOf(toolBar).isEmpty())) {
1517                 menu->addAction(toolbars.at(i)->toggleViewAction());
1518             }
1519         }
1520     }
1521 #endif
1522     Q_UNUSED(d);
1523     return menu;
1524 }
1525 #endif // QT_CONFIG(menu)
1526 
1527 QT_END_NAMESPACE
1528 
1529 #include "moc_qmainwindow.cpp"
1530