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/qtest.h>
38#include <QtTest/qsignalspy.h>
39#include "../shared/util.h"
40#include "../shared/visualtestutil.h"
41#include "../shared/qtest_quickcontrols.h"
42
43#include <QtGui/qpa/qwindowsysteminterface.h>
44#include <QtQuick/qquickview.h>
45#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h>
46#include <QtQuickTemplates2/private/qquickcombobox_p.h>
47#include <QtQuickTemplates2/private/qquickdialog_p.h>
48#include <QtQuickTemplates2/private/qquickoverlay_p.h>
49#include <QtQuickTemplates2/private/qquickpopup_p.h>
50#include <QtQuickTemplates2/private/qquickbutton_p.h>
51#include <QtQuickTemplates2/private/qquickslider_p.h>
52#include <QtQuickTemplates2/private/qquickstackview_p.h>
53
54using namespace QQuickVisualTestUtil;
55
56class tst_QQuickPopup : public QQmlDataTest
57{
58 Q_OBJECT
59
60private slots:
61 void initTestCase();
62 void visible_data();
63 void visible();
64 void state();
65 void overlay_data();
66 void overlay();
67 void zOrder_data();
68 void zOrder();
69 void windowChange();
70 void closePolicy_data();
71 void closePolicy();
72 void activeFocusOnClose1();
73 void activeFocusOnClose2();
74 void activeFocusOnClose3();
75 void activeFocusOnClosingSeveralPopups();
76 void activeFocusAfterExit();
77 void activeFocusOnDelayedEnter();
78 void hover_data();
79 void hover();
80 void wheel_data();
81 void wheel();
82 void parentDestroyed();
83 void nested();
84 void modelessOnModalOnModeless();
85 void grabber();
86 void cursorShape();
87 void componentComplete();
88 void closeOnEscapeWithNestedPopups();
89 void closeOnEscapeWithVisiblePopup();
90 void enabled();
91 void orientation_data();
92 void orientation();
93 void qquickview();
94 void disabledPalette();
95 void disabledParentPalette();
96 void countChanged();
97 void toolTipCrashOnClose();
98 void setOverlayParentToNull();
99 void tabFence();
100 void invisibleToolTipOpen();
101 void centerInOverlayWithinStackViewItem();
102 void destroyDuringExitTransition();
103};
104
105void tst_QQuickPopup::initTestCase()
106{
107 QQmlDataTest::initTestCase();
108 qputenv(varName: "QML_NO_TOUCH_COMPRESSION", value: "1");
109}
110
111void tst_QQuickPopup::visible_data()
112{
113 QTest::addColumn<QString>(name: "source");
114 QTest::newRow(dataTag: "Window") << "window.qml";
115 QTest::newRow(dataTag: "ApplicationWindow") << "applicationwindow.qml";
116}
117
118void tst_QQuickPopup::visible()
119{
120 QFETCH(QString, source);
121 QQuickApplicationHelper helper(this, source);
122 QVERIFY2(helper.ready, helper.failureMessage());
123
124 QQuickWindow *window = helper.window;
125 window->show();
126 window->requestActivate();
127 QVERIFY(QTest::qWaitForWindowActive(window));
128
129 QQuickPopup *popup = window->property(name: "popup").value<QQuickPopup*>();
130 QVERIFY(popup);
131 QQuickItem *popupItem = popup->popupItem();
132
133 popup->open();
134 QVERIFY(popup->isVisible());
135
136 QQuickOverlay *overlay = QQuickOverlay::overlay(window);
137 QVERIFY(overlay);
138 QVERIFY(overlay->childItems().contains(popupItem));
139
140 popup->close();
141 QTRY_VERIFY(!popup->isVisible());
142 QVERIFY(!overlay->childItems().contains(popupItem));
143
144 popup->setVisible(true);
145 QVERIFY(popup->isVisible());
146 QVERIFY(overlay->childItems().contains(popupItem));
147
148 popup->setVisible(false);
149 QTRY_VERIFY(!popup->isVisible());
150 QVERIFY(!overlay->childItems().contains(popupItem));
151}
152
153void tst_QQuickPopup::state()
154{
155 QQuickApplicationHelper helper(this, "applicationwindow.qml");
156 QVERIFY2(helper.ready, helper.failureMessage());
157
158 QQuickWindow *window = helper.window;
159 window->show();
160 QVERIFY(QTest::qWaitForWindowExposed(window));
161
162 QQuickPopup *popup = window->property(name: "popup").value<QQuickPopup*>();
163 QVERIFY(popup);
164
165 QCOMPARE(popup->isVisible(), false);
166
167 QSignalSpy visibleChangedSpy(popup, SIGNAL(visibleChanged()));
168 QSignalSpy aboutToShowSpy(popup, SIGNAL(aboutToShow()));
169 QSignalSpy aboutToHideSpy(popup, SIGNAL(aboutToHide()));
170 QSignalSpy openedSpy(popup, SIGNAL(opened()));
171 QSignalSpy closedSpy(popup, SIGNAL(closed()));
172
173 QVERIFY(visibleChangedSpy.isValid());
174 QVERIFY(aboutToShowSpy.isValid());
175 QVERIFY(aboutToHideSpy.isValid());
176 QVERIFY(openedSpy.isValid());
177 QVERIFY(closedSpy.isValid());
178
179 popup->open();
180 QCOMPARE(visibleChangedSpy.count(), 1);
181 QCOMPARE(aboutToShowSpy.count(), 1);
182 QCOMPARE(aboutToHideSpy.count(), 0);
183 QTRY_COMPARE(openedSpy.count(), 1);
184 QCOMPARE(closedSpy.count(), 0);
185
186 popup->close();
187 QTRY_COMPARE(visibleChangedSpy.count(), 2);
188 QCOMPARE(aboutToShowSpy.count(), 1);
189 QCOMPARE(aboutToHideSpy.count(), 1);
190 QCOMPARE(openedSpy.count(), 1);
191 QTRY_COMPARE(closedSpy.count(), 1);
192}
193
194void tst_QQuickPopup::overlay_data()
195{
196 QTest::addColumn<QString>(name: "source");
197 QTest::addColumn<bool>(name: "modal");
198 QTest::addColumn<bool>(name: "dim");
199
200 QTest::newRow(dataTag: "Window") << "window.qml" << false << false;
201 QTest::newRow(dataTag: "Window,dim") << "window.qml" << false << true;
202 QTest::newRow(dataTag: "Window,modal") << "window.qml" << true << false;
203 QTest::newRow(dataTag: "Window,modal,dim") << "window.qml" << true << true;
204
205 QTest::newRow(dataTag: "ApplicationWindow") << "applicationwindow.qml" << false << false;
206 QTest::newRow(dataTag: "ApplicationWindow,dim") << "applicationwindow.qml" << false << true;
207 QTest::newRow(dataTag: "ApplicationWindow,modal") << "applicationwindow.qml" << true << false;
208 QTest::newRow(dataTag: "ApplicationWindow,modal,dim") << "applicationwindow.qml" << true << true;
209}
210
211void tst_QQuickPopup::overlay()
212{
213 QFETCH(QString, source);
214 QFETCH(bool, modal);
215 QFETCH(bool, dim);
216
217 QQuickApplicationHelper helper(this, source);
218 QVERIFY2(helper.ready, helper.failureMessage());
219
220 QQuickWindow *window = helper.window;
221 window->show();
222 window->requestActivate();
223 QVERIFY(QTest::qWaitForWindowActive(window));
224
225 QQuickOverlay *overlay = QQuickOverlay::overlay(window);
226 QVERIFY(overlay);
227
228 QSignalSpy overlayPressedSignal(overlay, SIGNAL(pressed()));
229 QSignalSpy overlayReleasedSignal(overlay, SIGNAL(released()));
230 QVERIFY(overlayPressedSignal.isValid());
231 QVERIFY(overlayReleasedSignal.isValid());
232
233 QVERIFY(!overlay->isVisible()); // no popups open
234
235 QTest::mouseClick(window, button: Qt::LeftButton);
236 QCOMPARE(overlayPressedSignal.count(), 0);
237 QCOMPARE(overlayReleasedSignal.count(), 0);
238
239 QQuickPopup *popup = window->property(name: "popup").value<QQuickPopup*>();
240 QVERIFY(popup);
241
242 QQuickOverlayAttached *overlayAttached = qobject_cast<QQuickOverlayAttached *>(object: qmlAttachedPropertiesObject<QQuickOverlay>(obj: popup));
243 QVERIFY(overlayAttached);
244 QCOMPARE(overlayAttached->overlay(), overlay);
245
246 QSignalSpy overlayAttachedPressedSignal(overlayAttached, SIGNAL(pressed()));
247 QSignalSpy overlayAttachedReleasedSignal(overlayAttached, SIGNAL(released()));
248 QVERIFY(overlayAttachedPressedSignal.isValid());
249 QVERIFY(overlayAttachedReleasedSignal.isValid());
250
251 QQuickButton *button = window->property(name: "button").value<QQuickButton*>();
252 QVERIFY(button);
253
254 int overlayPressCount = 0;
255 int overlayReleaseCount = 0;
256
257 popup->open();
258 QVERIFY(popup->isVisible());
259 QVERIFY(overlay->isVisible());
260 QTRY_VERIFY(popup->isOpened());
261
262 QTest::mousePress(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(1, 1));
263 QCOMPARE(overlayPressedSignal.count(), ++overlayPressCount);
264 QCOMPARE(overlayReleasedSignal.count(), overlayReleaseCount);
265 QCOMPARE(overlayAttachedPressedSignal.count(), overlayPressCount);
266 QCOMPARE(overlayAttachedReleasedSignal.count(), overlayReleaseCount);
267
268 QTRY_VERIFY(!popup->isVisible());
269 QVERIFY(!overlay->isVisible());
270
271 QTest::mouseRelease(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(1, 1));
272 QCOMPARE(overlayPressedSignal.count(), overlayPressCount);
273 QCOMPARE(overlayReleasedSignal.count(), overlayReleaseCount); // no modal-popups open
274 QCOMPARE(overlayAttachedPressedSignal.count(), overlayPressCount);
275 QCOMPARE(overlayAttachedReleasedSignal.count(), overlayReleaseCount);
276
277 popup->setDim(dim);
278 popup->setModal(modal);
279 popup->setClosePolicy(QQuickPopup::CloseOnReleaseOutside);
280
281 // mouse
282 popup->open();
283 QVERIFY(popup->isVisible());
284 QVERIFY(overlay->isVisible());
285 QTRY_VERIFY(popup->isOpened());
286
287 QTest::mousePress(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(1, 1));
288 QCOMPARE(overlayPressedSignal.count(), ++overlayPressCount);
289 QCOMPARE(overlayReleasedSignal.count(), overlayReleaseCount);
290 QCOMPARE(overlayAttachedPressedSignal.count(), overlayPressCount);
291 QCOMPARE(overlayAttachedReleasedSignal.count(), overlayReleaseCount);
292
293 QTest::mouseRelease(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(1, 1));
294 QCOMPARE(overlayPressedSignal.count(), overlayPressCount);
295 QCOMPARE(overlayReleasedSignal.count(), ++overlayReleaseCount);
296 QCOMPARE(overlayAttachedPressedSignal.count(), overlayPressCount);
297 QCOMPARE(overlayAttachedReleasedSignal.count(), overlayReleaseCount);
298
299 QTRY_VERIFY(!popup->isVisible());
300 QVERIFY(!overlay->isVisible());
301
302 // touch
303 popup->open();
304 QVERIFY(popup->isVisible());
305 QVERIFY(overlay->isVisible());
306
307 struct TouchDeviceDeleter
308 {
309 static inline void cleanup(QTouchDevice *device)
310 {
311 QWindowSystemInterface::unregisterTouchDevice(device);
312 delete device;
313 }
314 };
315
316 QScopedPointer<QTouchDevice, TouchDeviceDeleter> device(new QTouchDevice);
317 device->setType(QTouchDevice::TouchScreen);
318 QWindowSystemInterface::registerTouchDevice(device: device.data());
319
320 QTest::touchEvent(window, device: device.data()).press(touchId: 0, pt: QPoint(1, 1));
321 QCOMPARE(overlayPressedSignal.count(), ++overlayPressCount);
322 QCOMPARE(overlayReleasedSignal.count(), overlayReleaseCount);
323 QCOMPARE(overlayAttachedPressedSignal.count(), overlayPressCount);
324 QCOMPARE(overlayAttachedReleasedSignal.count(), overlayReleaseCount);
325
326 QTest::touchEvent(window, device: device.data()).release(touchId: 0, pt: QPoint(1, 1));
327 QCOMPARE(overlayPressedSignal.count(), overlayPressCount);
328 QCOMPARE(overlayReleasedSignal.count(), ++overlayReleaseCount);
329 QCOMPARE(overlayAttachedPressedSignal.count(), overlayPressCount);
330 QCOMPARE(overlayAttachedReleasedSignal.count(), overlayReleaseCount);
331
332 QTRY_VERIFY(!popup->isVisible());
333 QVERIFY(!overlay->isVisible());
334
335 // multi-touch
336 popup->open();
337 QVERIFY(popup->isVisible());
338 QVERIFY(overlay->isVisible());
339 QVERIFY(!button->isPressed());
340
341 QTest::touchEvent(window, device: device.data()).press(touchId: 0, pt: button->mapToScene(point: QPointF(1, 1)).toPoint());
342 QVERIFY(popup->isVisible());
343 QVERIFY(overlay->isVisible());
344 QCOMPARE(button->isPressed(), !modal);
345 QCOMPARE(overlayPressedSignal.count(), ++overlayPressCount);
346 QCOMPARE(overlayReleasedSignal.count(), overlayReleaseCount);
347
348 QTest::touchEvent(window, device: device.data()).stationary(touchId: 0).press(touchId: 1, pt: button->mapToScene(point: QPointF(button->width() / 2, button->height() / 2)).toPoint());
349 QVERIFY(popup->isVisible());
350 QVERIFY(overlay->isVisible());
351 QCOMPARE(button->isPressed(), !modal);
352 QCOMPARE(overlayPressedSignal.count(), ++overlayPressCount);
353 QCOMPARE(overlayReleasedSignal.count(), overlayReleaseCount);
354
355 QTest::touchEvent(window, device: device.data()).release(touchId: 0, pt: button->mapToScene(point: QPointF(1, 1)).toPoint()).stationary(touchId: 1);
356 QTRY_VERIFY(!popup->isVisible());
357 QVERIFY(!overlay->isVisible());
358 QVERIFY(!button->isPressed());
359 QCOMPARE(overlayPressedSignal.count(), overlayPressCount);
360 QCOMPARE(overlayReleasedSignal.count(), ++overlayReleaseCount);
361
362 QTest::touchEvent(window, device: device.data()).release(touchId: 1, pt: button->mapToScene(point: QPointF(button->width() / 2, button->height() / 2)).toPoint());
363 QVERIFY(!popup->isVisible());
364 QVERIFY(!overlay->isVisible());
365 QVERIFY(!button->isPressed());
366 QCOMPARE(overlayPressedSignal.count(), overlayPressCount);
367 QCOMPARE(overlayReleasedSignal.count(), overlayReleaseCount);
368}
369
370void tst_QQuickPopup::zOrder_data()
371{
372 QTest::addColumn<QString>(name: "source");
373 QTest::newRow(dataTag: "Window") << "window.qml";
374 QTest::newRow(dataTag: "ApplicationWindow") << "applicationwindow.qml";
375}
376
377void tst_QQuickPopup::zOrder()
378{
379 QFETCH(QString, source);
380 QQuickApplicationHelper helper(this, source);
381 QVERIFY2(helper.ready, helper.failureMessage());
382
383 QQuickWindow *window = helper.window;
384 window->show();
385 window->requestActivate();
386 QVERIFY(QTest::qWaitForWindowActive(window));
387
388 QQuickPopup *popup = window->property(name: "popup").value<QQuickPopup*>();
389 QVERIFY(popup);
390 popup->setModal(true);
391
392 QQuickPopup *popup2 = window->property(name: "popup2").value<QQuickPopup*>();
393 QVERIFY(popup2);
394 popup2->setModal(true);
395
396 // show popups in reverse order. popup2 has higher z-order so it appears
397 // on top and must be closed first, even if the other popup was opened last
398 popup2->open();
399 popup->open();
400 QVERIFY(popup2->isVisible());
401 QVERIFY(popup->isVisible());
402
403 QTest::mouseClick(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(1, 1));
404 QTRY_VERIFY(!popup2->isVisible());
405 QVERIFY(popup->isVisible());
406
407 QTest::mouseClick(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(1, 1));
408 QVERIFY(!popup2->isVisible());
409 QTRY_VERIFY(!popup->isVisible());
410}
411
412void tst_QQuickPopup::windowChange()
413{
414 QQuickPopup popup;
415 QSignalSpy spy(&popup, SIGNAL(windowChanged(QQuickWindow*)));
416 QVERIFY(spy.isValid());
417
418 QQuickItem item;
419 popup.setParentItem(&item);
420 QVERIFY(!popup.window());
421 QCOMPARE(spy.count(), 0);
422
423 QQuickWindow window;
424 item.setParentItem(window.contentItem());
425 QCOMPARE(popup.window(), &window);
426 QCOMPARE(spy.count(), 1);
427
428 item.setParentItem(nullptr);
429 QVERIFY(!popup.window());
430 QCOMPARE(spy.count(), 2);
431
432 popup.setParentItem(window.contentItem());
433 QCOMPARE(popup.window(), &window);
434 QCOMPARE(spy.count(), 3);
435
436 popup.resetParentItem();
437 QVERIFY(!popup.window());
438 QCOMPARE(spy.count(), 4);
439
440 popup.setParent(&window);
441 popup.resetParentItem();
442 QCOMPARE(popup.window(), &window);
443 QCOMPARE(spy.count(), 5);
444
445 popup.setParent(this);
446 popup.resetParentItem();
447 QVERIFY(!popup.window());
448 QCOMPARE(spy.count(), 6);
449
450 item.setParentItem(window.contentItem());
451 popup.setParent(&item);
452 popup.resetParentItem();
453 QCOMPARE(popup.window(), &window);
454 QCOMPARE(spy.count(), 7);
455
456 popup.setParent(nullptr);
457}
458
459Q_DECLARE_METATYPE(QQuickPopup::ClosePolicy)
460
461void tst_QQuickPopup::closePolicy_data()
462{
463 qRegisterMetaType<QQuickPopup::ClosePolicy>();
464
465 QTest::addColumn<QString>(name: "source");
466 QTest::addColumn<QQuickPopup::ClosePolicy>(name: "closePolicy");
467
468 QTest::newRow(dataTag: "Window:NoAutoClose") << "window.qml"<< static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::NoAutoClose);
469 QTest::newRow(dataTag: "Window:CloseOnPressOutside") << "window.qml"<< static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::CloseOnPressOutside);
470 QTest::newRow(dataTag: "Window:CloseOnPressOutsideParent") << "window.qml"<< static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::CloseOnPressOutsideParent);
471 QTest::newRow(dataTag: "Window:CloseOnPressOutside|Parent") << "window.qml"<< static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::CloseOnPressOutside | QQuickPopup::CloseOnPressOutsideParent);
472 QTest::newRow(dataTag: "Window:CloseOnReleaseOutside") << "window.qml"<< static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::CloseOnReleaseOutside);
473 QTest::newRow(dataTag: "Window:CloseOnReleaseOutside|Parent") << "window.qml"<< static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::CloseOnReleaseOutside | QQuickPopup::CloseOnReleaseOutsideParent);
474 QTest::newRow(dataTag: "Window:CloseOnEscape") << "window.qml"<< static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::CloseOnEscape);
475
476 QTest::newRow(dataTag: "ApplicationWindow:NoAutoClose") << "applicationwindow.qml"<< static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::NoAutoClose);
477 QTest::newRow(dataTag: "ApplicationWindow:CloseOnPressOutside") << "applicationwindow.qml"<< static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::CloseOnPressOutside);
478 QTest::newRow(dataTag: "ApplicationWindow:CloseOnPressOutsideParent") << "applicationwindow.qml"<< static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::CloseOnPressOutsideParent);
479 QTest::newRow(dataTag: "ApplicationWindow:CloseOnPressOutside|Parent") << "applicationwindow.qml"<< static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::CloseOnPressOutside | QQuickPopup::CloseOnPressOutsideParent);
480 QTest::newRow(dataTag: "ApplicationWindow:CloseOnReleaseOutside") << "applicationwindow.qml"<< static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::CloseOnReleaseOutside);
481 QTest::newRow(dataTag: "ApplicationWindow:CloseOnReleaseOutside|Parent") << "applicationwindow.qml"<< static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::CloseOnReleaseOutside | QQuickPopup::CloseOnReleaseOutsideParent);
482 QTest::newRow(dataTag: "ApplicationWindow:CloseOnEscape") << "applicationwindow.qml"<< static_cast<QQuickPopup::ClosePolicy>(QQuickPopup::CloseOnEscape);
483}
484
485void tst_QQuickPopup::closePolicy()
486{
487 QFETCH(QString, source);
488 QFETCH(QQuickPopup::ClosePolicy, closePolicy);
489
490 QQuickApplicationHelper helper(this, source);
491 QVERIFY2(helper.ready, helper.failureMessage());
492
493 QQuickWindow *window = helper.window;
494 window->show();
495 window->requestActivate();
496 QVERIFY(QTest::qWaitForWindowActive(window));
497
498 QQuickPopup *popup = window->property(name: "popup").value<QQuickPopup*>();
499 QVERIFY(popup);
500
501 QQuickButton *button = window->property(name: "button").value<QQuickButton*>();
502 QVERIFY(button);
503
504 popup->setModal(true);
505 popup->setFocus(true);
506 popup->setClosePolicy(closePolicy);
507
508 popup->open();
509 QVERIFY(popup->isVisible());
510 QTRY_VERIFY(popup->isOpened());
511
512 // press outside popup and its parent
513 QTest::mousePress(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(1, 1), delay: 50);
514 if (closePolicy.testFlag(flag: QQuickPopup::CloseOnPressOutside) || closePolicy.testFlag(flag: QQuickPopup::CloseOnPressOutsideParent))
515 QTRY_VERIFY(!popup->isVisible());
516 else
517 QVERIFY(popup->isVisible());
518
519 popup->open();
520 QVERIFY(popup->isVisible());
521 QTRY_VERIFY(popup->isOpened());
522
523 // release outside popup and its parent
524 QTest::mouseRelease(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(1, 1));
525 if (closePolicy.testFlag(flag: QQuickPopup::CloseOnReleaseOutside))
526 QTRY_VERIFY(!popup->isVisible());
527 else
528 QVERIFY(popup->isVisible());
529
530 popup->open();
531 QVERIFY(popup->isVisible());
532 QTRY_VERIFY(popup->isOpened());
533
534 // press outside popup but inside its parent
535 QTest::mousePress(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(button->x() + 1, button->y() + 1));
536 if (closePolicy.testFlag(flag: QQuickPopup::CloseOnPressOutside) && !closePolicy.testFlag(flag: QQuickPopup::CloseOnPressOutsideParent))
537 QTRY_VERIFY(!popup->isVisible());
538 else
539 QVERIFY(popup->isVisible());
540
541 popup->open();
542 QVERIFY(popup->isVisible());
543 QTRY_VERIFY(popup->isOpened());
544
545 // release outside popup but inside its parent
546 QTest::mouseRelease(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(button->x() + 1, button->y() + 1));
547 if (closePolicy.testFlag(flag: QQuickPopup::CloseOnReleaseOutside) && !closePolicy.testFlag(flag: QQuickPopup::CloseOnReleaseOutsideParent))
548 QTRY_VERIFY(!popup->isVisible());
549 else
550 QVERIFY(popup->isVisible());
551
552 popup->open();
553 QVERIFY(popup->isVisible());
554 QTRY_VERIFY(popup->isOpened());
555
556 // press inside and release outside
557 QTest::mousePress(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(button->x() + popup->x() + 1,
558 button->y() + popup->y() + 1));
559 QVERIFY(popup->isVisible());
560 QTest::mouseRelease(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(1, 1));
561 QVERIFY(popup->isVisible());
562
563 // escape
564 QTest::keyClick(window, key: Qt::Key_Escape);
565 if (closePolicy.testFlag(flag: QQuickPopup::CloseOnEscape))
566 QTRY_VERIFY(!popup->isVisible());
567 else
568 QVERIFY(popup->isVisible());
569}
570
571void tst_QQuickPopup::activeFocusOnClose1()
572{
573 // Test that a popup that never sets focus: true (e.g. ToolTip) doesn't affect
574 // the active focus item when it closes.
575 QQuickApplicationHelper helper(this, QStringLiteral("activeFocusOnClose1.qml"));
576 QVERIFY2(helper.ready, helper.failureMessage());
577 QQuickApplicationWindow *window = helper.appWindow;
578 window->show();
579 window->requestActivate();
580 QVERIFY(QTest::qWaitForWindowActive(window));
581
582 QQuickPopup *focusedPopup = helper.appWindow->property(name: "focusedPopup").value<QQuickPopup*>();
583 QVERIFY(focusedPopup);
584
585 QQuickPopup *nonFocusedPopup = helper.appWindow->property(name: "nonFocusedPopup").value<QQuickPopup*>();
586 QVERIFY(nonFocusedPopup);
587
588 focusedPopup->open();
589 QVERIFY(focusedPopup->isVisible());
590 QTRY_VERIFY(focusedPopup->isOpened());
591 QVERIFY(focusedPopup->hasActiveFocus());
592
593 nonFocusedPopup->open();
594 QVERIFY(nonFocusedPopup->isVisible());
595 QTRY_VERIFY(nonFocusedPopup->isOpened());
596 QVERIFY(focusedPopup->hasActiveFocus());
597
598 nonFocusedPopup->close();
599 QTRY_VERIFY(!nonFocusedPopup->isVisible());
600 QVERIFY(focusedPopup->hasActiveFocus());
601
602 // QTBUG-66113: force active focus on a popup that did not request focus
603 nonFocusedPopup->open();
604 nonFocusedPopup->forceActiveFocus();
605 QVERIFY(nonFocusedPopup->isVisible());
606 QTRY_VERIFY(nonFocusedPopup->isOpened());
607 QVERIFY(nonFocusedPopup->hasActiveFocus());
608
609 nonFocusedPopup->close();
610 QTRY_VERIFY(!nonFocusedPopup->isVisible());
611 QVERIFY(focusedPopup->hasActiveFocus());
612}
613
614void tst_QQuickPopup::activeFocusOnClose2()
615{
616 // Test that a popup that sets focus: true but relinquishes focus (e.g. by
617 // calling forceActiveFocus() on another item) before it closes doesn't
618 // affect the active focus item when it closes.
619 QQuickApplicationHelper helper(this, QStringLiteral("activeFocusOnClose2.qml"));
620 QVERIFY2(helper.ready, helper.failureMessage());
621 QQuickApplicationWindow *window = helper.appWindow;
622 window->show();
623 window->requestActivate();
624 QVERIFY(QTest::qWaitForWindowActive(window));
625
626 QQuickPopup *popup1 = helper.appWindow->property(name: "popup1").value<QQuickPopup*>();
627 QVERIFY(popup1);
628
629 QQuickPopup *popup2 = helper.appWindow->property(name: "popup2").value<QQuickPopup*>();
630 QVERIFY(popup2);
631
632 QQuickButton *closePopup2Button = helper.appWindow->property(name: "closePopup2Button").value<QQuickButton*>();
633 QVERIFY(closePopup2Button);
634
635 popup1->open();
636 QVERIFY(popup1->isVisible());
637 QTRY_VERIFY(popup1->isOpened());
638 QVERIFY(popup1->hasActiveFocus());
639
640 popup2->open();
641 QVERIFY(popup2->isVisible());
642 QTRY_VERIFY(popup2->isOpened());
643 QVERIFY(popup2->hasActiveFocus());
644
645 // Causes popup1.contentItem.forceActiveFocus() to be called, then closes popup2.
646 QTest::mouseClick(window, button: Qt::LeftButton, stateKey: Qt::NoModifier,
647 pos: closePopup2Button->mapToScene(point: QPointF(closePopup2Button->width() / 2, closePopup2Button->height() / 2)).toPoint());
648 QTRY_VERIFY(!popup2->isVisible());
649 QVERIFY(popup1->hasActiveFocus());
650}
651
652void tst_QQuickPopup::activeFocusOnClose3()
653{
654 // Test that a closing popup that had focus doesn't steal focus from
655 // another popup that the focus was transferred to.
656 QQuickApplicationHelper helper(this, QStringLiteral("activeFocusOnClose3.qml"));
657 QVERIFY2(helper.ready, helper.failureMessage());
658 QQuickApplicationWindow *window = helper.appWindow;
659 window->show();
660 window->requestActivate();
661 QVERIFY(QTest::qWaitForWindowActive(window));
662
663 QQuickPopup *popup1 = helper.appWindow->property(name: "popup1").value<QQuickPopup*>();
664 QVERIFY(popup1);
665
666 QQuickPopup *popup2 = helper.appWindow->property(name: "popup2").value<QQuickPopup*>();
667 QVERIFY(popup2);
668
669 popup1->open();
670 QVERIFY(popup1->isVisible());
671 QTRY_VERIFY(popup1->hasActiveFocus());
672
673 popup2->open();
674 popup1->close();
675
676 QSignalSpy closedSpy(popup1, SIGNAL(closed()));
677 QVERIFY(closedSpy.isValid());
678 QVERIFY(closedSpy.wait());
679
680 QVERIFY(!popup1->isVisible());
681 QVERIFY(popup2->isVisible());
682 QTRY_VERIFY(popup2->hasActiveFocus());
683}
684
685void tst_QQuickPopup::activeFocusOnClosingSeveralPopups()
686{
687 // Test that active focus isn't lost when multiple popup closing simultaneously
688 QQuickApplicationHelper helper(this, QStringLiteral("activeFocusOnClosingSeveralPopups.qml"));
689 QVERIFY2(helper.ready, helper.failureMessage());
690 QQuickApplicationWindow *window = helper.appWindow;
691 window->show();
692 window->requestActivate();
693 QVERIFY(QTest::qWaitForWindowActive(window));
694
695 QQuickItem *button = window->property(name: "button").value<QQuickItem *>();
696 QVERIFY(button);
697
698 QQuickPopup *popup1 = window->property(name: "popup1").value<QQuickPopup *>();
699 QVERIFY(popup1);
700
701 QQuickPopup *popup2 = window->property(name: "popup2").value<QQuickPopup *>();
702 QVERIFY(popup2);
703
704 QCOMPARE(button->hasActiveFocus(), true);
705 popup1->open();
706 QTRY_VERIFY(popup1->isOpened());
707 QVERIFY(popup1->hasActiveFocus());
708 popup2->open();
709 QTRY_VERIFY(popup2->isOpened());
710 QVERIFY(popup2->hasActiveFocus());
711 QTRY_COMPARE(button->hasActiveFocus(), false);
712 // close the unfocused popup first
713 popup1->close();
714 popup2->close();
715 QTRY_VERIFY(!popup1->isVisible());
716 QTRY_VERIFY(!popup2->isVisible());
717 QTRY_COMPARE(button->hasActiveFocus(), true);
718
719 popup1->open();
720 QTRY_VERIFY(popup1->isOpened());
721 QVERIFY(popup1->hasActiveFocus());
722 popup2->open();
723 QTRY_VERIFY(popup2->isOpened());
724 QVERIFY(popup2->hasActiveFocus());
725 QTRY_COMPARE(button->hasActiveFocus(), false);
726 // close the focused popup first
727 popup2->close();
728 popup1->close();
729 QTRY_VERIFY(!popup1->isVisible());
730 QTRY_VERIFY(!popup2->isVisible());
731 QTRY_COMPARE(button->hasActiveFocus(), true);
732}
733
734void tst_QQuickPopup::activeFocusAfterExit()
735{
736 // Test that after closing a popup the highest one in z-order receives it instead.
737 QQuickApplicationHelper helper(this, QStringLiteral("activeFocusAfterExit.qml"));
738 QVERIFY2(helper.ready, helper.failureMessage());
739 QQuickApplicationWindow *window = helper.appWindow;
740 window->show();
741 window->requestActivate();
742 QVERIFY(QTest::qWaitForWindowActive(window));
743
744 QQuickPopup *popup1 = window->property(name: "popup1").value<QQuickPopup*>();
745 QVERIFY(popup1);
746
747 QQuickPopup *popup2 = window->property(name: "popup2").value<QQuickPopup*>();
748 QVERIFY(popup2);
749 QSignalSpy closedSpy2(popup2, SIGNAL(closed()));
750 QVERIFY(closedSpy2.isValid());
751
752 QQuickPopup *popup3 = window->property(name: "popup3").value<QQuickPopup*>();
753 QVERIFY(popup3);
754 QSignalSpy closedSpy3(popup3, SIGNAL(closed()));
755 QVERIFY(closedSpy3.isValid());
756
757 popup1->open();
758 QVERIFY(popup1->isVisible());
759 QTRY_VERIFY(popup1->hasActiveFocus());
760
761 popup2->open();
762 QVERIFY(popup2->isVisible());
763 QTRY_VERIFY(!popup2->hasActiveFocus());
764
765 popup3->open();
766 QVERIFY(popup3->isVisible());
767 QTRY_VERIFY(popup3->hasActiveFocus());
768
769 popup3->close();
770 closedSpy3.wait();
771 QVERIFY(!popup3->isVisible());
772 QTRY_VERIFY(!popup3->hasActiveFocus());
773 QTRY_VERIFY(!popup2->hasActiveFocus());
774 QTRY_VERIFY(popup1->hasActiveFocus());
775
776 popup2->close();
777 closedSpy2.wait();
778 QVERIFY(!popup2->isVisible());
779 QTRY_VERIFY(!popup2->hasActiveFocus());
780 QTRY_VERIFY(popup1->hasActiveFocus());
781}
782
783void tst_QQuickPopup::activeFocusOnDelayedEnter()
784{
785 // Test that after opening two popups, first of which has an animation, does not cause
786 // the first one to receive focus after the animation stops.
787 QQuickApplicationHelper helper(this, QStringLiteral("activeFocusOnDelayedEnter.qml"));
788 QVERIFY2(helper.ready, helper.failureMessage());
789 QQuickApplicationWindow *window = helper.appWindow;
790 window->show();
791 window->requestActivate();
792 QVERIFY(QTest::qWaitForWindowActive(window));
793
794 QQuickPopup *popup1 = window->property(name: "popup1").value<QQuickPopup*>();
795 QVERIFY(popup1);
796 QSignalSpy openedSpy(popup1, SIGNAL(opened()));
797
798 QQuickPopup *popup2 = window->property(name: "popup2").value<QQuickPopup*>();
799 QVERIFY(popup2);
800
801 popup1->open();
802 popup2->open();
803 openedSpy.wait();
804 QTRY_VERIFY(popup2->hasActiveFocus());
805}
806
807void tst_QQuickPopup::hover_data()
808{
809 QTest::addColumn<QString>(name: "source");
810 QTest::addColumn<bool>(name: "modal");
811
812 QTest::newRow(dataTag: "Window:modal") << "window-hover.qml" << true;
813 QTest::newRow(dataTag: "Window:modeless") << "window-hover.qml" << false;
814 QTest::newRow(dataTag: "ApplicationWindow:modal") << "applicationwindow-hover.qml" << true;
815 QTest::newRow(dataTag: "ApplicationWindow:modeless") << "applicationwindow-hover.qml" << false;
816}
817
818void tst_QQuickPopup::hover()
819{
820 QFETCH(QString, source);
821 QFETCH(bool, modal);
822
823 QQuickApplicationHelper helper(this, source);
824 QVERIFY2(helper.ready, helper.failureMessage());
825 QQuickWindow *window = helper.window;
826 window->show();
827 window->requestActivate();
828 QVERIFY(QTest::qWaitForWindowActive(window));
829
830 QQuickPopup *popup = window->property(name: "popup").value<QQuickPopup*>();
831 QVERIFY(popup);
832 popup->setModal(modal);
833
834 QQuickButton *parentButton = window->property(name: "parentButton").value<QQuickButton*>();
835 QVERIFY(parentButton);
836 parentButton->setHoverEnabled(true);
837
838 QQuickButton *childButton = window->property(name: "childButton").value<QQuickButton*>();
839 QVERIFY(childButton);
840 childButton->setHoverEnabled(true);
841
842 QSignalSpy openedSpy(popup, SIGNAL(opened()));
843 QVERIFY(openedSpy.isValid());
844 popup->open();
845 QVERIFY(openedSpy.count() == 1 || openedSpy.wait());
846
847 // hover the parent button outside the popup
848 QTest::mouseMove(window, pos: QPoint(window->width() - 1, window->height() - 1));
849 QCOMPARE(parentButton->isHovered(), !modal);
850 QVERIFY(!childButton->isHovered());
851
852 // hover the popup background
853 QTest::mouseMove(window, pos: QPoint(1, 1));
854 QVERIFY(!parentButton->isHovered());
855 QVERIFY(!childButton->isHovered());
856
857 // hover the child button in a popup
858 QTest::mouseMove(window, pos: QPoint(popup->x() + popup->width() / 2, popup->y() + popup->height() / 2));
859 QVERIFY(!parentButton->isHovered());
860 QVERIFY(childButton->isHovered());
861
862 QSignalSpy closedSpy(popup, SIGNAL(closed()));
863 QVERIFY(closedSpy.isValid());
864 popup->close();
865 QVERIFY(closedSpy.count() == 1 || closedSpy.wait());
866
867 // hover the parent button after closing the popup
868 QTest::mouseMove(window, pos: QPoint(window->width() / 2, window->height() / 2));
869 QVERIFY(parentButton->isHovered());
870}
871
872void tst_QQuickPopup::wheel_data()
873{
874 QTest::addColumn<QString>(name: "source");
875 QTest::addColumn<bool>(name: "modal");
876
877 QTest::newRow(dataTag: "Window:modal") << "window-wheel.qml" << true;
878 QTest::newRow(dataTag: "Window:modeless") << "window-wheel.qml" << false;
879 QTest::newRow(dataTag: "ApplicationWindow:modal") << "applicationwindow-wheel.qml" << true;
880 QTest::newRow(dataTag: "ApplicationWindow:modeless") << "applicationwindow-wheel.qml" << false;
881}
882
883static bool sendWheelEvent(QQuickItem *item, const QPoint &localPos, int degrees)
884{
885 QQuickWindow *window = item->window();
886 QWheelEvent wheelEvent(localPos, item->window()->mapToGlobal(pos: localPos),
887 QPoint(0, 0), QPoint(0, 8 * degrees),
888 0, Qt::Vertical, Qt::NoButton, {});
889 QSpontaneKeyEvent::setSpontaneous(&wheelEvent);
890 return qGuiApp->notify(window, &wheelEvent);
891}
892
893void tst_QQuickPopup::wheel()
894{
895 QFETCH(QString, source);
896 QFETCH(bool, modal);
897
898 QQuickApplicationHelper helper(this, source);
899 QVERIFY2(helper.ready, helper.failureMessage());
900 QQuickWindow *window = helper.window;
901 window->show();
902 QVERIFY(QTest::qWaitForWindowExposed(window));
903
904 QQuickSlider *contentSlider = window->property(name: "contentSlider").value<QQuickSlider*>();
905 QVERIFY(contentSlider);
906
907 QQuickPopup *popup = window->property(name: "popup").value<QQuickPopup*>();
908 QVERIFY(popup && popup->contentItem());
909 popup->setModal(modal);
910
911 QQuickSlider *popupSlider = window->property(name: "popupSlider").value<QQuickSlider*>();
912 QVERIFY(popupSlider);
913
914 {
915 // wheel over the content
916 qreal oldContentValue = contentSlider->value();
917 qreal oldPopupValue = popupSlider->value();
918
919 QVERIFY(sendWheelEvent(contentSlider, QPoint(contentSlider->width() / 2, contentSlider->height() / 2), 15));
920
921 QVERIFY(!qFuzzyCompare(contentSlider->value(), oldContentValue)); // must have moved
922 QVERIFY(qFuzzyCompare(popupSlider->value(), oldPopupValue)); // must not have moved
923 }
924
925 QSignalSpy openedSpy(popup, SIGNAL(opened()));
926 QVERIFY(openedSpy.isValid());
927 popup->open();
928 QVERIFY(openedSpy.count() == 1 || openedSpy.wait());
929
930 {
931 // wheel over the popup content
932 qreal oldContentValue = contentSlider->value();
933 qreal oldPopupValue = popupSlider->value();
934
935 QVERIFY(sendWheelEvent(popupSlider, QPoint(popupSlider->width() / 2, popupSlider->height() / 2), 15));
936
937 QVERIFY(qFuzzyCompare(contentSlider->value(), oldContentValue)); // must not have moved
938 QVERIFY(!qFuzzyCompare(popupSlider->value(), oldPopupValue)); // must have moved
939 }
940
941 {
942 // wheel over the overlay
943 qreal oldContentValue = contentSlider->value();
944 qreal oldPopupValue = popupSlider->value();
945
946 QVERIFY(sendWheelEvent(QQuickOverlay::overlay(window), QPoint(0, 0), 15));
947
948 if (modal) {
949 // the content below a modal overlay must not move
950 QVERIFY(qFuzzyCompare(contentSlider->value(), oldContentValue));
951 } else {
952 // the content below a modeless overlay must move
953 QVERIFY(!qFuzzyCompare(contentSlider->value(), oldContentValue));
954 }
955 QVERIFY(qFuzzyCompare(popupSlider->value(), oldPopupValue)); // must not have moved
956 }
957}
958
959void tst_QQuickPopup::parentDestroyed()
960{
961 QQuickPopup popup;
962 popup.setParentItem(new QQuickItem);
963 delete popup.parentItem();
964 QVERIFY(!popup.parentItem());
965}
966
967void tst_QQuickPopup::nested()
968{
969 QQuickApplicationHelper helper(this, QStringLiteral("nested.qml"));
970 QVERIFY2(helper.ready, helper.failureMessage());
971 QQuickWindow *window = helper.window;
972 window->show();
973 QVERIFY(QTest::qWaitForWindowExposed(window));
974
975 QQuickPopup *modalPopup = window->property(name: "modalPopup").value<QQuickPopup *>();
976 QVERIFY(modalPopup);
977
978 QQuickPopup *modelessPopup = window->property(name: "modelessPopup").value<QQuickPopup *>();
979 QVERIFY(modelessPopup);
980
981 modalPopup->open();
982 QCOMPARE(modalPopup->isVisible(), true);
983
984 modelessPopup->open();
985 QCOMPARE(modelessPopup->isVisible(), true);
986
987 // click outside the modeless popup on the top, but inside the modal popup below
988 QTest::mouseClick(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(150, 150));
989
990 QTRY_COMPARE(modelessPopup->isVisible(), false);
991 QCOMPARE(modalPopup->isVisible(), true);
992}
993
994void tst_QQuickPopup::modelessOnModalOnModeless()
995{
996 QQuickApplicationHelper helper(this, QStringLiteral("modelessOnModalOnModeless.qml"));
997 QVERIFY2(helper.ready, helper.failureMessage());
998 QQuickWindow *window = helper.window;
999 window->show();
1000 QVERIFY(QTest::qWaitForWindowExposed(window));
1001
1002 QQuickPopup *modelessPopup = window->property(name: "modelessPopup").value<QQuickPopup *>();
1003 QVERIFY(modelessPopup);
1004
1005 QQuickButton *button = window->property(name: "button").value<QQuickButton *>();
1006 QVERIFY(button);
1007 QQuickPopup *modalPopup = window->property(name: "modalPopup").value<QQuickPopup *>();
1008 QVERIFY(modalPopup);
1009 QQuickPopup *tooltip = window->property(name: "tooltip").value<QQuickPopup *>();
1010 QVERIFY(modalPopup);
1011
1012 modelessPopup->open();
1013 QCOMPARE(modelessPopup->isVisible(), true);
1014 QTRY_COMPARE(modelessPopup->isOpened(), true);
1015 const auto buttonPoint = button->mapToScene(point: button->boundingRect().center()).toPoint();
1016 // click into the button, should not be blocked
1017 QTest::mouseClick(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: buttonPoint);
1018 QVERIFY(button->isChecked());
1019 modalPopup->open();
1020 QCOMPARE(modalPopup->isVisible(), true);
1021 QTRY_COMPARE(modalPopup->isOpened(), true);
1022 // click into the button, should be blocked
1023 QTest::mouseClick(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: buttonPoint);
1024 QVERIFY(button->isChecked());
1025
1026 tooltip->setVisible(true);
1027 QCOMPARE(tooltip->isVisible(), true);
1028 QTRY_COMPARE(tooltip->isOpened(), true);
1029 // click into the button, should be blocked
1030 QTest::mouseClick(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: buttonPoint);
1031 QVERIFY(button->isChecked());
1032}
1033
1034// QTBUG-56697
1035void tst_QQuickPopup::grabber()
1036{
1037 QQuickApplicationHelper helper(this, QStringLiteral("grabber.qml"));
1038 QVERIFY2(helper.ready, helper.failureMessage());
1039 QQuickWindow *window = helper.window;
1040 window->show();
1041 QVERIFY(QTest::qWaitForWindowExposed(window));
1042
1043 QQuickPopup *menu = window->property(name: "menu").value<QQuickPopup *>();
1044 QVERIFY(menu);
1045
1046 QQuickPopup *popup = window->property(name: "popup").value<QQuickPopup *>();
1047 QVERIFY(popup);
1048
1049 QQuickPopup *combo = window->property(name: "combo").value<QQuickPopup *>();
1050 QVERIFY(combo);
1051
1052 menu->open();
1053 QTRY_COMPARE(menu->isOpened(), true);
1054 QCOMPARE(popup->isVisible(), false);
1055 QCOMPARE(combo->isVisible(), false);
1056
1057 // click a menu item to open the popup
1058 QTest::mouseClick(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(menu->width() / 2, menu->height() / 2));
1059 QTRY_COMPARE(menu->isVisible(), false);
1060 QTRY_COMPARE(popup->isOpened(), true);
1061 QCOMPARE(combo->isVisible(), false);
1062
1063 combo->open();
1064 QCOMPARE(menu->isVisible(), false);
1065 QCOMPARE(popup->isVisible(), true);
1066 QTRY_COMPARE(combo->isOpened(), true);
1067
1068 // click outside to close both the combo popup and the parent popup
1069 QTest::mouseClick(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(window->width() - 1, window->height() - 1));
1070 QCOMPARE(menu->isVisible(), false);
1071 QTRY_COMPARE(popup->isVisible(), false);
1072 QTRY_COMPARE(combo->isVisible(), false);
1073
1074 menu->open();
1075 QTRY_COMPARE(menu->isOpened(), true);
1076 QCOMPARE(popup->isVisible(), false);
1077 QCOMPARE(combo->isVisible(), false);
1078
1079 // click outside the menu to close it (QTBUG-56697)
1080 QTest::mouseClick(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: QPoint(window->width() - 1, window->height() - 1));
1081 QTRY_COMPARE(menu->isVisible(), false);
1082 QCOMPARE(popup->isVisible(), false);
1083 QCOMPARE(combo->isVisible(), false);
1084}
1085
1086void tst_QQuickPopup::cursorShape()
1087{
1088 // Ensure that the mouse cursor has the correct shape when over a popup
1089 // which is itself over an item with a different shape.
1090 QQuickApplicationHelper helper(this, QStringLiteral("cursor.qml"));
1091 QVERIFY2(helper.ready, helper.failureMessage());
1092 QQuickApplicationWindow *window = helper.appWindow;
1093 centerOnScreen(window);
1094 moveMouseAway(window);
1095 window->show();
1096 QVERIFY(QTest::qWaitForWindowExposed(window));
1097
1098 QQuickPopup *popup = helper.appWindow->property(name: "popup").value<QQuickPopup*>();
1099 QVERIFY(popup);
1100
1101 popup->open();
1102 QVERIFY(popup->isVisible());
1103 QTRY_VERIFY(popup->isOpened());
1104
1105 QQuickItem *textField = helper.appWindow->property(name: "textField").value<QQuickItem*>();
1106 QVERIFY(textField);
1107
1108 // Move the mouse over the text field.
1109 const QPoint textFieldPos(popup->x() - 10, textField->height() / 2);
1110 QTest::mouseMove(window, pos: textFieldPos);
1111 QCOMPARE(window->cursor().shape(), textField->cursor().shape());
1112
1113 // Move the mouse over the popup where it overlaps with the text field.
1114 const QPoint textFieldOverlapPos(popup->x() + 10, textField->height() / 2);
1115 QTest::mouseMove(window, pos: textFieldOverlapPos);
1116 QCOMPARE(window->cursor().shape(), popup->popupItem()->cursor().shape());
1117
1118 popup->close();
1119 QTRY_VERIFY(!popup->isVisible());
1120}
1121
1122class FriendlyPopup : public QQuickPopup
1123{
1124 friend class tst_QQuickPopup;
1125};
1126
1127void tst_QQuickPopup::componentComplete()
1128{
1129 FriendlyPopup cppPopup;
1130 QVERIFY(cppPopup.isComponentComplete());
1131
1132 QQmlEngine engine;
1133 QQmlComponent component(&engine);
1134 component.setData("import QtQuick.Controls 2.2; Popup { }", baseUrl: QUrl());
1135
1136 FriendlyPopup *qmlPopup = static_cast<FriendlyPopup *>(component.beginCreate(engine.rootContext()));
1137 QVERIFY(qmlPopup);
1138 QVERIFY(!qmlPopup->isComponentComplete());
1139
1140 component.completeCreate();
1141 QVERIFY(qmlPopup->isComponentComplete());
1142}
1143
1144void tst_QQuickPopup::closeOnEscapeWithNestedPopups()
1145{
1146 // Tests the scenario in the Gallery example, where there are nested popups that should
1147 // close in the correct order when the Escape key is pressed.
1148 QQuickApplicationHelper helper(this, QStringLiteral("closeOnEscapeWithNestedPopups.qml"));
1149 QVERIFY2(helper.ready, helper.failureMessage());
1150 QQuickApplicationWindow *window = helper.appWindow;
1151 window->show();
1152 QVERIFY(QTest::qWaitForWindowExposed(window));
1153
1154 // The stack view should have two items, and it should pop the second when escape is pressed
1155 // and it has focus.
1156 QQuickStackView *stackView = window->findChild<QQuickStackView*>(aName: "stackView");
1157 QVERIFY(stackView);
1158 QCOMPARE(stackView->depth(), 2);
1159
1160 QQuickItem *optionsToolButton = window->findChild<QQuickItem*>(aName: "optionsToolButton");
1161 QVERIFY(optionsToolButton);
1162
1163 // Click on the options tool button. The settings menu should pop up.
1164 const QPoint optionsToolButtonCenter = optionsToolButton->mapToScene(
1165 point: QPointF(optionsToolButton->width() / 2, optionsToolButton->height() / 2)).toPoint();
1166 QTest::mouseClick(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: optionsToolButtonCenter);
1167
1168 QQuickPopup *optionsMenu = window->findChild<QQuickPopup*>(aName: "optionsMenu");
1169 QVERIFY(optionsMenu);
1170 QTRY_VERIFY(optionsMenu->isVisible());
1171
1172 QQuickItem *settingsMenuItem = window->findChild<QQuickItem*>(aName: "settingsMenuItem");
1173 QVERIFY(settingsMenuItem);
1174
1175 // Click on the settings menu item. The settings dialog should pop up.
1176 const QPoint settingsMenuItemCenter = settingsMenuItem->mapToScene(
1177 point: QPointF(settingsMenuItem->width() / 2, settingsMenuItem->height() / 2)).toPoint();
1178 QTest::mouseClick(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: settingsMenuItemCenter);
1179
1180 QQuickPopup *settingsDialog = window->contentItem()->findChild<QQuickPopup*>(aName: "settingsDialog");
1181 QVERIFY(settingsDialog);
1182 QTRY_VERIFY(settingsDialog->isVisible());
1183
1184 QQuickComboBox *comboBox = window->contentItem()->findChild<QQuickComboBox*>(aName: "comboBox");
1185 QVERIFY(comboBox);
1186
1187 // Click on the combo box button. The combo box popup should pop up.
1188 const QPoint comboBoxCenter = comboBox->mapToScene(
1189 point: QPointF(comboBox->width() / 2, comboBox->height() / 2)).toPoint();
1190 QTest::mouseClick(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: comboBoxCenter);
1191 QTRY_VERIFY(comboBox->popup()->isVisible());
1192
1193 // Close the combo box popup with the escape key. The settings dialog should still be visible.
1194 QTest::keyClick(window, key: Qt::Key_Escape);
1195 QTRY_VERIFY(!comboBox->popup()->isVisible());
1196 QVERIFY(settingsDialog->isVisible());
1197
1198 // Close the settings dialog with the escape key.
1199 QTest::keyClick(window, key: Qt::Key_Escape);
1200 QTRY_VERIFY(!settingsDialog->isVisible());
1201
1202 // The stack view should still have two items.
1203 QCOMPARE(stackView->depth(), 2);
1204
1205 // Remove one by pressing the Escape key (the Shortcut should be activated).
1206 QTest::keyClick(window, key: Qt::Key_Escape);
1207 QCOMPARE(stackView->depth(), 1);
1208}
1209
1210void tst_QQuickPopup::closeOnEscapeWithVisiblePopup()
1211{
1212 QQuickApplicationHelper helper(this, QStringLiteral("closeOnEscapeWithVisiblePopup.qml"));
1213 QVERIFY2(helper.ready, helper.failureMessage());
1214 QQuickWindow *window = helper.window;
1215 window->show();
1216 QVERIFY(QTest::qWaitForWindowActive(window));
1217
1218 QQuickPopup *popup = window->findChild<QQuickPopup *>(aName: "popup");
1219 QVERIFY(popup);
1220 QTRY_VERIFY(popup->isOpened());
1221
1222 QTRY_VERIFY(window->activeFocusItem());
1223 QTest::keyClick(window, key: Qt::Key_Escape);
1224 QTRY_VERIFY(!popup->isVisible());
1225}
1226
1227void tst_QQuickPopup::enabled()
1228{
1229 QQuickPopup popup;
1230 QVERIFY(popup.isEnabled());
1231 QVERIFY(popup.popupItem()->isEnabled());
1232
1233 QSignalSpy enabledSpy(&popup, &QQuickPopup::enabledChanged);
1234 QVERIFY(enabledSpy.isValid());
1235
1236 popup.setEnabled(false);
1237 QVERIFY(!popup.isEnabled());
1238 QVERIFY(!popup.popupItem()->isEnabled());
1239 QCOMPARE(enabledSpy.count(), 1);
1240
1241 popup.popupItem()->setEnabled(true);
1242 QVERIFY(popup.isEnabled());
1243 QVERIFY(popup.popupItem()->isEnabled());
1244 QCOMPARE(enabledSpy.count(), 2);
1245}
1246
1247void tst_QQuickPopup::orientation_data()
1248{
1249 QTest::addColumn<Qt::ScreenOrientation>(name: "orientation");
1250 QTest::addColumn<QPointF>(name: "position");
1251
1252 QTest::newRow(dataTag: "Portrait") << Qt::PortraitOrientation << QPointF(330, 165);
1253 QTest::newRow(dataTag: "Landscape") << Qt::LandscapeOrientation << QPointF(165, 270);
1254 QTest::newRow(dataTag: "InvertedPortrait") << Qt::InvertedPortraitOrientation << QPointF(270, 135);
1255 QTest::newRow(dataTag: "InvertedLandscape") << Qt::InvertedLandscapeOrientation << QPointF(135, 330);
1256}
1257
1258void tst_QQuickPopup::orientation()
1259{
1260 QFETCH(Qt::ScreenOrientation, orientation);
1261 QFETCH(QPointF, position);
1262
1263 QQuickApplicationHelper helper(this, "orientation.qml");
1264 QVERIFY2(helper.ready, helper.failureMessage());
1265
1266 QQuickWindow *window = helper.window;
1267 window->reportContentOrientationChange(orientation);
1268 window->show();
1269 QVERIFY(QTest::qWaitForWindowActive(window));
1270
1271 QQuickPopup *popup = window->property(name: "popup").value<QQuickPopup*>();
1272 QVERIFY(popup);
1273 popup->open();
1274
1275 QCOMPARE(popup->popupItem()->position(), position);
1276}
1277
1278void tst_QQuickPopup::qquickview()
1279{
1280 QQuickView view;
1281 view.setObjectName("QQuickView");
1282 view.resize(w: 400, h: 400);
1283 view.setSource(testFileUrl(fileName: "dialog.qml"));
1284 QVERIFY(view.status() != QQuickView::Error);
1285 view.contentItem()->setObjectName("QQuickViewContentItem");
1286 view.show();
1287
1288 QQuickDialog *dialog = view.rootObject()->property(name: "dialog").value<QQuickDialog*>();
1289 QVERIFY(dialog);
1290 QTRY_COMPARE(dialog->property("opened").toBool(), true);
1291
1292 dialog->close();
1293 QTRY_COMPARE(dialog->property("visible").toBool(), false);
1294
1295 // QTBUG-72746: shouldn't crash on application exit after closing a Dialog when using QQuickView.
1296}
1297
1298// TODO: also test it out without setting enabled directly on menu, but on a parent
1299
1300// QTBUG-73447
1301void tst_QQuickPopup::disabledPalette()
1302{
1303 QQuickApplicationHelper helper(this, "disabledPalette.qml");
1304 QVERIFY2(helper.ready, helper.failureMessage());
1305
1306 QQuickWindow *window = helper.window;
1307 window->show();
1308 QVERIFY(QTest::qWaitForWindowActive(window));
1309
1310 QQuickPopup *popup = window->property(name: "popup").value<QQuickPopup*>();
1311 QVERIFY(popup);
1312
1313 QSignalSpy popupEnabledSpy(popup, SIGNAL(enabledChanged()));
1314 QVERIFY(popupEnabledSpy.isValid());
1315 QSignalSpy popupPaletteSpy(popup, SIGNAL(paletteChanged()));
1316 QVERIFY(popupPaletteSpy.isValid());
1317
1318 QSignalSpy popupItemEnabledSpy(popup->popupItem(), SIGNAL(enabledChanged()));
1319 QVERIFY(popupItemEnabledSpy.isValid());
1320 QSignalSpy popupItemPaletteSpy(popup->popupItem(), SIGNAL(paletteChanged()));
1321 QVERIFY(popupItemPaletteSpy.isValid());
1322
1323 QPalette palette = popup->palette();
1324 palette.setColor(acg: QPalette::Active, acr: QPalette::Base, acolor: Qt::green);
1325 palette.setColor(acg: QPalette::Disabled, acr: QPalette::Base, acolor: Qt::red);
1326 popup->setPalette(palette);
1327 QCOMPARE(popupPaletteSpy.count(), 1);
1328 QCOMPARE(popupItemPaletteSpy.count(), 1);
1329 QCOMPARE(popup->background()->property("color").value<QColor>(), Qt::green);
1330
1331 popup->setEnabled(false);
1332 QCOMPARE(popupEnabledSpy.count(), 1);
1333 QCOMPARE(popupItemEnabledSpy.count(), 1);
1334 QCOMPARE(popupPaletteSpy.count(), 2);
1335 QCOMPARE(popupItemPaletteSpy.count(), 2);
1336 QCOMPARE(popup->background()->property("color").value<QColor>(), Qt::red);
1337}
1338
1339void tst_QQuickPopup::disabledParentPalette()
1340{
1341 QQuickApplicationHelper helper(this, "disabledPalette.qml");
1342 QVERIFY2(helper.ready, helper.failureMessage());
1343
1344 QQuickWindow *window = helper.window;
1345 window->show();
1346 QVERIFY(QTest::qWaitForWindowActive(window));
1347
1348 QQuickPopup *popup = window->property(name: "popup").value<QQuickPopup*>();
1349 QVERIFY(popup);
1350
1351 QSignalSpy popupEnabledSpy(popup, SIGNAL(enabledChanged()));
1352 QVERIFY(popupEnabledSpy.isValid());
1353 QSignalSpy popupPaletteSpy(popup, SIGNAL(paletteChanged()));
1354 QVERIFY(popupPaletteSpy.isValid());
1355
1356 QSignalSpy popupItemEnabledSpy(popup->popupItem(), SIGNAL(enabledChanged()));
1357 QVERIFY(popupItemEnabledSpy.isValid());
1358 QSignalSpy popupItemPaletteSpy(popup->popupItem(), SIGNAL(paletteChanged()));
1359 QVERIFY(popupItemPaletteSpy.isValid());
1360
1361 QPalette palette = popup->palette();
1362 palette.setColor(acg: QPalette::Active, acr: QPalette::Base, acolor: Qt::green);
1363 palette.setColor(acg: QPalette::Disabled, acr: QPalette::Base, acolor: Qt::red);
1364 popup->setPalette(palette);
1365 QCOMPARE(popupPaletteSpy.count(), 1);
1366 QCOMPARE(popupItemPaletteSpy.count(), 1);
1367 QCOMPARE(popup->background()->property("color").value<QColor>(), Qt::green);
1368
1369 // Disable the overlay (which is QQuickPopupItem's parent) to ensure that
1370 // the palette is changed when the popup is indirectly disabled.
1371 popup->open();
1372 QTRY_VERIFY(popup->isOpened());
1373 QVERIFY(QMetaObject::invokeMethod(window, "disableOverlay"));
1374 QVERIFY(!popup->isEnabled());
1375 QVERIFY(!popup->popupItem()->isEnabled());
1376 QCOMPARE(popup->background()->property("color").value<QColor>(), Qt::red);
1377 QCOMPARE(popupEnabledSpy.count(), 1);
1378 QCOMPARE(popupItemEnabledSpy.count(), 1);
1379 QCOMPARE(popupPaletteSpy.count(), 2);
1380 QCOMPARE(popupItemPaletteSpy.count(), 2);
1381
1382 popup->close();
1383 QTRY_VERIFY(!popup->isVisible());
1384}
1385
1386void tst_QQuickPopup::countChanged()
1387{
1388 QQuickApplicationHelper helper(this, "countChanged.qml");
1389 QVERIFY2(helper.ready, helper.failureMessage());
1390
1391 QQuickWindow *window = helper.window;
1392 window->show();
1393 QVERIFY(QTest::qWaitForWindowActive(window));
1394
1395 QQuickComboBox *comboBox = window->property(name: "comboBox").value<QQuickComboBox*>();
1396 QVERIFY(comboBox);
1397 QCOMPARE(window->property("count").toInt(), 1);
1398
1399 QVERIFY(window->setProperty("isModel1", false));
1400 QTRY_COMPARE(window->property("count").toInt(), 2);
1401}
1402
1403// QTBUG-73243
1404void tst_QQuickPopup::toolTipCrashOnClose()
1405{
1406 QQuickApplicationHelper helper(this, "toolTipCrashOnClose.qml");
1407 QVERIFY2(helper.ready, helper.failureMessage());
1408
1409 QQuickWindow *window = helper.window;
1410 window->show();
1411 // The warning only occurs with debug builds for some reason.
1412 // In any case, the warning is irrelevant, but using ShaderEffectSource is important, so we ignore it.
1413#ifdef QT_DEBUG
1414 QTest::ignoreMessage(type: QtWarningMsg, message: "ShaderEffectSource: 'recursive' must be set to true when rendering recursively.");
1415#endif
1416 QVERIFY(QTest::qWaitForWindowActive(window));
1417
1418 QTest::mouseMove(window, pos: QPoint(window->width() / 2, window->height() / 2));
1419 QTRY_VERIFY(window->property("toolTipOpened").toBool());
1420
1421 QVERIFY(window->close());
1422 // Shouldn't crash.
1423}
1424
1425void tst_QQuickPopup::setOverlayParentToNull()
1426{
1427 QQuickApplicationHelper helper(this, "toolTipCrashOnClose.qml");
1428 QVERIFY2(helper.ready, helper.failureMessage());
1429
1430 QQuickWindow *window = helper.window;
1431 centerOnScreen(window);
1432 moveMouseAway(window);
1433 window->show();
1434#ifdef QT_DEBUG
1435 QTest::ignoreMessage(type: QtWarningMsg, message: "ShaderEffectSource: 'recursive' must be set to true when rendering recursively.");
1436#endif
1437 QVERIFY(QTest::qWaitForWindowActive(window));
1438
1439 QVERIFY(QMetaObject::invokeMethod(window, "nullifyOverlayParent"));
1440
1441 QTest::mouseMove(window, pos: QPoint(window->width() / 2, window->height() / 2));
1442 QTRY_VERIFY(window->property("toolTipOpened").toBool());
1443
1444 QVERIFY(window->close());
1445 // While nullifying the overlay parent doesn't make much sense, it shouldn't crash.
1446}
1447
1448void tst_QQuickPopup::tabFence()
1449{
1450 if (QGuiApplication::styleHints()->tabFocusBehavior() != Qt::TabFocusAllControls)
1451 QSKIP("This platform only allows tab focus for text controls");
1452
1453 QQuickApplicationHelper helper(this, "tabFence.qml");
1454 QVERIFY2(helper.ready, helper.failureMessage());
1455
1456 QQuickWindow *window = helper.window;
1457 window->show();
1458 QVERIFY(QTest::qWaitForWindowActive(window));
1459
1460 QQuickPopup *popup = window->property(name: "dialog").value<QQuickPopup*>();
1461 QVERIFY(popup);
1462 popup->open();
1463 popup->setModal(true);
1464
1465 QQuickButton *outsideButton1 = window->property(name: "outsideButton1").value<QQuickButton*>();
1466 QVERIFY(outsideButton1);
1467 QQuickButton *outsideButton2 = window->property(name: "outsideButton2").value<QQuickButton*>();
1468 QVERIFY(outsideButton2);
1469 QQuickButton *dialogButton1 = window->property(name: "dialogButton1").value<QQuickButton*>();
1470 QVERIFY(dialogButton1);
1471 QQuickButton *dialogButton2 = window->property(name: "dialogButton2").value<QQuickButton*>();
1472 QVERIFY(dialogButton2);
1473
1474 // When modal, focus loops between the two external buttons
1475 outsideButton1->forceActiveFocus();
1476 QVERIFY(outsideButton1->hasActiveFocus());
1477 QTest::keyClick(window, key: Qt::Key_Tab);
1478 QVERIFY(outsideButton2->hasActiveFocus());
1479 QTest::keyClick(window, key: Qt::Key_Tab);
1480 QVERIFY(outsideButton1->hasActiveFocus());
1481
1482 // Same thing for dialog's buttons
1483 dialogButton1->forceActiveFocus();
1484 QVERIFY(dialogButton1->hasActiveFocus());
1485 QTest::keyClick(window, key: Qt::Key_Tab);
1486 QVERIFY(dialogButton2->hasActiveFocus());
1487 QTest::keyClick(window, key: Qt::Key_Tab);
1488 QVERIFY(dialogButton1->hasActiveFocus());
1489
1490 popup->setModal(false);
1491
1492 // When not modal, focus goes in and out of the dialog
1493 outsideButton1->forceActiveFocus();
1494 QVERIFY(outsideButton1->hasActiveFocus());
1495 QTest::keyClick(window, key: Qt::Key_Tab);
1496 QVERIFY(outsideButton2->hasActiveFocus());
1497 QTest::keyClick(window, key: Qt::Key_Tab);
1498 QVERIFY(dialogButton1->hasActiveFocus());
1499 QTest::keyClick(window, key: Qt::Key_Tab);
1500 QVERIFY(dialogButton2->hasActiveFocus());
1501 QTest::keyClick(window, key: Qt::Key_Tab);
1502 QVERIFY(outsideButton1->hasActiveFocus());
1503}
1504
1505void tst_QQuickPopup::invisibleToolTipOpen()
1506{
1507 QQuickApplicationHelper helper(this, "invisibleToolTipOpen.qml");
1508 QVERIFY2(helper.ready, helper.failureMessage());
1509
1510 QQuickWindow *window = helper.window;
1511 centerOnScreen(window);
1512 moveMouseAway(window);
1513 window->show();
1514 QVERIFY(QTest::qWaitForWindowActive(window));
1515
1516 QQuickItem *mouseArea = qvariant_cast<QQuickItem *>(v: window->property(name: "mouseArea"));
1517 QVERIFY(mouseArea);
1518 QObject *loader = qvariant_cast<QObject *>(v: window->property(name: "loader"));
1519 QVERIFY(loader);
1520
1521 QTest::mouseMove(window, pos: QPoint(mouseArea->width() / 2, mouseArea->height() / 2));
1522 QTRY_VERIFY(mouseArea->property("isToolTipVisible").toBool());
1523
1524 QSignalSpy componentLoadedSpy(loader, SIGNAL(loaded()));
1525 QVERIFY(componentLoadedSpy.isValid());
1526
1527 loader->setProperty(name: "active", value: true);
1528 QTRY_COMPARE(componentLoadedSpy.count(), 1);
1529
1530 QTRY_VERIFY(mouseArea->property("isToolTipVisible").toBool());
1531}
1532
1533void tst_QQuickPopup::centerInOverlayWithinStackViewItem()
1534{
1535 QQuickApplicationHelper helper(this, "centerInOverlayWithinStackViewItem.qml");
1536 QVERIFY2(helper.ready, helper.failureMessage());
1537
1538 QQuickWindow *window = helper.window;
1539 window->show();
1540 QVERIFY(QTest::qWaitForWindowExposed(window));
1541
1542 QQuickPopup *popup = window->property(name: "popup").value<QQuickPopup*>();
1543 QVERIFY(popup);
1544 QTRY_COMPARE(popup->isVisible(), true);
1545
1546 // Shouldn't crash on exit.
1547}
1548
1549void tst_QQuickPopup::destroyDuringExitTransition()
1550{
1551 QQuickApplicationHelper helper(this, "destroyDuringExitTransition.qml");
1552 QVERIFY2(helper.ready, helper.failureMessage());
1553
1554 QQuickWindow *window = helper.window;
1555 window->show();
1556 QVERIFY(QTest::qWaitForWindowActive(window));
1557
1558 QPointer<QQuickPopup> dialog2 = window->property(name: "dialog2").value<QQuickPopup*>();
1559 QVERIFY(dialog2);
1560 QTRY_COMPARE(dialog2->isVisible(), true);
1561
1562 // Close the second dialog, destroying it before its exit transition can finish.
1563 QTest::keyClick(window, key: Qt::Key_Escape);
1564 QTRY_VERIFY(!dialog2);
1565
1566 // Events should go through to the dialog underneath.
1567 QQuickPopup *dialog1 = window->property(name: "dialog1").value<QQuickPopup*>();
1568 QVERIFY(dialog1);
1569 QQuickButton *button = dialog1->property(name: "button").value<QQuickButton*>();
1570 QVERIFY(button);
1571 const auto buttonClickPos = button->mapToScene(point: QPointF(button->width() / 2, button->height() / 2)).toPoint();
1572 QTest::mousePress(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: buttonClickPos);
1573 QVERIFY(button->isDown());
1574 QTest::mouseRelease(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: buttonClickPos);
1575 QVERIFY(!button->isDown());
1576}
1577
1578QTEST_QUICKCONTROLS_MAIN(tst_QQuickPopup)
1579
1580#include "tst_qquickpopup.moc"
1581

source code of qtquickcontrols2/tests/auto/qquickpopup/tst_qquickpopup.cpp