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 | |
54 | using namespace QQuickVisualTestUtil; |
55 | |
56 | class : public QQmlDataTest |
57 | { |
58 | Q_OBJECT |
59 | |
60 | private 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 | |
105 | void tst_QQuickPopup::() |
106 | { |
107 | QQmlDataTest::initTestCase(); |
108 | qputenv(varName: "QML_NO_TOUCH_COMPRESSION" , value: "1" ); |
109 | } |
110 | |
111 | void tst_QQuickPopup::() |
112 | { |
113 | QTest::addColumn<QString>(name: "source" ); |
114 | QTest::newRow(dataTag: "Window" ) << "window.qml" ; |
115 | QTest::newRow(dataTag: "ApplicationWindow" ) << "applicationwindow.qml" ; |
116 | } |
117 | |
118 | void tst_QQuickPopup::() |
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 * = window->property(name: "popup" ).value<QQuickPopup*>(); |
130 | QVERIFY(popup); |
131 | QQuickItem * = 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 | |
153 | void tst_QQuickPopup::() |
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 * = 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 | |
194 | void tst_QQuickPopup::() |
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 | |
211 | void tst_QQuickPopup::() |
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 * = 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 | |
370 | void tst_QQuickPopup::() |
371 | { |
372 | QTest::addColumn<QString>(name: "source" ); |
373 | QTest::newRow(dataTag: "Window" ) << "window.qml" ; |
374 | QTest::newRow(dataTag: "ApplicationWindow" ) << "applicationwindow.qml" ; |
375 | } |
376 | |
377 | void tst_QQuickPopup::() |
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 * = window->property(name: "popup" ).value<QQuickPopup*>(); |
389 | QVERIFY(popup); |
390 | popup->setModal(true); |
391 | |
392 | QQuickPopup * = 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 | |
412 | void tst_QQuickPopup::() |
413 | { |
414 | QQuickPopup ; |
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 | |
459 | Q_DECLARE_METATYPE(QQuickPopup::ClosePolicy) |
460 | |
461 | void tst_QQuickPopup::() |
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 | |
485 | void tst_QQuickPopup::() |
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 * = 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 | |
571 | void tst_QQuickPopup::() |
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 * = helper.appWindow->property(name: "focusedPopup" ).value<QQuickPopup*>(); |
583 | QVERIFY(focusedPopup); |
584 | |
585 | QQuickPopup * = 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 | |
614 | void tst_QQuickPopup::() |
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 * = helper.appWindow->property(name: "popup1" ).value<QQuickPopup*>(); |
627 | QVERIFY(popup1); |
628 | |
629 | QQuickPopup * = helper.appWindow->property(name: "popup2" ).value<QQuickPopup*>(); |
630 | QVERIFY(popup2); |
631 | |
632 | QQuickButton * = 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 | |
652 | void tst_QQuickPopup::() |
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 * = helper.appWindow->property(name: "popup1" ).value<QQuickPopup*>(); |
664 | QVERIFY(popup1); |
665 | |
666 | QQuickPopup * = 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 | |
685 | void tst_QQuickPopup::() |
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 * = window->property(name: "popup1" ).value<QQuickPopup *>(); |
699 | QVERIFY(popup1); |
700 | |
701 | QQuickPopup * = 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 | |
734 | void tst_QQuickPopup::() |
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 * = window->property(name: "popup1" ).value<QQuickPopup*>(); |
745 | QVERIFY(popup1); |
746 | |
747 | QQuickPopup * = window->property(name: "popup2" ).value<QQuickPopup*>(); |
748 | QVERIFY(popup2); |
749 | QSignalSpy closedSpy2(popup2, SIGNAL(closed())); |
750 | QVERIFY(closedSpy2.isValid()); |
751 | |
752 | QQuickPopup * = 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 | |
783 | void tst_QQuickPopup::() |
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 * = window->property(name: "popup1" ).value<QQuickPopup*>(); |
795 | QVERIFY(popup1); |
796 | QSignalSpy openedSpy(popup1, SIGNAL(opened())); |
797 | |
798 | QQuickPopup * = 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 | |
807 | void tst_QQuickPopup::() |
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 | |
818 | void tst_QQuickPopup::() |
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 * = 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 | |
872 | void tst_QQuickPopup::() |
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 | |
883 | static 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 | |
893 | void tst_QQuickPopup::() |
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 * = window->property(name: "popup" ).value<QQuickPopup*>(); |
908 | QVERIFY(popup && popup->contentItem()); |
909 | popup->setModal(modal); |
910 | |
911 | QQuickSlider * = window->property(name: "popupSlider" ).value<QQuickSlider*>(); |
912 | QVERIFY(popupSlider); |
913 | |
914 | { |
915 | // wheel over the content |
916 | qreal oldContentValue = contentSlider->value(); |
917 | qreal = 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 = 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 = 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 | |
959 | void tst_QQuickPopup::() |
960 | { |
961 | QQuickPopup ; |
962 | popup.setParentItem(new QQuickItem); |
963 | delete popup.parentItem(); |
964 | QVERIFY(!popup.parentItem()); |
965 | } |
966 | |
967 | void tst_QQuickPopup::() |
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 * = window->property(name: "modalPopup" ).value<QQuickPopup *>(); |
976 | QVERIFY(modalPopup); |
977 | |
978 | QQuickPopup * = 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 | |
994 | void tst_QQuickPopup::() |
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 * = window->property(name: "modelessPopup" ).value<QQuickPopup *>(); |
1003 | QVERIFY(modelessPopup); |
1004 | |
1005 | QQuickButton *button = window->property(name: "button" ).value<QQuickButton *>(); |
1006 | QVERIFY(button); |
1007 | QQuickPopup * = 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 |
1035 | void tst_QQuickPopup::() |
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 * = window->property(name: "menu" ).value<QQuickPopup *>(); |
1044 | QVERIFY(menu); |
1045 | |
1046 | QQuickPopup * = 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 | |
1086 | void tst_QQuickPopup::() |
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 * = 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 | |
1122 | class : public QQuickPopup |
1123 | { |
1124 | friend class tst_QQuickPopup; |
1125 | }; |
1126 | |
1127 | void tst_QQuickPopup::() |
1128 | { |
1129 | FriendlyPopup ; |
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 * = static_cast<FriendlyPopup *>(component.beginCreate(engine.rootContext())); |
1137 | QVERIFY(qmlPopup); |
1138 | QVERIFY(!qmlPopup->isComponentComplete()); |
1139 | |
1140 | component.completeCreate(); |
1141 | QVERIFY(qmlPopup->isComponentComplete()); |
1142 | } |
1143 | |
1144 | void tst_QQuickPopup::() |
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 * = window->findChild<QQuickPopup*>(aName: "optionsMenu" ); |
1169 | QVERIFY(optionsMenu); |
1170 | QTRY_VERIFY(optionsMenu->isVisible()); |
1171 | |
1172 | QQuickItem * = 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 = 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 | |
1210 | void tst_QQuickPopup::() |
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 * = 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 | |
1227 | void tst_QQuickPopup::() |
1228 | { |
1229 | QQuickPopup ; |
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 | |
1247 | void tst_QQuickPopup::() |
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 | |
1258 | void tst_QQuickPopup::() |
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 * = window->property(name: "popup" ).value<QQuickPopup*>(); |
1272 | QVERIFY(popup); |
1273 | popup->open(); |
1274 | |
1275 | QCOMPARE(popup->popupItem()->position(), position); |
1276 | } |
1277 | |
1278 | void tst_QQuickPopup::() |
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 |
1301 | void tst_QQuickPopup::() |
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 * = window->property(name: "popup" ).value<QQuickPopup*>(); |
1311 | QVERIFY(popup); |
1312 | |
1313 | QSignalSpy (popup, SIGNAL(enabledChanged())); |
1314 | QVERIFY(popupEnabledSpy.isValid()); |
1315 | QSignalSpy (popup, SIGNAL(paletteChanged())); |
1316 | QVERIFY(popupPaletteSpy.isValid()); |
1317 | |
1318 | QSignalSpy (popup->popupItem(), SIGNAL(enabledChanged())); |
1319 | QVERIFY(popupItemEnabledSpy.isValid()); |
1320 | QSignalSpy (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 | |
1339 | void tst_QQuickPopup::() |
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 * = window->property(name: "popup" ).value<QQuickPopup*>(); |
1349 | QVERIFY(popup); |
1350 | |
1351 | QSignalSpy (popup, SIGNAL(enabledChanged())); |
1352 | QVERIFY(popupEnabledSpy.isValid()); |
1353 | QSignalSpy (popup, SIGNAL(paletteChanged())); |
1354 | QVERIFY(popupPaletteSpy.isValid()); |
1355 | |
1356 | QSignalSpy (popup->popupItem(), SIGNAL(enabledChanged())); |
1357 | QVERIFY(popupItemEnabledSpy.isValid()); |
1358 | QSignalSpy (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 | |
1386 | void tst_QQuickPopup::() |
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 |
1404 | void tst_QQuickPopup::() |
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 | |
1425 | void tst_QQuickPopup::() |
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 | |
1448 | void tst_QQuickPopup::() |
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 * = 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 | |
1505 | void tst_QQuickPopup::() |
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 | |
1533 | void tst_QQuickPopup::() |
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 * = window->property(name: "popup" ).value<QQuickPopup*>(); |
1543 | QVERIFY(popup); |
1544 | QTRY_COMPARE(popup->isVisible(), true); |
1545 | |
1546 | // Shouldn't crash on exit. |
1547 | } |
1548 | |
1549 | void tst_QQuickPopup::() |
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 | |
1578 | QTEST_QUICKCONTROLS_MAIN(tst_QQuickPopup) |
1579 | |
1580 | #include "tst_qquickpopup.moc" |
1581 | |