1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the test suite of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
44 #include <QtQuick/qquickitem.h>
45 #include <QtQuick/qquickcanvas.h>
46 #include <QtQuick/qquickview.h>
47 #include <QtWidgets/QGraphicsSceneMouseEvent>
48 #include "private/qquickfocusscope_p.h"
49 #include "private/qquickitem_p.h"
52 #include "../../shared/util.h"
54 class TestItem : public QQuickItem
58 TestItem(QQuickItem *parent = 0)
59 : QQuickItem(parent), focused(false), pressCount(0), releaseCount(0)
60 , wheelCount(0), acceptIncomingTouchEvents(true)
61 , touchEventReached(false) {}
67 bool acceptIncomingTouchEvents;
68 bool touchEventReached;
70 virtual void focusInEvent(QFocusEvent *) { Q_ASSERT(!focused); focused = true; }
71 virtual void focusOutEvent(QFocusEvent *) { Q_ASSERT(focused); focused = false; }
72 virtual void mousePressEvent(QMouseEvent *event) { event->accept(); ++pressCount; }
73 virtual void mouseReleaseEvent(QMouseEvent *event) { event->accept(); ++releaseCount; }
74 virtual void touchEvent(QTouchEvent *event) {
75 touchEventReached = true;
76 event->setAccepted(acceptIncomingTouchEvents);
78 virtual void wheelEvent(QWheelEvent *event) { event->accept(); ++wheelCount; }
81 class TestCanvas: public QQuickCanvas
88 virtual bool event(QEvent *event)
90 return QQuickCanvas::event(event);
94 class TestPolishItem : public QQuickItem
98 TestPolishItem(QQuickItem *parent = 0)
99 : QQuickItem(parent), wasPolished(false) {
106 virtual void updatePolish() {
116 class TestFocusScope : public QQuickFocusScope
120 TestFocusScope(QQuickItem *parent = 0) : QQuickFocusScope(parent), focused(false) {}
124 virtual void focusInEvent(QFocusEvent *) { Q_ASSERT(!focused); focused = true; }
125 virtual void focusOutEvent(QFocusEvent *) { Q_ASSERT(focused); focused = false; }
128 class tst_qquickitem : public QQmlDataTest
139 void addedToCanvas();
141 void multipleFocusClears();
144 void setParentItem();
151 void touchEventAcceptIgnore_data();
152 void touchEventAcceptIgnore();
153 void polishOutsideAnimation();
154 void polishOnCompleted();
156 void wheelEvent_data();
158 void hoverEvent_data();
160 void hoverEventInParent();
162 void paintOrder_data();
168 NoOp, Append, Remove, StackBefore, StackAfter, SetZ
171 void ensureFocus(QWindow *w) {
173 w->requestActivateWindow();
174 qApp->processEvents();
178 void tst_qquickitem::initTestCase()
180 QQmlDataTest::initTestCase();
181 qmlRegisterType<TestPolishItem>("Qt.test", 1, 0, "TestPolishItem");
184 // Focus has no effect when outside a canvas
185 void tst_qquickitem::noCanvas()
187 QQuickItem *root = new TestItem;
188 QQuickItem *child = new TestItem(root);
189 QQuickItem *scope = new TestItem(root);
190 QQuickFocusScope *scopedChild = new TestFocusScope(scope);
191 QQuickFocusScope *scopedChild2 = new TestFocusScope(scope);
193 QCOMPARE(root->hasFocus(), false);
194 QCOMPARE(child->hasFocus(), false);
195 QCOMPARE(scope->hasFocus(), false);
196 QCOMPARE(scopedChild->hasFocus(), false);
197 QCOMPARE(scopedChild2->hasFocus(), false);
199 root->setFocus(true);
200 scope->setFocus(true);
201 scopedChild2->setFocus(true);
202 QCOMPARE(root->hasFocus(), true);
203 QCOMPARE(child->hasFocus(), false);
204 QCOMPARE(scope->hasFocus(), true);
205 QCOMPARE(scopedChild->hasFocus(), false);
206 QCOMPARE(scopedChild2->hasFocus(), true);
208 root->setFocus(false);
209 child->setFocus(true);
210 scopedChild->setFocus(true);
211 scope->setFocus(false);
212 QCOMPARE(root->hasFocus(), false);
213 QCOMPARE(child->hasFocus(), true);
214 QCOMPARE(scope->hasFocus(), false);
215 QCOMPARE(scopedChild->hasFocus(), true);
216 QCOMPARE(scopedChild2->hasFocus(), true);
222 FocusData() : focus(false), activeFocus(false) {}
224 void set(bool f, bool af) { focus = f; activeFocus = af; }
228 struct FocusState : public QHash<QQuickItem *, FocusData>
230 FocusState() : activeFocusItem(0) {}
231 FocusState &operator<<(QQuickItem *item) {
232 insert(item, FocusData());
236 void active(QQuickItem *i) {
239 QQuickItem *activeFocusItem;
244 if (focusState.activeFocusItem) { \
245 QCOMPARE(canvas.activeFocusItem(), focusState.activeFocusItem); \
246 if (qobject_cast<TestItem *>(canvas.activeFocusItem())) \
247 QCOMPARE(qobject_cast<TestItem *>(canvas.activeFocusItem())->focused, true); \
248 else if (qobject_cast<TestFocusScope *>(canvas.activeFocusItem())) \
249 QCOMPARE(qobject_cast<TestFocusScope *>(canvas.activeFocusItem())->focused, true); \
251 QCOMPARE(canvas.activeFocusItem(), canvas.rootItem()); \
253 for (QHash<QQuickItem *, FocusData>::Iterator iter = focusState.begin(); \
254 iter != focusState.end(); \
256 QCOMPARE(iter.key()->hasFocus(), iter.value().focus); \
257 QCOMPARE(iter.key()->hasActiveFocus(), iter.value().activeFocus); \
261 // Tests a simple set of top-level scoped items
262 void tst_qquickitem::simpleFocus()
265 ensureFocus(&canvas);
268 QSKIP("QTBUG-24094: fails on Mac OS X 10.7");
271 QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
273 QQuickItem *l1c1 = new TestItem(canvas.rootItem());
274 QQuickItem *l1c2 = new TestItem(canvas.rootItem());
275 QQuickItem *l1c3 = new TestItem(canvas.rootItem());
277 QQuickItem *l2c1 = new TestItem(l1c1);
278 QQuickItem *l2c2 = new TestItem(l1c1);
279 QQuickItem *l2c3 = new TestItem(l1c3);
281 FocusState focusState;
282 focusState << l1c1 << l1c2 << l1c3
283 << l2c1 << l2c2 << l2c3;
286 l1c1->setFocus(true);
287 focusState[l1c1].set(true, true);
288 focusState.active(l1c1);
291 l2c3->setFocus(true);
292 focusState[l1c1].set(false, false);
293 focusState[l2c3].set(true, true);
294 focusState.active(l2c3);
297 l1c3->setFocus(true);
298 focusState[l2c3].set(false, false);
299 focusState[l1c3].set(true, true);
300 focusState.active(l1c3);
303 l1c2->setFocus(false);
306 l1c3->setFocus(false);
307 focusState[l1c3].set(false, false);
308 focusState.active(0);
311 l2c1->setFocus(true);
312 focusState[l2c1].set(true, true);
313 focusState.active(l2c1);
317 // Items with a focus scope
318 void tst_qquickitem::scopedFocus()
321 ensureFocus(&canvas);
322 QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
324 QQuickItem *l1c1 = new TestItem(canvas.rootItem());
325 QQuickItem *l1c2 = new TestItem(canvas.rootItem());
326 QQuickItem *l1c3 = new TestItem(canvas.rootItem());
328 QQuickItem *l2c1 = new TestItem(l1c1);
329 QQuickItem *l2c2 = new TestItem(l1c1);
330 QQuickItem *l2c3 = new TestFocusScope(l1c3);
332 QQuickItem *l3c1 = new TestItem(l2c3);
333 QQuickItem *l3c2 = new TestFocusScope(l2c3);
335 QQuickItem *l4c1 = new TestItem(l3c2);
336 QQuickItem *l4c2 = new TestItem(l3c2);
338 FocusState focusState;
339 focusState << l1c1 << l1c2 << l1c3
340 << l2c1 << l2c2 << l2c3
345 l4c2->setFocus(true);
346 focusState[l4c2].set(true, false);
349 l4c1->setFocus(true);
350 focusState[l4c2].set(false, false);
351 focusState[l4c1].set(true, false);
354 l1c1->setFocus(true);
355 focusState[l1c1].set(true, true);
356 focusState.active(l1c1);
359 l3c2->setFocus(true);
360 focusState[l3c2].set(true, false);
363 l2c3->setFocus(true);
364 focusState[l1c1].set(false, false);
365 focusState[l2c3].set(true, true);
366 focusState[l3c2].set(true, true);
367 focusState[l4c1].set(true, true);
368 focusState.active(l4c1);
371 l3c2->setFocus(false);
372 focusState[l3c2].set(false, false);
373 focusState[l4c1].set(true, false);
374 focusState.active(l2c3);
377 l3c2->setFocus(true);
378 focusState[l3c2].set(true, true);
379 focusState[l4c1].set(true, true);
380 focusState.active(l4c1);
383 l4c1->setFocus(false);
384 focusState[l4c1].set(false, false);
385 focusState.active(l3c2);
388 l1c3->setFocus(true);
389 focusState[l1c3].set(true, true);
390 focusState[l2c3].set(false, false);
391 focusState[l3c2].set(true, false);
392 focusState.active(l1c3);
396 // Tests focus corrects itself when a tree is added to a canvas for the first time
397 void tst_qquickitem::addedToCanvas()
401 ensureFocus(&canvas);
402 QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
404 QQuickItem *item = new TestItem;
406 FocusState focusState;
409 item->setFocus(true);
410 focusState[item].set(true, false);
413 item->setParentItem(canvas.rootItem());
414 focusState[item].set(true, true);
415 focusState.active(item);
421 ensureFocus(&canvas);
422 QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
424 QQuickItem *item = new TestItem(canvas.rootItem());
426 QQuickItem *tree = new TestItem;
427 QQuickItem *c1 = new TestItem(tree);
428 QQuickItem *c2 = new TestItem(tree);
430 FocusState focusState;
431 focusState << item << tree << c1 << c2;
433 item->setFocus(true);
436 focusState[item].set(true, true);
437 focusState[c1].set(true, false);
438 focusState[c2].set(true, false);
439 focusState.active(item);
442 tree->setParentItem(item);
443 focusState[c1].set(false, false);
444 focusState[c2].set(false, false);
450 ensureFocus(&canvas);
451 QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
453 QQuickItem *tree = new TestItem;
454 QQuickItem *c1 = new TestItem(tree);
455 QQuickItem *c2 = new TestItem(tree);
457 FocusState focusState;
458 focusState << tree << c1 << c2;
461 focusState[c1].set(true, false);
462 focusState[c2].set(true, false);
465 tree->setParentItem(canvas.rootItem());
466 focusState[c1].set(true, true);
467 focusState[c2].set(false, false);
468 focusState.active(c1);
474 ensureFocus(&canvas);
475 QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
476 QQuickItem *tree = new TestFocusScope;
477 QQuickItem *c1 = new TestItem(tree);
478 QQuickItem *c2 = new TestItem(tree);
480 FocusState focusState;
481 focusState << tree << c1 << c2;
484 focusState[c1].set(true, false);
485 focusState[c2].set(true, false);
488 tree->setParentItem(canvas.rootItem());
489 focusState[c1].set(true, false);
490 focusState[c2].set(false, false);
493 tree->setFocus(true);
494 focusState[tree].set(true, true);
495 focusState[c1].set(true, true);
496 focusState.active(c1);
502 ensureFocus(&canvas);
503 QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
504 QQuickItem *tree = new TestFocusScope;
505 QQuickItem *c1 = new TestItem(tree);
506 QQuickItem *c2 = new TestItem(tree);
508 FocusState focusState;
509 focusState << tree << c1 << c2;
510 tree->setFocus(true);
513 focusState[tree].set(true, false);
514 focusState[c1].set(true, false);
515 focusState[c2].set(true, false);
518 tree->setParentItem(canvas.rootItem());
519 focusState[tree].set(true, true);
520 focusState[c1].set(true, true);
521 focusState[c2].set(false, false);
522 focusState.active(c1);
528 ensureFocus(&canvas);
529 QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
530 QQuickItem *child = new TestItem(canvas.rootItem());
531 QQuickItem *tree = new TestFocusScope;
532 QQuickItem *c1 = new TestItem(tree);
533 QQuickItem *c2 = new TestItem(tree);
535 FocusState focusState;
536 focusState << child << tree << c1 << c2;
537 child->setFocus(true);
538 tree->setFocus(true);
541 focusState[child].set(true, true);
542 focusState[tree].set(true, false);
543 focusState[c1].set(true, false);
544 focusState[c2].set(true, false);
545 focusState.active(child);
548 tree->setParentItem(canvas.rootItem());
549 focusState[tree].set(false, false);
550 focusState[c1].set(true, false);
551 focusState[c2].set(false, false);
554 tree->setFocus(true);
555 focusState[child].set(false, false);
556 focusState[tree].set(true, true);
557 focusState[c1].set(true, true);
558 focusState.active(c1);
563 void tst_qquickitem::changeParent()
565 // Parent to no parent
568 ensureFocus(&canvas);
569 QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
570 QQuickItem *child = new TestItem(canvas.rootItem());
572 FocusState focusState;
576 child->setFocus(true);
577 focusState[child].set(true, true);
578 focusState.active(child);
581 child->setParentItem(0);
582 focusState[child].set(true, false);
583 focusState.active(0);
587 // Different parent, same focus scope
590 ensureFocus(&canvas);
591 QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
592 QQuickItem *child = new TestItem(canvas.rootItem());
593 QQuickItem *child2 = new TestItem(canvas.rootItem());
595 FocusState focusState;
596 focusState << child << child2;
599 child->setFocus(true);
600 focusState[child].set(true, true);
601 focusState.active(child);
604 child->setParentItem(child2);
608 // Different parent, different focus scope
611 ensureFocus(&canvas);
612 QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
613 QQuickItem *child = new TestItem(canvas.rootItem());
614 QQuickItem *child2 = new TestFocusScope(canvas.rootItem());
615 QQuickItem *item = new TestItem(child);
617 FocusState focusState;
618 focusState << child << child2 << item;
621 item->setFocus(true);
622 focusState[item].set(true, true);
623 focusState.active(item);
626 item->setParentItem(child2);
627 focusState[item].set(true, false);
628 focusState.active(0);
633 ensureFocus(&canvas);
634 QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
635 QQuickItem *child = new TestItem(canvas.rootItem());
636 QQuickItem *child2 = new TestFocusScope(canvas.rootItem());
637 QQuickItem *item = new TestItem(child2);
639 FocusState focusState;
640 focusState << child << child2 << item;
643 item->setFocus(true);
644 focusState[item].set(true, false);
645 focusState.active(0);
648 item->setParentItem(child);
649 focusState[item].set(true, true);
650 focusState.active(item);
655 ensureFocus(&canvas);
656 QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
657 QQuickItem *child = new TestItem(canvas.rootItem());
658 QQuickItem *child2 = new TestFocusScope(canvas.rootItem());
659 QQuickItem *item = new TestItem(child2);
661 FocusState focusState;
662 focusState << child << child2 << item;
665 child->setFocus(true);
666 item->setFocus(true);
667 focusState[child].set(true, true);
668 focusState[item].set(true, false);
669 focusState.active(child);
672 item->setParentItem(child);
673 focusState[item].set(false, false);
679 void tst_qquickitem::multipleFocusClears()
681 //Multiple clears of focus inside a focus scope shouldn't crash. QTBUG-24714
682 QQuickView *view = new QQuickView;
683 view->setSource(testFileUrl("multipleFocusClears.qml"));
686 QTRY_VERIFY(QGuiApplication::focusWindow() == view);
689 void tst_qquickitem::constructor()
691 QQuickItem *root = new QQuickItem;
692 QVERIFY(root->parent() == 0);
693 QVERIFY(root->parentItem() == 0);
695 QQuickItem *child1 = new QQuickItem(root);
696 QVERIFY(child1->parent() == root);
697 QVERIFY(child1->parentItem() == root);
698 QCOMPARE(root->childItems().count(), 1);
699 QCOMPARE(root->childItems().at(0), child1);
701 QQuickItem *child2 = new QQuickItem(root);
702 QVERIFY(child2->parent() == root);
703 QVERIFY(child2->parentItem() == root);
704 QCOMPARE(root->childItems().count(), 2);
705 QCOMPARE(root->childItems().at(0), child1);
706 QCOMPARE(root->childItems().at(1), child2);
711 void tst_qquickitem::setParentItem()
713 QQuickItem *root = new QQuickItem;
714 QVERIFY(root->parent() == 0);
715 QVERIFY(root->parentItem() == 0);
717 QQuickItem *child1 = new QQuickItem;
718 QVERIFY(child1->parent() == 0);
719 QVERIFY(child1->parentItem() == 0);
721 child1->setParentItem(root);
722 QVERIFY(child1->parent() == 0);
723 QVERIFY(child1->parentItem() == root);
724 QCOMPARE(root->childItems().count(), 1);
725 QCOMPARE(root->childItems().at(0), child1);
727 QQuickItem *child2 = new QQuickItem;
728 QVERIFY(child2->parent() == 0);
729 QVERIFY(child2->parentItem() == 0);
730 child2->setParentItem(root);
731 QVERIFY(child2->parent() == 0);
732 QVERIFY(child2->parentItem() == root);
733 QCOMPARE(root->childItems().count(), 2);
734 QCOMPARE(root->childItems().at(0), child1);
735 QCOMPARE(root->childItems().at(1), child2);
737 child1->setParentItem(0);
738 QVERIFY(child1->parent() == 0);
739 QVERIFY(child1->parentItem() == 0);
740 QCOMPARE(root->childItems().count(), 1);
741 QCOMPARE(root->childItems().at(0), child2);
745 QVERIFY(child1->parent() == 0);
746 QVERIFY(child1->parentItem() == 0);
747 QVERIFY(child2->parent() == 0);
748 QVERIFY(child2->parentItem() == 0);
754 void tst_qquickitem::visible()
756 QQuickItem *root = new QQuickItem;
758 QQuickItem *child1 = new QQuickItem;
759 child1->setParentItem(root);
761 QQuickItem *child2 = new QQuickItem;
762 child2->setParentItem(root);
764 QVERIFY(child1->isVisible());
765 QVERIFY(child2->isVisible());
767 root->setVisible(false);
768 QVERIFY(!child1->isVisible());
769 QVERIFY(!child2->isVisible());
771 root->setVisible(true);
772 QVERIFY(child1->isVisible());
773 QVERIFY(child2->isVisible());
775 child1->setVisible(false);
776 QVERIFY(!child1->isVisible());
777 QVERIFY(child2->isVisible());
779 child2->setParentItem(child1);
780 QVERIFY(!child1->isVisible());
781 QVERIFY(!child2->isVisible());
783 child2->setParentItem(root);
784 QVERIFY(!child1->isVisible());
785 QVERIFY(child2->isVisible());
792 void tst_qquickitem::enabled()
794 QQuickItem *root = new QQuickItem;
796 QQuickItem *child1 = new QQuickItem;
797 child1->setParentItem(root);
799 QQuickItem *child2 = new QQuickItem;
800 child2->setParentItem(root);
802 QVERIFY(child1->isEnabled());
803 QVERIFY(child2->isEnabled());
805 root->setEnabled(false);
806 QVERIFY(!child1->isEnabled());
807 QVERIFY(!child2->isEnabled());
809 root->setEnabled(true);
810 QVERIFY(child1->isEnabled());
811 QVERIFY(child2->isEnabled());
813 child1->setEnabled(false);
814 QVERIFY(!child1->isEnabled());
815 QVERIFY(child2->isEnabled());
817 child2->setParentItem(child1);
818 QVERIFY(!child1->isEnabled());
819 QVERIFY(!child2->isEnabled());
821 child2->setParentItem(root);
822 QVERIFY(!child1->isEnabled());
823 QVERIFY(child2->isEnabled());
830 void tst_qquickitem::enabledFocus()
833 ensureFocus(&canvas);
835 QQuickFocusScope root;
838 root.setEnabled(false);
840 QCOMPARE(root.isEnabled(), false);
841 QCOMPARE(root.hasFocus(), true);
842 QCOMPARE(root.hasActiveFocus(), false);
844 root.setParentItem(canvas.rootItem());
846 QCOMPARE(root.isEnabled(), false);
847 QCOMPARE(root.hasFocus(), true);
848 QCOMPARE(root.hasActiveFocus(), false);
849 QCOMPARE(canvas.activeFocusItem(), canvas.rootItem());
851 root.setEnabled(true);
852 QCOMPARE(root.isEnabled(), true);
853 QCOMPARE(root.hasFocus(), true);
854 QCOMPARE(root.hasActiveFocus(), true);
855 QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&root));
858 child1.setParentItem(&root);
860 QCOMPARE(child1.isEnabled(), true);
861 QCOMPARE(child1.hasFocus(), false);
862 QCOMPARE(child1.hasActiveFocus(), false);
863 QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&root));
866 child2.setFocus(true);
867 child2.setParentItem(&root);
869 QCOMPARE(root.isEnabled(), true);
870 QCOMPARE(root.hasFocus(), true);
871 QCOMPARE(root.hasActiveFocus(), true);
872 QCOMPARE(child2.isEnabled(), true);
873 QCOMPARE(child2.hasFocus(), true);
874 QCOMPARE(child2.hasActiveFocus(), true);
875 QCOMPARE(canvas.activeFocusItem(), &child2);
877 child2.setEnabled(false);
879 QCOMPARE(root.isEnabled(), true);
880 QCOMPARE(root.hasFocus(), true);
881 QCOMPARE(root.hasActiveFocus(), true);
882 QCOMPARE(child1.isEnabled(), true);
883 QCOMPARE(child1.hasFocus(), false);
884 QCOMPARE(child1.hasActiveFocus(), false);
885 QCOMPARE(child2.isEnabled(), false);
886 QCOMPARE(child2.hasFocus(), true);
887 QCOMPARE(child2.hasActiveFocus(), false);
888 QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&root));
890 child1.setEnabled(false);
891 QCOMPARE(child1.isEnabled(), false);
892 QCOMPARE(child1.hasFocus(), false);
893 QCOMPARE(child1.hasActiveFocus(), false);
895 child1.setFocus(true);
896 QCOMPARE(child1.isEnabled(), false);
897 QCOMPARE(child1.hasFocus(), true);
898 QCOMPARE(child1.hasActiveFocus(), false);
899 QCOMPARE(child2.isEnabled(), false);
900 QCOMPARE(child2.hasFocus(), false);
901 QCOMPARE(child2.hasActiveFocus(), false);
902 QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&root));
904 child1.setEnabled(true);
905 QCOMPARE(child1.isEnabled(), true);
906 QCOMPARE(child1.hasFocus(), true);
907 QCOMPARE(child1.hasActiveFocus(), true);
908 QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&child1));
910 root.setFocus(false);
911 QCOMPARE(root.isEnabled(), true);
912 QCOMPARE(root.hasFocus(), false);
913 QCOMPARE(root.hasActiveFocus(), false);
914 QCOMPARE(child1.isEnabled(), true);
915 QCOMPARE(child1.hasFocus(), true);
916 QCOMPARE(child1.hasActiveFocus(), false);
917 QCOMPARE(canvas.activeFocusItem(), canvas.rootItem());
919 child2.forceActiveFocus();
920 QCOMPARE(root.isEnabled(), true);
921 QCOMPARE(root.hasFocus(), true);
922 QCOMPARE(root.hasActiveFocus(), true);
923 QCOMPARE(child1.isEnabled(), true);
924 QCOMPARE(child1.hasFocus(), false);
925 QCOMPARE(child1.hasActiveFocus(), false);
926 QCOMPARE(child2.isEnabled(), false);
927 QCOMPARE(child2.hasFocus(), true);
928 QCOMPARE(child2.hasActiveFocus(), false);
929 QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&root));
931 root.setEnabled(false);
932 QCOMPARE(root.isEnabled(), false);
933 QCOMPARE(root.hasFocus(), true);
934 QCOMPARE(root.hasActiveFocus(), false);
935 QCOMPARE(child1.isEnabled(), false);
936 QCOMPARE(child1.hasFocus(), false);
937 QCOMPARE(child1.hasActiveFocus(), false);
938 QCOMPARE(child2.isEnabled(), false);
939 QCOMPARE(child2.hasFocus(), true);
940 QCOMPARE(child2.hasActiveFocus(), false);
941 QCOMPARE(canvas.activeFocusItem(), canvas.rootItem());
943 child1.forceActiveFocus();
944 QCOMPARE(root.isEnabled(), false);
945 QCOMPARE(root.hasFocus(), true);
946 QCOMPARE(root.hasActiveFocus(), false);
947 QCOMPARE(child1.isEnabled(), false);
948 QCOMPARE(child1.hasFocus(), true);
949 QCOMPARE(child1.hasActiveFocus(), false);
950 QCOMPARE(child2.isEnabled(), false);
951 QCOMPARE(child2.hasFocus(), false);
952 QCOMPARE(child2.hasActiveFocus(), false);
953 QCOMPARE(canvas.activeFocusItem(), canvas.rootItem());
955 root.setEnabled(true);
956 QCOMPARE(root.isEnabled(), true);
957 QCOMPARE(root.hasFocus(), true);
958 QCOMPARE(root.hasActiveFocus(), true);
959 QCOMPARE(child1.isEnabled(), true);
960 QCOMPARE(child1.hasFocus(), true);
961 QCOMPARE(child1.hasActiveFocus(), true);
962 QCOMPARE(child2.isEnabled(), false);
963 QCOMPARE(child2.hasFocus(), false);
964 QCOMPARE(child2.hasActiveFocus(), false);
965 QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&child1));
968 void tst_qquickitem::mouseGrab()
970 QQuickCanvas *canvas = new QQuickCanvas;
971 canvas->resize(200, 200);
974 TestItem *child1 = new TestItem;
975 child1->setAcceptedMouseButtons(Qt::LeftButton);
976 child1->setSize(QSizeF(200, 100));
977 child1->setParentItem(canvas->rootItem());
979 TestItem *child2 = new TestItem;
980 child2->setAcceptedMouseButtons(Qt::LeftButton);
982 child2->setSize(QSizeF(200, 100));
983 child2->setParentItem(canvas->rootItem());
985 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
987 QVERIFY(canvas->mouseGrabberItem() == child1);
990 QCOMPARE(child1->pressCount, 1);
991 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50,50));
993 QVERIFY(canvas->mouseGrabberItem() == 0);
994 QCOMPARE(child1->releaseCount, 1);
996 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
998 QVERIFY(canvas->mouseGrabberItem() == child1);
999 QCOMPARE(child1->pressCount, 2);
1000 child1->setEnabled(false);
1001 QVERIFY(canvas->mouseGrabberItem() == 0);
1002 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50,50));
1004 QCOMPARE(child1->releaseCount, 1);
1005 child1->setEnabled(true);
1007 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
1009 QVERIFY(canvas->mouseGrabberItem() == child1);
1010 QCOMPARE(child1->pressCount, 3);
1011 child1->setVisible(false);
1012 QVERIFY(canvas->mouseGrabberItem() == 0);
1013 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50,50));
1014 QCOMPARE(child1->releaseCount, 1);
1015 child1->setVisible(true);
1017 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
1019 QVERIFY(canvas->mouseGrabberItem() == child1);
1020 QCOMPARE(child1->pressCount, 4);
1021 child2->grabMouse();
1022 QVERIFY(canvas->mouseGrabberItem() == child2);
1023 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50,50));
1025 QCOMPARE(child1->releaseCount, 1);
1026 QCOMPARE(child2->releaseCount, 1);
1028 child2->grabMouse();
1029 QVERIFY(canvas->mouseGrabberItem() == child2);
1030 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
1032 QCOMPARE(child1->pressCount, 4);
1033 QCOMPARE(child2->pressCount, 1);
1034 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50,50));
1036 QCOMPARE(child1->releaseCount, 1);
1037 QCOMPARE(child2->releaseCount, 2);
1044 void tst_qquickitem::touchEventAcceptIgnore_data()
1046 QTest::addColumn<bool>("itemSupportsTouch");
1048 QTest::newRow("with touch") << true;
1049 QTest::newRow("without touch") << false;
1052 void tst_qquickitem::touchEventAcceptIgnore()
1054 QFETCH(bool, itemSupportsTouch);
1056 TestCanvas *canvas = new TestCanvas;
1057 canvas->resize(100, 100);
1060 TestItem *item = new TestItem;
1061 item->setSize(QSizeF(100, 100));
1062 item->setParentItem(canvas->rootItem());
1063 item->acceptIncomingTouchEvents = itemSupportsTouch;
1065 static QTouchDevice* device = 0;
1067 device =new QTouchDevice;
1068 device->setType(QTouchDevice::TouchScreen);
1069 QWindowSystemInterface::registerTouchDevice(device);
1072 // Send Begin, Update & End touch sequence
1074 QTouchEvent::TouchPoint point;
1076 point.setPos(QPointF(50, 50));
1077 point.setScreenPos(point.pos());
1078 point.setState(Qt::TouchPointPressed);
1080 QTouchEvent event(QEvent::TouchBegin, device,
1082 Qt::TouchPointPressed,
1083 QList<QTouchEvent::TouchPoint>() << point);
1084 event.setAccepted(true);
1086 item->touchEventReached = false;
1088 bool accepted = canvas->event(&event);
1090 QVERIFY(item->touchEventReached);
1091 QCOMPARE(accepted && event.isAccepted(), itemSupportsTouch);
1094 QTouchEvent::TouchPoint point;
1096 point.setPos(QPointF(60, 60));
1097 point.setScreenPos(point.pos());
1098 point.setState(Qt::TouchPointMoved);
1100 QTouchEvent event(QEvent::TouchUpdate, device,
1102 Qt::TouchPointMoved,
1103 QList<QTouchEvent::TouchPoint>() << point);
1104 event.setAccepted(true);
1106 item->touchEventReached = false;
1108 bool accepted = canvas->event(&event);
1110 QCOMPARE(item->touchEventReached, itemSupportsTouch);
1111 QCOMPARE(accepted && event.isAccepted(), itemSupportsTouch);
1114 QTouchEvent::TouchPoint point;
1116 point.setPos(QPointF(60, 60));
1117 point.setScreenPos(point.pos());
1118 point.setState(Qt::TouchPointReleased);
1120 QTouchEvent event(QEvent::TouchEnd, device,
1122 Qt::TouchPointReleased,
1123 QList<QTouchEvent::TouchPoint>() << point);
1124 event.setAccepted(true);
1126 item->touchEventReached = false;
1128 bool accepted = canvas->event(&event);
1130 QCOMPARE(item->touchEventReached, itemSupportsTouch);
1131 QCOMPARE(accepted && event.isAccepted(), itemSupportsTouch);
1138 void tst_qquickitem::polishOutsideAnimation()
1140 QQuickCanvas *canvas = new QQuickCanvas;
1141 canvas->resize(200, 200);
1144 TestPolishItem *item = new TestPolishItem(canvas->rootItem());
1145 item->setSize(QSizeF(200, 100));
1148 QTimer::singleShot(10, item, SLOT(doPolish()));
1149 QTRY_VERIFY(item->wasPolished);
1155 void tst_qquickitem::polishOnCompleted()
1157 QQuickView *view = new QQuickView;
1158 view->setSource(testFileUrl("polishOnCompleted.qml"));
1161 TestPolishItem *item = qobject_cast<TestPolishItem*>(view->rootObject());
1165 QSKIP("QTBUG-21590 view does not reliably receive polish without a running animation");
1168 QTRY_VERIFY(item->wasPolished);
1173 void tst_qquickitem::wheelEvent_data()
1175 QTest::addColumn<bool>("visible");
1176 QTest::addColumn<bool>("enabled");
1178 QTest::newRow("visible and enabled") << true << true;
1179 QTest::newRow("visible and disabled") << true << false;
1180 QTest::newRow("invisible and enabled") << false << true;
1181 QTest::newRow("invisible and disabled") << false << false;
1184 void tst_qquickitem::wheelEvent()
1186 QFETCH(bool, visible);
1187 QFETCH(bool, enabled);
1189 const bool shouldReceiveWheelEvents = visible && enabled;
1191 QQuickCanvas *canvas = new QQuickCanvas;
1192 canvas->resize(200, 200);
1195 TestItem *item = new TestItem;
1196 item->setSize(QSizeF(200, 100));
1197 item->setParentItem(canvas->rootItem());
1199 item->setEnabled(enabled);
1200 item->setVisible(visible);
1202 QWheelEvent event(QPoint(100, 50), -120, Qt::NoButton, Qt::NoModifier, Qt::Vertical);
1203 event.setAccepted(false);
1204 QGuiApplication::sendEvent(canvas, &event);
1206 if (shouldReceiveWheelEvents) {
1207 QVERIFY(event.isAccepted());
1208 QCOMPARE(item->wheelCount, 1);
1210 QVERIFY(!event.isAccepted());
1211 QCOMPARE(item->wheelCount, 0);
1217 class HoverItem : public QQuickItem
1221 HoverItem(QQuickItem *parent = 0)
1222 : QQuickItem(parent), hoverEnterCount(0), hoverMoveCount(0), hoverLeaveCount(0)
1224 void resetCounters() {
1225 hoverEnterCount = 0;
1227 hoverLeaveCount = 0;
1229 int hoverEnterCount;
1231 int hoverLeaveCount;
1233 virtual void hoverEnterEvent(QHoverEvent *event) {
1237 virtual void hoverMoveEvent(QHoverEvent *event) {
1241 virtual void hoverLeaveEvent(QHoverEvent *event) {
1247 void tst_qquickitem::hoverEvent_data()
1249 QTest::addColumn<bool>("visible");
1250 QTest::addColumn<bool>("enabled");
1251 QTest::addColumn<bool>("acceptHoverEvents");
1253 QTest::newRow("visible, enabled, accept hover") << true << true << true;
1254 QTest::newRow("visible, disabled, accept hover") << true << false << true;
1255 QTest::newRow("invisible, enabled, accept hover") << false << true << true;
1256 QTest::newRow("invisible, disabled, accept hover") << false << false << true;
1258 QTest::newRow("visible, enabled, not accept hover") << true << true << false;
1259 QTest::newRow("visible, disabled, not accept hover") << true << false << false;
1260 QTest::newRow("invisible, enabled, not accept hover") << false << true << false;
1261 QTest::newRow("invisible, disabled, not accept hover") << false << false << false;
1264 // ### For some unknown reason QTest::mouseMove() isn't working correctly.
1265 static void sendMouseMove(QObject *object, const QPoint &position)
1267 QMouseEvent moveEvent(QEvent::MouseMove, position, Qt::NoButton, Qt::NoButton, 0);
1268 QGuiApplication::sendEvent(object, &moveEvent);
1271 void tst_qquickitem::hoverEvent()
1273 QFETCH(bool, visible);
1274 QFETCH(bool, enabled);
1275 QFETCH(bool, acceptHoverEvents);
1277 QQuickCanvas *canvas = new QQuickCanvas();
1278 canvas->resize(200, 200);
1281 HoverItem *item = new HoverItem;
1282 item->setSize(QSizeF(100, 100));
1283 item->setParentItem(canvas->rootItem());
1285 item->setEnabled(enabled);
1286 item->setVisible(visible);
1287 item->setAcceptHoverEvents(acceptHoverEvents);
1289 const QPoint outside(150, 150);
1290 const QPoint inside(50, 50);
1291 const QPoint anotherInside(51, 51);
1293 sendMouseMove(canvas, outside);
1294 item->resetCounters();
1296 // Enter, then move twice inside, then leave.
1297 sendMouseMove(canvas, inside);
1298 sendMouseMove(canvas, anotherInside);
1299 sendMouseMove(canvas, inside);
1300 sendMouseMove(canvas, outside);
1302 const bool shouldReceiveHoverEvents = visible && enabled && acceptHoverEvents;
1303 if (shouldReceiveHoverEvents) {
1304 QCOMPARE(item->hoverEnterCount, 1);
1305 QCOMPARE(item->hoverMoveCount, 2);
1306 QCOMPARE(item->hoverLeaveCount, 1);
1308 QCOMPARE(item->hoverEnterCount, 0);
1309 QCOMPARE(item->hoverMoveCount, 0);
1310 QCOMPARE(item->hoverLeaveCount, 0);
1316 void tst_qquickitem::hoverEventInParent()
1318 QQuickCanvas *canvas = new QQuickCanvas();
1319 canvas->resize(200, 200);
1322 HoverItem *parentItem = new HoverItem(canvas->rootItem());
1323 parentItem->setSize(QSizeF(200, 200));
1324 parentItem->setAcceptHoverEvents(true);
1326 HoverItem *leftItem = new HoverItem(parentItem);
1327 leftItem->setSize(QSizeF(100, 200));
1328 leftItem->setAcceptHoverEvents(true);
1330 HoverItem *rightItem = new HoverItem(parentItem);
1331 rightItem->setSize(QSizeF(100, 200));
1332 rightItem->setPos(QPointF(100, 0));
1333 rightItem->setAcceptHoverEvents(true);
1335 const QPoint insideLeft(50, 100);
1336 const QPoint insideRight(150, 100);
1338 sendMouseMove(canvas, insideLeft);
1339 parentItem->resetCounters();
1340 leftItem->resetCounters();
1341 rightItem->resetCounters();
1343 sendMouseMove(canvas, insideRight);
1344 QCOMPARE(parentItem->hoverEnterCount, 0);
1345 QCOMPARE(parentItem->hoverLeaveCount, 0);
1346 QCOMPARE(leftItem->hoverEnterCount, 0);
1347 QCOMPARE(leftItem->hoverLeaveCount, 1);
1348 QCOMPARE(rightItem->hoverEnterCount, 1);
1349 QCOMPARE(rightItem->hoverLeaveCount, 0);
1351 sendMouseMove(canvas, insideLeft);
1352 QCOMPARE(parentItem->hoverEnterCount, 0);
1353 QCOMPARE(parentItem->hoverLeaveCount, 0);
1354 QCOMPARE(leftItem->hoverEnterCount, 1);
1355 QCOMPARE(leftItem->hoverLeaveCount, 1);
1356 QCOMPARE(rightItem->hoverEnterCount, 1);
1357 QCOMPARE(rightItem->hoverLeaveCount, 1);
1362 void tst_qquickitem::paintOrder_data()
1364 const QUrl order1Url = testFileUrl("order.1.qml");
1365 const QUrl order2Url = testFileUrl("order.2.qml");
1367 QTest::addColumn<QUrl>("source");
1368 QTest::addColumn<int>("op");
1369 QTest::addColumn<QVariant>("param1");
1370 QTest::addColumn<QVariant>("param2");
1371 QTest::addColumn<QStringList>("expected");
1373 QTest::newRow("test 1 noop") << order1Url
1374 << int(NoOp) << QVariant() << QVariant()
1375 << (QStringList() << "1" << "2" << "3");
1376 QTest::newRow("test 1 add") << order1Url
1377 << int(Append) << QVariant("new") << QVariant()
1378 << (QStringList() << "1" << "2" << "3" << "new");
1379 QTest::newRow("test 1 remove") << order1Url
1380 << int(Remove) << QVariant(1) << QVariant()
1381 << (QStringList() << "1" << "3");
1382 QTest::newRow("test 1 stack before") << order1Url
1383 << int(StackBefore) << QVariant(2) << QVariant(1)
1384 << (QStringList() << "1" << "3" << "2");
1385 QTest::newRow("test 1 stack after") << order1Url
1386 << int(StackAfter) << QVariant(0) << QVariant(1)
1387 << (QStringList() << "2" << "1" << "3");
1388 QTest::newRow("test 1 set z") << order1Url
1389 << int(SetZ) << QVariant(1) << QVariant(qreal(1.))
1390 << (QStringList() << "1" << "3" << "2");
1392 QTest::newRow("test 2 noop") << order2Url
1393 << int(NoOp) << QVariant() << QVariant()
1394 << (QStringList() << "1" << "3" << "2");
1395 QTest::newRow("test 2 add") << order2Url
1396 << int(Append) << QVariant("new") << QVariant()
1397 << (QStringList() << "1" << "3" << "new" << "2");
1398 QTest::newRow("test 2 remove 1") << order2Url
1399 << int(Remove) << QVariant(1) << QVariant()
1400 << (QStringList() << "1" << "3");
1401 QTest::newRow("test 2 remove 2") << order2Url
1402 << int(Remove) << QVariant(2) << QVariant()
1403 << (QStringList() << "1" << "2");
1404 QTest::newRow("test 2 stack before 1") << order2Url
1405 << int(StackBefore) << QVariant(1) << QVariant(0)
1406 << (QStringList() << "1" << "3" << "2");
1407 QTest::newRow("test 2 stack before 2") << order2Url
1408 << int(StackBefore) << QVariant(2) << QVariant(0)
1409 << (QStringList() << "3" << "1" << "2");
1410 QTest::newRow("test 2 stack after 1") << order2Url
1411 << int(StackAfter) << QVariant(0) << QVariant(1)
1412 << (QStringList() << "1" << "3" << "2");
1413 QTest::newRow("test 2 stack after 2") << order2Url
1414 << int(StackAfter) << QVariant(0) << QVariant(2)
1415 << (QStringList() << "3" << "1" << "2");
1416 QTest::newRow("test 1 set z") << order1Url
1417 << int(SetZ) << QVariant(2) << QVariant(qreal(2.))
1418 << (QStringList() << "1" << "2" << "3");
1421 void tst_qquickitem::paintOrder()
1423 QFETCH(QUrl, source);
1425 QFETCH(QVariant, param1);
1426 QFETCH(QVariant, param2);
1427 QFETCH(QStringList, expected);
1430 view.setSource(source);
1432 QQuickItem *root = qobject_cast<QQuickItem*>(view.rootObject());
1437 QQuickItem *item = new QQuickItem(root);
1438 item->setObjectName(param1.toString());
1442 QQuickItem *item = root->childItems().at(param1.toInt());
1447 QQuickItem *item1 = root->childItems().at(param1.toInt());
1448 QQuickItem *item2 = root->childItems().at(param2.toInt());
1449 item1->stackBefore(item2);
1453 QQuickItem *item1 = root->childItems().at(param1.toInt());
1454 QQuickItem *item2 = root->childItems().at(param2.toInt());
1455 item1->stackAfter(item2);
1459 QQuickItem *item = root->childItems().at(param1.toInt());
1460 item->setZ(param2.toReal());
1467 QList<QQuickItem*> list = QQuickItemPrivate::get(root)->paintOrderChildItems();
1470 for (int i = 0; i < list.count(); ++i)
1471 items << list.at(i)->objectName();
1473 QCOMPARE(items, expected);
1477 QTEST_MAIN(tst_qquickitem)
1479 #include "tst_qquickitem.moc"