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

source code of qtbase/src/widgets/widgets/qmainwindow.cpp