| 1 | /**************************************************************************** |
| 2 | ** |
| 3 | ** Copyright (C) 2017 The Qt Company Ltd. |
| 4 | ** Contact: http://www.qt.io/licensing/ |
| 5 | ** |
| 6 | ** This file is part of the test suite of the Qt Toolkit. |
| 7 | ** |
| 8 | ** $QT_BEGIN_LICENSE:LGPL3$ |
| 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 http://www.qt.io/terms-conditions. For further |
| 15 | ** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free |
| 28 | ** Software Foundation and appearing in the file LICENSE.GPL included in |
| 29 | ** the packaging of this file. Please review the following information to |
| 30 | ** ensure the GNU General Public License version 2.0 requirements will be |
| 31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. |
| 32 | ** |
| 33 | ** $QT_END_LICENSE$ |
| 34 | ** |
| 35 | ****************************************************************************/ |
| 36 | |
| 37 | #include <QtTest> |
| 38 | #include <QtQml> |
| 39 | #include "../shared/util.h" |
| 40 | #include "../shared/visualtestutil.h" |
| 41 | #include "../shared/qtest_quickcontrols.h" |
| 42 | |
| 43 | #include <QtQuickTemplates2/private/qquickapplicationwindow_p.h> |
| 44 | #include <QtQuickTemplates2/private/qquickmenu_p.h> |
| 45 | #include <QtQuickTemplates2/private/qquickmenubar_p.h> |
| 46 | #include <QtQuickTemplates2/private/qquickmenubaritem_p.h> |
| 47 | #include <QtQuickTemplates2/private/qquickmenuitem_p.h> |
| 48 | |
| 49 | using namespace QQuickVisualTestUtil; |
| 50 | |
| 51 | class : public QQmlDataTest |
| 52 | { |
| 53 | Q_OBJECT |
| 54 | |
| 55 | public: |
| 56 | |
| 57 | private slots: |
| 58 | void delegate(); |
| 59 | void mouse(); |
| 60 | void keys(); |
| 61 | void mnemonics(); |
| 62 | void addRemove(); |
| 63 | void checkHighlightWhenMenuDismissed(); |
| 64 | }; |
| 65 | |
| 66 | void tst_qquickmenubar::() |
| 67 | { |
| 68 | QQmlApplicationEngine engine(testFileUrl(fileName: "empty.qml" )); |
| 69 | QScopedPointer<QQuickMenuBar> (qobject_cast<QQuickMenuBar *>(object: engine.rootObjects().value(i: 0))); |
| 70 | QVERIFY(menuBar); |
| 71 | |
| 72 | QQmlComponent *delegate = menuBar->delegate(); |
| 73 | QVERIFY(delegate); |
| 74 | |
| 75 | QScopedPointer<QQuickMenuBarItem> item(qobject_cast<QQuickMenuBarItem *>(object: delegate->create())); |
| 76 | QVERIFY(item); |
| 77 | } |
| 78 | |
| 79 | void tst_qquickmenubar::() |
| 80 | { |
| 81 | if ((QGuiApplication::platformName() == QLatin1String("offscreen" )) |
| 82 | || (QGuiApplication::platformName() == QLatin1String("minimal" ))) |
| 83 | QSKIP("Mouse highlight not functional on offscreen/minimal platforms" ); |
| 84 | |
| 85 | QQmlApplicationEngine engine(testFileUrl(fileName: "menubar.qml" )); |
| 86 | |
| 87 | QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(object: engine.rootObjects().value(i: 0))); |
| 88 | QVERIFY(window); |
| 89 | |
| 90 | centerOnScreen(window: window.data()); |
| 91 | moveMouseAway(window: window.data()); |
| 92 | QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| 93 | |
| 94 | QQuickMenuBar * = window->property(name: "header" ).value<QQuickMenuBar *>(); |
| 95 | QVERIFY(menuBar); |
| 96 | |
| 97 | QQuickMenu * = menuBar->menuAt(index: 0); |
| 98 | QQuickMenu * = menuBar->menuAt(index: 1); |
| 99 | QQuickMenu * = menuBar->menuAt(index: 2); |
| 100 | QQuickMenu * = menuBar->menuAt(index: 3); |
| 101 | QVERIFY(fileMenuBarMenu && editMenuBarMenu && viewMenuBarMenu && helpMenuBarMenu); |
| 102 | |
| 103 | QQuickMenuBarItem * = qobject_cast<QQuickMenuBarItem *>(object: fileMenuBarMenu->parentItem()); |
| 104 | QQuickMenuBarItem * = qobject_cast<QQuickMenuBarItem *>(object: editMenuBarMenu->parentItem()); |
| 105 | QQuickMenuBarItem * = qobject_cast<QQuickMenuBarItem *>(object: viewMenuBarMenu->parentItem()); |
| 106 | QQuickMenuBarItem * = qobject_cast<QQuickMenuBarItem *>(object: helpMenuBarMenu->parentItem()); |
| 107 | QVERIFY(fileMenuBarItem && editMenuBarItem && viewMenuBarItem && helpMenuBarItem); |
| 108 | |
| 109 | // highlight a menubar item |
| 110 | QTest::mouseMove(window: window.data(), pos: fileMenuBarItem->mapToScene(point: QPointF(fileMenuBarItem->width() / 2, fileMenuBarItem->height() / 2)).toPoint()); |
| 111 | QVERIFY(fileMenuBarItem->isHighlighted()); |
| 112 | QVERIFY(!fileMenuBarMenu->isVisible()); |
| 113 | |
| 114 | // highlight another menubar item |
| 115 | QTest::mouseMove(window: window.data(), pos: editMenuBarItem->mapToScene(point: QPointF(editMenuBarItem->width() / 2, editMenuBarItem->height() / 2)).toPoint()); |
| 116 | QVERIFY(!fileMenuBarItem->isHighlighted()); |
| 117 | QVERIFY(editMenuBarItem->isHighlighted()); |
| 118 | QVERIFY(!fileMenuBarMenu->isVisible()); |
| 119 | QVERIFY(!editMenuBarMenu->isVisible()); |
| 120 | |
| 121 | // trigger a menubar item to open a menu |
| 122 | QTest::mouseClick(window: window.data(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: editMenuBarItem->mapToScene(point: QPointF(editMenuBarItem->width() / 2, editMenuBarItem->height() / 2)).toPoint()); |
| 123 | QVERIFY(editMenuBarItem->isHighlighted()); |
| 124 | QVERIFY(editMenuBarMenu->isVisible()); |
| 125 | QTRY_VERIFY(editMenuBarMenu->isOpened()); |
| 126 | |
| 127 | // re-trigger a menubar item to hide the menu |
| 128 | QTest::mouseClick(window: window.data(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: editMenuBarItem->mapToScene(point: QPointF(editMenuBarItem->width() / 2, editMenuBarItem->height() / 2)).toPoint()); |
| 129 | QVERIFY(editMenuBarItem->isHighlighted()); |
| 130 | QVERIFY(editMenuBarItem->hasActiveFocus()); |
| 131 | QTRY_VERIFY(!editMenuBarMenu->isVisible()); |
| 132 | |
| 133 | // re-trigger a menubar item to show the menu again |
| 134 | QTest::mouseClick(window: window.data(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: editMenuBarItem->mapToScene(point: QPointF(editMenuBarItem->width() / 2, editMenuBarItem->height() / 2)).toPoint()); |
| 135 | QVERIFY(editMenuBarItem->isHighlighted()); |
| 136 | QVERIFY(editMenuBarMenu->isVisible()); |
| 137 | QTRY_VERIFY(editMenuBarMenu->isOpened()); |
| 138 | |
| 139 | // highlight another menubar item to open another menu |
| 140 | QTest::mouseMove(window: window.data(), pos: helpMenuBarItem->mapToScene(point: QPointF(helpMenuBarItem->width() / 2, helpMenuBarItem->height() / 2)).toPoint()); |
| 141 | QVERIFY(!fileMenuBarItem->isHighlighted()); |
| 142 | QVERIFY(!editMenuBarItem->isHighlighted()); |
| 143 | QVERIFY(!viewMenuBarItem->isHighlighted()); |
| 144 | QVERIFY(helpMenuBarItem->isHighlighted()); |
| 145 | QVERIFY(!fileMenuBarMenu->isVisible()); |
| 146 | QVERIFY(!viewMenuBarMenu->isVisible()); |
| 147 | QVERIFY(helpMenuBarMenu->isVisible()); |
| 148 | QTRY_VERIFY(!editMenuBarMenu->isVisible()); |
| 149 | QTRY_VERIFY(helpMenuBarMenu->isOpened()); |
| 150 | |
| 151 | // trigger a menu item to close the menu |
| 152 | QQuickMenuItem * = qobject_cast<QQuickMenuItem *>(object: helpMenuBarMenu->itemAt(index: 0)); |
| 153 | QVERIFY(aboutMenuItem); |
| 154 | QTest::mouseClick(window: window.data(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: aboutMenuItem->mapToScene(point: QPointF(aboutMenuItem->width() / 2, aboutMenuItem->height() / 2)).toPoint()); |
| 155 | QVERIFY(!helpMenuBarItem->isHighlighted()); |
| 156 | QTRY_VERIFY(!helpMenuBarMenu->isVisible()); |
| 157 | |
| 158 | // highlight a menubar item |
| 159 | QTest::mouseMove(window: window.data(), pos: editMenuBarItem->mapToScene(point: QPointF(editMenuBarItem->width() / 2, editMenuBarItem->height() / 2)).toPoint()); |
| 160 | QVERIFY(editMenuBarItem->isHighlighted()); |
| 161 | QVERIFY(!helpMenuBarItem->isHighlighted()); |
| 162 | QVERIFY(!editMenuBarMenu->isVisible()); |
| 163 | QVERIFY(!helpMenuBarMenu->isVisible()); |
| 164 | |
| 165 | // trigger a menubar item to open a menu |
| 166 | QTest::mouseClick(window: window.data(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: viewMenuBarItem->mapToScene(point: QPointF(viewMenuBarItem->width() / 2, viewMenuBarItem->height() / 2)).toPoint()); |
| 167 | QVERIFY(!editMenuBarItem->isHighlighted()); |
| 168 | QVERIFY(viewMenuBarItem->isHighlighted()); |
| 169 | QVERIFY(viewMenuBarMenu->isVisible()); |
| 170 | QTRY_VERIFY(viewMenuBarMenu->isOpened()); |
| 171 | |
| 172 | // trigger a menu item to open a sub-menu |
| 173 | QQuickMenuItem * = qobject_cast<QQuickMenuItem *>(object: viewMenuBarMenu->itemAt(index: 0)); |
| 174 | QVERIFY(alignmentSubMenuItem); |
| 175 | QQuickMenu * = alignmentSubMenuItem->subMenu(); |
| 176 | QVERIFY(alignmentSubMenu); |
| 177 | QTest::mouseClick(window: window.data(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: alignmentSubMenuItem->mapToScene(point: QPointF(alignmentSubMenuItem->width() / 2, alignmentSubMenuItem->height() / 2)).toPoint()); |
| 178 | QVERIFY(viewMenuBarMenu->isVisible()); |
| 179 | QVERIFY(alignmentSubMenu->isVisible()); |
| 180 | QTRY_VERIFY(alignmentSubMenu->isOpened()); |
| 181 | |
| 182 | // trigger a menu item to open a sub-sub-menu |
| 183 | QQuickMenuItem * = qobject_cast<QQuickMenuItem *>(object: alignmentSubMenu->itemAt(index: 1)); |
| 184 | QVERIFY(verticalSubMenuItem); |
| 185 | QQuickMenu * = verticalSubMenuItem->subMenu(); |
| 186 | QVERIFY(verticalSubMenu); |
| 187 | QTest::mouseClick(window: window.data(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: verticalSubMenuItem->mapToScene(point: QPointF(verticalSubMenuItem->width() / 2, verticalSubMenuItem->height() / 2)).toPoint()); |
| 188 | QVERIFY(viewMenuBarMenu->isVisible()); |
| 189 | QVERIFY(alignmentSubMenu->isVisible()); |
| 190 | QVERIFY(verticalSubMenu->isVisible()); |
| 191 | QTRY_VERIFY(verticalSubMenu->isOpened()); |
| 192 | |
| 193 | // trigger a menu item to close the whole chain of menus |
| 194 | QQuickMenuItem * = qobject_cast<QQuickMenuItem *>(object: verticalSubMenu->itemAt(index: 1)); |
| 195 | QVERIFY(centerMenuItem); |
| 196 | QTest::mouseClick(window: window.data(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: centerMenuItem->mapToScene(point: QPointF(centerMenuItem->width() / 2, centerMenuItem->height() / 2)).toPoint()); |
| 197 | QVERIFY(!viewMenuBarItem->isHighlighted()); |
| 198 | QTRY_VERIFY(!viewMenuBarMenu->isVisible()); |
| 199 | QTRY_VERIFY(!alignmentSubMenu->isVisible()); |
| 200 | QTRY_VERIFY(!verticalSubMenu->isVisible()); |
| 201 | |
| 202 | // re-highlight the same menubar item |
| 203 | QTest::mouseMove(window: window.data(), pos: viewMenuBarItem->mapToScene(point: QPointF(viewMenuBarItem->width() / 2, viewMenuBarItem->height() / 2)).toPoint()); |
| 204 | QVERIFY(viewMenuBarItem->isHighlighted()); |
| 205 | |
| 206 | // re-open the chain of menus |
| 207 | QTest::mouseClick(window: window.data(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: viewMenuBarItem->mapToScene(point: QPointF(viewMenuBarItem->width() / 2, viewMenuBarItem->height() / 2)).toPoint()); |
| 208 | QTRY_VERIFY(viewMenuBarMenu->isOpened()); |
| 209 | QTest::mouseClick(window: window.data(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: alignmentSubMenuItem->mapToScene(point: QPointF(alignmentSubMenuItem->width() / 2, alignmentSubMenuItem->height() / 2)).toPoint()); |
| 210 | QTRY_VERIFY(alignmentSubMenu->isOpened()); |
| 211 | QTest::mouseClick(window: window.data(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: verticalSubMenuItem->mapToScene(point: QPointF(verticalSubMenuItem->width() / 2, verticalSubMenuItem->height() / 2)).toPoint()); |
| 212 | QTRY_VERIFY(verticalSubMenu->isOpened()); |
| 213 | |
| 214 | // click outside to close the whole chain of menus |
| 215 | QTest::mouseClick(window: window.data(), button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(window->width() - 1, window->height() - 1)); |
| 216 | QVERIFY(!viewMenuBarItem->isHighlighted()); |
| 217 | QTRY_VERIFY(!viewMenuBarMenu->isVisible()); |
| 218 | QTRY_VERIFY(!alignmentSubMenu->isVisible()); |
| 219 | QTRY_VERIFY(!verticalSubMenu->isVisible()); |
| 220 | } |
| 221 | |
| 222 | void tst_qquickmenubar::() |
| 223 | { |
| 224 | QQmlApplicationEngine engine(testFileUrl(fileName: "menubar.qml" )); |
| 225 | |
| 226 | QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(object: engine.rootObjects().value(i: 0))); |
| 227 | QVERIFY(window); |
| 228 | |
| 229 | centerOnScreen(window: window.data()); |
| 230 | moveMouseAway(window: window.data()); |
| 231 | QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| 232 | |
| 233 | QQuickMenuBar * = window->property(name: "header" ).value<QQuickMenuBar *>(); |
| 234 | QVERIFY(menuBar); |
| 235 | |
| 236 | QQuickMenu * = menuBar->menuAt(index: 0); |
| 237 | QQuickMenu * = menuBar->menuAt(index: 1); |
| 238 | QQuickMenu * = menuBar->menuAt(index: 2); |
| 239 | QQuickMenu * = menuBar->menuAt(index: 3); |
| 240 | QVERIFY(fileMenuBarMenu && editMenuBarMenu && viewMenuBarMenu && helpMenuBarMenu); |
| 241 | |
| 242 | QQuickMenuBarItem * = qobject_cast<QQuickMenuBarItem *>(object: fileMenuBarMenu->parentItem()); |
| 243 | QQuickMenuBarItem * = qobject_cast<QQuickMenuBarItem *>(object: editMenuBarMenu->parentItem()); |
| 244 | QQuickMenuBarItem * = qobject_cast<QQuickMenuBarItem *>(object: viewMenuBarMenu->parentItem()); |
| 245 | QQuickMenuBarItem * = qobject_cast<QQuickMenuBarItem *>(object: helpMenuBarMenu->parentItem()); |
| 246 | QVERIFY(fileMenuBarItem && editMenuBarItem && viewMenuBarItem && helpMenuBarItem); |
| 247 | |
| 248 | // trigger a menubar item to open a menu |
| 249 | editMenuBarItem->forceActiveFocus(); |
| 250 | QTest::keyClick(window: window.data(), key: Qt::Key_Space); |
| 251 | QVERIFY(editMenuBarItem->isHighlighted()); |
| 252 | QVERIFY(editMenuBarMenu->isVisible()); |
| 253 | QTRY_VERIFY(editMenuBarMenu->isOpened()); |
| 254 | QVERIFY(editMenuBarMenu->hasActiveFocus()); |
| 255 | |
| 256 | // navigate down to the menu |
| 257 | QQuickMenuItem * = qobject_cast<QQuickMenuItem *>(object: editMenuBarMenu->itemAt(index: 0)); |
| 258 | QVERIFY(cutMenuItem); |
| 259 | QVERIFY(!cutMenuItem->isHighlighted()); |
| 260 | QVERIFY(!cutMenuItem->hasActiveFocus()); |
| 261 | QTest::keyClick(window: window.data(), key: Qt::Key_Down); |
| 262 | QVERIFY(cutMenuItem->isHighlighted()); |
| 263 | QVERIFY(cutMenuItem->hasActiveFocus()); |
| 264 | |
| 265 | // navigate up, back to the menubar |
| 266 | QTest::keyClick(window: window.data(), key: Qt::Key_Up); |
| 267 | QVERIFY(editMenuBarItem->isHighlighted()); |
| 268 | QVERIFY(editMenuBarItem->hasActiveFocus()); |
| 269 | QTRY_VERIFY(!editMenuBarMenu->isVisible()); |
| 270 | QVERIFY(!cutMenuItem->isHighlighted()); |
| 271 | QVERIFY(!cutMenuItem->hasActiveFocus()); |
| 272 | |
| 273 | // navigate down to re-open the menu |
| 274 | QTest::keyClick(window: window.data(), key: Qt::Key_Down); |
| 275 | QVERIFY(editMenuBarItem->isHighlighted()); |
| 276 | QVERIFY(!editMenuBarItem->hasActiveFocus()); |
| 277 | QVERIFY(editMenuBarMenu->isVisible()); |
| 278 | QTRY_VERIFY(editMenuBarMenu->isOpened()); |
| 279 | QVERIFY(editMenuBarMenu->hasActiveFocus()); |
| 280 | QVERIFY(cutMenuItem->isHighlighted()); |
| 281 | QVERIFY(cutMenuItem->hasActiveFocus()); |
| 282 | |
| 283 | // navigate left in popup mode (menu open) |
| 284 | QTest::keyClick(window: window.data(), key: Qt::Key_Left); |
| 285 | QVERIFY(fileMenuBarItem->isHighlighted()); |
| 286 | QVERIFY(!editMenuBarItem->isHighlighted()); |
| 287 | QVERIFY(fileMenuBarMenu->isVisible()); |
| 288 | QTRY_VERIFY(fileMenuBarMenu->isOpened()); |
| 289 | QTRY_VERIFY(!editMenuBarMenu->isVisible()); |
| 290 | |
| 291 | // navigate left in popup mode (wrap) |
| 292 | QTest::keyClick(window: window.data(), key: Qt::Key_Left); |
| 293 | QVERIFY(helpMenuBarItem->isHighlighted()); |
| 294 | QVERIFY(!fileMenuBarItem->isHighlighted()); |
| 295 | QVERIFY(helpMenuBarMenu->isVisible()); |
| 296 | QTRY_VERIFY(helpMenuBarMenu->isOpened()); |
| 297 | QTRY_VERIFY(!fileMenuBarMenu->isVisible()); |
| 298 | |
| 299 | // navigate up to close the menu |
| 300 | QTest::keyClick(window: window.data(), key: Qt::Key_Up); |
| 301 | QVERIFY(helpMenuBarItem->isHighlighted()); |
| 302 | QTRY_VERIFY(!helpMenuBarMenu->isVisible()); |
| 303 | |
| 304 | // navigate right in non-popup mode (wrap) |
| 305 | QTest::keyClick(window: window.data(), key: Qt::Key_Right); |
| 306 | QVERIFY(fileMenuBarItem->isHighlighted()); |
| 307 | QVERIFY(!helpMenuBarItem->isHighlighted()); |
| 308 | QVERIFY(!fileMenuBarMenu->isVisible()); |
| 309 | QVERIFY(!helpMenuBarMenu->isVisible()); |
| 310 | |
| 311 | // navigate right in non-popup mode (menu closed) |
| 312 | QTest::keyClick(window: window.data(), key: Qt::Key_Right); |
| 313 | QVERIFY(!fileMenuBarItem->isHighlighted()); |
| 314 | QVERIFY(editMenuBarItem->isHighlighted()); |
| 315 | QVERIFY(!fileMenuBarMenu->isVisible()); |
| 316 | QVERIFY(!editMenuBarMenu->isVisible()); |
| 317 | |
| 318 | // open a menu |
| 319 | viewMenuBarItem->forceActiveFocus(); |
| 320 | QTest::keyClick(window: window.data(), key: Qt::Key_Space); |
| 321 | QVERIFY(viewMenuBarItem->isHighlighted()); |
| 322 | QVERIFY(viewMenuBarMenu->isVisible()); |
| 323 | QTRY_VERIFY(viewMenuBarMenu->isOpened()); |
| 324 | QVERIFY(!viewMenuBarItem->hasActiveFocus()); |
| 325 | QVERIFY(viewMenuBarMenu->hasActiveFocus()); |
| 326 | |
| 327 | // open a sub-menu |
| 328 | QQuickMenuItem * = qobject_cast<QQuickMenuItem *>(object: viewMenuBarMenu->itemAt(index: 0)); |
| 329 | QVERIFY(alignmentSubMenuItem); |
| 330 | QQuickMenu * = alignmentSubMenuItem->subMenu(); |
| 331 | QVERIFY(alignmentSubMenu); |
| 332 | QTest::keyClick(window: window.data(), key: Qt::Key_Down); |
| 333 | QVERIFY(alignmentSubMenuItem->isHighlighted()); |
| 334 | QVERIFY(!alignmentSubMenu->isVisible()); |
| 335 | QTest::keyClick(window: window.data(), key: Qt::Key_Right); |
| 336 | QVERIFY(alignmentSubMenu->isVisible()); |
| 337 | QTRY_VERIFY(alignmentSubMenu->isOpened()); |
| 338 | |
| 339 | // open a sub-sub-menu |
| 340 | QQuickMenuItem * = qobject_cast<QQuickMenuItem *>(object: alignmentSubMenu->itemAt(index: 0)); |
| 341 | QVERIFY(horizontalSubMenuItem); |
| 342 | QVERIFY(horizontalSubMenuItem->isHighlighted()); |
| 343 | QQuickMenu * = horizontalSubMenuItem->subMenu(); |
| 344 | QVERIFY(horizontalSubMenu); |
| 345 | QTest::keyClick(window: window.data(), key: Qt::Key_Right); |
| 346 | QVERIFY(viewMenuBarMenu->isVisible()); |
| 347 | QVERIFY(alignmentSubMenu->isVisible()); |
| 348 | QVERIFY(horizontalSubMenu->isVisible()); |
| 349 | QTRY_VERIFY(horizontalSubMenu->isOpened()); |
| 350 | |
| 351 | // navigate left to close a sub-menu |
| 352 | QTest::keyClick(window: window.data(), key: Qt::Key_Left); |
| 353 | QTRY_VERIFY(!horizontalSubMenu->isVisible()); |
| 354 | QVERIFY(viewMenuBarMenu->isVisible()); |
| 355 | QVERIFY(alignmentSubMenu->isVisible()); |
| 356 | |
| 357 | // navigate right to re-open the sub-menu |
| 358 | QTest::keyClick(window: window.data(), key: Qt::Key_Right); |
| 359 | QVERIFY(horizontalSubMenuItem->isHighlighted()); |
| 360 | QVERIFY(horizontalSubMenu->isVisible()); |
| 361 | QTRY_VERIFY(horizontalSubMenu->isOpened()); |
| 362 | |
| 363 | // navigate right to the next menubar menu |
| 364 | QTest::keyClick(window: window.data(), key: Qt::Key_Right); |
| 365 | QVERIFY(!viewMenuBarItem->isHighlighted()); |
| 366 | QVERIFY(helpMenuBarItem->isHighlighted()); |
| 367 | QVERIFY(helpMenuBarMenu->isVisible()); |
| 368 | QTRY_VERIFY(!viewMenuBarMenu->isVisible()); |
| 369 | QTRY_VERIFY(!alignmentSubMenu->isVisible()); |
| 370 | QTRY_VERIFY(!horizontalSubMenu->isVisible()); |
| 371 | QTRY_VERIFY(helpMenuBarMenu->isOpened()); |
| 372 | |
| 373 | // navigate back |
| 374 | QTest::keyClick(window: window.data(), key: Qt::Key_Left); |
| 375 | QVERIFY(!helpMenuBarItem->isHighlighted()); |
| 376 | QVERIFY(viewMenuBarItem->isHighlighted()); |
| 377 | QVERIFY(viewMenuBarMenu->isVisible()); |
| 378 | QTRY_VERIFY(!helpMenuBarMenu->isVisible()); |
| 379 | QTRY_VERIFY(viewMenuBarMenu->isOpened()); |
| 380 | |
| 381 | // re-open the chain of menus |
| 382 | QTest::keyClick(window: window.data(), key: Qt::Key_Down); |
| 383 | QVERIFY(alignmentSubMenuItem->isHighlighted()); |
| 384 | QTest::keyClick(window: window.data(), key: Qt::Key_Right); |
| 385 | QTRY_VERIFY(alignmentSubMenu->isOpened()); |
| 386 | QTest::keyClick(window: window.data(), key: Qt::Key_Right); |
| 387 | QTRY_VERIFY(horizontalSubMenu->isOpened()); |
| 388 | |
| 389 | // repeat escape to close the whole chain of menus one by one |
| 390 | QTest::keyClick(window: window.data(), key: Qt::Key_Escape); |
| 391 | QTRY_VERIFY(!horizontalSubMenu->isVisible()); |
| 392 | QVERIFY(viewMenuBarItem->isHighlighted()); |
| 393 | QVERIFY(viewMenuBarMenu->isVisible()); |
| 394 | QVERIFY(alignmentSubMenu->isVisible()); |
| 395 | |
| 396 | QTest::keyClick(window: window.data(), key: Qt::Key_Escape); |
| 397 | QTRY_VERIFY(!alignmentSubMenu->isVisible()); |
| 398 | QVERIFY(viewMenuBarItem->isHighlighted()); |
| 399 | QVERIFY(viewMenuBarMenu->isVisible()); |
| 400 | |
| 401 | QTest::keyClick(window: window.data(), key: Qt::Key_Escape); |
| 402 | QVERIFY(!viewMenuBarItem->isHighlighted()); |
| 403 | QTRY_VERIFY(!viewMenuBarMenu->isVisible()); |
| 404 | } |
| 405 | |
| 406 | void tst_qquickmenubar::() |
| 407 | { |
| 408 | #ifdef Q_OS_MACOS |
| 409 | QSKIP("Mnemonics are not used on macOS" ); |
| 410 | #endif |
| 411 | |
| 412 | QQmlApplicationEngine engine(testFileUrl(fileName: "menubar.qml" )); |
| 413 | |
| 414 | QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(object: engine.rootObjects().value(i: 0))); |
| 415 | QVERIFY(window); |
| 416 | |
| 417 | centerOnScreen(window: window.data()); |
| 418 | moveMouseAway(window: window.data()); |
| 419 | QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| 420 | |
| 421 | QQuickMenuBar * = window->property(name: "header" ).value<QQuickMenuBar *>(); |
| 422 | QVERIFY(menuBar); |
| 423 | |
| 424 | QQuickMenu * = menuBar->menuAt(index: 0); |
| 425 | QQuickMenu * = menuBar->menuAt(index: 1); |
| 426 | QQuickMenu * = menuBar->menuAt(index: 2); |
| 427 | QQuickMenu * = menuBar->menuAt(index: 3); |
| 428 | QVERIFY(fileMenuBarMenu && editMenuBarMenu && viewMenuBarMenu && helpMenuBarMenu); |
| 429 | |
| 430 | QQuickMenuBarItem * = qobject_cast<QQuickMenuBarItem *>(object: fileMenuBarMenu->parentItem()); |
| 431 | QQuickMenuBarItem * = qobject_cast<QQuickMenuBarItem *>(object: editMenuBarMenu->parentItem()); |
| 432 | QQuickMenuBarItem * = qobject_cast<QQuickMenuBarItem *>(object: viewMenuBarMenu->parentItem()); |
| 433 | QQuickMenuBarItem * = qobject_cast<QQuickMenuBarItem *>(object: helpMenuBarMenu->parentItem()); |
| 434 | QVERIFY(fileMenuBarItem && editMenuBarItem && viewMenuBarItem && helpMenuBarItem); |
| 435 | |
| 436 | // trigger a menubar item to open a menu |
| 437 | QTest::keyClick(window: window.data(), key: Qt::Key_E, modifier: Qt::AltModifier); // "&Edit" |
| 438 | QVERIFY(editMenuBarItem->isHighlighted()); |
| 439 | QVERIFY(!editMenuBarItem->hasActiveFocus()); |
| 440 | QVERIFY(editMenuBarMenu->isVisible()); |
| 441 | QTRY_VERIFY(editMenuBarMenu->isOpened()); |
| 442 | QVERIFY(editMenuBarMenu->hasActiveFocus()); |
| 443 | |
| 444 | // re-trigger a menubar item to hide the menu |
| 445 | QTest::keyClick(window: window.data(), key: Qt::Key_E, modifier: Qt::AltModifier); // "&Edit" |
| 446 | QVERIFY(editMenuBarItem->isHighlighted()); |
| 447 | QVERIFY(editMenuBarItem->hasActiveFocus()); |
| 448 | QVERIFY(!editMenuBarMenu->hasActiveFocus()); |
| 449 | QTRY_VERIFY(!editMenuBarMenu->isVisible()); |
| 450 | |
| 451 | // re-trigger a menubar item to show the menu again |
| 452 | QTest::keyClick(window: window.data(), key: Qt::Key_E, modifier: Qt::AltModifier); // "&Edit" |
| 453 | QVERIFY(editMenuBarItem->isHighlighted()); |
| 454 | QVERIFY(editMenuBarMenu->isVisible()); |
| 455 | QTRY_VERIFY(editMenuBarMenu->isOpened()); |
| 456 | QVERIFY(editMenuBarMenu->hasActiveFocus()); |
| 457 | QVERIFY(!editMenuBarItem->hasActiveFocus()); |
| 458 | |
| 459 | // trigger another menubar item to open another menu |
| 460 | QTest::keyClick(window: window.data(), key: Qt::Key_H, modifier: Qt::AltModifier); // "&Help" |
| 461 | QVERIFY(!editMenuBarItem->isHighlighted()); |
| 462 | QVERIFY(helpMenuBarItem->isHighlighted()); |
| 463 | QVERIFY(!viewMenuBarMenu->isVisible()); |
| 464 | QVERIFY(helpMenuBarMenu->isVisible()); |
| 465 | QTRY_VERIFY(helpMenuBarMenu->isOpened()); |
| 466 | |
| 467 | // trigger a menu item to close the menu |
| 468 | QTest::keyClick(window: window.data(), key: Qt::Key_A, modifier: Qt::AltModifier); // "&About" |
| 469 | QVERIFY(!helpMenuBarItem->isHighlighted()); |
| 470 | QTRY_VERIFY(!helpMenuBarMenu->isVisible()); |
| 471 | |
| 472 | // trigger a menubar item to open a menu |
| 473 | QTest::keyClick(window: window.data(), key: Qt::Key_V, modifier: Qt::AltModifier); // "&View" |
| 474 | QVERIFY(!editMenuBarItem->isHighlighted()); |
| 475 | QVERIFY(viewMenuBarItem->isHighlighted()); |
| 476 | QVERIFY(viewMenuBarMenu->isVisible()); |
| 477 | QTRY_VERIFY(viewMenuBarMenu->isOpened()); |
| 478 | |
| 479 | // trigger a menu item to open a sub-menu |
| 480 | QQuickMenuItem * = qobject_cast<QQuickMenuItem *>(object: viewMenuBarMenu->itemAt(index: 0)); |
| 481 | QVERIFY(alignmentSubMenuItem); |
| 482 | QQuickMenu * = alignmentSubMenuItem->subMenu(); |
| 483 | QVERIFY(alignmentSubMenu); |
| 484 | QTest::keyClick(window: window.data(), key: Qt::Key_A, modifier: Qt::AltModifier); // "&Alignment" |
| 485 | QVERIFY(viewMenuBarMenu->isVisible()); |
| 486 | QVERIFY(alignmentSubMenu->isVisible()); |
| 487 | QTRY_VERIFY(alignmentSubMenu->isOpened()); |
| 488 | |
| 489 | // trigger a menu item to open a sub-sub-menu |
| 490 | QQuickMenuItem * = qobject_cast<QQuickMenuItem *>(object: alignmentSubMenu->itemAt(index: 1)); |
| 491 | QVERIFY(verticalSubMenuItem); |
| 492 | QQuickMenu * = verticalSubMenuItem->subMenu(); |
| 493 | QVERIFY(verticalSubMenu); |
| 494 | QTest::keyClick(window: window.data(), key: Qt::Key_V, modifier: Qt::AltModifier); // "&Vertical" |
| 495 | QVERIFY(viewMenuBarMenu->isVisible()); |
| 496 | QVERIFY(alignmentSubMenu->isVisible()); |
| 497 | QVERIFY(verticalSubMenu->isVisible()); |
| 498 | QTRY_VERIFY(verticalSubMenu->isOpened()); |
| 499 | |
| 500 | // trigger a menu item to close the whole chain of menus |
| 501 | QTest::keyClick(window: window.data(), key: Qt::Key_C, modifier: Qt::AltModifier); // "&Center" |
| 502 | QVERIFY(!viewMenuBarItem->isHighlighted()); |
| 503 | QTRY_VERIFY(!viewMenuBarMenu->isVisible()); |
| 504 | QTRY_VERIFY(!alignmentSubMenu->isVisible()); |
| 505 | QTRY_VERIFY(!verticalSubMenu->isVisible()); |
| 506 | } |
| 507 | |
| 508 | void tst_qquickmenubar::() |
| 509 | { |
| 510 | QQmlApplicationEngine engine(testFileUrl(fileName: "empty.qml" )); |
| 511 | |
| 512 | QScopedPointer<QQuickMenuBar> (qobject_cast<QQuickMenuBar *>(object: engine.rootObjects().value(i: 0))); |
| 513 | QVERIFY(menuBar); |
| 514 | |
| 515 | QQmlComponent component(&engine); |
| 516 | component.setData("import QtQuick.Controls 2.0; Menu { }" , baseUrl: QUrl()); |
| 517 | |
| 518 | QPointer<QQuickMenu> (qobject_cast<QQuickMenu *>(object: component.create())); |
| 519 | QVERIFY(!menu1.isNull()); |
| 520 | menuBar->addMenu(menu: menu1.data()); |
| 521 | QCOMPARE(menuBar->count(), 1); |
| 522 | QCOMPARE(menuBar->menuAt(0), menu1.data()); |
| 523 | |
| 524 | QPointer<QQuickMenuBarItem> (qobject_cast<QQuickMenuBarItem *>(object: menuBar->itemAt(index: 0))); |
| 525 | QVERIFY(menuBarItem1); |
| 526 | QCOMPARE(menuBarItem1->menu(), menu1.data()); |
| 527 | QCOMPARE(menuBar->itemAt(0), menuBarItem1.data()); |
| 528 | |
| 529 | QScopedPointer<QQuickMenu> (qobject_cast<QQuickMenu *>(object: component.create())); |
| 530 | QVERIFY(!menu2.isNull()); |
| 531 | menuBar->insertMenu(index: 0, menu: menu2.data()); |
| 532 | QCOMPARE(menuBar->count(), 2); |
| 533 | QCOMPARE(menuBar->menuAt(0), menu2.data()); |
| 534 | QCOMPARE(menuBar->menuAt(1), menu1.data()); |
| 535 | |
| 536 | QPointer<QQuickMenuBarItem> (qobject_cast<QQuickMenuBarItem *>(object: menuBar->itemAt(index: 0))); |
| 537 | QVERIFY(menuBarItem2); |
| 538 | QCOMPARE(menuBarItem2->menu(), menu2.data()); |
| 539 | QCOMPARE(menuBar->itemAt(0), menuBarItem2.data()); |
| 540 | QCOMPARE(menuBar->itemAt(1), menuBarItem1.data()); |
| 541 | |
| 542 | // takeMenu(int) does not destroy the menu, but does destroy the respective item in the menubar |
| 543 | QCOMPARE(menuBar->takeMenu(1), menu1.data()); |
| 544 | QCOMPARE(menuBar->count(), 1); |
| 545 | QVERIFY(!menuBar->menuAt(1)); |
| 546 | QVERIFY(!menuBar->itemAt(1)); |
| 547 | QCoreApplication::sendPostedEvents(receiver: menu1.data(), event_type: QEvent::DeferredDelete); |
| 548 | QVERIFY(!menu1.isNull()); |
| 549 | QCoreApplication::sendPostedEvents(receiver: menuBarItem1, event_type: QEvent::DeferredDelete); |
| 550 | QVERIFY(menuBarItem1.isNull()); |
| 551 | |
| 552 | // addMenu(Menu) re-creates the respective item in the menubar |
| 553 | menuBar->addMenu(menu: menu1.data()); |
| 554 | QCOMPARE(menuBar->count(), 2); |
| 555 | menuBarItem1 = qobject_cast<QQuickMenuBarItem *>(object: menuBar->itemAt(index: 1)); |
| 556 | QVERIFY(!menuBarItem1.isNull()); |
| 557 | |
| 558 | // removeMenu(Menu) destroys both the menu and the respective item in the menubar |
| 559 | menuBar->removeMenu(menu: menu1.data()); |
| 560 | QCOMPARE(menuBar->count(), 1); |
| 561 | QVERIFY(!menuBar->itemAt(1)); |
| 562 | QCoreApplication::sendPostedEvents(receiver: menu1.data(), event_type: QEvent::DeferredDelete); |
| 563 | QVERIFY(menu1.isNull()); |
| 564 | QCoreApplication::sendPostedEvents(receiver: menuBarItem1, event_type: QEvent::DeferredDelete); |
| 565 | QVERIFY(menuBarItem1.isNull()); |
| 566 | } |
| 567 | |
| 568 | void tst_qquickmenubar::() |
| 569 | { |
| 570 | if ((QGuiApplication::platformName() == QLatin1String("offscreen" )) |
| 571 | || (QGuiApplication::platformName() == QLatin1String("minimal" ))) |
| 572 | QSKIP("Mouse highlight not functional on offscreen/minimal platforms" ); |
| 573 | |
| 574 | QQmlApplicationEngine engine(testFileUrl(fileName: "checkHighlightWhenDismissed.qml" )); |
| 575 | QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(object: engine.rootObjects().value(i: 0))); |
| 576 | QVERIFY(window); |
| 577 | |
| 578 | centerOnScreen(window: window.data()); |
| 579 | moveMouseAway(window: window.data()); |
| 580 | QVERIFY(QTest::qWaitForWindowActive(window.data())); |
| 581 | |
| 582 | QQuickMenuBar * = window->findChild<QQuickMenuBar *>(aName: "menuBar" ); |
| 583 | QVERIFY(menuBar); |
| 584 | |
| 585 | QQuickMenu * = menuBar->menuAt(index: 0); |
| 586 | QQuickMenu * = menuBar->menuAt(index: 1); |
| 587 | QVERIFY(staticMenu && dynamicMenu); |
| 588 | QQuickMenuBarItem * = qobject_cast<QQuickMenuBarItem *>(object: staticMenu->parentItem()); |
| 589 | QQuickMenuBarItem * = qobject_cast<QQuickMenuBarItem *>(object: dynamicMenu->parentItem()); |
| 590 | QVERIFY(staticMenuBarItem && dynamicMenuBarItem); |
| 591 | |
| 592 | // highlight the static MenuBarItem and open the menu |
| 593 | QTest::mouseMove(window: window.data(), pos: staticMenuBarItem->mapToScene( |
| 594 | point: QPointF(staticMenuBarItem->width() / 2, staticMenuBarItem->height() / 2)).toPoint()); |
| 595 | QTest::mouseClick(window: window.data(), button: Qt::LeftButton, stateKey: Qt::NoModifier, |
| 596 | pos: staticMenuBarItem->mapToScene(point: QPointF(staticMenuBarItem->width() / 2, staticMenuBarItem->height() / 2)).toPoint()); |
| 597 | QCOMPARE(staticMenuBarItem->isHighlighted(), true); |
| 598 | QCOMPARE(staticMenu->isVisible(), true); |
| 599 | QTRY_COMPARE(staticMenu->isOpened(), true); |
| 600 | |
| 601 | // click a menu item to dismiss the menu and unhighlight the static MenuBarItem |
| 602 | QQuickMenuItem * = qobject_cast<QQuickMenuItem *>(object: staticMenu->itemAt(index: 0)); |
| 603 | QVERIFY(menuItem); |
| 604 | QTest::mouseClick(window: window.data(), button: Qt::LeftButton, stateKey: Qt::NoModifier, |
| 605 | pos: menuItem->mapToScene(point: QPointF(menuItem->width() / 2, menuItem->height() / 2)).toPoint()); |
| 606 | QCOMPARE(staticMenuBarItem->isHighlighted(), false); |
| 607 | |
| 608 | // highlight the dynamic MenuBarItem and open the menu |
| 609 | QTest::mouseMove(window: window.data(), pos: dynamicMenuBarItem->mapToScene( |
| 610 | point: QPointF(dynamicMenuBarItem->width() / 2, dynamicMenuBarItem->height() / 2)).toPoint()); |
| 611 | QTest::mouseClick(window: window.data(), button: Qt::LeftButton, stateKey: Qt::NoModifier, |
| 612 | pos: dynamicMenuBarItem->mapToScene(point: QPointF(dynamicMenuBarItem->width() / 2, dynamicMenuBarItem->height() / 2)).toPoint()); |
| 613 | QCOMPARE(dynamicMenuBarItem->isHighlighted(), true); |
| 614 | QCOMPARE(dynamicMenu->isVisible(), true); |
| 615 | QTRY_COMPARE(dynamicMenu->isOpened(), true); |
| 616 | |
| 617 | // click a menu item to dismiss the menu and unhighlight the dynamic MenuBarItem |
| 618 | menuItem = qobject_cast<QQuickMenuItem *>(object: dynamicMenu->itemAt(index: 0)); |
| 619 | QVERIFY(menuItem); |
| 620 | QTest::mouseClick(window: window.data(), button: Qt::LeftButton, stateKey: Qt::NoModifier, |
| 621 | pos: menuItem->mapToScene(point: QPointF(menuItem->width() / 2, menuItem->height() / 2)).toPoint()); |
| 622 | QCOMPARE(dynamicMenuBarItem->isHighlighted(), false); |
| 623 | } |
| 624 | |
| 625 | QTEST_QUICKCONTROLS_MAIN(tst_qquickmenubar) |
| 626 | |
| 627 | #include "tst_qquickmenubar.moc" |
| 628 | |