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 #include <qmenubar.h>
41 
42 #include <qstyle.h>
43 #include <qlayout.h>
44 #include <qapplication.h>
45 #include <qdesktopwidget.h>
46 #ifndef QT_NO_ACCESSIBILITY
47 # include <qaccessible.h>
48 #endif
49 #include <qpainter.h>
50 #include <qstylepainter.h>
51 #include <qevent.h>
52 #if QT_CONFIG(mainwindow)
53 #include <qmainwindow.h>
54 #endif
55 #if QT_CONFIG(toolbar)
56 #include <qtoolbar.h>
57 #endif
58 #if QT_CONFIG(toolbutton)
59 #include <qtoolbutton.h>
60 #endif
61 #if QT_CONFIG(whatsthis)
62 #include <qwhatsthis.h>
63 #endif
64 #include <qpa/qplatformtheme.h>
65 #include "private/qguiapplication_p.h"
66 #include "qpa/qplatformintegration.h"
67 #include <private/qdesktopwidget_p.h>
68 
69 #include "qmenu_p.h"
70 #include "qmenubar_p.h"
71 #include <private/qscreen_p.h>
72 #include "qdebug.h"
73 
74 QT_BEGIN_NAMESPACE
75 
76 class QMenuBarExtension : public QToolButton
77 {
78 public:
79     explicit QMenuBarExtension(QWidget *parent);
80 
81     QSize sizeHint() const override;
82     void paintEvent(QPaintEvent *) override;
83 };
84 
QMenuBarExtension(QWidget * parent)85 QMenuBarExtension::QMenuBarExtension(QWidget *parent)
86     : QToolButton(parent)
87 {
88     setObjectName(QLatin1String("qt_menubar_ext_button"));
89     setAutoRaise(true);
90 #if QT_CONFIG(menu)
91     setPopupMode(QToolButton::InstantPopup);
92 #endif
93     setIcon(style()->standardIcon(QStyle::SP_ToolBarHorizontalExtensionButton, nullptr, parentWidget()));
94 }
95 
paintEvent(QPaintEvent *)96 void QMenuBarExtension::paintEvent(QPaintEvent *)
97 {
98     QStylePainter p(this);
99     QStyleOptionToolButton opt;
100     initStyleOption(&opt);
101     // We do not need to draw both extension arrows
102     opt.features &= ~QStyleOptionToolButton::HasMenu;
103     p.drawComplexControl(QStyle::CC_ToolButton, opt);
104 }
105 
106 
sizeHint() const107 QSize QMenuBarExtension::sizeHint() const
108 {
109     int ext = style()->pixelMetric(QStyle::PM_ToolBarExtensionExtent, nullptr, parentWidget());
110     return QSize(ext, ext);
111 }
112 
113 
114 /*!
115     \internal
116 */
actionAt(QPoint p) const117 QAction *QMenuBarPrivate::actionAt(QPoint p) const
118 {
119     for(int i = 0; i < actions.size(); ++i) {
120         if(actionRect(actions.at(i)).contains(p))
121             return actions.at(i);
122     }
123     return nullptr;
124 }
125 
menuRect(bool extVisible) const126 QRect QMenuBarPrivate::menuRect(bool extVisible) const
127 {
128     Q_Q(const QMenuBar);
129 
130     int hmargin = q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, nullptr, q);
131     QRect result = q->rect();
132     result.adjust(hmargin, 0, -hmargin, 0);
133 
134     if (extVisible) {
135         if (q->isRightToLeft())
136             result.setLeft(result.left() + extension->sizeHint().width());
137         else
138             result.setWidth(result.width() - extension->sizeHint().width());
139     }
140 
141     if (leftWidget && leftWidget->isVisible()) {
142         QSize sz = leftWidget->sizeHint();
143         if (q->isRightToLeft())
144             result.setRight(result.right() - sz.width());
145         else
146             result.setLeft(result.left() + sz.width());
147     }
148 
149     if (rightWidget && rightWidget->isVisible()) {
150         QSize sz = rightWidget->sizeHint();
151         if (q->isRightToLeft())
152             result.setLeft(result.left() + sz.width());
153         else
154             result.setRight(result.right() - sz.width());
155     }
156 
157     return result;
158 }
159 
isVisible(QAction * action)160 bool QMenuBarPrivate::isVisible(QAction *action)
161 {
162     return !hiddenActions.contains(action);
163 }
164 
updateGeometries()165 void QMenuBarPrivate::updateGeometries()
166 {
167     Q_Q(QMenuBar);
168     if(!itemsDirty)
169         return;
170     int q_width = q->width()-(q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, nullptr, q)*2);
171     int q_start = -1;
172     if(leftWidget || rightWidget) {
173         int vmargin = q->style()->pixelMetric(QStyle::PM_MenuBarVMargin, nullptr, q)
174                       + q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, nullptr, q);
175         int hmargin = q->style()->pixelMetric(QStyle::PM_MenuBarHMargin, nullptr, q)
176                       + q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, nullptr, q);
177         if (leftWidget && leftWidget->isVisible()) {
178             QSize sz = leftWidget->sizeHint();
179             q_width -= sz.width();
180             q_start = sz.width();
181             QPoint pos(hmargin, (q->height() - leftWidget->height()) / 2);
182             QRect vRect = QStyle::visualRect(q->layoutDirection(), q->rect(), QRect(pos, sz));
183             leftWidget->setGeometry(vRect);
184         }
185         if (rightWidget && rightWidget->isVisible()) {
186             QSize sz = rightWidget->sizeHint();
187             q_width -= sz.width();
188             QPoint pos(q->width() - sz.width() - hmargin, vmargin);
189             QRect vRect = QStyle::visualRect(q->layoutDirection(), q->rect(), QRect(pos, sz));
190             rightWidget->setGeometry(vRect);
191         }
192     }
193 
194 #ifdef Q_OS_MAC
195     if(q->isNativeMenuBar()) {//nothing to see here folks, move along..
196         itemsDirty = false;
197         return;
198     }
199 #endif
200     calcActionRects(q_width, q_start);
201     currentAction = nullptr;
202 #ifndef QT_NO_SHORTCUT
203     if(itemsDirty) {
204         for(int j = 0; j < shortcutIndexMap.size(); ++j)
205             q->releaseShortcut(shortcutIndexMap.value(j));
206         shortcutIndexMap.clear();
207         const int actionsCount = actions.count();
208         shortcutIndexMap.reserve(actionsCount);
209         for (int i = 0; i < actionsCount; i++)
210             shortcutIndexMap.append(q->grabShortcut(QKeySequence::mnemonic(actions.at(i)->text())));
211     }
212 #endif
213     itemsDirty = false;
214 
215     hiddenActions.clear();
216     //this is the menu rectangle without any extension
217     QRect menuRect = this->menuRect(false);
218 
219     //we try to see if the actions will fit there
220     bool hasHiddenActions = false;
221     for (int i = 0; i < actions.count(); ++i) {
222         const QRect &rect = actionRects.at(i);
223         if (rect.isValid() && !menuRect.contains(rect)) {
224             hasHiddenActions = true;
225             break;
226         }
227     }
228 
229     //...and if not, determine the ones that fit on the menu with the extension visible
230     if (hasHiddenActions) {
231         menuRect = this->menuRect(true);
232         for (int i = 0; i < actions.count(); ++i) {
233             const QRect &rect = actionRects.at(i);
234             if (rect.isValid() && !menuRect.contains(rect)) {
235                 hiddenActions.append(actions.at(i));
236             }
237         }
238     }
239 
240     if (hiddenActions.count() > 0) {
241         QMenu *pop = extension->menu();
242         if (!pop) {
243             pop = new QMenu(q);
244             extension->setMenu(pop);
245         }
246         pop->clear();
247         pop->addActions(hiddenActions);
248 
249         int vmargin = q->style()->pixelMetric(QStyle::PM_MenuBarVMargin, nullptr, q);
250         int x = q->isRightToLeft()
251                 ? menuRect.left() - extension->sizeHint().width() + 1
252                 : menuRect.right();
253         extension->setGeometry(x, vmargin, extension->sizeHint().width(), menuRect.height() - vmargin*2);
254         extension->show();
255     } else {
256         extension->hide();
257     }
258     q->updateGeometry();
259 }
260 
actionRect(QAction * act) const261 QRect QMenuBarPrivate::actionRect(QAction *act) const
262 {
263     const int index = actions.indexOf(act);
264 
265     //makes sure the geometries are up-to-date
266     const_cast<QMenuBarPrivate*>(this)->updateGeometries();
267 
268     if (index < 0 || index >= actionRects.count())
269         return QRect(); // that can happen in case of native menubar
270 
271     return actionRects.at(index);
272 }
273 
focusFirstAction()274 void QMenuBarPrivate::focusFirstAction()
275 {
276     if(!currentAction) {
277         updateGeometries();
278         int index = 0;
279         while (index < actions.count() && actionRects.at(index).isNull()) ++index;
280         if (index < actions.count())
281             setCurrentAction(actions.at(index));
282     }
283 }
284 
setKeyboardMode(bool b)285 void QMenuBarPrivate::setKeyboardMode(bool b)
286 {
287     Q_Q(QMenuBar);
288     if (b && !q->style()->styleHint(QStyle::SH_MenuBar_AltKeyNavigation, nullptr, q)) {
289         setCurrentAction(nullptr);
290         return;
291     }
292     keyboardState = b;
293     if(b) {
294         QWidget *fw = QApplication::focusWidget();
295         if (fw && fw != q && fw->window() != QApplication::activePopupWidget())
296             keyboardFocusWidget = fw;
297         focusFirstAction();
298         q->setFocus(Qt::MenuBarFocusReason);
299     } else {
300         if(!popupState)
301             setCurrentAction(nullptr);
302         if(keyboardFocusWidget) {
303             if (QApplication::focusWidget() == q)
304                 keyboardFocusWidget->setFocus(Qt::MenuBarFocusReason);
305             keyboardFocusWidget = nullptr;
306         }
307     }
308     q->update();
309 }
310 
popupAction(QAction * action,bool activateFirst)311 void QMenuBarPrivate::popupAction(QAction *action, bool activateFirst)
312 {
313     Q_Q(QMenuBar);
314     if(!action || !action->menu() || closePopupMode)
315         return;
316     popupState = true;
317     if (action->isEnabled() && action->menu()->isEnabled()) {
318         closePopupMode = 0;
319         activeMenu = action->menu();
320         activeMenu->d_func()->causedPopup.widget = q;
321         activeMenu->d_func()->causedPopup.action = action;
322 
323         QRect adjustedActionRect = actionRect(action);
324         QPoint pos(q->mapToGlobal(QPoint(adjustedActionRect.left(), adjustedActionRect.bottom() + 1)));
325         QSize popup_size = activeMenu->sizeHint();
326         //we put the popup menu on the screen containing the bottom-center of the action rect
327         QScreen *menubarScreen = q->window()->windowHandle()->screen();
328         QScreen *popupScreen = menubarScreen->virtualSiblingAt(pos + QPoint(adjustedActionRect.width() / 2, 0));
329         if (!popupScreen)
330             popupScreen = menubarScreen;
331         QRect screenRect = popupScreen->geometry();
332         pos = QPoint(qMax(pos.x(), screenRect.x()), qMax(pos.y(), screenRect.y()));
333         const bool fitUp = (pos.y() - popup_size.height() >= screenRect.top());
334         const bool fitDown = (pos.y() + popup_size.height() <= screenRect.bottom());
335         const bool rtl = q->isRightToLeft();
336         const int actionWidth = adjustedActionRect.width();
337 
338         if (!fitUp && !fitDown) { //we should shift the menu
339             bool shouldShiftToRight = !rtl;
340             if (rtl && popup_size.width() > pos.x())
341                 shouldShiftToRight = true;
342             else if (actionWidth + popup_size.width() + pos.x() > screenRect.right())
343                 shouldShiftToRight = false;
344 
345             if (shouldShiftToRight) {
346                 pos.rx() += actionWidth + (rtl ? popup_size.width() : 0);
347             } else {
348                 //shift to left
349                 if (!rtl)
350                     pos.rx() -= popup_size.width();
351             }
352         } else if (rtl) {
353             pos.rx() += actionWidth;
354         }
355 
356         if(!defaultPopDown || (fitUp && !fitDown))
357             pos.setY(qMax(screenRect.y(), q->mapToGlobal(QPoint(0, adjustedActionRect.top()-popup_size.height())).y()));
358         QMenuPrivate::get(activeMenu)->topData()->initialScreenIndex = QGuiApplication::screens().indexOf(popupScreen);
359         activeMenu->popup(pos);
360         if(activateFirst)
361             activeMenu->d_func()->setFirstActionActive();
362     }
363     q->update(actionRect(action));
364 }
365 
setCurrentAction(QAction * action,bool popup,bool activateFirst)366 void QMenuBarPrivate::setCurrentAction(QAction *action, bool popup, bool activateFirst)
367 {
368     if(currentAction == action && popup == popupState)
369         return;
370 
371     autoReleaseTimer.stop();
372 
373     doChildEffects = (popup && !activeMenu);
374     Q_Q(QMenuBar);
375     QWidget *fw = nullptr;
376     if(QMenu *menu = activeMenu) {
377         activeMenu = nullptr;
378         if (popup) {
379             fw = q->window()->focusWidget();
380             q->setFocus(Qt::NoFocusReason);
381         }
382         menu->hide();
383     }
384 
385     if(currentAction)
386         q->update(actionRect(currentAction));
387 
388     popupState = popup;
389 #if QT_CONFIG(statustip)
390     QAction *previousAction = currentAction;
391 #endif
392     currentAction = action;
393     if (action && action->isEnabled()) {
394         activateAction(action, QAction::Hover);
395         if(popup)
396             popupAction(action, activateFirst);
397         q->update(actionRect(action));
398 #if QT_CONFIG(statustip)
399     }  else if (previousAction) {
400         QString empty;
401         QStatusTipEvent tip(empty);
402         QCoreApplication::sendEvent(q, &tip);
403 #endif
404     }
405     if (fw)
406         fw->setFocus(Qt::NoFocusReason);
407 }
408 
calcActionRects(int max_width,int start) const409 void QMenuBarPrivate::calcActionRects(int max_width, int start) const
410 {
411     Q_Q(const QMenuBar);
412 
413     if(!itemsDirty)
414         return;
415 
416     //let's reinitialize the buffer
417     actionRects.resize(actions.count());
418     actionRects.fill(QRect());
419 
420     const QStyle *style = q->style();
421 
422     const int itemSpacing = style->pixelMetric(QStyle::PM_MenuBarItemSpacing, nullptr, q);
423     int max_item_height = 0, separator = -1, separator_start = 0, separator_len = 0;
424 
425     //calculate size
426     const QFontMetrics fm = q->fontMetrics();
427     const int hmargin = style->pixelMetric(QStyle::PM_MenuBarHMargin, nullptr, q),
428               vmargin = style->pixelMetric(QStyle::PM_MenuBarVMargin, nullptr, q),
429                 icone = style->pixelMetric(QStyle::PM_SmallIconSize, nullptr, q);
430     for(int i = 0; i < actions.count(); i++) {
431         QAction *action = actions.at(i);
432         if(!action->isVisible())
433             continue;
434 
435         QSize sz;
436 
437         //calc what I think the size is..
438         if(action->isSeparator()) {
439             if (style->styleHint(QStyle::SH_DrawMenuBarSeparator, nullptr, q))
440                 separator = i;
441             continue; //we don't really position these!
442         } else {
443             const QString s = action->text();
444             QIcon is = action->icon();
445             // If an icon is set, only the icon is visible
446             if (!is.isNull())
447                 sz = sz.expandedTo(QSize(icone, icone));
448             else if (!s.isEmpty())
449                 sz = fm.size(Qt::TextShowMnemonic, s);
450         }
451 
452         //let the style modify the above size..
453         QStyleOptionMenuItem opt;
454         q->initStyleOption(&opt, action);
455         sz = q->style()->sizeFromContents(QStyle::CT_MenuBarItem, &opt, sz, q);
456 
457         if(!sz.isEmpty()) {
458             { //update the separator state
459                 int iWidth = sz.width() + itemSpacing;
460                 if(separator == -1)
461                     separator_start += iWidth;
462                 else
463                     separator_len += iWidth;
464             }
465             //maximum height
466             max_item_height = qMax(max_item_height, sz.height());
467             //append
468             actionRects[i] = QRect(0, 0, sz.width(), sz.height());
469         }
470     }
471 
472     //calculate position
473     const int fw = q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, nullptr, q);
474     int x = fw + ((start == -1) ? hmargin : start) + itemSpacing;
475     int y = fw + vmargin;
476     for(int i = 0; i < actions.count(); i++) {
477         QRect &rect = actionRects[i];
478         if (rect.isNull())
479             continue;
480 
481         //resize
482         rect.setHeight(max_item_height);
483 
484         //move
485         if(separator != -1 && i >= separator) { //after the separator
486             int left = (max_width - separator_len - hmargin - itemSpacing) + (x - separator_start - hmargin);
487             if(left < separator_start) { //wrap
488                 separator_start = x = hmargin;
489                 y += max_item_height;
490             }
491             rect.moveLeft(left);
492         } else {
493             rect.moveLeft(x);
494         }
495         rect.moveTop(y);
496 
497         //keep moving along..
498         x += rect.width() + itemSpacing;
499 
500         //make sure we follow the layout direction
501         rect = QStyle::visualRect(q->layoutDirection(), q->rect(), rect);
502     }
503 }
504 
activateAction(QAction * action,QAction::ActionEvent action_e)505 void QMenuBarPrivate::activateAction(QAction *action, QAction::ActionEvent action_e)
506 {
507     Q_Q(QMenuBar);
508     if (!action || !action->isEnabled())
509         return;
510     action->activate(action_e);
511     if (action_e == QAction::Hover)
512         action->showStatusText(q);
513 
514 //     if(action_e == QAction::Trigger)
515 //         emit q->activated(action);
516 //     else if(action_e == QAction::Hover)
517 //         emit q->highlighted(action);
518 }
519 
520 
_q_actionTriggered()521 void QMenuBarPrivate::_q_actionTriggered()
522 {
523     Q_Q(QMenuBar);
524     if (QAction *action = qobject_cast<QAction *>(q->sender())) {
525         emit q->triggered(action);
526     }
527 }
528 
_q_actionHovered()529 void QMenuBarPrivate::_q_actionHovered()
530 {
531     Q_Q(QMenuBar);
532     if (QAction *action = qobject_cast<QAction *>(q->sender())) {
533         emit q->hovered(action);
534 #ifndef QT_NO_ACCESSIBILITY
535         if (QAccessible::isActive()) {
536             int actionIndex = actions.indexOf(action);
537             QAccessibleEvent focusEvent(q, QAccessible::Focus);
538             focusEvent.setChild(actionIndex);
539             QAccessible::updateAccessibility(&focusEvent);
540         }
541 #endif //QT_NO_ACCESSIBILITY
542     }
543 }
544 
545 /*!
546     Initialize \a option with the values from the menu bar and information from \a action. This method
547     is useful for subclasses when they need a QStyleOptionMenuItem, but don't want
548     to fill in all the information themselves.
549 
550     \sa QStyleOption::initFrom(), QMenu::initStyleOption()
551 */
initStyleOption(QStyleOptionMenuItem * option,const QAction * action) const552 void QMenuBar::initStyleOption(QStyleOptionMenuItem *option, const QAction *action) const
553 {
554     if (!option || !action)
555         return;
556     Q_D(const QMenuBar);
557     option->palette = palette();
558     option->state = QStyle::State_None;
559     if (isEnabled() && action->isEnabled())
560         option->state |= QStyle::State_Enabled;
561     else
562         option->palette.setCurrentColorGroup(QPalette::Disabled);
563     option->fontMetrics = fontMetrics();
564     if (d->currentAction && d->currentAction == action) {
565         option->state |= QStyle::State_Selected;
566         if (d->popupState && !d->closePopupMode)
567             option->state |= QStyle::State_Sunken;
568     }
569     if (hasFocus() || d->currentAction)
570         option->state |= QStyle::State_HasFocus;
571     option->menuRect = rect();
572     option->menuItemType = QStyleOptionMenuItem::Normal;
573     option->checkType = QStyleOptionMenuItem::NotCheckable;
574     option->text = action->text();
575     option->icon = action->icon();
576 }
577 
578 /*!
579     \class QMenuBar
580     \brief The QMenuBar class provides a horizontal menu bar.
581 
582     \ingroup mainwindow-classes
583     \inmodule QtWidgets
584 
585     A menu bar consists of a list of pull-down menu items. You add
586     menu items with addMenu(). For example, asuming that \c menubar
587     is a pointer to a QMenuBar and \c fileMenu is a pointer to a
588     QMenu, the following statement inserts the menu into the menu bar:
589     \snippet code/src_gui_widgets_qmenubar.cpp 0
590 
591     The ampersand in the menu item's text sets Alt+F as a shortcut for
592     this menu. (You can use "\&\&" to get a real ampersand in the menu
593     bar.)
594 
595     There is no need to lay out a menu bar. It automatically sets its
596     own geometry to the top of the parent widget and changes it
597     appropriately whenever the parent is resized.
598 
599     \section1 Usage
600 
601     In most main window style applications you would use the
602     \l{QMainWindow::}{menuBar()} function provided in QMainWindow,
603     adding \l{QMenu}s to the menu bar and adding \l{QAction}s to the
604     pop-up menus.
605 
606     Example (from the \l{mainwindows/menus}{Menus} example):
607 
608     \snippet mainwindows/menus/mainwindow.cpp 9
609 
610     Menu items may be removed with removeAction().
611 
612     Widgets can be added to menus by using instances of the QWidgetAction
613     class to hold them. These actions can then be inserted into menus
614     in the usual way; see the QMenu documentation for more details.
615 
616     \section1 Platform Dependent Look and Feel
617 
618     Different platforms have different requirements for the appearance
619     of menu bars and their behavior when the user interacts with them.
620     For example, Windows systems are often configured so that the
621     underlined character mnemonics that indicate keyboard shortcuts
622     for items in the menu bar are only shown when the \uicontrol{Alt} key is
623     pressed.
624 
625     \section1 QMenuBar as a Global Menu Bar
626 
627     On \macos and on certain Linux desktop environments such as
628     Ubuntu Unity, QMenuBar is a wrapper for using the system-wide menu bar.
629     If you have multiple menu bars in one dialog the outermost menu bar
630     (normally inside a widget with widget flag Qt::Window) will
631     be used for the system-wide menu bar.
632 
633     Qt for \macos also provides a menu bar merging feature to make
634     QMenuBar conform more closely to accepted \macos menu bar layout.
635     The merging functionality is based on string matching the title of
636     a QMenu entry. These strings are translated (using QObject::tr())
637     in the "QMenuBar" context. If an entry is moved its slots will still
638     fire as if it was in the original place. The table below outlines
639     the strings looked for and where the entry is placed if matched:
640 
641     \table
642     \header \li String matches \li Placement \li Notes
643     \row \li about.*
644          \li Application Menu | About <application name>
645          \li The application name is fetched from the \c {Info.plist} file
646             (see note below). If this entry is not found no About item
647             will appear in the Application Menu.
648     \row \li config, options, setup, settings or preferences
649          \li Application Menu | Preferences
650          \li If this entry is not found the Settings item will be disabled
651     \row \li quit or exit
652          \li Application Menu | Quit <application name>
653          \li If this entry is not found a default Quit item will be
654             created to call QCoreApplication::quit()
655     \endtable
656 
657     You can override this behavior by using the QAction::menuRole()
658     property.
659 
660     If you want all windows in a Mac application to share one menu
661     bar, you must create a menu bar that does not have a parent.
662     Create a parent-less menu bar this way:
663 
664     \snippet code/src_gui_widgets_qmenubar.cpp 1
665 
666     \b{Note:} Do \e{not} call QMainWindow::menuBar() to create the
667     shared menu bar, because that menu bar will have the QMainWindow
668     as its parent. That menu bar would only be displayed for the
669     parent QMainWindow.
670 
671     \b{Note:} The text used for the application name in the \macos menu
672     bar is obtained from the value set in the \c{Info.plist} file in
673     the application's bundle. See \l{Qt for macOS - Deployment}
674     for more information.
675 
676     \b{Note:} On Linux, if the com.canonical.AppMenu.Registrar
677     service is available on the D-Bus session bus, then Qt will
678     communicate with it to install the application's menus into the
679     global menu bar, as described.
680 
681     \section1 Examples
682 
683     The \l{mainwindows/menus}{Menus} example shows how to use QMenuBar
684     and QMenu.  The other \l{Main Window Examples}{main window
685     application examples} also provide menus using these classes.
686 
687     \sa QMenu, QShortcut, QAction,
688         {http://developer.apple.com/documentation/UserExperience/Conceptual/AppleHIGuidelines/XHIGIntro/XHIGIntro.html}{Introduction to Apple Human Interface Guidelines},
689         {fowler}{GUI Design Handbook: Menu Bar}, {Menus Example}
690 */
691 
692 
init()693 void QMenuBarPrivate::init()
694 {
695     Q_Q(QMenuBar);
696     q->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
697     q->setAttribute(Qt::WA_CustomWhatsThis);
698 
699     if (!QCoreApplication::testAttribute(Qt::AA_DontUseNativeMenuBar))
700         platformMenuBar = QGuiApplicationPrivate::platformTheme()->createPlatformMenuBar();
701 
702     if (platformMenuBar)
703         q->hide();
704     q->setBackgroundRole(QPalette::Button);
705     handleReparent();
706     q->setMouseTracking(q->style()->styleHint(QStyle::SH_MenuBar_MouseTracking, nullptr, q));
707 
708     extension = new QMenuBarExtension(q);
709     extension->setFocusPolicy(Qt::NoFocus);
710     extension->hide();
711 }
712 
713 //Gets the next action for keyboard navigation
getNextAction(const int _start,const int increment) const714 QAction *QMenuBarPrivate::getNextAction(const int _start, const int increment) const
715 {
716     Q_Q(const QMenuBar);
717     const_cast<QMenuBarPrivate*>(this)->updateGeometries();
718     bool allowActiveAndDisabled = q->style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, nullptr, q);
719     const int start = (_start == -1 && increment == -1) ? actions.count() : _start;
720     const int end =  increment == -1 ? 0 : actions.count() - 1;
721 
722     for (int i = start; i != end;) {
723         i += increment;
724         QAction *current = actions.at(i);
725         if (!actionRects.at(i).isNull() && (allowActiveAndDisabled || current->isEnabled()))
726             return current;
727     }
728 
729     if (_start != -1) //let's try from the beginning or the end
730         return getNextAction(-1, increment);
731 
732     return nullptr;
733 }
734 
735 /*!
736     Constructs a menu bar with parent \a parent.
737 */
QMenuBar(QWidget * parent)738 QMenuBar::QMenuBar(QWidget *parent) : QWidget(*new QMenuBarPrivate, parent, { })
739 {
740     Q_D(QMenuBar);
741     d->init();
742 }
743 
744 
745 /*!
746     Destroys the menu bar.
747 */
~QMenuBar()748 QMenuBar::~QMenuBar()
749 {
750     Q_D(QMenuBar);
751     delete d->platformMenuBar;
752     d->platformMenuBar = nullptr;
753 }
754 
755 /*!
756     This convenience function creates a new action with \a text.
757     The function adds the newly created action to the menu's
758     list of actions, and returns it.
759 
760     \sa QWidget::addAction(), QWidget::actions()
761 */
addAction(const QString & text)762 QAction *QMenuBar::addAction(const QString &text)
763 {
764     QAction *ret = new QAction(text, this);
765     addAction(ret);
766     return ret;
767 }
768 
769 /*!
770     \overload
771 
772     This convenience function creates a new action with the given \a
773     text. The action's triggered() signal is connected to the \a
774     receiver's \a member slot. The function adds the newly created
775     action to the menu's list of actions and returns it.
776 
777     \sa QWidget::addAction(), QWidget::actions()
778 */
addAction(const QString & text,const QObject * receiver,const char * member)779 QAction *QMenuBar::addAction(const QString &text, const QObject *receiver, const char* member)
780 {
781     QAction *ret = new QAction(text, this);
782     QObject::connect(ret, SIGNAL(triggered(bool)), receiver, member);
783     addAction(ret);
784     return ret;
785 }
786 
787 /*!
788     \fn template<typename Obj, typename PointerToMemberFunctionOrFunctor> QAction *QMenuBar::addAction(const QString &text, const Obj *receiver, PointerToMemberFunctionOrFunctor method)
789 
790     \since 5.11
791 
792     \overload
793 
794     This convenience function creates a new action with the given \a
795     text. The action's triggered() signal is connected to the
796     \a method of the \a receiver. The function adds the newly created
797     action to the menu's list of actions and returns it.
798 
799     QMenuBar takes ownership of the returned QAction.
800 
801     \sa QWidget::addAction(), QWidget::actions()
802 */
803 
804 /*!
805     \fn template<typename Functor> QAction *QMenuBar::addAction(const QString &text, Functor functor)
806 
807     \since 5.11
808 
809     \overload
810 
811     This convenience function creates a new action with the given \a
812     text. The action's triggered() signal is connected to the
813     \a functor. The function adds the newly created
814     action to the menu's list of actions and returns it.
815 
816     QMenuBar takes ownership of the returned QAction.
817 
818     \sa QWidget::addAction(), QWidget::actions()
819 */
820 
821 /*!
822   Appends a new QMenu with \a title to the menu bar. The menu bar
823   takes ownership of the menu. Returns the new menu.
824 
825   \sa QWidget::addAction(), QMenu::menuAction()
826 */
addMenu(const QString & title)827 QMenu *QMenuBar::addMenu(const QString &title)
828 {
829     QMenu *menu = new QMenu(title, this);
830     addAction(menu->menuAction());
831     return menu;
832 }
833 
834 /*!
835   Appends a new QMenu with \a icon and \a title to the menu bar. The menu bar
836   takes ownership of the menu. Returns the new menu.
837 
838   \sa QWidget::addAction(), QMenu::menuAction()
839 */
addMenu(const QIcon & icon,const QString & title)840 QMenu *QMenuBar::addMenu(const QIcon &icon, const QString &title)
841 {
842     QMenu *menu = new QMenu(title, this);
843     menu->setIcon(icon);
844     addAction(menu->menuAction());
845     return menu;
846 }
847 
848 /*!
849     Appends \a menu to the menu bar. Returns the menu's menuAction(). The menu bar
850     does not take ownership of the menu.
851 
852     \note The returned QAction object can be used to hide the corresponding
853     menu.
854 
855     \sa QWidget::addAction(), QMenu::menuAction()
856 */
addMenu(QMenu * menu)857 QAction *QMenuBar::addMenu(QMenu *menu)
858 {
859     QAction *action = menu->menuAction();
860     addAction(action);
861     return action;
862 }
863 
864 /*!
865   Appends a separator to the menu.
866 */
addSeparator()867 QAction *QMenuBar::addSeparator()
868 {
869     QAction *ret = new QAction(this);
870     ret->setSeparator(true);
871     addAction(ret);
872     return ret;
873 }
874 
875 /*!
876     This convenience function creates a new separator action, i.e. an
877     action with QAction::isSeparator() returning true. The function inserts
878     the newly created action into this menu bar's list of actions before
879     action \a before and returns it.
880 
881     \sa QWidget::insertAction(), addSeparator()
882 */
insertSeparator(QAction * before)883 QAction *QMenuBar::insertSeparator(QAction *before)
884 {
885     QAction *action = new QAction(this);
886     action->setSeparator(true);
887     insertAction(before, action);
888     return action;
889 }
890 
891 /*!
892   This convenience function inserts \a menu before action \a before
893   and returns the menus menuAction().
894 
895   \sa QWidget::insertAction(), addMenu()
896 */
insertMenu(QAction * before,QMenu * menu)897 QAction *QMenuBar::insertMenu(QAction *before, QMenu *menu)
898 {
899     QAction *action = menu->menuAction();
900     insertAction(before, action);
901     return action;
902 }
903 
904 /*!
905   Returns the QAction that is currently highlighted, if any,
906   else \nullptr.
907 */
activeAction() const908 QAction *QMenuBar::activeAction() const
909 {
910     Q_D(const QMenuBar);
911     return d->currentAction;
912 }
913 
914 /*!
915     \since 4.1
916 
917     Sets the currently highlighted action to \a act.
918 */
setActiveAction(QAction * act)919 void QMenuBar::setActiveAction(QAction *act)
920 {
921     Q_D(QMenuBar);
922     d->setCurrentAction(act, true, false);
923 }
924 
925 
926 /*!
927     Removes all the actions from the menu bar.
928 
929     \note On \macos, menu items that have been merged to the system
930     menu bar are not removed by this function. One way to handle this
931     would be to remove the extra actions yourself. You can set the
932     \l{QAction::MenuRole}{menu role} on the different menus, so that
933     you know ahead of time which menu items get merged and which do
934     not. Then decide what to recreate or remove yourself.
935 
936     \sa removeAction()
937 */
clear()938 void QMenuBar::clear()
939 {
940     QList<QAction*> acts = actions();
941     for(int i = 0; i < acts.size(); i++)
942         removeAction(acts[i]);
943 }
944 
945 /*!
946     \property QMenuBar::defaultUp
947     \brief the popup orientation
948 
949     The default popup orientation. By default, menus pop "down" the
950     screen. By setting the property to true, the menu will pop "up".
951     You might call this for menus that are \e below the document to
952     which they refer.
953 
954     If the menu would not fit on the screen, the other direction is
955     used automatically.
956 */
setDefaultUp(bool b)957 void QMenuBar::setDefaultUp(bool b)
958 {
959     Q_D(QMenuBar);
960     d->defaultPopDown = !b;
961 }
962 
isDefaultUp() const963 bool QMenuBar::isDefaultUp() const
964 {
965     Q_D(const QMenuBar);
966     return !d->defaultPopDown;
967 }
968 
969 /*!
970   \reimp
971 */
resizeEvent(QResizeEvent *)972 void QMenuBar::resizeEvent(QResizeEvent *)
973 {
974     Q_D(QMenuBar);
975     d->itemsDirty = true;
976     d->updateGeometries();
977 }
978 
979 /*!
980   \reimp
981 */
paintEvent(QPaintEvent * e)982 void QMenuBar::paintEvent(QPaintEvent *e)
983 {
984     Q_D(QMenuBar);
985     QPainter p(this);
986     QRegion emptyArea(rect());
987 
988     //draw the items
989     for (int i = 0; i < d->actions.count(); ++i) {
990         QAction *action = d->actions.at(i);
991         QRect adjustedActionRect = d->actionRect(action);
992         if (adjustedActionRect.isEmpty() || !d->isVisible(action))
993             continue;
994         if(!e->rect().intersects(adjustedActionRect))
995             continue;
996 
997         emptyArea -= adjustedActionRect;
998         QStyleOptionMenuItem opt;
999         initStyleOption(&opt, action);
1000         opt.rect = adjustedActionRect;
1001         p.setClipRect(adjustedActionRect);
1002         style()->drawControl(QStyle::CE_MenuBarItem, &opt, &p, this);
1003     }
1004      //draw border
1005     if (int fw = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, nullptr, this)) {
1006         QRegion borderReg;
1007         borderReg += QRect(0, 0, fw, height()); //left
1008         borderReg += QRect(width()-fw, 0, fw, height()); //right
1009         borderReg += QRect(0, 0, width(), fw); //top
1010         borderReg += QRect(0, height()-fw, width(), fw); //bottom
1011         p.setClipRegion(borderReg);
1012         emptyArea -= borderReg;
1013         QStyleOptionFrame frame;
1014         frame.rect = rect();
1015         frame.palette = palette();
1016         frame.state = QStyle::State_None;
1017         frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, &frame);
1018         frame.midLineWidth = 0;
1019         style()->drawPrimitive(QStyle::PE_PanelMenuBar, &frame, &p, this);
1020     }
1021     p.setClipRegion(emptyArea);
1022     QStyleOptionMenuItem menuOpt;
1023     menuOpt.palette = palette();
1024     menuOpt.state = QStyle::State_None;
1025     menuOpt.menuItemType = QStyleOptionMenuItem::EmptyArea;
1026     menuOpt.checkType = QStyleOptionMenuItem::NotCheckable;
1027     menuOpt.rect = rect();
1028     menuOpt.menuRect = rect();
1029     style()->drawControl(QStyle::CE_MenuBarEmptyArea, &menuOpt, &p, this);
1030 }
1031 
1032 /*!
1033   \reimp
1034 */
setVisible(bool visible)1035 void QMenuBar::setVisible(bool visible)
1036 {
1037     if (isNativeMenuBar()) {
1038         if (!visible)
1039             QWidget::setVisible(false);
1040         return;
1041     }
1042     QWidget::setVisible(visible);
1043 }
1044 
1045 /*!
1046   \reimp
1047 */
mousePressEvent(QMouseEvent * e)1048 void QMenuBar::mousePressEvent(QMouseEvent *e)
1049 {
1050     Q_D(QMenuBar);
1051     if(e->button() != Qt::LeftButton)
1052         return;
1053 
1054     d->mouseDown = true;
1055 
1056     QAction *action = d->actionAt(e->pos());
1057     if (!action || !d->isVisible(action) || !action->isEnabled()) {
1058         d->setCurrentAction(nullptr);
1059 #if QT_CONFIG(whatsthis)
1060         if (QWhatsThis::inWhatsThisMode())
1061             QWhatsThis::showText(e->globalPos(), d->whatsThis, this);
1062 #endif
1063         return;
1064     }
1065 
1066     if(d->currentAction == action && d->popupState) {
1067         if(QMenu *menu = d->activeMenu) {
1068             d->activeMenu = nullptr;
1069             menu->setAttribute(Qt::WA_NoMouseReplay);
1070             menu->hide();
1071         }
1072     } else {
1073         d->setCurrentAction(action, true);
1074     }
1075 }
1076 
1077 /*!
1078   \reimp
1079 */
mouseReleaseEvent(QMouseEvent * e)1080 void QMenuBar::mouseReleaseEvent(QMouseEvent *e)
1081 {
1082     Q_D(QMenuBar);
1083     if(e->button() != Qt::LeftButton || !d->mouseDown)
1084         return;
1085 
1086     d->mouseDown = false;
1087     QAction *action = d->actionAt(e->pos());
1088 
1089     // do noting if the action is hidden
1090     if (!d->isVisible(action))
1091         return;
1092     if((d->closePopupMode && action == d->currentAction) || !action || !action->menu()) {
1093         //we set the current action before activating
1094         //so that we let the leave event set the current back to 0
1095         d->setCurrentAction(action, false);
1096         if(action)
1097             d->activateAction(action, QAction::Trigger);
1098     }
1099     d->closePopupMode = 0;
1100 }
1101 
1102 /*!
1103   \reimp
1104 */
keyPressEvent(QKeyEvent * e)1105 void QMenuBar::keyPressEvent(QKeyEvent *e)
1106 {
1107     Q_D(QMenuBar);
1108     d->updateGeometries();
1109     int key = e->key();
1110     if(isRightToLeft()) {  // in reverse mode open/close key for submenues are reversed
1111         if(key == Qt::Key_Left)
1112             key = Qt::Key_Right;
1113         else if(key == Qt::Key_Right)
1114             key = Qt::Key_Left;
1115     }
1116     if(key == Qt::Key_Tab) //means right
1117         key = Qt::Key_Right;
1118     else if(key == Qt::Key_Backtab) //means left
1119         key = Qt::Key_Left;
1120 
1121     bool key_consumed = false;
1122     switch(key) {
1123     case Qt::Key_Up:
1124     case Qt::Key_Down:
1125     case Qt::Key_Enter:
1126     case Qt::Key_Space:
1127     case Qt::Key_Return: {
1128         if (!style()->styleHint(QStyle::SH_MenuBar_AltKeyNavigation, nullptr, this) || !d->currentAction)
1129            break;
1130         if(d->currentAction->menu()) {
1131             d->popupAction(d->currentAction, true);
1132         } else if(key == Qt::Key_Enter || key == Qt::Key_Return || key == Qt::Key_Space) {
1133             d->activateAction(d->currentAction, QAction::Trigger);
1134             d->setCurrentAction(d->currentAction, false);
1135             d->setKeyboardMode(false);
1136         }
1137         key_consumed = true;
1138         break; }
1139 
1140     case Qt::Key_Right:
1141     case Qt::Key_Left: {
1142         if(d->currentAction) {
1143             int index = d->actions.indexOf(d->currentAction);
1144             if (QAction *nextAction = d->getNextAction(index, key == Qt::Key_Left ? -1 : +1)) {
1145                 d->setCurrentAction(nextAction, d->popupState, true);
1146                 key_consumed = true;
1147             }
1148         }
1149         break; }
1150 
1151     default:
1152         key_consumed = false;
1153     }
1154 
1155 #ifndef QT_NO_SHORTCUT
1156     if (!key_consumed && e->matches(QKeySequence::Cancel)) {
1157         d->setCurrentAction(nullptr);
1158         d->setKeyboardMode(false);
1159         key_consumed = true;
1160     }
1161 #endif
1162 
1163     if(!key_consumed &&
1164        (!e->modifiers() ||
1165         (e->modifiers()&(Qt::MetaModifier|Qt::AltModifier))) && e->text().length()==1 && !d->popupState) {
1166         int clashCount = 0;
1167         QAction *first = nullptr, *currentSelected = nullptr, *firstAfterCurrent = nullptr;
1168         {
1169             const QChar c = e->text().at(0).toUpper();
1170             for(int i = 0; i < d->actions.size(); ++i) {
1171                 if (d->actionRects.at(i).isNull())
1172                     continue;
1173                 QAction *act = d->actions.at(i);
1174                 QString s = act->text();
1175                 if(!s.isEmpty()) {
1176                     int ampersand = s.indexOf(QLatin1Char('&'));
1177                     if(ampersand >= 0) {
1178                         if(s[ampersand+1].toUpper() == c) {
1179                             clashCount++;
1180                             if(!first)
1181                                 first = act;
1182                             if(act == d->currentAction)
1183                                 currentSelected = act;
1184                             else if (!firstAfterCurrent && currentSelected)
1185                                 firstAfterCurrent = act;
1186                         }
1187                     }
1188                 }
1189             }
1190         }
1191         QAction *next_action = nullptr;
1192         if(clashCount >= 1) {
1193             if(clashCount == 1 || !d->currentAction || (currentSelected && !firstAfterCurrent))
1194                 next_action = first;
1195             else
1196                 next_action = firstAfterCurrent;
1197         }
1198         if(next_action) {
1199             key_consumed = true;
1200             d->setCurrentAction(next_action, true, true);
1201         }
1202     }
1203     if(key_consumed)
1204         e->accept();
1205     else
1206         e->ignore();
1207 }
1208 
1209 /*!
1210   \reimp
1211 */
mouseMoveEvent(QMouseEvent * e)1212 void QMenuBar::mouseMoveEvent(QMouseEvent *e)
1213 {
1214     Q_D(QMenuBar);
1215     if (!(e->buttons() & Qt::LeftButton)) {
1216         d->mouseDown = false;
1217         // We receive mouse move and mouse press on touch.
1218         // Mouse move will open the menu and mouse press
1219         // will close it, so ignore mouse move.
1220         if (e->source() != Qt::MouseEventNotSynthesized)
1221             return;
1222     }
1223 
1224     bool popupState = d->popupState || d->mouseDown;
1225     QAction *action = d->actionAt(e->pos());
1226     if ((action && d->isVisible(action)) || !popupState)
1227         d->setCurrentAction(action, popupState);
1228 }
1229 
1230 /*!
1231   \reimp
1232 */
leaveEvent(QEvent *)1233 void QMenuBar::leaveEvent(QEvent *)
1234 {
1235     Q_D(QMenuBar);
1236     if((!hasFocus() && !d->popupState) ||
1237         (d->currentAction && d->currentAction->menu() == nullptr))
1238         d->setCurrentAction(nullptr);
1239 }
1240 
getPlatformMenu(const QAction * action)1241 QPlatformMenu *QMenuBarPrivate::getPlatformMenu(const QAction *action)
1242 {
1243     if (!action || !action->menu())
1244         return nullptr;
1245 
1246     QPlatformMenu *platformMenu = action->menu()->platformMenu();
1247     if (!platformMenu && platformMenuBar) {
1248         platformMenu = platformMenuBar->createMenu();
1249         if (platformMenu)
1250             action->menu()->setPlatformMenu(platformMenu);
1251     }
1252 
1253     return platformMenu;
1254 }
1255 
findInsertionPlatformMenu(const QAction * action)1256 QPlatformMenu *QMenuBarPrivate::findInsertionPlatformMenu(const QAction *action)
1257 {
1258     Q_Q(QMenuBar);
1259     QPlatformMenu *beforeMenu = nullptr;
1260     for (int beforeIndex = indexOf(const_cast<QAction *>(action)) + 1;
1261          !beforeMenu && (beforeIndex < q->actions().size());
1262          ++beforeIndex) {
1263         beforeMenu = getPlatformMenu(q->actions().at(beforeIndex));
1264     }
1265 
1266     return beforeMenu;
1267 }
1268 
copyActionToPlatformMenu(const QAction * action,QPlatformMenu * menu)1269 void QMenuBarPrivate::copyActionToPlatformMenu(const QAction *action, QPlatformMenu *menu)
1270 {
1271     const auto tag = reinterpret_cast<quintptr>(action);
1272     if (menu->tag() != tag)
1273         menu->setTag(tag);
1274     menu->setText(action->text());
1275     menu->setVisible(action->isVisible());
1276     menu->setEnabled(action->isEnabled());
1277 }
1278 
1279 /*!
1280   \reimp
1281 */
actionEvent(QActionEvent * e)1282 void QMenuBar::actionEvent(QActionEvent *e)
1283 {
1284     Q_D(QMenuBar);
1285     d->itemsDirty = true;
1286 
1287     if (d->platformMenuBar) {
1288         QPlatformMenuBar *nativeMenuBar = d->platformMenuBar;
1289         if (!nativeMenuBar)
1290             return;
1291 
1292         if (e->type() == QEvent::ActionAdded) {
1293             QPlatformMenu *menu = d->getPlatformMenu(e->action());
1294             if (menu) {
1295                 d->copyActionToPlatformMenu(e->action(), menu);
1296 
1297                 QPlatformMenu *beforeMenu = d->findInsertionPlatformMenu(e->action());
1298                 d->platformMenuBar->insertMenu(menu, beforeMenu);
1299             }
1300         } else if (e->type() == QEvent::ActionRemoved) {
1301             QPlatformMenu *menu = d->getPlatformMenu(e->action());
1302             if (menu)
1303                 d->platformMenuBar->removeMenu(menu);
1304         } else if (e->type() == QEvent::ActionChanged) {
1305             QPlatformMenu *cur = d->platformMenuBar->menuForTag(reinterpret_cast<quintptr>(e->action()));
1306             QPlatformMenu *menu = d->getPlatformMenu(e->action());
1307 
1308             // the menu associated with the action can change, need to
1309             // remove and/or insert the new platform menu
1310             if (menu != cur) {
1311                 if (cur)
1312                     d->platformMenuBar->removeMenu(cur);
1313                 if (menu) {
1314                     d->copyActionToPlatformMenu(e->action(), menu);
1315 
1316                     QPlatformMenu *beforeMenu = d->findInsertionPlatformMenu(e->action());
1317                     d->platformMenuBar->insertMenu(menu, beforeMenu);
1318                 }
1319             } else if (menu) {
1320                 d->copyActionToPlatformMenu(e->action(), menu);
1321                 d->platformMenuBar->syncMenu(menu);
1322             }
1323         }
1324     }
1325 
1326     if(e->type() == QEvent::ActionAdded) {
1327         connect(e->action(), SIGNAL(triggered()), this, SLOT(_q_actionTriggered()));
1328         connect(e->action(), SIGNAL(hovered()), this, SLOT(_q_actionHovered()));
1329     } else if(e->type() == QEvent::ActionRemoved) {
1330         e->action()->disconnect(this);
1331     }
1332     // updateGeometries() is also needed for native menu bars because
1333     // it updates shortcutIndexMap
1334     if (isVisible() || isNativeMenuBar())
1335         d->updateGeometries();
1336     if (isVisible())
1337         update();
1338 }
1339 
1340 /*!
1341   \reimp
1342 */
focusInEvent(QFocusEvent *)1343 void QMenuBar::focusInEvent(QFocusEvent *)
1344 {
1345     Q_D(QMenuBar);
1346     if(d->keyboardState)
1347         d->focusFirstAction();
1348 }
1349 
1350 /*!
1351   \reimp
1352 */
focusOutEvent(QFocusEvent *)1353 void QMenuBar::focusOutEvent(QFocusEvent *)
1354 {
1355     Q_D(QMenuBar);
1356     if(!d->popupState) {
1357         d->setCurrentAction(nullptr);
1358         d->setKeyboardMode(false);
1359     }
1360 }
1361 
1362 /*!
1363   \reimp
1364  */
timerEvent(QTimerEvent * e)1365 void QMenuBar::timerEvent (QTimerEvent *e)
1366 {
1367     Q_D(QMenuBar);
1368     if (e->timerId() == d->autoReleaseTimer.timerId()) {
1369         d->autoReleaseTimer.stop();
1370         d->setCurrentAction(nullptr);
1371     }
1372     QWidget::timerEvent(e);
1373 }
1374 
1375 
handleReparent()1376 void QMenuBarPrivate::handleReparent()
1377 {
1378     Q_Q(QMenuBar);
1379     QWidget *newParent = q->parentWidget();
1380 
1381     //Note: if parent is reparented, then window may change even if parent doesn't.
1382     // We need to install an avent filter on each parent up to the parent that is
1383     // also a window (for shortcuts)
1384     QWidget *newWindow = newParent ? newParent->window() : nullptr;
1385 
1386     QVector<QPointer<QWidget> > newParents;
1387     // Remove event filters on ex-parents, keep them on still-parents
1388     // The parents are always ordered in the vector
1389     foreach (const QPointer<QWidget> &w, oldParents) {
1390         if (w) {
1391             if (newParent == w) {
1392                 newParents.append(w);
1393                 if (newParent != newWindow) //stop at the window
1394                     newParent = newParent->parentWidget();
1395             } else {
1396                 w->removeEventFilter(q);
1397             }
1398         }
1399     }
1400 
1401     // At this point, newParent is the next one to be added to newParents
1402     while (newParent && newParent != newWindow) {
1403         //install event filters all the way up to (excluding) the window
1404         newParents.append(newParent);
1405         newParent->installEventFilter(q);
1406         newParent = newParent->parentWidget();
1407     }
1408 
1409     if (newParent && newWindow) {
1410         // Install the event filter on the window
1411         newParents.append(newParent);
1412         newParent->installEventFilter(q);
1413     }
1414     oldParents = newParents;
1415 
1416     if (platformMenuBar) {
1417         if (newWindow) {
1418             // force the underlying platform window to be created, since
1419             // the platform menubar needs it (and we have no other way to
1420             // discover when the platform window is created)
1421             newWindow->createWinId();
1422             platformMenuBar->handleReparent(newWindow->windowHandle());
1423         } else {
1424             platformMenuBar->handleReparent(nullptr);
1425         }
1426     }
1427 }
1428 
1429 /*!
1430   \reimp
1431 */
changeEvent(QEvent * e)1432 void QMenuBar::changeEvent(QEvent *e)
1433 {
1434     Q_D(QMenuBar);
1435     if(e->type() == QEvent::StyleChange) {
1436         d->itemsDirty = true;
1437         setMouseTracking(style()->styleHint(QStyle::SH_MenuBar_MouseTracking, nullptr, this));
1438         if(parentWidget())
1439             resize(parentWidget()->width(), heightForWidth(parentWidget()->width()));
1440         d->updateGeometries();
1441     } else if (e->type() == QEvent::ParentChange) {
1442         d->handleReparent();
1443     } else if (e->type() == QEvent::FontChange
1444                || e->type() == QEvent::ApplicationFontChange) {
1445         d->itemsDirty = true;
1446         d->updateGeometries();
1447     }
1448 
1449     QWidget::changeEvent(e);
1450 }
1451 
1452 /*!
1453   \reimp
1454 */
event(QEvent * e)1455 bool QMenuBar::event(QEvent *e)
1456 {
1457     Q_D(QMenuBar);
1458     switch (e->type()) {
1459     case QEvent::KeyPress: {
1460         QKeyEvent *ke = (QKeyEvent*)e;
1461 #if 0
1462         if(!d->keyboardState) { //all keypresses..
1463             d->setCurrentAction(0);
1464             return ;
1465         }
1466 #endif
1467         if(ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab) {
1468             keyPressEvent(ke);
1469             return true;
1470         }
1471 
1472     } break;
1473 #ifndef QT_NO_SHORTCUT
1474     case QEvent::Shortcut: {
1475         QShortcutEvent *se = static_cast<QShortcutEvent *>(e);
1476         int shortcutId = se->shortcutId();
1477         for(int j = 0; j < d->shortcutIndexMap.size(); ++j) {
1478             if (shortcutId == d->shortcutIndexMap.value(j))
1479                 d->_q_internalShortcutActivated(j);
1480         }
1481     } break;
1482 #endif
1483     case QEvent::Show:
1484         d->_q_updateLayout();
1485     break;
1486 #ifndef QT_NO_SHORTCUT
1487     case QEvent::ShortcutOverride: {
1488         QKeyEvent *kev = static_cast<QKeyEvent*>(e);
1489         //we only filter out escape if there is a current action
1490         if (kev->matches(QKeySequence::Cancel) && d->currentAction) {
1491             e->accept();
1492             return true;
1493         }
1494     }
1495     break;
1496 #endif
1497 #if QT_CONFIG(whatsthis)
1498     case QEvent::QueryWhatsThis:
1499         e->setAccepted(d->whatsThis.size());
1500         if (QAction *action = d->actionAt(static_cast<QHelpEvent*>(e)->pos())) {
1501             if (action->whatsThis().size() || action->menu())
1502                 e->accept();
1503         }
1504         return true;
1505 #endif
1506     case QEvent::LayoutDirectionChange:
1507         d->_q_updateLayout();
1508         break;
1509     default:
1510         break;
1511     }
1512     return QWidget::event(e);
1513 }
1514 
1515 /*!
1516   \reimp
1517 */
eventFilter(QObject * object,QEvent * event)1518 bool QMenuBar::eventFilter(QObject *object, QEvent *event)
1519 {
1520     Q_D(QMenuBar);
1521     if (object && (event->type() == QEvent::ParentChange)) //GrandparentChange
1522             d->handleReparent();
1523 
1524     if (object == d->leftWidget || object == d->rightWidget) {
1525         switch (event->type()) {
1526         case QEvent::ShowToParent:
1527         case QEvent::HideToParent:
1528             d->_q_updateLayout();
1529             break;
1530         default:
1531             break;
1532         }
1533     }
1534 
1535     if (isNativeMenuBar() && event->type() == QEvent::ShowToParent) {
1536         // On some desktops like Unity, the D-Bus menu bar is unregistered
1537         // when the window is hidden. So when the window is shown, we need
1538         // to forcefully re-register it. The only way to force re-registering
1539         // with D-Bus menu is the handleReparent method.
1540         QWidget *widget = qobject_cast<QWidget *>(object);
1541         QWindow *handle = widget ? widget->windowHandle() : nullptr;
1542         if (handle != nullptr)
1543             d->platformMenuBar->handleReparent(handle);
1544     }
1545 
1546     if (style()->styleHint(QStyle::SH_MenuBar_AltKeyNavigation, nullptr, this)) {
1547         if (d->altPressed) {
1548             switch (event->type()) {
1549             case QEvent::KeyPress:
1550             case QEvent::KeyRelease:
1551             {
1552                 QKeyEvent *kev = static_cast<QKeyEvent*>(event);
1553                 if (kev->key() == Qt::Key_Alt || kev->key() == Qt::Key_Meta) {
1554                     if (event->type() == QEvent::KeyPress) // Alt-press does not interest us, we have the shortcut-override event
1555                         break;
1556                     d->setKeyboardMode(!d->keyboardState);
1557                 }
1558             }
1559             Q_FALLTHROUGH();
1560             case QEvent::MouseButtonPress:
1561             case QEvent::MouseButtonRelease:
1562             case QEvent::MouseMove:
1563             case QEvent::FocusIn:
1564             case QEvent::FocusOut:
1565             case QEvent::ActivationChange:
1566             case QEvent::Shortcut:
1567                 d->altPressed = false;
1568                 qApp->removeEventFilter(this);
1569                 break;
1570             default:
1571                 break;
1572             }
1573         } else if (isVisible()) {
1574             if (event->type() == QEvent::ShortcutOverride) {
1575                 QKeyEvent *kev = static_cast<QKeyEvent*>(event);
1576                 if ((kev->key() == Qt::Key_Alt || kev->key() == Qt::Key_Meta)
1577                     && kev->modifiers() == Qt::AltModifier) {
1578                     d->altPressed = true;
1579                     qApp->installEventFilter(this);
1580                 }
1581             }
1582         }
1583     }
1584 
1585     return false;
1586 }
1587 
1588 /*!
1589   Returns the QAction at \a pt. Returns \nullptr if there is no action at \a pt or if
1590 the location has a separator.
1591 
1592     \sa addAction(), addSeparator()
1593 */
actionAt(const QPoint & pt) const1594 QAction *QMenuBar::actionAt(const QPoint &pt) const
1595 {
1596     Q_D(const QMenuBar);
1597     return d->actionAt(pt);
1598 }
1599 
1600 /*!
1601   Returns the geometry of action \a act as a QRect.
1602 
1603     \sa actionAt()
1604 */
actionGeometry(QAction * act) const1605 QRect QMenuBar::actionGeometry(QAction *act) const
1606 {
1607     Q_D(const QMenuBar);
1608     return d->actionRect(act);
1609 }
1610 
1611 /*!
1612   \reimp
1613 */
minimumSizeHint() const1614 QSize QMenuBar::minimumSizeHint() const
1615 {
1616     Q_D(const QMenuBar);
1617     const bool as_gui_menubar = !isNativeMenuBar();
1618 
1619     ensurePolished();
1620     QSize ret(0, 0);
1621     const_cast<QMenuBarPrivate*>(d)->updateGeometries();
1622     const int hmargin = style()->pixelMetric(QStyle::PM_MenuBarHMargin, nullptr, this);
1623     const int vmargin = style()->pixelMetric(QStyle::PM_MenuBarVMargin, nullptr, this);
1624     int fw = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, nullptr, this);
1625     int spaceBelowMenuBar = style()->styleHint(QStyle::SH_MainWindow_SpaceBelowMenuBar, nullptr, this);
1626     if(as_gui_menubar) {
1627         int w = parentWidget() ? parentWidget()->width() : QDesktopWidgetPrivate::width();
1628         d->calcActionRects(w - (2 * fw), 0);
1629         for (int i = 0; ret.isNull() && i < d->actions.count(); ++i)
1630             ret = d->actionRects.at(i).size();
1631         if (!d->extension->isHidden())
1632             ret += QSize(d->extension->sizeHint().width(), 0);
1633         ret += QSize(2*fw + hmargin, 2*fw + vmargin);
1634     }
1635     int margin = 2*vmargin + 2*fw + spaceBelowMenuBar;
1636     if(d->leftWidget) {
1637         QSize sz = d->leftWidget->minimumSizeHint();
1638         ret.setWidth(ret.width() + sz.width());
1639         if(sz.height() + margin > ret.height())
1640             ret.setHeight(sz.height() + margin);
1641     }
1642     if(d->rightWidget) {
1643         QSize sz = d->rightWidget->minimumSizeHint();
1644         ret.setWidth(ret.width() + sz.width());
1645         if(sz.height() + margin > ret.height())
1646             ret.setHeight(sz.height() + margin);
1647     }
1648     if(as_gui_menubar) {
1649         QStyleOptionMenuItem opt;
1650         opt.rect = rect();
1651         opt.menuRect = rect();
1652         opt.state = QStyle::State_None;
1653         opt.menuItemType = QStyleOptionMenuItem::Normal;
1654         opt.checkType = QStyleOptionMenuItem::NotCheckable;
1655         opt.palette = palette();
1656         return (style()->sizeFromContents(QStyle::CT_MenuBar, &opt,
1657                                          ret.expandedTo(QApplication::globalStrut()),
1658                                          this));
1659     }
1660     return ret;
1661 }
1662 
1663 /*!
1664   \reimp
1665 */
sizeHint() const1666 QSize QMenuBar::sizeHint() const
1667 {
1668     Q_D(const QMenuBar);
1669     const bool as_gui_menubar = !isNativeMenuBar();
1670 
1671     ensurePolished();
1672     QSize ret(0, 0);
1673     const_cast<QMenuBarPrivate*>(d)->updateGeometries();
1674     const int hmargin = style()->pixelMetric(QStyle::PM_MenuBarHMargin, nullptr, this);
1675     const int vmargin = style()->pixelMetric(QStyle::PM_MenuBarVMargin, nullptr, this);
1676     int fw = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, nullptr, this);
1677     int spaceBelowMenuBar = style()->styleHint(QStyle::SH_MainWindow_SpaceBelowMenuBar, nullptr, this);
1678     if(as_gui_menubar) {
1679         const int w = parentWidget() ? parentWidget()->width() : QDesktopWidgetPrivate::width();
1680         d->calcActionRects(w - (2 * fw), 0);
1681         for (int i = 0; i < d->actionRects.count(); ++i) {
1682             const QRect &actionRect = d->actionRects.at(i);
1683             ret = ret.expandedTo(QSize(actionRect.x() + actionRect.width(), actionRect.y() + actionRect.height()));
1684         }
1685         //the action geometries already contain the top and left
1686         //margins. So we only need to add those from right and bottom.
1687         ret += QSize(fw + hmargin, fw + vmargin);
1688     }
1689     int margin = 2*vmargin + 2*fw + spaceBelowMenuBar;
1690     if(d->leftWidget) {
1691         QSize sz = d->leftWidget->sizeHint();
1692         sz.rheight() += margin;
1693         ret = ret.expandedTo(sz);
1694     }
1695     if(d->rightWidget) {
1696         QSize sz = d->rightWidget->sizeHint();
1697         ret.setWidth(ret.width() + sz.width());
1698         if(sz.height() + margin > ret.height())
1699             ret.setHeight(sz.height() + margin);
1700     }
1701     if(as_gui_menubar) {
1702         QStyleOptionMenuItem opt;
1703         opt.rect = rect();
1704         opt.menuRect = rect();
1705         opt.state = QStyle::State_None;
1706         opt.menuItemType = QStyleOptionMenuItem::Normal;
1707         opt.checkType = QStyleOptionMenuItem::NotCheckable;
1708         opt.palette = palette();
1709         return (style()->sizeFromContents(QStyle::CT_MenuBar, &opt,
1710                                          ret.expandedTo(QApplication::globalStrut()),
1711                                          this));
1712     }
1713     return ret;
1714 }
1715 
1716 /*!
1717   \reimp
1718 */
heightForWidth(int) const1719 int QMenuBar::heightForWidth(int) const
1720 {
1721     Q_D(const QMenuBar);
1722     const bool as_gui_menubar = !isNativeMenuBar();
1723 
1724     const_cast<QMenuBarPrivate*>(d)->updateGeometries();
1725     int height = 0;
1726     const int vmargin = style()->pixelMetric(QStyle::PM_MenuBarVMargin, nullptr, this);
1727     int fw = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, nullptr, this);
1728     int spaceBelowMenuBar = style()->styleHint(QStyle::SH_MainWindow_SpaceBelowMenuBar, nullptr, this);
1729     if(as_gui_menubar) {
1730         for (int i = 0; i < d->actionRects.count(); ++i)
1731             height = qMax(height, d->actionRects.at(i).height());
1732         if (height) //there is at least one non-null item
1733             height += spaceBelowMenuBar;
1734         height += 2*fw;
1735         height += 2*vmargin;
1736     }
1737     int margin = 2*vmargin + 2*fw + spaceBelowMenuBar;
1738     if(d->leftWidget)
1739         height = qMax(d->leftWidget->sizeHint().height() + margin, height);
1740     if(d->rightWidget)
1741         height = qMax(d->rightWidget->sizeHint().height() + margin, height);
1742     if(as_gui_menubar) {
1743         QStyleOptionMenuItem opt;
1744         opt.init(this);
1745         opt.menuRect = rect();
1746         opt.state = QStyle::State_None;
1747         opt.menuItemType = QStyleOptionMenuItem::Normal;
1748         opt.checkType = QStyleOptionMenuItem::NotCheckable;
1749         return style()->sizeFromContents(QStyle::CT_MenuBar, &opt, QSize(0, height), this).height(); //not pretty..
1750     }
1751     return height;
1752 }
1753 
1754 /*!
1755   \internal
1756 */
_q_internalShortcutActivated(int id)1757 void QMenuBarPrivate::_q_internalShortcutActivated(int id)
1758 {
1759     Q_Q(QMenuBar);
1760     QAction *act = actions.at(id);
1761     if (act && act->menu()) {
1762         if (QPlatformMenu *platformMenu = act->menu()->platformMenu()) {
1763             platformMenu->showPopup(q->windowHandle(), actionRects.at(id), nullptr);
1764             return;
1765         }
1766     }
1767 
1768     keyboardFocusWidget = QApplication::focusWidget();
1769     setCurrentAction(act, true, true);
1770     if (act && !act->menu()) {
1771         activateAction(act, QAction::Trigger);
1772         //100 is the same as the default value in QPushButton::animateClick
1773         autoReleaseTimer.start(100, q);
1774     } else if (act && q->style()->styleHint(QStyle::SH_MenuBar_AltKeyNavigation, nullptr, q)) {
1775         // When we open a menu using a shortcut, we should end up in keyboard state
1776         setKeyboardMode(true);
1777     }
1778 }
1779 
_q_updateLayout()1780 void QMenuBarPrivate::_q_updateLayout()
1781 {
1782     Q_Q(QMenuBar);
1783     itemsDirty = true;
1784     if (q->isVisible()) {
1785         updateGeometries();
1786         q->update();
1787     }
1788 }
1789 
1790 /*!
1791     \fn void QMenuBar::setCornerWidget(QWidget *widget, Qt::Corner corner)
1792 
1793     This sets the given \a widget to be shown directly on the left of the first
1794     menu item, or on the right of the last menu item, depending on \a corner.
1795 
1796     The menu bar takes ownership of \a widget, reparenting it into the menu bar.
1797     However, if the \a corner already contains a widget, this previous widget
1798     will no longer be managed and will still be a visible child of the menu bar.
1799 
1800    \note Using a corner other than Qt::TopRightCorner or Qt::TopLeftCorner
1801     will result in a warning.
1802 */
setCornerWidget(QWidget * w,Qt::Corner corner)1803 void QMenuBar::setCornerWidget(QWidget *w, Qt::Corner corner)
1804 {
1805     Q_D(QMenuBar);
1806     switch (corner) {
1807     case Qt::TopLeftCorner:
1808         if (d->leftWidget)
1809             d->leftWidget->removeEventFilter(this);
1810         d->leftWidget = w;
1811         break;
1812     case Qt::TopRightCorner:
1813         if (d->rightWidget)
1814             d->rightWidget->removeEventFilter(this);
1815         d->rightWidget = w;
1816         break;
1817     default:
1818         qWarning("QMenuBar::setCornerWidget: Only TopLeftCorner and TopRightCorner are supported");
1819         return;
1820     }
1821 
1822     if (w) {
1823         w->setParent(this);
1824         w->installEventFilter(this);
1825     }
1826 
1827     d->_q_updateLayout();
1828 }
1829 
1830 /*!
1831     Returns the widget on the left of the first or on the right of the last menu
1832     item, depending on \a corner.
1833 
1834    \note Using a corner other than Qt::TopRightCorner or Qt::TopLeftCorner
1835     will result in a warning.
1836 */
cornerWidget(Qt::Corner corner) const1837 QWidget *QMenuBar::cornerWidget(Qt::Corner corner) const
1838 {
1839     Q_D(const QMenuBar);
1840     QWidget *w = nullptr;
1841     switch(corner) {
1842     case Qt::TopLeftCorner:
1843         w = d->leftWidget;
1844         break;
1845     case Qt::TopRightCorner:
1846         w = d->rightWidget;
1847         break;
1848     default:
1849         qWarning("QMenuBar::cornerWidget: Only TopLeftCorner and TopRightCorner are supported");
1850         break;
1851     }
1852 
1853     return w;
1854 }
1855 
1856 /*!
1857     \property QMenuBar::nativeMenuBar
1858     \brief Whether or not a menubar will be used as a native menubar on platforms that support it
1859     \since 4.6
1860 
1861     This property specifies whether or not the menubar should be used as a native menubar on
1862     platforms that support it. The currently supported platforms are \macos, and
1863     Linux desktops which use the com.canonical.dbusmenu D-Bus interface (such as Ubuntu Unity).
1864     If this property is \c true, the menubar is used in the native menubar and is not in the window of
1865     its parent; if \c false the menubar remains in the window. On other platforms,
1866     setting this attribute has no effect, and reading this attribute will always return \c false.
1867 
1868     The default is to follow whether the Qt::AA_DontUseNativeMenuBar attribute
1869     is set for the application. Explicitly setting this property overrides
1870     the presence (or absence) of the attribute.
1871 */
1872 
setNativeMenuBar(bool nativeMenuBar)1873 void QMenuBar::setNativeMenuBar(bool nativeMenuBar)
1874 {
1875     Q_D(QMenuBar);
1876     if (nativeMenuBar != bool(d->platformMenuBar)) {
1877         if (!nativeMenuBar) {
1878             delete d->platformMenuBar;
1879             d->platformMenuBar = nullptr;
1880         } else {
1881             if (!d->platformMenuBar)
1882                 d->platformMenuBar = QGuiApplicationPrivate::platformTheme()->createPlatformMenuBar();
1883         }
1884 
1885         updateGeometry();
1886         if (!nativeMenuBar && parentWidget())
1887             setVisible(true);
1888     }
1889 }
1890 
isNativeMenuBar() const1891 bool QMenuBar::isNativeMenuBar() const
1892 {
1893     Q_D(const QMenuBar);
1894     return bool(d->platformMenuBar);
1895 }
1896 
1897 /*!
1898     \internal
1899 */
platformMenuBar()1900 QPlatformMenuBar *QMenuBar::platformMenuBar()
1901 {
1902     Q_D(const QMenuBar);
1903     return d->platformMenuBar;
1904 }
1905 
1906 /*!
1907     \fn void QMenuBar::triggered(QAction *action)
1908 
1909     This signal is emitted when an action in a menu belonging to this menubar
1910     is triggered as a result of a mouse click; \a action is the action that
1911     caused the signal to be emitted.
1912 
1913     \note QMenuBar has to have ownership of the QMenu in order this signal to work.
1914 
1915     Normally, you connect each menu action to a single slot using
1916     QAction::triggered(), but sometimes you will want to connect
1917     several items to a single slot (most often if the user selects
1918     from an array). This signal is useful in such cases.
1919 
1920     \sa hovered(), QAction::triggered()
1921 */
1922 
1923 /*!
1924     \fn void QMenuBar::hovered(QAction *action)
1925 
1926     This signal is emitted when a menu action is highlighted; \a action
1927     is the action that caused the event to be sent.
1928 
1929     Often this is used to update status information.
1930 
1931     \sa triggered(), QAction::hovered()
1932 */
1933 
1934 // for private slots
1935 
1936 QT_END_NAMESPACE
1937 
1938 #include <moc_qmenubar.cpp>
1939