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