307968d834b03900410e066f8f15e57fa4e7fa21
[profile/ivi/qtdeclarative.git] / tests / auto / qtquick2 / qquickcanvas / tst_qquickcanvas.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
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 <QtQuick/QQuickItem>
46 #include <QtQuick/QQuickCanvas>
47 #include <QtDeclarative/QDeclarativeEngine>
48 #include <QtDeclarative/QDeclarativeComponent>
49 #include <QtQuick/private/qquickrectangle_p.h>
50 #include <QtGui/QWindowSystemInterface>
51 #include "../../shared/util.h"
52 #include <QSignalSpy>
53
54 struct TouchEventData {
55     QEvent::Type type;
56     QWidget *widget;
57     QWindow *window;
58     Qt::TouchPointStates states;
59     QList<QTouchEvent::TouchPoint> touchPoints;
60 };
61
62 static QTouchEvent::TouchPoint makeTouchPoint(QQuickItem *item, const QPointF &p, const QPointF &lastPoint = QPointF())
63 {
64     QPointF last = lastPoint.isNull() ? p : lastPoint;
65
66     QTouchEvent::TouchPoint tp;
67
68     tp.setPos(p);
69     tp.setLastPos(last);
70     tp.setScenePos(item->mapToScene(p));
71     tp.setLastScenePos(item->mapToScene(last));
72     tp.setScreenPos(item->canvas()->mapToGlobal(tp.scenePos().toPoint()));
73     tp.setLastScreenPos(item->canvas()->mapToGlobal(tp.lastScenePos().toPoint()));
74     return tp;
75 }
76
77 static TouchEventData makeTouchData(QEvent::Type type, QWindow *w, Qt::TouchPointStates states, const QList<QTouchEvent::TouchPoint>& touchPoints)
78 {
79     TouchEventData d = { type, 0, w, states, touchPoints };
80     return d;
81 }
82 static TouchEventData makeTouchData(QEvent::Type type, QWindow *w, Qt::TouchPointStates states, const QTouchEvent::TouchPoint &touchPoint)
83 {
84     QList<QTouchEvent::TouchPoint> points;
85     points << touchPoint;
86     return makeTouchData(type, w, states, points);
87 }
88
89 #define COMPARE_TOUCH_POINTS(tp1, tp2) \
90 { \
91     QCOMPARE(tp1.pos(), tp2.pos()); \
92     QCOMPARE(tp1.lastPos(), tp2.lastPos()); \
93     QCOMPARE(tp1.scenePos(), tp2.scenePos()); \
94     QCOMPARE(tp1.lastScenePos(), tp2.lastScenePos()); \
95     QCOMPARE(tp1.screenPos(), tp2.screenPos()); \
96     QCOMPARE(tp1.lastScreenPos(), tp2.lastScreenPos()); \
97 }
98
99 #define COMPARE_TOUCH_DATA(d1, d2) \
100 { \
101     QCOMPARE((int)d1.type, (int)d2.type); \
102     QCOMPARE(d1.widget, d2.widget); \
103     QCOMPARE((int)d1.states, (int)d2.states); \
104     QCOMPARE(d1.touchPoints.count(), d2.touchPoints.count()); \
105     for (int i=0; i<d1.touchPoints.count(); i++) { \
106         COMPARE_TOUCH_POINTS(d1.touchPoints[i], d2.touchPoints[i]); \
107     } \
108 }
109
110 class TestTouchItem : public QQuickRectangle
111 {
112     Q_OBJECT
113 public:
114     TestTouchItem(QQuickItem *parent = 0)
115         : QQuickRectangle(parent), acceptEvents(true), mousePressId(0)
116     {
117         border()->setWidth(1);
118         setAcceptedMouseButtons(Qt::LeftButton);
119         setFiltersChildMouseEvents(true);
120     }
121
122     void reset() {
123         acceptEvents = true;
124         setEnabled(true);
125         setOpacity(1.0);
126
127         lastEvent = makeTouchData(QEvent::None, canvas(), 0, QList<QTouchEvent::TouchPoint>());//CHECK_VALID
128     }
129
130     static void clearMousePressCounter()
131     {
132         mousePressNum = 0;
133     }
134
135     bool acceptEvents;
136     TouchEventData lastEvent;
137     int mousePressId;
138 protected:
139     virtual void touchEvent(QTouchEvent *event) {
140         if (!acceptEvents) {
141             event->ignore();
142             return;
143         }
144         lastEvent = makeTouchData(event->type(), event->window(), event->touchPointStates(), event->touchPoints());
145         event->accept();
146     }
147
148     virtual void mousePressEvent(QMouseEvent *) {
149         mousePressId = ++mousePressNum;
150     }
151
152     bool childMouseEventFilter(QQuickItem *, QEvent *event) {
153         if (event->type() == QEvent::MouseButtonPress)
154             mousePressId = ++mousePressNum;
155         return false;
156     }
157
158     static int mousePressNum;
159 };
160
161 int TestTouchItem::mousePressNum = 0;
162
163 class ConstantUpdateItem : public QQuickItem
164 {
165 Q_OBJECT
166 public:
167     ConstantUpdateItem(QQuickItem *parent = 0) : QQuickItem(parent), iterations(0) {setFlag(ItemHasContents);}
168
169     int iterations;
170 protected:
171     QSGNode* updatePaintNode(QSGNode *, UpdatePaintNodeData *){
172         iterations++;
173         update();
174         return 0;
175     }
176 };
177
178 class tst_qquickcanvas : public QDeclarativeDataTest
179 {
180     Q_OBJECT
181 public:
182
183 private slots:
184     void initTestCase()
185     {
186         QDeclarativeDataTest::initTestCase();
187         touchDevice = new QTouchDevice();
188         touchDevice->setType(QTouchDevice::TouchScreen);
189         QWindowSystemInterface::registerTouchDevice(touchDevice);
190     }
191
192
193     void constantUpdates();
194     void mouseFiltering();
195     void headless();
196
197     void touchEvent_basic();
198     void touchEvent_propagation();
199     void touchEvent_propagation_data();
200
201     void clearCanvas();
202
203     void qmlCreation();
204     void clearColor();
205
206     void grab();
207     void multipleWindows();
208
209     void animationsWhileHidden();
210
211     void focusObject();
212
213 private:
214     QTouchDevice *touchDevice;
215 };
216
217 //If the item calls update inside updatePaintNode, it should schedule another update
218 void tst_qquickcanvas::constantUpdates()
219 {
220     QQuickCanvas canvas;
221     canvas.resize(250, 250);
222     ConstantUpdateItem item(canvas.rootItem());
223     canvas.show();
224     QTRY_VERIFY(item.iterations > 60);
225 }
226
227 void tst_qquickcanvas::touchEvent_basic()
228 {
229     TestTouchItem::clearMousePressCounter();
230
231     QQuickCanvas *canvas = new QQuickCanvas;
232     canvas->resize(250, 250);
233     canvas->move(100, 100);
234     canvas->show();
235
236     TestTouchItem *bottomItem = new TestTouchItem(canvas->rootItem());
237     bottomItem->setObjectName("Bottom Item");
238     bottomItem->setSize(QSizeF(150, 150));
239
240     TestTouchItem *middleItem = new TestTouchItem(bottomItem);
241     middleItem->setObjectName("Middle Item");
242     middleItem->setPos(QPointF(50, 50));
243     middleItem->setSize(QSizeF(150, 150));
244
245     TestTouchItem *topItem = new TestTouchItem(middleItem);
246     topItem->setObjectName("Top Item");
247     topItem->setPos(QPointF(50, 50));
248     topItem->setSize(QSizeF(150, 150));
249
250     QPointF pos(10, 10);
251
252     // press single point
253     QTest::touchEvent(canvas, touchDevice).press(0, topItem->mapToScene(pos).toPoint(),canvas);
254     QTest::qWait(50);
255
256     QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
257
258     QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
259     QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
260     TouchEventData d = makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(topItem,pos));
261     COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(topItem, pos)));
262     topItem->reset();
263
264     // press multiple points
265     QTest::touchEvent(canvas, touchDevice).press(0, topItem->mapToScene(pos).toPoint(),canvas)
266             .press(1, bottomItem->mapToScene(pos).toPoint(), canvas);
267     QTest::qWait(50);
268     QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
269     QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
270     QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
271     COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(topItem, pos)));
272     COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(bottomItem, pos)));
273     topItem->reset();
274     bottomItem->reset();
275
276     // touch point on top item moves to bottom item, but top item should still receive the event
277     QTest::touchEvent(canvas, touchDevice).press(0, topItem->mapToScene(pos).toPoint(), canvas);
278     QTest::qWait(50);
279     QTest::touchEvent(canvas, touchDevice).move(0, bottomItem->mapToScene(pos).toPoint(), canvas);
280     QTest::qWait(50);
281     QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
282     COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchUpdate, canvas, Qt::TouchPointMoved,
283             makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos), pos)));
284     topItem->reset();
285
286     // touch point on bottom item moves to top item, but bottom item should still receive the event
287     QTest::touchEvent(canvas, touchDevice).press(0, bottomItem->mapToScene(pos).toPoint(), canvas);
288     QTest::qWait(50);
289     QTest::touchEvent(canvas, touchDevice).move(0, topItem->mapToScene(pos).toPoint(), canvas);
290     QTest::qWait(50);
291     QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
292     COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchUpdate, canvas, Qt::TouchPointMoved,
293             makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos), pos)));
294     bottomItem->reset();
295
296     // a single stationary press on an item shouldn't cause an event
297     QTest::touchEvent(canvas, touchDevice).press(0, topItem->mapToScene(pos).toPoint(), canvas);
298     QTest::qWait(50);
299     QTest::touchEvent(canvas, touchDevice).stationary(0)
300             .press(1, bottomItem->mapToScene(pos).toPoint(), canvas);
301     QTest::qWait(50);
302     QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);    // received press only, not stationary
303     QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
304     QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
305     COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(topItem, pos)));
306     COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(bottomItem, pos)));
307     topItem->reset();
308     bottomItem->reset();
309
310     // move touch point from top item to bottom, and release
311     QTest::touchEvent(canvas, touchDevice).press(0, topItem->mapToScene(pos).toPoint(),canvas);
312     QTest::qWait(50);
313     QTest::touchEvent(canvas, touchDevice).release(0, bottomItem->mapToScene(pos).toPoint(),canvas);
314     QTest::qWait(50);
315     QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
316     COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchEnd, canvas, Qt::TouchPointReleased,
317             makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos), pos)));
318     topItem->reset();
319
320     // release while another point is pressed
321     QTest::touchEvent(canvas, touchDevice).press(0, topItem->mapToScene(pos).toPoint(),canvas)
322             .press(1, bottomItem->mapToScene(pos).toPoint(), canvas);
323     QTest::qWait(50);
324     QTest::touchEvent(canvas, touchDevice).move(0, bottomItem->mapToScene(pos).toPoint(), canvas);
325     QTest::qWait(50);
326     QTest::touchEvent(canvas, touchDevice).release(0, bottomItem->mapToScene(pos).toPoint(), canvas)
327                              .stationary(1);
328     QTest::qWait(50);
329     QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
330     QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
331     QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
332     COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchEnd, canvas, Qt::TouchPointReleased,
333             makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos))));
334     COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(bottomItem, pos)));
335     topItem->reset();
336     bottomItem->reset();
337
338     delete topItem;
339     delete middleItem;
340     delete bottomItem;
341     delete canvas;
342 }
343
344 void tst_qquickcanvas::touchEvent_propagation()
345 {
346     TestTouchItem::clearMousePressCounter();
347
348     QFETCH(bool, acceptEvents);
349     QFETCH(bool, enableItem);
350     QFETCH(qreal, itemOpacity);
351
352     QQuickCanvas *canvas = new QQuickCanvas;
353     canvas->resize(250, 250);
354     canvas->move(100, 100);
355     canvas->show();
356
357     TestTouchItem *bottomItem = new TestTouchItem(canvas->rootItem());
358     bottomItem->setObjectName("Bottom Item");
359     bottomItem->setSize(QSizeF(150, 150));
360
361     TestTouchItem *middleItem = new TestTouchItem(bottomItem);
362     middleItem->setObjectName("Middle Item");
363     middleItem->setPos(QPointF(50, 50));
364     middleItem->setSize(QSizeF(150, 150));
365
366     TestTouchItem *topItem = new TestTouchItem(middleItem);
367     topItem->setObjectName("Top Item");
368     topItem->setPos(QPointF(50, 50));
369     topItem->setSize(QSizeF(150, 150));
370
371     QPointF pos(10, 10);
372     QPoint pointInBottomItem = bottomItem->mapToScene(pos).toPoint();  // (10, 10)
373     QPoint pointInMiddleItem = middleItem->mapToScene(pos).toPoint();  // (60, 60) overlaps with bottomItem
374     QPoint pointInTopItem = topItem->mapToScene(pos).toPoint();  // (110, 110) overlaps with bottom & top items
375
376     // disable topItem
377     topItem->acceptEvents = acceptEvents;
378     topItem->setEnabled(enableItem);
379     topItem->setOpacity(itemOpacity);
380
381     // single touch to top item, should be received by middle item
382     QTest::touchEvent(canvas, touchDevice).press(0, pointInTopItem, canvas);
383     QTest::qWait(50);
384     QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
385     QCOMPARE(middleItem->lastEvent.touchPoints.count(), 1);
386     QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
387     COMPARE_TOUCH_DATA(middleItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed,
388             makeTouchPoint(middleItem, middleItem->mapFromItem(topItem, pos))));
389
390     // touch top and middle items, middle item should get both events
391     QTest::touchEvent(canvas, touchDevice).press(0, pointInTopItem, canvas)
392             .press(1, pointInMiddleItem, canvas);
393     QTest::qWait(50);
394     QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
395     QCOMPARE(middleItem->lastEvent.touchPoints.count(), 2);
396     QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
397     COMPARE_TOUCH_DATA(middleItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed,
398            (QList<QTouchEvent::TouchPoint>() << makeTouchPoint(middleItem, middleItem->mapFromItem(topItem, pos))
399                                               << makeTouchPoint(middleItem, pos) )));
400     middleItem->reset();
401
402     // disable middleItem as well
403     middleItem->acceptEvents = acceptEvents;
404     middleItem->setEnabled(enableItem);
405     middleItem->setOpacity(itemOpacity);
406
407     // touch top and middle items, bottom item should get all events
408     QTest::touchEvent(canvas, touchDevice).press(0, pointInTopItem, canvas)
409             .press(1, pointInMiddleItem, canvas);
410     QTest::qWait(50);
411     QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
412     QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
413     QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 2);
414     COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed,
415             (QList<QTouchEvent::TouchPoint>() << makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos))
416                                               << makeTouchPoint(bottomItem, bottomItem->mapFromItem(middleItem, pos)) )));
417     bottomItem->reset();
418
419     // disable bottom item as well
420     bottomItem->acceptEvents = acceptEvents;
421     bottomItem->setEnabled(enableItem);
422     bottomItem->setOpacity(itemOpacity);
423
424     // no events should be received
425     QTest::touchEvent(canvas, touchDevice).press(0, pointInTopItem, canvas)
426             .press(1, pointInMiddleItem, canvas)
427             .press(2, pointInBottomItem, canvas);
428     QTest::qWait(50);
429     QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
430     QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
431     QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
432
433     topItem->reset();
434     middleItem->reset();
435     bottomItem->reset();
436
437     // disable middle item, touch on top item
438     middleItem->acceptEvents = acceptEvents;
439     middleItem->setEnabled(enableItem);
440     middleItem->setOpacity(itemOpacity);
441     QTest::touchEvent(canvas, touchDevice).press(0, pointInTopItem, canvas);
442     QTest::qWait(50);
443     if (!enableItem || itemOpacity == 0) {
444         // middle item is disabled or has 0 opacity, bottom item receives the event
445         QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
446         QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
447         QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
448         COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed,
449                 makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos))));
450     } else {
451         // middle item ignores event, sends it to the top item (top-most child)
452         QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
453         QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
454         QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
455         COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed,
456                 makeTouchPoint(topItem, pos)));
457     }
458
459     delete topItem;
460     delete middleItem;
461     delete bottomItem;
462     delete canvas;
463 }
464
465 void tst_qquickcanvas::touchEvent_propagation_data()
466 {
467     QTest::addColumn<bool>("acceptEvents");
468     QTest::addColumn<bool>("enableItem");
469     QTest::addColumn<qreal>("itemOpacity");
470
471     QTest::newRow("disable events") << false << true << 1.0;
472     QTest::newRow("disable item") << true << false << 1.0;
473     QTest::newRow("opacity of 0") << true << true << 0.0;
474 }
475
476 void tst_qquickcanvas::clearCanvas()
477 {
478     QQuickCanvas *canvas = new QQuickCanvas;
479     QQuickItem *item = new QQuickItem;
480     item->setParentItem(canvas->rootItem());
481
482     QVERIFY(item->canvas() == canvas);
483
484     delete canvas;
485
486     QVERIFY(item->canvas() == 0);
487
488     delete item;
489 }
490
491 void tst_qquickcanvas::mouseFiltering()
492 {
493     TestTouchItem::clearMousePressCounter();
494
495     QQuickCanvas *canvas = new QQuickCanvas;
496     canvas->resize(250, 250);
497     canvas->move(100, 100);
498     canvas->show();
499
500     TestTouchItem *bottomItem = new TestTouchItem(canvas->rootItem());
501     bottomItem->setObjectName("Bottom Item");
502     bottomItem->setSize(QSizeF(150, 150));
503
504     TestTouchItem *middleItem = new TestTouchItem(bottomItem);
505     middleItem->setObjectName("Middle Item");
506     middleItem->setPos(QPointF(50, 50));
507     middleItem->setSize(QSizeF(150, 150));
508
509     TestTouchItem *topItem = new TestTouchItem(middleItem);
510     topItem->setObjectName("Top Item");
511     topItem->setPos(QPointF(50, 50));
512     topItem->setSize(QSizeF(150, 150));
513
514     QPoint pos(100, 100);
515
516     QTest::mousePress(canvas, Qt::LeftButton, 0, pos);
517
518     // Mouse filtering propagates down the stack, so the
519     // correct order is
520     // 1. middleItem filters event
521     // 2. bottomItem filters event
522     // 3. topItem receives event
523     QTRY_COMPARE(middleItem->mousePressId, 1);
524     QTRY_COMPARE(bottomItem->mousePressId, 2);
525     QTRY_COMPARE(topItem->mousePressId, 3);
526
527     delete canvas;
528 }
529
530 void tst_qquickcanvas::qmlCreation()
531 {
532     QDeclarativeEngine engine;
533     QDeclarativeComponent component(&engine);
534     component.loadUrl(testFileUrl("window.qml"));
535     QObject* created = component.create();
536     QVERIFY(created);
537
538     QQuickCanvas* canvas = qobject_cast<QQuickCanvas*>(created);
539     QVERIFY(canvas);
540     QCOMPARE(canvas->clearColor(), QColor(Qt::green));
541
542     QQuickItem* item = canvas->findChild<QQuickItem*>("item");
543     QVERIFY(item);
544     QCOMPARE(item->canvas(), canvas);
545
546     delete canvas;
547 }
548
549 void tst_qquickcanvas::clearColor()
550 {
551     //### Can we examine rendering to make sure it is really blue?
552     QQuickCanvas *canvas = new QQuickCanvas;
553     canvas->resize(250, 250);
554     canvas->move(100, 100);
555     canvas->setClearColor(Qt::blue);
556     canvas->show();
557     QTest::qWaitForWindowShown(canvas);
558     QCOMPARE(canvas->clearColor(), QColor(Qt::blue));
559     delete canvas;
560 }
561
562 void tst_qquickcanvas::grab()
563 {
564     QQuickCanvas canvas;
565     canvas.setClearColor(Qt::red);
566
567     canvas.resize(250, 250);
568     canvas.show();
569
570     QImage content = canvas.grabFrameBuffer();
571     QCOMPARE(content.width(), canvas.width());
572     QCOMPARE(content.height(), canvas.height());
573     QCOMPARE((uint) content.convertToFormat(QImage::Format_RGB32).pixel(0, 0), (uint) 0xffff0000);
574 }
575
576 void tst_qquickcanvas::multipleWindows()
577 {
578     QList<QQuickCanvas *> windows;
579     for (int i=0; i<6; ++i) {
580         QQuickCanvas *c = new QQuickCanvas();
581         c->setClearColor(Qt::GlobalColor(Qt::red + i));
582         c->resize(300, 200);
583         c->setPos(100 + i * 30, 100 + i * 20);
584         c->show();
585         windows << c;
586         QVERIFY(c->visible());
587     }
588
589     // move them
590     for (int i=0; i<windows.size(); ++i) {
591         QQuickCanvas *c = windows.at(i);
592         c->setPos(c->x() - 10, c->y() - 10);
593     }
594
595     // resize them
596     for (int i=0; i<windows.size(); ++i) {
597         QQuickCanvas *c = windows.at(i);
598         c->resize(200, 150);
599     }
600
601     qDeleteAll(windows);
602 }
603
604 void tst_qquickcanvas::animationsWhileHidden()
605 {
606     QDeclarativeEngine engine;
607     QDeclarativeComponent component(&engine);
608     component.loadUrl(testFileUrl("AnimationsWhileHidden.qml"));
609     QObject* created = component.create();
610
611     QQuickCanvas* canvas = qobject_cast<QQuickCanvas*>(created);
612     QVERIFY(canvas);
613     QVERIFY(canvas->visible());
614
615     // Now hide the window and verify that it went off screen
616     canvas->hide();
617     QTest::qWait(10);
618     QVERIFY(!canvas->visible());
619
620     // Running animaiton should cause it to become visible again shortly.
621     QTRY_VERIFY(canvas->visible());
622
623     delete canvas;
624 }
625
626
627 void tst_qquickcanvas::headless()
628 {
629     QDeclarativeEngine engine;
630     QDeclarativeComponent component(&engine);
631     component.loadUrl(testFileUrl("Headless.qml"));
632     QObject* created = component.create();
633
634     QQuickCanvas* canvas = qobject_cast<QQuickCanvas*>(created);
635     QVERIFY(canvas);
636
637     QTest::qWaitForWindowShown(canvas);
638     QVERIFY(canvas->visible());
639
640     QSignalSpy initialized(canvas, SIGNAL(sceneGraphInitialized()));
641     QSignalSpy invalidated(canvas, SIGNAL(sceneGraphInvalidated()));
642
643     // Verify that the canvas is alive and kicking
644     QVERIFY(canvas->openglContext() != 0);
645
646     // Store the visual result
647     QImage originalContent = canvas->grabFrameBuffer();
648
649     // Hide the canvas and verify signal emittion and GL context deletion
650     canvas->hide();
651     QCOMPARE(invalidated.size(), 1);
652     QVERIFY(canvas->openglContext() == 0);
653
654     // Destroy the native windowing system buffers
655     canvas->destroy();
656     QVERIFY(canvas->handle() == 0);
657
658     // Show and verify that we are back and running
659     canvas->show();
660     QTest::qWaitForWindowShown(canvas);
661
662     QCOMPARE(initialized.size(), 1);
663     QVERIFY(canvas->openglContext() != 0);
664
665     // Verify that the visual output is the same
666     QImage newContent = canvas->grabFrameBuffer();
667
668     QCOMPARE(originalContent, newContent);
669
670
671 }
672
673 void tst_qquickcanvas::focusObject()
674 {
675     QDeclarativeEngine engine;
676     QDeclarativeComponent component(&engine);
677     component.loadUrl(testFileUrl("focus.qml"));
678     QObject *created = component.create();
679     QVERIFY(created);
680
681     QQuickCanvas *canvas = qobject_cast<QQuickCanvas*>(created);
682     QVERIFY(canvas);
683
684     QQuickItem *item1 = canvas->findChild<QQuickItem*>("item1");
685     QVERIFY(item1);
686     item1->setFocus(true);
687     QCOMPARE(item1, canvas->focusObject());
688
689     QQuickItem *item2 = canvas->findChild<QQuickItem*>("item2");
690     QVERIFY(item2);
691     item2->setFocus(true);
692     QCOMPARE(item2, canvas->focusObject());
693
694     delete canvas;
695 }
696
697 QTEST_MAIN(tst_qquickcanvas)
698
699 #include "tst_qquickcanvas.moc"