1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the test suite of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
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 https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | #include <qtest.h> |
29 | #include <QtTest/QSignalSpy> |
30 | #include <QtQml/qqmlengine.h> |
31 | #include <QtQml/qqmlcomponent.h> |
32 | #include <QtQml/qqmlcontext.h> |
33 | #include <QtQuick/qquickitemgrabresult.h> |
34 | #include <QtQuick/qquickview.h> |
35 | #include <QtGui/private/qinputmethod_p.h> |
36 | #include <QtQuick/private/qquickloader_p.h> |
37 | #include <QtQuick/private/qquickrectangle_p.h> |
38 | #include <QtQuick/private/qquicktextinput_p.h> |
39 | #include <QtQuick/private/qquickitemchangelistener_p.h> |
40 | #include <QtGui/qstylehints.h> |
41 | #include <private/qquickitem_p.h> |
42 | #include "../../shared/util.h" |
43 | #include "../shared/visualtestutil.h" |
44 | #include "../../shared/platforminputcontext.h" |
45 | |
46 | using namespace QQuickVisualTestUtil; |
47 | |
48 | class tst_QQuickItem : public QQmlDataTest |
49 | { |
50 | Q_OBJECT |
51 | public: |
52 | tst_QQuickItem(); |
53 | |
54 | private slots: |
55 | void initTestCase(); |
56 | void cleanup(); |
57 | |
58 | void activeFocusOnTab(); |
59 | void activeFocusOnTab2(); |
60 | void activeFocusOnTab3(); |
61 | void activeFocusOnTab4(); |
62 | void activeFocusOnTab5(); |
63 | void activeFocusOnTab6(); |
64 | void activeFocusOnTab7(); |
65 | void activeFocusOnTab8(); |
66 | void activeFocusOnTab9(); |
67 | void activeFocusOnTab10(); |
68 | void activeFocusOnTab_infiniteLoop_data(); |
69 | void activeFocusOnTab_infiniteLoop(); |
70 | |
71 | void nextItemInFocusChain(); |
72 | void nextItemInFocusChain2(); |
73 | void nextItemInFocusChain3(); |
74 | |
75 | void tabFence(); |
76 | void qtbug_50516(); |
77 | void qtbug_50516_2_data(); |
78 | void qtbug_50516_2(); |
79 | void focusableItemReparentedToLoadedComponent(); |
80 | |
81 | void keys(); |
82 | #if QT_CONFIG(shortcut) |
83 | void standardKeys_data(); |
84 | void standardKeys(); |
85 | #endif |
86 | void keysProcessingOrder(); |
87 | void keysim(); |
88 | void keysForward(); |
89 | void keyNavigation_data(); |
90 | void keyNavigation(); |
91 | void keyNavigation_RightToLeft(); |
92 | void keyNavigation_skipNotVisible(); |
93 | void keyNavigation_implicitSetting(); |
94 | void keyNavigation_implicitDestroy(); |
95 | void keyNavigation_focusReason(); |
96 | void keyNavigation_loop(); |
97 | void keyNavigation_repeater(); |
98 | void layoutMirroring(); |
99 | void layoutMirroringWindow(); |
100 | void layoutMirroringIllegalParent(); |
101 | void smooth(); |
102 | void antialiasing(); |
103 | void clip(); |
104 | void mapCoordinates(); |
105 | void mapCoordinates_data(); |
106 | void mapCoordinatesRect(); |
107 | void mapCoordinatesRect_data(); |
108 | void propertyChanges(); |
109 | void nonexistentPropertyConnection(); |
110 | void transforms(); |
111 | void transforms_data(); |
112 | void childrenRect(); |
113 | void childrenRectBug(); |
114 | void childrenRectBug2(); |
115 | void childrenRectBug3(); |
116 | void childrenRectBottomRightCorner(); |
117 | |
118 | void childrenProperty(); |
119 | void resourcesProperty(); |
120 | |
121 | void changeListener(); |
122 | void transformCrash(); |
123 | void implicitSize(); |
124 | void qtbug_16871(); |
125 | void visibleChildren(); |
126 | void parentLoop(); |
127 | void contains_data(); |
128 | void contains(); |
129 | void childAt(); |
130 | void isAncestorOf(); |
131 | |
132 | void grab(); |
133 | |
134 | private: |
135 | QQmlEngine engine; |
136 | bool qt_tab_all_widgets() { |
137 | return QGuiApplication::styleHints()->tabFocusBehavior() == Qt::TabFocusAllControls; |
138 | } |
139 | }; |
140 | |
141 | class KeysTestObject : public QObject |
142 | { |
143 | Q_OBJECT |
144 | |
145 | Q_PROPERTY(bool processLast READ processLast NOTIFY processLastChanged) |
146 | |
147 | public: |
148 | KeysTestObject() : mKey(0), mModifiers(0), mForwardedKey(0), mLast(false), mNativeScanCode(0) {} |
149 | |
150 | void reset() { |
151 | mKey = 0; |
152 | mText = QString(); |
153 | mModifiers = 0; |
154 | mForwardedKey = 0; |
155 | mNativeScanCode = 0; |
156 | } |
157 | |
158 | bool processLast() const { return mLast; } |
159 | void setProcessLast(bool b) { |
160 | if (b != mLast) { |
161 | mLast = b; |
162 | emit processLastChanged(); |
163 | } |
164 | } |
165 | |
166 | public slots: |
167 | void keyPress(int key, QString text, int modifiers) { |
168 | mKey = key; |
169 | mText = text; |
170 | mModifiers = modifiers; |
171 | } |
172 | void keyRelease(int key, QString text, int modifiers) { |
173 | mKey = key; |
174 | mText = text; |
175 | mModifiers = modifiers; |
176 | } |
177 | void forwardedKey(int key) { |
178 | mForwardedKey = key; |
179 | } |
180 | void specialKey(int key, QString text, quint32 nativeScanCode) { |
181 | mKey = key; |
182 | mText = text; |
183 | mNativeScanCode = nativeScanCode; |
184 | } |
185 | |
186 | signals: |
187 | void processLastChanged(); |
188 | |
189 | public: |
190 | int mKey; |
191 | QString mText; |
192 | int mModifiers; |
193 | int mForwardedKey; |
194 | bool mLast; |
195 | quint32 mNativeScanCode; |
196 | |
197 | private: |
198 | }; |
199 | |
200 | class KeyTestItem : public QQuickItem |
201 | { |
202 | Q_OBJECT |
203 | public: |
204 | KeyTestItem(QQuickItem *parent=nullptr) : QQuickItem(parent), mKey(0) {} |
205 | |
206 | protected: |
207 | void keyPressEvent(QKeyEvent *e) { |
208 | mKey = e->key(); |
209 | |
210 | if (e->key() == Qt::Key_A) |
211 | e->accept(); |
212 | else |
213 | e->ignore(); |
214 | } |
215 | |
216 | void keyReleaseEvent(QKeyEvent *e) { |
217 | if (e->key() == Qt::Key_B) |
218 | e->accept(); |
219 | else |
220 | e->ignore(); |
221 | } |
222 | |
223 | public: |
224 | int mKey; |
225 | }; |
226 | |
227 | class FocusEventFilter : public QObject |
228 | { |
229 | protected: |
230 | bool eventFilter(QObject *watched, QEvent *event) { |
231 | if ((event->type() == QEvent::FocusIn) || (event->type() == QEvent::FocusOut)) { |
232 | QFocusEvent *focusEvent = static_cast<QFocusEvent *>(event); |
233 | lastFocusReason = focusEvent->reason(); |
234 | return false; |
235 | } else |
236 | return QObject::eventFilter(watched, event); |
237 | } |
238 | public: |
239 | Qt::FocusReason lastFocusReason; |
240 | }; |
241 | |
242 | QML_DECLARE_TYPE(KeyTestItem); |
243 | |
244 | class HollowTestItem : public QQuickItem |
245 | { |
246 | Q_OBJECT |
247 | Q_PROPERTY(bool circle READ isCircle WRITE setCircle) |
248 | Q_PROPERTY(qreal holeRadius READ holeRadius WRITE setHoleRadius) |
249 | |
250 | public: |
251 | HollowTestItem(QQuickItem *parent = nullptr) |
252 | : QQuickItem(parent), |
253 | m_isPressed(false), |
254 | m_isHovered(false), |
255 | m_isCircle(false), |
256 | m_holeRadius(50) |
257 | { |
258 | setAcceptHoverEvents(true); |
259 | setAcceptedMouseButtons(Qt::LeftButton); |
260 | } |
261 | |
262 | bool isPressed() const { return m_isPressed; } |
263 | bool isHovered() const { return m_isHovered; } |
264 | |
265 | bool isCircle() const { return m_isCircle; } |
266 | void setCircle(bool circle) { m_isCircle = circle; } |
267 | |
268 | qreal holeRadius() const { return m_holeRadius; } |
269 | void setHoleRadius(qreal radius) { m_holeRadius = radius; } |
270 | |
271 | bool contains(const QPointF &point) const { |
272 | const qreal w = width(); |
273 | const qreal h = height(); |
274 | const qreal r = m_holeRadius; |
275 | |
276 | // check boundaries |
277 | if (!QRectF(0, 0, w, h).contains(p: point)) |
278 | return false; |
279 | |
280 | // square shape |
281 | if (!m_isCircle) |
282 | return !QRectF(w / 2 - r, h / 2 - r, r * 2, r * 2).contains(p: point); |
283 | |
284 | // circle shape |
285 | const qreal dx = point.x() - (w / 2); |
286 | const qreal dy = point.y() - (h / 2); |
287 | const qreal dd = (dx * dx) + (dy * dy); |
288 | const qreal outerRadius = qMin<qreal>(a: w / 2, b: h / 2); |
289 | return dd > (r * r) && dd <= outerRadius * outerRadius; |
290 | } |
291 | |
292 | protected: |
293 | void hoverEnterEvent(QHoverEvent *) { m_isHovered = true; } |
294 | void hoverLeaveEvent(QHoverEvent *) { m_isHovered = false; } |
295 | void mousePressEvent(QMouseEvent *) { m_isPressed = true; } |
296 | void mouseReleaseEvent(QMouseEvent *) { m_isPressed = false; } |
297 | |
298 | private: |
299 | bool m_isPressed; |
300 | bool m_isHovered; |
301 | bool m_isCircle; |
302 | qreal m_holeRadius; |
303 | }; |
304 | |
305 | QML_DECLARE_TYPE(HollowTestItem); |
306 | |
307 | class TabFenceItem : public QQuickItem |
308 | { |
309 | Q_OBJECT |
310 | |
311 | public: |
312 | TabFenceItem(QQuickItem *parent = nullptr) |
313 | : QQuickItem(parent) |
314 | { |
315 | QQuickItemPrivate *d = QQuickItemPrivate::get(item: this); |
316 | d->isTabFence = true; |
317 | } |
318 | }; |
319 | |
320 | QML_DECLARE_TYPE(TabFenceItem); |
321 | |
322 | class TabFenceItem2 : public QQuickItem |
323 | { |
324 | Q_OBJECT |
325 | |
326 | public: |
327 | TabFenceItem2(QQuickItem *parent = nullptr) |
328 | : QQuickItem(parent) |
329 | { |
330 | QQuickItemPrivate *d = QQuickItemPrivate::get(item: this); |
331 | d->isTabFence = true; |
332 | setFlag(flag: ItemIsFocusScope); |
333 | } |
334 | }; |
335 | |
336 | QML_DECLARE_TYPE(TabFenceItem2); |
337 | |
338 | tst_QQuickItem::tst_QQuickItem() |
339 | { |
340 | } |
341 | |
342 | void tst_QQuickItem::initTestCase() |
343 | { |
344 | QQmlDataTest::initTestCase(); |
345 | qmlRegisterType<KeyTestItem>(uri: "Test" ,versionMajor: 1,versionMinor: 0,qmlName: "KeyTestItem" ); |
346 | qmlRegisterType<HollowTestItem>(uri: "Test" , versionMajor: 1, versionMinor: 0, qmlName: "HollowTestItem" ); |
347 | qmlRegisterType<TabFenceItem>(uri: "Test" , versionMajor: 1, versionMinor: 0, qmlName: "TabFence" ); |
348 | qmlRegisterType<TabFenceItem2>(uri: "Test" , versionMajor: 1, versionMinor: 0, qmlName: "TabFence2" ); |
349 | } |
350 | |
351 | void tst_QQuickItem::cleanup() |
352 | { |
353 | QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); |
354 | inputMethodPrivate->testContext = nullptr; |
355 | } |
356 | |
357 | void tst_QQuickItem::activeFocusOnTab() |
358 | { |
359 | if (!qt_tab_all_widgets()) |
360 | QSKIP("This function doesn't support NOT iterating all." ); |
361 | |
362 | QQuickView *window = new QQuickView(nullptr); |
363 | window->setBaseSize(QSize(800,600)); |
364 | |
365 | window->setSource(testFileUrl(fileName: "activeFocusOnTab.qml" )); |
366 | window->show(); |
367 | window->requestActivate(); |
368 | QVERIFY(QTest::qWaitForWindowActive(window)); |
369 | QCOMPARE(QGuiApplication::focusWindow(), window); |
370 | |
371 | // original: button12 |
372 | QQuickItem *item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button12" ); |
373 | QVERIFY(item); |
374 | QVERIFY(item->hasActiveFocus()); |
375 | |
376 | // Tab: button12->sub2 |
377 | QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "" , false, 1); |
378 | QGuiApplication::sendEvent(receiver: window, event: &key); |
379 | QVERIFY(key.isAccepted()); |
380 | |
381 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "sub2" ); |
382 | QVERIFY(item); |
383 | QVERIFY(item->hasActiveFocus()); |
384 | |
385 | // Tab: sub2->button21 |
386 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "" , false, 1); |
387 | QGuiApplication::sendEvent(receiver: window, event: &key); |
388 | QVERIFY(key.isAccepted()); |
389 | |
390 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button21" ); |
391 | QVERIFY(item); |
392 | QVERIFY(item->hasActiveFocus()); |
393 | |
394 | // Tab: button21->button22 |
395 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "" , false, 1); |
396 | QGuiApplication::sendEvent(receiver: window, event: &key); |
397 | QVERIFY(key.isAccepted()); |
398 | |
399 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button22" ); |
400 | QVERIFY(item); |
401 | QVERIFY(item->hasActiveFocus()); |
402 | |
403 | // Tab: button22->edit |
404 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "" , false, 1); |
405 | QGuiApplication::sendEvent(receiver: window, event: &key); |
406 | QVERIFY(key.isAccepted()); |
407 | |
408 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "edit" ); |
409 | QVERIFY(item); |
410 | QVERIFY(item->hasActiveFocus()); |
411 | |
412 | // BackTab: edit->button22 |
413 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "" , false, 1); |
414 | QGuiApplication::sendEvent(receiver: window, event: &key); |
415 | QVERIFY(key.isAccepted()); |
416 | |
417 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button22" ); |
418 | QVERIFY(item); |
419 | QVERIFY(item->hasActiveFocus()); |
420 | |
421 | // BackTab: button22->button21 |
422 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "" , false, 1); |
423 | QGuiApplication::sendEvent(receiver: window, event: &key); |
424 | QVERIFY(key.isAccepted()); |
425 | |
426 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button21" ); |
427 | QVERIFY(item); |
428 | QVERIFY(item->hasActiveFocus()); |
429 | |
430 | // BackTab: button21->sub2 |
431 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "" , false, 1); |
432 | QGuiApplication::sendEvent(receiver: window, event: &key); |
433 | QVERIFY(key.isAccepted()); |
434 | |
435 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "sub2" ); |
436 | QVERIFY(item); |
437 | QVERIFY(item->hasActiveFocus()); |
438 | |
439 | // BackTab: sub2->button12 |
440 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "" , false, 1); |
441 | QGuiApplication::sendEvent(receiver: window, event: &key); |
442 | QVERIFY(key.isAccepted()); |
443 | |
444 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button12" ); |
445 | QVERIFY(item); |
446 | QVERIFY(item->hasActiveFocus()); |
447 | |
448 | // BackTab: button12->button11 |
449 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "" , false, 1); |
450 | QGuiApplication::sendEvent(receiver: window, event: &key); |
451 | QVERIFY(key.isAccepted()); |
452 | |
453 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button11" ); |
454 | QVERIFY(item); |
455 | QVERIFY(item->hasActiveFocus()); |
456 | |
457 | // BackTab: button11->edit |
458 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "" , false, 1); |
459 | QGuiApplication::sendEvent(receiver: window, event: &key); |
460 | QVERIFY(key.isAccepted()); |
461 | |
462 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "edit" ); |
463 | QVERIFY(item); |
464 | QVERIFY(item->hasActiveFocus()); |
465 | |
466 | delete window; |
467 | } |
468 | |
469 | void tst_QQuickItem::activeFocusOnTab2() |
470 | { |
471 | if (!qt_tab_all_widgets()) |
472 | QSKIP("This function doesn't support NOT iterating all." ); |
473 | |
474 | QQuickView *window = new QQuickView(nullptr); |
475 | window->setBaseSize(QSize(800,600)); |
476 | |
477 | window->setSource(testFileUrl(fileName: "activeFocusOnTab.qml" )); |
478 | window->show(); |
479 | window->requestActivate(); |
480 | QVERIFY(QTest::qWaitForWindowActive(window)); |
481 | QCOMPARE(QGuiApplication::focusWindow(), window); |
482 | |
483 | // original: button12 |
484 | QQuickItem *item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button12" ); |
485 | QVERIFY(item); |
486 | QVERIFY(item->hasActiveFocus()); |
487 | |
488 | // BackTab: button12->button11 |
489 | QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "" , false, 1); |
490 | QGuiApplication::sendEvent(receiver: window, event: &key); |
491 | QVERIFY(key.isAccepted()); |
492 | |
493 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button11" ); |
494 | QVERIFY(item); |
495 | QVERIFY(item->hasActiveFocus()); |
496 | |
497 | // BackTab: button11->edit |
498 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "" , false, 1); |
499 | QGuiApplication::sendEvent(receiver: window, event: &key); |
500 | QVERIFY(key.isAccepted()); |
501 | |
502 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "edit" ); |
503 | QVERIFY(item); |
504 | QVERIFY(item->hasActiveFocus()); |
505 | |
506 | delete window; |
507 | } |
508 | |
509 | void tst_QQuickItem::activeFocusOnTab3() |
510 | { |
511 | if (!qt_tab_all_widgets()) |
512 | QSKIP("This function doesn't support NOT iterating all." ); |
513 | |
514 | QQuickView *window = new QQuickView(nullptr); |
515 | window->setBaseSize(QSize(800,600)); |
516 | |
517 | window->setSource(testFileUrl(fileName: "activeFocusOnTab3.qml" )); |
518 | window->show(); |
519 | window->requestActivate(); |
520 | QVERIFY(QTest::qWaitForWindowActive(window)); |
521 | QCOMPARE(QGuiApplication::focusWindow(), window); |
522 | |
523 | // original: button1 |
524 | QQuickItem *item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button1" ); |
525 | QVERIFY(item); |
526 | QVERIFY(item->hasActiveFocus()); |
527 | |
528 | // 4 Tabs: button1->button2, through a repeater |
529 | QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "" , false, 1);; |
530 | for (int i = 0; i < 4; ++i) { |
531 | QGuiApplication::sendEvent(receiver: window, event: &key); |
532 | QVERIFY(key.isAccepted()); |
533 | } |
534 | |
535 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button2" ); |
536 | QVERIFY(item); |
537 | QVERIFY(item->hasActiveFocus()); |
538 | |
539 | // 4 Tabs: button2->button3, through a row |
540 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "" , false, 1);; |
541 | for (int i = 0; i < 4; ++i) { |
542 | QGuiApplication::sendEvent(receiver: window, event: &key); |
543 | QVERIFY(key.isAccepted()); |
544 | } |
545 | |
546 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button3" ); |
547 | QVERIFY(item); |
548 | QVERIFY(item->hasActiveFocus()); |
549 | |
550 | // 4 Tabs: button3->button4, through a flow |
551 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "" , false, 1);; |
552 | for (int i = 0; i < 4; ++i) { |
553 | QGuiApplication::sendEvent(receiver: window, event: &key); |
554 | QVERIFY(key.isAccepted()); |
555 | } |
556 | |
557 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button4" ); |
558 | QVERIFY(item); |
559 | QVERIFY(item->hasActiveFocus()); |
560 | |
561 | // 4 Tabs: button4->button5, through a focusscope |
562 | // parent is activeFocusOnTab:false, one of children is focus:true |
563 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "" , false, 1);; |
564 | for (int i = 0; i < 4; ++i) { |
565 | QGuiApplication::sendEvent(receiver: window, event: &key); |
566 | QVERIFY(key.isAccepted()); |
567 | } |
568 | |
569 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button5" ); |
570 | QVERIFY(item); |
571 | QVERIFY(item->hasActiveFocus()); |
572 | |
573 | // 4 Tabs: button5->button6, through a focusscope |
574 | // parent is activeFocusOnTab:true, one of children is focus:true |
575 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "" , false, 1);; |
576 | for (int i = 0; i < 4; ++i) { |
577 | QGuiApplication::sendEvent(receiver: window, event: &key); |
578 | QVERIFY(key.isAccepted()); |
579 | } |
580 | |
581 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button6" ); |
582 | QVERIFY(item); |
583 | QVERIFY(item->hasActiveFocus()); |
584 | |
585 | // 5 Tabs: button6->button7, through a focusscope |
586 | // parent is activeFocusOnTab:true, none of children is focus:true |
587 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "" , false, 1);; |
588 | for (int i = 0; i < 5; ++i) { |
589 | QGuiApplication::sendEvent(receiver: window, event: &key); |
590 | QVERIFY(key.isAccepted()); |
591 | } |
592 | |
593 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button7" ); |
594 | QVERIFY(item); |
595 | QVERIFY(item->hasActiveFocus()); |
596 | |
597 | // 4 BackTabs: button7->button6, through a focusscope |
598 | // parent is activeFocusOnTab:true, one of children got focus:true in previous code |
599 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "" , false, 1); |
600 | for (int i = 0; i < 4; ++i) { |
601 | QGuiApplication::sendEvent(receiver: window, event: &key); |
602 | QVERIFY(key.isAccepted()); |
603 | } |
604 | |
605 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button6" ); |
606 | QVERIFY(item); |
607 | QVERIFY(item->hasActiveFocus()); |
608 | |
609 | // 4 Tabs: button6->button7, through a focusscope |
610 | // parent is activeFocusOnTab:true, one of children got focus:true in previous code |
611 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "" , false, 1);; |
612 | for (int i = 0; i < 4; ++i) { |
613 | QGuiApplication::sendEvent(receiver: window, event: &key); |
614 | QVERIFY(key.isAccepted()); |
615 | } |
616 | |
617 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button7" ); |
618 | QVERIFY(item); |
619 | QVERIFY(item->hasActiveFocus()); |
620 | |
621 | // 4 BackTabs: button7->button6, through a focusscope |
622 | // parent is activeFocusOnTab:true, one of children got focus:true in previous code |
623 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "" , false, 1); |
624 | for (int i = 0; i < 4; ++i) { |
625 | QGuiApplication::sendEvent(receiver: window, event: &key); |
626 | QVERIFY(key.isAccepted()); |
627 | } |
628 | |
629 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button6" ); |
630 | QVERIFY(item); |
631 | QVERIFY(item->hasActiveFocus()); |
632 | |
633 | // 4 BackTabs: button6->button5, through a focusscope(parent is activeFocusOnTab: false) |
634 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "" , false, 1); |
635 | for (int i = 0; i < 4; ++i) { |
636 | QGuiApplication::sendEvent(receiver: window, event: &key); |
637 | QVERIFY(key.isAccepted()); |
638 | } |
639 | |
640 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button5" ); |
641 | QVERIFY(item); |
642 | QVERIFY(item->hasActiveFocus()); |
643 | |
644 | // 4 BackTabs: button5->button4, through a focusscope(parent is activeFocusOnTab: false) |
645 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "" , false, 1); |
646 | for (int i = 0; i < 4; ++i) { |
647 | QGuiApplication::sendEvent(receiver: window, event: &key); |
648 | QVERIFY(key.isAccepted()); |
649 | } |
650 | |
651 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button4" ); |
652 | QVERIFY(item); |
653 | QVERIFY(item->hasActiveFocus()); |
654 | |
655 | // 4 BackTabs: button4->button3, through a flow |
656 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "" , false, 1); |
657 | for (int i = 0; i < 4; ++i) { |
658 | QGuiApplication::sendEvent(receiver: window, event: &key); |
659 | QVERIFY(key.isAccepted()); |
660 | } |
661 | |
662 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button3" ); |
663 | QVERIFY(item); |
664 | QVERIFY(item->hasActiveFocus()); |
665 | |
666 | // 4 BackTabs: button3->button2, through a row |
667 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "" , false, 1); |
668 | for (int i = 0; i < 4; ++i) { |
669 | QGuiApplication::sendEvent(receiver: window, event: &key); |
670 | QVERIFY(key.isAccepted()); |
671 | } |
672 | |
673 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button2" ); |
674 | QVERIFY(item); |
675 | QVERIFY(item->hasActiveFocus()); |
676 | |
677 | // 4 BackTabs: button2->button1, through a repeater |
678 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "" , false, 1); |
679 | for (int i = 0; i < 4; ++i) { |
680 | QGuiApplication::sendEvent(receiver: window, event: &key); |
681 | QVERIFY(key.isAccepted()); |
682 | } |
683 | |
684 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button1" ); |
685 | QVERIFY(item); |
686 | QVERIFY(item->hasActiveFocus()); |
687 | |
688 | delete window; |
689 | } |
690 | |
691 | void tst_QQuickItem::activeFocusOnTab4() |
692 | { |
693 | if (!qt_tab_all_widgets()) |
694 | QSKIP("This function doesn't support NOT iterating all." ); |
695 | |
696 | QQuickView *window = new QQuickView(nullptr); |
697 | window->setBaseSize(QSize(800,600)); |
698 | |
699 | window->setSource(testFileUrl(fileName: "activeFocusOnTab4.qml" )); |
700 | window->show(); |
701 | window->requestActivate(); |
702 | QVERIFY(QTest::qWaitForWindowActive(window)); |
703 | QCOMPARE(QGuiApplication::focusWindow(), window); |
704 | |
705 | // original: button11 |
706 | QQuickItem *item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button11" ); |
707 | item->setActiveFocusOnTab(true); |
708 | QVERIFY(item); |
709 | QVERIFY(item->hasActiveFocus()); |
710 | |
711 | // Tab: button11->button21 |
712 | QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "" , false, 1); |
713 | QGuiApplication::sendEvent(receiver: window, event: &key); |
714 | QVERIFY(key.isAccepted()); |
715 | |
716 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button21" ); |
717 | QVERIFY(item); |
718 | QVERIFY(item->hasActiveFocus()); |
719 | |
720 | delete window; |
721 | } |
722 | |
723 | void tst_QQuickItem::activeFocusOnTab5() |
724 | { |
725 | if (!qt_tab_all_widgets()) |
726 | QSKIP("This function doesn't support NOT iterating all." ); |
727 | |
728 | QQuickView *window = new QQuickView(nullptr); |
729 | window->setBaseSize(QSize(800,600)); |
730 | |
731 | window->setSource(testFileUrl(fileName: "activeFocusOnTab4.qml" )); |
732 | window->show(); |
733 | window->requestActivate(); |
734 | QVERIFY(QTest::qWaitForWindowActive(window)); |
735 | QCOMPARE(QGuiApplication::focusWindow(), window); |
736 | |
737 | // original: button11 in sub1 |
738 | QQuickItem *item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button11" ); |
739 | QVERIFY(item); |
740 | QVERIFY(item->hasActiveFocus()); |
741 | |
742 | QQuickItem *item2 = findItem<QQuickItem>(parent: window->rootObject(), objectName: "sub1" ); |
743 | item2->setActiveFocusOnTab(true); |
744 | |
745 | // Tab: button11->button21 |
746 | QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "" , false, 1); |
747 | QGuiApplication::sendEvent(receiver: window, event: &key); |
748 | QVERIFY(key.isAccepted()); |
749 | |
750 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button21" ); |
751 | QVERIFY(item); |
752 | QVERIFY(item->hasActiveFocus()); |
753 | |
754 | delete window; |
755 | } |
756 | |
757 | void tst_QQuickItem::activeFocusOnTab6() |
758 | { |
759 | if (qt_tab_all_widgets()) |
760 | QSKIP("This function doesn't support iterating all." ); |
761 | |
762 | QQuickView *window = new QQuickView(nullptr); |
763 | window->setBaseSize(QSize(800,600)); |
764 | |
765 | window->setSource(testFileUrl(fileName: "activeFocusOnTab6.qml" )); |
766 | window->show(); |
767 | window->requestActivate(); |
768 | QVERIFY(QTest::qWaitForWindowActive(window)); |
769 | QCOMPARE(QGuiApplication::focusWindow(), window); |
770 | |
771 | // original: button12 |
772 | QQuickItem *item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button12" ); |
773 | QVERIFY(item); |
774 | QVERIFY(item->hasActiveFocus()); |
775 | |
776 | // Tab: button12->edit |
777 | QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "" , false, 1); |
778 | QGuiApplication::sendEvent(receiver: window, event: &key); |
779 | QVERIFY(key.isAccepted()); |
780 | |
781 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "edit" ); |
782 | QVERIFY(item); |
783 | QVERIFY(item->hasActiveFocus()); |
784 | |
785 | // BackTab: edit->button12 |
786 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "" , false, 1); |
787 | QGuiApplication::sendEvent(receiver: window, event: &key); |
788 | QVERIFY(key.isAccepted()); |
789 | |
790 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button12" ); |
791 | QVERIFY(item); |
792 | QVERIFY(item->hasActiveFocus()); |
793 | |
794 | // BackTab: button12->button11 |
795 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "" , false, 1); |
796 | QGuiApplication::sendEvent(receiver: window, event: &key); |
797 | QVERIFY(key.isAccepted()); |
798 | |
799 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button11" ); |
800 | QVERIFY(item); |
801 | QVERIFY(item->hasActiveFocus()); |
802 | |
803 | // BackTab: button11->edit |
804 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "" , false, 1); |
805 | QGuiApplication::sendEvent(receiver: window, event: &key); |
806 | QVERIFY(key.isAccepted()); |
807 | |
808 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "edit" ); |
809 | QVERIFY(item); |
810 | QVERIFY(item->hasActiveFocus()); |
811 | |
812 | delete window; |
813 | } |
814 | |
815 | void tst_QQuickItem::activeFocusOnTab7() |
816 | { |
817 | if (qt_tab_all_widgets()) |
818 | QSKIP("This function doesn't support iterating all." ); |
819 | |
820 | QQuickView *window = new QQuickView(nullptr); |
821 | window->setBaseSize(QSize(300,300)); |
822 | |
823 | window->setSource(testFileUrl(fileName: "activeFocusOnTab7.qml" )); |
824 | window->show(); |
825 | window->requestActivate(); |
826 | QVERIFY(QTest::qWaitForWindowActive(window)); |
827 | QCOMPARE(QGuiApplication::focusWindow(), window); |
828 | |
829 | QQuickItem *item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button1" ); |
830 | QVERIFY(item); |
831 | item->forceActiveFocus(); |
832 | QVERIFY(item->hasActiveFocus()); |
833 | |
834 | // Tab: button1->button1 |
835 | QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "" , false, 1); |
836 | QGuiApplication::sendEvent(receiver: window, event: &key); |
837 | QVERIFY(!key.isAccepted()); |
838 | |
839 | QVERIFY(item->hasActiveFocus()); |
840 | |
841 | // BackTab: button1->button1 |
842 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "" , false, 1); |
843 | QGuiApplication::sendEvent(receiver: window, event: &key); |
844 | QVERIFY(!key.isAccepted()); |
845 | |
846 | QVERIFY(item->hasActiveFocus()); |
847 | |
848 | delete window; |
849 | } |
850 | |
851 | void tst_QQuickItem::activeFocusOnTab8() |
852 | { |
853 | QQuickView *window = new QQuickView(nullptr); |
854 | window->setBaseSize(QSize(300,300)); |
855 | |
856 | window->setSource(testFileUrl(fileName: "activeFocusOnTab8.qml" )); |
857 | window->show(); |
858 | window->requestActivate(); |
859 | QVERIFY(QTest::qWaitForWindowActive(window)); |
860 | QCOMPARE(QGuiApplication::focusWindow(), window); |
861 | |
862 | QQuickItem *content = window->contentItem(); |
863 | QVERIFY(content); |
864 | QVERIFY(content->hasActiveFocus()); |
865 | |
866 | QQuickItem *button1 = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button1" ); |
867 | QVERIFY(button1); |
868 | QVERIFY(!button1->hasActiveFocus()); |
869 | |
870 | QQuickItem *button2 = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button2" ); |
871 | QVERIFY(button2); |
872 | QVERIFY(!button2->hasActiveFocus()); |
873 | |
874 | // Tab: contentItem->button1 |
875 | QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "" , false, 1); |
876 | QGuiApplication::sendEvent(receiver: window, event: &key); |
877 | QVERIFY(key.isAccepted()); |
878 | |
879 | QVERIFY(button1->hasActiveFocus()); |
880 | |
881 | // Tab: button1->button2 |
882 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "" , false, 1); |
883 | QGuiApplication::sendEvent(receiver: window, event: &key); |
884 | QVERIFY(key.isAccepted()); |
885 | |
886 | QVERIFY(button2->hasActiveFocus()); |
887 | QVERIFY(!button1->hasActiveFocus()); |
888 | |
889 | // BackTab: button2->button1 |
890 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "" , false, 1); |
891 | QGuiApplication::sendEvent(receiver: window, event: &key); |
892 | QVERIFY(key.isAccepted()); |
893 | |
894 | QVERIFY(button1->hasActiveFocus()); |
895 | QVERIFY(!button2->hasActiveFocus()); |
896 | |
897 | delete window; |
898 | } |
899 | |
900 | void tst_QQuickItem::activeFocusOnTab9() |
901 | { |
902 | if (qt_tab_all_widgets()) |
903 | QSKIP("This function doesn't support iterating all." ); |
904 | |
905 | QQuickView *window = new QQuickView(nullptr); |
906 | window->setBaseSize(QSize(300,300)); |
907 | |
908 | window->setSource(testFileUrl(fileName: "activeFocusOnTab9.qml" )); |
909 | window->show(); |
910 | window->requestActivate(); |
911 | QVERIFY(QTest::qWaitForWindowActive(window)); |
912 | QCOMPARE(QGuiApplication::focusWindow(), window); |
913 | |
914 | QQuickItem *content = window->contentItem(); |
915 | QVERIFY(content); |
916 | QVERIFY(content->hasActiveFocus()); |
917 | |
918 | QQuickItem *textinput1 = findItem<QQuickItem>(parent: window->rootObject(), objectName: "textinput1" ); |
919 | QVERIFY(textinput1); |
920 | QQuickItem *textedit1 = findItem<QQuickItem>(parent: window->rootObject(), objectName: "textedit1" ); |
921 | QVERIFY(textedit1); |
922 | |
923 | QVERIFY(!textinput1->hasActiveFocus()); |
924 | textinput1->forceActiveFocus(); |
925 | QVERIFY(textinput1->hasActiveFocus()); |
926 | |
927 | // Tab: textinput1->textedit1 |
928 | QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "" , false, 1); |
929 | QGuiApplication::sendEvent(receiver: window, event: &key); |
930 | QVERIFY(key.isAccepted()); |
931 | |
932 | QVERIFY(textedit1->hasActiveFocus()); |
933 | |
934 | // BackTab: textedit1->textinput1 |
935 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "" , false, 1); |
936 | QGuiApplication::sendEvent(receiver: window, event: &key); |
937 | QVERIFY(key.isAccepted()); |
938 | |
939 | QVERIFY(textinput1->hasActiveFocus()); |
940 | |
941 | // BackTab: textinput1->textedit1 |
942 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "" , false, 1); |
943 | QGuiApplication::sendEvent(receiver: window, event: &key); |
944 | QVERIFY(key.isAccepted()); |
945 | |
946 | QVERIFY(textedit1->hasActiveFocus()); |
947 | |
948 | delete window; |
949 | } |
950 | |
951 | void tst_QQuickItem::activeFocusOnTab10() |
952 | { |
953 | if (!qt_tab_all_widgets()) |
954 | QSKIP("This function doesn't support NOT iterating all." ); |
955 | |
956 | QQuickView *window = new QQuickView(nullptr); |
957 | window->setBaseSize(QSize(300,300)); |
958 | |
959 | window->setSource(testFileUrl(fileName: "activeFocusOnTab9.qml" )); |
960 | window->show(); |
961 | window->requestActivate(); |
962 | QVERIFY(QTest::qWaitForWindowActive(window)); |
963 | QCOMPARE(QGuiApplication::focusWindow(), window); |
964 | |
965 | QQuickItem *content = window->contentItem(); |
966 | QVERIFY(content); |
967 | QVERIFY(content->hasActiveFocus()); |
968 | |
969 | QQuickItem *textinput1 = findItem<QQuickItem>(parent: window->rootObject(), objectName: "textinput1" ); |
970 | QVERIFY(textinput1); |
971 | QQuickItem *textedit1 = findItem<QQuickItem>(parent: window->rootObject(), objectName: "textedit1" ); |
972 | QVERIFY(textedit1); |
973 | QQuickItem *textinput2 = findItem<QQuickItem>(parent: window->rootObject(), objectName: "textinput2" ); |
974 | QVERIFY(textinput2); |
975 | QQuickItem *textedit2 = findItem<QQuickItem>(parent: window->rootObject(), objectName: "textedit2" ); |
976 | QVERIFY(textedit2); |
977 | |
978 | QVERIFY(!textinput1->hasActiveFocus()); |
979 | textinput1->forceActiveFocus(); |
980 | QVERIFY(textinput1->hasActiveFocus()); |
981 | |
982 | // Tab: textinput1->textinput2 |
983 | QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "" , false, 1); |
984 | QGuiApplication::sendEvent(receiver: window, event: &key); |
985 | QVERIFY(key.isAccepted()); |
986 | |
987 | QVERIFY(textinput2->hasActiveFocus()); |
988 | |
989 | // Tab: textinput2->textedit1 |
990 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "" , false, 1); |
991 | QGuiApplication::sendEvent(receiver: window, event: &key); |
992 | QVERIFY(key.isAccepted()); |
993 | |
994 | QVERIFY(textedit1->hasActiveFocus()); |
995 | |
996 | // BackTab: textedit1->textinput2 |
997 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "" , false, 1); |
998 | QGuiApplication::sendEvent(receiver: window, event: &key); |
999 | QVERIFY(key.isAccepted()); |
1000 | |
1001 | QVERIFY(textinput2->hasActiveFocus()); |
1002 | |
1003 | // BackTab: textinput2->textinput1 |
1004 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "" , false, 1); |
1005 | QGuiApplication::sendEvent(receiver: window, event: &key); |
1006 | QVERIFY(key.isAccepted()); |
1007 | |
1008 | QVERIFY(textinput1->hasActiveFocus()); |
1009 | |
1010 | // BackTab: textinput1->textedit2 |
1011 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "" , false, 1); |
1012 | QGuiApplication::sendEvent(receiver: window, event: &key); |
1013 | QVERIFY(key.isAccepted()); |
1014 | |
1015 | QVERIFY(textedit2->hasActiveFocus()); |
1016 | |
1017 | // BackTab: textedit2->textedit1 |
1018 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "" , false, 1); |
1019 | QGuiApplication::sendEvent(receiver: window, event: &key); |
1020 | QVERIFY(key.isAccepted()); |
1021 | |
1022 | QVERIFY(textedit1->hasActiveFocus()); |
1023 | |
1024 | // BackTab: textedit1->textinput2 |
1025 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "" , false, 1); |
1026 | QGuiApplication::sendEvent(receiver: window, event: &key); |
1027 | QVERIFY(key.isAccepted()); |
1028 | |
1029 | QVERIFY(textinput2->hasActiveFocus()); |
1030 | |
1031 | delete window; |
1032 | } |
1033 | |
1034 | void tst_QQuickItem::activeFocusOnTab_infiniteLoop_data() |
1035 | { |
1036 | QTest::addColumn<QUrl>(name: "source" ); |
1037 | QTest::newRow(dataTag: "infiniteLoop" ) << testFileUrl(fileName: "activeFocusOnTab_infiniteLoop.qml" ); // QTBUG-68271 |
1038 | QTest::newRow(dataTag: "infiniteLoop2" ) << testFileUrl(fileName: "activeFocusOnTab_infiniteLoop2.qml" );// QTBUG-81510 |
1039 | } |
1040 | |
1041 | void tst_QQuickItem::activeFocusOnTab_infiniteLoop() |
1042 | { |
1043 | QFETCH(QUrl, source); |
1044 | |
1045 | // create a window where the currently focused item is not visible |
1046 | QScopedPointer<QQuickView>window(new QQuickView()); |
1047 | window->setSource(source); |
1048 | window->show(); |
1049 | auto *hiddenChild = findItem<QQuickItem>(parent: window->rootObject(), objectName: "hiddenChild" ); |
1050 | QVERIFY(hiddenChild); |
1051 | |
1052 | // move the focus - this used to result in an infinite loop |
1053 | auto *item = hiddenChild->nextItemInFocusChain(); |
1054 | // focus is moved to the root object since there is no other candidate |
1055 | QCOMPARE(item, window->rootObject()); |
1056 | item = hiddenChild->nextItemInFocusChain(forward: false); |
1057 | QCOMPARE(item, window->rootObject()); |
1058 | } |
1059 | |
1060 | void tst_QQuickItem::nextItemInFocusChain() |
1061 | { |
1062 | if (!qt_tab_all_widgets()) |
1063 | QSKIP("This function doesn't support NOT iterating all." ); |
1064 | |
1065 | QQuickView *window = new QQuickView(nullptr); |
1066 | window->setBaseSize(QSize(800,600)); |
1067 | |
1068 | window->setSource(testFileUrl(fileName: "activeFocusOnTab.qml" )); |
1069 | window->show(); |
1070 | window->requestActivate(); |
1071 | QVERIFY(QTest::qWaitForWindowActive(window)); |
1072 | QCOMPARE(QGuiApplication::focusWindow(), window); |
1073 | |
1074 | QQuickItem *button11 = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button11" ); |
1075 | QVERIFY(button11); |
1076 | QQuickItem *button12 = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button12" ); |
1077 | QVERIFY(button12); |
1078 | |
1079 | QQuickItem *sub2 = findItem<QQuickItem>(parent: window->rootObject(), objectName: "sub2" ); |
1080 | QVERIFY(sub2); |
1081 | QQuickItem *button21 = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button21" ); |
1082 | QVERIFY(button21); |
1083 | QQuickItem *button22 = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button22" ); |
1084 | QVERIFY(button22); |
1085 | |
1086 | QQuickItem *edit = findItem<QQuickItem>(parent: window->rootObject(), objectName: "edit" ); |
1087 | QVERIFY(edit); |
1088 | |
1089 | QQuickItem *next, *prev; |
1090 | |
1091 | next = button11->nextItemInFocusChain(forward: true); |
1092 | QVERIFY(next); |
1093 | QCOMPARE(next, button12); |
1094 | prev = button11->nextItemInFocusChain(forward: false); |
1095 | QVERIFY(prev); |
1096 | QCOMPARE(prev, edit); |
1097 | |
1098 | next = button12->nextItemInFocusChain(); |
1099 | QVERIFY(next); |
1100 | QCOMPARE(next, sub2); |
1101 | prev = button12->nextItemInFocusChain(forward: false); |
1102 | QVERIFY(prev); |
1103 | QCOMPARE(prev, button11); |
1104 | |
1105 | next = sub2->nextItemInFocusChain(forward: true); |
1106 | QVERIFY(next); |
1107 | QCOMPARE(next, button21); |
1108 | prev = sub2->nextItemInFocusChain(forward: false); |
1109 | QVERIFY(prev); |
1110 | QCOMPARE(prev, button12); |
1111 | |
1112 | next = button21->nextItemInFocusChain(); |
1113 | QVERIFY(next); |
1114 | QCOMPARE(next, button22); |
1115 | prev = button21->nextItemInFocusChain(forward: false); |
1116 | QVERIFY(prev); |
1117 | QCOMPARE(prev, sub2); |
1118 | |
1119 | next = button22->nextItemInFocusChain(forward: true); |
1120 | QVERIFY(next); |
1121 | QCOMPARE(next, edit); |
1122 | prev = button22->nextItemInFocusChain(forward: false); |
1123 | QVERIFY(prev); |
1124 | QCOMPARE(prev, button21); |
1125 | |
1126 | next = edit->nextItemInFocusChain(); |
1127 | QVERIFY(next); |
1128 | QCOMPARE(next, button11); |
1129 | prev = edit->nextItemInFocusChain(forward: false); |
1130 | QVERIFY(prev); |
1131 | QCOMPARE(prev, button22); |
1132 | |
1133 | delete window; |
1134 | } |
1135 | |
1136 | void tst_QQuickItem::nextItemInFocusChain2() |
1137 | { |
1138 | if (qt_tab_all_widgets()) |
1139 | QSKIP("This function doesn't support iterating all." ); |
1140 | |
1141 | QQuickView *window = new QQuickView(nullptr); |
1142 | window->setBaseSize(QSize(800,600)); |
1143 | |
1144 | window->setSource(testFileUrl(fileName: "activeFocusOnTab6.qml" )); |
1145 | window->show(); |
1146 | window->requestActivate(); |
1147 | QVERIFY(QTest::qWaitForWindowActive(window)); |
1148 | QCOMPARE(QGuiApplication::focusWindow(), window); |
1149 | |
1150 | QQuickItem *button11 = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button11" ); |
1151 | QVERIFY(button11); |
1152 | QQuickItem *button12 = findItem<QQuickItem>(parent: window->rootObject(), objectName: "button12" ); |
1153 | QVERIFY(button12); |
1154 | |
1155 | QQuickItem *edit = findItem<QQuickItem>(parent: window->rootObject(), objectName: "edit" ); |
1156 | QVERIFY(edit); |
1157 | |
1158 | QQuickItem *next, *prev; |
1159 | |
1160 | next = button11->nextItemInFocusChain(forward: true); |
1161 | QVERIFY(next); |
1162 | QCOMPARE(next, button12); |
1163 | prev = button11->nextItemInFocusChain(forward: false); |
1164 | QVERIFY(prev); |
1165 | QCOMPARE(prev, edit); |
1166 | |
1167 | next = button12->nextItemInFocusChain(); |
1168 | QVERIFY(next); |
1169 | QCOMPARE(next, edit); |
1170 | prev = button12->nextItemInFocusChain(forward: false); |
1171 | QVERIFY(prev); |
1172 | QCOMPARE(prev, button11); |
1173 | |
1174 | next = edit->nextItemInFocusChain(); |
1175 | QVERIFY(next); |
1176 | QCOMPARE(next, button11); |
1177 | prev = edit->nextItemInFocusChain(forward: false); |
1178 | QVERIFY(prev); |
1179 | QCOMPARE(prev, button12); |
1180 | |
1181 | delete window; |
1182 | } |
1183 | |
1184 | void tst_QQuickItem::nextItemInFocusChain3() |
1185 | { |
1186 | QQuickView *window = new QQuickView(nullptr); |
1187 | window->setBaseSize(QSize(800,600)); |
1188 | |
1189 | window->setSource(testFileUrl(fileName: "nextItemInFocusChain3.qml" )); |
1190 | window->show(); |
1191 | window->requestActivate(); |
1192 | QVERIFY(QTest::qWaitForWindowActive(window)); |
1193 | QCOMPARE(QGuiApplication::focusWindow(), window); |
1194 | } |
1195 | |
1196 | void verifyTabFocusChain(QQuickView *window, const char **focusChain, bool forward) |
1197 | { |
1198 | int idx = 0; |
1199 | for (const char **objectName = focusChain; *objectName; ++objectName, ++idx) { |
1200 | const QString &descrStr = QString("idx=%1 objectName=\"%2\"" ).arg(a: idx).arg(a: *objectName); |
1201 | const char *descr = descrStr.toLocal8Bit().data(); |
1202 | QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, forward ? Qt::NoModifier : Qt::ShiftModifier); |
1203 | QGuiApplication::sendEvent(receiver: window, event: &key); |
1204 | QVERIFY2(key.isAccepted(), descr); |
1205 | |
1206 | QQuickItem *item = findItem<QQuickItem>(parent: window->rootObject(), objectName: *objectName); |
1207 | QVERIFY2(item, descr); |
1208 | QVERIFY2(item->hasActiveFocus(), descr); |
1209 | } |
1210 | } |
1211 | |
1212 | void tst_QQuickItem::tabFence() |
1213 | { |
1214 | QQuickView *window = new QQuickView(nullptr); |
1215 | window->setBaseSize(QSize(800,600)); |
1216 | |
1217 | window->setSource(testFileUrl(fileName: "tabFence.qml" )); |
1218 | window->show(); |
1219 | window->requestActivate(); |
1220 | QVERIFY(QTest::qWaitForWindowActive(window)); |
1221 | QVERIFY(QGuiApplication::focusWindow() == window); |
1222 | QVERIFY(window->rootObject()->hasActiveFocus()); |
1223 | |
1224 | const char *rootTabFocusChain[] = { |
1225 | "input1" , "input2" , "input3" , "input1" , nullptr |
1226 | }; |
1227 | verifyTabFocusChain(window, focusChain: rootTabFocusChain, forward: true /* forward */); |
1228 | |
1229 | const char *rootBacktabFocusChain[] = { |
1230 | "input3" , "input2" , "input1" , "input3" , nullptr |
1231 | }; |
1232 | verifyTabFocusChain(window, focusChain: rootBacktabFocusChain, forward: false /* forward */); |
1233 | |
1234 | // Give focus to input11 in fence1 |
1235 | QQuickItem *item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "input11" ); |
1236 | item->setFocus(true); |
1237 | QVERIFY(item); |
1238 | QVERIFY(item->hasActiveFocus()); |
1239 | |
1240 | const char *fence1TabFocusChain[] = { |
1241 | "input12" , "input13" , "input11" , "input12" , nullptr |
1242 | }; |
1243 | verifyTabFocusChain(window, focusChain: fence1TabFocusChain, forward: true /* forward */); |
1244 | |
1245 | const char *fence1BacktabFocusChain[] = { |
1246 | "input11" , "input13" , "input12" , "input11" , nullptr |
1247 | }; |
1248 | verifyTabFocusChain(window, focusChain: fence1BacktabFocusChain, forward: false /* forward */); |
1249 | } |
1250 | |
1251 | void tst_QQuickItem::qtbug_50516() |
1252 | { |
1253 | QQuickView *window = new QQuickView(nullptr); |
1254 | window->setBaseSize(QSize(800,600)); |
1255 | |
1256 | window->setSource(testFileUrl(fileName: "qtbug_50516.qml" )); |
1257 | window->show(); |
1258 | window->requestActivate(); |
1259 | QVERIFY(QTest::qWaitForWindowActive(window)); |
1260 | QVERIFY(QGuiApplication::focusWindow() == window); |
1261 | QVERIFY(window->rootObject()->hasActiveFocus()); |
1262 | |
1263 | QQuickItem *contentItem = window->rootObject(); |
1264 | QQuickItem *next = contentItem->nextItemInFocusChain(forward: true); |
1265 | QCOMPARE(next, contentItem); |
1266 | next = contentItem->nextItemInFocusChain(forward: false); |
1267 | QCOMPARE(next, contentItem); |
1268 | |
1269 | delete window; |
1270 | } |
1271 | |
1272 | void tst_QQuickItem::qtbug_50516_2_data() |
1273 | { |
1274 | QTest::addColumn<QString>(name: "filename" ); |
1275 | QTest::addColumn<QString>(name: "item1" ); |
1276 | QTest::addColumn<QString>(name: "item2" ); |
1277 | |
1278 | QTest::newRow(dataTag: "FocusScope TabFence with one Item(focused)" ) |
1279 | << QStringLiteral("qtbug_50516_2_1.qml" ) << QStringLiteral("root" ) << QStringLiteral("root" ); |
1280 | QTest::newRow(dataTag: "FocusScope TabFence with one Item(unfocused)" ) |
1281 | << QStringLiteral("qtbug_50516_2_2.qml" ) << QStringLiteral("root" ) << QStringLiteral("root" ); |
1282 | QTest::newRow(dataTag: "FocusScope TabFence with two Items(focused)" ) |
1283 | << QStringLiteral("qtbug_50516_2_3.qml" ) << QStringLiteral("root" ) << QStringLiteral("root" ); |
1284 | QTest::newRow(dataTag: "FocusScope TabFence with two Items(unfocused)" ) |
1285 | << QStringLiteral("qtbug_50516_2_4.qml" ) << QStringLiteral("root" ) << QStringLiteral("root" ); |
1286 | QTest::newRow(dataTag: "FocusScope TabFence with one Item and one TextInput(unfocused)" ) |
1287 | << QStringLiteral("qtbug_50516_2_5.qml" ) << QStringLiteral("item1" ) << QStringLiteral("item1" ); |
1288 | QTest::newRow(dataTag: "FocusScope TabFence with two TextInputs(unfocused)" ) |
1289 | << QStringLiteral("qtbug_50516_2_6.qml" ) << QStringLiteral("item1" ) << QStringLiteral("item2" ); |
1290 | } |
1291 | |
1292 | void tst_QQuickItem::qtbug_50516_2() |
1293 | { |
1294 | QFETCH(QString, filename); |
1295 | QFETCH(QString, item1); |
1296 | QFETCH(QString, item2); |
1297 | |
1298 | QQuickView *window = new QQuickView(nullptr); |
1299 | window->setBaseSize(QSize(800,600)); |
1300 | |
1301 | window->setSource(testFileUrl(fileName: filename)); |
1302 | window->show(); |
1303 | window->requestActivate(); |
1304 | QVERIFY(QTest::qWaitForWindowActive(window)); |
1305 | QVERIFY(QGuiApplication::focusWindow() == window); |
1306 | QVERIFY(window->rootObject()->hasActiveFocus()); |
1307 | |
1308 | QQuickItem *contentItem = window->rootObject(); |
1309 | QQuickItem *next = contentItem->nextItemInFocusChain(forward: true); |
1310 | QCOMPARE(next->objectName(), item1); |
1311 | next = contentItem->nextItemInFocusChain(forward: false); |
1312 | QCOMPARE(next->objectName(), item2); |
1313 | |
1314 | delete window; |
1315 | } |
1316 | |
1317 | void tst_QQuickItem::focusableItemReparentedToLoadedComponent() // QTBUG-89736 |
1318 | { |
1319 | QQuickView window; |
1320 | window.setSource(testFileUrl(fileName: "focusableItemReparentedToLoadedComponent.qml" )); |
1321 | window.show(); |
1322 | QVERIFY(QTest::qWaitForWindowActive(&window)); |
1323 | QCOMPARE(QGuiApplication::focusWindow(), &window); |
1324 | QQuickLoader *loader = window.rootObject()->findChild<QQuickLoader *>(); |
1325 | QVERIFY(loader); |
1326 | QTRY_VERIFY(loader->status() == QQuickLoader::Ready); |
1327 | QQuickTextInput *textInput = window.rootObject()->findChild<QQuickTextInput *>(); |
1328 | QVERIFY(textInput); |
1329 | |
1330 | // click to focus |
1331 | QTest::mouseClick(window: &window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: {10, 10}); |
1332 | QTRY_VERIFY(textInput->hasActiveFocus()); |
1333 | |
1334 | // unload and reload |
1335 | auto component = loader->sourceComponent(); |
1336 | loader->resetSourceComponent(); |
1337 | QTRY_VERIFY(loader->status() == QQuickLoader::Null); |
1338 | loader->setSourceComponent(component); |
1339 | QTRY_VERIFY(loader->status() == QQuickLoader::Ready); |
1340 | |
1341 | // click to focus again |
1342 | QTest::mouseClick(window: &window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: {10, 10}); |
1343 | QTRY_VERIFY(textInput->hasActiveFocus()); |
1344 | } |
1345 | |
1346 | void tst_QQuickItem::keys() |
1347 | { |
1348 | QQuickView *window = new QQuickView(nullptr); |
1349 | window->setBaseSize(QSize(240,320)); |
1350 | |
1351 | KeysTestObject *testObject = new KeysTestObject; |
1352 | window->rootContext()->setContextProperty("keysTestObject" , testObject); |
1353 | |
1354 | window->rootContext()->setContextProperty("enableKeyHanding" , QVariant(true)); |
1355 | window->rootContext()->setContextProperty("forwardeeVisible" , QVariant(true)); |
1356 | |
1357 | window->setSource(testFileUrl(fileName: "keystest.qml" )); |
1358 | window->show(); |
1359 | window->requestActivate(); |
1360 | QVERIFY(QTest::qWaitForWindowActive(window)); |
1361 | QCOMPARE(QGuiApplication::focusWindow(), window); |
1362 | |
1363 | QVERIFY(window->rootObject()); |
1364 | QCOMPARE(window->rootObject()->property("isEnabled" ).toBool(), true); |
1365 | |
1366 | QKeyEvent key(QEvent::KeyPress, Qt::Key_A, Qt::NoModifier, "A" , false, 1); |
1367 | QGuiApplication::sendEvent(receiver: window, event: &key); |
1368 | QCOMPARE(testObject->mKey, int(Qt::Key_A)); |
1369 | QCOMPARE(testObject->mForwardedKey, int(Qt::Key_A)); |
1370 | QCOMPARE(testObject->mText, QLatin1String("A" )); |
1371 | QCOMPARE(testObject->mModifiers, int(Qt::NoModifier)); |
1372 | QVERIFY(!key.isAccepted()); |
1373 | |
1374 | testObject->reset(); |
1375 | |
1376 | key = QKeyEvent(QEvent::KeyRelease, Qt::Key_A, Qt::ShiftModifier, "A" , false, 1); |
1377 | QGuiApplication::sendEvent(receiver: window, event: &key); |
1378 | QCOMPARE(testObject->mKey, int(Qt::Key_A)); |
1379 | QCOMPARE(testObject->mForwardedKey, int(Qt::Key_A)); |
1380 | QCOMPARE(testObject->mText, QLatin1String("A" )); |
1381 | QCOMPARE(testObject->mModifiers, int(Qt::ShiftModifier)); |
1382 | QVERIFY(key.isAccepted()); |
1383 | |
1384 | testObject->reset(); |
1385 | |
1386 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier, "" , false, 1); |
1387 | QGuiApplication::sendEvent(receiver: window, event: &key); |
1388 | QCOMPARE(testObject->mKey, int(Qt::Key_Return)); |
1389 | QCOMPARE(testObject->mForwardedKey, int(Qt::Key_Return)); |
1390 | QCOMPARE(testObject->mText, QLatin1String("Return" )); |
1391 | QCOMPARE(testObject->mModifiers, int(Qt::NoModifier)); |
1392 | QVERIFY(key.isAccepted()); |
1393 | |
1394 | testObject->reset(); |
1395 | |
1396 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_0, Qt::NoModifier, "0" , false, 1); |
1397 | QGuiApplication::sendEvent(receiver: window, event: &key); |
1398 | QCOMPARE(testObject->mKey, int(Qt::Key_0)); |
1399 | QCOMPARE(testObject->mForwardedKey, int(Qt::Key_0)); |
1400 | QCOMPARE(testObject->mText, QLatin1String("0" )); |
1401 | QCOMPARE(testObject->mModifiers, int(Qt::NoModifier)); |
1402 | QVERIFY(key.isAccepted()); |
1403 | |
1404 | testObject->reset(); |
1405 | |
1406 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_9, Qt::NoModifier, "9" , false, 1); |
1407 | QGuiApplication::sendEvent(receiver: window, event: &key); |
1408 | QCOMPARE(testObject->mKey, int(Qt::Key_9)); |
1409 | QCOMPARE(testObject->mForwardedKey, int(Qt::Key_9)); |
1410 | QCOMPARE(testObject->mText, QLatin1String("9" )); |
1411 | QCOMPARE(testObject->mModifiers, int(Qt::NoModifier)); |
1412 | QVERIFY(!key.isAccepted()); |
1413 | |
1414 | testObject->reset(); |
1415 | |
1416 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "" , false, 1); |
1417 | QGuiApplication::sendEvent(receiver: window, event: &key); |
1418 | QCOMPARE(testObject->mKey, int(Qt::Key_Tab)); |
1419 | QCOMPARE(testObject->mForwardedKey, int(Qt::Key_Tab)); |
1420 | QCOMPARE(testObject->mText, QLatin1String("Tab" )); |
1421 | QCOMPARE(testObject->mModifiers, int(Qt::NoModifier)); |
1422 | QVERIFY(key.isAccepted()); |
1423 | |
1424 | testObject->reset(); |
1425 | |
1426 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Backtab, Qt::NoModifier, "" , false, 1); |
1427 | QGuiApplication::sendEvent(receiver: window, event: &key); |
1428 | QCOMPARE(testObject->mKey, int(Qt::Key_Backtab)); |
1429 | QCOMPARE(testObject->mForwardedKey, int(Qt::Key_Backtab)); |
1430 | QCOMPARE(testObject->mText, QLatin1String("Backtab" )); |
1431 | QCOMPARE(testObject->mModifiers, int(Qt::NoModifier)); |
1432 | QVERIFY(key.isAccepted()); |
1433 | |
1434 | testObject->reset(); |
1435 | |
1436 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_VolumeUp, Qt::NoModifier, 1234, 0, 0); |
1437 | QGuiApplication::sendEvent(receiver: window, event: &key); |
1438 | QCOMPARE(testObject->mKey, int(Qt::Key_VolumeUp)); |
1439 | QCOMPARE(testObject->mForwardedKey, int(Qt::Key_VolumeUp)); |
1440 | QCOMPARE(testObject->mModifiers, int(Qt::NoModifier)); |
1441 | QCOMPARE(testObject->mNativeScanCode, quint32(1234)); |
1442 | QVERIFY(key.isAccepted()); |
1443 | |
1444 | testObject->reset(); |
1445 | |
1446 | window->rootContext()->setContextProperty("forwardeeVisible" , QVariant(false)); |
1447 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_A, Qt::NoModifier, "A" , false, 1); |
1448 | QGuiApplication::sendEvent(receiver: window, event: &key); |
1449 | QCOMPARE(testObject->mKey, int(Qt::Key_A)); |
1450 | QCOMPARE(testObject->mForwardedKey, 0); |
1451 | QCOMPARE(testObject->mText, QLatin1String("A" )); |
1452 | QCOMPARE(testObject->mModifiers, int(Qt::NoModifier)); |
1453 | QVERIFY(!key.isAccepted()); |
1454 | |
1455 | testObject->reset(); |
1456 | |
1457 | window->rootContext()->setContextProperty("enableKeyHanding" , QVariant(false)); |
1458 | QCOMPARE(window->rootObject()->property("isEnabled" ).toBool(), false); |
1459 | |
1460 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier, "" , false, 1); |
1461 | QGuiApplication::sendEvent(receiver: window, event: &key); |
1462 | QCOMPARE(testObject->mKey, 0); |
1463 | QVERIFY(!key.isAccepted()); |
1464 | |
1465 | window->rootContext()->setContextProperty("enableKeyHanding" , QVariant(true)); |
1466 | QCOMPARE(window->rootObject()->property("isEnabled" ).toBool(), true); |
1467 | |
1468 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier, "" , false, 1); |
1469 | QGuiApplication::sendEvent(receiver: window, event: &key); |
1470 | QCOMPARE(testObject->mKey, int(Qt::Key_Return)); |
1471 | QVERIFY(key.isAccepted()); |
1472 | |
1473 | delete window; |
1474 | delete testObject; |
1475 | } |
1476 | |
1477 | #if QT_CONFIG(shortcut) |
1478 | |
1479 | Q_DECLARE_METATYPE(QEvent::Type); |
1480 | Q_DECLARE_METATYPE(QKeySequence::StandardKey); |
1481 | |
1482 | void tst_QQuickItem::standardKeys_data() |
1483 | { |
1484 | QTest::addColumn<QKeySequence::StandardKey>(name: "standardKey" ); |
1485 | QTest::addColumn<QKeySequence::StandardKey>(name: "contextProperty" ); |
1486 | QTest::addColumn<QEvent::Type>(name: "eventType" ); |
1487 | QTest::addColumn<bool>(name: "pressed" ); |
1488 | QTest::addColumn<bool>(name: "released" ); |
1489 | |
1490 | QTest::newRow(dataTag: "Press: Open" ) << QKeySequence::Open << QKeySequence::Open << QEvent::KeyPress << true << false; |
1491 | QTest::newRow(dataTag: "Press: Close" ) << QKeySequence::Close << QKeySequence::Close << QEvent::KeyPress << true << false; |
1492 | QTest::newRow(dataTag: "Press: Save" ) << QKeySequence::Save << QKeySequence::Save << QEvent::KeyPress << true << false; |
1493 | QTest::newRow(dataTag: "Press: Quit" ) << QKeySequence::Quit << QKeySequence::Quit << QEvent::KeyPress << true << false; |
1494 | |
1495 | QTest::newRow(dataTag: "Release: New" ) << QKeySequence::New << QKeySequence::New << QEvent::KeyRelease << false << true; |
1496 | QTest::newRow(dataTag: "Release: Delete" ) << QKeySequence::Delete << QKeySequence::Delete << QEvent::KeyRelease << false << true; |
1497 | QTest::newRow(dataTag: "Release: Undo" ) << QKeySequence::Undo << QKeySequence::Undo << QEvent::KeyRelease << false << true; |
1498 | QTest::newRow(dataTag: "Release: Redo" ) << QKeySequence::Redo << QKeySequence::Redo << QEvent::KeyRelease << false << true; |
1499 | |
1500 | QTest::newRow(dataTag: "Mismatch: Cut" ) << QKeySequence::Cut << QKeySequence::Copy << QEvent::KeyPress << false << false; |
1501 | QTest::newRow(dataTag: "Mismatch: Copy" ) << QKeySequence::Copy << QKeySequence::Paste << QEvent::KeyPress << false << false; |
1502 | QTest::newRow(dataTag: "Mismatch: Paste" ) << QKeySequence::Paste << QKeySequence::Cut << QEvent::KeyRelease << false << false; |
1503 | QTest::newRow(dataTag: "Mismatch: Quit" ) << QKeySequence::Quit << QKeySequence::New << QEvent::KeyRelease << false << false; |
1504 | } |
1505 | |
1506 | void tst_QQuickItem::standardKeys() |
1507 | { |
1508 | QFETCH(QKeySequence::StandardKey, standardKey); |
1509 | QFETCH(QKeySequence::StandardKey, contextProperty); |
1510 | QFETCH(QEvent::Type, eventType); |
1511 | QFETCH(bool, pressed); |
1512 | QFETCH(bool, released); |
1513 | |
1514 | QKeySequence keySequence(standardKey); |
1515 | if (keySequence.isEmpty()) |
1516 | QSKIP("Undefined key sequence." ); |
1517 | |
1518 | QQuickView view; |
1519 | view.rootContext()->setContextProperty("standardKey" , contextProperty); |
1520 | view.setSource(testFileUrl(fileName: "standardkeys.qml" )); |
1521 | view.show(); |
1522 | view.requestActivate(); |
1523 | QVERIFY(QTest::qWaitForWindowActive(&view)); |
1524 | |
1525 | QQuickItem *item = qobject_cast<QQuickItem*>(object: view.rootObject()); |
1526 | QVERIFY(item); |
1527 | |
1528 | const int key = keySequence[0] & Qt::Key_unknown; |
1529 | const int modifiers = keySequence[0] & Qt::KeyboardModifierMask; |
1530 | QKeyEvent keyEvent(eventType, key, static_cast<Qt::KeyboardModifiers>(modifiers)); |
1531 | QGuiApplication::sendEvent(receiver: &view, event: &keyEvent); |
1532 | |
1533 | QCOMPARE(item->property("pressed" ).toBool(), pressed); |
1534 | QCOMPARE(item->property("released" ).toBool(), released); |
1535 | } |
1536 | |
1537 | #endif // QT_CONFIG(shortcut) |
1538 | |
1539 | void tst_QQuickItem::keysProcessingOrder() |
1540 | { |
1541 | QQuickView *window = new QQuickView(nullptr); |
1542 | window->setBaseSize(QSize(240,320)); |
1543 | |
1544 | KeysTestObject *testObject = new KeysTestObject; |
1545 | window->rootContext()->setContextProperty("keysTestObject" , testObject); |
1546 | |
1547 | window->setSource(testFileUrl(fileName: "keyspriority.qml" )); |
1548 | window->show(); |
1549 | window->requestActivate(); |
1550 | QVERIFY(QTest::qWaitForWindowActive(window)); |
1551 | QCOMPARE(QGuiApplication::focusWindow(), window); |
1552 | |
1553 | KeyTestItem *testItem = qobject_cast<KeyTestItem*>(object: window->rootObject()); |
1554 | QVERIFY(testItem); |
1555 | |
1556 | QCOMPARE(testItem->property("priorityTest" ).toInt(), 0); |
1557 | |
1558 | QKeyEvent key(QEvent::KeyPress, Qt::Key_A, Qt::NoModifier, "A" , false, 1); |
1559 | QGuiApplication::sendEvent(receiver: window, event: &key); |
1560 | QCOMPARE(testObject->mKey, int(Qt::Key_A)); |
1561 | QCOMPARE(testObject->mText, QLatin1String("A" )); |
1562 | QCOMPARE(testObject->mModifiers, int(Qt::NoModifier)); |
1563 | QVERIFY(key.isAccepted()); |
1564 | |
1565 | testObject->reset(); |
1566 | |
1567 | testObject->setProcessLast(true); |
1568 | |
1569 | QCOMPARE(testItem->property("priorityTest" ).toInt(), 1); |
1570 | |
1571 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_A, Qt::NoModifier, "A" , false, 1); |
1572 | QGuiApplication::sendEvent(receiver: window, event: &key); |
1573 | QCOMPARE(testObject->mKey, 0); |
1574 | QVERIFY(key.isAccepted()); |
1575 | |
1576 | testObject->reset(); |
1577 | |
1578 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_B, Qt::NoModifier, "B" , false, 1); |
1579 | QGuiApplication::sendEvent(receiver: window, event: &key); |
1580 | QCOMPARE(testObject->mKey, int(Qt::Key_B)); |
1581 | QCOMPARE(testObject->mText, QLatin1String("B" )); |
1582 | QCOMPARE(testObject->mModifiers, int(Qt::NoModifier)); |
1583 | QVERIFY(!key.isAccepted()); |
1584 | |
1585 | testObject->reset(); |
1586 | |
1587 | key = QKeyEvent(QEvent::KeyRelease, Qt::Key_B, Qt::NoModifier, "B" , false, 1); |
1588 | QGuiApplication::sendEvent(receiver: window, event: &key); |
1589 | QCOMPARE(testObject->mKey, 0); |
1590 | QVERIFY(key.isAccepted()); |
1591 | |
1592 | delete window; |
1593 | delete testObject; |
1594 | } |
1595 | |
1596 | void tst_QQuickItem::keysim() |
1597 | { |
1598 | PlatformInputContext platformInputContext; |
1599 | QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); |
1600 | inputMethodPrivate->testContext = &platformInputContext; |
1601 | |
1602 | QQuickView *window = new QQuickView(nullptr); |
1603 | window->setBaseSize(QSize(240,320)); |
1604 | |
1605 | window->setSource(testFileUrl(fileName: "keysim.qml" )); |
1606 | window->show(); |
1607 | window->requestActivate(); |
1608 | QVERIFY(QTest::qWaitForWindowActive(window)); |
1609 | QCOMPARE(QGuiApplication::focusWindow(), window); |
1610 | |
1611 | QVERIFY(window->rootObject()); |
1612 | QVERIFY(window->rootObject()->hasFocus() && window->rootObject()->hasActiveFocus()); |
1613 | |
1614 | QQuickTextInput *input = window->rootObject()->findChild<QQuickTextInput*>(); |
1615 | QVERIFY(input); |
1616 | |
1617 | QInputMethodEvent ev("Hello world!" , QList<QInputMethodEvent::Attribute>()); |
1618 | QGuiApplication::sendEvent(qGuiApp->focusObject(), event: &ev); |
1619 | |
1620 | QEXPECT_FAIL("" , "QTBUG-24280" , Continue); |
1621 | QCOMPARE(input->text(), QLatin1String("Hello world!" )); |
1622 | |
1623 | delete window; |
1624 | } |
1625 | |
1626 | void tst_QQuickItem::keysForward() |
1627 | { |
1628 | QQuickView window; |
1629 | window.setBaseSize(QSize(240,320)); |
1630 | |
1631 | window.setSource(testFileUrl(fileName: "keysforward.qml" )); |
1632 | window.show(); |
1633 | window.requestActivate(); |
1634 | QVERIFY(QTest::qWaitForWindowActive(&window)); |
1635 | QCOMPARE(QGuiApplication::focusWindow(), &window); |
1636 | |
1637 | QQuickItem *rootItem = qobject_cast<QQuickItem *>(object: window.rootObject()); |
1638 | QVERIFY(rootItem); |
1639 | QQuickItem *sourceItem = rootItem->property(name: "source" ).value<QQuickItem *>(); |
1640 | QVERIFY(sourceItem); |
1641 | QQuickItem *primaryTarget = rootItem->property(name: "primaryTarget" ).value<QQuickItem *>(); |
1642 | QVERIFY(primaryTarget); |
1643 | QQuickItem *secondaryTarget = rootItem->property(name: "secondaryTarget" ).value<QQuickItem *>(); |
1644 | QVERIFY(secondaryTarget); |
1645 | |
1646 | // primary target accepts/consumes Key_P |
1647 | QKeyEvent pressKeyP(QEvent::KeyPress, Qt::Key_P, Qt::NoModifier, "P" ); |
1648 | QCoreApplication::sendEvent(receiver: sourceItem, event: &pressKeyP); |
1649 | QCOMPARE(rootItem->property("pressedKeys" ).toList(), QVariantList()); |
1650 | QCOMPARE(sourceItem->property("pressedKeys" ).toList(), QVariantList()); |
1651 | QCOMPARE(primaryTarget->property("pressedKeys" ).toList(), QVariantList() << Qt::Key_P); |
1652 | QCOMPARE(secondaryTarget->property("pressedKeys" ).toList(), QVariantList() << Qt::Key_P); |
1653 | QVERIFY(pressKeyP.isAccepted()); |
1654 | |
1655 | QKeyEvent releaseKeyP(QEvent::KeyRelease, Qt::Key_P, Qt::NoModifier, "P" ); |
1656 | QCoreApplication::sendEvent(receiver: sourceItem, event: &releaseKeyP); |
1657 | QCOMPARE(rootItem->property("releasedKeys" ).toList(), QVariantList()); |
1658 | QCOMPARE(sourceItem->property("releasedKeys" ).toList(), QVariantList()); |
1659 | QCOMPARE(primaryTarget->property("releasedKeys" ).toList(), QVariantList() << Qt::Key_P); |
1660 | QCOMPARE(secondaryTarget->property("releasedKeys" ).toList(), QVariantList() << Qt::Key_P); |
1661 | QVERIFY(releaseKeyP.isAccepted()); |
1662 | |
1663 | // secondary target accepts/consumes Key_S |
1664 | QKeyEvent pressKeyS(QEvent::KeyPress, Qt::Key_S, Qt::NoModifier, "S" ); |
1665 | QCoreApplication::sendEvent(receiver: sourceItem, event: &pressKeyS); |
1666 | QCOMPARE(rootItem->property("pressedKeys" ).toList(), QVariantList()); |
1667 | QCOMPARE(sourceItem->property("pressedKeys" ).toList(), QVariantList()); |
1668 | QCOMPARE(primaryTarget->property("pressedKeys" ).toList(), QVariantList() << Qt::Key_P); |
1669 | QCOMPARE(secondaryTarget->property("pressedKeys" ).toList(), QVariantList() << Qt::Key_P << Qt::Key_S); |
1670 | QVERIFY(pressKeyS.isAccepted()); |
1671 | |
1672 | QKeyEvent releaseKeyS(QEvent::KeyRelease, Qt::Key_S, Qt::NoModifier, "S" ); |
1673 | QCoreApplication::sendEvent(receiver: sourceItem, event: &releaseKeyS); |
1674 | QCOMPARE(rootItem->property("releasedKeys" ).toList(), QVariantList()); |
1675 | QCOMPARE(sourceItem->property("releasedKeys" ).toList(), QVariantList()); |
1676 | QCOMPARE(primaryTarget->property("releasedKeys" ).toList(), QVariantList() << Qt::Key_P); |
1677 | QCOMPARE(secondaryTarget->property("releasedKeys" ).toList(), QVariantList() << Qt::Key_P << Qt::Key_S); |
1678 | QVERIFY(releaseKeyS.isAccepted()); |
1679 | |
1680 | // neither target accepts/consumes Key_Q |
1681 | QKeyEvent pressKeyQ(QEvent::KeyPress, Qt::Key_Q, Qt::NoModifier, "Q" ); |
1682 | QCoreApplication::sendEvent(receiver: sourceItem, event: &pressKeyQ); |
1683 | QCOMPARE(rootItem->property("pressedKeys" ).toList(), QVariantList()); |
1684 | QCOMPARE(sourceItem->property("pressedKeys" ).toList(), QVariantList() << Qt::Key_Q); |
1685 | QCOMPARE(primaryTarget->property("pressedKeys" ).toList(), QVariantList() << Qt::Key_P << Qt::Key_Q); |
1686 | QCOMPARE(secondaryTarget->property("pressedKeys" ).toList(), QVariantList() << Qt::Key_P << Qt::Key_S << Qt::Key_Q); |
1687 | QVERIFY(!pressKeyQ.isAccepted()); |
1688 | |
1689 | QKeyEvent releaseKeyQ(QEvent::KeyRelease, Qt::Key_Q, Qt::NoModifier, "Q" ); |
1690 | QCoreApplication::sendEvent(receiver: sourceItem, event: &releaseKeyQ); |
1691 | QCOMPARE(rootItem->property("releasedKeys" ).toList(), QVariantList()); |
1692 | QCOMPARE(sourceItem->property("releasedKeys" ).toList(), QVariantList() << Qt::Key_Q); |
1693 | QCOMPARE(primaryTarget->property("releasedKeys" ).toList(), QVariantList() << Qt::Key_P << Qt::Key_Q); |
1694 | QCOMPARE(secondaryTarget->property("releasedKeys" ).toList(), QVariantList() << Qt::Key_P << Qt::Key_S << Qt::Key_Q); |
1695 | QVERIFY(!releaseKeyQ.isAccepted()); |
1696 | } |
1697 | |
1698 | QQuickItemPrivate *childPrivate(QQuickItem *rootItem, const char * itemString) |
1699 | { |
1700 | QQuickItem *item = findItem<QQuickItem>(parent: rootItem, objectName: QString(QLatin1String(itemString))); |
1701 | QQuickItemPrivate* itemPrivate = QQuickItemPrivate::get(item); |
1702 | return itemPrivate; |
1703 | } |
1704 | |
1705 | QVariant childProperty(QQuickItem *rootItem, const char * itemString, const char * property) |
1706 | { |
1707 | QQuickItem *item = findItem<QQuickItem>(parent: rootItem, objectName: QString(QLatin1String(itemString))); |
1708 | return item->property(name: property); |
1709 | } |
1710 | |
1711 | bool anchorsMirrored(QQuickItem *rootItem, const char * itemString) |
1712 | { |
1713 | QQuickItem *item = findItem<QQuickItem>(parent: rootItem, objectName: QString(QLatin1String(itemString))); |
1714 | QQuickItemPrivate* itemPrivate = QQuickItemPrivate::get(item); |
1715 | return itemPrivate->anchors()->mirrored(); |
1716 | } |
1717 | |
1718 | void tst_QQuickItem::layoutMirroring() |
1719 | { |
1720 | QQuickView *window = new QQuickView(nullptr); |
1721 | window->setSource(testFileUrl(fileName: "layoutmirroring.qml" )); |
1722 | window->show(); |
1723 | |
1724 | QQuickItem *rootItem = qobject_cast<QQuickItem*>(object: window->rootObject()); |
1725 | QVERIFY(rootItem); |
1726 | QQuickItemPrivate *rootPrivate = QQuickItemPrivate::get(item: rootItem); |
1727 | QVERIFY(rootPrivate); |
1728 | |
1729 | QCOMPARE(childPrivate(rootItem, "mirrored1" )->effectiveLayoutMirror, true); |
1730 | QCOMPARE(childPrivate(rootItem, "mirrored2" )->effectiveLayoutMirror, true); |
1731 | QCOMPARE(childPrivate(rootItem, "notMirrored1" )->effectiveLayoutMirror, false); |
1732 | QCOMPARE(childPrivate(rootItem, "notMirrored2" )->effectiveLayoutMirror, false); |
1733 | QCOMPARE(childPrivate(rootItem, "inheritedMirror1" )->effectiveLayoutMirror, true); |
1734 | QCOMPARE(childPrivate(rootItem, "inheritedMirror2" )->effectiveLayoutMirror, true); |
1735 | |
1736 | QCOMPARE(anchorsMirrored(rootItem, "mirrored1" ), true); |
1737 | QCOMPARE(anchorsMirrored(rootItem, "mirrored2" ), true); |
1738 | QCOMPARE(anchorsMirrored(rootItem, "notMirrored1" ), false); |
1739 | QCOMPARE(anchorsMirrored(rootItem, "notMirrored2" ), false); |
1740 | QCOMPARE(anchorsMirrored(rootItem, "inheritedMirror1" ), true); |
1741 | QCOMPARE(anchorsMirrored(rootItem, "inheritedMirror2" ), true); |
1742 | |
1743 | QCOMPARE(childPrivate(rootItem, "mirrored1" )->inheritedLayoutMirror, true); |
1744 | QCOMPARE(childPrivate(rootItem, "mirrored2" )->inheritedLayoutMirror, false); |
1745 | QCOMPARE(childPrivate(rootItem, "notMirrored1" )->inheritedLayoutMirror, true); |
1746 | QCOMPARE(childPrivate(rootItem, "notMirrored2" )->inheritedLayoutMirror, false); |
1747 | QCOMPARE(childPrivate(rootItem, "inheritedMirror1" )->inheritedLayoutMirror, true); |
1748 | QCOMPARE(childPrivate(rootItem, "inheritedMirror2" )->inheritedLayoutMirror, true); |
1749 | |
1750 | QCOMPARE(childPrivate(rootItem, "mirrored1" )->isMirrorImplicit, false); |
1751 | QCOMPARE(childPrivate(rootItem, "mirrored2" )->isMirrorImplicit, false); |
1752 | QCOMPARE(childPrivate(rootItem, "notMirrored1" )->isMirrorImplicit, false); |
1753 | QCOMPARE(childPrivate(rootItem, "notMirrored2" )->isMirrorImplicit, true); |
1754 | QCOMPARE(childPrivate(rootItem, "inheritedMirror1" )->isMirrorImplicit, true); |
1755 | QCOMPARE(childPrivate(rootItem, "inheritedMirror2" )->isMirrorImplicit, true); |
1756 | |
1757 | QCOMPARE(childPrivate(rootItem, "mirrored1" )->inheritMirrorFromParent, true); |
1758 | QCOMPARE(childPrivate(rootItem, "mirrored2" )->inheritMirrorFromParent, false); |
1759 | QCOMPARE(childPrivate(rootItem, "notMirrored1" )->inheritMirrorFromParent, true); |
1760 | QCOMPARE(childPrivate(rootItem, "notMirrored2" )->inheritMirrorFromParent, false); |
1761 | QCOMPARE(childPrivate(rootItem, "inheritedMirror1" )->inheritMirrorFromParent, true); |
1762 | QCOMPARE(childPrivate(rootItem, "inheritedMirror2" )->inheritMirrorFromParent, true); |
1763 | |
1764 | QCOMPARE(childPrivate(rootItem, "mirrored1" )->inheritMirrorFromItem, true); |
1765 | QCOMPARE(childPrivate(rootItem, "mirrored2" )->inheritMirrorFromItem, false); |
1766 | QCOMPARE(childPrivate(rootItem, "notMirrored1" )->inheritMirrorFromItem, false); |
1767 | QCOMPARE(childPrivate(rootItem, "notMirrored2" )->inheritMirrorFromItem, false); |
1768 | QCOMPARE(childPrivate(rootItem, "inheritedMirror1" )->inheritMirrorFromItem, false); |
1769 | QCOMPARE(childPrivate(rootItem, "inheritedMirror2" )->inheritMirrorFromItem, false); |
1770 | |
1771 | // load dynamic content using Loader that needs to inherit mirroring |
1772 | rootItem->setProperty(name: "state" , value: "newContent" ); |
1773 | QCOMPARE(childPrivate(rootItem, "notMirrored3" )->effectiveLayoutMirror, false); |
1774 | QCOMPARE(childPrivate(rootItem, "inheritedMirror3" )->effectiveLayoutMirror, true); |
1775 | |
1776 | QCOMPARE(childPrivate(rootItem, "notMirrored3" )->inheritedLayoutMirror, true); |
1777 | QCOMPARE(childPrivate(rootItem, "inheritedMirror3" )->inheritedLayoutMirror, true); |
1778 | |
1779 | QCOMPARE(childPrivate(rootItem, "notMirrored3" )->isMirrorImplicit, false); |
1780 | QCOMPARE(childPrivate(rootItem, "inheritedMirror3" )->isMirrorImplicit, true); |
1781 | |
1782 | QCOMPARE(childPrivate(rootItem, "notMirrored3" )->inheritMirrorFromParent, true); |
1783 | QCOMPARE(childPrivate(rootItem, "inheritedMirror3" )->inheritMirrorFromParent, true); |
1784 | |
1785 | QCOMPARE(childPrivate(rootItem, "notMirrored3" )->inheritMirrorFromItem, false); |
1786 | QCOMPARE(childPrivate(rootItem, "notMirrored3" )->inheritMirrorFromItem, false); |
1787 | |
1788 | // disable inheritance |
1789 | rootItem->setProperty(name: "childrenInherit" , value: false); |
1790 | |
1791 | QCOMPARE(childPrivate(rootItem, "inheritedMirror1" )->effectiveLayoutMirror, false); |
1792 | QCOMPARE(childPrivate(rootItem, "inheritedMirror2" )->effectiveLayoutMirror, false); |
1793 | QCOMPARE(childPrivate(rootItem, "mirrored1" )->effectiveLayoutMirror, true); |
1794 | QCOMPARE(childPrivate(rootItem, "notMirrored1" )->effectiveLayoutMirror, false); |
1795 | |
1796 | QCOMPARE(childPrivate(rootItem, "inheritedMirror1" )->inheritedLayoutMirror, false); |
1797 | QCOMPARE(childPrivate(rootItem, "inheritedMirror2" )->inheritedLayoutMirror, false); |
1798 | QCOMPARE(childPrivate(rootItem, "mirrored1" )->inheritedLayoutMirror, false); |
1799 | QCOMPARE(childPrivate(rootItem, "notMirrored1" )->inheritedLayoutMirror, false); |
1800 | |
1801 | // re-enable inheritance |
1802 | rootItem->setProperty(name: "childrenInherit" , value: true); |
1803 | |
1804 | QCOMPARE(childPrivate(rootItem, "inheritedMirror1" )->effectiveLayoutMirror, true); |
1805 | QCOMPARE(childPrivate(rootItem, "inheritedMirror2" )->effectiveLayoutMirror, true); |
1806 | QCOMPARE(childPrivate(rootItem, "mirrored1" )->effectiveLayoutMirror, true); |
1807 | QCOMPARE(childPrivate(rootItem, "notMirrored1" )->effectiveLayoutMirror, false); |
1808 | |
1809 | QCOMPARE(childPrivate(rootItem, "inheritedMirror1" )->inheritedLayoutMirror, true); |
1810 | QCOMPARE(childPrivate(rootItem, "inheritedMirror2" )->inheritedLayoutMirror, true); |
1811 | QCOMPARE(childPrivate(rootItem, "mirrored1" )->inheritedLayoutMirror, true); |
1812 | QCOMPARE(childPrivate(rootItem, "notMirrored1" )->inheritedLayoutMirror, true); |
1813 | |
1814 | // |
1815 | // dynamic parenting |
1816 | // |
1817 | QQuickItem *parentItem1 = new QQuickItem(); |
1818 | QQuickItemPrivate::get(item: parentItem1)->effectiveLayoutMirror = true; // LayoutMirroring.enabled: true |
1819 | QQuickItemPrivate::get(item: parentItem1)->isMirrorImplicit = false; |
1820 | QQuickItemPrivate::get(item: parentItem1)->inheritMirrorFromItem = true; // LayoutMirroring.childrenInherit: true |
1821 | QQuickItemPrivate::get(item: parentItem1)->resolveLayoutMirror(); |
1822 | |
1823 | // inherit in constructor |
1824 | QQuickItem *childItem1 = new QQuickItem(parentItem1); |
1825 | QCOMPARE(QQuickItemPrivate::get(childItem1)->effectiveLayoutMirror, true); |
1826 | QCOMPARE(QQuickItemPrivate::get(childItem1)->inheritMirrorFromParent, true); |
1827 | |
1828 | // inherit through a parent change |
1829 | QQuickItem *childItem2 = new QQuickItem(); |
1830 | QCOMPARE(QQuickItemPrivate::get(childItem2)->effectiveLayoutMirror, false); |
1831 | QCOMPARE(QQuickItemPrivate::get(childItem2)->inheritMirrorFromParent, false); |
1832 | childItem2->setParentItem(parentItem1); |
1833 | QCOMPARE(QQuickItemPrivate::get(childItem2)->effectiveLayoutMirror, true); |
1834 | QCOMPARE(QQuickItemPrivate::get(childItem2)->inheritMirrorFromParent, true); |
1835 | |
1836 | // stop inherting through a parent change |
1837 | QQuickItem *parentItem2 = new QQuickItem(); |
1838 | QQuickItemPrivate::get(item: parentItem2)->effectiveLayoutMirror = true; // LayoutMirroring.enabled: true |
1839 | QQuickItemPrivate::get(item: parentItem2)->resolveLayoutMirror(); |
1840 | childItem2->setParentItem(parentItem2); |
1841 | QCOMPARE(QQuickItemPrivate::get(childItem2)->effectiveLayoutMirror, false); |
1842 | QCOMPARE(QQuickItemPrivate::get(childItem2)->inheritMirrorFromParent, false); |
1843 | |
1844 | delete parentItem1; |
1845 | delete parentItem2; |
1846 | } |
1847 | |
1848 | void tst_QQuickItem::layoutMirroringWindow() |
1849 | { |
1850 | QQmlComponent component(&engine); |
1851 | component.loadUrl(url: testFileUrl(fileName: "layoutmirroring_window.qml" )); |
1852 | QScopedPointer<QObject> object(component.create()); |
1853 | QQuickWindow *window = qobject_cast<QQuickWindow *>(object: object.data()); |
1854 | QVERIFY(window); |
1855 | window->show(); |
1856 | |
1857 | QQuickItemPrivate *content = QQuickItemPrivate::get(item: window->contentItem()); |
1858 | QCOMPARE(content->effectiveLayoutMirror, true); |
1859 | QCOMPARE(content->inheritedLayoutMirror, true); |
1860 | QCOMPARE(content->isMirrorImplicit, false); |
1861 | QCOMPARE(content->inheritMirrorFromParent, true); |
1862 | QCOMPARE(content->inheritMirrorFromItem, true); |
1863 | } |
1864 | |
1865 | void tst_QQuickItem::layoutMirroringIllegalParent() |
1866 | { |
1867 | QQmlComponent component(&engine); |
1868 | component.setData("import QtQuick 2.0; QtObject { LayoutMirroring.enabled: true; LayoutMirroring.childrenInherit: true }" , baseUrl: QUrl::fromLocalFile(localfile: "" )); |
1869 | QTest::ignoreMessage(type: QtWarningMsg, message: "<Unknown File>:1:21: QML QtObject: LayoutDirection attached property only works with Items and Windows" ); |
1870 | QObject *object = component.create(); |
1871 | QVERIFY(object != nullptr); |
1872 | } |
1873 | |
1874 | void tst_QQuickItem::keyNavigation_data() |
1875 | { |
1876 | QTest::addColumn<QString>(name: "source" ); |
1877 | QTest::newRow(dataTag: "KeyNavigation" ) << QStringLiteral("keynavigationtest.qml" ); |
1878 | QTest::newRow(dataTag: "KeyNavigation_FocusScope" ) << QStringLiteral("keynavigationtest_focusscope.qml" ); |
1879 | } |
1880 | |
1881 | void tst_QQuickItem::keyNavigation() |
1882 | { |
1883 | QFETCH(QString, source); |
1884 | |
1885 | QQuickView *window = new QQuickView(nullptr); |
1886 | window->setBaseSize(QSize(240,320)); |
1887 | |
1888 | window->setSource(testFileUrl(fileName: source)); |
1889 | window->show(); |
1890 | window->requestActivate(); |
1891 | QVERIFY(QTest::qWaitForWindowActive(window)); |
1892 | QCOMPARE(QGuiApplication::focusWindow(), window); |
1893 | |
1894 | QQuickItem *item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item1" ); |
1895 | QVERIFY(item); |
1896 | QVERIFY(item->hasActiveFocus()); |
1897 | |
1898 | QVariant result; |
1899 | QVERIFY(QMetaObject::invokeMethod(window->rootObject(), "verify" , |
1900 | Q_RETURN_ARG(QVariant, result))); |
1901 | QVERIFY(result.toBool()); |
1902 | |
1903 | // right |
1904 | QKeyEvent key(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, "" , false, 1); |
1905 | QGuiApplication::sendEvent(receiver: window, event: &key); |
1906 | QVERIFY(key.isAccepted()); |
1907 | |
1908 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item2" ); |
1909 | QVERIFY(item); |
1910 | QVERIFY(item->hasActiveFocus()); |
1911 | |
1912 | // down |
1913 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier, "" , false, 1); |
1914 | QGuiApplication::sendEvent(receiver: window, event: &key); |
1915 | QVERIFY(key.isAccepted()); |
1916 | |
1917 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item4" ); |
1918 | QVERIFY(item); |
1919 | QVERIFY(item->hasActiveFocus()); |
1920 | |
1921 | // left |
1922 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier, "" , false, 1); |
1923 | QGuiApplication::sendEvent(receiver: window, event: &key); |
1924 | QVERIFY(key.isAccepted()); |
1925 | |
1926 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item3" ); |
1927 | QVERIFY(item); |
1928 | QVERIFY(item->hasActiveFocus()); |
1929 | |
1930 | // up |
1931 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Up, Qt::NoModifier, "" , false, 1); |
1932 | QGuiApplication::sendEvent(receiver: window, event: &key); |
1933 | QVERIFY(key.isAccepted()); |
1934 | |
1935 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item1" ); |
1936 | QVERIFY(item); |
1937 | QVERIFY(item->hasActiveFocus()); |
1938 | |
1939 | // tab |
1940 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "" , false, 1); |
1941 | QGuiApplication::sendEvent(receiver: window, event: &key); |
1942 | QVERIFY(key.isAccepted()); |
1943 | |
1944 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item2" ); |
1945 | QVERIFY(item); |
1946 | QVERIFY(item->hasActiveFocus()); |
1947 | |
1948 | // backtab |
1949 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Backtab, Qt::NoModifier, "" , false, 1); |
1950 | QGuiApplication::sendEvent(receiver: window, event: &key); |
1951 | QVERIFY(key.isAccepted()); |
1952 | |
1953 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item1" ); |
1954 | QVERIFY(item); |
1955 | QVERIFY(item->hasActiveFocus()); |
1956 | |
1957 | delete window; |
1958 | } |
1959 | |
1960 | void tst_QQuickItem::keyNavigation_RightToLeft() |
1961 | { |
1962 | QQuickView *window = new QQuickView(nullptr); |
1963 | window->setBaseSize(QSize(240,320)); |
1964 | |
1965 | window->setSource(testFileUrl(fileName: "keynavigationtest.qml" )); |
1966 | window->show(); |
1967 | window->requestActivate(); |
1968 | QVERIFY(QTest::qWaitForWindowActive(window)); |
1969 | QCOMPARE(QGuiApplication::focusWindow(), window); |
1970 | |
1971 | QQuickItem *rootItem = qobject_cast<QQuickItem*>(object: window->rootObject()); |
1972 | QVERIFY(rootItem); |
1973 | QQuickItemPrivate* rootItemPrivate = QQuickItemPrivate::get(item: rootItem); |
1974 | |
1975 | rootItemPrivate->effectiveLayoutMirror = true; // LayoutMirroring.mirror: true |
1976 | rootItemPrivate->isMirrorImplicit = false; |
1977 | rootItemPrivate->inheritMirrorFromItem = true; // LayoutMirroring.inherit: true |
1978 | rootItemPrivate->resolveLayoutMirror(); |
1979 | |
1980 | QEvent wa(QEvent::WindowActivate); |
1981 | QGuiApplication::sendEvent(receiver: window, event: &wa); |
1982 | QFocusEvent fe(QEvent::FocusIn); |
1983 | QGuiApplication::sendEvent(receiver: window, event: &fe); |
1984 | |
1985 | QQuickItem *item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item1" ); |
1986 | QVERIFY(item); |
1987 | QVERIFY(item->hasActiveFocus()); |
1988 | |
1989 | QVariant result; |
1990 | QVERIFY(QMetaObject::invokeMethod(window->rootObject(), "verify" , |
1991 | Q_RETURN_ARG(QVariant, result))); |
1992 | QVERIFY(result.toBool()); |
1993 | |
1994 | // right |
1995 | QKeyEvent key(QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier, "" , false, 1); |
1996 | QGuiApplication::sendEvent(receiver: window, event: &key); |
1997 | QVERIFY(key.isAccepted()); |
1998 | |
1999 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item2" ); |
2000 | QVERIFY(item); |
2001 | QVERIFY(item->hasActiveFocus()); |
2002 | |
2003 | // left |
2004 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, "" , false, 1); |
2005 | QGuiApplication::sendEvent(receiver: window, event: &key); |
2006 | QVERIFY(key.isAccepted()); |
2007 | |
2008 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item1" ); |
2009 | QVERIFY(item); |
2010 | QVERIFY(item->hasActiveFocus()); |
2011 | |
2012 | delete window; |
2013 | } |
2014 | |
2015 | void tst_QQuickItem::keyNavigation_skipNotVisible() |
2016 | { |
2017 | QQuickView *window = new QQuickView(nullptr); |
2018 | window->setBaseSize(QSize(240,320)); |
2019 | |
2020 | window->setSource(testFileUrl(fileName: "keynavigationtest.qml" )); |
2021 | window->show(); |
2022 | window->requestActivate(); |
2023 | QVERIFY(QTest::qWaitForWindowActive(window)); |
2024 | QCOMPARE(QGuiApplication::focusWindow(), window); |
2025 | |
2026 | QQuickItem *item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item1" ); |
2027 | QVERIFY(item); |
2028 | QVERIFY(item->hasActiveFocus()); |
2029 | |
2030 | // Set item 2 to not visible |
2031 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item2" ); |
2032 | QVERIFY(item); |
2033 | item->setVisible(false); |
2034 | QVERIFY(!item->isVisible()); |
2035 | |
2036 | // right |
2037 | QKeyEvent key(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, "" , false, 1); |
2038 | QGuiApplication::sendEvent(receiver: window, event: &key); |
2039 | QVERIFY(key.isAccepted()); |
2040 | |
2041 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item1" ); |
2042 | QVERIFY(item); |
2043 | QVERIFY(item->hasActiveFocus()); |
2044 | |
2045 | // tab |
2046 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "" , false, 1); |
2047 | QGuiApplication::sendEvent(receiver: window, event: &key); |
2048 | QVERIFY(key.isAccepted()); |
2049 | |
2050 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item3" ); |
2051 | QVERIFY(item); |
2052 | QVERIFY(item->hasActiveFocus()); |
2053 | |
2054 | // backtab |
2055 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Backtab, Qt::NoModifier, "" , false, 1); |
2056 | QGuiApplication::sendEvent(receiver: window, event: &key); |
2057 | QVERIFY(key.isAccepted()); |
2058 | |
2059 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item1" ); |
2060 | QVERIFY(item); |
2061 | QVERIFY(item->hasActiveFocus()); |
2062 | |
2063 | //Set item 3 to not visible |
2064 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item3" ); |
2065 | QVERIFY(item); |
2066 | item->setVisible(false); |
2067 | QVERIFY(!item->isVisible()); |
2068 | |
2069 | // tab |
2070 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "" , false, 1); |
2071 | QGuiApplication::sendEvent(receiver: window, event: &key); |
2072 | QVERIFY(key.isAccepted()); |
2073 | |
2074 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item4" ); |
2075 | QVERIFY(item); |
2076 | QVERIFY(item->hasActiveFocus()); |
2077 | |
2078 | // backtab |
2079 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Backtab, Qt::NoModifier, "" , false, 1); |
2080 | QGuiApplication::sendEvent(receiver: window, event: &key); |
2081 | QVERIFY(key.isAccepted()); |
2082 | |
2083 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item1" ); |
2084 | QVERIFY(item); |
2085 | QVERIFY(item->hasActiveFocus()); |
2086 | |
2087 | delete window; |
2088 | } |
2089 | |
2090 | void tst_QQuickItem::keyNavigation_implicitSetting() |
2091 | { |
2092 | QQuickView *window = new QQuickView(nullptr); |
2093 | window->setBaseSize(QSize(240,320)); |
2094 | |
2095 | window->setSource(testFileUrl(fileName: "keynavigationtest_implicit.qml" )); |
2096 | window->show(); |
2097 | window->requestActivate(); |
2098 | QVERIFY(QTest::qWaitForWindowActive(window)); |
2099 | QCOMPARE(QGuiApplication::focusWindow(), window); |
2100 | |
2101 | QEvent wa(QEvent::WindowActivate); |
2102 | QGuiApplication::sendEvent(receiver: window, event: &wa); |
2103 | QFocusEvent fe(QEvent::FocusIn); |
2104 | QGuiApplication::sendEvent(receiver: window, event: &fe); |
2105 | |
2106 | QQuickItem *item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item1" ); |
2107 | QVERIFY(item); |
2108 | QVERIFY(item->hasActiveFocus()); |
2109 | |
2110 | QVariant result; |
2111 | QVERIFY(QMetaObject::invokeMethod(window->rootObject(), "verify" , |
2112 | Q_RETURN_ARG(QVariant, result))); |
2113 | QVERIFY(result.toBool()); |
2114 | |
2115 | // right |
2116 | QKeyEvent key(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, "" , false, 1); |
2117 | QGuiApplication::sendEvent(receiver: window, event: &key); |
2118 | QVERIFY(key.isAccepted()); |
2119 | |
2120 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item2" ); |
2121 | QVERIFY(item); |
2122 | QVERIFY(item->hasActiveFocus()); |
2123 | |
2124 | // back to item1 |
2125 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier, "" , false, 1); |
2126 | QGuiApplication::sendEvent(receiver: window, event: &key); |
2127 | QVERIFY(key.isAccepted()); |
2128 | |
2129 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item1" ); |
2130 | QVERIFY(item); |
2131 | QVERIFY(item->hasActiveFocus()); |
2132 | |
2133 | // down |
2134 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier, "" , false, 1); |
2135 | QGuiApplication::sendEvent(receiver: window, event: &key); |
2136 | QVERIFY(key.isAccepted()); |
2137 | |
2138 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item3" ); |
2139 | QVERIFY(item); |
2140 | QVERIFY(item->hasActiveFocus()); |
2141 | |
2142 | // move to item4 |
2143 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, "" , false, 1); |
2144 | QGuiApplication::sendEvent(receiver: window, event: &key); |
2145 | QVERIFY(key.isAccepted()); |
2146 | |
2147 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item4" ); |
2148 | QVERIFY(item); |
2149 | QVERIFY(item->hasActiveFocus()); |
2150 | |
2151 | // left |
2152 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier, "" , false, 1); |
2153 | QGuiApplication::sendEvent(receiver: window, event: &key); |
2154 | QVERIFY(key.isAccepted()); |
2155 | |
2156 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item3" ); |
2157 | QVERIFY(item); |
2158 | QVERIFY(item->hasActiveFocus()); |
2159 | |
2160 | // back to item4 |
2161 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, "" , false, 1); |
2162 | QGuiApplication::sendEvent(receiver: window, event: &key); |
2163 | QVERIFY(key.isAccepted()); |
2164 | |
2165 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item4" ); |
2166 | QVERIFY(item); |
2167 | QVERIFY(item->hasActiveFocus()); |
2168 | |
2169 | // up |
2170 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Up, Qt::NoModifier, "" , false, 1); |
2171 | QGuiApplication::sendEvent(receiver: window, event: &key); |
2172 | QVERIFY(key.isAccepted()); |
2173 | |
2174 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item2" ); |
2175 | QVERIFY(item); |
2176 | QVERIFY(item->hasActiveFocus()); |
2177 | |
2178 | // back to item4 |
2179 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier, "" , false, 1); |
2180 | QGuiApplication::sendEvent(receiver: window, event: &key); |
2181 | QVERIFY(key.isAccepted()); |
2182 | |
2183 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item4" ); |
2184 | QVERIFY(item); |
2185 | QVERIFY(item->hasActiveFocus()); |
2186 | |
2187 | // tab |
2188 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "" , false, 1); |
2189 | QGuiApplication::sendEvent(receiver: window, event: &key); |
2190 | QVERIFY(key.isAccepted()); |
2191 | |
2192 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item1" ); |
2193 | QVERIFY(item); |
2194 | QVERIFY(item->hasActiveFocus()); |
2195 | |
2196 | // back to item4 |
2197 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Backtab, Qt::NoModifier, "" , false, 1); |
2198 | QGuiApplication::sendEvent(receiver: window, event: &key); |
2199 | QVERIFY(key.isAccepted()); |
2200 | |
2201 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item4" ); |
2202 | QVERIFY(item); |
2203 | QVERIFY(item->hasActiveFocus()); |
2204 | |
2205 | // backtab |
2206 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Backtab, Qt::NoModifier, "" , false, 1); |
2207 | QGuiApplication::sendEvent(receiver: window, event: &key); |
2208 | QVERIFY(key.isAccepted()); |
2209 | |
2210 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item3" ); |
2211 | QVERIFY(item); |
2212 | QVERIFY(item->hasActiveFocus()); |
2213 | |
2214 | delete window; |
2215 | } |
2216 | |
2217 | // QTBUG-75399 |
2218 | void tst_QQuickItem::keyNavigation_implicitDestroy() |
2219 | { |
2220 | QQuickView view; |
2221 | view.setSource(testFileUrl(fileName: "keynavigationtest_implicitDestroy.qml" )); |
2222 | view.show(); |
2223 | |
2224 | QVERIFY(QTest::qWaitForWindowActive(&view)); |
2225 | |
2226 | QQuickItem *root = view.rootObject(); |
2227 | QVERIFY(QMetaObject::invokeMethod(root, "createImplicitKeyNavigation" )); |
2228 | |
2229 | // process events is necessary to trigger upcoming memory access violation |
2230 | QTest::qWait(ms: 0); |
2231 | |
2232 | QVERIFY(root->hasActiveFocus()); |
2233 | |
2234 | QKeyEvent keyPress = QKeyEvent(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier, "" , false, 1); |
2235 | QGuiApplication::sendEvent(receiver: &view, event: &keyPress); // <-- access violation happens here |
2236 | // this should fail the test, even if the access violation does not occur |
2237 | QVERIFY(!keyPress.isAccepted()); |
2238 | } |
2239 | |
2240 | void tst_QQuickItem::keyNavigation_focusReason() |
2241 | { |
2242 | QQuickView *window = new QQuickView(nullptr); |
2243 | window->setBaseSize(QSize(240,320)); |
2244 | |
2245 | FocusEventFilter focusEventFilter; |
2246 | |
2247 | window->setSource(testFileUrl(fileName: "keynavigationtest.qml" )); |
2248 | window->show(); |
2249 | window->requestActivate(); |
2250 | |
2251 | QVERIFY(QTest::qWaitForWindowActive(window)); |
2252 | QCOMPARE(QGuiApplication::focusWindow(), window); |
2253 | |
2254 | // install event filter on first item |
2255 | QQuickItem *item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item1" ); |
2256 | QVERIFY(item); |
2257 | QVERIFY(item->hasActiveFocus()); |
2258 | item->installEventFilter(filterObj: &focusEventFilter); |
2259 | |
2260 | //install event filter on second item |
2261 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item2" ); |
2262 | QVERIFY(item); |
2263 | item->installEventFilter(filterObj: &focusEventFilter); |
2264 | |
2265 | //install event filter on third item |
2266 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item3" ); |
2267 | QVERIFY(item); |
2268 | item->installEventFilter(filterObj: &focusEventFilter); |
2269 | |
2270 | //install event filter on last item |
2271 | item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item4" ); |
2272 | QVERIFY(item); |
2273 | item->installEventFilter(filterObj: &focusEventFilter); |
2274 | |
2275 | // tab |
2276 | QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "" , false, 1); |
2277 | QGuiApplication::sendEvent(receiver: window, event: &key); |
2278 | QVERIFY(key.isAccepted()); |
2279 | QCOMPARE(focusEventFilter.lastFocusReason, Qt::TabFocusReason); |
2280 | |
2281 | // backtab |
2282 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Backtab, Qt::NoModifier, "" , false, 1); |
2283 | QGuiApplication::sendEvent(receiver: window, event: &key); |
2284 | QVERIFY(key.isAccepted()); |
2285 | QCOMPARE(focusEventFilter.lastFocusReason, Qt::BacktabFocusReason); |
2286 | |
2287 | // right - it's also one kind of key navigation |
2288 | key = QKeyEvent(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, "" , false, 1); |
2289 | QGuiApplication::sendEvent(receiver: window, event: &key); |
2290 | QVERIFY(key.isAccepted()); |
2291 | QCOMPARE(focusEventFilter.lastFocusReason, Qt::TabFocusReason); |
2292 | |
2293 | item->setFocus(focus: true, reason: Qt::OtherFocusReason); |
2294 | QVERIFY(item->hasActiveFocus()); |
2295 | QCOMPARE(focusEventFilter.lastFocusReason, Qt::OtherFocusReason); |
2296 | |
2297 | delete window; |
2298 | } |
2299 | |
2300 | void tst_QQuickItem::keyNavigation_loop() |
2301 | { |
2302 | // QTBUG-47229 |
2303 | QQuickView *window = new QQuickView(nullptr); |
2304 | window->setBaseSize(QSize(240,320)); |
2305 | |
2306 | window->setSource(testFileUrl(fileName: "keynavigationtest_loop.qml" )); |
2307 | window->show(); |
2308 | window->requestActivate(); |
2309 | |
2310 | QVERIFY(QTest::qWaitForWindowActive(window)); |
2311 | QCOMPARE(QGuiApplication::focusWindow(), window); |
2312 | |
2313 | QQuickItem *item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item1" ); |
2314 | QVERIFY(item); |
2315 | QVERIFY(item->hasActiveFocus()); |
2316 | |
2317 | QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier, "" , false, 1); |
2318 | QGuiApplication::sendEvent(receiver: window, event: &key); |
2319 | QVERIFY(key.isAccepted()); |
2320 | QVERIFY(item->hasActiveFocus()); |
2321 | |
2322 | delete window; |
2323 | } |
2324 | |
2325 | void tst_QQuickItem::keyNavigation_repeater() |
2326 | { |
2327 | // QTBUG-83356 |
2328 | QScopedPointer<QQuickView> window(new QQuickView()); |
2329 | window->setBaseSize(QSize(240,320)); |
2330 | |
2331 | window->setSource(testFileUrl(fileName: "keynavigationtest_repeater.qml" )); |
2332 | window->show(); |
2333 | window->requestActivate(); |
2334 | |
2335 | QVariant result; |
2336 | QVERIFY(QMetaObject::invokeMethod(window->rootObject(), "verify" , |
2337 | Q_RETURN_ARG(QVariant, result))); |
2338 | QVERIFY(result.toBool()); |
2339 | } |
2340 | |
2341 | void tst_QQuickItem::smooth() |
2342 | { |
2343 | QQmlComponent component(&engine); |
2344 | component.setData("import QtQuick 2.0; Item { smooth: false; }" , baseUrl: QUrl::fromLocalFile(localfile: "" )); |
2345 | QQuickItem *item = qobject_cast<QQuickItem*>(object: component.create()); |
2346 | QSignalSpy spy(item, SIGNAL(smoothChanged(bool))); |
2347 | |
2348 | QVERIFY(item); |
2349 | QVERIFY(!item->smooth()); |
2350 | |
2351 | item->setSmooth(true); |
2352 | QVERIFY(item->smooth()); |
2353 | QCOMPARE(spy.count(),1); |
2354 | QList<QVariant> arguments = spy.first(); |
2355 | QCOMPARE(arguments.count(), 1); |
2356 | QVERIFY(arguments.at(0).toBool()); |
2357 | |
2358 | item->setSmooth(true); |
2359 | QCOMPARE(spy.count(),1); |
2360 | |
2361 | item->setSmooth(false); |
2362 | QVERIFY(!item->smooth()); |
2363 | QCOMPARE(spy.count(),2); |
2364 | item->setSmooth(false); |
2365 | QCOMPARE(spy.count(),2); |
2366 | |
2367 | delete item; |
2368 | } |
2369 | |
2370 | void tst_QQuickItem::antialiasing() |
2371 | { |
2372 | QQmlComponent component(&engine); |
2373 | component.setData("import QtQuick 2.0; Item { antialiasing: false; }" , baseUrl: QUrl::fromLocalFile(localfile: "" )); |
2374 | QQuickItem *item = qobject_cast<QQuickItem*>(object: component.create()); |
2375 | QSignalSpy spy(item, SIGNAL(antialiasingChanged(bool))); |
2376 | |
2377 | QVERIFY(item); |
2378 | QVERIFY(!item->antialiasing()); |
2379 | |
2380 | item->setAntialiasing(true); |
2381 | QVERIFY(item->antialiasing()); |
2382 | QCOMPARE(spy.count(),1); |
2383 | QList<QVariant> arguments = spy.first(); |
2384 | QCOMPARE(arguments.count(), 1); |
2385 | QVERIFY(arguments.at(0).toBool()); |
2386 | |
2387 | item->setAntialiasing(true); |
2388 | QCOMPARE(spy.count(),1); |
2389 | |
2390 | item->setAntialiasing(false); |
2391 | QVERIFY(!item->antialiasing()); |
2392 | QCOMPARE(spy.count(),2); |
2393 | item->setAntialiasing(false); |
2394 | QCOMPARE(spy.count(),2); |
2395 | |
2396 | delete item; |
2397 | } |
2398 | |
2399 | void tst_QQuickItem::clip() |
2400 | { |
2401 | QQmlComponent component(&engine); |
2402 | component.setData("import QtQuick 2.0\nItem { clip: false\n }" , baseUrl: QUrl::fromLocalFile(localfile: "" )); |
2403 | QQuickItem *item = qobject_cast<QQuickItem*>(object: component.create()); |
2404 | QSignalSpy spy(item, SIGNAL(clipChanged(bool))); |
2405 | |
2406 | QVERIFY(item); |
2407 | QVERIFY(!item->clip()); |
2408 | |
2409 | item->setClip(true); |
2410 | QVERIFY(item->clip()); |
2411 | |
2412 | QList<QVariant> arguments = spy.first(); |
2413 | QCOMPARE(arguments.count(), 1); |
2414 | QVERIFY(arguments.at(0).toBool()); |
2415 | |
2416 | QCOMPARE(spy.count(),1); |
2417 | item->setClip(true); |
2418 | QCOMPARE(spy.count(),1); |
2419 | |
2420 | item->setClip(false); |
2421 | QVERIFY(!item->clip()); |
2422 | QCOMPARE(spy.count(),2); |
2423 | item->setClip(false); |
2424 | QCOMPARE(spy.count(),2); |
2425 | |
2426 | delete item; |
2427 | } |
2428 | |
2429 | void tst_QQuickItem::mapCoordinates() |
2430 | { |
2431 | QFETCH(int, x); |
2432 | QFETCH(int, y); |
2433 | |
2434 | QQuickView *window = new QQuickView(nullptr); |
2435 | window->setBaseSize(QSize(300, 300)); |
2436 | window->setSource(testFileUrl(fileName: "mapCoordinates.qml" )); |
2437 | window->show(); |
2438 | qApp->processEvents(); |
2439 | |
2440 | QQuickItem *root = qobject_cast<QQuickItem*>(object: window->rootObject()); |
2441 | QVERIFY(root != nullptr); |
2442 | QQuickItem *a = findItem<QQuickItem>(parent: window->rootObject(), objectName: "itemA" ); |
2443 | QVERIFY(a != nullptr); |
2444 | QQuickItem *b = findItem<QQuickItem>(parent: window->rootObject(), objectName: "itemB" ); |
2445 | QVERIFY(b != nullptr); |
2446 | |
2447 | QVariant result; |
2448 | |
2449 | QVERIFY(QMetaObject::invokeMethod(root, "mapAToB" , |
2450 | Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y))); |
2451 | QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapToItem(b, QPointF(x, y))); |
2452 | |
2453 | QVERIFY(QMetaObject::invokeMethod(root, "mapAToBPoint" , |
2454 | Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y))); |
2455 | QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapToItem(b, QPointF(x, y))); |
2456 | |
2457 | QVERIFY(QMetaObject::invokeMethod(root, "mapAFromB" , |
2458 | Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y))); |
2459 | QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapFromItem(b, QPointF(x, y))); |
2460 | |
2461 | QVERIFY(QMetaObject::invokeMethod(root, "mapAFromBPoint" , |
2462 | Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y))); |
2463 | QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapFromItem(b, QPointF(x, y))); |
2464 | |
2465 | QVERIFY(QMetaObject::invokeMethod(root, "mapAToNull" , |
2466 | Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y))); |
2467 | QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapToScene(QPointF(x, y))); |
2468 | |
2469 | QVERIFY(QMetaObject::invokeMethod(root, "mapAFromNull" , |
2470 | Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y))); |
2471 | QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapFromScene(QPointF(x, y))); |
2472 | |
2473 | QVERIFY(QMetaObject::invokeMethod(root, "mapAToGlobal" , |
2474 | Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y))); |
2475 | QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapToGlobal(QPointF(x, y))); |
2476 | |
2477 | QVERIFY(QMetaObject::invokeMethod(root, "mapAToGlobalPoint" , |
2478 | Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y))); |
2479 | QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapToGlobal(QPointF(x, y))); |
2480 | |
2481 | QVERIFY(QMetaObject::invokeMethod(root, "mapAFromGlobal" , |
2482 | Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y))); |
2483 | QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapFromGlobal(QPointF(x, y))); |
2484 | |
2485 | QVERIFY(QMetaObject::invokeMethod(root, "mapAFromGlobalPoint" , |
2486 | Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y))); |
2487 | QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapFromGlobal(QPointF(x, y))); |
2488 | |
2489 | // for orphans we are primarily testing that we don't crash. |
2490 | // when orphaned the final position is the original position of the item translated by x,y |
2491 | QVERIFY(QMetaObject::invokeMethod(root, "mapOrphanToGlobal" , |
2492 | Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y))); |
2493 | QCOMPARE(result.value<QPointF>(), QPointF(150,150) + QPointF(x, y)); |
2494 | |
2495 | QVERIFY(QMetaObject::invokeMethod(root, "mapOrphanFromGlobal" , |
2496 | Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y))); |
2497 | QCOMPARE(result.value<QPointF>(), -QPointF(150,150) + QPointF(x, y)); |
2498 | |
2499 | QString warning1 = testFileUrl(fileName: "mapCoordinates.qml" ).toString() + ":35:5: QML Item: mapToItem() given argument \"1122\" which is neither null nor an Item" ; |
2500 | QString warning2 = testFileUrl(fileName: "mapCoordinates.qml" ).toString() + ":35:5: QML Item: mapFromItem() given argument \"1122\" which is neither null nor an Item" ; |
2501 | |
2502 | QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning1)); |
2503 | QVERIFY(QMetaObject::invokeMethod(root, "checkMapAToInvalid" , |
2504 | Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y))); |
2505 | QVERIFY(result.toBool()); |
2506 | |
2507 | QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning2)); |
2508 | QVERIFY(QMetaObject::invokeMethod(root, "checkMapAFromInvalid" , |
2509 | Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y))); |
2510 | QVERIFY(result.toBool()); |
2511 | |
2512 | delete window; |
2513 | } |
2514 | |
2515 | void tst_QQuickItem::mapCoordinates_data() |
2516 | { |
2517 | QTest::addColumn<int>(name: "x" ); |
2518 | QTest::addColumn<int>(name: "y" ); |
2519 | |
2520 | for (int i=-20; i<=20; i+=10) |
2521 | QTest::newRow(dataTag: QTest::toString(i)) << i << i; |
2522 | } |
2523 | |
2524 | void tst_QQuickItem::mapCoordinatesRect() |
2525 | { |
2526 | QFETCH(int, x); |
2527 | QFETCH(int, y); |
2528 | QFETCH(int, width); |
2529 | QFETCH(int, height); |
2530 | |
2531 | QQuickView *window = new QQuickView(nullptr); |
2532 | window->setBaseSize(QSize(300, 300)); |
2533 | window->setSource(testFileUrl(fileName: "mapCoordinatesRect.qml" )); |
2534 | window->show(); |
2535 | qApp->processEvents(); |
2536 | |
2537 | QQuickItem *root = qobject_cast<QQuickItem*>(object: window->rootObject()); |
2538 | QVERIFY(root != nullptr); |
2539 | QQuickItem *a = findItem<QQuickItem>(parent: window->rootObject(), objectName: "itemA" ); |
2540 | QVERIFY(a != nullptr); |
2541 | QQuickItem *b = findItem<QQuickItem>(parent: window->rootObject(), objectName: "itemB" ); |
2542 | QVERIFY(b != nullptr); |
2543 | |
2544 | QVariant result; |
2545 | |
2546 | QVERIFY(QMetaObject::invokeMethod(root, "mapAToB" , |
2547 | Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y), Q_ARG(QVariant, width), Q_ARG(QVariant, height))); |
2548 | QCOMPARE(result.value<QRectF>(), qobject_cast<QQuickItem*>(a)->mapRectToItem(b, QRectF(x, y, width, height))); |
2549 | |
2550 | QVERIFY(QMetaObject::invokeMethod(root, "mapAToBRect" , |
2551 | Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y), Q_ARG(QVariant, width), Q_ARG(QVariant, height))); |
2552 | QCOMPARE(result.value<QRectF>(), qobject_cast<QQuickItem*>(a)->mapRectToItem(b, QRectF(x, y, width, height))); |
2553 | |
2554 | QVERIFY(QMetaObject::invokeMethod(root, "mapAFromB" , |
2555 | Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y), Q_ARG(QVariant, width), Q_ARG(QVariant, height))); |
2556 | QCOMPARE(result.value<QRectF>(), qobject_cast<QQuickItem*>(a)->mapRectFromItem(b, QRectF(x, y, width, height))); |
2557 | |
2558 | QVERIFY(QMetaObject::invokeMethod(root, "mapAFromBRect" , |
2559 | Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y), Q_ARG(QVariant, width), Q_ARG(QVariant, height))); |
2560 | QCOMPARE(result.value<QRectF>(), qobject_cast<QQuickItem*>(a)->mapRectFromItem(b, QRectF(x, y, width, height))); |
2561 | |
2562 | QVERIFY(QMetaObject::invokeMethod(root, "mapAToNull" , |
2563 | Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y), Q_ARG(QVariant, width), Q_ARG(QVariant, height))); |
2564 | QCOMPARE(result.value<QRectF>(), qobject_cast<QQuickItem*>(a)->mapRectToScene(QRectF(x, y, width, height))); |
2565 | |
2566 | QVERIFY(QMetaObject::invokeMethod(root, "mapAFromNull" , |
2567 | Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y), Q_ARG(QVariant, width), Q_ARG(QVariant, height))); |
2568 | QCOMPARE(result.value<QRectF>(), qobject_cast<QQuickItem*>(a)->mapRectFromScene(QRectF(x, y, width, height))); |
2569 | |
2570 | QString warning1 = testFileUrl(fileName: "mapCoordinatesRect.qml" ).toString() + ":35:5: QML Item: mapToItem() given argument \"1122\" which is neither null nor an Item" ; |
2571 | QString warning2 = testFileUrl(fileName: "mapCoordinatesRect.qml" ).toString() + ":35:5: QML Item: mapFromItem() given argument \"1122\" which is neither null nor an Item" ; |
2572 | |
2573 | QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning1)); |
2574 | QVERIFY(QMetaObject::invokeMethod(root, "checkMapAToInvalid" , |
2575 | Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y), Q_ARG(QVariant, width), Q_ARG(QVariant, height))); |
2576 | QVERIFY(result.toBool()); |
2577 | |
2578 | QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning2)); |
2579 | QVERIFY(QMetaObject::invokeMethod(root, "checkMapAFromInvalid" , |
2580 | Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y), Q_ARG(QVariant, width), Q_ARG(QVariant, height))); |
2581 | QVERIFY(result.toBool()); |
2582 | |
2583 | delete window; |
2584 | } |
2585 | |
2586 | void tst_QQuickItem::mapCoordinatesRect_data() |
2587 | { |
2588 | QTest::addColumn<int>(name: "x" ); |
2589 | QTest::addColumn<int>(name: "y" ); |
2590 | QTest::addColumn<int>(name: "width" ); |
2591 | QTest::addColumn<int>(name: "height" ); |
2592 | |
2593 | for (int i=-20; i<=20; i+=5) |
2594 | QTest::newRow(dataTag: QTest::toString(i)) << i << i << i << i; |
2595 | } |
2596 | |
2597 | void tst_QQuickItem::transforms_data() |
2598 | { |
2599 | QTest::addColumn<QByteArray>(name: "qml" ); |
2600 | QTest::addColumn<QTransform>(name: "transform" ); |
2601 | QTest::newRow(dataTag: "translate" ) << QByteArray("Translate { x: 10; y: 20 }" ) |
2602 | << QTransform(1,0,0,0,1,0,10,20,1); |
2603 | QTest::newRow(dataTag: "matrix4x4" ) << QByteArray("Matrix4x4 { matrix: Qt.matrix4x4(1,0,0,10, 0,1,0,15, 0,0,1,0, 0,0,0,1) }" ) |
2604 | << QTransform(1,0,0,0,1,0,10,15,1); |
2605 | QTest::newRow(dataTag: "rotation" ) << QByteArray("Rotation { angle: 90 }" ) |
2606 | << QTransform(0,1,0,-1,0,0,0,0,1); |
2607 | QTest::newRow(dataTag: "scale" ) << QByteArray("Scale { xScale: 1.5; yScale: -2 }" ) |
2608 | << QTransform(1.5,0,0,0,-2,0,0,0,1); |
2609 | QTest::newRow(dataTag: "sequence" ) << QByteArray("[ Translate { x: 10; y: 20 }, Scale { xScale: 1.5; yScale: -2 } ]" ) |
2610 | << QTransform(1,0,0,0,1,0,10,20,1) * QTransform(1.5,0,0,0,-2,0,0,0,1); |
2611 | } |
2612 | |
2613 | void tst_QQuickItem::transforms() |
2614 | { |
2615 | QFETCH(QByteArray, qml); |
2616 | QFETCH(QTransform, transform); |
2617 | QQmlComponent component(&engine); |
2618 | component.setData("import QtQuick 2.3\nItem { transform: " +qml+"}" , baseUrl: QUrl::fromLocalFile(localfile: "" )); |
2619 | QQuickItem *item = qobject_cast<QQuickItem*>(object: component.create()); |
2620 | QVERIFY(item); |
2621 | QCOMPARE(item->itemTransform(nullptr,nullptr), transform); |
2622 | } |
2623 | |
2624 | void tst_QQuickItem::childrenProperty() |
2625 | { |
2626 | QQmlComponent component(&engine, testFileUrl(fileName: "childrenProperty.qml" )); |
2627 | |
2628 | QObject *o = component.create(); |
2629 | QVERIFY(o != nullptr); |
2630 | |
2631 | QCOMPARE(o->property("test1" ).toBool(), true); |
2632 | QCOMPARE(o->property("test2" ).toBool(), true); |
2633 | QCOMPARE(o->property("test3" ).toBool(), true); |
2634 | QCOMPARE(o->property("test4" ).toBool(), true); |
2635 | QCOMPARE(o->property("test5" ).toBool(), true); |
2636 | delete o; |
2637 | } |
2638 | |
2639 | void tst_QQuickItem::resourcesProperty() |
2640 | { |
2641 | QQmlComponent component(&engine, testFileUrl(fileName: "resourcesProperty.qml" )); |
2642 | |
2643 | QObject *object = component.create(); |
2644 | QVERIFY(object != nullptr); |
2645 | |
2646 | QQmlProperty property(object, "resources" , component.creationContext()); |
2647 | |
2648 | QVERIFY(property.isValid()); |
2649 | QQmlListReference list = qvariant_cast<QQmlListReference>(v: property.read()); |
2650 | QVERIFY(list.isValid()); |
2651 | |
2652 | QCOMPARE(list.count(), 4); |
2653 | |
2654 | QCOMPARE(object->property("test1" ).toBool(), true); |
2655 | QCOMPARE(object->property("test2" ).toBool(), true); |
2656 | QCOMPARE(object->property("test3" ).toBool(), true); |
2657 | QCOMPARE(object->property("test4" ).toBool(), true); |
2658 | QCOMPARE(object->property("test5" ).toBool(), true); |
2659 | QCOMPARE(object->property("test6" ).toBool(), true); |
2660 | |
2661 | QObject *subObject = object->findChild<QObject *>(aName: "subObject" ); |
2662 | |
2663 | QVERIFY(subObject); |
2664 | |
2665 | QCOMPARE(object, subObject->parent()); |
2666 | |
2667 | delete subObject; |
2668 | |
2669 | QCOMPARE(list.count(), 3); |
2670 | |
2671 | delete object; |
2672 | } |
2673 | |
2674 | void tst_QQuickItem::propertyChanges() |
2675 | { |
2676 | QQuickView *window = new QQuickView(nullptr); |
2677 | window->setBaseSize(QSize(300, 300)); |
2678 | window->setSource(testFileUrl(fileName: "propertychanges.qml" )); |
2679 | window->show(); |
2680 | window->requestActivate(); |
2681 | QVERIFY(QTest::qWaitForWindowActive(window)); |
2682 | QCOMPARE(QGuiApplication::focusWindow(), window); |
2683 | |
2684 | QQuickItem *item = findItem<QQuickItem>(parent: window->rootObject(), objectName: "item" ); |
2685 | QQuickItem *parentItem = findItem<QQuickItem>(parent: window->rootObject(), objectName: "parentItem" ); |
2686 | |
2687 | QVERIFY(item); |
2688 | QVERIFY(parentItem); |
2689 | |
2690 | QSignalSpy parentSpy(item, SIGNAL(parentChanged(QQuickItem*))); |
2691 | QSignalSpy widthSpy(item, SIGNAL(widthChanged())); |
2692 | QSignalSpy heightSpy(item, SIGNAL(heightChanged())); |
2693 | QSignalSpy baselineOffsetSpy(item, SIGNAL(baselineOffsetChanged(qreal))); |
2694 | QSignalSpy childrenRectSpy(parentItem, SIGNAL(childrenRectChanged(QRectF))); |
2695 | QSignalSpy focusSpy(item, SIGNAL(focusChanged(bool))); |
2696 | QSignalSpy wantsFocusSpy(parentItem, SIGNAL(activeFocusChanged(bool))); |
2697 | QSignalSpy childrenChangedSpy(parentItem, SIGNAL(childrenChanged())); |
2698 | QSignalSpy xSpy(item, SIGNAL(xChanged())); |
2699 | QSignalSpy ySpy(item, SIGNAL(yChanged())); |
2700 | |
2701 | item->setParentItem(parentItem); |
2702 | item->setWidth(100.0); |
2703 | item->setHeight(200.0); |
2704 | item->setFocus(true); |
2705 | item->setBaselineOffset(10.0); |
2706 | |
2707 | QCOMPARE(item->parentItem(), parentItem); |
2708 | QCOMPARE(parentSpy.count(),1); |
2709 | QList<QVariant> parentArguments = parentSpy.first(); |
2710 | QCOMPARE(parentArguments.count(), 1); |
2711 | QCOMPARE(item->parentItem(), qvariant_cast<QQuickItem *>(parentArguments.at(0))); |
2712 | QCOMPARE(childrenChangedSpy.count(),1); |
2713 | |
2714 | item->setParentItem(parentItem); |
2715 | QCOMPARE(childrenChangedSpy.count(),1); |
2716 | |
2717 | QCOMPARE(item->width(), 100.0); |
2718 | QCOMPARE(widthSpy.count(),1); |
2719 | |
2720 | QCOMPARE(item->height(), 200.0); |
2721 | QCOMPARE(heightSpy.count(),1); |
2722 | |
2723 | QCOMPARE(item->baselineOffset(), 10.0); |
2724 | QCOMPARE(baselineOffsetSpy.count(),1); |
2725 | QList<QVariant> baselineOffsetArguments = baselineOffsetSpy.first(); |
2726 | QCOMPARE(baselineOffsetArguments.count(), 1); |
2727 | QCOMPARE(item->baselineOffset(), baselineOffsetArguments.at(0).toReal()); |
2728 | |
2729 | QCOMPARE(parentItem->childrenRect(), QRectF(0.0,0.0,100.0,200.0)); |
2730 | QCOMPARE(childrenRectSpy.count(),1); |
2731 | QList<QVariant> childrenRectArguments = childrenRectSpy.at(i: 0); |
2732 | QCOMPARE(childrenRectArguments.count(), 1); |
2733 | QCOMPARE(parentItem->childrenRect(), childrenRectArguments.at(0).toRectF()); |
2734 | |
2735 | QCOMPARE(item->hasActiveFocus(), true); |
2736 | QCOMPARE(focusSpy.count(),1); |
2737 | QList<QVariant> focusArguments = focusSpy.first(); |
2738 | QCOMPARE(focusArguments.count(), 1); |
2739 | QCOMPARE(focusArguments.at(0).toBool(), true); |
2740 | |
2741 | QCOMPARE(parentItem->hasActiveFocus(), false); |
2742 | QCOMPARE(parentItem->hasFocus(), false); |
2743 | QCOMPARE(wantsFocusSpy.count(),0); |
2744 | |
2745 | item->setX(10.0); |
2746 | QCOMPARE(item->x(), 10.0); |
2747 | QCOMPARE(xSpy.count(), 1); |
2748 | |
2749 | item->setY(10.0); |
2750 | QCOMPARE(item->y(), 10.0); |
2751 | QCOMPARE(ySpy.count(), 1); |
2752 | |
2753 | delete window; |
2754 | } |
2755 | |
2756 | void tst_QQuickItem::nonexistentPropertyConnection() |
2757 | { |
2758 | // QTBUG-56551: don't crash |
2759 | QQmlComponent component(&engine, testFileUrl(fileName: "nonexistentPropertyConnection.qml" )); |
2760 | QObject *o = component.create(); |
2761 | QVERIFY(o); |
2762 | delete o; |
2763 | } |
2764 | |
2765 | void tst_QQuickItem::childrenRect() |
2766 | { |
2767 | QQuickView *window = new QQuickView(nullptr); |
2768 | window->setSource(testFileUrl(fileName: "childrenRect.qml" )); |
2769 | window->setBaseSize(QSize(240,320)); |
2770 | window->show(); |
2771 | |
2772 | QQuickItem *o = window->rootObject(); |
2773 | QQuickItem *item = o->findChild<QQuickItem*>(aName: "testItem" ); |
2774 | QCOMPARE(item->width(), qreal(0)); |
2775 | QCOMPARE(item->height(), qreal(0)); |
2776 | |
2777 | o->setProperty(name: "childCount" , value: 1); |
2778 | QCOMPARE(item->width(), qreal(10)); |
2779 | QCOMPARE(item->height(), qreal(20)); |
2780 | |
2781 | o->setProperty(name: "childCount" , value: 5); |
2782 | QCOMPARE(item->width(), qreal(50)); |
2783 | QCOMPARE(item->height(), qreal(100)); |
2784 | |
2785 | o->setProperty(name: "childCount" , value: 0); |
2786 | QCOMPARE(item->width(), qreal(0)); |
2787 | QCOMPARE(item->height(), qreal(0)); |
2788 | |
2789 | delete o; |
2790 | delete window; |
2791 | } |
2792 | |
2793 | // QTBUG-11383 |
2794 | void tst_QQuickItem::childrenRectBug() |
2795 | { |
2796 | QQuickView *window = new QQuickView(nullptr); |
2797 | |
2798 | QString warning = testFileUrl(fileName: "childrenRectBug.qml" ).toString() + ":7:5: QML Item: Binding loop detected for property \"height\"" ; |
2799 | QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning)); |
2800 | QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning)); |
2801 | |
2802 | window->setSource(testFileUrl(fileName: "childrenRectBug.qml" )); |
2803 | window->show(); |
2804 | |
2805 | QQuickItem *o = window->rootObject(); |
2806 | QQuickItem *item = o->findChild<QQuickItem*>(aName: "theItem" ); |
2807 | QCOMPARE(item->width(), qreal(200)); |
2808 | QCOMPARE(item->height(), qreal(100)); |
2809 | QCOMPARE(item->x(), qreal(100)); |
2810 | |
2811 | delete window; |
2812 | } |
2813 | |
2814 | // QTBUG-11465 |
2815 | void tst_QQuickItem::childrenRectBug2() |
2816 | { |
2817 | QQuickView *window = new QQuickView(nullptr); |
2818 | |
2819 | QString warning1 = testFileUrl(fileName: "childrenRectBug2.qml" ).toString() + ":7:5: QML Item: Binding loop detected for property \"width\"" ; |
2820 | QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning1)); |
2821 | QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning1)); |
2822 | |
2823 | QString warning2 = testFileUrl(fileName: "childrenRectBug2.qml" ).toString() + ":7:5: QML Item: Binding loop detected for property \"height\"" ; |
2824 | QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning2)); |
2825 | QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning2)); |
2826 | QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning2)); |
2827 | QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning2)); |
2828 | |
2829 | window->setSource(testFileUrl(fileName: "childrenRectBug2.qml" )); |
2830 | window->show(); |
2831 | |
2832 | QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(object: window->rootObject()); |
2833 | QVERIFY(rect); |
2834 | QQuickItem *item = rect->findChild<QQuickItem*>(aName: "theItem" ); |
2835 | QCOMPARE(item->width(), qreal(100)); |
2836 | QCOMPARE(item->height(), qreal(110)); |
2837 | QCOMPARE(item->x(), qreal(130)); |
2838 | |
2839 | QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(item: rect); |
2840 | rectPrivate->setState("row" ); |
2841 | QCOMPARE(item->width(), qreal(210)); |
2842 | QCOMPARE(item->height(), qreal(50)); |
2843 | QCOMPARE(item->x(), qreal(75)); |
2844 | |
2845 | delete window; |
2846 | } |
2847 | |
2848 | // QTBUG-12722 |
2849 | void tst_QQuickItem::childrenRectBug3() |
2850 | { |
2851 | QQuickView *window = new QQuickView(nullptr); |
2852 | window->setSource(testFileUrl(fileName: "childrenRectBug3.qml" )); |
2853 | window->show(); |
2854 | |
2855 | //don't crash on delete |
2856 | delete window; |
2857 | } |
2858 | |
2859 | // QTBUG-38732 |
2860 | void tst_QQuickItem::childrenRectBottomRightCorner() |
2861 | { |
2862 | QQuickView *window = new QQuickView(nullptr); |
2863 | window->setSource(testFileUrl(fileName: "childrenRectBottomRightCorner.qml" )); |
2864 | window->show(); |
2865 | |
2866 | QQuickItem *rect = window->rootObject()->findChild<QQuickItem*>(aName: "childrenRectProxy" ); |
2867 | QCOMPARE(rect->x(), qreal(-100)); |
2868 | QCOMPARE(rect->y(), qreal(-100)); |
2869 | QCOMPARE(rect->width(), qreal(50)); |
2870 | QCOMPARE(rect->height(), qreal(50)); |
2871 | |
2872 | delete window; |
2873 | } |
2874 | |
2875 | struct TestListener : public QQuickItemChangeListener |
2876 | { |
2877 | TestListener(bool remove = false) : remove(remove) { } |
2878 | |
2879 | void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange, const QRectF &oldGeometry) override |
2880 | { |
2881 | record(item, change: QQuickItemPrivate::Geometry, value: oldGeometry); |
2882 | } |
2883 | void itemSiblingOrderChanged(QQuickItem *item) override |
2884 | { |
2885 | record(item, change: QQuickItemPrivate::SiblingOrder); |
2886 | } |
2887 | void itemVisibilityChanged(QQuickItem *item) override |
2888 | { |
2889 | record(item, change: QQuickItemPrivate::Visibility); |
2890 | } |
2891 | void itemOpacityChanged(QQuickItem *item) override |
2892 | { |
2893 | record(item, change: QQuickItemPrivate::Opacity); |
2894 | } |
2895 | void itemRotationChanged(QQuickItem *item) override |
2896 | { |
2897 | record(item, change: QQuickItemPrivate::Rotation); |
2898 | } |
2899 | void itemImplicitWidthChanged(QQuickItem *item) override |
2900 | { |
2901 | record(item, change: QQuickItemPrivate::ImplicitWidth); |
2902 | } |
2903 | void itemImplicitHeightChanged(QQuickItem *item) override |
2904 | { |
2905 | record(item, change: QQuickItemPrivate::ImplicitHeight); |
2906 | } |
2907 | void itemDestroyed(QQuickItem *item) override |
2908 | { |
2909 | record(item, change: QQuickItemPrivate::Destroyed); |
2910 | } |
2911 | void itemChildAdded(QQuickItem *item, QQuickItem *child) override |
2912 | { |
2913 | record(item, change: QQuickItemPrivate::Children, value: QVariant::fromValue(value: child)); |
2914 | } |
2915 | void itemChildRemoved(QQuickItem *item, QQuickItem *child) override |
2916 | { |
2917 | record(item, change: QQuickItemPrivate::Children, value: QVariant::fromValue(value: child)); |
2918 | } |
2919 | void itemParentChanged(QQuickItem *item, QQuickItem *parent) override |
2920 | { |
2921 | record(item, change: QQuickItemPrivate::Parent, value: QVariant::fromValue(value: parent)); |
2922 | } |
2923 | |
2924 | QQuickAnchorsPrivate *anchorPrivate() override { return nullptr; } |
2925 | |
2926 | void record(QQuickItem *item, QQuickItemPrivate::ChangeType change, const QVariant &value = QVariant()) |
2927 | { |
2928 | changes += change; |
2929 | values[change] = value; |
2930 | // QTBUG-54732 |
2931 | if (remove) |
2932 | QQuickItemPrivate::get(item)->removeItemChangeListener(this, types: change); |
2933 | } |
2934 | |
2935 | int count(QQuickItemPrivate::ChangeType change) const |
2936 | { |
2937 | return changes.count(t: change); |
2938 | } |
2939 | |
2940 | QVariant value(QQuickItemPrivate::ChangeType change) const |
2941 | { |
2942 | return values.value(key: change); |
2943 | } |
2944 | |
2945 | bool remove; |
2946 | QList<QQuickItemPrivate::ChangeType> changes; |
2947 | QHash<QQuickItemPrivate::ChangeType, QVariant> values; |
2948 | }; |
2949 | |
2950 | void tst_QQuickItem::changeListener() |
2951 | { |
2952 | QQuickWindow window; |
2953 | window.show(); |
2954 | QVERIFY(QTest::qWaitForWindowExposed(&window)); |
2955 | |
2956 | QQuickItem *item = new QQuickItem; |
2957 | TestListener itemListener; |
2958 | QQuickItemPrivate::get(item)->addItemChangeListener(listener: &itemListener, types: QQuickItemPrivate::ChangeTypes(0xffff)); |
2959 | |
2960 | item->setImplicitWidth(10); |
2961 | QCOMPARE(itemListener.count(QQuickItemPrivate::ImplicitWidth), 1); |
2962 | QCOMPARE(itemListener.count(QQuickItemPrivate::Geometry), 1); |
2963 | QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,0,0))); |
2964 | |
2965 | item->setImplicitHeight(20); |
2966 | QCOMPARE(itemListener.count(QQuickItemPrivate::ImplicitHeight), 1); |
2967 | QCOMPARE(itemListener.count(QQuickItemPrivate::Geometry), 2); |
2968 | QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,10,0))); |
2969 | |
2970 | item->setWidth(item->width() + 30); |
2971 | QCOMPARE(itemListener.count(QQuickItemPrivate::Geometry), 3); |
2972 | QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,10,20))); |
2973 | |
2974 | item->setHeight(item->height() + 40); |
2975 | QCOMPARE(itemListener.count(QQuickItemPrivate::Geometry), 4); |
2976 | QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,40,20))); |
2977 | |
2978 | item->setOpacity(0.5); |
2979 | QCOMPARE(itemListener.count(QQuickItemPrivate::Opacity), 1); |
2980 | |
2981 | item->setRotation(90); |
2982 | QCOMPARE(itemListener.count(QQuickItemPrivate::Rotation), 1); |
2983 | |
2984 | item->setParentItem(window.contentItem()); |
2985 | QCOMPARE(itemListener.count(QQuickItemPrivate::Parent), 1); |
2986 | |
2987 | item->setVisible(false); |
2988 | QCOMPARE(itemListener.count(QQuickItemPrivate::Visibility), 1); |
2989 | |
2990 | QQuickItemPrivate::get(item)->removeItemChangeListener(&itemListener, types: QQuickItemPrivate::ChangeTypes(0xffff)); |
2991 | |
2992 | QQuickItem *parent = new QQuickItem(window.contentItem()); |
2993 | TestListener parentListener; |
2994 | QQuickItemPrivate::get(item: parent)->addItemChangeListener(listener: &parentListener, types: QQuickItemPrivate::Children); |
2995 | |
2996 | QQuickItem *child1 = new QQuickItem; |
2997 | QQuickItem *child2 = new QQuickItem; |
2998 | TestListener child1Listener; |
2999 | TestListener child2Listener; |
3000 | QQuickItemPrivate::get(item: child1)->addItemChangeListener(listener: &child1Listener, types: QQuickItemPrivate::Parent | QQuickItemPrivate::SiblingOrder | QQuickItemPrivate::Destroyed); |
3001 | QQuickItemPrivate::get(item: child2)->addItemChangeListener(listener: &child2Listener, types: QQuickItemPrivate::Parent | QQuickItemPrivate::SiblingOrder | QQuickItemPrivate::Destroyed); |
3002 | |
3003 | child1->setParentItem(parent); |
3004 | QCOMPARE(parentListener.count(QQuickItemPrivate::Children), 1); |
3005 | QCOMPARE(parentListener.value(QQuickItemPrivate::Children), QVariant::fromValue(child1)); |
3006 | QCOMPARE(child1Listener.count(QQuickItemPrivate::Parent), 1); |
3007 | QCOMPARE(child1Listener.value(QQuickItemPrivate::Parent), QVariant::fromValue(parent)); |
3008 | |
3009 | child2->setParentItem(parent); |
3010 | QCOMPARE(parentListener.count(QQuickItemPrivate::Children), 2); |
3011 | QCOMPARE(parentListener.value(QQuickItemPrivate::Children), QVariant::fromValue(child2)); |
3012 | QCOMPARE(child2Listener.count(QQuickItemPrivate::Parent), 1); |
3013 | QCOMPARE(child2Listener.value(QQuickItemPrivate::Parent), QVariant::fromValue(parent)); |
3014 | |
3015 | child2->stackBefore(child1); |
3016 | QCOMPARE(child1Listener.count(QQuickItemPrivate::SiblingOrder), 1); |
3017 | QCOMPARE(child2Listener.count(QQuickItemPrivate::SiblingOrder), 1); |
3018 | |
3019 | child1->setParentItem(nullptr); |
3020 | QCOMPARE(parentListener.count(QQuickItemPrivate::Children), 3); |
3021 | QCOMPARE(parentListener.value(QQuickItemPrivate::Children), QVariant::fromValue(child1)); |
3022 | QCOMPARE(child1Listener.count(QQuickItemPrivate::Parent), 2); |
3023 | QCOMPARE(child1Listener.value(QQuickItemPrivate::Parent), QVariant::fromValue<QQuickItem *>(nullptr)); |
3024 | |
3025 | delete child1; |
3026 | QCOMPARE(child1Listener.count(QQuickItemPrivate::Destroyed), 1); |
3027 | |
3028 | delete child2; |
3029 | QCOMPARE(parentListener.count(QQuickItemPrivate::Children), 4); |
3030 | QCOMPARE(parentListener.value(QQuickItemPrivate::Children), QVariant::fromValue(child2)); |
3031 | QCOMPARE(child2Listener.count(QQuickItemPrivate::Parent), 2); |
3032 | QCOMPARE(child2Listener.value(QQuickItemPrivate::Parent), QVariant::fromValue<QQuickItem *>(nullptr)); |
3033 | QCOMPARE(child2Listener.count(QQuickItemPrivate::Destroyed), 1); |
3034 | |
3035 | QQuickItemPrivate::get(item: parent)->removeItemChangeListener(&parentListener, types: QQuickItemPrivate::Children); |
3036 | QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0); |
3037 | |
3038 | // QTBUG-54732: all listeners should get invoked even if they remove themselves while iterating the listeners |
3039 | QList<TestListener *> listeners; |
3040 | for (int i = 0; i < 5; ++i) |
3041 | listeners << new TestListener(true); |
3042 | |
3043 | // itemVisibilityChanged x 5 |
3044 | foreach (TestListener *listener, listeners) |
3045 | QQuickItemPrivate::get(item: parent)->addItemChangeListener(listener, types: QQuickItemPrivate::Visibility); |
3046 | QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count()); |
3047 | parent->setVisible(false); |
3048 | foreach (TestListener *listener, listeners) |
3049 | QCOMPARE(listener->count(QQuickItemPrivate::Visibility), 1); |
3050 | QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0); |
3051 | |
3052 | // itemRotationChanged x 5 |
3053 | foreach (TestListener *listener, listeners) |
3054 | QQuickItemPrivate::get(item: parent)->addItemChangeListener(listener, types: QQuickItemPrivate::Rotation); |
3055 | QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count()); |
3056 | parent->setRotation(90); |
3057 | foreach (TestListener *listener, listeners) |
3058 | QCOMPARE(listener->count(QQuickItemPrivate::Rotation), 1); |
3059 | QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0); |
3060 | |
3061 | // itemOpacityChanged x 5 |
3062 | foreach (TestListener *listener, listeners) |
3063 | QQuickItemPrivate::get(item: parent)->addItemChangeListener(listener, types: QQuickItemPrivate::Opacity); |
3064 | QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count()); |
3065 | parent->setOpacity(0.5); |
3066 | foreach (TestListener *listener, listeners) |
3067 | QCOMPARE(listener->count(QQuickItemPrivate::Opacity), 1); |
3068 | QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0); |
3069 | |
3070 | // itemChildAdded() x 5 |
3071 | foreach (TestListener *listener, listeners) |
3072 | QQuickItemPrivate::get(item: parent)->addItemChangeListener(listener, types: QQuickItemPrivate::Children); |
3073 | QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count()); |
3074 | child1 = new QQuickItem(parent); |
3075 | foreach (TestListener *listener, listeners) |
3076 | QCOMPARE(listener->count(QQuickItemPrivate::Children), 1); |
3077 | QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0); |
3078 | |
3079 | // itemParentChanged() x 5 |
3080 | foreach (TestListener *listener, listeners) |
3081 | QQuickItemPrivate::get(item: child1)->addItemChangeListener(listener, types: QQuickItemPrivate::Parent); |
3082 | QCOMPARE(QQuickItemPrivate::get(child1)->changeListeners.count(), listeners.count()); |
3083 | child1->setParentItem(nullptr); |
3084 | foreach (TestListener *listener, listeners) |
3085 | QCOMPARE(listener->count(QQuickItemPrivate::Parent), 1); |
3086 | QCOMPARE(QQuickItemPrivate::get(child1)->changeListeners.count(), 0); |
3087 | |
3088 | // itemImplicitWidthChanged() x 5 |
3089 | foreach (TestListener *listener, listeners) |
3090 | QQuickItemPrivate::get(item: parent)->addItemChangeListener(listener, types: QQuickItemPrivate::ImplicitWidth); |
3091 | QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count()); |
3092 | parent->setImplicitWidth(parent->implicitWidth() + 1); |
3093 | foreach (TestListener *listener, listeners) |
3094 | QCOMPARE(listener->count(QQuickItemPrivate::ImplicitWidth), 1); |
3095 | QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0); |
3096 | |
3097 | // itemImplicitHeightChanged() x 5 |
3098 | foreach (TestListener *listener, listeners) |
3099 | QQuickItemPrivate::get(item: parent)->addItemChangeListener(listener, types: QQuickItemPrivate::ImplicitHeight); |
3100 | QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count()); |
3101 | parent->setImplicitHeight(parent->implicitHeight() + 1); |
3102 | foreach (TestListener *listener, listeners) |
3103 | QCOMPARE(listener->count(QQuickItemPrivate::ImplicitHeight), 1); |
3104 | QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0); |
3105 | |
3106 | // itemGeometryChanged() x 5 |
3107 | foreach (TestListener *listener, listeners) |
3108 | QQuickItemPrivate::get(item: parent)->addItemChangeListener(listener, types: QQuickItemPrivate::Geometry); |
3109 | QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count()); |
3110 | parent->setWidth(parent->width() + 1); |
3111 | foreach (TestListener *listener, listeners) |
3112 | QCOMPARE(listener->count(QQuickItemPrivate::Geometry), 1); |
3113 | QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0); |
3114 | |
3115 | // itemChildRemoved() x 5 |
3116 | child1->setParentItem(parent); |
3117 | foreach (TestListener *listener, listeners) |
3118 | QQuickItemPrivate::get(item: parent)->addItemChangeListener(listener, types: QQuickItemPrivate::Children); |
3119 | QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count()); |
3120 | delete child1; |
3121 | foreach (TestListener *listener, listeners) |
3122 | QCOMPARE(listener->count(QQuickItemPrivate::Children), 2); |
3123 | QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0); |
3124 | |
3125 | // itemDestroyed() x 5 |
3126 | foreach (TestListener *listener, listeners) |
3127 | QQuickItemPrivate::get(item: parent)->addItemChangeListener(listener, types: QQuickItemPrivate::Destroyed); |
3128 | QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count()); |
3129 | delete parent; |
3130 | foreach (TestListener *listener, listeners) |
3131 | QCOMPARE(listener->count(QQuickItemPrivate::Destroyed), 1); |
3132 | } |
3133 | |
3134 | // QTBUG-13893 |
3135 | void tst_QQuickItem::transformCrash() |
3136 | { |
3137 | QQuickView *window = new QQuickView(nullptr); |
3138 | window->setSource(testFileUrl(fileName: "transformCrash.qml" )); |
3139 | window->show(); |
3140 | |
3141 | delete window; |
3142 | } |
3143 | |
3144 | void tst_QQuickItem::implicitSize() |
3145 | { |
3146 | QQuickView *window = new QQuickView(nullptr); |
3147 | window->setSource(testFileUrl(fileName: "implicitsize.qml" )); |
3148 | window->show(); |
3149 | |
3150 | QQuickItem *item = qobject_cast<QQuickItem*>(object: window->rootObject()); |
3151 | QVERIFY(item); |
3152 | QCOMPARE(item->width(), qreal(80)); |
3153 | QCOMPARE(item->height(), qreal(60)); |
3154 | |
3155 | QCOMPARE(item->implicitWidth(), qreal(200)); |
3156 | QCOMPARE(item->implicitHeight(), qreal(100)); |
3157 | |
3158 | QMetaObject::invokeMethod(obj: item, member: "resetSize" ); |
3159 | |
3160 | QCOMPARE(item->width(), qreal(200)); |
3161 | QCOMPARE(item->height(), qreal(100)); |
3162 | |
3163 | QMetaObject::invokeMethod(obj: item, member: "changeImplicit" ); |
3164 | |
3165 | QCOMPARE(item->implicitWidth(), qreal(150)); |
3166 | QCOMPARE(item->implicitHeight(), qreal(80)); |
3167 | QCOMPARE(item->width(), qreal(150)); |
3168 | QCOMPARE(item->height(), qreal(80)); |
3169 | |
3170 | QMetaObject::invokeMethod(obj: item, member: "assignImplicitBinding" ); |
3171 | |
3172 | QCOMPARE(item->implicitWidth(), qreal(150)); |
3173 | QCOMPARE(item->implicitHeight(), qreal(80)); |
3174 | QCOMPARE(item->width(), qreal(150)); |
3175 | QCOMPARE(item->height(), qreal(80)); |
3176 | |
3177 | QMetaObject::invokeMethod(obj: item, member: "increaseImplicit" ); |
3178 | |
3179 | QCOMPARE(item->implicitWidth(), qreal(200)); |
3180 | QCOMPARE(item->implicitHeight(), qreal(100)); |
3181 | QCOMPARE(item->width(), qreal(175)); |
3182 | QCOMPARE(item->height(), qreal(90)); |
3183 | |
3184 | QMetaObject::invokeMethod(obj: item, member: "changeImplicit" ); |
3185 | |
3186 | QCOMPARE(item->implicitWidth(), qreal(150)); |
3187 | QCOMPARE(item->implicitHeight(), qreal(80)); |
3188 | QCOMPARE(item->width(), qreal(150)); |
3189 | QCOMPARE(item->height(), qreal(80)); |
3190 | |
3191 | QMetaObject::invokeMethod(obj: item, member: "assignUndefinedBinding" ); |
3192 | |
3193 | QCOMPARE(item->implicitWidth(), qreal(150)); |
3194 | QCOMPARE(item->implicitHeight(), qreal(80)); |
3195 | QCOMPARE(item->width(), qreal(150)); |
3196 | QCOMPARE(item->height(), qreal(80)); |
3197 | |
3198 | QMetaObject::invokeMethod(obj: item, member: "increaseImplicit" ); |
3199 | |
3200 | QCOMPARE(item->implicitWidth(), qreal(200)); |
3201 | QCOMPARE(item->implicitHeight(), qreal(100)); |
3202 | QCOMPARE(item->width(), qreal(175)); |
3203 | QCOMPARE(item->height(), qreal(90)); |
3204 | |
3205 | QMetaObject::invokeMethod(obj: item, member: "changeImplicit" ); |
3206 | |
3207 | QCOMPARE(item->implicitWidth(), qreal(150)); |
3208 | QCOMPARE(item->implicitHeight(), qreal(80)); |
3209 | QCOMPARE(item->width(), qreal(150)); |
3210 | QCOMPARE(item->height(), qreal(80)); |
3211 | |
3212 | delete window; |
3213 | } |
3214 | |
3215 | void tst_QQuickItem::qtbug_16871() |
3216 | { |
3217 | QQmlComponent component(&engine, testFileUrl(fileName: "qtbug_16871.qml" )); |
3218 | QObject *o = component.create(); |
3219 | QVERIFY(o != nullptr); |
3220 | delete o; |
3221 | } |
3222 | |
3223 | |
3224 | void tst_QQuickItem::visibleChildren() |
3225 | { |
3226 | QQuickView *window = new QQuickView(nullptr); |
3227 | window->setSource(testFileUrl(fileName: "visiblechildren.qml" )); |
3228 | window->show(); |
3229 | |
3230 | QQuickItem *root = qobject_cast<QQuickItem*>(object: window->rootObject()); |
3231 | QVERIFY(root); |
3232 | |
3233 | QCOMPARE(root->property("test1_1" ).toBool(), true); |
3234 | QCOMPARE(root->property("test1_2" ).toBool(), true); |
3235 | QCOMPARE(root->property("test1_3" ).toBool(), true); |
3236 | QCOMPARE(root->property("test1_4" ).toBool(), true); |
3237 | |
3238 | QMetaObject::invokeMethod(obj: root, member: "hideFirstAndLastRowChild" ); |
3239 | QCOMPARE(root->property("test2_1" ).toBool(), true); |
3240 | QCOMPARE(root->property("test2_2" ).toBool(), true); |
3241 | QCOMPARE(root->property("test2_3" ).toBool(), true); |
3242 | QCOMPARE(root->property("test2_4" ).toBool(), true); |
3243 | |
3244 | QMetaObject::invokeMethod(obj: root, member: "showLastRowChildsLastChild" ); |
3245 | QCOMPARE(root->property("test3_1" ).toBool(), true); |
3246 | QCOMPARE(root->property("test3_2" ).toBool(), true); |
3247 | QCOMPARE(root->property("test3_3" ).toBool(), true); |
3248 | QCOMPARE(root->property("test3_4" ).toBool(), true); |
3249 | |
3250 | QMetaObject::invokeMethod(obj: root, member: "showLastRowChild" ); |
3251 | QCOMPARE(root->property("test4_1" ).toBool(), true); |
3252 | QCOMPARE(root->property("test4_2" ).toBool(), true); |
3253 | QCOMPARE(root->property("test4_3" ).toBool(), true); |
3254 | QCOMPARE(root->property("test4_4" ).toBool(), true); |
3255 | |
3256 | QString warning1 = testFileUrl(fileName: "visiblechildren.qml" ).toString() + ":87: TypeError: Cannot read property 'visibleChildren' of null" ; |
3257 | QTest::ignoreMessage(type: QtWarningMsg, qPrintable(warning1)); |
3258 | QMetaObject::invokeMethod(obj: root, member: "tryWriteToReadonlyVisibleChildren" ); |
3259 | |
3260 | QMetaObject::invokeMethod(obj: root, member: "reparentVisibleItem3" ); |
3261 | QCOMPARE(root->property("test6_1" ).toBool(), true); |
3262 | QCOMPARE(root->property("test6_2" ).toBool(), true); |
3263 | QCOMPARE(root->property("test6_3" ).toBool(), true); |
3264 | QCOMPARE(root->property("test6_4" ).toBool(), true); |
3265 | |
3266 | QMetaObject::invokeMethod(obj: root, member: "reparentImlicitlyInvisibleItem4_1" ); |
3267 | QCOMPARE(root->property("test7_1" ).toBool(), true); |
3268 | QCOMPARE(root->property("test7_2" ).toBool(), true); |
3269 | QCOMPARE(root->property("test7_3" ).toBool(), true); |
3270 | QCOMPARE(root->property("test7_4" ).toBool(), true); |
3271 | |
3272 | // FINALLY TEST THAT EVERYTHING IS AS EXPECTED |
3273 | QCOMPARE(root->property("test8_1" ).toBool(), true); |
3274 | QCOMPARE(root->property("test8_2" ).toBool(), true); |
3275 | QCOMPARE(root->property("test8_3" ).toBool(), true); |
3276 | QCOMPARE(root->property("test8_4" ).toBool(), true); |
3277 | QCOMPARE(root->property("test8_5" ).toBool(), true); |
3278 | |
3279 | delete window; |
3280 | } |
3281 | |
3282 | void tst_QQuickItem::parentLoop() |
3283 | { |
3284 | QQuickView *window = new QQuickView(nullptr); |
3285 | |
3286 | #if QT_CONFIG(regularexpression) |
3287 | QRegularExpression msgRegexp = QRegularExpression("QQuickItem::setParentItem: Parent QQuickItem\\(.*\\) is already part of the subtree of QQuickItem\\(.*\\)" ); |
3288 | QTest::ignoreMessage(type: QtWarningMsg, messagePattern: msgRegexp); |
3289 | #endif |
3290 | window->setSource(testFileUrl(fileName: "parentLoop.qml" )); |
3291 | |
3292 | QQuickItem *root = qobject_cast<QQuickItem*>(object: window->rootObject()); |
3293 | QVERIFY(root); |
3294 | |
3295 | QQuickItem *item1 = root->findChild<QQuickItem*>(aName: "item1" ); |
3296 | QVERIFY(item1); |
3297 | QCOMPARE(item1->parentItem(), root); |
3298 | |
3299 | QQuickItem *item2 = root->findChild<QQuickItem*>(aName: "item2" ); |
3300 | QVERIFY(item2); |
3301 | QCOMPARE(item2->parentItem(), item1); |
3302 | |
3303 | delete window; |
3304 | } |
3305 | |
3306 | void tst_QQuickItem::contains_data() |
3307 | { |
3308 | QTest::addColumn<bool>(name: "circleTest" ); |
3309 | QTest::addColumn<bool>(name: "insideTarget" ); |
3310 | QTest::addColumn<QList<QPoint> >(name: "points" ); |
3311 | |
3312 | QList<QPoint> points; |
3313 | |
3314 | points << QPoint(176, 176) |
3315 | << QPoint(176, 226) |
3316 | << QPoint(226, 176) |
3317 | << QPoint(226, 226) |
3318 | << QPoint(150, 200) |
3319 | << QPoint(200, 150) |
3320 | << QPoint(200, 250) |
3321 | << QPoint(250, 200); |
3322 | QTest::newRow(dataTag: "hollow square: testing points inside" ) << false << true << points; |
3323 | |
3324 | points.clear(); |
3325 | points << QPoint(162, 162) |
3326 | << QPoint(162, 242) |
3327 | << QPoint(242, 162) |
3328 | << QPoint(242, 242) |
3329 | << QPoint(200, 200) |
3330 | << QPoint(175, 200) |
3331 | << QPoint(200, 175) |
3332 | << QPoint(200, 228) |
3333 | << QPoint(228, 200) |
3334 | << QPoint(200, 122) |
3335 | << QPoint(122, 200) |
3336 | << QPoint(200, 280) |
3337 | << QPoint(280, 200); |
3338 | QTest::newRow(dataTag: "hollow square: testing points outside" ) << false << false << points; |
3339 | |
3340 | points.clear(); |
3341 | points << QPoint(174, 174) |
3342 | << QPoint(174, 225) |
3343 | << QPoint(225, 174) |
3344 | << QPoint(225, 225) |
3345 | << QPoint(165, 200) |
3346 | << QPoint(200, 165) |
3347 | << QPoint(200, 235) |
3348 | << QPoint(235, 200); |
3349 | QTest::newRow(dataTag: "hollow circle: testing points inside" ) << true << true << points; |
3350 | |
3351 | points.clear(); |
3352 | points << QPoint(160, 160) |
3353 | << QPoint(160, 240) |
3354 | << QPoint(240, 160) |
3355 | << QPoint(240, 240) |
3356 | << QPoint(200, 200) |
3357 | << QPoint(185, 185) |
3358 | << QPoint(185, 216) |
3359 | << QPoint(216, 185) |
3360 | << QPoint(216, 216) |
3361 | << QPoint(145, 200) |
3362 | << QPoint(200, 145) |
3363 | << QPoint(255, 200) |
3364 | << QPoint(200, 255); |
3365 | QTest::newRow(dataTag: "hollow circle: testing points outside" ) << true << false << points; |
3366 | } |
3367 | |
3368 | void tst_QQuickItem::contains() |
3369 | { |
3370 | QFETCH(bool, circleTest); |
3371 | QFETCH(bool, insideTarget); |
3372 | QFETCH(QList<QPoint>, points); |
3373 | |
3374 | QQuickView *window = new QQuickView(nullptr); |
3375 | window->rootContext()->setContextProperty("circleShapeTest" , circleTest); |
3376 | window->setBaseSize(QSize(400, 400)); |
3377 | window->setSource(testFileUrl(fileName: "hollowTestItem.qml" )); |
3378 | window->show(); |
3379 | window->requestActivate(); |
3380 | QVERIFY(QTest::qWaitForWindowActive(window)); |
3381 | QCOMPARE(QGuiApplication::focusWindow(), window); |
3382 | |
3383 | QQuickItem *root = qobject_cast<QQuickItem *>(object: window->rootObject()); |
3384 | QVERIFY(root); |
3385 | |
3386 | HollowTestItem *hollowItem = root->findChild<HollowTestItem *>(aName: "hollowItem" ); |
3387 | QVERIFY(hollowItem); |
3388 | |
3389 | foreach (const QPoint &point, points) { |
3390 | // check mouse hover |
3391 | QTest::mouseMove(window, pos: point); |
3392 | QTest::qWait(ms: 10); |
3393 | QCOMPARE(hollowItem->isHovered(), insideTarget); |
3394 | |
3395 | // check mouse press |
3396 | QTest::mousePress(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: point); |
3397 | QTest::qWait(ms: 10); |
3398 | QCOMPARE(hollowItem->isPressed(), insideTarget); |
3399 | |
3400 | // check mouse release |
3401 | QTest::mouseRelease(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: point); |
3402 | QTest::qWait(ms: 10); |
3403 | QCOMPARE(hollowItem->isPressed(), false); |
3404 | } |
3405 | |
3406 | delete window; |
3407 | } |
3408 | |
3409 | void tst_QQuickItem::childAt() |
3410 | { |
3411 | QQuickItem parent; |
3412 | |
3413 | QQuickItem child1; |
3414 | child1.setX(0); |
3415 | child1.setY(0); |
3416 | child1.setWidth(100); |
3417 | child1.setHeight(100); |
3418 | child1.setParentItem(&parent); |
3419 | |
3420 | QQuickItem child2; |
3421 | child2.setX(50); |
3422 | child2.setY(50); |
3423 | child2.setWidth(100); |
3424 | child2.setHeight(100); |
3425 | child2.setParentItem(&parent); |
3426 | |
3427 | QQuickItem child3; |
3428 | child3.setX(0); |
3429 | child3.setY(200); |
3430 | child3.setWidth(50); |
3431 | child3.setHeight(50); |
3432 | child3.setParentItem(&parent); |
3433 | |
3434 | QCOMPARE(parent.childAt(0, 0), &child1); |
3435 | QCOMPARE(parent.childAt(0, 99), &child1); |
3436 | QCOMPARE(parent.childAt(25, 25), &child1); |
3437 | QCOMPARE(parent.childAt(25, 75), &child1); |
3438 | QCOMPARE(parent.childAt(75, 25), &child1); |
3439 | QCOMPARE(parent.childAt(75, 75), &child2); |
3440 | QCOMPARE(parent.childAt(149, 149), &child2); |
3441 | QCOMPARE(parent.childAt(25, 200), &child3); |
3442 | QCOMPARE(parent.childAt(0, 150), static_cast<QQuickItem *>(nullptr)); |
3443 | QCOMPARE(parent.childAt(300, 300), static_cast<QQuickItem *>(nullptr)); |
3444 | } |
3445 | |
3446 | void tst_QQuickItem::grab() |
3447 | { |
3448 | if ((QGuiApplication::platformName() == QLatin1String("offscreen" )) |
3449 | || (QGuiApplication::platformName() == QLatin1String("minimal" ))) |
3450 | QSKIP("Skipping due to grabToImage not functional on offscreen/minimal platforms" ); |
3451 | |
3452 | QQuickView view; |
3453 | view.setSource(testFileUrl(fileName: "grabToImage.qml" )); |
3454 | view.show(); |
3455 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
3456 | |
3457 | QQuickItem *root = qobject_cast<QQuickItem *>(object: view.rootObject()); |
3458 | QVERIFY(root); |
3459 | QQuickItem *item = root->findChild<QQuickItem *>(aName: "myItem" ); |
3460 | QVERIFY(item); |
3461 | #if QT_CONFIG(opengl) |
3462 | { // Default size (item is 100x100) |
3463 | QSharedPointer<QQuickItemGrabResult> result = item->grabToImage(); |
3464 | QSignalSpy spy(result.data(), SIGNAL(ready())); |
3465 | QTRY_VERIFY(spy.size() > 0); |
3466 | QVERIFY(!result->url().isEmpty()); |
3467 | QImage image = result->image(); |
3468 | QCOMPARE(image.pixel(0, 0), qRgb(255, 0, 0)); |
3469 | QCOMPARE(image.pixel(99, 99), qRgb(0, 0, 255)); |
3470 | } |
3471 | |
3472 | { // Smaller size |
3473 | QSharedPointer<QQuickItemGrabResult> result = item->grabToImage(targetSize: QSize(50, 50)); |
3474 | QVERIFY(!result.isNull()); |
3475 | QSignalSpy spy(result.data(), SIGNAL(ready())); |
3476 | QTRY_VERIFY(spy.size() > 0); |
3477 | QVERIFY(!result->url().isEmpty()); |
3478 | QImage image = result->image(); |
3479 | QCOMPARE(image.pixel(0, 0), qRgb(255, 0, 0)); |
3480 | QCOMPARE(image.pixel(49, 49), qRgb(0, 0, 255)); |
3481 | } |
3482 | #endif |
3483 | } |
3484 | |
3485 | void tst_QQuickItem::isAncestorOf() |
3486 | { |
3487 | QQuickItem parent; |
3488 | |
3489 | QQuickItem sub1; |
3490 | sub1.setParentItem(&parent); |
3491 | |
3492 | QQuickItem child1; |
3493 | child1.setParentItem(&sub1); |
3494 | QQuickItem child2; |
3495 | child2.setParentItem(&sub1); |
3496 | |
3497 | QQuickItem sub2; |
3498 | sub2.setParentItem(&parent); |
3499 | |
3500 | QQuickItem child3; |
3501 | child3.setParentItem(&sub2); |
3502 | QQuickItem child4; |
3503 | child4.setParentItem(&sub2); |
3504 | |
3505 | QVERIFY(parent.isAncestorOf(&sub1)); |
3506 | QVERIFY(parent.isAncestorOf(&sub2)); |
3507 | QVERIFY(parent.isAncestorOf(&child1)); |
3508 | QVERIFY(parent.isAncestorOf(&child2)); |
3509 | QVERIFY(parent.isAncestorOf(&child3)); |
3510 | QVERIFY(parent.isAncestorOf(&child4)); |
3511 | QVERIFY(sub1.isAncestorOf(&child1)); |
3512 | QVERIFY(sub1.isAncestorOf(&child2)); |
3513 | QVERIFY(!sub1.isAncestorOf(&child3)); |
3514 | QVERIFY(!sub1.isAncestorOf(&child4)); |
3515 | QVERIFY(sub2.isAncestorOf(&child3)); |
3516 | QVERIFY(sub2.isAncestorOf(&child4)); |
3517 | QVERIFY(!sub2.isAncestorOf(&child1)); |
3518 | QVERIFY(!sub2.isAncestorOf(&child2)); |
3519 | QVERIFY(!sub1.isAncestorOf(&sub1)); |
3520 | QVERIFY(!sub2.isAncestorOf(&sub2)); |
3521 | } |
3522 | |
3523 | QTEST_MAIN(tst_QQuickItem) |
3524 | |
3525 | #include "tst_qquickitem.moc" |
3526 | |