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
49using namespace QQuickVisualTestUtil;
50
51class tst_qquickmenubar : public QQmlDataTest
52{
53 Q_OBJECT
54
55public:
56
57private slots:
58 void delegate();
59 void mouse();
60 void keys();
61 void mnemonics();
62 void addRemove();
63 void checkHighlightWhenMenuDismissed();
64};
65
66void tst_qquickmenubar::delegate()
67{
68 QQmlApplicationEngine engine(testFileUrl(fileName: "empty.qml"));
69 QScopedPointer<QQuickMenuBar> menuBar(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
79void tst_qquickmenubar::mouse()
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 *menuBar = window->property(name: "header").value<QQuickMenuBar *>();
95 QVERIFY(menuBar);
96
97 QQuickMenu *fileMenuBarMenu = menuBar->menuAt(index: 0);
98 QQuickMenu *editMenuBarMenu = menuBar->menuAt(index: 1);
99 QQuickMenu *viewMenuBarMenu = menuBar->menuAt(index: 2);
100 QQuickMenu *helpMenuBarMenu = menuBar->menuAt(index: 3);
101 QVERIFY(fileMenuBarMenu && editMenuBarMenu && viewMenuBarMenu && helpMenuBarMenu);
102
103 QQuickMenuBarItem *fileMenuBarItem = qobject_cast<QQuickMenuBarItem *>(object: fileMenuBarMenu->parentItem());
104 QQuickMenuBarItem *editMenuBarItem = qobject_cast<QQuickMenuBarItem *>(object: editMenuBarMenu->parentItem());
105 QQuickMenuBarItem *viewMenuBarItem = qobject_cast<QQuickMenuBarItem *>(object: viewMenuBarMenu->parentItem());
106 QQuickMenuBarItem *helpMenuBarItem = 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 *aboutMenuItem = 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 *alignmentSubMenuItem = qobject_cast<QQuickMenuItem *>(object: viewMenuBarMenu->itemAt(index: 0));
174 QVERIFY(alignmentSubMenuItem);
175 QQuickMenu *alignmentSubMenu = 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 *verticalSubMenuItem = qobject_cast<QQuickMenuItem *>(object: alignmentSubMenu->itemAt(index: 1));
184 QVERIFY(verticalSubMenuItem);
185 QQuickMenu *verticalSubMenu = 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 *centerMenuItem = 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
222void tst_qquickmenubar::keys()
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 *menuBar = window->property(name: "header").value<QQuickMenuBar *>();
234 QVERIFY(menuBar);
235
236 QQuickMenu *fileMenuBarMenu = menuBar->menuAt(index: 0);
237 QQuickMenu *editMenuBarMenu = menuBar->menuAt(index: 1);
238 QQuickMenu *viewMenuBarMenu = menuBar->menuAt(index: 2);
239 QQuickMenu *helpMenuBarMenu = menuBar->menuAt(index: 3);
240 QVERIFY(fileMenuBarMenu && editMenuBarMenu && viewMenuBarMenu && helpMenuBarMenu);
241
242 QQuickMenuBarItem *fileMenuBarItem = qobject_cast<QQuickMenuBarItem *>(object: fileMenuBarMenu->parentItem());
243 QQuickMenuBarItem *editMenuBarItem = qobject_cast<QQuickMenuBarItem *>(object: editMenuBarMenu->parentItem());
244 QQuickMenuBarItem *viewMenuBarItem = qobject_cast<QQuickMenuBarItem *>(object: viewMenuBarMenu->parentItem());
245 QQuickMenuBarItem *helpMenuBarItem = 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 *cutMenuItem = 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 *alignmentSubMenuItem = qobject_cast<QQuickMenuItem *>(object: viewMenuBarMenu->itemAt(index: 0));
329 QVERIFY(alignmentSubMenuItem);
330 QQuickMenu *alignmentSubMenu = 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 *horizontalSubMenuItem = qobject_cast<QQuickMenuItem *>(object: alignmentSubMenu->itemAt(index: 0));
341 QVERIFY(horizontalSubMenuItem);
342 QVERIFY(horizontalSubMenuItem->isHighlighted());
343 QQuickMenu *horizontalSubMenu = 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
406void tst_qquickmenubar::mnemonics()
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 *menuBar = window->property(name: "header").value<QQuickMenuBar *>();
422 QVERIFY(menuBar);
423
424 QQuickMenu *fileMenuBarMenu = menuBar->menuAt(index: 0);
425 QQuickMenu *editMenuBarMenu = menuBar->menuAt(index: 1);
426 QQuickMenu *viewMenuBarMenu = menuBar->menuAt(index: 2);
427 QQuickMenu *helpMenuBarMenu = menuBar->menuAt(index: 3);
428 QVERIFY(fileMenuBarMenu && editMenuBarMenu && viewMenuBarMenu && helpMenuBarMenu);
429
430 QQuickMenuBarItem *fileMenuBarItem = qobject_cast<QQuickMenuBarItem *>(object: fileMenuBarMenu->parentItem());
431 QQuickMenuBarItem *editMenuBarItem = qobject_cast<QQuickMenuBarItem *>(object: editMenuBarMenu->parentItem());
432 QQuickMenuBarItem *viewMenuBarItem = qobject_cast<QQuickMenuBarItem *>(object: viewMenuBarMenu->parentItem());
433 QQuickMenuBarItem *helpMenuBarItem = 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 *alignmentSubMenuItem = qobject_cast<QQuickMenuItem *>(object: viewMenuBarMenu->itemAt(index: 0));
481 QVERIFY(alignmentSubMenuItem);
482 QQuickMenu *alignmentSubMenu = 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 *verticalSubMenuItem = qobject_cast<QQuickMenuItem *>(object: alignmentSubMenu->itemAt(index: 1));
491 QVERIFY(verticalSubMenuItem);
492 QQuickMenu *verticalSubMenu = 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
508void tst_qquickmenubar::addRemove()
509{
510 QQmlApplicationEngine engine(testFileUrl(fileName: "empty.qml"));
511
512 QScopedPointer<QQuickMenuBar> menuBar(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> menu1(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> menuBarItem1(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> menu2(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> menuBarItem2(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
568void tst_qquickmenubar::checkHighlightWhenMenuDismissed()
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 *menuBar = window->findChild<QQuickMenuBar *>(aName: "menuBar");
583 QVERIFY(menuBar);
584
585 QQuickMenu *staticMenu = menuBar->menuAt(index: 0);
586 QQuickMenu *dynamicMenu = menuBar->menuAt(index: 1);
587 QVERIFY(staticMenu && dynamicMenu);
588 QQuickMenuBarItem *staticMenuBarItem = qobject_cast<QQuickMenuBarItem *>(object: staticMenu->parentItem());
589 QQuickMenuBarItem *dynamicMenuBarItem = 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 *menuItem = 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
625QTEST_QUICKCONTROLS_MAIN(tst_qquickmenubar)
626
627#include "tst_qquickmenubar.moc"
628

source code of qtquickcontrols2/tests/auto/qquickmenubar/tst_qquickmenubar.cpp