diff options
Diffstat (limited to 'src/widgets/widgets/qmenubar.cpp')
-rw-r--r-- | src/widgets/widgets/qmenubar.cpp | 357 |
1 files changed, 138 insertions, 219 deletions
diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp index 5fd84f7f3b..c9c9191c17 100644 --- a/src/widgets/widgets/qmenubar.cpp +++ b/src/widgets/widgets/qmenubar.cpp @@ -1,48 +1,12 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWidgets module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include <qmenubar.h> #include <qstyle.h> #include <qlayout.h> #include <qapplication.h> -#ifndef QT_NO_ACCESSIBILITY +#if QT_CONFIG(accessibility) # include <qaccessible.h> #endif #include <qpainter.h> @@ -71,6 +35,8 @@ QT_BEGIN_NAMESPACE +using namespace Qt::StringLiterals; + class QMenuBarExtension : public QToolButton { public: @@ -83,7 +49,7 @@ public: QMenuBarExtension::QMenuBarExtension(QWidget *parent) : QToolButton(parent) { - setObjectName(QLatin1String("qt_menubar_ext_button")); + setObjectName("qt_menubar_ext_button"_L1); setAutoRaise(true); #if QT_CONFIG(menu) setPopupMode(QToolButton::InstantPopup); @@ -115,7 +81,7 @@ QSize QMenuBarExtension::sizeHint() const QAction *QMenuBarPrivate::actionAt(QPoint p) const { for(int i = 0; i < actions.size(); ++i) { - if(actionRect(actions.at(i)).contains(p)) + if (actionRect(actions.at(i)).contains(p)) return actions.at(i); } return nullptr; @@ -163,11 +129,11 @@ bool QMenuBarPrivate::isVisible(QAction *action) void QMenuBarPrivate::updateGeometries() { Q_Q(QMenuBar); - if(!itemsDirty) + if (!itemsDirty) return; int q_width = q->width()-(q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, nullptr, q)*2); int q_start = -1; - if(leftWidget || rightWidget) { + if (leftWidget || rightWidget) { int vmargin = q->style()->pixelMetric(QStyle::PM_MenuBarVMargin, nullptr, q) + q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, nullptr, q); int hmargin = q->style()->pixelMetric(QStyle::PM_MenuBarHMargin, nullptr, q) @@ -190,7 +156,7 @@ void QMenuBarPrivate::updateGeometries() } #ifdef Q_OS_MAC - if(q->isNativeMenuBar()) {//nothing to see here folks, move along.. + if (q->isNativeMenuBar()) {//nothing to see here folks, move along.. itemsDirty = false; return; } @@ -198,11 +164,11 @@ void QMenuBarPrivate::updateGeometries() calcActionRects(q_width, q_start); currentAction = nullptr; #ifndef QT_NO_SHORTCUT - if(itemsDirty) { + if (itemsDirty) { for(int j = 0; j < shortcutIndexMap.size(); ++j) q->releaseShortcut(shortcutIndexMap.value(j)); shortcutIndexMap.clear(); - const int actionsCount = actions.count(); + const int actionsCount = actions.size(); shortcutIndexMap.reserve(actionsCount); for (int i = 0; i < actionsCount; i++) shortcutIndexMap.append(q->grabShortcut(QKeySequence::mnemonic(actions.at(i)->text()))); @@ -216,7 +182,7 @@ void QMenuBarPrivate::updateGeometries() //we try to see if the actions will fit there bool hasHiddenActions = false; - for (int i = 0; i < actions.count(); ++i) { + for (int i = 0; i < actions.size(); ++i) { const QRect &rect = actionRects.at(i); if (rect.isValid() && !menuRect.contains(rect)) { hasHiddenActions = true; @@ -227,7 +193,7 @@ void QMenuBarPrivate::updateGeometries() //...and if not, determine the ones that fit on the menu with the extension visible if (hasHiddenActions) { menuRect = this->menuRect(true); - for (int i = 0; i < actions.count(); ++i) { + for (int i = 0; i < actions.size(); ++i) { const QRect &rect = actionRects.at(i); if (rect.isValid() && !menuRect.contains(rect)) { hiddenActions.append(actions.at(i)); @@ -235,7 +201,7 @@ void QMenuBarPrivate::updateGeometries() } } - if (hiddenActions.count() > 0) { + if (hiddenActions.size() > 0) { QMenu *pop = extension->menu(); if (!pop) { pop = new QMenu(q); @@ -263,7 +229,7 @@ QRect QMenuBarPrivate::actionRect(QAction *act) const //makes sure the geometries are up-to-date const_cast<QMenuBarPrivate*>(this)->updateGeometries(); - if (index < 0 || index >= actionRects.count()) + if (index < 0 || index >= actionRects.size()) return QRect(); // that can happen in case of native menubar return actionRects.at(index); @@ -271,11 +237,11 @@ QRect QMenuBarPrivate::actionRect(QAction *act) const void QMenuBarPrivate::focusFirstAction() { - if(!currentAction) { + if (!currentAction) { updateGeometries(); int index = 0; - while (index < actions.count() && actionRects.at(index).isNull()) ++index; - if (index < actions.count()) + while (index < actions.size() && actionRects.at(index).isNull()) ++index; + if (index < actions.size()) setCurrentAction(actions.at(index)); } } @@ -288,16 +254,16 @@ void QMenuBarPrivate::setKeyboardMode(bool b) return; } keyboardState = b; - if(b) { + if (b) { QWidget *fw = QApplication::focusWidget(); if (fw && fw != q && fw->window() != QApplication::activePopupWidget()) keyboardFocusWidget = fw; focusFirstAction(); q->setFocus(Qt::MenuBarFocusReason); } else { - if(!popupState) + if (!popupState) setCurrentAction(nullptr); - if(keyboardFocusWidget) { + if (keyboardFocusWidget) { if (QApplication::focusWidget() == q) keyboardFocusWidget->setFocus(Qt::MenuBarFocusReason); keyboardFocusWidget = nullptr; @@ -309,23 +275,34 @@ void QMenuBarPrivate::setKeyboardMode(bool b) void QMenuBarPrivate::popupAction(QAction *action, bool activateFirst) { Q_Q(QMenuBar); - if(!action || !action->menu() || closePopupMode) + if (!action || !action->menu() || closePopupMode) return; popupState = true; if (action->isEnabled() && action->menu()->isEnabled()) { closePopupMode = 0; activeMenu = action->menu(); - activeMenu->d_func()->causedPopup.widget = q; - activeMenu->d_func()->causedPopup.action = action; + auto *activeMenuPriv = activeMenu->d_func(); + activeMenuPriv->causedPopup.widget = q; + activeMenuPriv->causedPopup.action = action; QRect adjustedActionRect = actionRect(action); - QPoint pos(q->mapToGlobal(QPoint(adjustedActionRect.left(), adjustedActionRect.bottom() + 1))); - QSize popup_size = activeMenu->sizeHint(); + QPoint popupPos = adjustedActionRect.bottomLeft() + QPoint(0, 1); + //we put the popup menu on the screen containing the bottom-center of the action rect QScreen *menubarScreen = q->window()->windowHandle()->screen(); - QScreen *popupScreen = menubarScreen->virtualSiblingAt(pos + QPoint(adjustedActionRect.width() / 2, 0)); + QPoint screenTestPos = q->mapToGlobal(popupPos + QPoint(adjustedActionRect.width() / 2, 0)); + QPointer<QScreen> popupScreen = menubarScreen->virtualSiblingAt(screenTestPos); if (!popupScreen) popupScreen = menubarScreen; + std::swap(popupScreen, activeMenuPriv->popupScreen); + const QSize popup_size = activeMenu->sizeHint(); + std::swap(popupScreen, activeMenuPriv->popupScreen); + + // Use screenTestPos.y() for the popup y position. This is the correct global y + // consistent with the selected screen in cases where the action rect spans + // multiple screens with different scale factors. + QPoint pos(q->mapToGlobal(popupPos).x(), screenTestPos.y()); + QRect screenRect = popupScreen->geometry(); pos = QPoint(qMax(pos.x(), screenRect.x()), qMax(pos.y(), screenRect.y())); const bool fitUp = (pos.y() - popup_size.height() >= screenRect.top()); @@ -351,11 +328,11 @@ void QMenuBarPrivate::popupAction(QAction *action, bool activateFirst) pos.rx() += actionWidth; } - if(!defaultPopDown || (fitUp && !fitDown)) + if (!defaultPopDown || (fitUp && !fitDown)) pos.setY(qMax(screenRect.y(), q->mapToGlobal(QPoint(0, adjustedActionRect.top()-popup_size.height())).y())); QMenuPrivate::get(activeMenu)->topData()->initialScreen = popupScreen; activeMenu->popup(pos); - if(activateFirst) + if (activateFirst) activeMenu->d_func()->setFirstActionActive(); } q->update(actionRect(action)); @@ -363,7 +340,7 @@ void QMenuBarPrivate::popupAction(QAction *action, bool activateFirst) void QMenuBarPrivate::setCurrentAction(QAction *action, bool popup, bool activateFirst) { - if(currentAction == action && popup == popupState) + if (currentAction == action && popup == popupState) return; autoReleaseTimer.stop(); @@ -371,7 +348,7 @@ void QMenuBarPrivate::setCurrentAction(QAction *action, bool popup, bool activat doChildEffects = (popup && !activeMenu); Q_Q(QMenuBar); QWidget *fw = nullptr; - if(QMenu *menu = activeMenu) { + if (QMenu *menu = activeMenu) { activeMenu = nullptr; if (popup) { fw = q->window()->focusWidget(); @@ -380,7 +357,7 @@ void QMenuBarPrivate::setCurrentAction(QAction *action, bool popup, bool activat menu->hide(); } - if(currentAction) + if (currentAction) q->update(actionRect(currentAction)); popupState = popup; @@ -390,7 +367,7 @@ void QMenuBarPrivate::setCurrentAction(QAction *action, bool popup, bool activat currentAction = action; if (action && action->isEnabled()) { activateAction(action, QAction::Hover); - if(popup) + if (popup) popupAction(action, activateFirst); q->update(actionRect(action)); #if QT_CONFIG(statustip) @@ -408,11 +385,11 @@ void QMenuBarPrivate::calcActionRects(int max_width, int start) const { Q_Q(const QMenuBar); - if(!itemsDirty) + if (!itemsDirty) return; //let's reinitialize the buffer - actionRects.resize(actions.count()); + actionRects.resize(actions.size()); actionRects.fill(QRect()); const QStyle *style = q->style(); @@ -425,15 +402,15 @@ void QMenuBarPrivate::calcActionRects(int max_width, int start) const const int hmargin = style->pixelMetric(QStyle::PM_MenuBarHMargin, nullptr, q), vmargin = style->pixelMetric(QStyle::PM_MenuBarVMargin, nullptr, q), icone = style->pixelMetric(QStyle::PM_SmallIconSize, nullptr, q); - for(int i = 0; i < actions.count(); i++) { + for(int i = 0; i < actions.size(); i++) { QAction *action = actions.at(i); - if(!action->isVisible()) + if (!action->isVisible()) continue; QSize sz; //calc what I think the size is.. - if(action->isSeparator()) { + if (action->isSeparator()) { if (style->styleHint(QStyle::SH_DrawMenuBarSeparator, nullptr, q)) separator = i; continue; //we don't really position these! @@ -452,10 +429,10 @@ void QMenuBarPrivate::calcActionRects(int max_width, int start) const q->initStyleOption(&opt, action); sz = q->style()->sizeFromContents(QStyle::CT_MenuBarItem, &opt, sz, q); - if(!sz.isEmpty()) { + if (!sz.isEmpty()) { { //update the separator state int iWidth = sz.width() + itemSpacing; - if(separator == -1) + if (separator == -1) separator_start += iWidth; else separator_len += iWidth; @@ -471,7 +448,7 @@ void QMenuBarPrivate::calcActionRects(int max_width, int start) const const int fw = q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, nullptr, q); int x = fw + ((start == -1) ? hmargin : start) + itemSpacing; int y = fw + vmargin; - for(int i = 0; i < actions.count(); i++) { + for(int i = 0; i < actions.size(); i++) { QRect &rect = actionRects[i]; if (rect.isNull()) continue; @@ -480,9 +457,9 @@ void QMenuBarPrivate::calcActionRects(int max_width, int start) const rect.setHeight(max_item_height); //move - if(separator != -1 && i >= separator) { //after the separator + if (separator != -1 && i >= separator) { //after the separator int left = (max_width - separator_len - hmargin - itemSpacing) + (x - separator_start - hmargin); - if(left < separator_start) { //wrap + if (left < separator_start) { //wrap separator_start = x = hmargin; y += max_item_height; } @@ -509,9 +486,9 @@ void QMenuBarPrivate::activateAction(QAction *action, QAction::ActionEvent actio if (action_e == QAction::Hover) action->showStatusText(q); -// if(action_e == QAction::Trigger) +// if (action_e == QAction::Trigger) // emit q->activated(action); -// else if(action_e == QAction::Hover) +// else if (action_e == QAction::Hover) // emit q->highlighted(action); } @@ -529,14 +506,14 @@ void QMenuBarPrivate::_q_actionHovered() Q_Q(QMenuBar); if (QAction *action = qobject_cast<QAction *>(q->sender())) { emit q->hovered(action); -#ifndef QT_NO_ACCESSIBILITY +#if QT_CONFIG(accessibility) if (QAccessible::isActive()) { int actionIndex = actions.indexOf(action); QAccessibleEvent focusEvent(q, QAccessible::Focus); focusEvent.setChild(actionIndex); QAccessible::updateAccessibility(&focusEvent); } -#endif //QT_NO_ACCESSIBILITY +#endif // QT_CONFIG(accessibility) } } @@ -581,7 +558,7 @@ void QMenuBar::initStyleOption(QStyleOptionMenuItem *option, const QAction *acti \inmodule QtWidgets A menu bar consists of a list of pull-down menu items. You add - menu items with addMenu(). For example, asuming that \c menubar + menu items with addMenu(). For example, assuming that \c menubar is a pointer to a QMenuBar and \c fileMenu is a pointer to a QMenu, the following statement inserts the menu into the menu bar: \snippet code/src_gui_widgets_qmenubar.cpp 0 @@ -630,11 +607,13 @@ void QMenuBar::initStyleOption(QStyleOptionMenuItem *option, const QAction *acti Qt for \macos also provides a menu bar merging feature to make QMenuBar conform more closely to accepted \macos menu bar layout. - The merging functionality is based on string matching the title of - a QMenu entry. These strings are translated (using QObject::tr()) - in the "QMenuBar" context. If an entry is moved its slots will still - fire as if it was in the original place. The table below outlines - the strings looked for and where the entry is placed if matched: + If an entry is moved its slots will still fire as if it was in the + original place. + + The merging functionality is based on the QAction::menuRole() of + the menu entries. If an item has QAction::TextHeuristicRole, + the role is determined by string matching the title using the + following heuristics: \table \header \li String matches \li Placement \li Notes @@ -652,8 +631,8 @@ void QMenuBar::initStyleOption(QStyleOptionMenuItem *option, const QAction *acti created to call QCoreApplication::quit() \endtable - You can override this behavior by using the QAction::menuRole() - property. + You can override this behavior by setting the QAction::menuRole() + property to QAction::NoRole. If you want all windows in a Mac application to share one menu bar, you must create a menu bar that does not have a parent. @@ -684,7 +663,7 @@ void QMenuBar::initStyleOption(QStyleOptionMenuItem *option, const QAction *acti \sa QMenu, QShortcut, QAction, {http://developer.apple.com/documentation/UserExperience/Conceptual/AppleHIGuidelines/XHIGIntro/XHIGIntro.html}{Introduction to Apple Human Interface Guidelines}, - {fowler}{GUI Design Handbook: Menu Bar}, {Menus Example} + {Menus Example} */ @@ -714,8 +693,8 @@ QAction *QMenuBarPrivate::getNextAction(const int _start, const int increment) c Q_Q(const QMenuBar); const_cast<QMenuBarPrivate*>(this)->updateGeometries(); bool allowActiveAndDisabled = q->style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, nullptr, q); - const int start = (_start == -1 && increment == -1) ? actions.count() : _start; - const int end = increment == -1 ? 0 : actions.count() - 1; + const int start = (_start == -1 && increment == -1) ? actions.size() : _start; + const int end = increment == -1 ? 0 : actions.size() - 1; for (int i = start; i != end;) { i += increment; @@ -751,72 +730,6 @@ QMenuBar::~QMenuBar() } /*! - This convenience function creates a new action with \a text. - The function adds the newly created action to the menu's - list of actions, and returns it. - - \sa QWidget::addAction(), QWidget::actions() -*/ -QAction *QMenuBar::addAction(const QString &text) -{ - QAction *ret = new QAction(text, this); - addAction(ret); - return ret; -} - -/*! - \overload - - This convenience function creates a new action with the given \a - text. The action's triggered() signal is connected to the \a - receiver's \a member slot. The function adds the newly created - action to the menu's list of actions and returns it. - - \sa QWidget::addAction(), QWidget::actions() -*/ -QAction *QMenuBar::addAction(const QString &text, const QObject *receiver, const char* member) -{ - QAction *ret = new QAction(text, this); - QObject::connect(ret, SIGNAL(triggered(bool)), receiver, member); - addAction(ret); - return ret; -} - -/*! - \fn template<typename Obj, typename PointerToMemberFunctionOrFunctor> QAction *QMenuBar::addAction(const QString &text, const Obj *receiver, PointerToMemberFunctionOrFunctor method) - - \since 5.11 - - \overload - - This convenience function creates a new action with the given \a - text. The action's triggered() signal is connected to the - \a method of the \a receiver. The function adds the newly created - action to the menu's list of actions and returns it. - - QMenuBar takes ownership of the returned QAction. - - \sa QWidget::addAction(), QWidget::actions() -*/ - -/*! - \fn template<typename Functor> QAction *QMenuBar::addAction(const QString &text, Functor functor) - - \since 5.11 - - \overload - - This convenience function creates a new action with the given \a - text. The action's triggered() signal is connected to the - \a functor. The function adds the newly created - action to the menu's list of actions and returns it. - - QMenuBar takes ownership of the returned QAction. - - \sa QWidget::addAction(), QWidget::actions() -*/ - -/*! Appends a new QMenu with \a title to the menu bar. The menu bar takes ownership of the menu. Returns the new menu. @@ -984,12 +897,12 @@ void QMenuBar::paintEvent(QPaintEvent *e) QRegion emptyArea(rect()); //draw the items - for (int i = 0; i < d->actions.count(); ++i) { + for (int i = 0; i < d->actions.size(); ++i) { QAction *action = d->actions.at(i); QRect adjustedActionRect = d->actionRect(action); if (adjustedActionRect.isEmpty() || !d->isVisible(action)) continue; - if(!e->rect().intersects(adjustedActionRect)) + if (!e->rect().intersects(adjustedActionRect)) continue; emptyArea -= adjustedActionRect; @@ -1012,7 +925,7 @@ void QMenuBar::paintEvent(QPaintEvent *e) frame.rect = rect(); frame.palette = palette(); frame.state = QStyle::State_None; - frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, &frame); + frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, &frame, this); frame.midLineWidth = 0; style()->drawPrimitive(QStyle::PE_PanelMenuBar, &frame, &p, this); } @@ -1046,7 +959,7 @@ void QMenuBar::setVisible(bool visible) void QMenuBar::mousePressEvent(QMouseEvent *e) { Q_D(QMenuBar); - if(e->button() != Qt::LeftButton) + if (e->button() != Qt::LeftButton) return; d->mouseDown = true; @@ -1061,8 +974,8 @@ void QMenuBar::mousePressEvent(QMouseEvent *e) return; } - if(d->currentAction == action && d->popupState) { - if(QMenu *menu = d->activeMenu) { + if (d->currentAction == action && d->popupState) { + if (QMenu *menu = d->activeMenu) { d->activeMenu = nullptr; menu->setAttribute(Qt::WA_NoMouseReplay); menu->hide(); @@ -1078,7 +991,7 @@ void QMenuBar::mousePressEvent(QMouseEvent *e) void QMenuBar::mouseReleaseEvent(QMouseEvent *e) { Q_D(QMenuBar); - if(e->button() != Qt::LeftButton || !d->mouseDown) + if (e->button() != Qt::LeftButton || !d->mouseDown) return; d->mouseDown = false; @@ -1087,11 +1000,11 @@ void QMenuBar::mouseReleaseEvent(QMouseEvent *e) // do noting if the action is hidden if (!d->isVisible(action)) return; - if((d->closePopupMode && action == d->currentAction) || !action || !action->menu()) { + if ((d->closePopupMode && action == d->currentAction) || !action || !action->menu()) { //we set the current action before activating //so that we let the leave event set the current back to 0 d->setCurrentAction(action, false); - if(action) + if (action) d->activateAction(action, QAction::Trigger); } d->closePopupMode = 0; @@ -1105,15 +1018,15 @@ void QMenuBar::keyPressEvent(QKeyEvent *e) Q_D(QMenuBar); d->updateGeometries(); int key = e->key(); - if(isRightToLeft()) { // in reverse mode open/close key for submenues are reversed - if(key == Qt::Key_Left) + if (isRightToLeft()) { // in reverse mode open/close key for submenues are reversed + if (key == Qt::Key_Left) key = Qt::Key_Right; - else if(key == Qt::Key_Right) + else if (key == Qt::Key_Right) key = Qt::Key_Left; } - if(key == Qt::Key_Tab) //means right + if (key == Qt::Key_Tab) //means right key = Qt::Key_Right; - else if(key == Qt::Key_Backtab) //means left + else if (key == Qt::Key_Backtab) //means left key = Qt::Key_Left; bool key_consumed = false; @@ -1125,9 +1038,9 @@ void QMenuBar::keyPressEvent(QKeyEvent *e) case Qt::Key_Return: { if (!style()->styleHint(QStyle::SH_MenuBar_AltKeyNavigation, nullptr, this) || !d->currentAction) break; - if(d->currentAction->menu()) { + if (d->currentAction->menu()) { d->popupAction(d->currentAction, true); - } else if(key == Qt::Key_Enter || key == Qt::Key_Return || key == Qt::Key_Space) { + } else if (key == Qt::Key_Enter || key == Qt::Key_Return || key == Qt::Key_Space) { d->activateAction(d->currentAction, QAction::Trigger); d->setCurrentAction(d->currentAction, false); d->setKeyboardMode(false); @@ -1137,7 +1050,7 @@ void QMenuBar::keyPressEvent(QKeyEvent *e) case Qt::Key_Right: case Qt::Key_Left: { - if(d->currentAction) { + if (d->currentAction) { int index = d->actions.indexOf(d->currentAction); if (QAction *nextAction = d->getNextAction(index, key == Qt::Key_Left ? -1 : +1)) { d->setCurrentAction(nextAction, d->popupState, true); @@ -1158,9 +1071,9 @@ void QMenuBar::keyPressEvent(QKeyEvent *e) } #endif - if(!key_consumed && + if (!key_consumed && (!e->modifiers() || - (e->modifiers()&(Qt::MetaModifier|Qt::AltModifier))) && e->text().length()==1 && !d->popupState) { + (e->modifiers()&(Qt::MetaModifier|Qt::AltModifier))) && e->text().size()==1 && !d->popupState) { int clashCount = 0; QAction *first = nullptr, *currentSelected = nullptr, *firstAfterCurrent = nullptr; { @@ -1170,14 +1083,14 @@ void QMenuBar::keyPressEvent(QKeyEvent *e) continue; QAction *act = d->actions.at(i); QString s = act->text(); - if(!s.isEmpty()) { - int ampersand = s.indexOf(QLatin1Char('&')); - if(ampersand >= 0) { - if(s[ampersand+1].toUpper() == c) { + if (!s.isEmpty()) { + qsizetype ampersand = s.indexOf(u'&'); + if (ampersand >= 0) { + if (s[ampersand+1].toUpper() == c) { clashCount++; - if(!first) + if (!first) first = act; - if(act == d->currentAction) + if (act == d->currentAction) currentSelected = act; else if (!firstAfterCurrent && currentSelected) firstAfterCurrent = act; @@ -1187,18 +1100,18 @@ void QMenuBar::keyPressEvent(QKeyEvent *e) } } QAction *next_action = nullptr; - if(clashCount >= 1) { - if(clashCount == 1 || !d->currentAction || (currentSelected && !firstAfterCurrent)) + if (clashCount >= 1) { + if (clashCount == 1 || !d->currentAction || (currentSelected && !firstAfterCurrent)) next_action = first; else next_action = firstAfterCurrent; } - if(next_action) { + if (next_action) { key_consumed = true; d->setCurrentAction(next_action, true, true); } } - if(key_consumed) + if (key_consumed) e->accept(); else e->ignore(); @@ -1231,7 +1144,7 @@ void QMenuBar::mouseMoveEvent(QMouseEvent *e) void QMenuBar::leaveEvent(QEvent *) { Q_D(QMenuBar); - if((!hasFocus() && !d->popupState) || + if ((!hasFocus() && !d->popupState) || (d->currentAction && d->currentAction->menu() == nullptr)) d->setCurrentAction(nullptr); } @@ -1322,10 +1235,10 @@ void QMenuBar::actionEvent(QActionEvent *e) } } - if(e->type() == QEvent::ActionAdded) { + if (e->type() == QEvent::ActionAdded) { connect(e->action(), SIGNAL(triggered()), this, SLOT(_q_actionTriggered())); connect(e->action(), SIGNAL(hovered()), this, SLOT(_q_actionHovered())); - } else if(e->type() == QEvent::ActionRemoved) { + } else if (e->type() == QEvent::ActionRemoved) { e->action()->disconnect(this); } // updateGeometries() is also needed for native menu bars because @@ -1342,7 +1255,7 @@ void QMenuBar::actionEvent(QActionEvent *e) void QMenuBar::focusInEvent(QFocusEvent *) { Q_D(QMenuBar); - if(d->keyboardState) + if (d->keyboardState) d->focusFirstAction(); } @@ -1352,7 +1265,7 @@ void QMenuBar::focusInEvent(QFocusEvent *) void QMenuBar::focusOutEvent(QFocusEvent *) { Q_D(QMenuBar); - if(!d->popupState) { + if (!d->popupState) { d->setCurrentAction(nullptr); d->setKeyboardMode(false); } @@ -1385,7 +1298,12 @@ void QMenuBarPrivate::handleReparent() QList<QPointer<QWidget>> newParents; // Remove event filters on ex-parents, keep them on still-parents // The parents are always ordered in the vector - foreach (const QPointer<QWidget> &w, oldParents) { + // + // Take a copy because this method is called from changeEvent() and eventFilter(), + // which might cause recursion into the class due to event processing, which might + // modify oldParents. + const auto copy = oldParents; + for (const QPointer<QWidget> &w : copy) { if (w) { if (newParent == w) { newParents.append(w); @@ -1431,10 +1349,10 @@ void QMenuBarPrivate::handleReparent() void QMenuBar::changeEvent(QEvent *e) { Q_D(QMenuBar); - if(e->type() == QEvent::StyleChange) { + if (e->type() == QEvent::StyleChange) { d->itemsDirty = true; setMouseTracking(style()->styleHint(QStyle::SH_MenuBar_MouseTracking, nullptr, this)); - if(parentWidget()) + if (parentWidget()) resize(parentWidget()->width(), heightForWidth(parentWidget()->width())); d->updateGeometries(); } else if (e->type() == QEvent::ParentChange) { @@ -1456,14 +1374,14 @@ bool QMenuBar::event(QEvent *e) Q_D(QMenuBar); switch (e->type()) { case QEvent::KeyPress: { - QKeyEvent *ke = (QKeyEvent*)e; + QKeyEvent *ke = static_cast<QKeyEvent *>(e); #if 0 - if(!d->keyboardState) { //all keypresses.. + if (!d->keyboardState) { //all keypresses.. d->setCurrentAction(0); return ; } #endif - if(ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab) { + if (ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab) { keyPressEvent(ke); return true; } @@ -1484,7 +1402,7 @@ bool QMenuBar::event(QEvent *e) break; #ifndef QT_NO_SHORTCUT case QEvent::ShortcutOverride: { - QKeyEvent *kev = static_cast<QKeyEvent*>(e); + QKeyEvent *kev = static_cast<QKeyEvent *>(e); //we only filter out escape if there is a current action if (kev->matches(QKeySequence::Cancel) && d->currentAction) { e->accept(); @@ -1588,7 +1506,7 @@ bool QMenuBar::eventFilter(QObject *object, QEvent *event) Returns the QAction at \a pt. Returns \nullptr if there is no action at \a pt or if the location has a separator. - \sa addAction(), addSeparator() + \sa QWidget::addAction(), addSeparator() */ QAction *QMenuBar::actionAt(const QPoint &pt) const { @@ -1622,29 +1540,29 @@ QSize QMenuBar::minimumSizeHint() const const int vmargin = style()->pixelMetric(QStyle::PM_MenuBarVMargin, nullptr, this); int fw = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, nullptr, this); int spaceBelowMenuBar = style()->styleHint(QStyle::SH_MainWindow_SpaceBelowMenuBar, nullptr, this); - if(as_gui_menubar) { + if (as_gui_menubar) { int w = parentWidget() ? parentWidget()->width() : QGuiApplication::primaryScreen()->virtualGeometry().width(); d->calcActionRects(w - (2 * fw), 0); - for (int i = 0; ret.isNull() && i < d->actions.count(); ++i) + for (int i = 0; ret.isNull() && i < d->actions.size(); ++i) ret = d->actionRects.at(i).size(); if (!d->extension->isHidden()) ret += QSize(d->extension->sizeHint().width(), 0); ret += QSize(2*fw + hmargin, 2*fw + vmargin); } int margin = 2*vmargin + 2*fw + spaceBelowMenuBar; - if(d->leftWidget) { + if (d->leftWidget) { QSize sz = d->leftWidget->minimumSizeHint(); ret.setWidth(ret.width() + sz.width()); - if(sz.height() + margin > ret.height()) + if (sz.height() + margin > ret.height()) ret.setHeight(sz.height() + margin); } - if(d->rightWidget) { + if (d->rightWidget) { QSize sz = d->rightWidget->minimumSizeHint(); ret.setWidth(ret.width() + sz.width()); - if(sz.height() + margin > ret.height()) + if (sz.height() + margin > ret.height()) ret.setHeight(sz.height() + margin); } - if(as_gui_menubar) { + if (as_gui_menubar) { QStyleOptionMenuItem opt; opt.rect = rect(); opt.menuRect = rect(); @@ -1672,10 +1590,10 @@ QSize QMenuBar::sizeHint() const const int vmargin = style()->pixelMetric(QStyle::PM_MenuBarVMargin, nullptr, this); int fw = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, nullptr, this); int spaceBelowMenuBar = style()->styleHint(QStyle::SH_MainWindow_SpaceBelowMenuBar, nullptr, this); - if(as_gui_menubar) { + if (as_gui_menubar) { const int w = parentWidget() ? parentWidget()->width() : QGuiApplication::primaryScreen()->virtualGeometry().width(); d->calcActionRects(w - (2 * fw), 0); - for (int i = 0; i < d->actionRects.count(); ++i) { + for (int i = 0; i < d->actionRects.size(); ++i) { const QRect &actionRect = d->actionRects.at(i); ret = ret.expandedTo(QSize(actionRect.x() + actionRect.width(), actionRect.y() + actionRect.height())); } @@ -1684,18 +1602,18 @@ QSize QMenuBar::sizeHint() const ret += QSize(fw + hmargin, fw + vmargin); } int margin = 2*vmargin + 2*fw + spaceBelowMenuBar; - if(d->leftWidget) { + if (d->leftWidget) { QSize sz = d->leftWidget->sizeHint(); sz.rheight() += margin; ret = ret.expandedTo(sz); } - if(d->rightWidget) { + if (d->rightWidget) { QSize sz = d->rightWidget->sizeHint(); ret.setWidth(ret.width() + sz.width()); - if(sz.height() + margin > ret.height()) + if (sz.height() + margin > ret.height()) ret.setHeight(sz.height() + margin); } - if(as_gui_menubar) { + if (as_gui_menubar) { QStyleOptionMenuItem opt; opt.rect = rect(); opt.menuRect = rect(); @@ -1721,8 +1639,8 @@ int QMenuBar::heightForWidth(int) const const int vmargin = style()->pixelMetric(QStyle::PM_MenuBarVMargin, nullptr, this); int fw = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, nullptr, this); int spaceBelowMenuBar = style()->styleHint(QStyle::SH_MainWindow_SpaceBelowMenuBar, nullptr, this); - if(as_gui_menubar) { - for (int i = 0; i < d->actionRects.count(); ++i) + if (as_gui_menubar) { + for (int i = 0; i < d->actionRects.size(); ++i) height = qMax(height, d->actionRects.at(i).height()); if (height) //there is at least one non-null item height += spaceBelowMenuBar; @@ -1730,11 +1648,11 @@ int QMenuBar::heightForWidth(int) const height += 2*vmargin; } int margin = 2*vmargin + 2*fw + spaceBelowMenuBar; - if(d->leftWidget) + if (d->leftWidget) height = qMax(d->leftWidget->sizeHint().height() + margin, height); - if(d->rightWidget) + if (d->rightWidget) height = qMax(d->rightWidget->sizeHint().height() + margin, height); - if(as_gui_menubar) { + if (as_gui_menubar) { QStyleOptionMenuItem opt; opt.initFrom(this); opt.menuRect = rect(); @@ -1872,6 +1790,7 @@ void QMenuBar::setNativeMenuBar(bool nativeMenuBar) if (!nativeMenuBar) { delete d->platformMenuBar; d->platformMenuBar = nullptr; + d->itemsDirty = true; } else { if (!d->platformMenuBar) d->platformMenuBar = QGuiApplicationPrivate::platformTheme()->createPlatformMenuBar(); |