Merge remote-tracking branch 'origin/master' into api_changes
[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     void focusSubItemInNonFocusScope();
143     void parentItemWithFocus();
144     void reparentFocusedItem();
145
146     void constructor();
147     void setParentItem();
148
149     void visible();
150     void enabled();
151     void enabledFocus();
152
153     void mouseGrab();
154     void touchEventAcceptIgnore_data();
155     void touchEventAcceptIgnore();
156     void polishOutsideAnimation();
157     void polishOnCompleted();
158
159     void wheelEvent_data();
160     void wheelEvent();
161     void hoverEvent_data();
162     void hoverEvent();
163     void hoverEventInParent();
164
165     void paintOrder_data();
166     void paintOrder();
167
168 private:
169
170     enum PaintOrderOp {
171         NoOp, Append, Remove, StackBefore, StackAfter, SetZ
172     };
173
174     void ensureFocus(QWindow *w) {
175         w->show();
176         w->requestActivateWindow();
177         qApp->processEvents();
178     }
179 };
180
181 void tst_qquickitem::initTestCase()
182 {
183     QQmlDataTest::initTestCase();
184     qmlRegisterType<TestPolishItem>("Qt.test", 1, 0, "TestPolishItem");
185 }
186
187 // Focus still updates when outside a canvas
188 void tst_qquickitem::noCanvas()
189 {
190     QQuickItem *root = new TestItem;
191     QQuickItem *child = new TestItem(root);
192     QQuickItem *scope = new TestItem(root);
193     QQuickFocusScope *scopedChild = new TestFocusScope(scope);
194     QQuickFocusScope *scopedChild2 = new TestFocusScope(scope);
195
196     QCOMPARE(root->hasFocus(), false);
197     QCOMPARE(child->hasFocus(), false);
198     QCOMPARE(scope->hasFocus(), false);
199     QCOMPARE(scopedChild->hasFocus(), false);
200     QCOMPARE(scopedChild2->hasFocus(), false);
201
202     root->setFocus(true);
203     scope->setFocus(true);
204     scopedChild2->setFocus(true);
205     QCOMPARE(root->hasFocus(), true);
206     QCOMPARE(child->hasFocus(), false);
207     QCOMPARE(scope->hasFocus(), false);
208     QCOMPARE(scopedChild->hasFocus(), false);
209     QCOMPARE(scopedChild2->hasFocus(), true);
210
211     root->setFocus(false);
212     child->setFocus(true);
213     scopedChild->setFocus(true);
214     scope->setFocus(false);
215     QCOMPARE(root->hasFocus(), false);
216     QCOMPARE(child->hasFocus(), false);
217     QCOMPARE(scope->hasFocus(), false);
218     QCOMPARE(scopedChild->hasFocus(), true);
219     QCOMPARE(scopedChild2->hasFocus(), false);
220
221     delete root;
222 }
223
224 struct FocusData {
225     FocusData() : focus(false), activeFocus(false) {}
226
227     void set(bool f, bool af) { focus = f; activeFocus = af; }
228     bool focus;
229     bool activeFocus;
230 };
231 struct FocusState : public QHash<QQuickItem *, FocusData>
232 {
233     FocusState() : activeFocusItem(0) {}
234     FocusState &operator<<(QQuickItem *item) {
235         insert(item, FocusData());
236         return *this;
237     }
238
239     void active(QQuickItem *i) {
240         activeFocusItem = i;
241     }
242     QQuickItem *activeFocusItem;
243 };
244
245 #define FVERIFY() \
246     do { \
247         if (focusState.activeFocusItem) { \
248             QCOMPARE(canvas.activeFocusItem(), focusState.activeFocusItem); \
249             if (qobject_cast<TestItem *>(canvas.activeFocusItem())) \
250                 QCOMPARE(qobject_cast<TestItem *>(canvas.activeFocusItem())->focused, true); \
251             else if (qobject_cast<TestFocusScope *>(canvas.activeFocusItem())) \
252                 QCOMPARE(qobject_cast<TestFocusScope *>(canvas.activeFocusItem())->focused, true); \
253         } else { \
254             QCOMPARE(canvas.activeFocusItem(), canvas.rootItem()); \
255         } \
256         for (QHash<QQuickItem *, FocusData>::Iterator iter = focusState.begin(); \
257             iter != focusState.end(); \
258             iter++) { \
259             QCOMPARE(iter.key()->hasFocus(), iter.value().focus); \
260             QCOMPARE(iter.key()->hasActiveFocus(), iter.value().activeFocus); \
261         } \
262     } while (false)
263
264 // Tests a simple set of top-level scoped items
265 void tst_qquickitem::simpleFocus()
266 {
267     QQuickCanvas canvas;
268     ensureFocus(&canvas);
269
270 #ifdef Q_OS_MAC
271     QSKIP("QTBUG-24094: fails on Mac OS X 10.7");
272 #endif
273
274     QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
275
276     QQuickItem *l1c1 = new TestItem(canvas.rootItem());
277     QQuickItem *l1c2 = new TestItem(canvas.rootItem());
278     QQuickItem *l1c3 = new TestItem(canvas.rootItem());
279
280     QQuickItem *l2c1 = new TestItem(l1c1);
281     QQuickItem *l2c2 = new TestItem(l1c1);
282     QQuickItem *l2c3 = new TestItem(l1c3);
283
284     FocusState focusState;
285     focusState << l1c1 << l1c2 << l1c3
286                << l2c1 << l2c2 << l2c3;
287     FVERIFY();
288
289     l1c1->setFocus(true);
290     focusState[l1c1].set(true, true);
291     focusState.active(l1c1);
292     FVERIFY();
293
294     l2c3->setFocus(true);
295     focusState[l1c1].set(false, false);
296     focusState[l2c3].set(true, true);
297     focusState.active(l2c3);
298     FVERIFY();
299
300     l1c3->setFocus(true);
301     focusState[l2c3].set(false, false);
302     focusState[l1c3].set(true, true);
303     focusState.active(l1c3);
304     FVERIFY();
305
306     l1c2->setFocus(false);
307     FVERIFY();
308
309     l1c3->setFocus(false);
310     focusState[l1c3].set(false, false);
311     focusState.active(0);
312     FVERIFY();
313
314     l2c1->setFocus(true);
315     focusState[l2c1].set(true, true);
316     focusState.active(l2c1);
317     FVERIFY();
318 }
319
320 // Items with a focus scope
321 void tst_qquickitem::scopedFocus()
322 {
323     QQuickCanvas canvas;
324     ensureFocus(&canvas);
325     QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
326
327     QQuickItem *l1c1 = new TestItem(canvas.rootItem());
328     QQuickItem *l1c2 = new TestItem(canvas.rootItem());
329     QQuickItem *l1c3 = new TestItem(canvas.rootItem());
330
331     QQuickItem *l2c1 = new TestItem(l1c1);
332     QQuickItem *l2c2 = new TestItem(l1c1);
333     QQuickItem *l2c3 = new TestFocusScope(l1c3);
334
335     QQuickItem *l3c1 = new TestItem(l2c3);
336     QQuickItem *l3c2 = new TestFocusScope(l2c3);
337
338     QQuickItem *l4c1 = new TestItem(l3c2);
339     QQuickItem *l4c2 = new TestItem(l3c2);
340
341     FocusState focusState;
342     focusState << l1c1 << l1c2 << l1c3
343                << l2c1 << l2c2 << l2c3
344                << l3c1 << l3c2
345                << l4c1 << l4c2;
346     FVERIFY();
347
348     l4c2->setFocus(true);
349     focusState[l4c2].set(true, false);
350     FVERIFY();
351
352     l4c1->setFocus(true);
353     focusState[l4c2].set(false, false);
354     focusState[l4c1].set(true, false);
355     FVERIFY();
356
357     l1c1->setFocus(true);
358     focusState[l1c1].set(true, true);
359     focusState.active(l1c1);
360     FVERIFY();
361
362     l3c2->setFocus(true);
363     focusState[l3c2].set(true, false);
364     FVERIFY();
365
366     l2c3->setFocus(true);
367     focusState[l1c1].set(false, false);
368     focusState[l2c3].set(true, true);
369     focusState[l3c2].set(true, true);
370     focusState[l4c1].set(true, true);
371     focusState.active(l4c1);
372     FVERIFY();
373
374     l3c2->setFocus(false);
375     focusState[l3c2].set(false, false);
376     focusState[l4c1].set(true, false);
377     focusState.active(l2c3);
378     FVERIFY();
379
380     l3c2->setFocus(true);
381     focusState[l3c2].set(true, true);
382     focusState[l4c1].set(true, true);
383     focusState.active(l4c1);
384     FVERIFY();
385
386     l4c1->setFocus(false);
387     focusState[l4c1].set(false, false);
388     focusState.active(l3c2);
389     FVERIFY();
390
391     l1c3->setFocus(true);
392     focusState[l1c3].set(true, true);
393     focusState[l2c3].set(false, false);
394     focusState[l3c2].set(true, false);
395     focusState.active(l1c3);
396     FVERIFY();
397 }
398
399 // Tests focus corrects itself when a tree is added to a canvas for the first time
400 void tst_qquickitem::addedToCanvas()
401 {
402     {
403     QQuickCanvas canvas;
404     ensureFocus(&canvas);
405     QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
406
407     QQuickItem *item = new TestItem;
408
409     FocusState focusState;
410     focusState << item;
411
412     item->setFocus(true);
413     focusState[item].set(true, false);
414     FVERIFY();
415
416     item->setParentItem(canvas.rootItem());
417     focusState[item].set(true, true);
418     focusState.active(item);
419     FVERIFY();
420     }
421
422     {
423     QQuickCanvas canvas;
424     ensureFocus(&canvas);
425     QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
426
427     QQuickItem *item = new TestItem(canvas.rootItem());
428
429     QQuickItem *tree = new TestItem;
430     QQuickItem *c1 = new TestItem(tree);
431     QQuickItem *c2 = new TestItem(tree);
432
433     FocusState focusState;
434     focusState << item << tree << c1 << c2;
435
436     item->setFocus(true);
437     c1->setFocus(true);
438     c2->setFocus(true);
439     focusState[item].set(true, true);
440     focusState[c1].set(false, false);
441     focusState[c2].set(true, false);
442     focusState.active(item);
443     FVERIFY();
444
445     tree->setParentItem(item);
446     focusState[c1].set(false, false);
447     focusState[c2].set(false, false);
448     FVERIFY();
449     }
450
451     {
452     QQuickCanvas canvas;
453     ensureFocus(&canvas);
454     QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
455
456     QQuickItem *tree = new TestItem;
457     QQuickItem *c1 = new TestItem(tree);
458     QQuickItem *c2 = new TestItem(tree);
459
460     FocusState focusState;
461     focusState << tree << c1 << c2;
462     c1->setFocus(true);
463     c2->setFocus(true);
464     focusState[c1].set(false, false);
465     focusState[c2].set(true, false);
466     FVERIFY();
467
468     tree->setParentItem(canvas.rootItem());
469     focusState[c1].set(false, false);
470     focusState[c2].set(true, true);
471     focusState.active(c2);
472     FVERIFY();
473     }
474
475     {
476     QQuickCanvas canvas;
477     ensureFocus(&canvas);
478     QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
479     QQuickItem *tree = new TestFocusScope;
480     QQuickItem *c1 = new TestItem(tree);
481     QQuickItem *c2 = new TestItem(tree);
482
483     FocusState focusState;
484     focusState << tree << c1 << c2;
485     c1->setFocus(true);
486     c2->setFocus(true);
487     focusState[c1].set(false, false);
488     focusState[c2].set(true, false);
489     FVERIFY();
490
491     tree->setParentItem(canvas.rootItem());
492     focusState[c1].set(false, false);
493     focusState[c2].set(true, false);
494     FVERIFY();
495
496     tree->setFocus(true);
497     focusState[tree].set(true, true);
498     focusState[c2].set(true, true);
499     focusState.active(c2);
500     FVERIFY();
501     }
502
503     {
504     QQuickCanvas canvas;
505     ensureFocus(&canvas);
506     QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
507     QQuickItem *tree = new TestFocusScope;
508     QQuickItem *c1 = new TestItem(tree);
509     QQuickItem *c2 = new TestItem(tree);
510
511     FocusState focusState;
512     focusState << tree << c1 << c2;
513     tree->setFocus(true);
514     c1->setFocus(true);
515     c2->setFocus(true);
516     focusState[tree].set(true, false);
517     focusState[c1].set(false, false);
518     focusState[c2].set(true, false);
519     FVERIFY();
520
521     tree->setParentItem(canvas.rootItem());
522     focusState[tree].set(true, true);
523     focusState[c1].set(false, false);
524     focusState[c2].set(true, true);
525     focusState.active(c2);
526     FVERIFY();
527     }
528
529     {
530     QQuickCanvas canvas;
531     ensureFocus(&canvas);
532     QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
533     QQuickItem *child = new TestItem(canvas.rootItem());
534     QQuickItem *tree = new TestFocusScope;
535     QQuickItem *c1 = new TestItem(tree);
536     QQuickItem *c2 = new TestItem(tree);
537
538     FocusState focusState;
539     focusState << child << tree << c1 << c2;
540     child->setFocus(true);
541     tree->setFocus(true);
542     c1->setFocus(true);
543     c2->setFocus(true);
544     focusState[child].set(true, true);
545     focusState[tree].set(true, false);
546     focusState[c1].set(false, false);
547     focusState[c2].set(true, false);
548     focusState.active(child);
549     FVERIFY();
550
551     tree->setParentItem(canvas.rootItem());
552     focusState[tree].set(false, false);
553     focusState[c1].set(false, false);
554     focusState[c2].set(true, false);
555     FVERIFY();
556
557     tree->setFocus(true);
558     focusState[child].set(false, false);
559     focusState[tree].set(true, true);
560     focusState[c2].set(true, true);
561     focusState.active(c2);
562     FVERIFY();
563     }
564 }
565
566 void tst_qquickitem::changeParent()
567 {
568     // Parent to no parent
569     {
570     QQuickCanvas canvas;
571     ensureFocus(&canvas);
572     QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
573     QQuickItem *child = new TestItem(canvas.rootItem());
574
575     FocusState focusState;
576     focusState << child;
577     FVERIFY();
578
579     child->setFocus(true);
580     focusState[child].set(true, true);
581     focusState.active(child);
582     FVERIFY();
583
584     child->setParentItem(0);
585     focusState[child].set(true, false);
586     focusState.active(0);
587     FVERIFY();
588     }
589
590     // Different parent, same focus scope
591     {
592     QQuickCanvas canvas;
593     ensureFocus(&canvas);
594     QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
595     QQuickItem *child = new TestItem(canvas.rootItem());
596     QQuickItem *child2 = new TestItem(canvas.rootItem());
597
598     FocusState focusState;
599     focusState << child << child2;
600     FVERIFY();
601
602     child->setFocus(true);
603     focusState[child].set(true, true);
604     focusState.active(child);
605     FVERIFY();
606
607     child->setParentItem(child2);
608     FVERIFY();
609     }
610
611     // Different parent, different focus scope
612     {
613     QQuickCanvas canvas;
614     ensureFocus(&canvas);
615     QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
616     QQuickItem *child = new TestItem(canvas.rootItem());
617     QQuickItem *child2 = new TestFocusScope(canvas.rootItem());
618     QQuickItem *item = new TestItem(child);
619
620     FocusState focusState;
621     focusState << child << child2 << item;
622     FVERIFY();
623
624     item->setFocus(true);
625     focusState[item].set(true, true);
626     focusState.active(item);
627     FVERIFY();
628
629     item->setParentItem(child2);
630     focusState[item].set(true, false);
631     focusState.active(0);
632     FVERIFY();
633     }
634     {
635     QQuickCanvas canvas;
636     ensureFocus(&canvas);
637     QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
638     QQuickItem *child = new TestItem(canvas.rootItem());
639     QQuickItem *child2 = new TestFocusScope(canvas.rootItem());
640     QQuickItem *item = new TestItem(child2);
641
642     FocusState focusState;
643     focusState << child << child2 << item;
644     FVERIFY();
645
646     item->setFocus(true);
647     focusState[item].set(true, false);
648     focusState.active(0);
649     FVERIFY();
650
651     item->setParentItem(child);
652     focusState[item].set(true, true);
653     focusState.active(item);
654     FVERIFY();
655     }
656     {
657     QQuickCanvas canvas;
658     ensureFocus(&canvas);
659     QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
660     QQuickItem *child = new TestItem(canvas.rootItem());
661     QQuickItem *child2 = new TestFocusScope(canvas.rootItem());
662     QQuickItem *item = new TestItem(child2);
663
664     FocusState focusState;
665     focusState << child << child2 << item;
666     FVERIFY();
667
668     child->setFocus(true);
669     item->setFocus(true);
670     focusState[child].set(true, true);
671     focusState[item].set(true, false);
672     focusState.active(child);
673     FVERIFY();
674
675     item->setParentItem(child);
676     focusState[item].set(false, false);
677     FVERIFY();
678     }
679
680     // child has active focus, then its fs parent changes parent to 0, then
681     // child is deleted, then its parent changes again to a valid parent
682     {
683     QQuickCanvas canvas;
684     ensureFocus(&canvas);
685     QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
686     QQuickItem *item = new TestFocusScope(canvas.rootItem());
687     QQuickItem *child = new TestItem(item);
688     QQuickItem *child2 = new TestItem;
689
690     FocusState focusState;
691     focusState << item << child;
692     FVERIFY();
693
694     item->setFocus(true);
695     child->setFocus(true);
696     focusState[child].set(true, true);
697     focusState[item].set(true, true);
698     focusState.active(child);
699     FVERIFY();
700
701     item->setParentItem(0);
702     focusState[child].set(true, false);
703     focusState[item].set(true, false);
704     focusState.active(0);
705     FVERIFY();
706
707     focusState.remove(child);
708     delete child;
709     item->setParentItem(canvas.rootItem());
710     focusState[item].set(true, true);
711     focusState.active(item);
712     FVERIFY();
713     delete child2;
714     }
715 }
716
717 void tst_qquickitem::multipleFocusClears()
718 {
719     //Multiple clears of focus inside a focus scope shouldn't crash. QTBUG-24714
720     QQuickView *view = new QQuickView;
721     view->setSource(testFileUrl("multipleFocusClears.qml"));
722     view->show();
723     ensureFocus(view);
724     QTRY_VERIFY(QGuiApplication::focusWindow() == view);
725 }
726
727 void tst_qquickitem::focusSubItemInNonFocusScope()
728 {
729     QQuickView *view = new QQuickView;
730     view->setSource(testFileUrl("focusSubItemInNonFocusScope.qml"));
731     view->show();
732     qApp->processEvents();
733
734     QQuickItem *dummyItem = view->rootObject()->findChild<QQuickItem *>("dummyItem");
735     QVERIFY(dummyItem);
736
737     QQuickItem *textInput = view->rootObject()->findChild<QQuickItem *>("textInput");
738     QVERIFY(textInput);
739
740     QVERIFY(dummyItem->hasFocus());
741     QVERIFY(!textInput->hasFocus());
742     QVERIFY(dummyItem->hasActiveFocus());
743
744     QVERIFY(QMetaObject::invokeMethod(textInput, "forceActiveFocus"));
745
746     QVERIFY(!dummyItem->hasFocus());
747     QVERIFY(textInput->hasFocus());
748     QVERIFY(textInput->hasActiveFocus());
749
750     delete view;
751 }
752
753 void tst_qquickitem::parentItemWithFocus()
754 {
755     QQuickCanvas canvas;
756     ensureFocus(&canvas);
757     QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
758     {
759     QQuickItem parent;
760     QQuickItem child;
761
762     FocusState focusState;
763     focusState << &parent << &child;
764     FVERIFY();
765
766     parent.setFocus(true);
767     child.setFocus(true);
768     focusState[&parent].set(true, false);
769     focusState[&child].set(true, false);
770     FVERIFY();
771
772     child.setParentItem(&parent);
773     focusState[&parent].set(true, false);
774     focusState[&child].set(false, false);
775     FVERIFY();
776
777     parent.setParentItem(canvas.rootItem());
778     focusState[&parent].set(true, true);
779     focusState[&child].set(false, false);
780     focusState.active(&parent);
781     FVERIFY();
782
783     child.forceActiveFocus();
784     focusState[&parent].set(false, false);
785     focusState[&child].set(true, true);
786     focusState.active(&child);
787     FVERIFY();
788     } {
789     QQuickItem parent;
790     QQuickItem child;
791     QQuickItem grandchild(&child);
792
793     FocusState focusState;
794     focusState << &parent << &child << &grandchild;
795     FVERIFY();
796
797     parent.setFocus(true);
798     grandchild.setFocus(true);
799     focusState[&parent].set(true, false);
800     focusState[&child].set(false, false);
801     focusState[&grandchild].set(true, false);
802     FVERIFY();
803
804     child.setParentItem(&parent);
805     focusState[&parent].set(true, false);
806     focusState[&child].set(false, false);
807     focusState[&grandchild].set(false, false);
808     FVERIFY();
809
810     parent.setParentItem(canvas.rootItem());
811     focusState[&parent].set(true, true);
812     focusState[&child].set(false, false);
813     focusState[&grandchild].set(false, false);
814     focusState.active(&parent);
815     FVERIFY();
816
817     grandchild.forceActiveFocus();
818     focusState[&parent].set(false, false);
819     focusState[&child].set(false, false);
820     focusState[&grandchild].set(true, true);
821     focusState.active(&grandchild);
822     FVERIFY();
823     }
824 }
825
826 void tst_qquickitem::reparentFocusedItem()
827 {
828     QQuickCanvas canvas;
829     ensureFocus(&canvas);
830     QTRY_VERIFY(QGuiApplication::focusWindow() == &canvas);
831
832     QQuickItem parent(canvas.rootItem());
833     QQuickItem child(&parent);
834     QQuickItem sibling(&parent);
835     QQuickItem grandchild(&child);
836
837     FocusState focusState;
838     focusState << &parent << &child << &sibling << &grandchild;
839     FVERIFY();
840
841     grandchild.setFocus(true);
842     focusState[&parent].set(false, false);
843     focusState[&child].set(false, false);
844     focusState[&sibling].set(false, false);
845     focusState[&grandchild].set(true, true);
846     focusState.active(&grandchild);
847     FVERIFY();
848
849     // Parenting the item to another item within the same focus scope shouldn't change it's focus.
850     child.setParentItem(&sibling);
851     FVERIFY();
852 }
853
854 void tst_qquickitem::constructor()
855 {
856     QQuickItem *root = new QQuickItem;
857     QVERIFY(root->parent() == 0);
858     QVERIFY(root->parentItem() == 0);
859
860     QQuickItem *child1 = new QQuickItem(root);
861     QVERIFY(child1->parent() == root);
862     QVERIFY(child1->parentItem() == root);
863     QCOMPARE(root->childItems().count(), 1);
864     QCOMPARE(root->childItems().at(0), child1);
865
866     QQuickItem *child2 = new QQuickItem(root);
867     QVERIFY(child2->parent() == root);
868     QVERIFY(child2->parentItem() == root);
869     QCOMPARE(root->childItems().count(), 2);
870     QCOMPARE(root->childItems().at(0), child1);
871     QCOMPARE(root->childItems().at(1), child2);
872
873     delete root;
874 }
875
876 void tst_qquickitem::setParentItem()
877 {
878     QQuickItem *root = new QQuickItem;
879     QVERIFY(root->parent() == 0);
880     QVERIFY(root->parentItem() == 0);
881
882     QQuickItem *child1 = new QQuickItem;
883     QVERIFY(child1->parent() == 0);
884     QVERIFY(child1->parentItem() == 0);
885
886     child1->setParentItem(root);
887     QVERIFY(child1->parent() == 0);
888     QVERIFY(child1->parentItem() == root);
889     QCOMPARE(root->childItems().count(), 1);
890     QCOMPARE(root->childItems().at(0), child1);
891
892     QQuickItem *child2 = new QQuickItem;
893     QVERIFY(child2->parent() == 0);
894     QVERIFY(child2->parentItem() == 0);
895     child2->setParentItem(root);
896     QVERIFY(child2->parent() == 0);
897     QVERIFY(child2->parentItem() == root);
898     QCOMPARE(root->childItems().count(), 2);
899     QCOMPARE(root->childItems().at(0), child1);
900     QCOMPARE(root->childItems().at(1), child2);
901
902     child1->setParentItem(0);
903     QVERIFY(child1->parent() == 0);
904     QVERIFY(child1->parentItem() == 0);
905     QCOMPARE(root->childItems().count(), 1);
906     QCOMPARE(root->childItems().at(0), child2);
907
908     delete root;
909
910     QVERIFY(child1->parent() == 0);
911     QVERIFY(child1->parentItem() == 0);
912     QVERIFY(child2->parent() == 0);
913     QVERIFY(child2->parentItem() == 0);
914
915     delete child1;
916     delete child2;
917 }
918
919 void tst_qquickitem::visible()
920 {
921     QQuickItem *root = new QQuickItem;
922
923     QQuickItem *child1 = new QQuickItem;
924     child1->setParentItem(root);
925
926     QQuickItem *child2 = new QQuickItem;
927     child2->setParentItem(root);
928
929     QVERIFY(child1->isVisible());
930     QVERIFY(child2->isVisible());
931
932     root->setVisible(false);
933     QVERIFY(!child1->isVisible());
934     QVERIFY(!child2->isVisible());
935
936     root->setVisible(true);
937     QVERIFY(child1->isVisible());
938     QVERIFY(child2->isVisible());
939
940     child1->setVisible(false);
941     QVERIFY(!child1->isVisible());
942     QVERIFY(child2->isVisible());
943
944     child2->setParentItem(child1);
945     QVERIFY(!child1->isVisible());
946     QVERIFY(!child2->isVisible());
947
948     child2->setParentItem(root);
949     QVERIFY(!child1->isVisible());
950     QVERIFY(child2->isVisible());
951
952     delete root;
953     delete child1;
954     delete child2;
955 }
956
957 void tst_qquickitem::enabled()
958 {
959     QQuickItem *root = new QQuickItem;
960
961     QQuickItem *child1 = new QQuickItem;
962     child1->setParentItem(root);
963
964     QQuickItem *child2 = new QQuickItem;
965     child2->setParentItem(root);
966
967     QVERIFY(child1->isEnabled());
968     QVERIFY(child2->isEnabled());
969
970     root->setEnabled(false);
971     QVERIFY(!child1->isEnabled());
972     QVERIFY(!child2->isEnabled());
973
974     root->setEnabled(true);
975     QVERIFY(child1->isEnabled());
976     QVERIFY(child2->isEnabled());
977
978     child1->setEnabled(false);
979     QVERIFY(!child1->isEnabled());
980     QVERIFY(child2->isEnabled());
981
982     child2->setParentItem(child1);
983     QVERIFY(!child1->isEnabled());
984     QVERIFY(!child2->isEnabled());
985
986     child2->setParentItem(root);
987     QVERIFY(!child1->isEnabled());
988     QVERIFY(child2->isEnabled());
989
990     delete root;
991     delete child1;
992     delete child2;
993 }
994
995 void tst_qquickitem::enabledFocus()
996 {
997     QQuickCanvas canvas;
998     ensureFocus(&canvas);
999
1000     QQuickFocusScope root;
1001
1002     root.setFocus(true);
1003     root.setEnabled(false);
1004
1005     QCOMPARE(root.isEnabled(), false);
1006     QCOMPARE(root.hasFocus(), true);
1007     QCOMPARE(root.hasActiveFocus(), false);
1008
1009     root.setParentItem(canvas.rootItem());
1010
1011     QCOMPARE(root.isEnabled(), false);
1012     QCOMPARE(root.hasFocus(), true);
1013     QCOMPARE(root.hasActiveFocus(), false);
1014     QCOMPARE(canvas.activeFocusItem(), canvas.rootItem());
1015
1016     root.setEnabled(true);
1017     QCOMPARE(root.isEnabled(), true);
1018     QCOMPARE(root.hasFocus(), true);
1019     QCOMPARE(root.hasActiveFocus(), true);
1020     QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&root));
1021
1022     QQuickItem child1;
1023     child1.setParentItem(&root);
1024
1025     QCOMPARE(child1.isEnabled(), true);
1026     QCOMPARE(child1.hasFocus(), false);
1027     QCOMPARE(child1.hasActiveFocus(), false);
1028     QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&root));
1029
1030     QQuickItem child2;
1031     child2.setFocus(true);
1032     child2.setParentItem(&root);
1033
1034     QCOMPARE(root.isEnabled(), true);
1035     QCOMPARE(root.hasFocus(), true);
1036     QCOMPARE(root.hasActiveFocus(), true);
1037     QCOMPARE(child2.isEnabled(), true);
1038     QCOMPARE(child2.hasFocus(), true);
1039     QCOMPARE(child2.hasActiveFocus(), true);
1040     QCOMPARE(canvas.activeFocusItem(), &child2);
1041
1042     child2.setEnabled(false);
1043
1044     QCOMPARE(root.isEnabled(), true);
1045     QCOMPARE(root.hasFocus(), true);
1046     QCOMPARE(root.hasActiveFocus(), true);
1047     QCOMPARE(child1.isEnabled(), true);
1048     QCOMPARE(child1.hasFocus(), false);
1049     QCOMPARE(child1.hasActiveFocus(), false);
1050     QCOMPARE(child2.isEnabled(), false);
1051     QCOMPARE(child2.hasFocus(), true);
1052     QCOMPARE(child2.hasActiveFocus(), false);
1053     QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&root));
1054
1055     child1.setEnabled(false);
1056     QCOMPARE(child1.isEnabled(), false);
1057     QCOMPARE(child1.hasFocus(), false);
1058     QCOMPARE(child1.hasActiveFocus(), false);
1059
1060     child1.setFocus(true);
1061     QCOMPARE(child1.isEnabled(), false);
1062     QCOMPARE(child1.hasFocus(), true);
1063     QCOMPARE(child1.hasActiveFocus(), false);
1064     QCOMPARE(child2.isEnabled(), false);
1065     QCOMPARE(child2.hasFocus(), false);
1066     QCOMPARE(child2.hasActiveFocus(), false);
1067     QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&root));
1068
1069     child1.setEnabled(true);
1070     QCOMPARE(child1.isEnabled(), true);
1071     QCOMPARE(child1.hasFocus(), true);
1072     QCOMPARE(child1.hasActiveFocus(), true);
1073     QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&child1));
1074
1075     root.setFocus(false);
1076     QCOMPARE(root.isEnabled(), true);
1077     QCOMPARE(root.hasFocus(), false);
1078     QCOMPARE(root.hasActiveFocus(), false);
1079     QCOMPARE(child1.isEnabled(), true);
1080     QCOMPARE(child1.hasFocus(), true);
1081     QCOMPARE(child1.hasActiveFocus(), false);
1082     QCOMPARE(canvas.activeFocusItem(), canvas.rootItem());
1083
1084     child2.forceActiveFocus();
1085     QCOMPARE(root.isEnabled(), true);
1086     QCOMPARE(root.hasFocus(), true);
1087     QCOMPARE(root.hasActiveFocus(), true);
1088     QCOMPARE(child1.isEnabled(), true);
1089     QCOMPARE(child1.hasFocus(), false);
1090     QCOMPARE(child1.hasActiveFocus(), false);
1091     QCOMPARE(child2.isEnabled(), false);
1092     QCOMPARE(child2.hasFocus(), true);
1093     QCOMPARE(child2.hasActiveFocus(), false);
1094     QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&root));
1095
1096     root.setEnabled(false);
1097     QCOMPARE(root.isEnabled(), false);
1098     QCOMPARE(root.hasFocus(), true);
1099     QCOMPARE(root.hasActiveFocus(), false);
1100     QCOMPARE(child1.isEnabled(), false);
1101     QCOMPARE(child1.hasFocus(), false);
1102     QCOMPARE(child1.hasActiveFocus(), false);
1103     QCOMPARE(child2.isEnabled(), false);
1104     QCOMPARE(child2.hasFocus(), true);
1105     QCOMPARE(child2.hasActiveFocus(), false);
1106     QCOMPARE(canvas.activeFocusItem(), canvas.rootItem());
1107
1108     child1.forceActiveFocus();
1109     QCOMPARE(root.isEnabled(), false);
1110     QCOMPARE(root.hasFocus(), true);
1111     QCOMPARE(root.hasActiveFocus(), false);
1112     QCOMPARE(child1.isEnabled(), false);
1113     QCOMPARE(child1.hasFocus(), true);
1114     QCOMPARE(child1.hasActiveFocus(), false);
1115     QCOMPARE(child2.isEnabled(), false);
1116     QCOMPARE(child2.hasFocus(), false);
1117     QCOMPARE(child2.hasActiveFocus(), false);
1118     QCOMPARE(canvas.activeFocusItem(), canvas.rootItem());
1119
1120     root.setEnabled(true);
1121     QCOMPARE(root.isEnabled(), true);
1122     QCOMPARE(root.hasFocus(), true);
1123     QCOMPARE(root.hasActiveFocus(), true);
1124     QCOMPARE(child1.isEnabled(), true);
1125     QCOMPARE(child1.hasFocus(), true);
1126     QCOMPARE(child1.hasActiveFocus(), true);
1127     QCOMPARE(child2.isEnabled(), false);
1128     QCOMPARE(child2.hasFocus(), false);
1129     QCOMPARE(child2.hasActiveFocus(), false);
1130     QCOMPARE(canvas.activeFocusItem(), static_cast<QQuickItem *>(&child1));
1131 }
1132
1133 void tst_qquickitem::mouseGrab()
1134 {
1135     QQuickCanvas *canvas = new QQuickCanvas;
1136     canvas->resize(200, 200);
1137     canvas->show();
1138
1139     TestItem *child1 = new TestItem;
1140     child1->setAcceptedMouseButtons(Qt::LeftButton);
1141     child1->setSize(QSizeF(200, 100));
1142     child1->setParentItem(canvas->rootItem());
1143
1144     TestItem *child2 = new TestItem;
1145     child2->setAcceptedMouseButtons(Qt::LeftButton);
1146     child2->setY(51);
1147     child2->setSize(QSizeF(200, 100));
1148     child2->setParentItem(canvas->rootItem());
1149
1150     QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
1151     QTest::qWait(100);
1152     QVERIFY(canvas->mouseGrabberItem() == child1);
1153     QTest::qWait(100);
1154
1155     QCOMPARE(child1->pressCount, 1);
1156     QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50,50));
1157     QTest::qWait(50);
1158     QVERIFY(canvas->mouseGrabberItem() == 0);
1159     QCOMPARE(child1->releaseCount, 1);
1160
1161     QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
1162     QTest::qWait(50);
1163     QVERIFY(canvas->mouseGrabberItem() == child1);
1164     QCOMPARE(child1->pressCount, 2);
1165     child1->setEnabled(false);
1166     QVERIFY(canvas->mouseGrabberItem() == 0);
1167     QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50,50));
1168     QTest::qWait(50);
1169     QCOMPARE(child1->releaseCount, 1);
1170     child1->setEnabled(true);
1171
1172     QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
1173     QTest::qWait(50);
1174     QVERIFY(canvas->mouseGrabberItem() == child1);
1175     QCOMPARE(child1->pressCount, 3);
1176     child1->setVisible(false);
1177     QVERIFY(canvas->mouseGrabberItem() == 0);
1178     QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50,50));
1179     QCOMPARE(child1->releaseCount, 1);
1180     child1->setVisible(true);
1181
1182     QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
1183     QTest::qWait(50);
1184     QVERIFY(canvas->mouseGrabberItem() == child1);
1185     QCOMPARE(child1->pressCount, 4);
1186     child2->grabMouse();
1187     QVERIFY(canvas->mouseGrabberItem() == child2);
1188     QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50,50));
1189     QTest::qWait(50);
1190     QCOMPARE(child1->releaseCount, 1);
1191     QCOMPARE(child2->releaseCount, 1);
1192
1193     child2->grabMouse();
1194     QVERIFY(canvas->mouseGrabberItem() == child2);
1195     QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50,50));
1196     QTest::qWait(50);
1197     QCOMPARE(child1->pressCount, 4);
1198     QCOMPARE(child2->pressCount, 1);
1199     QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50,50));
1200     QTest::qWait(50);
1201     QCOMPARE(child1->releaseCount, 1);
1202     QCOMPARE(child2->releaseCount, 2);
1203
1204     delete child1;
1205     delete child2;
1206     delete canvas;
1207 }
1208
1209 void tst_qquickitem::touchEventAcceptIgnore_data()
1210 {
1211     QTest::addColumn<bool>("itemSupportsTouch");
1212
1213     QTest::newRow("with touch") << true;
1214     QTest::newRow("without touch") << false;
1215 }
1216
1217 void tst_qquickitem::touchEventAcceptIgnore()
1218 {
1219     QFETCH(bool, itemSupportsTouch);
1220
1221     TestCanvas *canvas = new TestCanvas;
1222     canvas->resize(100, 100);
1223     canvas->show();
1224
1225     TestItem *item = new TestItem;
1226     item->setSize(QSizeF(100, 100));
1227     item->setParentItem(canvas->rootItem());
1228     item->acceptIncomingTouchEvents = itemSupportsTouch;
1229
1230     static QTouchDevice* device = 0;
1231     if (!device) {
1232         device =new QTouchDevice;
1233         device->setType(QTouchDevice::TouchScreen);
1234         QWindowSystemInterface::registerTouchDevice(device);
1235     }
1236
1237     // Send Begin, Update & End touch sequence
1238     {
1239         QTouchEvent::TouchPoint point;
1240         point.setId(1);
1241         point.setPos(QPointF(50, 50));
1242         point.setScreenPos(point.pos());
1243         point.setState(Qt::TouchPointPressed);
1244
1245         QTouchEvent event(QEvent::TouchBegin, device,
1246                           Qt::NoModifier,
1247                           Qt::TouchPointPressed,
1248                           QList<QTouchEvent::TouchPoint>() << point);
1249         event.setAccepted(true);
1250
1251         item->touchEventReached = false;
1252
1253         bool accepted = canvas->event(&event);
1254
1255         QVERIFY(item->touchEventReached);
1256         QCOMPARE(accepted && event.isAccepted(), itemSupportsTouch);
1257     }
1258     {
1259         QTouchEvent::TouchPoint point;
1260         point.setId(1);
1261         point.setPos(QPointF(60, 60));
1262         point.setScreenPos(point.pos());
1263         point.setState(Qt::TouchPointMoved);
1264
1265         QTouchEvent event(QEvent::TouchUpdate, device,
1266                           Qt::NoModifier,
1267                           Qt::TouchPointMoved,
1268                           QList<QTouchEvent::TouchPoint>() << point);
1269         event.setAccepted(true);
1270
1271         item->touchEventReached = false;
1272
1273         bool accepted = canvas->event(&event);
1274
1275         QCOMPARE(item->touchEventReached, itemSupportsTouch);
1276         QCOMPARE(accepted && event.isAccepted(), itemSupportsTouch);
1277     }
1278     {
1279         QTouchEvent::TouchPoint point;
1280         point.setId(1);
1281         point.setPos(QPointF(60, 60));
1282         point.setScreenPos(point.pos());
1283         point.setState(Qt::TouchPointReleased);
1284
1285         QTouchEvent event(QEvent::TouchEnd, device,
1286                           Qt::NoModifier,
1287                           Qt::TouchPointReleased,
1288                           QList<QTouchEvent::TouchPoint>() << point);
1289         event.setAccepted(true);
1290
1291         item->touchEventReached = false;
1292
1293         bool accepted = canvas->event(&event);
1294
1295         QCOMPARE(item->touchEventReached, itemSupportsTouch);
1296         QCOMPARE(accepted && event.isAccepted(), itemSupportsTouch);
1297     }
1298
1299     delete item;
1300     delete canvas;
1301 }
1302
1303 void tst_qquickitem::polishOutsideAnimation()
1304 {
1305     QQuickCanvas *canvas = new QQuickCanvas;
1306     canvas->resize(200, 200);
1307     canvas->show();
1308
1309     TestPolishItem *item = new TestPolishItem(canvas->rootItem());
1310     item->setSize(QSizeF(200, 100));
1311     QTest::qWait(50);
1312
1313     QTimer::singleShot(10, item, SLOT(doPolish()));
1314     QTRY_VERIFY(item->wasPolished);
1315
1316     delete item;
1317     delete canvas;
1318 }
1319
1320 void tst_qquickitem::polishOnCompleted()
1321 {
1322     QQuickView *view = new QQuickView;
1323     view->setSource(testFileUrl("polishOnCompleted.qml"));
1324     view->show();
1325
1326     TestPolishItem *item = qobject_cast<TestPolishItem*>(view->rootObject());
1327     QVERIFY(item);
1328
1329 #ifdef Q_OS_MAC
1330     QSKIP("QTBUG-21590 view does not reliably receive polish without a running animation");
1331 #endif
1332
1333     QTRY_VERIFY(item->wasPolished);
1334
1335     delete view;
1336 }
1337
1338 void tst_qquickitem::wheelEvent_data()
1339 {
1340     QTest::addColumn<bool>("visible");
1341     QTest::addColumn<bool>("enabled");
1342
1343     QTest::newRow("visible and enabled") << true << true;
1344     QTest::newRow("visible and disabled") << true << false;
1345     QTest::newRow("invisible and enabled") << false << true;
1346     QTest::newRow("invisible and disabled") << false << false;
1347 }
1348
1349 void tst_qquickitem::wheelEvent()
1350 {
1351     QFETCH(bool, visible);
1352     QFETCH(bool, enabled);
1353
1354     const bool shouldReceiveWheelEvents = visible && enabled;
1355
1356     QQuickCanvas *canvas = new QQuickCanvas;
1357     canvas->resize(200, 200);
1358     canvas->show();
1359
1360     TestItem *item = new TestItem;
1361     item->setSize(QSizeF(200, 100));
1362     item->setParentItem(canvas->rootItem());
1363
1364     item->setEnabled(enabled);
1365     item->setVisible(visible);
1366
1367     QWheelEvent event(QPoint(100, 50), -120, Qt::NoButton, Qt::NoModifier, Qt::Vertical);
1368     event.setAccepted(false);
1369     QGuiApplication::sendEvent(canvas, &event);
1370
1371     if (shouldReceiveWheelEvents) {
1372         QVERIFY(event.isAccepted());
1373         QCOMPARE(item->wheelCount, 1);
1374     } else {
1375         QVERIFY(!event.isAccepted());
1376         QCOMPARE(item->wheelCount, 0);
1377     }
1378
1379     delete canvas;
1380 }
1381
1382 class HoverItem : public QQuickItem
1383 {
1384 Q_OBJECT
1385 public:
1386     HoverItem(QQuickItem *parent = 0)
1387         : QQuickItem(parent), hoverEnterCount(0), hoverMoveCount(0), hoverLeaveCount(0)
1388     { }
1389     void resetCounters() {
1390         hoverEnterCount = 0;
1391         hoverMoveCount = 0;
1392         hoverLeaveCount = 0;
1393     }
1394     int hoverEnterCount;
1395     int hoverMoveCount;
1396     int hoverLeaveCount;
1397 protected:
1398     virtual void hoverEnterEvent(QHoverEvent *event) {
1399         event->accept();
1400         ++hoverEnterCount;
1401     }
1402     virtual void hoverMoveEvent(QHoverEvent *event) {
1403         event->accept();
1404         ++hoverMoveCount;
1405     }
1406     virtual void hoverLeaveEvent(QHoverEvent *event) {
1407         event->accept();
1408         ++hoverLeaveCount;
1409     }
1410 };
1411
1412 void tst_qquickitem::hoverEvent_data()
1413 {
1414     QTest::addColumn<bool>("visible");
1415     QTest::addColumn<bool>("enabled");
1416     QTest::addColumn<bool>("acceptHoverEvents");
1417
1418     QTest::newRow("visible, enabled, accept hover") << true << true << true;
1419     QTest::newRow("visible, disabled, accept hover") << true << false << true;
1420     QTest::newRow("invisible, enabled, accept hover") << false << true << true;
1421     QTest::newRow("invisible, disabled, accept hover") << false << false << true;
1422
1423     QTest::newRow("visible, enabled, not accept hover") << true << true << false;
1424     QTest::newRow("visible, disabled, not accept hover") << true << false << false;
1425     QTest::newRow("invisible, enabled, not accept hover") << false << true << false;
1426     QTest::newRow("invisible, disabled, not accept hover") << false << false << false;
1427 }
1428
1429 // ### For some unknown reason QTest::mouseMove() isn't working correctly.
1430 static void sendMouseMove(QObject *object, const QPoint &position)
1431 {
1432     QMouseEvent moveEvent(QEvent::MouseMove, position, Qt::NoButton, Qt::NoButton, 0);
1433     QGuiApplication::sendEvent(object, &moveEvent);
1434 }
1435
1436 void tst_qquickitem::hoverEvent()
1437 {
1438     QFETCH(bool, visible);
1439     QFETCH(bool, enabled);
1440     QFETCH(bool, acceptHoverEvents);
1441
1442     QQuickCanvas *canvas = new QQuickCanvas();
1443     canvas->resize(200, 200);
1444     canvas->show();
1445
1446     HoverItem *item = new HoverItem;
1447     item->setSize(QSizeF(100, 100));
1448     item->setParentItem(canvas->rootItem());
1449
1450     item->setEnabled(enabled);
1451     item->setVisible(visible);
1452     item->setAcceptHoverEvents(acceptHoverEvents);
1453
1454     const QPoint outside(150, 150);
1455     const QPoint inside(50, 50);
1456     const QPoint anotherInside(51, 51);
1457
1458     sendMouseMove(canvas, outside);
1459     item->resetCounters();
1460
1461     // Enter, then move twice inside, then leave.
1462     sendMouseMove(canvas, inside);
1463     sendMouseMove(canvas, anotherInside);
1464     sendMouseMove(canvas, inside);
1465     sendMouseMove(canvas, outside);
1466
1467     const bool shouldReceiveHoverEvents = visible && enabled && acceptHoverEvents;
1468     if (shouldReceiveHoverEvents) {
1469         QCOMPARE(item->hoverEnterCount, 1);
1470         QCOMPARE(item->hoverMoveCount, 2);
1471         QCOMPARE(item->hoverLeaveCount, 1);
1472     } else {
1473         QCOMPARE(item->hoverEnterCount, 0);
1474         QCOMPARE(item->hoverMoveCount, 0);
1475         QCOMPARE(item->hoverLeaveCount, 0);
1476     }
1477
1478     delete canvas;
1479 }
1480
1481 void tst_qquickitem::hoverEventInParent()
1482 {
1483     QQuickCanvas *canvas = new QQuickCanvas();
1484     canvas->resize(200, 200);
1485     canvas->show();
1486
1487     HoverItem *parentItem = new HoverItem(canvas->rootItem());
1488     parentItem->setSize(QSizeF(200, 200));
1489     parentItem->setAcceptHoverEvents(true);
1490
1491     HoverItem *leftItem = new HoverItem(parentItem);
1492     leftItem->setSize(QSizeF(100, 200));
1493     leftItem->setAcceptHoverEvents(true);
1494
1495     HoverItem *rightItem = new HoverItem(parentItem);
1496     rightItem->setSize(QSizeF(100, 200));
1497     rightItem->setPos(QPointF(100, 0));
1498     rightItem->setAcceptHoverEvents(true);
1499
1500     const QPoint insideLeft(50, 100);
1501     const QPoint insideRight(150, 100);
1502
1503     sendMouseMove(canvas, insideLeft);
1504     parentItem->resetCounters();
1505     leftItem->resetCounters();
1506     rightItem->resetCounters();
1507
1508     sendMouseMove(canvas, insideRight);
1509     QCOMPARE(parentItem->hoverEnterCount, 0);
1510     QCOMPARE(parentItem->hoverLeaveCount, 0);
1511     QCOMPARE(leftItem->hoverEnterCount, 0);
1512     QCOMPARE(leftItem->hoverLeaveCount, 1);
1513     QCOMPARE(rightItem->hoverEnterCount, 1);
1514     QCOMPARE(rightItem->hoverLeaveCount, 0);
1515
1516     sendMouseMove(canvas, insideLeft);
1517     QCOMPARE(parentItem->hoverEnterCount, 0);
1518     QCOMPARE(parentItem->hoverLeaveCount, 0);
1519     QCOMPARE(leftItem->hoverEnterCount, 1);
1520     QCOMPARE(leftItem->hoverLeaveCount, 1);
1521     QCOMPARE(rightItem->hoverEnterCount, 1);
1522     QCOMPARE(rightItem->hoverLeaveCount, 1);
1523
1524     delete canvas;
1525 }
1526
1527 void tst_qquickitem::paintOrder_data()
1528 {
1529     const QUrl order1Url = testFileUrl("order.1.qml");
1530     const QUrl order2Url = testFileUrl("order.2.qml");
1531
1532     QTest::addColumn<QUrl>("source");
1533     QTest::addColumn<int>("op");
1534     QTest::addColumn<QVariant>("param1");
1535     QTest::addColumn<QVariant>("param2");
1536     QTest::addColumn<QStringList>("expected");
1537
1538     QTest::newRow("test 1 noop") << order1Url
1539         << int(NoOp) << QVariant() << QVariant()
1540         << (QStringList() << "1" << "2" << "3");
1541     QTest::newRow("test 1 add") << order1Url
1542         << int(Append) << QVariant("new") << QVariant()
1543         << (QStringList() << "1" << "2" << "3" << "new");
1544     QTest::newRow("test 1 remove") << order1Url
1545         << int(Remove) << QVariant(1) << QVariant()
1546         << (QStringList() << "1" << "3");
1547     QTest::newRow("test 1 stack before") << order1Url
1548         << int(StackBefore) << QVariant(2) << QVariant(1)
1549         << (QStringList() << "1" << "3" << "2");
1550     QTest::newRow("test 1 stack after") << order1Url
1551         << int(StackAfter) << QVariant(0) << QVariant(1)
1552         << (QStringList() << "2" << "1" << "3");
1553     QTest::newRow("test 1 set z") << order1Url
1554         << int(SetZ) << QVariant(1) << QVariant(qreal(1.))
1555         << (QStringList() << "1" << "3" << "2");
1556
1557     QTest::newRow("test 2 noop") << order2Url
1558         << int(NoOp) << QVariant() << QVariant()
1559         << (QStringList() << "1" << "3" << "2");
1560     QTest::newRow("test 2 add") << order2Url
1561         << int(Append) << QVariant("new") << QVariant()
1562         << (QStringList() << "1" << "3" << "new" << "2");
1563     QTest::newRow("test 2 remove 1") << order2Url
1564         << int(Remove) << QVariant(1) << QVariant()
1565         << (QStringList() << "1" << "3");
1566     QTest::newRow("test 2 remove 2") << order2Url
1567         << int(Remove) << QVariant(2) << QVariant()
1568         << (QStringList() << "1" << "2");
1569     QTest::newRow("test 2 stack before 1") << order2Url
1570         << int(StackBefore) << QVariant(1) << QVariant(0)
1571         << (QStringList() << "1" << "3" << "2");
1572     QTest::newRow("test 2 stack before 2") << order2Url
1573         << int(StackBefore) << QVariant(2) << QVariant(0)
1574         << (QStringList() << "3" << "1" << "2");
1575     QTest::newRow("test 2 stack after 1") << order2Url
1576         << int(StackAfter) << QVariant(0) << QVariant(1)
1577         << (QStringList() << "1" << "3" << "2");
1578     QTest::newRow("test 2 stack after 2") << order2Url
1579         << int(StackAfter) << QVariant(0) << QVariant(2)
1580         << (QStringList() << "3" << "1" << "2");
1581     QTest::newRow("test 1 set z") << order1Url
1582         << int(SetZ) << QVariant(2) << QVariant(qreal(2.))
1583         << (QStringList() << "1" << "2" << "3");
1584 }
1585
1586 void tst_qquickitem::paintOrder()
1587 {
1588     QFETCH(QUrl, source);
1589     QFETCH(int, op);
1590     QFETCH(QVariant, param1);
1591     QFETCH(QVariant, param2);
1592     QFETCH(QStringList, expected);
1593
1594     QQuickView view;
1595     view.setSource(source);
1596
1597     QQuickItem *root = qobject_cast<QQuickItem*>(view.rootObject());
1598     QVERIFY(root);
1599
1600     switch (op) {
1601         case Append: {
1602                 QQuickItem *item = new QQuickItem(root);
1603                 item->setObjectName(param1.toString());
1604             }
1605             break;
1606         case Remove: {
1607                 QQuickItem *item = root->childItems().at(param1.toInt());
1608                 delete item;
1609             }
1610             break;
1611         case StackBefore: {
1612                 QQuickItem *item1 = root->childItems().at(param1.toInt());
1613                 QQuickItem *item2 = root->childItems().at(param2.toInt());
1614                 item1->stackBefore(item2);
1615             }
1616             break;
1617         case StackAfter: {
1618                 QQuickItem *item1 = root->childItems().at(param1.toInt());
1619                 QQuickItem *item2 = root->childItems().at(param2.toInt());
1620                 item1->stackAfter(item2);
1621             }
1622             break;
1623         case SetZ: {
1624                 QQuickItem *item = root->childItems().at(param1.toInt());
1625                 item->setZ(param2.toReal());
1626             }
1627             break;
1628         default:
1629             break;
1630     }
1631
1632     QList<QQuickItem*> list = QQuickItemPrivate::get(root)->paintOrderChildItems();
1633
1634     QStringList items;
1635     for (int i = 0; i < list.count(); ++i)
1636         items << list.at(i)->objectName();
1637
1638     QCOMPARE(items, expected);
1639 }
1640
1641
1642 QTEST_MAIN(tst_qquickitem)
1643
1644 #include "tst_qquickitem.moc"