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
46using namespace QQuickVisualTestUtil;
47
48class tst_QQuickItem : public QQmlDataTest
49{
50 Q_OBJECT
51public:
52 tst_QQuickItem();
53
54private 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
134private:
135 QQmlEngine engine;
136 bool qt_tab_all_widgets() {
137 return QGuiApplication::styleHints()->tabFocusBehavior() == Qt::TabFocusAllControls;
138 }
139};
140
141class KeysTestObject : public QObject
142{
143 Q_OBJECT
144
145 Q_PROPERTY(bool processLast READ processLast NOTIFY processLastChanged)
146
147public:
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
166public 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
186signals:
187 void processLastChanged();
188
189public:
190 int mKey;
191 QString mText;
192 int mModifiers;
193 int mForwardedKey;
194 bool mLast;
195 quint32 mNativeScanCode;
196
197private:
198};
199
200class KeyTestItem : public QQuickItem
201{
202 Q_OBJECT
203public:
204 KeyTestItem(QQuickItem *parent=nullptr) : QQuickItem(parent), mKey(0) {}
205
206protected:
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
223public:
224 int mKey;
225};
226
227class FocusEventFilter : public QObject
228{
229protected:
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 }
238public:
239 Qt::FocusReason lastFocusReason;
240};
241
242QML_DECLARE_TYPE(KeyTestItem);
243
244class 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
250public:
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
292protected:
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
298private:
299 bool m_isPressed;
300 bool m_isHovered;
301 bool m_isCircle;
302 qreal m_holeRadius;
303};
304
305QML_DECLARE_TYPE(HollowTestItem);
306
307class TabFenceItem : public QQuickItem
308{
309 Q_OBJECT
310
311public:
312 TabFenceItem(QQuickItem *parent = nullptr)
313 : QQuickItem(parent)
314 {
315 QQuickItemPrivate *d = QQuickItemPrivate::get(item: this);
316 d->isTabFence = true;
317 }
318};
319
320QML_DECLARE_TYPE(TabFenceItem);
321
322class TabFenceItem2 : public QQuickItem
323{
324 Q_OBJECT
325
326public:
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
336QML_DECLARE_TYPE(TabFenceItem2);
337
338tst_QQuickItem::tst_QQuickItem()
339{
340}
341
342void 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
351void tst_QQuickItem::cleanup()
352{
353 QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod());
354 inputMethodPrivate->testContext = nullptr;
355}
356
357void 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
469void 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
509void 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
691void 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
723void 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
757void 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
815void 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
851void 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
900void 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
951void 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
1034void 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
1041void 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
1060void 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
1136void 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
1184void 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
1196void 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
1212void 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
1251void 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
1272void 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
1292void 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
1317void 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
1346void 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
1479Q_DECLARE_METATYPE(QEvent::Type);
1480Q_DECLARE_METATYPE(QKeySequence::StandardKey);
1481
1482void 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
1506void 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
1539void 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
1596void 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
1626void 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
1698QQuickItemPrivate *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
1705QVariant 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
1711bool 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
1718void 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
1848void 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
1865void 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
1874void 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
1881void 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
1960void 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
2015void 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
2090void 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
2218void 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
2240void 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
2300void 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
2325void 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
2341void 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
2370void 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
2399void 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
2429void 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
2515void 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
2524void 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
2586void 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
2597void 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
2613void 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
2624void 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
2639void 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
2674void 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
2756void 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
2765void 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
2794void 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
2815void 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
2849void 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
2860void 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
2875struct 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
2950void 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
3135void 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
3144void 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
3215void 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
3224void 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
3282void 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
3306void 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
3368void 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
3409void 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
3446void 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
3485void 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
3523QTEST_MAIN(tst_QQuickItem)
3524
3525#include "tst_qquickitem.moc"
3526

source code of qtdeclarative/tests/auto/quick/qquickitem2/tst_qquickitem.cpp