From b4669b919048c1dbdac2b3e9b2e79f3d023aa078 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Wed, 26 Feb 2020 16:59:52 +0100 Subject: QMenu: hide when a QWidgetAction fires the trigged signal QMenu hides regularly when the user interacts with it, and manages the firing of signals based on that. It ignores if a QAction that is added to it fires the triggered() signal programmatically. With QWidgetActions added to the menu, the menu usually doesn't get interacted with directly, as the widget gets the input events. Since the action can be added to multiple menus, neither widget nor action can interact with the menus programmatically. Instead, the menu needs to hide when the widget action triggers. Test included that covers the case where a QWidgetAction is added to multiple menus that are visible. Documentation updated, and removed a redudant paragraph as a drive-by change. [ChangeLog][QtWidgets][QMenu] a popup menu hides when a QWidgetAction added to it fires the triggered signal. Change-Id: I69f378426a45c2e46cebdaa5e6f1b21c8fb03633 Fixes: QTBUG-10427 Reviewed-by: Richard Moe Gustavsen --- tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp | 79 ++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) (limited to 'tests/auto/widgets/widgets/qmenu') diff --git a/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp b/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp index d7d3a934f8..7e39138473 100644 --- a/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp +++ b/tests/auto/widgets/widgets/qmenu/tst_qmenu.cpp @@ -116,6 +116,7 @@ private slots: void QTBUG20403_nested_popup_on_shortcut_trigger(); void QTBUG47515_widgetActionEnterLeave(); void QTBUG8122_widgetActionCrashOnClose(); + void widgetActionTriggerClosesMenu(); void QTBUG_10735_crashWithDialog(); #ifdef Q_OS_MAC @@ -1407,6 +1408,84 @@ void tst_QMenu::QTBUG8122_widgetActionCrashOnClose() QTRY_VERIFY(menu->isHidden()); } +/*! + Test that a QWidgetAction that fires closes the menus that it is in. +*/ +void tst_QMenu::widgetActionTriggerClosesMenu() +{ + class ButtonAction : public QWidgetAction + { + public: + ButtonAction() + : QWidgetAction(nullptr) + {} + + void click() + { + if (pushButton) + pushButton->click(); + } + + protected: + QWidget *createWidget(QWidget *parent) + { + QPushButton *button = new QPushButton(QLatin1String("Button"), parent); + connect(button, &QPushButton::clicked, this, &QAction::trigger); + + if (!pushButton) + pushButton = button; + return button; + } + + private: + QPointer pushButton; + }; + + QMenu menu; + QMenu submenu; + + int menuTriggeredCount = 0; + int menuAboutToHideCount = 0; + QAction *actionTriggered = nullptr; + + connect(&menu, &QMenu::triggered, this, [&](QAction *action){ + ++menuTriggeredCount; + actionTriggered = action; + }); + connect (&menu, &QMenu::aboutToHide, this, [&](){ + ++menuAboutToHideCount; + }); + + QAction regularAction(QLatin1String("Action")); + ButtonAction widgetAction; + + submenu.addAction(®ularAction); + submenu.addAction(&widgetAction); + + menu.addMenu(&submenu); + menu.addAction(®ularAction); + menu.addAction(&widgetAction); + + menu.popup(QPoint(200,200)); + submenu.popup(QPoint(250,250)); + if (!QTest::qWaitForWindowExposed(&menu) || !QTest::qWaitForWindowExposed(&submenu)) + QSKIP("Failed to show menus, aborting test"); + + regularAction.trigger(); + QVERIFY(menu.isVisible()); + QVERIFY(submenu.isVisible()); + QCOMPARE(menuTriggeredCount, 1); + QCOMPARE(actionTriggered, ®ularAction); + menuTriggeredCount = 0; + actionTriggered = nullptr; + + widgetAction.click(); + QVERIFY(!menu.isVisible()); + QVERIFY(!submenu.isVisible()); + QCOMPARE(menuTriggeredCount, 1); + QCOMPARE(menuAboutToHideCount, 1); + QCOMPARE(actionTriggered, &widgetAction); +} class MyMenu : public QMenu { -- cgit v1.2.3