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();
143 void setParentItem();
150 void touchEventAcceptIgnore_data();
151 void touchEventAcceptIgnore();
152 void polishOutsideAnimation();
153 void polishOnCompleted();
155 void wheelEvent_data();
157 void hoverEvent_data();
159 void hoverEventInParent();
161 void paintOrder_data();
167 NoOp, Append, Remove, StackBefore, StackAfter, SetZ
170 void ensureFocus(QWindow *w) {
172 w->requestActivateWindow();
173 qApp->processEvents();
177 void tst_qquickitem::initTestCase()
179 QQmlDataTest::initTestCase();
180 qmlRegisterType<TestPolishItem>("Qt.test", 1, 0, "TestPolishItem");
183 // Focus has no effect when outside a canvas
184 void tst_qquickitem::noCanvas()
186 QQuickItem *root = new TestItem;
187 QQuickItem *child = new TestItem(root);
188 QQuickItem *scope = new TestItem(root);
189 QQuickFocusScope *scopedChild = new TestFocusScope(scope);
190 QQuickFocusScope *scopedChild2 = new TestFocusScope(scope);
192 QCOMPARE(root->hasFocus(), false);
193 QCOMPARE(child->hasFocus(), false);
194 QCOMPARE(scope->hasFocus(), false);
195 QCOMPARE(scopedChild->hasFocus(), false);
196 QCOMPARE(scopedChild2->hasFocus(), false);
198 root->setFocus(true);
199 scope->setFocus(true);
200 scopedChild2->setFocus(true);
201 QCOMPARE(root->hasFocus(), true);
202 QCOMPARE(child->hasFocus(), false);
203 QCOMPARE(scope->hasFocus(), true);
204 QCOMPARE(scopedChild->hasFocus(), false);
205 QCOMPARE(scopedChild2->hasFocus(), true);
207 root->setFocus(false);
208 child->setFocus(true);
209 scopedChild->setFocus(true);
210 scope->setFocus(false);
211 QCOMPARE(root->hasFocus(), false);
212 QCOMPARE(child->hasFocus(), true);
213 QCOMPARE(scope->hasFocus(), false);
214 QCOMPARE(scopedChild->hasFocus(), true);
215 QCOMPARE(scopedChild2->hasFocus(), true);
221 FocusData() : focus(false), activeFocus(false) {}
223 void set(bool f, bool af) { focus = f; activeFocus = af; }
227 struct FocusState : public QHash<QQuickItem *, FocusData>
229 FocusState() : activeFocusItem(0) {}
230 FocusState &operator<<(QQuickItem *item) {
231 insert(item, FocusData());
235 void active(QQuickItem *i) {
238 QQuickItem *activeFocusItem;
243 if (focusState.activeFocusItem) { \
244 QCOMPARE(canvas.activeFocusItem(), focusState.activeFocusItem); \
245 if (qobject_cast<TestItem *>(canvas.activeFocusItem())) \
246 QCOMPARE(qobject_cast<TestItem *>(canvas.activeFocusItem())->focused, true); \
247 else if (qobject_cast<TestFocusScope *>(canvas.activeFocusItem())) \
248 QCOMPARE(qobject_cast<TestFocusScope *>(canvas.activeFocusItem())->focused, true); \
250 QCOMPARE(canvas.activeFocusItem(), canvas.rootItem()); \
252 for (QHash<QQuickItem *, FocusData>::Iterator iter = focusState.begin(); \
253 iter != focusState.end(); \
255 QCOMPARE(iter.key()->hasFocus(), iter.value().focus); \
256 QCOMPARE(iter.key()->hasActiveFocus(), iter.value().activeFocus); \
260 // Tests a simple set of top-level scoped items
261 void tst_qquickitem::simpleFocus()
264 ensureFocus(&canvas);
267 QSKIP("QTBUG-24094: fails on Mac OS X 10.7");
270 QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
272 QQuickItem *l1c1 = new TestItem(canvas.rootItem());
273 QQuickItem *l1c2 = new TestItem(canvas.rootItem());
274 QQuickItem *l1c3 = new TestItem(canvas.rootItem());
276 QQuickItem *l2c1 = new TestItem(l1c1);
277 QQuickItem *l2c2 = new TestItem(l1c1);
278 QQuickItem *l2c3 = new TestItem(l1c3);
280 FocusState focusState;
281 focusState << l1c1 << l1c2 << l1c3
282 << l2c1 << l2c2 << l2c3;
285 l1c1->setFocus(true);
286 focusState[l1c1].set(true, true);
287 focusState.active(l1c1);
290 l2c3->setFocus(true);
291 focusState[l1c1].set(false, false);
292 focusState[l2c3].set(true, true);
293 focusState.active(l2c3);
296 l1c3->setFocus(true);
297 focusState[l2c3].set(false, false);
298 focusState[l1c3].set(true, true);
299 focusState.active(l1c3);
302 l1c2->setFocus(false);
305 l1c3->setFocus(false);
306 focusState[l1c3].set(false, false);
307 focusState.active(0);
310 l2c1->setFocus(true);
311 focusState[l2c1].set(true, true);
312 focusState.active(l2c1);
316 // Items with a focus scope
317 void tst_qquickitem::scopedFocus()
320 ensureFocus(&canvas);
321 QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
323 QQuickItem *l1c1 = new TestItem(canvas.rootItem());
324 QQuickItem *l1c2 = new TestItem(canvas.rootItem());
325 QQuickItem *l1c3 = new TestItem(canvas.rootItem());
327 QQuickItem *l2c1 = new TestItem(l1c1);
328 QQuickItem *l2c2 = new TestItem(l1c1);
329 QQuickItem *l2c3 = new TestFocusScope(l1c3);
331 QQuickItem *l3c1 = new TestItem(l2c3);
332 QQuickItem *l3c2 = new TestFocusScope(l2c3);
334 QQuickItem *l4c1 = new TestItem(l3c2);
335 QQuickItem *l4c2 = new TestItem(l3c2);
337 FocusState focusState;
338 focusState << l1c1 << l1c2 << l1c3
339 << l2c1 << l2c2 << l2c3
344 l4c2->setFocus(true);
345 focusState[l4c2].set(true, false);
348 l4c1->setFocus(true);
349 focusState[l4c2].set(false, false);
350 focusState[l4c1].set(true, false);
353 l1c1->setFocus(true);
354 focusState[l1c1].set(true, true);
355 focusState.active(l1c1);
358 l3c2->setFocus(true);
359 focusState[l3c2].set(true, false);
362 l2c3->setFocus(true);
363 focusState[l1c1].set(false, false);
364 focusState[l2c3].set(true, true);
365 focusState[l3c2].set(true, true);
366 focusState[l4c1].set(true, true);
367 focusState.active(l4c1);
370 l3c2->setFocus(false);
371 focusState[l3c2].set(false, false);
372 focusState[l4c1].set(true, false);
373 focusState.active(l2c3);
376 l3c2->setFocus(true);
377 focusState[l3c2].set(true, true);
378 focusState[l4c1].set(true, true);
379 focusState.active(l4c1);
382 l4c1->setFocus(false);
383 focusState[l4c1].set(false, false);
384 focusState.active(l3c2);
387 l1c3->setFocus(true);
388 focusState[l1c3].set(true, true);
389 focusState[l2c3].set(false, false);
390 focusState[l3c2].set(true, false);
391 focusState.active(l1c3);
395 // Tests focus corrects itself when a tree is added to a canvas for the first time
396 void tst_qquickitem::addedToCanvas()
400 ensureFocus(&canvas);
401 QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
403 QQuickItem *item = new TestItem;
405 FocusState focusState;
408 item->setFocus(true);
409 focusState[item].set(true, false);
412 item->setParentItem(canvas.rootItem());
413 focusState[item].set(true, true);
414 focusState.active(item);
420 ensureFocus(&canvas);
421 QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
423 QQuickItem *item = new TestItem(canvas.rootItem());
425 QQuickItem *tree = new TestItem;
426 QQuickItem *c1 = new TestItem(tree);
427 QQuickItem *c2 = new TestItem(tree);
429 FocusState focusState;
430 focusState << item << tree << c1 << c2;
432 item->setFocus(true);
435 focusState[item].set(true, true);
436 focusState[c1].set(true, false);
437 focusState[c2].set(true, false);
438 focusState.active(item);
441 tree->setParentItem(item);
442 focusState[c1].set(false, false);
443 focusState[c2].set(false, false);
449 ensureFocus(&canvas);
450 QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
452 QQuickItem *tree = new TestItem;
453 QQuickItem *c1 = new TestItem(tree);
454 QQuickItem *c2 = new TestItem(tree);
456 FocusState focusState;
457 focusState << tree << c1 << c2;
460 focusState[c1].set(true, false);
461 focusState[c2].set(true, false);
464 tree->setParentItem(canvas.rootItem());
465 focusState[c1].set(true, true);
466 focusState[c2].set(false, false);
467 focusState.active(c1);
473 ensureFocus(&canvas);
474 QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
475 QQuickItem *tree = new TestFocusScope;
476 QQuickItem *c1 = new TestItem(tree);
477 QQuickItem *c2 = new TestItem(tree);
479 FocusState focusState;
480 focusState << tree << c1 << c2;
483 focusState[c1].set(true, false);
484 focusState[c2].set(true, false);
487 tree->setParentItem(canvas.rootItem());
488 focusState[c1].set(true, false);
489 focusState[c2].set(false, false);
492 tree->setFocus(true);
493 focusState[tree].set(true, true);
494 focusState[c1].set(true, true);
495 focusState.active(c1);
501 ensureFocus(&canvas);
502 QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
503 QQuickItem *tree = new TestFocusScope;
504 QQuickItem *c1 = new TestItem(tree);
505 QQuickItem *c2 = new TestItem(tree);
507 FocusState focusState;
508 focusState << tree << c1 << c2;
509 tree->setFocus(true);
512 focusState[tree].set(true, false);
513 focusState[c1].set(true, false);
514 focusState[c2].set(true, false);
517 tree->setParentItem(canvas.rootItem());
518 focusState[tree].set(true, true);
519 focusState[c1].set(true, true);
520 focusState[c2].set(false, false);
521 focusState.active(c1);
527 ensureFocus(&canvas);
528 QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
529 QQuickItem *child = new TestItem(canvas.rootItem());
530 QQuickItem *tree = new TestFocusScope;
531 QQuickItem *c1 = new TestItem(tree);
532 QQuickItem *c2 = new TestItem(tree);
534 FocusState focusState;
535 focusState << child << tree << c1 << c2;
536 child->setFocus(true);
537 tree->setFocus(true);
540 focusState[child].set(true, true);
541 focusState[tree].set(true, false);
542 focusState[c1].set(true, false);
543 focusState[c2].set(true, false);
544 focusState.active(child);
547 tree->setParentItem(canvas.rootItem());
548 focusState[tree].set(false, false);
549 focusState[c1].set(true, false);
550 focusState[c2].set(false, false);
553 tree->setFocus(true);
554 focusState[child].set(false, false);
555 focusState[tree].set(true, true);
556 focusState[c1].set(true, true);
557 focusState.active(c1);
562 void tst_qquickitem::changeParent()
564 // Parent to no parent
567 ensureFocus(&canvas);
568 QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
569 QQuickItem *child = new TestItem(canvas.rootItem());
571 FocusState focusState;
575 child->setFocus(true);
576 focusState[child].set(true, true);
577 focusState.active(child);
580 child->setParentItem(0);
581 focusState[child].set(true, false);
582 focusState.active(0);
586 // Different parent, same focus scope
589 ensureFocus(&canvas);
590 QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
591 QQuickItem *child = new TestItem(canvas.rootItem());
592 QQuickItem *child2 = new TestItem(canvas.rootItem());
594 FocusState focusState;
595 focusState << child << child2;
598 child->setFocus(true);
599 focusState[child].set(true, true);
600 focusState.active(child);
603 child->setParentItem(child2);
607 // Different parent, different focus scope
610 ensureFocus(&canvas);
611 QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
612 QQuickItem *child = new TestItem(canvas.rootItem());
613 QQuickItem *child2 = new TestFocusScope(canvas.rootItem());
614 QQuickItem *item = new TestItem(child);
616 FocusState focusState;
617 focusState << child << child2 << item;
620 item->setFocus(true);
621 focusState[item].set(true, true);
622 focusState.active(item);
625 item->setParentItem(child2);
626 focusState[item].set(true, false);
627 focusState.active(0);
632 ensureFocus(&canvas);
633 QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
634 QQuickItem *child = new TestItem(canvas.rootItem());
635 QQuickItem *child2 = new TestFocusScope(canvas.rootItem());
636 QQuickItem *item = new TestItem(child2);
638 FocusState focusState;
639 focusState << child << child2 << item;
642 item->setFocus(true);
643 focusState[item].set(true, false);
644 focusState.active(0);
647 item->setParentItem(child);
648 focusState[item].set(true, true);
649 focusState.active(item);
654 ensureFocus(&canvas);
655 QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
656 QQuickItem *child = new TestItem(canvas.rootItem());
657 QQuickItem *child2 = new TestFocusScope(canvas.rootItem());
658 QQuickItem *item = new TestItem(child2);
660 FocusState focusState;
661 focusState << child << child2 << item;
664 child->setFocus(true);
665 item->setFocus(true);
666 focusState[child].set(true, true);
667 focusState[item].set(true, false);
668 focusState.active(child);
671 item->setParentItem(child);
672 focusState[item].set(false, false);
678 void tst_qquickitem::constructor()
680 QQuickItem *root = new QQuickItem;
681 QVERIFY(root->parent() == 0);
682 QVERIFY(root->parentItem() == 0);
684 QQuickItem *child1 = new QQuickItem(root);
685 QVERIFY(child1->parent() == root);
686 QVERIFY(child1->parentItem() == root);
687 QCOMPARE(root->childItems().count(), 1);
688 QCOMPARE(root->childItems().at(0), child1);
690 QQuickItem *child2 = new QQuickItem(root);
691 QVERIFY(child2->parent() == root);
692 QVERIFY(child2->parentItem() == root);
693 QCOMPARE(root->childItems().count(), 2);
694 QCOMPARE(root->childItems().at(0), child1);
695 QCOMPARE(root->childItems().at(1), child2);
700 void tst_qquickitem::setParentItem()
702 QQuickItem *root = new QQuickItem;
703 QVERIFY(root->parent() == 0);
704 QVERIFY(root->parentItem() == 0);
706 QQuickItem *child1 = new QQuickItem;
707 QVERIFY(child1->parent() == 0);
708 QVERIFY(child1->parentItem() == 0);
710 child1->setParentItem(root);
711 QVERIFY(child1->parent() == 0);
712 QVERIFY(child1->parentItem() == root);
713 QCOMPARE(root->childItems().count(), 1);
714 QCOMPARE(root->childItems().at(0), child1);
716 QQuickItem *child2 = new QQuickItem;
717 QVERIFY(child2->parent() == 0);
718 QVERIFY(child2->parentItem() == 0);
719 child2->setParentItem(root);
720 QVERIFY(child2->parent() == 0);
721 QVERIFY(child2->parentItem() == root);
722 QCOMPARE(root->childItems().count(), 2);
723 QCOMPARE(root->childItems().at(0), child1);
724 QCOMPARE(root->childItems().at(1), child2);
726 child1->setParentItem(0);
727 QVERIFY(child1->parent() == 0);
728 QVERIFY(child1->parentItem() == 0);
729 QCOMPARE(root->childItems().count(), 1);
730 QCOMPARE(root->childItems().at(0), child2);
734 QVERIFY(child1->parent() == 0);
735 QVERIFY(child1->parentItem() == 0);
736 QVERIFY(child2->parent() == 0);
737 QVERIFY(child2->parentItem() == 0);
743 void tst_qquickitem::visible()
745 QQuickItem *root = new QQuickItem;
747 QQuickItem *child1 = new QQuickItem;
748 child1->setParentItem(root);
750 QQuickItem *child2 = new QQuickItem;
751 child2->setParentItem(root);
753 QVERIFY(child1->isVisible());
754 QVERIFY(child2->isVisible());
756 root->setVisible(false);
757 QVERIFY(!child1->isVisible());
758 QVERIFY(!child2->isVisible());
760 root->setVisible(true);
761 QVERIFY(child1->isVisible());
762 QVERIFY(child2->isVisible());
764 child1->setVisible(false);
765 QVERIFY(!child1->isVisible());
766 QVERIFY(child2->isVisible());
768 child2->setParentItem(child1);
769 QVERIFY(!child1->isVisible());
770 QVERIFY(!child2->isVisible());
772 child2->setParentItem(root);
773 QVERIFY(!child1->isVisible());
774 QVERIFY(child2->isVisible());
781 void tst_qquickitem::enabled()
783 QQuickItem *root = new QQuickItem;
785 QQuickItem *child1 = new QQuickItem;
786 child1->setParentItem(root);
788 QQuickItem *child2 = new QQuickItem;
789 child2->setParentItem(root);
791 QVERIFY(child1->isEnabled());
792 QVERIFY(child2->isEnabled());
794 root->setEnabled(false);
795 QVERIFY(!child1->isEnabled());
796 QVERIFY(!child2->isEnabled());
798 root->setEnabled(true);
799 QVERIFY(child1->isEnabled());
800 QVERIFY(child2->isEnabled());
802 child1->setEnabled(false);
803 QVERIFY(!child1->isEnabled());
804 QVERIFY(child2->isEnabled());
806 child2->setParentItem(child1);
807 QVERIFY(!child1->isEnabled());
808 QVERIFY(!child2->isEnabled());
810 child2->setParentItem(root);
811 QVERIFY(!child1->isEnabled());
812 QVERIFY(child2->isEnabled());
819 void tst_qquickitem::enabledFocus()
822 ensureFocus(&canvas);
824 QQuickFocusScope root;
827 root.setEnabled(false);
829 QCOMPARE(root.isEnabled(), false);
830 QCOMPARE(root.hasFocus(), true);
831 QCOMPARE(root.hasActiveFocus(), false);
833 root.setParentItem(canvas.rootItem());
835 QCOMPARE(root.isEnabled(), false);
836 QCOMPARE(root.hasFocus(), true);
837 QCOMPARE(root.hasActiveFocus(), false);
838 QCOMPARE(canvas.activeFocusItem(), canvas.rootItem());
840 root.setEnabled(true);
841 QCOMPARE(root.isEnabled(), true);
842 QCOMPARE(root.hasFocus(), true);
843 QCOMPARE(root.hasActiveFocus(), true);
844 QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&root));
847 child1.setParentItem(&root);
849 QCOMPARE(child1.isEnabled(), true);
850 QCOMPARE(child1.hasFocus(), false);
851 QCOMPARE(child1.hasActiveFocus(), false);
852 QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&root));
855 child2.setFocus(true);
856 child2.setParentItem(&root);
858 QCOMPARE(root.isEnabled(), true);
859 QCOMPARE(root.hasFocus(), true);
860 QCOMPARE(root.hasActiveFocus(), true);
861 QCOMPARE(child2.isEnabled(), true);
862 QCOMPARE(child2.hasFocus(), true);
863 QCOMPARE(child2.hasActiveFocus(), true);
864 QCOMPARE(canvas.activeFocusItem(), &child2);
866 child2.setEnabled(false);
868 QCOMPARE(root.isEnabled(), true);
869 QCOMPARE(root.hasFocus(), true);
870 QCOMPARE(root.hasActiveFocus(), true);
871 QCOMPARE(child1.isEnabled(), true);
872 QCOMPARE(child1.hasFocus(), false);
873 QCOMPARE(child1.hasActiveFocus(), false);
874 QCOMPARE(child2.isEnabled(), false);
875 QCOMPARE(child2.hasFocus(), true);
876 QCOMPARE(child2.hasActiveFocus(), false);
877 QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&root));
879 child1.setEnabled(false);
880 QCOMPARE(child1.isEnabled(), false);
881 QCOMPARE(child1.hasFocus(), false);
882 QCOMPARE(child1.hasActiveFocus(), false);
884 child1.setFocus(true);
885 QCOMPARE(child1.isEnabled(), false);
886 QCOMPARE(child1.hasFocus(), true);
887 QCOMPARE(child1.hasActiveFocus(), false);
888 QCOMPARE(child2.isEnabled(), false);
889 QCOMPARE(child2.hasFocus(), false);
890 QCOMPARE(child2.hasActiveFocus(), false);
891 QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&root));
893 child1.setEnabled(true);
894 QCOMPARE(child1.isEnabled(), true);
895 QCOMPARE(child1.hasFocus(), true);
896 QCOMPARE(child1.hasActiveFocus(), true);
897 QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&child1));
899 root.setFocus(false);
900 QCOMPARE(root.isEnabled(), true);
901 QCOMPARE(root.hasFocus(), false);
902 QCOMPARE(root.hasActiveFocus(), false);
903 QCOMPARE(child1.isEnabled(), true);
904 QCOMPARE(child1.hasFocus(), true);
905 QCOMPARE(child1.hasActiveFocus(), false);
906 QCOMPARE(canvas.activeFocusItem(), canvas.rootItem());
908 child2.forceActiveFocus();
909 QCOMPARE(root.isEnabled(), true);
910 QCOMPARE(root.hasFocus(), true);
911 QCOMPARE(root.hasActiveFocus(), true);
912 QCOMPARE(child1.isEnabled(), true);
913 QCOMPARE(child1.hasFocus(), false);
914 QCOMPARE(child1.hasActiveFocus(), false);
915 QCOMPARE(child2.isEnabled(), false);
916 QCOMPARE(child2.hasFocus(), true);
917 QCOMPARE(child2.hasActiveFocus(), false);
918 QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&root));
920 root.setEnabled(false);
921 QCOMPARE(root.isEnabled(), false);
922 QCOMPARE(root.hasFocus(), true);
923 QCOMPARE(root.hasActiveFocus(), false);
924 QCOMPARE(child1.isEnabled(), false);
925 QCOMPARE(child1.hasFocus(), false);
926 QCOMPARE(child1.hasActiveFocus(), false);
927 QCOMPARE(child2.isEnabled(), false);
928 QCOMPARE(child2.hasFocus(), true);
929 QCOMPARE(child2.hasActiveFocus(), false);
930 QCOMPARE(canvas.activeFocusItem(), canvas.rootItem());
932 child1.forceActiveFocus();
933 QCOMPARE(root.isEnabled(), false);
934 QCOMPARE(root.hasFocus(), true);
935 QCOMPARE(root.hasActiveFocus(), false);
936 QCOMPARE(child1.isEnabled(), false);
937 QCOMPARE(child1.hasFocus(), true);
938 QCOMPARE(child1.hasActiveFocus(), false);
939 QCOMPARE(child2.isEnabled(), false);
940 QCOMPARE(child2.hasFocus(), false);
941 QCOMPARE(child2.hasActiveFocus(), false);
942 QCOMPARE(canvas.activeFocusItem(), canvas.rootItem());
944 root.setEnabled(true);
945 QCOMPARE(root.isEnabled(), true);
946 QCOMPARE(root.hasFocus(), true);
947 QCOMPARE(root.hasActiveFocus(), true);
948 QCOMPARE(child1.isEnabled(), true);
949 QCOMPARE(child1.hasFocus(), true);
950 QCOMPARE(child1.hasActiveFocus(), true);
951 QCOMPARE(child2.isEnabled(), false);
952 QCOMPARE(child2.hasFocus(), false);
953 QCOMPARE(child2.hasActiveFocus(), false);
954 QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&child1));
957 void tst_qquickitem::mouseGrab()
959 QQuickCanvas *canvas = new QQuickCanvas;
960 canvas->resize(200, 200);
963 TestItem *child1 = new TestItem;
964 child1->setAcceptedMouseButtons(Qt::LeftButton);
965 child1->setSize(QSizeF(200, 100));
966 child1->setParentItem(canvas->rootItem());
968 TestItem *child2 = new TestItem;
969 child2->setAcceptedMouseButtons(Qt::LeftButton);
971 child2->setSize(QSizeF(200, 100));
972 child2->setParentItem(canvas->rootItem());
974 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
976 QVERIFY(canvas->mouseGrabberItem() == child1);
979 QCOMPARE(child1->pressCount, 1);
980 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50,50));
982 QVERIFY(canvas->mouseGrabberItem() == 0);
983 QCOMPARE(child1->releaseCount, 1);
985 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
987 QVERIFY(canvas->mouseGrabberItem() == child1);
988 QCOMPARE(child1->pressCount, 2);
989 child1->setEnabled(false);
990 QVERIFY(canvas->mouseGrabberItem() == 0);
991 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50,50));
993 QCOMPARE(child1->releaseCount, 1);
994 child1->setEnabled(true);
996 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
998 QVERIFY(canvas->mouseGrabberItem() == child1);
999 QCOMPARE(child1->pressCount, 3);
1000 child1->setVisible(false);
1001 QVERIFY(canvas->mouseGrabberItem() == 0);
1002 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50,50));
1003 QCOMPARE(child1->releaseCount, 1);
1004 child1->setVisible(true);
1006 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
1008 QVERIFY(canvas->mouseGrabberItem() == child1);
1009 QCOMPARE(child1->pressCount, 4);
1010 child2->grabMouse();
1011 QVERIFY(canvas->mouseGrabberItem() == child2);
1012 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50,50));
1014 QCOMPARE(child1->releaseCount, 1);
1015 QCOMPARE(child2->releaseCount, 1);
1017 child2->grabMouse();
1018 QVERIFY(canvas->mouseGrabberItem() == child2);
1019 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
1021 QCOMPARE(child1->pressCount, 4);
1022 QCOMPARE(child2->pressCount, 1);
1023 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50,50));
1025 QCOMPARE(child1->releaseCount, 1);
1026 QCOMPARE(child2->releaseCount, 2);
1033 void tst_qquickitem::touchEventAcceptIgnore_data()
1035 QTest::addColumn<bool>("itemSupportsTouch");
1037 QTest::newRow("with touch") << true;
1038 QTest::newRow("without touch") << false;
1041 void tst_qquickitem::touchEventAcceptIgnore()
1043 QFETCH(bool, itemSupportsTouch);
1045 TestCanvas *canvas = new TestCanvas;
1046 canvas->resize(100, 100);
1049 TestItem *item = new TestItem;
1050 item->setSize(QSizeF(100, 100));
1051 item->setParentItem(canvas->rootItem());
1052 item->acceptIncomingTouchEvents = itemSupportsTouch;
1054 static QTouchDevice* device = 0;
1056 device =new QTouchDevice;
1057 device->setType(QTouchDevice::TouchScreen);
1058 QWindowSystemInterface::registerTouchDevice(device);
1061 // Send Begin, Update & End touch sequence
1063 QTouchEvent::TouchPoint point;
1065 point.setPos(QPointF(50, 50));
1066 point.setScreenPos(point.pos());
1067 point.setState(Qt::TouchPointPressed);
1069 QTouchEvent event(QEvent::TouchBegin, device,
1071 Qt::TouchPointPressed,
1072 QList<QTouchEvent::TouchPoint>() << point);
1073 event.setAccepted(true);
1075 item->touchEventReached = false;
1077 bool accepted = canvas->event(&event);
1079 QVERIFY(item->touchEventReached);
1080 QCOMPARE(accepted && event.isAccepted(), itemSupportsTouch);
1083 QTouchEvent::TouchPoint point;
1085 point.setPos(QPointF(60, 60));
1086 point.setScreenPos(point.pos());
1087 point.setState(Qt::TouchPointMoved);
1089 QTouchEvent event(QEvent::TouchUpdate, device,
1091 Qt::TouchPointMoved,
1092 QList<QTouchEvent::TouchPoint>() << point);
1093 event.setAccepted(true);
1095 item->touchEventReached = false;
1097 bool accepted = canvas->event(&event);
1099 QCOMPARE(item->touchEventReached, itemSupportsTouch);
1100 QCOMPARE(accepted && event.isAccepted(), itemSupportsTouch);
1103 QTouchEvent::TouchPoint point;
1105 point.setPos(QPointF(60, 60));
1106 point.setScreenPos(point.pos());
1107 point.setState(Qt::TouchPointReleased);
1109 QTouchEvent event(QEvent::TouchEnd, device,
1111 Qt::TouchPointReleased,
1112 QList<QTouchEvent::TouchPoint>() << point);
1113 event.setAccepted(true);
1115 item->touchEventReached = false;
1117 bool accepted = canvas->event(&event);
1119 QCOMPARE(item->touchEventReached, itemSupportsTouch);
1120 QCOMPARE(accepted && event.isAccepted(), itemSupportsTouch);
1127 void tst_qquickitem::polishOutsideAnimation()
1129 QQuickCanvas *canvas = new QQuickCanvas;
1130 canvas->resize(200, 200);
1133 TestPolishItem *item = new TestPolishItem(canvas->rootItem());
1134 item->setSize(QSizeF(200, 100));
1137 QTimer::singleShot(10, item, SLOT(doPolish()));
1138 QTRY_VERIFY(item->wasPolished);
1144 void tst_qquickitem::polishOnCompleted()
1146 QQuickView *view = new QQuickView;
1147 view->setSource(testFileUrl("polishOnCompleted.qml"));
1150 TestPolishItem *item = qobject_cast<TestPolishItem*>(view->rootObject());
1154 QSKIP("QTBUG-21590 view does not reliably receive polish without a running animation");
1157 QTRY_VERIFY(item->wasPolished);
1162 void tst_qquickitem::wheelEvent_data()
1164 QTest::addColumn<bool>("visible");
1165 QTest::addColumn<bool>("enabled");
1167 QTest::newRow("visible and enabled") << true << true;
1168 QTest::newRow("visible and disabled") << true << false;
1169 QTest::newRow("invisible and enabled") << false << true;
1170 QTest::newRow("invisible and disabled") << false << false;
1173 void tst_qquickitem::wheelEvent()
1175 QFETCH(bool, visible);
1176 QFETCH(bool, enabled);
1178 const bool shouldReceiveWheelEvents = visible && enabled;
1180 QQuickCanvas *canvas = new QQuickCanvas;
1181 canvas->resize(200, 200);
1184 TestItem *item = new TestItem;
1185 item->setSize(QSizeF(200, 100));
1186 item->setParentItem(canvas->rootItem());
1188 item->setEnabled(enabled);
1189 item->setVisible(visible);
1191 QWheelEvent event(QPoint(100, 50), -120, Qt::NoButton, Qt::NoModifier, Qt::Vertical);
1192 event.setAccepted(false);
1193 QGuiApplication::sendEvent(canvas, &event);
1195 if (shouldReceiveWheelEvents) {
1196 QVERIFY(event.isAccepted());
1197 QCOMPARE(item->wheelCount, 1);
1199 QVERIFY(!event.isAccepted());
1200 QCOMPARE(item->wheelCount, 0);
1206 class HoverItem : public QQuickItem
1210 HoverItem(QQuickItem *parent = 0)
1211 : QQuickItem(parent), hoverEnterCount(0), hoverMoveCount(0), hoverLeaveCount(0)
1213 void resetCounters() {
1214 hoverEnterCount = 0;
1216 hoverLeaveCount = 0;
1218 int hoverEnterCount;
1220 int hoverLeaveCount;
1222 virtual void hoverEnterEvent(QHoverEvent *event) {
1226 virtual void hoverMoveEvent(QHoverEvent *event) {
1230 virtual void hoverLeaveEvent(QHoverEvent *event) {
1236 void tst_qquickitem::hoverEvent_data()
1238 QTest::addColumn<bool>("visible");
1239 QTest::addColumn<bool>("enabled");
1240 QTest::addColumn<bool>("acceptHoverEvents");
1242 QTest::newRow("visible, enabled, accept hover") << true << true << true;
1243 QTest::newRow("visible, disabled, accept hover") << true << false << true;
1244 QTest::newRow("invisible, enabled, accept hover") << false << true << true;
1245 QTest::newRow("invisible, disabled, accept hover") << false << false << true;
1247 QTest::newRow("visible, enabled, not accept hover") << true << true << false;
1248 QTest::newRow("visible, disabled, not accept hover") << true << false << false;
1249 QTest::newRow("invisible, enabled, not accept hover") << false << true << false;
1250 QTest::newRow("invisible, disabled, not accept hover") << false << false << false;
1253 // ### For some unknown reason QTest::mouseMove() isn't working correctly.
1254 static void sendMouseMove(QObject *object, const QPoint &position)
1256 QMouseEvent moveEvent(QEvent::MouseMove, position, Qt::NoButton, Qt::NoButton, 0);
1257 QGuiApplication::sendEvent(object, &moveEvent);
1260 void tst_qquickitem::hoverEvent()
1262 QFETCH(bool, visible);
1263 QFETCH(bool, enabled);
1264 QFETCH(bool, acceptHoverEvents);
1266 QQuickCanvas *canvas = new QQuickCanvas();
1267 canvas->resize(200, 200);
1270 HoverItem *item = new HoverItem;
1271 item->setSize(QSizeF(100, 100));
1272 item->setParentItem(canvas->rootItem());
1274 item->setEnabled(enabled);
1275 item->setVisible(visible);
1276 item->setAcceptHoverEvents(acceptHoverEvents);
1278 const QPoint outside(150, 150);
1279 const QPoint inside(50, 50);
1280 const QPoint anotherInside(51, 51);
1282 sendMouseMove(canvas, outside);
1283 item->resetCounters();
1285 // Enter, then move twice inside, then leave.
1286 sendMouseMove(canvas, inside);
1287 sendMouseMove(canvas, anotherInside);
1288 sendMouseMove(canvas, inside);
1289 sendMouseMove(canvas, outside);
1291 const bool shouldReceiveHoverEvents = visible && enabled && acceptHoverEvents;
1292 if (shouldReceiveHoverEvents) {
1293 QCOMPARE(item->hoverEnterCount, 1);
1294 QCOMPARE(item->hoverMoveCount, 2);
1295 QCOMPARE(item->hoverLeaveCount, 1);
1297 QCOMPARE(item->hoverEnterCount, 0);
1298 QCOMPARE(item->hoverMoveCount, 0);
1299 QCOMPARE(item->hoverLeaveCount, 0);
1305 void tst_qquickitem::hoverEventInParent()
1307 QQuickCanvas *canvas = new QQuickCanvas();
1308 canvas->resize(200, 200);
1311 HoverItem *parentItem = new HoverItem(canvas->rootItem());
1312 parentItem->setSize(QSizeF(200, 200));
1313 parentItem->setAcceptHoverEvents(true);
1315 HoverItem *leftItem = new HoverItem(parentItem);
1316 leftItem->setSize(QSizeF(100, 200));
1317 leftItem->setAcceptHoverEvents(true);
1319 HoverItem *rightItem = new HoverItem(parentItem);
1320 rightItem->setSize(QSizeF(100, 200));
1321 rightItem->setPos(QPointF(100, 0));
1322 rightItem->setAcceptHoverEvents(true);
1324 const QPoint insideLeft(50, 100);
1325 const QPoint insideRight(150, 100);
1327 sendMouseMove(canvas, insideLeft);
1328 parentItem->resetCounters();
1329 leftItem->resetCounters();
1330 rightItem->resetCounters();
1332 sendMouseMove(canvas, insideRight);
1333 QCOMPARE(parentItem->hoverEnterCount, 0);
1334 QCOMPARE(parentItem->hoverLeaveCount, 0);
1335 QCOMPARE(leftItem->hoverEnterCount, 0);
1336 QCOMPARE(leftItem->hoverLeaveCount, 1);
1337 QCOMPARE(rightItem->hoverEnterCount, 1);
1338 QCOMPARE(rightItem->hoverLeaveCount, 0);
1340 sendMouseMove(canvas, insideLeft);
1341 QCOMPARE(parentItem->hoverEnterCount, 0);
1342 QCOMPARE(parentItem->hoverLeaveCount, 0);
1343 QCOMPARE(leftItem->hoverEnterCount, 1);
1344 QCOMPARE(leftItem->hoverLeaveCount, 1);
1345 QCOMPARE(rightItem->hoverEnterCount, 1);
1346 QCOMPARE(rightItem->hoverLeaveCount, 1);
1351 void tst_qquickitem::paintOrder_data()
1353 const QUrl order1Url = testFileUrl("order.1.qml");
1354 const QUrl order2Url = testFileUrl("order.2.qml");
1356 QTest::addColumn<QUrl>("source");
1357 QTest::addColumn<int>("op");
1358 QTest::addColumn<QVariant>("param1");
1359 QTest::addColumn<QVariant>("param2");
1360 QTest::addColumn<QStringList>("expected");
1362 QTest::newRow("test 1 noop") << order1Url
1363 << int(NoOp) << QVariant() << QVariant()
1364 << (QStringList() << "1" << "2" << "3");
1365 QTest::newRow("test 1 add") << order1Url
1366 << int(Append) << QVariant("new") << QVariant()
1367 << (QStringList() << "1" << "2" << "3" << "new");
1368 QTest::newRow("test 1 remove") << order1Url
1369 << int(Remove) << QVariant(1) << QVariant()
1370 << (QStringList() << "1" << "3");
1371 QTest::newRow("test 1 stack before") << order1Url
1372 << int(StackBefore) << QVariant(2) << QVariant(1)
1373 << (QStringList() << "1" << "3" << "2");
1374 QTest::newRow("test 1 stack after") << order1Url
1375 << int(StackAfter) << QVariant(0) << QVariant(1)
1376 << (QStringList() << "2" << "1" << "3");
1377 QTest::newRow("test 1 set z") << order1Url
1378 << int(SetZ) << QVariant(1) << QVariant(qreal(1.))
1379 << (QStringList() << "1" << "3" << "2");
1381 QTest::newRow("test 2 noop") << order2Url
1382 << int(NoOp) << QVariant() << QVariant()
1383 << (QStringList() << "1" << "3" << "2");
1384 QTest::newRow("test 2 add") << order2Url
1385 << int(Append) << QVariant("new") << QVariant()
1386 << (QStringList() << "1" << "3" << "new" << "2");
1387 QTest::newRow("test 2 remove 1") << order2Url
1388 << int(Remove) << QVariant(1) << QVariant()
1389 << (QStringList() << "1" << "3");
1390 QTest::newRow("test 2 remove 2") << order2Url
1391 << int(Remove) << QVariant(2) << QVariant()
1392 << (QStringList() << "1" << "2");
1393 QTest::newRow("test 2 stack before 1") << order2Url
1394 << int(StackBefore) << QVariant(1) << QVariant(0)
1395 << (QStringList() << "1" << "3" << "2");
1396 QTest::newRow("test 2 stack before 2") << order2Url
1397 << int(StackBefore) << QVariant(2) << QVariant(0)
1398 << (QStringList() << "3" << "1" << "2");
1399 QTest::newRow("test 2 stack after 1") << order2Url
1400 << int(StackAfter) << QVariant(0) << QVariant(1)
1401 << (QStringList() << "1" << "3" << "2");
1402 QTest::newRow("test 2 stack after 2") << order2Url
1403 << int(StackAfter) << QVariant(0) << QVariant(2)
1404 << (QStringList() << "3" << "1" << "2");
1405 QTest::newRow("test 1 set z") << order1Url
1406 << int(SetZ) << QVariant(2) << QVariant(qreal(2.))
1407 << (QStringList() << "1" << "2" << "3");
1410 void tst_qquickitem::paintOrder()
1412 QFETCH(QUrl, source);
1414 QFETCH(QVariant, param1);
1415 QFETCH(QVariant, param2);
1416 QFETCH(QStringList, expected);
1419 view.setSource(source);
1421 QQuickItem *root = qobject_cast<QQuickItem*>(view.rootObject());
1426 QQuickItem *item = new QQuickItem(root);
1427 item->setObjectName(param1.toString());
1431 QQuickItem *item = root->childItems().at(param1.toInt());
1436 QQuickItem *item1 = root->childItems().at(param1.toInt());
1437 QQuickItem *item2 = root->childItems().at(param2.toInt());
1438 item1->stackBefore(item2);
1442 QQuickItem *item1 = root->childItems().at(param1.toInt());
1443 QQuickItem *item2 = root->childItems().at(param2.toInt());
1444 item1->stackAfter(item2);
1448 QQuickItem *item = root->childItems().at(param1.toInt());
1449 item->setZ(param2.toReal());
1456 QList<QQuickItem*> list = QQuickItemPrivate::get(root)->paintOrderChildItems();
1459 for (int i = 0; i < list.count(); ++i)
1460 items << list.at(i)->objectName();
1462 QCOMPARE(items, expected);
1466 QTEST_MAIN(tst_qquickitem)
1468 #include "tst_qquickitem.moc"