aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/quickcontrols/qquickmenu/tst_qquickmenu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/quickcontrols/qquickmenu/tst_qquickmenu.cpp')
-rw-r--r--tests/auto/quickcontrols/qquickmenu/tst_qquickmenu.cpp240
1 files changed, 212 insertions, 28 deletions
diff --git a/tests/auto/quickcontrols/qquickmenu/tst_qquickmenu.cpp b/tests/auto/quickcontrols/qquickmenu/tst_qquickmenu.cpp
index fbb4e7d5f9..f54678b686 100644
--- a/tests/auto/quickcontrols/qquickmenu/tst_qquickmenu.cpp
+++ b/tests/auto/quickcontrols/qquickmenu/tst_qquickmenu.cpp
@@ -47,6 +47,10 @@ private slots:
void contextMenuKeyboard();
void disabledMenuItemKeyNavigation();
void mnemonics();
+#if QT_CONFIG(shortcut)
+ void checkableMnemonics_data();
+ void checkableMnemonics();
+#endif
void menuButton();
void addItem();
void menuSeparator();
@@ -87,9 +91,6 @@ private slots:
void customMenuCullItems();
void customMenuUseRepeaterAsTheContentItem();
void invalidUrlInImgTag();
-
-private:
- static bool hasWindowActivation();
};
tst_QQuickMenu::tst_QQuickMenu()
@@ -97,11 +98,6 @@ tst_QQuickMenu::tst_QQuickMenu()
{
}
-bool tst_QQuickMenu::hasWindowActivation()
-{
- return (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation));
-}
-
void tst_QQuickMenu::defaults()
{
QQuickControlsApplicationHelper helper(this, QLatin1String("applicationwindow.qml"));
@@ -146,8 +142,7 @@ void tst_QQuickMenu::count()
void tst_QQuickMenu::mouse()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
|| (QGuiApplication::platformName() == QLatin1String("minimal")))
@@ -278,8 +273,7 @@ void tst_QQuickMenu::pressAndHold()
void tst_QQuickMenu::contextMenuKeyboard()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
if (QGuiApplication::styleHints()->tabFocusBehavior() != Qt::TabFocusAllControls)
QSKIP("This platform only allows tab focus for text controls");
@@ -468,8 +462,7 @@ void tst_QQuickMenu::contextMenuKeyboard()
// QTBUG-70181
void tst_QQuickMenu::disabledMenuItemKeyNavigation()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
if (QGuiApplication::styleHints()->tabFocusBehavior() != Qt::TabFocusAllControls)
QSKIP("This platform only allows tab focus for text controls");
@@ -535,8 +528,7 @@ void tst_QQuickMenu::disabledMenuItemKeyNavigation()
void tst_QQuickMenu::mnemonics()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
#ifdef Q_OS_MACOS
QSKIP("Mnemonics are not used on macOS");
@@ -591,10 +583,207 @@ void tst_QQuickMenu::mnemonics()
QCOMPARE(subMenuItemSpy.size(), 1);
}
+#if QT_CONFIG(shortcut)
+namespace CheckableMnemonics {
+using MnemonicKey = std::pair<Qt::Key, QString>;
+
+enum class MenuItemType {
+ Action,
+ MenuItem
+};
+
+enum class SignalName {
+ CheckedChanged = 0x01,
+ Triggered = 0x02,
+};
+Q_DECLARE_FLAGS(SignalNames, SignalName);
+
+class ItemSignalSpy
+{
+public:
+ ItemSignalSpy(MenuItemType type, QObject *item) : item(item)
+ {
+ switch (type) {
+ case MenuItemType::Action:
+ initSignals<QQuickAction>(qobject_cast<QQuickAction *>(item));
+ break;
+ case MenuItemType::MenuItem:
+ initSignals<QQuickMenuItem>(qobject_cast<QQuickMenuItem *>(item));
+ break;
+ }
+ }
+
+ [[nodiscard]] bool isValid() const
+ {
+ return ((checkedChangedSpy && checkedChangedSpy->isValid()) &&
+ (triggeredSpy && triggeredSpy->isValid()));
+ }
+
+ [[nodiscard]] int signalSize(SignalName signal) const
+ {
+ constexpr int INVALID_SIZE = -1; // makes the test fail even when the signal is not expected
+ switch (signal) {
+ case SignalName::CheckedChanged:
+ return checkedChangedSpy ? checkedChangedSpy->size() : INVALID_SIZE;
+ case SignalName::Triggered:
+ return triggeredSpy ? triggeredSpy->size() : INVALID_SIZE;
+ }
+ Q_UNREACHABLE_RETURN(INVALID_SIZE);
+ }
+
+private:
+ template<typename Item>
+ void initSignals(Item *item)
+ {
+ checkedChangedSpy = std::make_unique<QSignalSpy>(item, &Item::checkedChanged);
+ triggeredSpy = std::make_unique<QSignalSpy>(item, &Item::triggered);
+ }
+
+private:
+ QPointer<QObject> item;
+ std::unique_ptr<QSignalSpy> checkedChangedSpy = nullptr;
+ std::unique_ptr<QSignalSpy> triggeredSpy = nullptr;
+};
+
+}
+
+void tst_QQuickMenu::checkableMnemonics_data()
+{
+ if (QKeySequence::mnemonic("&A").isEmpty())
+ QSKIP("Mnemonics are not enabled");
+
+ using namespace CheckableMnemonics;
+
+ QTest::addColumn<bool>("checkable");
+ QTest::addColumn<bool>("enabled");
+ QTest::addColumn<bool>("isSubMenu");
+ QTest::addColumn<MenuItemType>("itemType");
+ QTest::addColumn<MnemonicKey>("mnemonicKey");
+ QTest::addColumn<SignalNames>("expectedSignals");
+
+ QTest::addRow("checkable_enabled_action")
+ << true << true << false << MenuItemType::Action << MnemonicKey{Qt::Key_A, "A"}
+ << SignalNames{SignalName::Triggered, SignalName::CheckedChanged};
+ QTest::addRow("checkable_disabled_action")
+ << true << false << false << MenuItemType::Action << MnemonicKey{Qt::Key_A, "A"}
+ << SignalNames{};
+ QTest::addRow("uncheckable_enabled_action")
+ << false << true << false << MenuItemType::Action << MnemonicKey{Qt::Key_A, "A"}
+ << SignalNames{SignalName::Triggered};
+ QTest::addRow("uncheckable_disabled_action")
+ << false << false << false << MenuItemType::Action << MnemonicKey{Qt::Key_A, "A"}
+ << SignalNames{};
+
+ QTest::addRow("checkable_enabled_menuItem")
+ << true << true << false << MenuItemType::MenuItem << MnemonicKey{Qt::Key_I, "I"}
+ << SignalNames{SignalName::Triggered, SignalName::CheckedChanged};
+ QTest::addRow("checkable_disabled_menuItem")
+ << true << false << false << MenuItemType::MenuItem << MnemonicKey{Qt::Key_I, "I"}
+ << SignalNames{};
+ QTest::addRow("uncheckable_enabled_menuItem")
+ << false << true << false << MenuItemType::MenuItem << MnemonicKey{Qt::Key_I, "I"}
+ << SignalNames{SignalName::Triggered};
+ QTest::addRow("uncheckable_disabled_menuItem")
+ << false << false << false << MenuItemType::MenuItem << MnemonicKey{Qt::Key_I, "I"}
+ << SignalNames{};
+
+ QTest::addRow("checkable_enabled_subMenuItem")
+ << true << true << true << MenuItemType::MenuItem << MnemonicKey{Qt::Key_S, "S"}
+ << SignalNames{SignalName::Triggered, SignalName::CheckedChanged};
+ QTest::addRow("checkable_disabled_subMenuItem")
+ << true << false << true << MenuItemType::MenuItem << MnemonicKey{Qt::Key_S, "S"}
+ << SignalNames{};
+ QTest::addRow("uncheckable_enabled_subMenuItem")
+ << false << true << true << MenuItemType::MenuItem << MnemonicKey{Qt::Key_S, "S"}
+ << SignalNames{SignalName::Triggered};
+ QTest::addRow("uncheckable_disabled_subMenuItem")
+ << false << false << true << MenuItemType::MenuItem << MnemonicKey{Qt::Key_S, "S"}
+ << SignalNames{};
+
+ QTest::addRow("checkable_enabled_subMenuAction")
+ << true << true << true << MenuItemType::Action << MnemonicKey{Qt::Key_U, "U"}
+ << SignalNames{SignalName::Triggered, SignalName::CheckedChanged};
+ QTest::addRow("checkable_disabled_subMenuAction")
+ << true << false << true << MenuItemType::Action << MnemonicKey{Qt::Key_U, "U"}
+ << SignalNames{};
+ QTest::addRow("uncheckable_enabled_subMenuAction")
+ << false << true << true << MenuItemType::Action << MnemonicKey{Qt::Key_U, "U"}
+ << SignalNames{SignalName::Triggered};
+ QTest::addRow("uncheckable_disabled_subMenuAction")
+ << false << false << true << MenuItemType::Action << MnemonicKey{Qt::Key_U, "U"}
+ << SignalNames{};
+}
+
+// QTBUG-96630
+void tst_QQuickMenu::checkableMnemonics()
+{
+ using namespace CheckableMnemonics;
+
+ QFETCH(bool, checkable);
+ QFETCH(bool, enabled);
+ QFETCH(bool, isSubMenu);
+ QFETCH(MenuItemType, itemType);
+ QFETCH(MnemonicKey, mnemonicKey);
+ QFETCH(SignalNames, expectedSignals);
+
+ QQuickControlsApplicationHelper helper(this, QLatin1String("mnemonics.qml"));
+ QVERIFY2(helper.ready, helper.failureMessage());
+
+ QQuickWindow *window = helper.window;
+ window->show();
+ window->requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(window));
+
+ window->setProperty("checkable", checkable);
+ window->setProperty("enabled", enabled);
+
+ QQuickMenu *menu = window->property("menu").value<QQuickMenu *>();
+ QVERIFY(menu);
+
+ auto clickKey = [window](const MnemonicKey &mnemonic) mutable {
+ QTest::simulateEvent(window, true, mnemonic.first, Qt::NoModifier, mnemonic.second, false);
+ QTest::simulateEvent(window, false, mnemonic.first, Qt::NoModifier, mnemonic.second, false);
+ };
+
+ constexpr auto EMPTY_ITEM_NAME = "";
+ const char *itemName = EMPTY_ITEM_NAME;
+ switch (itemType) {
+ case MenuItemType::Action:
+ itemName = isSubMenu ? "subMenuAction" : "action";
+ break;
+ case MenuItemType::MenuItem:
+ itemName = isSubMenu ? "subMenuItem" : "menuItem";
+ break;
+ }
+ QCOMPARE_NE(itemName, EMPTY_ITEM_NAME);
+
+ QObject *menuItem = window->property(itemName).value<QObject*>();
+ QVERIFY(menuItem);
+
+ menu->open();
+ QTRY_VERIFY(menu->isOpened());
+
+ if (isSubMenu) {
+ QQuickMenu *subMenu = window->property("subMenu").value<QQuickMenu *>();
+ QVERIFY(subMenu);
+ clickKey(MnemonicKey{Qt::Key_M, "M"}); // "Sub &Menu"
+ QTRY_VERIFY(subMenu->isOpened());
+ }
+
+ const ItemSignalSpy itemSignalSpy(itemType, menuItem);
+ QVERIFY(itemSignalSpy.isValid());
+
+ clickKey(mnemonicKey);
+ QCOMPARE(itemSignalSpy.signalSize(SignalName::CheckedChanged),
+ expectedSignals & SignalName::CheckedChanged ? 1 : 0);
+ QCOMPARE(itemSignalSpy.signalSize(SignalName::Triggered),
+ expectedSignals & SignalName::Triggered ? 1 : 0);
+}
+#endif
+
void tst_QQuickMenu::menuButton()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
if (QGuiApplication::styleHints()->tabFocusBehavior() != Qt::TabFocusAllControls)
QSKIP("This platform only allows tab focus for text controls");
@@ -648,8 +837,7 @@ void tst_QQuickMenu::addItem()
void tst_QQuickMenu::menuSeparator()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QQuickControlsApplicationHelper helper(this, QLatin1String("menuSeparator.qml"));
QVERIFY2(helper.ready, helper.failureMessage());
@@ -1037,8 +1225,7 @@ void tst_QQuickMenu::actions()
#if QT_CONFIG(shortcut)
void tst_QQuickMenu::actionShortcuts()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QQuickControlsApplicationHelper helper(this, QLatin1String("actionShortcuts.qml"));
QVERIFY2(helper.ready, helper.failureMessage());
@@ -1332,8 +1519,7 @@ void tst_QQuickMenu::subMenuKeyboard_data()
void tst_QQuickMenu::subMenuKeyboard()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QFETCH(bool, cascade);
QFETCH(bool, mirrored);
@@ -1461,8 +1647,7 @@ void tst_QQuickMenu::subMenuDisabledKeyboard_data()
// QTBUG-69540
void tst_QQuickMenu::subMenuDisabledKeyboard()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QFETCH(bool, cascade);
QFETCH(bool, mirrored);
@@ -2050,8 +2235,7 @@ void tst_QQuickMenu::menuItemWidthAfterRetranslate()
void tst_QQuickMenu::giveMenuItemFocusOnButtonPress()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QQuickControlsApplicationHelper helper(this, QLatin1String("giveMenuItemFocusOnButtonPress.qml"));
QVERIFY2(helper.ready, helper.failureMessage());