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 still updates 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(), false);
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(), false);
214 QCOMPARE(scope->hasFocus(), false);
215 QCOMPARE(scopedChild->hasFocus(), true);
216 QCOMPARE(scopedChild2->hasFocus(), false);
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(false, 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(false, false);
462 focusState[c2].set(true, false);
465 tree->setParentItem(canvas.rootItem());
466 focusState[c1].set(false, false);
467 focusState[c2].set(true, true);
468 focusState.active(c2);
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(false, false);
485 focusState[c2].set(true, false);
488 tree->setParentItem(canvas.rootItem());
489 focusState[c1].set(false, false);
490 focusState[c2].set(true, false);
493 tree->setFocus(true);
494 focusState[tree].set(true, true);
495 focusState[c2].set(true, true);
496 focusState.active(c2);
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(false, false);
515 focusState[c2].set(true, false);
518 tree->setParentItem(canvas.rootItem());
519 focusState[tree].set(true, true);
520 focusState[c1].set(false, false);
521 focusState[c2].set(true, true);
522 focusState.active(c2);
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(false, 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(false, false);
551 focusState[c2].set(true, false);
554 tree->setFocus(true);
555 focusState[child].set(false, false);
556 focusState[tree].set(true, true);
557 focusState[c2].set(true, true);
558 focusState.active(c2);
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);
677 // child has active focus, then its fs parent changes parent to 0, then
678 // child is deleted, then its parent changes again to a valid parent
681 ensureFocus(&canvas);
682 QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
683 QQuickItem *item = new TestFocusScope(canvas.rootItem());
684 QQuickItem *child = new TestItem(item);
685 QQuickItem *child2 = new TestItem;
687 FocusState focusState;
688 focusState << item << child;
691 item->setFocus(true);
692 child->setFocus(true);
693 focusState[child].set(true, true);
694 focusState[item].set(true, true);
695 focusState.active(child);
698 item->setParentItem(0);
699 focusState[child].set(true, false);
700 focusState[item].set(true, false);
701 focusState.active(0);
704 focusState.remove(child);
706 item->setParentItem(canvas.rootItem());
707 focusState[item].set(true, true);
708 focusState.active(item);
713 void tst_qquickitem::multipleFocusClears()
715 //Multiple clears of focus inside a focus scope shouldn't crash. QTBUG-24714
716 QQuickView *view = new QQuickView;
717 view->setSource(testFileUrl("multipleFocusClears.qml"));
720 QTRY_VERIFY(QGuiApplication::focusWindow() == view);
723 void tst_qquickitem::constructor()
725 QQuickItem *root = new QQuickItem;
726 QVERIFY(root->parent() == 0);
727 QVERIFY(root->parentItem() == 0);
729 QQuickItem *child1 = new QQuickItem(root);
730 QVERIFY(child1->parent() == root);
731 QVERIFY(child1->parentItem() == root);
732 QCOMPARE(root->childItems().count(), 1);
733 QCOMPARE(root->childItems().at(0), child1);
735 QQuickItem *child2 = new QQuickItem(root);
736 QVERIFY(child2->parent() == root);
737 QVERIFY(child2->parentItem() == root);
738 QCOMPARE(root->childItems().count(), 2);
739 QCOMPARE(root->childItems().at(0), child1);
740 QCOMPARE(root->childItems().at(1), child2);
745 void tst_qquickitem::setParentItem()
747 QQuickItem *root = new QQuickItem;
748 QVERIFY(root->parent() == 0);
749 QVERIFY(root->parentItem() == 0);
751 QQuickItem *child1 = new QQuickItem;
752 QVERIFY(child1->parent() == 0);
753 QVERIFY(child1->parentItem() == 0);
755 child1->setParentItem(root);
756 QVERIFY(child1->parent() == 0);
757 QVERIFY(child1->parentItem() == root);
758 QCOMPARE(root->childItems().count(), 1);
759 QCOMPARE(root->childItems().at(0), child1);
761 QQuickItem *child2 = new QQuickItem;
762 QVERIFY(child2->parent() == 0);
763 QVERIFY(child2->parentItem() == 0);
764 child2->setParentItem(root);
765 QVERIFY(child2->parent() == 0);
766 QVERIFY(child2->parentItem() == root);
767 QCOMPARE(root->childItems().count(), 2);
768 QCOMPARE(root->childItems().at(0), child1);
769 QCOMPARE(root->childItems().at(1), child2);
771 child1->setParentItem(0);
772 QVERIFY(child1->parent() == 0);
773 QVERIFY(child1->parentItem() == 0);
774 QCOMPARE(root->childItems().count(), 1);
775 QCOMPARE(root->childItems().at(0), child2);
779 QVERIFY(child1->parent() == 0);
780 QVERIFY(child1->parentItem() == 0);
781 QVERIFY(child2->parent() == 0);
782 QVERIFY(child2->parentItem() == 0);
788 void tst_qquickitem::visible()
790 QQuickItem *root = new QQuickItem;
792 QQuickItem *child1 = new QQuickItem;
793 child1->setParentItem(root);
795 QQuickItem *child2 = new QQuickItem;
796 child2->setParentItem(root);
798 QVERIFY(child1->isVisible());
799 QVERIFY(child2->isVisible());
801 root->setVisible(false);
802 QVERIFY(!child1->isVisible());
803 QVERIFY(!child2->isVisible());
805 root->setVisible(true);
806 QVERIFY(child1->isVisible());
807 QVERIFY(child2->isVisible());
809 child1->setVisible(false);
810 QVERIFY(!child1->isVisible());
811 QVERIFY(child2->isVisible());
813 child2->setParentItem(child1);
814 QVERIFY(!child1->isVisible());
815 QVERIFY(!child2->isVisible());
817 child2->setParentItem(root);
818 QVERIFY(!child1->isVisible());
819 QVERIFY(child2->isVisible());
826 void tst_qquickitem::enabled()
828 QQuickItem *root = new QQuickItem;
830 QQuickItem *child1 = new QQuickItem;
831 child1->setParentItem(root);
833 QQuickItem *child2 = new QQuickItem;
834 child2->setParentItem(root);
836 QVERIFY(child1->isEnabled());
837 QVERIFY(child2->isEnabled());
839 root->setEnabled(false);
840 QVERIFY(!child1->isEnabled());
841 QVERIFY(!child2->isEnabled());
843 root->setEnabled(true);
844 QVERIFY(child1->isEnabled());
845 QVERIFY(child2->isEnabled());
847 child1->setEnabled(false);
848 QVERIFY(!child1->isEnabled());
849 QVERIFY(child2->isEnabled());
851 child2->setParentItem(child1);
852 QVERIFY(!child1->isEnabled());
853 QVERIFY(!child2->isEnabled());
855 child2->setParentItem(root);
856 QVERIFY(!child1->isEnabled());
857 QVERIFY(child2->isEnabled());
864 void tst_qquickitem::enabledFocus()
867 ensureFocus(&canvas);
869 QQuickFocusScope root;
872 root.setEnabled(false);
874 QCOMPARE(root.isEnabled(), false);
875 QCOMPARE(root.hasFocus(), true);
876 QCOMPARE(root.hasActiveFocus(), false);
878 root.setParentItem(canvas.rootItem());
880 QCOMPARE(root.isEnabled(), false);
881 QCOMPARE(root.hasFocus(), true);
882 QCOMPARE(root.hasActiveFocus(), false);
883 QCOMPARE(canvas.activeFocusItem(), canvas.rootItem());
885 root.setEnabled(true);
886 QCOMPARE(root.isEnabled(), true);
887 QCOMPARE(root.hasFocus(), true);
888 QCOMPARE(root.hasActiveFocus(), true);
889 QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&root));
892 child1.setParentItem(&root);
894 QCOMPARE(child1.isEnabled(), true);
895 QCOMPARE(child1.hasFocus(), false);
896 QCOMPARE(child1.hasActiveFocus(), false);
897 QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&root));
900 child2.setFocus(true);
901 child2.setParentItem(&root);
903 QCOMPARE(root.isEnabled(), true);
904 QCOMPARE(root.hasFocus(), true);
905 QCOMPARE(root.hasActiveFocus(), true);
906 QCOMPARE(child2.isEnabled(), true);
907 QCOMPARE(child2.hasFocus(), true);
908 QCOMPARE(child2.hasActiveFocus(), true);
909 QCOMPARE(canvas.activeFocusItem(), &child2);
911 child2.setEnabled(false);
913 QCOMPARE(root.isEnabled(), true);
914 QCOMPARE(root.hasFocus(), true);
915 QCOMPARE(root.hasActiveFocus(), true);
916 QCOMPARE(child1.isEnabled(), true);
917 QCOMPARE(child1.hasFocus(), false);
918 QCOMPARE(child1.hasActiveFocus(), false);
919 QCOMPARE(child2.isEnabled(), false);
920 QCOMPARE(child2.hasFocus(), true);
921 QCOMPARE(child2.hasActiveFocus(), false);
922 QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&root));
924 child1.setEnabled(false);
925 QCOMPARE(child1.isEnabled(), false);
926 QCOMPARE(child1.hasFocus(), false);
927 QCOMPARE(child1.hasActiveFocus(), false);
929 child1.setFocus(true);
930 QCOMPARE(child1.isEnabled(), false);
931 QCOMPARE(child1.hasFocus(), true);
932 QCOMPARE(child1.hasActiveFocus(), false);
933 QCOMPARE(child2.isEnabled(), false);
934 QCOMPARE(child2.hasFocus(), false);
935 QCOMPARE(child2.hasActiveFocus(), false);
936 QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&root));
938 child1.setEnabled(true);
939 QCOMPARE(child1.isEnabled(), true);
940 QCOMPARE(child1.hasFocus(), true);
941 QCOMPARE(child1.hasActiveFocus(), true);
942 QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&child1));
944 root.setFocus(false);
945 QCOMPARE(root.isEnabled(), true);
946 QCOMPARE(root.hasFocus(), false);
947 QCOMPARE(root.hasActiveFocus(), false);
948 QCOMPARE(child1.isEnabled(), true);
949 QCOMPARE(child1.hasFocus(), true);
950 QCOMPARE(child1.hasActiveFocus(), false);
951 QCOMPARE(canvas.activeFocusItem(), canvas.rootItem());
953 child2.forceActiveFocus();
954 QCOMPARE(root.isEnabled(), true);
955 QCOMPARE(root.hasFocus(), true);
956 QCOMPARE(root.hasActiveFocus(), true);
957 QCOMPARE(child1.isEnabled(), true);
958 QCOMPARE(child1.hasFocus(), false);
959 QCOMPARE(child1.hasActiveFocus(), false);
960 QCOMPARE(child2.isEnabled(), false);
961 QCOMPARE(child2.hasFocus(), true);
962 QCOMPARE(child2.hasActiveFocus(), false);
963 QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&root));
965 root.setEnabled(false);
966 QCOMPARE(root.isEnabled(), false);
967 QCOMPARE(root.hasFocus(), true);
968 QCOMPARE(root.hasActiveFocus(), false);
969 QCOMPARE(child1.isEnabled(), false);
970 QCOMPARE(child1.hasFocus(), false);
971 QCOMPARE(child1.hasActiveFocus(), false);
972 QCOMPARE(child2.isEnabled(), false);
973 QCOMPARE(child2.hasFocus(), true);
974 QCOMPARE(child2.hasActiveFocus(), false);
975 QCOMPARE(canvas.activeFocusItem(), canvas.rootItem());
977 child1.forceActiveFocus();
978 QCOMPARE(root.isEnabled(), false);
979 QCOMPARE(root.hasFocus(), true);
980 QCOMPARE(root.hasActiveFocus(), false);
981 QCOMPARE(child1.isEnabled(), false);
982 QCOMPARE(child1.hasFocus(), true);
983 QCOMPARE(child1.hasActiveFocus(), false);
984 QCOMPARE(child2.isEnabled(), false);
985 QCOMPARE(child2.hasFocus(), false);
986 QCOMPARE(child2.hasActiveFocus(), false);
987 QCOMPARE(canvas.activeFocusItem(), canvas.rootItem());
989 root.setEnabled(true);
990 QCOMPARE(root.isEnabled(), true);
991 QCOMPARE(root.hasFocus(), true);
992 QCOMPARE(root.hasActiveFocus(), true);
993 QCOMPARE(child1.isEnabled(), true);
994 QCOMPARE(child1.hasFocus(), true);
995 QCOMPARE(child1.hasActiveFocus(), true);
996 QCOMPARE(child2.isEnabled(), false);
997 QCOMPARE(child2.hasFocus(), false);
998 QCOMPARE(child2.hasActiveFocus(), false);
999 QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&child1));
1002 void tst_qquickitem::mouseGrab()
1004 QQuickCanvas *canvas = new QQuickCanvas;
1005 canvas->resize(200, 200);
1008 TestItem *child1 = new TestItem;
1009 child1->setAcceptedMouseButtons(Qt::LeftButton);
1010 child1->setSize(QSizeF(200, 100));
1011 child1->setParentItem(canvas->rootItem());
1013 TestItem *child2 = new TestItem;
1014 child2->setAcceptedMouseButtons(Qt::LeftButton);
1016 child2->setSize(QSizeF(200, 100));
1017 child2->setParentItem(canvas->rootItem());
1019 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
1021 QVERIFY(canvas->mouseGrabberItem() == child1);
1024 QCOMPARE(child1->pressCount, 1);
1025 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50,50));
1027 QVERIFY(canvas->mouseGrabberItem() == 0);
1028 QCOMPARE(child1->releaseCount, 1);
1030 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
1032 QVERIFY(canvas->mouseGrabberItem() == child1);
1033 QCOMPARE(child1->pressCount, 2);
1034 child1->setEnabled(false);
1035 QVERIFY(canvas->mouseGrabberItem() == 0);
1036 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50,50));
1038 QCOMPARE(child1->releaseCount, 1);
1039 child1->setEnabled(true);
1041 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
1043 QVERIFY(canvas->mouseGrabberItem() == child1);
1044 QCOMPARE(child1->pressCount, 3);
1045 child1->setVisible(false);
1046 QVERIFY(canvas->mouseGrabberItem() == 0);
1047 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50,50));
1048 QCOMPARE(child1->releaseCount, 1);
1049 child1->setVisible(true);
1051 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
1053 QVERIFY(canvas->mouseGrabberItem() == child1);
1054 QCOMPARE(child1->pressCount, 4);
1055 child2->grabMouse();
1056 QVERIFY(canvas->mouseGrabberItem() == child2);
1057 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50,50));
1059 QCOMPARE(child1->releaseCount, 1);
1060 QCOMPARE(child2->releaseCount, 1);
1062 child2->grabMouse();
1063 QVERIFY(canvas->mouseGrabberItem() == child2);
1064 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
1066 QCOMPARE(child1->pressCount, 4);
1067 QCOMPARE(child2->pressCount, 1);
1068 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50,50));
1070 QCOMPARE(child1->releaseCount, 1);
1071 QCOMPARE(child2->releaseCount, 2);
1078 void tst_qquickitem::touchEventAcceptIgnore_data()
1080 QTest::addColumn<bool>("itemSupportsTouch");
1082 QTest::newRow("with touch") << true;
1083 QTest::newRow("without touch") << false;
1086 void tst_qquickitem::touchEventAcceptIgnore()
1088 QFETCH(bool, itemSupportsTouch);
1090 TestCanvas *canvas = new TestCanvas;
1091 canvas->resize(100, 100);
1094 TestItem *item = new TestItem;
1095 item->setSize(QSizeF(100, 100));
1096 item->setParentItem(canvas->rootItem());
1097 item->acceptIncomingTouchEvents = itemSupportsTouch;
1099 static QTouchDevice* device = 0;
1101 device =new QTouchDevice;
1102 device->setType(QTouchDevice::TouchScreen);
1103 QWindowSystemInterface::registerTouchDevice(device);
1106 // Send Begin, Update & End touch sequence
1108 QTouchEvent::TouchPoint point;
1110 point.setPos(QPointF(50, 50));
1111 point.setScreenPos(point.pos());
1112 point.setState(Qt::TouchPointPressed);
1114 QTouchEvent event(QEvent::TouchBegin, device,
1116 Qt::TouchPointPressed,
1117 QList<QTouchEvent::TouchPoint>() << point);
1118 event.setAccepted(true);
1120 item->touchEventReached = false;
1122 bool accepted = canvas->event(&event);
1124 QVERIFY(item->touchEventReached);
1125 QCOMPARE(accepted && event.isAccepted(), itemSupportsTouch);
1128 QTouchEvent::TouchPoint point;
1130 point.setPos(QPointF(60, 60));
1131 point.setScreenPos(point.pos());
1132 point.setState(Qt::TouchPointMoved);
1134 QTouchEvent event(QEvent::TouchUpdate, device,
1136 Qt::TouchPointMoved,
1137 QList<QTouchEvent::TouchPoint>() << point);
1138 event.setAccepted(true);
1140 item->touchEventReached = false;
1142 bool accepted = canvas->event(&event);
1144 QCOMPARE(item->touchEventReached, itemSupportsTouch);
1145 QCOMPARE(accepted && event.isAccepted(), itemSupportsTouch);
1148 QTouchEvent::TouchPoint point;
1150 point.setPos(QPointF(60, 60));
1151 point.setScreenPos(point.pos());
1152 point.setState(Qt::TouchPointReleased);
1154 QTouchEvent event(QEvent::TouchEnd, device,
1156 Qt::TouchPointReleased,
1157 QList<QTouchEvent::TouchPoint>() << point);
1158 event.setAccepted(true);
1160 item->touchEventReached = false;
1162 bool accepted = canvas->event(&event);
1164 QCOMPARE(item->touchEventReached, itemSupportsTouch);
1165 QCOMPARE(accepted && event.isAccepted(), itemSupportsTouch);
1172 void tst_qquickitem::polishOutsideAnimation()
1174 QQuickCanvas *canvas = new QQuickCanvas;
1175 canvas->resize(200, 200);
1178 TestPolishItem *item = new TestPolishItem(canvas->rootItem());
1179 item->setSize(QSizeF(200, 100));
1182 QTimer::singleShot(10, item, SLOT(doPolish()));
1183 QTRY_VERIFY(item->wasPolished);
1189 void tst_qquickitem::polishOnCompleted()
1191 QQuickView *view = new QQuickView;
1192 view->setSource(testFileUrl("polishOnCompleted.qml"));
1195 TestPolishItem *item = qobject_cast<TestPolishItem*>(view->rootObject());
1199 QSKIP("QTBUG-21590 view does not reliably receive polish without a running animation");
1202 QTRY_VERIFY(item->wasPolished);
1207 void tst_qquickitem::wheelEvent_data()
1209 QTest::addColumn<bool>("visible");
1210 QTest::addColumn<bool>("enabled");
1212 QTest::newRow("visible and enabled") << true << true;
1213 QTest::newRow("visible and disabled") << true << false;
1214 QTest::newRow("invisible and enabled") << false << true;
1215 QTest::newRow("invisible and disabled") << false << false;
1218 void tst_qquickitem::wheelEvent()
1220 QFETCH(bool, visible);
1221 QFETCH(bool, enabled);
1223 const bool shouldReceiveWheelEvents = visible && enabled;
1225 QQuickCanvas *canvas = new QQuickCanvas;
1226 canvas->resize(200, 200);
1229 TestItem *item = new TestItem;
1230 item->setSize(QSizeF(200, 100));
1231 item->setParentItem(canvas->rootItem());
1233 item->setEnabled(enabled);
1234 item->setVisible(visible);
1236 QWheelEvent event(QPoint(100, 50), -120, Qt::NoButton, Qt::NoModifier, Qt::Vertical);
1237 event.setAccepted(false);
1238 QGuiApplication::sendEvent(canvas, &event);
1240 if (shouldReceiveWheelEvents) {
1241 QVERIFY(event.isAccepted());
1242 QCOMPARE(item->wheelCount, 1);
1244 QVERIFY(!event.isAccepted());
1245 QCOMPARE(item->wheelCount, 0);
1251 class HoverItem : public QQuickItem
1255 HoverItem(QQuickItem *parent = 0)
1256 : QQuickItem(parent), hoverEnterCount(0), hoverMoveCount(0), hoverLeaveCount(0)
1258 void resetCounters() {
1259 hoverEnterCount = 0;
1261 hoverLeaveCount = 0;
1263 int hoverEnterCount;
1265 int hoverLeaveCount;
1267 virtual void hoverEnterEvent(QHoverEvent *event) {
1271 virtual void hoverMoveEvent(QHoverEvent *event) {
1275 virtual void hoverLeaveEvent(QHoverEvent *event) {
1281 void tst_qquickitem::hoverEvent_data()
1283 QTest::addColumn<bool>("visible");
1284 QTest::addColumn<bool>("enabled");
1285 QTest::addColumn<bool>("acceptHoverEvents");
1287 QTest::newRow("visible, enabled, accept hover") << true << true << true;
1288 QTest::newRow("visible, disabled, accept hover") << true << false << true;
1289 QTest::newRow("invisible, enabled, accept hover") << false << true << true;
1290 QTest::newRow("invisible, disabled, accept hover") << false << false << true;
1292 QTest::newRow("visible, enabled, not accept hover") << true << true << false;
1293 QTest::newRow("visible, disabled, not accept hover") << true << false << false;
1294 QTest::newRow("invisible, enabled, not accept hover") << false << true << false;
1295 QTest::newRow("invisible, disabled, not accept hover") << false << false << false;
1298 // ### For some unknown reason QTest::mouseMove() isn't working correctly.
1299 static void sendMouseMove(QObject *object, const QPoint &position)
1301 QMouseEvent moveEvent(QEvent::MouseMove, position, Qt::NoButton, Qt::NoButton, 0);
1302 QGuiApplication::sendEvent(object, &moveEvent);
1305 void tst_qquickitem::hoverEvent()
1307 QFETCH(bool, visible);
1308 QFETCH(bool, enabled);
1309 QFETCH(bool, acceptHoverEvents);
1311 QQuickCanvas *canvas = new QQuickCanvas();
1312 canvas->resize(200, 200);
1315 HoverItem *item = new HoverItem;
1316 item->setSize(QSizeF(100, 100));
1317 item->setParentItem(canvas->rootItem());
1319 item->setEnabled(enabled);
1320 item->setVisible(visible);
1321 item->setAcceptHoverEvents(acceptHoverEvents);
1323 const QPoint outside(150, 150);
1324 const QPoint inside(50, 50);
1325 const QPoint anotherInside(51, 51);
1327 sendMouseMove(canvas, outside);
1328 item->resetCounters();
1330 // Enter, then move twice inside, then leave.
1331 sendMouseMove(canvas, inside);
1332 sendMouseMove(canvas, anotherInside);
1333 sendMouseMove(canvas, inside);
1334 sendMouseMove(canvas, outside);
1336 const bool shouldReceiveHoverEvents = visible && enabled && acceptHoverEvents;
1337 if (shouldReceiveHoverEvents) {
1338 QCOMPARE(item->hoverEnterCount, 1);
1339 QCOMPARE(item->hoverMoveCount, 2);
1340 QCOMPARE(item->hoverLeaveCount, 1);
1342 QCOMPARE(item->hoverEnterCount, 0);
1343 QCOMPARE(item->hoverMoveCount, 0);
1344 QCOMPARE(item->hoverLeaveCount, 0);
1350 void tst_qquickitem::hoverEventInParent()
1352 QQuickCanvas *canvas = new QQuickCanvas();
1353 canvas->resize(200, 200);
1356 HoverItem *parentItem = new HoverItem(canvas->rootItem());
1357 parentItem->setSize(QSizeF(200, 200));
1358 parentItem->setAcceptHoverEvents(true);
1360 HoverItem *leftItem = new HoverItem(parentItem);
1361 leftItem->setSize(QSizeF(100, 200));
1362 leftItem->setAcceptHoverEvents(true);
1364 HoverItem *rightItem = new HoverItem(parentItem);
1365 rightItem->setSize(QSizeF(100, 200));
1366 rightItem->setPos(QPointF(100, 0));
1367 rightItem->setAcceptHoverEvents(true);
1369 const QPoint insideLeft(50, 100);
1370 const QPoint insideRight(150, 100);
1372 sendMouseMove(canvas, insideLeft);
1373 parentItem->resetCounters();
1374 leftItem->resetCounters();
1375 rightItem->resetCounters();
1377 sendMouseMove(canvas, insideRight);
1378 QCOMPARE(parentItem->hoverEnterCount, 0);
1379 QCOMPARE(parentItem->hoverLeaveCount, 0);
1380 QCOMPARE(leftItem->hoverEnterCount, 0);
1381 QCOMPARE(leftItem->hoverLeaveCount, 1);
1382 QCOMPARE(rightItem->hoverEnterCount, 1);
1383 QCOMPARE(rightItem->hoverLeaveCount, 0);
1385 sendMouseMove(canvas, insideLeft);
1386 QCOMPARE(parentItem->hoverEnterCount, 0);
1387 QCOMPARE(parentItem->hoverLeaveCount, 0);
1388 QCOMPARE(leftItem->hoverEnterCount, 1);
1389 QCOMPARE(leftItem->hoverLeaveCount, 1);
1390 QCOMPARE(rightItem->hoverEnterCount, 1);
1391 QCOMPARE(rightItem->hoverLeaveCount, 1);
1396 void tst_qquickitem::paintOrder_data()
1398 const QUrl order1Url = testFileUrl("order.1.qml");
1399 const QUrl order2Url = testFileUrl("order.2.qml");
1401 QTest::addColumn<QUrl>("source");
1402 QTest::addColumn<int>("op");
1403 QTest::addColumn<QVariant>("param1");
1404 QTest::addColumn<QVariant>("param2");
1405 QTest::addColumn<QStringList>("expected");
1407 QTest::newRow("test 1 noop") << order1Url
1408 << int(NoOp) << QVariant() << QVariant()
1409 << (QStringList() << "1" << "2" << "3");
1410 QTest::newRow("test 1 add") << order1Url
1411 << int(Append) << QVariant("new") << QVariant()
1412 << (QStringList() << "1" << "2" << "3" << "new");
1413 QTest::newRow("test 1 remove") << order1Url
1414 << int(Remove) << QVariant(1) << QVariant()
1415 << (QStringList() << "1" << "3");
1416 QTest::newRow("test 1 stack before") << order1Url
1417 << int(StackBefore) << QVariant(2) << QVariant(1)
1418 << (QStringList() << "1" << "3" << "2");
1419 QTest::newRow("test 1 stack after") << order1Url
1420 << int(StackAfter) << QVariant(0) << QVariant(1)
1421 << (QStringList() << "2" << "1" << "3");
1422 QTest::newRow("test 1 set z") << order1Url
1423 << int(SetZ) << QVariant(1) << QVariant(qreal(1.))
1424 << (QStringList() << "1" << "3" << "2");
1426 QTest::newRow("test 2 noop") << order2Url
1427 << int(NoOp) << QVariant() << QVariant()
1428 << (QStringList() << "1" << "3" << "2");
1429 QTest::newRow("test 2 add") << order2Url
1430 << int(Append) << QVariant("new") << QVariant()
1431 << (QStringList() << "1" << "3" << "new" << "2");
1432 QTest::newRow("test 2 remove 1") << order2Url
1433 << int(Remove) << QVariant(1) << QVariant()
1434 << (QStringList() << "1" << "3");
1435 QTest::newRow("test 2 remove 2") << order2Url
1436 << int(Remove) << QVariant(2) << QVariant()
1437 << (QStringList() << "1" << "2");
1438 QTest::newRow("test 2 stack before 1") << order2Url
1439 << int(StackBefore) << QVariant(1) << QVariant(0)
1440 << (QStringList() << "1" << "3" << "2");
1441 QTest::newRow("test 2 stack before 2") << order2Url
1442 << int(StackBefore) << QVariant(2) << QVariant(0)
1443 << (QStringList() << "3" << "1" << "2");
1444 QTest::newRow("test 2 stack after 1") << order2Url
1445 << int(StackAfter) << QVariant(0) << QVariant(1)
1446 << (QStringList() << "1" << "3" << "2");
1447 QTest::newRow("test 2 stack after 2") << order2Url
1448 << int(StackAfter) << QVariant(0) << QVariant(2)
1449 << (QStringList() << "3" << "1" << "2");
1450 QTest::newRow("test 1 set z") << order1Url
1451 << int(SetZ) << QVariant(2) << QVariant(qreal(2.))
1452 << (QStringList() << "1" << "2" << "3");
1455 void tst_qquickitem::paintOrder()
1457 QFETCH(QUrl, source);
1459 QFETCH(QVariant, param1);
1460 QFETCH(QVariant, param2);
1461 QFETCH(QStringList, expected);
1464 view.setSource(source);
1466 QQuickItem *root = qobject_cast<QQuickItem*>(view.rootObject());
1471 QQuickItem *item = new QQuickItem(root);
1472 item->setObjectName(param1.toString());
1476 QQuickItem *item = root->childItems().at(param1.toInt());
1481 QQuickItem *item1 = root->childItems().at(param1.toInt());
1482 QQuickItem *item2 = root->childItems().at(param2.toInt());
1483 item1->stackBefore(item2);
1487 QQuickItem *item1 = root->childItems().at(param1.toInt());
1488 QQuickItem *item2 = root->childItems().at(param2.toInt());
1489 item1->stackAfter(item2);
1493 QQuickItem *item = root->childItems().at(param1.toInt());
1494 item->setZ(param2.toReal());
1501 QList<QQuickItem*> list = QQuickItemPrivate::get(root)->paintOrderChildItems();
1504 for (int i = 0; i < list.count(); ++i)
1505 items << list.at(i)->objectName();
1507 QCOMPARE(items, expected);
1511 QTEST_MAIN(tst_qquickitem)
1513 #include "tst_qquickitem.moc"