Remove copy of tests/shared/util.h.
[profile/ivi/qtdeclarative.git] / tests / auto / declarative / qsgcanvas / tst_qsgcanvas.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the test suite of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <qtest.h>
43 #include <QDebug>
44 #include <QTouchEvent>
45 #include <QtDeclarative/QSGItem>
46 #include <QtDeclarative/QSGCanvas>
47 #include <QtDeclarative/private/qsgrectangle_p.h>
48 #include <QtGui/QWindowSystemInterface>
49
50 struct TouchEventData {
51     QEvent::Type type;
52     QWidget *widget;
53     QWindow *window;
54     Qt::TouchPointStates states;
55     QList<QTouchEvent::TouchPoint> touchPoints;
56 };
57
58 static QTouchEvent::TouchPoint makeTouchPoint(QSGItem *item, const QPointF &p, const QPointF &lastPoint = QPointF())
59 {
60     QPointF last = lastPoint.isNull() ? p : lastPoint;
61
62     QTouchEvent::TouchPoint tp;
63
64     tp.setPos(p);
65     tp.setLastPos(last);
66     tp.setScenePos(item->mapToScene(p));
67     tp.setLastScenePos(item->mapToScene(last));
68     tp.setScreenPos(item->canvas()->mapToGlobal(tp.scenePos().toPoint()));
69     tp.setLastScreenPos(item->canvas()->mapToGlobal(tp.lastScenePos().toPoint()));
70     return tp;
71 }
72
73 static TouchEventData makeTouchData(QEvent::Type type, QWidget *w, Qt::TouchPointStates states, const QList<QTouchEvent::TouchPoint> &touchPoints)
74 {
75     TouchEventData d = { type, w, 0, states, touchPoints };
76     return d;
77 }
78
79 static TouchEventData makeTouchData(QEvent::Type type, QWidget *w, Qt::TouchPointStates states, const QTouchEvent::TouchPoint &touchPoint)
80 {
81     QList<QTouchEvent::TouchPoint> points;
82     points << touchPoint;
83     return makeTouchData(type, w, states, points);
84 }
85 static TouchEventData makeTouchData(QEvent::Type type, QWindow *w, Qt::TouchPointStates states, const QList<QTouchEvent::TouchPoint>& touchPoints)
86 {
87     TouchEventData d = { type, 0, w, states, touchPoints };
88     return d;
89 }
90 static TouchEventData makeTouchData(QEvent::Type type, QWindow *w, Qt::TouchPointStates states, const QTouchEvent::TouchPoint &touchPoint)
91 {
92     QList<QTouchEvent::TouchPoint> points;
93     points << touchPoint;
94     return makeTouchData(type, w, states, points);
95 }
96
97 #define COMPARE_TOUCH_POINTS(tp1, tp2) \
98 { \
99     QCOMPARE(tp1.pos(), tp2.pos()); \
100     QCOMPARE(tp1.lastPos(), tp2.lastPos()); \
101     QCOMPARE(tp1.scenePos(), tp2.scenePos()); \
102     QCOMPARE(tp1.lastScenePos(), tp2.lastScenePos()); \
103     QCOMPARE(tp1.screenPos(), tp2.screenPos()); \
104     QCOMPARE(tp1.lastScreenPos(), tp2.lastScreenPos()); \
105 }
106
107 #define COMPARE_TOUCH_DATA(d1, d2) \
108 { \
109     QCOMPARE((int)d1.type, (int)d2.type); \
110     QCOMPARE(d1.widget, d2.widget); \
111     QCOMPARE((int)d1.states, (int)d2.states); \
112     QCOMPARE(d1.touchPoints.count(), d2.touchPoints.count()); \
113     for (int i=0; i<d1.touchPoints.count(); i++) { \
114         COMPARE_TOUCH_POINTS(d1.touchPoints[i], d2.touchPoints[i]); \
115     } \
116 }
117
118 class TestTouchItem : public QSGRectangle
119 {
120     Q_OBJECT
121 public:
122     TestTouchItem(QSGItem *parent = 0)
123         : QSGRectangle(parent), acceptEvents(true), mousePressId(0)
124     {
125         border()->setWidth(1);
126         setAcceptedMouseButtons(Qt::LeftButton);
127         setFiltersChildMouseEvents(true);
128     }
129
130     void reset() {
131         acceptEvents = true;
132         setEnabled(true);
133         setOpacity(1.0);
134
135         lastEvent = makeTouchData(QEvent::None, canvas(), 0, QList<QTouchEvent::TouchPoint>());//CHECK_VALID
136     }
137
138     bool acceptEvents;
139     TouchEventData lastEvent;
140     int mousePressId;
141
142 protected:
143     virtual void touchEvent(QTouchEvent *event) {
144         if (!acceptEvents) {
145             event->ignore();
146             return;
147         }
148         lastEvent = makeTouchData(event->type(), event->widget(), event->touchPointStates(), event->touchPoints());
149         event->accept();
150     }
151
152     virtual void mousePressEvent(QMouseEvent *event) {
153         mousePressId = ++mousePressNum;
154     }
155
156     bool childMouseEventFilter(QSGItem *, QEvent *) {
157         mousePressId = ++mousePressNum;
158         return false;
159     }
160
161     static int mousePressNum;
162 };
163
164 int TestTouchItem::mousePressNum = 0;
165
166 class ConstantUpdateItem : public QSGItem
167 {
168 Q_OBJECT
169 public:
170     ConstantUpdateItem(QSGItem *parent = 0) : QSGItem(parent), iterations(0) {setFlag(ItemHasContents);}
171
172     int iterations;
173 protected:
174     QSGNode* updatePaintNode(QSGNode *, UpdatePaintNodeData *){
175         iterations++;
176         update();
177         return 0;
178     }
179 };
180
181 class tst_qsgcanvas : public QObject
182 {
183     Q_OBJECT
184 public:
185     tst_qsgcanvas();
186
187 private slots:
188     void initTestCase();
189     void cleanupTestCase();
190
191     void constantUpdates();
192
193     void touchEvent_basic();
194     void touchEvent_propagation();
195     void touchEvent_propagation_data();
196
197     void clearCanvas();
198     void mouseFiltering();
199 };
200
201 tst_qsgcanvas::tst_qsgcanvas()
202 {
203 }
204
205 void tst_qsgcanvas::initTestCase()
206 {
207 }
208
209 void tst_qsgcanvas::cleanupTestCase()
210 {
211 }
212
213 //If the item calls update inside updatePaintNode, it should schedule another update
214 void tst_qsgcanvas::constantUpdates()
215 {
216     QSGCanvas canvas;
217     ConstantUpdateItem item(canvas.rootItem());
218     canvas.show();
219     QTRY_VERIFY(item.iterations > 60);
220 }
221
222 void tst_qsgcanvas::touchEvent_basic()
223 {
224     QSGCanvas *canvas = new QSGCanvas;
225     canvas->resize(250, 250);
226     canvas->move(100, 100);
227     canvas->show();
228
229     TestTouchItem *bottomItem = new TestTouchItem(canvas->rootItem());
230     bottomItem->setObjectName("Bottom Item");
231     bottomItem->setSize(QSizeF(150, 150));
232
233     TestTouchItem *middleItem = new TestTouchItem(bottomItem);
234     middleItem->setObjectName("Middle Item");
235     middleItem->setPos(QPointF(50, 50));
236     middleItem->setSize(QSizeF(150, 150));
237
238     TestTouchItem *topItem = new TestTouchItem(middleItem);
239     topItem->setObjectName("Top Item");
240     topItem->setPos(QPointF(50, 50));
241     topItem->setSize(QSizeF(150, 150));
242
243     QPointF pos(10, 10);
244
245     // press single point
246     QTest::touchEvent(canvas).press(0, topItem->mapToScene(pos).toPoint(),canvas);
247     QTest::qWait(50);
248
249     QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
250
251     QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
252     QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
253     TouchEventData d = makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(topItem,pos));
254     COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(topItem, pos)));
255     topItem->reset();
256
257     // press multiple points
258     QTest::touchEvent(canvas).press(0, topItem->mapToScene(pos).toPoint(),canvas)
259             .press(1, bottomItem->mapToScene(pos).toPoint(), canvas);
260     QTest::qWait(50);
261     QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
262     QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
263     QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
264     COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(topItem, pos)));
265     COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(bottomItem, pos)));
266     topItem->reset();
267     bottomItem->reset();
268
269     // touch point on top item moves to bottom item, but top item should still receive the event
270     QTest::touchEvent(canvas).press(0, topItem->mapToScene(pos).toPoint(), canvas);
271     QTest::qWait(50);
272     QTest::touchEvent(canvas).move(0, bottomItem->mapToScene(pos).toPoint(), canvas);
273     QTest::qWait(50);
274     QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
275     COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchUpdate, canvas, Qt::TouchPointMoved,
276             makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos), pos)));
277     topItem->reset();
278
279     // touch point on bottom item moves to top item, but bottom item should still receive the event
280     QTest::touchEvent(canvas).press(0, bottomItem->mapToScene(pos).toPoint(), canvas);
281     QTest::qWait(50);
282     QTest::touchEvent(canvas).move(0, topItem->mapToScene(pos).toPoint(), canvas);
283     QTest::qWait(50);
284     QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
285     COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchUpdate, canvas, Qt::TouchPointMoved,
286             makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos), pos)));
287     bottomItem->reset();
288
289     // a single stationary press on an item shouldn't cause an event
290     QTest::touchEvent(canvas).press(0, topItem->mapToScene(pos).toPoint(), canvas);
291     QTest::qWait(50);
292     QTest::touchEvent(canvas).stationary(0)
293             .press(1, bottomItem->mapToScene(pos).toPoint(), canvas);
294     QTest::qWait(50);
295     QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);    // received press only, not stationary
296     QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
297     QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
298     COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(topItem, pos)));
299     COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(bottomItem, pos)));
300     topItem->reset();
301     bottomItem->reset();
302
303     // move touch point from top item to bottom, and release
304     QTest::touchEvent(canvas).press(0, topItem->mapToScene(pos).toPoint(),canvas);
305     QTest::qWait(50);
306     QTest::touchEvent(canvas).release(0, bottomItem->mapToScene(pos).toPoint(),canvas);
307     QTest::qWait(50);
308     QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
309     COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchEnd, canvas, Qt::TouchPointReleased,
310             makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos), pos)));
311     topItem->reset();
312
313     // release while another point is pressed
314     QTest::touchEvent(canvas).press(0, topItem->mapToScene(pos).toPoint(),canvas)
315             .press(1, bottomItem->mapToScene(pos).toPoint(), canvas);
316     QTest::qWait(50);
317     QTest::touchEvent(canvas).move(0, bottomItem->mapToScene(pos).toPoint(), canvas);
318     QTest::qWait(50);
319     QTest::touchEvent(canvas).release(0, bottomItem->mapToScene(pos).toPoint(), canvas)
320                              .stationary(1);
321     QTest::qWait(50);
322     QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
323     QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
324     QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
325     COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchEnd, canvas, Qt::TouchPointReleased,
326             makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos))));
327     COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(bottomItem, pos)));
328     topItem->reset();
329     bottomItem->reset();
330
331     delete topItem;
332     delete middleItem;
333     delete bottomItem;
334     delete canvas;
335 }
336
337 void tst_qsgcanvas::touchEvent_propagation()
338 {
339     QFETCH(bool, acceptEvents);
340     QFETCH(bool, enableItem);
341     QFETCH(qreal, itemOpacity);
342
343     QSGCanvas *canvas = new QSGCanvas;
344     canvas->resize(250, 250);
345     canvas->move(100, 100);
346     canvas->show();
347
348     TestTouchItem *bottomItem = new TestTouchItem(canvas->rootItem());
349     bottomItem->setObjectName("Bottom Item");
350     bottomItem->setSize(QSizeF(150, 150));
351
352     TestTouchItem *middleItem = new TestTouchItem(bottomItem);
353     middleItem->setObjectName("Middle Item");
354     middleItem->setPos(QPointF(50, 50));
355     middleItem->setSize(QSizeF(150, 150));
356
357     TestTouchItem *topItem = new TestTouchItem(middleItem);
358     topItem->setObjectName("Top Item");
359     topItem->setPos(QPointF(50, 50));
360     topItem->setSize(QSizeF(150, 150));
361
362     QPointF pos(10, 10);
363     QPoint pointInBottomItem = bottomItem->mapToScene(pos).toPoint();  // (10, 10)
364     QPoint pointInMiddleItem = middleItem->mapToScene(pos).toPoint();  // (60, 60) overlaps with bottomItem
365     QPoint pointInTopItem = topItem->mapToScene(pos).toPoint();  // (110, 110) overlaps with bottom & top items
366
367     // disable topItem
368     topItem->acceptEvents = acceptEvents;
369     topItem->setEnabled(enableItem);
370     topItem->setOpacity(itemOpacity);
371
372     // single touch to top item, should be received by middle item
373     QTest::touchEvent(canvas).press(0, pointInTopItem, canvas);
374     QTest::qWait(50);
375     QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
376     QCOMPARE(middleItem->lastEvent.touchPoints.count(), 1);
377     QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
378     COMPARE_TOUCH_DATA(middleItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed,
379             makeTouchPoint(middleItem, middleItem->mapFromItem(topItem, pos))));
380
381     // touch top and middle items, middle item should get both events
382     QTest::touchEvent(canvas).press(0, pointInTopItem, canvas)
383             .press(1, pointInMiddleItem, canvas);
384     QTest::qWait(50);
385     QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
386     QCOMPARE(middleItem->lastEvent.touchPoints.count(), 2);
387     QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
388     COMPARE_TOUCH_DATA(middleItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed,
389            (QList<QTouchEvent::TouchPoint>() << makeTouchPoint(middleItem, middleItem->mapFromItem(topItem, pos))
390                                               << makeTouchPoint(middleItem, pos) )));
391     middleItem->reset();
392
393     // disable middleItem as well
394     middleItem->acceptEvents = acceptEvents;
395     middleItem->setEnabled(enableItem);
396     middleItem->setOpacity(itemOpacity);
397
398     // touch top and middle items, bottom item should get all events
399     QTest::touchEvent(canvas).press(0, pointInTopItem, canvas)
400             .press(1, pointInMiddleItem, canvas);
401     QTest::qWait(50);
402     QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
403     QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
404     QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 2);
405     COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed,
406             (QList<QTouchEvent::TouchPoint>() << makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos))
407                                               << makeTouchPoint(bottomItem, bottomItem->mapFromItem(middleItem, pos)) )));
408     bottomItem->reset();
409
410     // disable bottom item as well
411     bottomItem->acceptEvents = acceptEvents;
412     bottomItem->setEnabled(enableItem);
413     bottomItem->setOpacity(itemOpacity);
414
415     // no events should be received
416     QTest::touchEvent(canvas).press(0, pointInTopItem, canvas)
417             .press(1, pointInMiddleItem, canvas)
418             .press(2, pointInBottomItem, canvas);
419     QTest::qWait(50);
420     QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
421     QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
422     QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
423
424     topItem->reset();
425     middleItem->reset();
426     bottomItem->reset();
427
428     // disable middle item, touch on top item
429     middleItem->acceptEvents = acceptEvents;
430     middleItem->setEnabled(enableItem);
431     middleItem->setOpacity(itemOpacity);
432     QTest::touchEvent(canvas).press(0, pointInTopItem, canvas);
433     QTest::qWait(50);
434     if (!enableItem || itemOpacity == 0) {
435         // middle item is disabled or has 0 opacity, bottom item receives the event
436         QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
437         QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
438         QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
439         COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed,
440                 makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos))));
441     } else {
442         // middle item ignores event, sends it to the top item (top-most child)
443         QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
444         QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
445         QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
446         COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed,
447                 makeTouchPoint(topItem, pos)));
448     }
449
450     delete topItem;
451     delete middleItem;
452     delete bottomItem;
453     delete canvas;
454 }
455
456 void tst_qsgcanvas::touchEvent_propagation_data()
457 {
458     QTest::addColumn<bool>("acceptEvents");
459     QTest::addColumn<bool>("enableItem");
460     QTest::addColumn<qreal>("itemOpacity");
461
462     QTest::newRow("disable events") << false << true << 1.0;
463     QTest::newRow("disable item") << true << false << 1.0;
464     QTest::newRow("opacity of 0") << true << true << 0.0;
465 }
466
467 void tst_qsgcanvas::clearCanvas()
468 {
469     QSGCanvas *canvas = new QSGCanvas;
470     QSGItem *item = new QSGItem;
471     item->setParentItem(canvas->rootItem());
472
473     QVERIFY(item->canvas() == canvas);
474
475     delete canvas;
476
477     QVERIFY(item->canvas() == 0);
478
479     delete item;
480 }
481
482 void tst_qsgcanvas::mouseFiltering()
483 {
484     QSGCanvas *canvas = new QSGCanvas;
485     canvas->resize(250, 250);
486     canvas->move(100, 100);
487     canvas->show();
488
489     TestTouchItem *bottomItem = new TestTouchItem(canvas->rootItem());
490     bottomItem->setObjectName("Bottom Item");
491     bottomItem->setSize(QSizeF(150, 150));
492
493     TestTouchItem *middleItem = new TestTouchItem(bottomItem);
494     middleItem->setObjectName("Middle Item");
495     middleItem->setPos(QPointF(50, 50));
496     middleItem->setSize(QSizeF(150, 150));
497
498     TestTouchItem *topItem = new TestTouchItem(middleItem);
499     topItem->setObjectName("Top Item");
500     topItem->setPos(QPointF(50, 50));
501     topItem->setSize(QSizeF(150, 150));
502
503     QPoint pos(100, 100);
504
505     QTest::mousePress(canvas, Qt::LeftButton, 0, pos);
506     QTest::qWait(50);
507
508     // Mouse filtering propagates down the stack, so the
509     // correct order is
510     // 1. middleItem filters event
511     // 2. bottomItem filters event
512     // 3. topItem receives event
513     QCOMPARE(middleItem->mousePressId, 1);
514     QCOMPARE(bottomItem->mousePressId, 2);
515     QCOMPARE(topItem->mousePressId, 3);
516 }
517
518
519 QTEST_MAIN(tst_qsgcanvas)
520
521 #include "tst_qsgcanvas.moc"