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