Update item focus even if it doesn't have a canvas
[profile/ivi/qtdeclarative.git] / tests / auto / quick / qquickitem / tst_qquickitem.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <qtest.h>
43
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"
50 #include <QDebug>
51 #include <QTimer>
52 #include "../../shared/util.h"
53
54 class TestItem : public QQuickItem
55 {
56 Q_OBJECT
57 public:
58     TestItem(QQuickItem *parent = 0)
59         : QQuickItem(parent), focused(false), pressCount(0), releaseCount(0)
60         , wheelCount(0), acceptIncomingTouchEvents(true)
61         , touchEventReached(false) {}
62
63     bool focused;
64     int pressCount;
65     int releaseCount;
66     int wheelCount;
67     bool acceptIncomingTouchEvents;
68     bool touchEventReached;
69 protected:
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);
77     }
78     virtual void wheelEvent(QWheelEvent *event) { event->accept(); ++wheelCount; }
79 };
80
81 class TestCanvas: public QQuickCanvas
82 {
83 public:
84     TestCanvas()
85         : QQuickCanvas()
86     {}
87
88     virtual bool event(QEvent *event)
89     {
90         return QQuickCanvas::event(event);
91     }
92 };
93
94 class TestPolishItem : public QQuickItem
95 {
96 Q_OBJECT
97 public:
98     TestPolishItem(QQuickItem *parent = 0)
99     : QQuickItem(parent), wasPolished(false) {
100
101     }
102
103     bool wasPolished;
104
105 protected:
106     virtual void updatePolish() {
107         wasPolished = true;
108     }
109
110 public slots:
111     void doPolish() {
112         polish();
113     }
114 };
115
116 class TestFocusScope : public QQuickFocusScope
117 {
118 Q_OBJECT
119 public:
120     TestFocusScope(QQuickItem *parent = 0) : QQuickFocusScope(parent), focused(false) {}
121
122     bool focused;
123 protected:
124     virtual void focusInEvent(QFocusEvent *) { Q_ASSERT(!focused); focused = true; }
125     virtual void focusOutEvent(QFocusEvent *) { Q_ASSERT(focused); focused = false; }
126 };
127
128 class tst_qquickitem : public QQmlDataTest
129 {
130     Q_OBJECT
131 public:
132
133 private slots:
134     void initTestCase();
135
136     void noCanvas();
137     void simpleFocus();
138     void scopedFocus();
139     void addedToCanvas();
140     void changeParent();
141     void multipleFocusClears();
142
143     void constructor();
144     void setParentItem();
145
146     void visible();
147     void enabled();
148     void enabledFocus();
149
150     void mouseGrab();
151     void touchEventAcceptIgnore_data();
152     void touchEventAcceptIgnore();
153     void polishOutsideAnimation();
154     void polishOnCompleted();
155
156     void wheelEvent_data();
157     void wheelEvent();
158     void hoverEvent_data();
159     void hoverEvent();
160     void hoverEventInParent();
161
162     void paintOrder_data();
163     void paintOrder();
164
165 private:
166
167     enum PaintOrderOp {
168         NoOp, Append, Remove, StackBefore, StackAfter, SetZ
169     };
170
171     void ensureFocus(QWindow *w) {
172         w->show();
173         w->requestActivateWindow();
174         qApp->processEvents();
175     }
176 };
177
178 void tst_qquickitem::initTestCase()
179 {
180     QQmlDataTest::initTestCase();
181     qmlRegisterType<TestPolishItem>("Qt.test", 1, 0, "TestPolishItem");
182 }
183
184 // Focus still updates when outside a canvas
185 void tst_qquickitem::noCanvas()
186 {
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);
192
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);
198
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);
207
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);
217
218     delete root;
219 }
220
221 struct FocusData {
222     FocusData() : focus(false), activeFocus(false) {}
223
224     void set(bool f, bool af) { focus = f; activeFocus = af; }
225     bool focus;
226     bool activeFocus;
227 };
228 struct FocusState : public QHash<QQuickItem *, FocusData>
229 {
230     FocusState() : activeFocusItem(0) {}
231     FocusState &operator<<(QQuickItem *item) {
232         insert(item, FocusData());
233         return *this;
234     }
235
236     void active(QQuickItem *i) {
237         activeFocusItem = i;
238     }
239     QQuickItem *activeFocusItem;
240 };
241
242 #define FVERIFY() \
243     do { \
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); \
250         } else { \
251             QCOMPARE(canvas.activeFocusItem(), canvas.rootItem()); \
252         } \
253         for (QHash<QQuickItem *, FocusData>::Iterator iter = focusState.begin(); \
254             iter != focusState.end(); \
255             iter++) { \
256             QCOMPARE(iter.key()->hasFocus(), iter.value().focus); \
257             QCOMPARE(iter.key()->hasActiveFocus(), iter.value().activeFocus); \
258         } \
259     } while (false)
260
261 // Tests a simple set of top-level scoped items
262 void tst_qquickitem::simpleFocus()
263 {
264     QQuickCanvas canvas;
265     ensureFocus(&canvas);
266
267 #ifdef Q_OS_MAC
268     QSKIP("QTBUG-24094: fails on Mac OS X 10.7");
269 #endif
270
271     QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
272
273     QQuickItem *l1c1 = new TestItem(canvas.rootItem());
274     QQuickItem *l1c2 = new TestItem(canvas.rootItem());
275     QQuickItem *l1c3 = new TestItem(canvas.rootItem());
276
277     QQuickItem *l2c1 = new TestItem(l1c1);
278     QQuickItem *l2c2 = new TestItem(l1c1);
279     QQuickItem *l2c3 = new TestItem(l1c3);
280
281     FocusState focusState;
282     focusState << l1c1 << l1c2 << l1c3
283                << l2c1 << l2c2 << l2c3;
284     FVERIFY();
285
286     l1c1->setFocus(true);
287     focusState[l1c1].set(true, true);
288     focusState.active(l1c1);
289     FVERIFY();
290
291     l2c3->setFocus(true);
292     focusState[l1c1].set(false, false);
293     focusState[l2c3].set(true, true);
294     focusState.active(l2c3);
295     FVERIFY();
296
297     l1c3->setFocus(true);
298     focusState[l2c3].set(false, false);
299     focusState[l1c3].set(true, true);
300     focusState.active(l1c3);
301     FVERIFY();
302
303     l1c2->setFocus(false);
304     FVERIFY();
305
306     l1c3->setFocus(false);
307     focusState[l1c3].set(false, false);
308     focusState.active(0);
309     FVERIFY();
310
311     l2c1->setFocus(true);
312     focusState[l2c1].set(true, true);
313     focusState.active(l2c1);
314     FVERIFY();
315 }
316
317 // Items with a focus scope
318 void tst_qquickitem::scopedFocus()
319 {
320     QQuickCanvas canvas;
321     ensureFocus(&canvas);
322     QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
323
324     QQuickItem *l1c1 = new TestItem(canvas.rootItem());
325     QQuickItem *l1c2 = new TestItem(canvas.rootItem());
326     QQuickItem *l1c3 = new TestItem(canvas.rootItem());
327
328     QQuickItem *l2c1 = new TestItem(l1c1);
329     QQuickItem *l2c2 = new TestItem(l1c1);
330     QQuickItem *l2c3 = new TestFocusScope(l1c3);
331
332     QQuickItem *l3c1 = new TestItem(l2c3);
333     QQuickItem *l3c2 = new TestFocusScope(l2c3);
334
335     QQuickItem *l4c1 = new TestItem(l3c2);
336     QQuickItem *l4c2 = new TestItem(l3c2);
337
338     FocusState focusState;
339     focusState << l1c1 << l1c2 << l1c3
340                << l2c1 << l2c2 << l2c3
341                << l3c1 << l3c2
342                << l4c1 << l4c2;
343     FVERIFY();
344
345     l4c2->setFocus(true);
346     focusState[l4c2].set(true, false);
347     FVERIFY();
348
349     l4c1->setFocus(true);
350     focusState[l4c2].set(false, false);
351     focusState[l4c1].set(true, false);
352     FVERIFY();
353
354     l1c1->setFocus(true);
355     focusState[l1c1].set(true, true);
356     focusState.active(l1c1);
357     FVERIFY();
358
359     l3c2->setFocus(true);
360     focusState[l3c2].set(true, false);
361     FVERIFY();
362
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);
369     FVERIFY();
370
371     l3c2->setFocus(false);
372     focusState[l3c2].set(false, false);
373     focusState[l4c1].set(true, false);
374     focusState.active(l2c3);
375     FVERIFY();
376
377     l3c2->setFocus(true);
378     focusState[l3c2].set(true, true);
379     focusState[l4c1].set(true, true);
380     focusState.active(l4c1);
381     FVERIFY();
382
383     l4c1->setFocus(false);
384     focusState[l4c1].set(false, false);
385     focusState.active(l3c2);
386     FVERIFY();
387
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);
393     FVERIFY();
394 }
395
396 // Tests focus corrects itself when a tree is added to a canvas for the first time
397 void tst_qquickitem::addedToCanvas()
398 {
399     {
400     QQuickCanvas canvas;
401     ensureFocus(&canvas);
402     QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
403
404     QQuickItem *item = new TestItem;
405
406     FocusState focusState;
407     focusState << item;
408
409     item->setFocus(true);
410     focusState[item].set(true, false);
411     FVERIFY();
412
413     item->setParentItem(canvas.rootItem());
414     focusState[item].set(true, true);
415     focusState.active(item);
416     FVERIFY();
417     }
418
419     {
420     QQuickCanvas canvas;
421     ensureFocus(&canvas);
422     QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
423
424     QQuickItem *item = new TestItem(canvas.rootItem());
425
426     QQuickItem *tree = new TestItem;
427     QQuickItem *c1 = new TestItem(tree);
428     QQuickItem *c2 = new TestItem(tree);
429
430     FocusState focusState;
431     focusState << item << tree << c1 << c2;
432
433     item->setFocus(true);
434     c1->setFocus(true);
435     c2->setFocus(true);
436     focusState[item].set(true, true);
437     focusState[c1].set(false, false);
438     focusState[c2].set(true, false);
439     focusState.active(item);
440     FVERIFY();
441
442     tree->setParentItem(item);
443     focusState[c1].set(false, false);
444     focusState[c2].set(false, false);
445     FVERIFY();
446     }
447
448     {
449     QQuickCanvas canvas;
450     ensureFocus(&canvas);
451     QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
452
453     QQuickItem *tree = new TestItem;
454     QQuickItem *c1 = new TestItem(tree);
455     QQuickItem *c2 = new TestItem(tree);
456
457     FocusState focusState;
458     focusState << tree << c1 << c2;
459     c1->setFocus(true);
460     c2->setFocus(true);
461     focusState[c1].set(false, false);
462     focusState[c2].set(true, false);
463     FVERIFY();
464
465     tree->setParentItem(canvas.rootItem());
466     focusState[c1].set(false, false);
467     focusState[c2].set(true, true);
468     focusState.active(c2);
469     FVERIFY();
470     }
471
472     {
473     QQuickCanvas canvas;
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);
479
480     FocusState focusState;
481     focusState << tree << c1 << c2;
482     c1->setFocus(true);
483     c2->setFocus(true);
484     focusState[c1].set(false, false);
485     focusState[c2].set(true, false);
486     FVERIFY();
487
488     tree->setParentItem(canvas.rootItem());
489     focusState[c1].set(false, false);
490     focusState[c2].set(true, false);
491     FVERIFY();
492
493     tree->setFocus(true);
494     focusState[tree].set(true, true);
495     focusState[c2].set(true, true);
496     focusState.active(c2);
497     FVERIFY();
498     }
499
500     {
501     QQuickCanvas canvas;
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);
507
508     FocusState focusState;
509     focusState << tree << c1 << c2;
510     tree->setFocus(true);
511     c1->setFocus(true);
512     c2->setFocus(true);
513     focusState[tree].set(true, false);
514     focusState[c1].set(false, false);
515     focusState[c2].set(true, false);
516     FVERIFY();
517
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);
523     FVERIFY();
524     }
525
526     {
527     QQuickCanvas canvas;
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);
534
535     FocusState focusState;
536     focusState << child << tree << c1 << c2;
537     child->setFocus(true);
538     tree->setFocus(true);
539     c1->setFocus(true);
540     c2->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);
546     FVERIFY();
547
548     tree->setParentItem(canvas.rootItem());
549     focusState[tree].set(false, false);
550     focusState[c1].set(false, false);
551     focusState[c2].set(true, false);
552     FVERIFY();
553
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);
559     FVERIFY();
560     }
561 }
562
563 void tst_qquickitem::changeParent()
564 {
565     // Parent to no parent
566     {
567     QQuickCanvas canvas;
568     ensureFocus(&canvas);
569     QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
570     QQuickItem *child = new TestItem(canvas.rootItem());
571
572     FocusState focusState;
573     focusState << child;
574     FVERIFY();
575
576     child->setFocus(true);
577     focusState[child].set(true, true);
578     focusState.active(child);
579     FVERIFY();
580
581     child->setParentItem(0);
582     focusState[child].set(true, false);
583     focusState.active(0);
584     FVERIFY();
585     }
586
587     // Different parent, same focus scope
588     {
589     QQuickCanvas canvas;
590     ensureFocus(&canvas);
591     QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
592     QQuickItem *child = new TestItem(canvas.rootItem());
593     QQuickItem *child2 = new TestItem(canvas.rootItem());
594
595     FocusState focusState;
596     focusState << child << child2;
597     FVERIFY();
598
599     child->setFocus(true);
600     focusState[child].set(true, true);
601     focusState.active(child);
602     FVERIFY();
603
604     child->setParentItem(child2);
605     FVERIFY();
606     }
607
608     // Different parent, different focus scope
609     {
610     QQuickCanvas canvas;
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);
616
617     FocusState focusState;
618     focusState << child << child2 << item;
619     FVERIFY();
620
621     item->setFocus(true);
622     focusState[item].set(true, true);
623     focusState.active(item);
624     FVERIFY();
625
626     item->setParentItem(child2);
627     focusState[item].set(true, false);
628     focusState.active(0);
629     FVERIFY();
630     }
631     {
632     QQuickCanvas canvas;
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);
638
639     FocusState focusState;
640     focusState << child << child2 << item;
641     FVERIFY();
642
643     item->setFocus(true);
644     focusState[item].set(true, false);
645     focusState.active(0);
646     FVERIFY();
647
648     item->setParentItem(child);
649     focusState[item].set(true, true);
650     focusState.active(item);
651     FVERIFY();
652     }
653     {
654     QQuickCanvas canvas;
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);
660
661     FocusState focusState;
662     focusState << child << child2 << item;
663     FVERIFY();
664
665     child->setFocus(true);
666     item->setFocus(true);
667     focusState[child].set(true, true);
668     focusState[item].set(true, false);
669     focusState.active(child);
670     FVERIFY();
671
672     item->setParentItem(child);
673     focusState[item].set(false, false);
674     FVERIFY();
675     }
676
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
679     {
680     QQuickCanvas canvas;
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;
686
687     FocusState focusState;
688     focusState << item << child;
689     FVERIFY();
690
691     item->setFocus(true);
692     child->setFocus(true);
693     focusState[child].set(true, true);
694     focusState[item].set(true, true);
695     focusState.active(child);
696     FVERIFY();
697
698     item->setParentItem(0);
699     focusState[child].set(true, false);
700     focusState[item].set(true, false);
701     focusState.active(0);
702     FVERIFY();
703
704     focusState.remove(child);
705     delete child;
706     item->setParentItem(canvas.rootItem());
707     focusState[item].set(true, true);
708     focusState.active(item);
709     FVERIFY();
710     }
711 }
712
713 void tst_qquickitem::multipleFocusClears()
714 {
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"));
718     view->show();
719     ensureFocus(view);
720     QTRY_VERIFY(QGuiApplication::focusWindow() == view);
721 }
722
723 void tst_qquickitem::constructor()
724 {
725     QQuickItem *root = new QQuickItem;
726     QVERIFY(root->parent() == 0);
727     QVERIFY(root->parentItem() == 0);
728
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);
734
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);
741
742     delete root;
743 }
744
745 void tst_qquickitem::setParentItem()
746 {
747     QQuickItem *root = new QQuickItem;
748     QVERIFY(root->parent() == 0);
749     QVERIFY(root->parentItem() == 0);
750
751     QQuickItem *child1 = new QQuickItem;
752     QVERIFY(child1->parent() == 0);
753     QVERIFY(child1->parentItem() == 0);
754
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);
760
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);
770
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);
776
777     delete root;
778
779     QVERIFY(child1->parent() == 0);
780     QVERIFY(child1->parentItem() == 0);
781     QVERIFY(child2->parent() == 0);
782     QVERIFY(child2->parentItem() == 0);
783
784     delete child1;
785     delete child2;
786 }
787
788 void tst_qquickitem::visible()
789 {
790     QQuickItem *root = new QQuickItem;
791
792     QQuickItem *child1 = new QQuickItem;
793     child1->setParentItem(root);
794
795     QQuickItem *child2 = new QQuickItem;
796     child2->setParentItem(root);
797
798     QVERIFY(child1->isVisible());
799     QVERIFY(child2->isVisible());
800
801     root->setVisible(false);
802     QVERIFY(!child1->isVisible());
803     QVERIFY(!child2->isVisible());
804
805     root->setVisible(true);
806     QVERIFY(child1->isVisible());
807     QVERIFY(child2->isVisible());
808
809     child1->setVisible(false);
810     QVERIFY(!child1->isVisible());
811     QVERIFY(child2->isVisible());
812
813     child2->setParentItem(child1);
814     QVERIFY(!child1->isVisible());
815     QVERIFY(!child2->isVisible());
816
817     child2->setParentItem(root);
818     QVERIFY(!child1->isVisible());
819     QVERIFY(child2->isVisible());
820
821     delete root;
822     delete child1;
823     delete child2;
824 }
825
826 void tst_qquickitem::enabled()
827 {
828     QQuickItem *root = new QQuickItem;
829
830     QQuickItem *child1 = new QQuickItem;
831     child1->setParentItem(root);
832
833     QQuickItem *child2 = new QQuickItem;
834     child2->setParentItem(root);
835
836     QVERIFY(child1->isEnabled());
837     QVERIFY(child2->isEnabled());
838
839     root->setEnabled(false);
840     QVERIFY(!child1->isEnabled());
841     QVERIFY(!child2->isEnabled());
842
843     root->setEnabled(true);
844     QVERIFY(child1->isEnabled());
845     QVERIFY(child2->isEnabled());
846
847     child1->setEnabled(false);
848     QVERIFY(!child1->isEnabled());
849     QVERIFY(child2->isEnabled());
850
851     child2->setParentItem(child1);
852     QVERIFY(!child1->isEnabled());
853     QVERIFY(!child2->isEnabled());
854
855     child2->setParentItem(root);
856     QVERIFY(!child1->isEnabled());
857     QVERIFY(child2->isEnabled());
858
859     delete root;
860     delete child1;
861     delete child2;
862 }
863
864 void tst_qquickitem::enabledFocus()
865 {
866     QQuickCanvas canvas;
867     ensureFocus(&canvas);
868
869     QQuickFocusScope root;
870
871     root.setFocus(true);
872     root.setEnabled(false);
873
874     QCOMPARE(root.isEnabled(), false);
875     QCOMPARE(root.hasFocus(), true);
876     QCOMPARE(root.hasActiveFocus(), false);
877
878     root.setParentItem(canvas.rootItem());
879
880     QCOMPARE(root.isEnabled(), false);
881     QCOMPARE(root.hasFocus(), true);
882     QCOMPARE(root.hasActiveFocus(), false);
883     QCOMPARE(canvas.activeFocusItem(), canvas.rootItem());
884
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));
890
891     QQuickItem child1;
892     child1.setParentItem(&root);
893
894     QCOMPARE(child1.isEnabled(), true);
895     QCOMPARE(child1.hasFocus(), false);
896     QCOMPARE(child1.hasActiveFocus(), false);
897     QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&root));
898
899     QQuickItem child2;
900     child2.setFocus(true);
901     child2.setParentItem(&root);
902
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);
910
911     child2.setEnabled(false);
912
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));
923
924     child1.setEnabled(false);
925     QCOMPARE(child1.isEnabled(), false);
926     QCOMPARE(child1.hasFocus(), false);
927     QCOMPARE(child1.hasActiveFocus(), false);
928
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));
937
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));
943
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());
952
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));
964
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());
976
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());
988
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));
1000 }
1001
1002 void tst_qquickitem::mouseGrab()
1003 {
1004     QQuickCanvas *canvas = new QQuickCanvas;
1005     canvas->resize(200, 200);
1006     canvas->show();
1007
1008     TestItem *child1 = new TestItem;
1009     child1->setAcceptedMouseButtons(Qt::LeftButton);
1010     child1->setSize(QSizeF(200, 100));
1011     child1->setParentItem(canvas->rootItem());
1012
1013     TestItem *child2 = new TestItem;
1014     child2->setAcceptedMouseButtons(Qt::LeftButton);
1015     child2->setY(51);
1016     child2->setSize(QSizeF(200, 100));
1017     child2->setParentItem(canvas->rootItem());
1018
1019     QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
1020     QTest::qWait(100);
1021     QVERIFY(canvas->mouseGrabberItem() == child1);
1022     QTest::qWait(100);
1023
1024     QCOMPARE(child1->pressCount, 1);
1025     QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50,50));
1026     QTest::qWait(50);
1027     QVERIFY(canvas->mouseGrabberItem() == 0);
1028     QCOMPARE(child1->releaseCount, 1);
1029
1030     QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
1031     QTest::qWait(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));
1037     QTest::qWait(50);
1038     QCOMPARE(child1->releaseCount, 1);
1039     child1->setEnabled(true);
1040
1041     QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
1042     QTest::qWait(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);
1050
1051     QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
1052     QTest::qWait(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));
1058     QTest::qWait(50);
1059     QCOMPARE(child1->releaseCount, 1);
1060     QCOMPARE(child2->releaseCount, 1);
1061
1062     child2->grabMouse();
1063     QVERIFY(canvas->mouseGrabberItem() == child2);
1064     QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
1065     QTest::qWait(50);
1066     QCOMPARE(child1->pressCount, 4);
1067     QCOMPARE(child2->pressCount, 1);
1068     QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50,50));
1069     QTest::qWait(50);
1070     QCOMPARE(child1->releaseCount, 1);
1071     QCOMPARE(child2->releaseCount, 2);
1072
1073     delete child1;
1074     delete child2;
1075     delete canvas;
1076 }
1077
1078 void tst_qquickitem::touchEventAcceptIgnore_data()
1079 {
1080     QTest::addColumn<bool>("itemSupportsTouch");
1081
1082     QTest::newRow("with touch") << true;
1083     QTest::newRow("without touch") << false;
1084 }
1085
1086 void tst_qquickitem::touchEventAcceptIgnore()
1087 {
1088     QFETCH(bool, itemSupportsTouch);
1089
1090     TestCanvas *canvas = new TestCanvas;
1091     canvas->resize(100, 100);
1092     canvas->show();
1093
1094     TestItem *item = new TestItem;
1095     item->setSize(QSizeF(100, 100));
1096     item->setParentItem(canvas->rootItem());
1097     item->acceptIncomingTouchEvents = itemSupportsTouch;
1098
1099     static QTouchDevice* device = 0;
1100     if (!device) {
1101         device =new QTouchDevice;
1102         device->setType(QTouchDevice::TouchScreen);
1103         QWindowSystemInterface::registerTouchDevice(device);
1104     }
1105
1106     // Send Begin, Update & End touch sequence
1107     {
1108         QTouchEvent::TouchPoint point;
1109         point.setId(1);
1110         point.setPos(QPointF(50, 50));
1111         point.setScreenPos(point.pos());
1112         point.setState(Qt::TouchPointPressed);
1113
1114         QTouchEvent event(QEvent::TouchBegin, device,
1115                           Qt::NoModifier,
1116                           Qt::TouchPointPressed,
1117                           QList<QTouchEvent::TouchPoint>() << point);
1118         event.setAccepted(true);
1119
1120         item->touchEventReached = false;
1121
1122         bool accepted = canvas->event(&event);
1123
1124         QVERIFY(item->touchEventReached);
1125         QCOMPARE(accepted && event.isAccepted(), itemSupportsTouch);
1126     }
1127     {
1128         QTouchEvent::TouchPoint point;
1129         point.setId(1);
1130         point.setPos(QPointF(60, 60));
1131         point.setScreenPos(point.pos());
1132         point.setState(Qt::TouchPointMoved);
1133
1134         QTouchEvent event(QEvent::TouchUpdate, device,
1135                           Qt::NoModifier,
1136                           Qt::TouchPointMoved,
1137                           QList<QTouchEvent::TouchPoint>() << point);
1138         event.setAccepted(true);
1139
1140         item->touchEventReached = false;
1141
1142         bool accepted = canvas->event(&event);
1143
1144         QCOMPARE(item->touchEventReached, itemSupportsTouch);
1145         QCOMPARE(accepted && event.isAccepted(), itemSupportsTouch);
1146     }
1147     {
1148         QTouchEvent::TouchPoint point;
1149         point.setId(1);
1150         point.setPos(QPointF(60, 60));
1151         point.setScreenPos(point.pos());
1152         point.setState(Qt::TouchPointReleased);
1153
1154         QTouchEvent event(QEvent::TouchEnd, device,
1155                           Qt::NoModifier,
1156                           Qt::TouchPointReleased,
1157                           QList<QTouchEvent::TouchPoint>() << point);
1158         event.setAccepted(true);
1159
1160         item->touchEventReached = false;
1161
1162         bool accepted = canvas->event(&event);
1163
1164         QCOMPARE(item->touchEventReached, itemSupportsTouch);
1165         QCOMPARE(accepted && event.isAccepted(), itemSupportsTouch);
1166     }
1167
1168     delete item;
1169     delete canvas;
1170 }
1171
1172 void tst_qquickitem::polishOutsideAnimation()
1173 {
1174     QQuickCanvas *canvas = new QQuickCanvas;
1175     canvas->resize(200, 200);
1176     canvas->show();
1177
1178     TestPolishItem *item = new TestPolishItem(canvas->rootItem());
1179     item->setSize(QSizeF(200, 100));
1180     QTest::qWait(50);
1181
1182     QTimer::singleShot(10, item, SLOT(doPolish()));
1183     QTRY_VERIFY(item->wasPolished);
1184
1185     delete item;
1186     delete canvas;
1187 }
1188
1189 void tst_qquickitem::polishOnCompleted()
1190 {
1191     QQuickView *view = new QQuickView;
1192     view->setSource(testFileUrl("polishOnCompleted.qml"));
1193     view->show();
1194
1195     TestPolishItem *item = qobject_cast<TestPolishItem*>(view->rootObject());
1196     QVERIFY(item);
1197
1198 #ifdef Q_OS_MAC
1199     QSKIP("QTBUG-21590 view does not reliably receive polish without a running animation");
1200 #endif
1201
1202     QTRY_VERIFY(item->wasPolished);
1203
1204     delete view;
1205 }
1206
1207 void tst_qquickitem::wheelEvent_data()
1208 {
1209     QTest::addColumn<bool>("visible");
1210     QTest::addColumn<bool>("enabled");
1211
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;
1216 }
1217
1218 void tst_qquickitem::wheelEvent()
1219 {
1220     QFETCH(bool, visible);
1221     QFETCH(bool, enabled);
1222
1223     const bool shouldReceiveWheelEvents = visible && enabled;
1224
1225     QQuickCanvas *canvas = new QQuickCanvas;
1226     canvas->resize(200, 200);
1227     canvas->show();
1228
1229     TestItem *item = new TestItem;
1230     item->setSize(QSizeF(200, 100));
1231     item->setParentItem(canvas->rootItem());
1232
1233     item->setEnabled(enabled);
1234     item->setVisible(visible);
1235
1236     QWheelEvent event(QPoint(100, 50), -120, Qt::NoButton, Qt::NoModifier, Qt::Vertical);
1237     event.setAccepted(false);
1238     QGuiApplication::sendEvent(canvas, &event);
1239
1240     if (shouldReceiveWheelEvents) {
1241         QVERIFY(event.isAccepted());
1242         QCOMPARE(item->wheelCount, 1);
1243     } else {
1244         QVERIFY(!event.isAccepted());
1245         QCOMPARE(item->wheelCount, 0);
1246     }
1247
1248     delete canvas;
1249 }
1250
1251 class HoverItem : public QQuickItem
1252 {
1253 Q_OBJECT
1254 public:
1255     HoverItem(QQuickItem *parent = 0)
1256         : QQuickItem(parent), hoverEnterCount(0), hoverMoveCount(0), hoverLeaveCount(0)
1257     { }
1258     void resetCounters() {
1259         hoverEnterCount = 0;
1260         hoverMoveCount = 0;
1261         hoverLeaveCount = 0;
1262     }
1263     int hoverEnterCount;
1264     int hoverMoveCount;
1265     int hoverLeaveCount;
1266 protected:
1267     virtual void hoverEnterEvent(QHoverEvent *event) {
1268         event->accept();
1269         ++hoverEnterCount;
1270     }
1271     virtual void hoverMoveEvent(QHoverEvent *event) {
1272         event->accept();
1273         ++hoverMoveCount;
1274     }
1275     virtual void hoverLeaveEvent(QHoverEvent *event) {
1276         event->accept();
1277         ++hoverLeaveCount;
1278     }
1279 };
1280
1281 void tst_qquickitem::hoverEvent_data()
1282 {
1283     QTest::addColumn<bool>("visible");
1284     QTest::addColumn<bool>("enabled");
1285     QTest::addColumn<bool>("acceptHoverEvents");
1286
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;
1291
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;
1296 }
1297
1298 // ### For some unknown reason QTest::mouseMove() isn't working correctly.
1299 static void sendMouseMove(QObject *object, const QPoint &position)
1300 {
1301     QMouseEvent moveEvent(QEvent::MouseMove, position, Qt::NoButton, Qt::NoButton, 0);
1302     QGuiApplication::sendEvent(object, &moveEvent);
1303 }
1304
1305 void tst_qquickitem::hoverEvent()
1306 {
1307     QFETCH(bool, visible);
1308     QFETCH(bool, enabled);
1309     QFETCH(bool, acceptHoverEvents);
1310
1311     QQuickCanvas *canvas = new QQuickCanvas();
1312     canvas->resize(200, 200);
1313     canvas->show();
1314
1315     HoverItem *item = new HoverItem;
1316     item->setSize(QSizeF(100, 100));
1317     item->setParentItem(canvas->rootItem());
1318
1319     item->setEnabled(enabled);
1320     item->setVisible(visible);
1321     item->setAcceptHoverEvents(acceptHoverEvents);
1322
1323     const QPoint outside(150, 150);
1324     const QPoint inside(50, 50);
1325     const QPoint anotherInside(51, 51);
1326
1327     sendMouseMove(canvas, outside);
1328     item->resetCounters();
1329
1330     // Enter, then move twice inside, then leave.
1331     sendMouseMove(canvas, inside);
1332     sendMouseMove(canvas, anotherInside);
1333     sendMouseMove(canvas, inside);
1334     sendMouseMove(canvas, outside);
1335
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);
1341     } else {
1342         QCOMPARE(item->hoverEnterCount, 0);
1343         QCOMPARE(item->hoverMoveCount, 0);
1344         QCOMPARE(item->hoverLeaveCount, 0);
1345     }
1346
1347     delete canvas;
1348 }
1349
1350 void tst_qquickitem::hoverEventInParent()
1351 {
1352     QQuickCanvas *canvas = new QQuickCanvas();
1353     canvas->resize(200, 200);
1354     canvas->show();
1355
1356     HoverItem *parentItem = new HoverItem(canvas->rootItem());
1357     parentItem->setSize(QSizeF(200, 200));
1358     parentItem->setAcceptHoverEvents(true);
1359
1360     HoverItem *leftItem = new HoverItem(parentItem);
1361     leftItem->setSize(QSizeF(100, 200));
1362     leftItem->setAcceptHoverEvents(true);
1363
1364     HoverItem *rightItem = new HoverItem(parentItem);
1365     rightItem->setSize(QSizeF(100, 200));
1366     rightItem->setPos(QPointF(100, 0));
1367     rightItem->setAcceptHoverEvents(true);
1368
1369     const QPoint insideLeft(50, 100);
1370     const QPoint insideRight(150, 100);
1371
1372     sendMouseMove(canvas, insideLeft);
1373     parentItem->resetCounters();
1374     leftItem->resetCounters();
1375     rightItem->resetCounters();
1376
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);
1384
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);
1392
1393     delete canvas;
1394 }
1395
1396 void tst_qquickitem::paintOrder_data()
1397 {
1398     const QUrl order1Url = testFileUrl("order.1.qml");
1399     const QUrl order2Url = testFileUrl("order.2.qml");
1400
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");
1406
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");
1425
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");
1453 }
1454
1455 void tst_qquickitem::paintOrder()
1456 {
1457     QFETCH(QUrl, source);
1458     QFETCH(int, op);
1459     QFETCH(QVariant, param1);
1460     QFETCH(QVariant, param2);
1461     QFETCH(QStringList, expected);
1462
1463     QQuickView view;
1464     view.setSource(source);
1465
1466     QQuickItem *root = qobject_cast<QQuickItem*>(view.rootObject());
1467     QVERIFY(root);
1468
1469     switch (op) {
1470         case Append: {
1471                 QQuickItem *item = new QQuickItem(root);
1472                 item->setObjectName(param1.toString());
1473             }
1474             break;
1475         case Remove: {
1476                 QQuickItem *item = root->childItems().at(param1.toInt());
1477                 delete item;
1478             }
1479             break;
1480         case StackBefore: {
1481                 QQuickItem *item1 = root->childItems().at(param1.toInt());
1482                 QQuickItem *item2 = root->childItems().at(param2.toInt());
1483                 item1->stackBefore(item2);
1484             }
1485             break;
1486         case StackAfter: {
1487                 QQuickItem *item1 = root->childItems().at(param1.toInt());
1488                 QQuickItem *item2 = root->childItems().at(param2.toInt());
1489                 item1->stackAfter(item2);
1490             }
1491             break;
1492         case SetZ: {
1493                 QQuickItem *item = root->childItems().at(param1.toInt());
1494                 item->setZ(param2.toReal());
1495             }
1496             break;
1497         default:
1498             break;
1499     }
1500
1501     QList<QQuickItem*> list = QQuickItemPrivate::get(root)->paintOrderChildItems();
1502
1503     QStringList items;
1504     for (int i = 0; i < list.count(); ++i)
1505         items << list.at(i)->objectName();
1506
1507     QCOMPARE(items, expected);
1508 }
1509
1510
1511 QTEST_MAIN(tst_qquickitem)
1512
1513 #include "tst_qquickitem.moc"