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