554be2346a8d5eba7b0be975fba53928bc33149f
[profile/ivi/qtdeclarative.git] / tests / auto / declarative / qsgflickable / tst_qsgflickable.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 #include <qtest.h>
42 #include <QtTest/QSignalSpy>
43 #include <QtDeclarative/qdeclarativeengine.h>
44 #include <QtDeclarative/qdeclarativecomponent.h>
45 #include <QtDeclarative/qsgview.h>
46 #include <private/qsgflickable_p.h>
47 #include <private/qdeclarativevaluetype_p.h>
48 #include <math.h>
49 #include "../../../shared/util.h"
50 #include <QtOpenGL/QGLShaderProgram>
51
52 #ifdef Q_OS_SYMBIAN
53 // In Symbian OS test data is located in applications private dir
54 #define SRCDIR "."
55 #endif
56
57 class tst_qsgflickable : public QObject
58 {
59     Q_OBJECT
60 public:
61     tst_qsgflickable();
62
63 private slots:
64     void initTestCase();
65     void cleanupTestCase();
66
67     void create();
68     void horizontalViewportSize();
69     void verticalViewportSize();
70     void properties();
71     void boundsBehavior();
72     void maximumFlickVelocity();
73     void flickDeceleration();
74     void pressDelay();
75     void nestedPressDelay();
76     void flickableDirection();
77     void resizeContent();
78     void returnToBounds();
79     void wheel();
80     void movingAndDragging();
81     void disabled();
82     void flickVelocity();
83     void margins();
84
85 private:
86     QDeclarativeEngine engine;
87
88     void flick(QSGView *canvas, const QPoint &from, const QPoint &to, int duration);
89     template<typename T>
90     T *findItem(QSGItem *parent, const QString &objectName);
91 };
92
93 tst_qsgflickable::tst_qsgflickable()
94 {
95 }
96
97 void tst_qsgflickable::initTestCase()
98 {
99
100 }
101
102 void tst_qsgflickable::cleanupTestCase()
103 {
104
105 }
106
107 void tst_qsgflickable::create()
108 {
109     QDeclarativeEngine engine;
110     QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/flickable01.qml"));
111     QSGFlickable *obj = qobject_cast<QSGFlickable*>(c.create());
112
113     QVERIFY(obj != 0);
114     QCOMPARE(obj->isAtXBeginning(), true);
115     QCOMPARE(obj->isAtXEnd(), false);
116     QCOMPARE(obj->isAtYBeginning(), true);
117     QCOMPARE(obj->isAtYEnd(), false);
118     QCOMPARE(obj->contentX(), 0.);
119     QCOMPARE(obj->contentY(), 0.);
120
121     QCOMPARE(obj->horizontalVelocity(), 0.);
122     QCOMPARE(obj->verticalVelocity(), 0.);
123
124     QCOMPARE(obj->isInteractive(), true);
125     QCOMPARE(obj->boundsBehavior(), QSGFlickable::DragAndOvershootBounds);
126     QCOMPARE(obj->pressDelay(), 0);
127     QCOMPARE(obj->maximumFlickVelocity(), 2500.);
128
129     delete obj;
130 }
131
132 void tst_qsgflickable::horizontalViewportSize()
133 {
134     QDeclarativeEngine engine;
135     QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/flickable02.qml"));
136     QSGFlickable *obj = qobject_cast<QSGFlickable*>(c.create());
137
138     QVERIFY(obj != 0);
139     QCOMPARE(obj->contentWidth(), 800.);
140     QCOMPARE(obj->contentHeight(), 300.);
141     QCOMPARE(obj->isAtXBeginning(), true);
142     QCOMPARE(obj->isAtXEnd(), false);
143     QCOMPARE(obj->isAtYBeginning(), true);
144     QCOMPARE(obj->isAtYEnd(), false);
145
146     delete obj;
147 }
148
149 void tst_qsgflickable::verticalViewportSize()
150 {
151     QDeclarativeEngine engine;
152     QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/flickable03.qml"));
153     QSGFlickable *obj = qobject_cast<QSGFlickable*>(c.create());
154
155     QVERIFY(obj != 0);
156     QCOMPARE(obj->contentWidth(), 200.);
157     QCOMPARE(obj->contentHeight(), 1200.);
158     QCOMPARE(obj->isAtXBeginning(), true);
159     QCOMPARE(obj->isAtXEnd(), false);
160     QCOMPARE(obj->isAtYBeginning(), true);
161     QCOMPARE(obj->isAtYEnd(), false);
162
163     delete obj;
164 }
165
166 void tst_qsgflickable::properties()
167 {
168     QDeclarativeEngine engine;
169     QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/flickable04.qml"));
170     QSGFlickable *obj = qobject_cast<QSGFlickable*>(c.create());
171
172     QVERIFY(obj != 0);
173     QCOMPARE(obj->isInteractive(), false);
174     QCOMPARE(obj->boundsBehavior(), QSGFlickable::StopAtBounds);
175     QCOMPARE(obj->pressDelay(), 200);
176     QCOMPARE(obj->maximumFlickVelocity(), 2000.);
177
178     QVERIFY(obj->property("ok").toBool() == false);
179     QMetaObject::invokeMethod(obj, "check");
180     QVERIFY(obj->property("ok").toBool() == true);
181
182     delete obj;
183 }
184
185 void tst_qsgflickable::boundsBehavior()
186 {
187     QDeclarativeComponent component(&engine);
188     component.setData("import QtQuick 2.0; Flickable { boundsBehavior: Flickable.StopAtBounds }", QUrl::fromLocalFile(""));
189     QSGFlickable *flickable = qobject_cast<QSGFlickable*>(component.create());
190     QSignalSpy spy(flickable, SIGNAL(boundsBehaviorChanged()));
191
192     QVERIFY(flickable);
193     QVERIFY(flickable->boundsBehavior() == QSGFlickable::StopAtBounds);
194
195     flickable->setBoundsBehavior(QSGFlickable::DragAndOvershootBounds);
196     QVERIFY(flickable->boundsBehavior() == QSGFlickable::DragAndOvershootBounds);
197     QCOMPARE(spy.count(),1);
198     flickable->setBoundsBehavior(QSGFlickable::DragAndOvershootBounds);
199     QCOMPARE(spy.count(),1);
200
201     flickable->setBoundsBehavior(QSGFlickable::DragOverBounds);
202     QVERIFY(flickable->boundsBehavior() == QSGFlickable::DragOverBounds);
203     QCOMPARE(spy.count(),2);
204     flickable->setBoundsBehavior(QSGFlickable::DragOverBounds);
205     QCOMPARE(spy.count(),2);
206
207     flickable->setBoundsBehavior(QSGFlickable::StopAtBounds);
208     QVERIFY(flickable->boundsBehavior() == QSGFlickable::StopAtBounds);
209     QCOMPARE(spy.count(),3);
210     flickable->setBoundsBehavior(QSGFlickable::StopAtBounds);
211     QCOMPARE(spy.count(),3);
212 }
213
214 void tst_qsgflickable::maximumFlickVelocity()
215 {
216     QDeclarativeComponent component(&engine);
217     component.setData("import QtQuick 2.0; Flickable { maximumFlickVelocity: 1.0; }", QUrl::fromLocalFile(""));
218     QSGFlickable *flickable = qobject_cast<QSGFlickable*>(component.create());
219     QSignalSpy spy(flickable, SIGNAL(maximumFlickVelocityChanged()));
220
221     QVERIFY(flickable);
222     QCOMPARE(flickable->maximumFlickVelocity(), 1.0);
223
224     flickable->setMaximumFlickVelocity(2.0);
225     QCOMPARE(flickable->maximumFlickVelocity(), 2.0);
226     QCOMPARE(spy.count(),1);
227     flickable->setMaximumFlickVelocity(2.0);
228     QCOMPARE(spy.count(),1);
229 }
230
231 void tst_qsgflickable::flickDeceleration()
232 {
233     QDeclarativeComponent component(&engine);
234     component.setData("import QtQuick 2.0; Flickable { flickDeceleration: 1.0; }", QUrl::fromLocalFile(""));
235     QSGFlickable *flickable = qobject_cast<QSGFlickable*>(component.create());
236     QSignalSpy spy(flickable, SIGNAL(flickDecelerationChanged()));
237
238     QVERIFY(flickable);
239     QCOMPARE(flickable->flickDeceleration(), 1.0);
240
241     flickable->setFlickDeceleration(2.0);
242     QCOMPARE(flickable->flickDeceleration(), 2.0);
243     QCOMPARE(spy.count(),1);
244     flickable->setFlickDeceleration(2.0);
245     QCOMPARE(spy.count(),1);
246 }
247
248 void tst_qsgflickable::pressDelay()
249 {
250     QDeclarativeComponent component(&engine);
251     component.setData("import QtQuick 2.0; Flickable { pressDelay: 100; }", QUrl::fromLocalFile(""));
252     QSGFlickable *flickable = qobject_cast<QSGFlickable*>(component.create());
253     QSignalSpy spy(flickable, SIGNAL(pressDelayChanged()));
254
255     QVERIFY(flickable);
256     QCOMPARE(flickable->pressDelay(), 100);
257
258     flickable->setPressDelay(200);
259     QCOMPARE(flickable->pressDelay(), 200);
260     QCOMPARE(spy.count(),1);
261     flickable->setPressDelay(200);
262     QCOMPARE(spy.count(),1);
263 }
264
265 // QTBUG-17361
266 void tst_qsgflickable::nestedPressDelay()
267 {
268     QSGView *canvas = new QSGView;
269     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/nestedPressDelay.qml"));
270     canvas->show();
271     canvas->requestActivateWindow();
272     QVERIFY(canvas->rootObject() != 0);
273
274     QSGFlickable *outer = qobject_cast<QSGFlickable*>(canvas->rootObject());
275     QVERIFY(outer != 0);
276
277     QSGFlickable *inner = canvas->rootObject()->findChild<QSGFlickable*>("innerFlickable");
278     QVERIFY(inner != 0);
279
280     QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(150, 150));
281     // the MouseArea is not pressed immediately
282     QVERIFY(outer->property("pressed").toBool() == false);
283
284     // The outer pressDelay will prevail (50ms, vs. 10sec)
285     // QTRY_VERIFY() has 5sec timeout, so will timeout well within 10sec.
286     QTRY_VERIFY(outer->property("pressed").toBool() == true);
287
288     QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(150, 150));
289
290     delete canvas;
291 }
292
293 void tst_qsgflickable::flickableDirection()
294 {
295     QDeclarativeComponent component(&engine);
296     component.setData("import QtQuick 2.0; Flickable { flickableDirection: Flickable.VerticalFlick; }", QUrl::fromLocalFile(""));
297     QSGFlickable *flickable = qobject_cast<QSGFlickable*>(component.create());
298     QSignalSpy spy(flickable, SIGNAL(flickableDirectionChanged()));
299
300     QVERIFY(flickable);
301     QCOMPARE(flickable->flickableDirection(), QSGFlickable::VerticalFlick);
302
303     flickable->setFlickableDirection(QSGFlickable::HorizontalAndVerticalFlick);
304     QCOMPARE(flickable->flickableDirection(), QSGFlickable::HorizontalAndVerticalFlick);
305     QCOMPARE(spy.count(),1);
306
307     flickable->setFlickableDirection(QSGFlickable::AutoFlickDirection);
308     QCOMPARE(flickable->flickableDirection(), QSGFlickable::AutoFlickDirection);
309     QCOMPARE(spy.count(),2);
310
311     flickable->setFlickableDirection(QSGFlickable::HorizontalFlick);
312     QCOMPARE(flickable->flickableDirection(), QSGFlickable::HorizontalFlick);
313     QCOMPARE(spy.count(),3);
314
315     flickable->setFlickableDirection(QSGFlickable::HorizontalFlick);
316     QCOMPARE(flickable->flickableDirection(), QSGFlickable::HorizontalFlick);
317     QCOMPARE(spy.count(),3);
318 }
319
320 // QtQuick 1.1
321 void tst_qsgflickable::resizeContent()
322 {
323     QDeclarativeEngine engine;
324     QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/resize.qml"));
325     QSGItem *root = qobject_cast<QSGItem*>(c.create());
326     QSGFlickable *obj = findItem<QSGFlickable>(root, "flick");
327
328     QVERIFY(obj != 0);
329     QCOMPARE(obj->contentX(), 0.);
330     QCOMPARE(obj->contentY(), 0.);
331     QCOMPARE(obj->contentWidth(), 300.);
332     QCOMPARE(obj->contentHeight(), 300.);
333
334     QMetaObject::invokeMethod(root, "resizeContent");
335
336     QCOMPARE(obj->contentX(), 100.);
337     QCOMPARE(obj->contentY(), 100.);
338     QCOMPARE(obj->contentWidth(), 600.);
339     QCOMPARE(obj->contentHeight(), 600.);
340
341     delete root;
342 }
343
344 // QtQuick 1.1
345 void tst_qsgflickable::returnToBounds()
346 {
347     QDeclarativeEngine engine;
348     QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/resize.qml"));
349     QSGItem *root = qobject_cast<QSGItem*>(c.create());
350     QSGFlickable *obj = findItem<QSGFlickable>(root, "flick");
351
352     QVERIFY(obj != 0);
353     QCOMPARE(obj->contentX(), 0.);
354     QCOMPARE(obj->contentY(), 0.);
355     QCOMPARE(obj->contentWidth(), 300.);
356     QCOMPARE(obj->contentHeight(), 300.);
357
358     obj->setContentX(100);
359     obj->setContentY(400);
360     QTRY_COMPARE(obj->contentX(), 100.);
361     QTRY_COMPARE(obj->contentY(), 400.);
362
363     QMetaObject::invokeMethod(root, "returnToBounds");
364
365     QTRY_COMPARE(obj->contentX(), 0.);
366     QTRY_COMPARE(obj->contentY(), 0.);
367
368     delete root;
369 }
370
371 void tst_qsgflickable::wheel()
372 {
373     QSGView *canvas = new QSGView;
374     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/wheel.qml"));
375     canvas->show();
376     canvas->requestActivateWindow();
377     QVERIFY(canvas->rootObject() != 0);
378
379     QSGFlickable *flick = canvas->rootObject()->findChild<QSGFlickable*>("flick");
380     QVERIFY(flick != 0);
381
382     {
383         QWheelEvent event(QPoint(200, 200), -120, Qt::NoButton, Qt::NoModifier, Qt::Vertical);
384         event.setAccepted(false);
385         QApplication::sendEvent(canvas, &event);
386     }
387
388     QTRY_VERIFY(flick->contentY() > 0);
389     QVERIFY(flick->contentX() == 0);
390
391     flick->setContentY(0);
392     QVERIFY(flick->contentY() == 0);
393
394     {
395         QWheelEvent event(QPoint(200, 200), -120, Qt::NoButton, Qt::NoModifier, Qt::Horizontal);
396         event.setAccepted(false);
397         QApplication::sendEvent(canvas, &event);
398     }
399
400     QTRY_VERIFY(flick->contentX() > 0);
401     QVERIFY(flick->contentY() == 0);
402
403     delete canvas;
404 }
405
406 void tst_qsgflickable::movingAndDragging()
407 {
408     QSGView *canvas = new QSGView;
409     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/flickable03.qml"));
410     canvas->show();
411     canvas->requestActivateWindow();
412     QTest::qWaitForWindowShown(canvas);
413     QVERIFY(canvas->rootObject() != 0);
414
415     QSGFlickable *flickable = qobject_cast<QSGFlickable*>(canvas->rootObject());
416     QVERIFY(flickable != 0);
417
418     QSignalSpy vDragSpy(flickable, SIGNAL(draggingVerticallyChanged()));
419     QSignalSpy hDragSpy(flickable, SIGNAL(draggingHorizontallyChanged()));
420     QSignalSpy dragSpy(flickable, SIGNAL(draggingChanged()));
421     QSignalSpy vMoveSpy(flickable, SIGNAL(movingVerticallyChanged()));
422     QSignalSpy hMoveSpy(flickable, SIGNAL(movingHorizontallyChanged()));
423     QSignalSpy moveSpy(flickable, SIGNAL(movingChanged()));
424     QSignalSpy dragStartSpy(flickable, SIGNAL(dragStarted()));
425     QSignalSpy dragEndSpy(flickable, SIGNAL(dragEnded()));
426
427     //Vertical
428     QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50, 90));
429
430     QTest::mouseMove(canvas, QPoint(50, 80));
431     QTest::mouseMove(canvas, QPoint(50, 70));
432     QTest::mouseMove(canvas, QPoint(50, 60));
433
434     QMouseEvent moveEvent(QEvent::MouseMove, QPoint(50, 80), Qt::LeftButton, Qt::LeftButton, 0);
435
436     QVERIFY(!flickable->isDraggingHorizontally());
437     QVERIFY(flickable->isDraggingVertically());
438     QVERIFY(flickable->isDragging());
439     QCOMPARE(vDragSpy.count(), 1);
440     QCOMPARE(dragSpy.count(), 1);
441     QCOMPARE(hDragSpy.count(), 0);
442     QCOMPARE(dragStartSpy.count(), 1);
443     QCOMPARE(dragEndSpy.count(), 0);
444
445     QVERIFY(!flickable->isMovingHorizontally());
446     QVERIFY(flickable->isMovingVertically());
447     QVERIFY(flickable->isMoving());
448     QCOMPARE(vMoveSpy.count(), 1);
449     QCOMPARE(moveSpy.count(), 1);
450     QCOMPARE(hMoveSpy.count(), 0);
451
452     QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50, 60));
453
454     QTRY_VERIFY(!flickable->isDraggingVertically());
455     QVERIFY(!flickable->isDragging());
456     QCOMPARE(vDragSpy.count(), 2);
457     QCOMPARE(dragSpy.count(), 2);
458     QCOMPARE(hDragSpy.count(), 0);
459     QCOMPARE(dragStartSpy.count(), 1);
460     QCOMPARE(dragEndSpy.count(), 1);
461
462     // wait for any motion to end
463     QTRY_VERIFY(flickable->isMoving() == false);
464
465     //Horizontal
466     vDragSpy.clear();
467     hDragSpy.clear();
468     dragSpy.clear();
469     vMoveSpy.clear();
470     hMoveSpy.clear();
471     moveSpy.clear();
472     dragStartSpy.clear();
473     dragEndSpy.clear();
474
475     QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(90, 50));
476
477     QTest::mouseMove(canvas, QPoint(80, 50));
478     QTest::mouseMove(canvas, QPoint(70, 50));
479     QTest::mouseMove(canvas, QPoint(60, 50));
480
481     QVERIFY(flickable->isDraggingHorizontally());
482     QVERIFY(flickable->isDragging());
483     QCOMPARE(vDragSpy.count(), 0);
484     QCOMPARE(dragSpy.count(), 1);
485     QCOMPARE(hDragSpy.count(), 1);
486     QCOMPARE(dragStartSpy.count(), 1);
487     QCOMPARE(dragEndSpy.count(), 0);
488
489     QVERIFY(!flickable->isMovingVertically());
490     QVERIFY(flickable->isMovingHorizontally());
491     QVERIFY(flickable->isMoving());
492     QCOMPARE(vMoveSpy.count(), 0);
493     QCOMPARE(moveSpy.count(), 1);
494     QCOMPARE(hMoveSpy.count(), 1);
495
496     QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(60, 50));
497
498     QTRY_VERIFY(!flickable->isDraggingHorizontally());
499     QVERIFY(!flickable->isDragging());
500     QCOMPARE(vDragSpy.count(), 0);
501     QCOMPARE(dragSpy.count(), 2);
502     QCOMPARE(hDragSpy.count(), 2);
503     QCOMPARE(dragStartSpy.count(), 1);
504     QCOMPARE(dragEndSpy.count(), 1);
505
506     // Don't test moving because a flick could occur
507
508     delete canvas;
509 }
510
511 void tst_qsgflickable::disabled()
512 {
513     QSGView *canvas = new QSGView;
514     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/disabled.qml"));
515     canvas->show();
516     canvas->requestActivateWindow();
517     QVERIFY(canvas->rootObject() != 0);
518
519     QSGFlickable *flick = canvas->rootObject()->findChild<QSGFlickable*>("flickable");
520     QVERIFY(flick != 0);
521
522     QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50, 90));
523
524     QTest::mouseMove(canvas, QPoint(50, 80));
525     QTest::mouseMove(canvas, QPoint(50, 70));
526     QTest::mouseMove(canvas, QPoint(50, 60));
527
528     QVERIFY(flick->isMoving() == false);
529
530     QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50, 60));
531
532     // verify that mouse clicks on other elements still work (QTBUG-20584)
533     QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50, 10));
534     QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50, 10));
535
536     QTRY_VERIFY(canvas->rootObject()->property("clicked").toBool() == true);
537 }
538
539 void tst_qsgflickable::flickVelocity()
540 {
541 #ifdef Q_WS_MAC
542     QSKIP("Producing flicks on Mac CI impossible due to timing problems", SkipAll);
543 #endif
544
545     QSGView *canvas = new QSGView;
546     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/flickable03.qml"));
547     canvas->show();
548     canvas->requestActivateWindow();
549     QVERIFY(canvas->rootObject() != 0);
550
551     QSGFlickable *flickable = qobject_cast<QSGFlickable*>(canvas->rootObject());
552     QVERIFY(flickable != 0);
553
554     // flick up
555     flick(canvas, QPoint(20,190), QPoint(20, 50), 200);
556     QVERIFY(flickable->verticalVelocity() > 0.0);
557     QTRY_VERIFY(flickable->verticalVelocity() == 0.0);
558
559     // flick down
560     flick(canvas, QPoint(20,10), QPoint(20, 140), 200);
561     QVERIFY(flickable->verticalVelocity() < 0.0);
562     QTRY_VERIFY(flickable->verticalVelocity() == 0.0);
563
564     delete canvas;
565 }
566
567 void tst_qsgflickable::margins()
568 {
569     QDeclarativeEngine engine;
570     QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/margins.qml"));
571     QSGItem *root = qobject_cast<QSGItem*>(c.create());
572     QSGFlickable *obj = qobject_cast<QSGFlickable*>(root);
573     QVERIFY(obj != 0);
574
575     // starting state
576     QCOMPARE(obj->contentX(), -40.);
577     QCOMPARE(obj->contentY(), -20.);
578     QCOMPARE(obj->contentWidth(), 1600.);
579     QCOMPARE(obj->contentHeight(), 600.);
580     QCOMPARE(obj->xOrigin(), 0.);
581     QCOMPARE(obj->yOrigin(), 0.);
582
583     // Reduce left margin
584     obj->setLeftMargin(30);
585     QTRY_COMPARE(obj->contentX(), -30.);
586
587     // Reduce top margin
588     obj->setTopMargin(20);
589     QTRY_COMPARE(obj->contentY(), -20.);
590
591     // position to the far right, including margin
592     obj->setContentX(1600 + 50 - obj->width());
593     obj->returnToBounds();
594     QTest::qWait(200);
595     QCOMPARE(obj->contentX(), 1600. + 50. - obj->width());
596
597     // position beyond the far right, including margin
598     obj->setContentX(1600 + 50 - obj->width() + 1.);
599     obj->returnToBounds();
600     QTRY_COMPARE(obj->contentX(), 1600. + 50. - obj->width());
601
602     // Reduce right margin
603     obj->setRightMargin(40);
604     QTRY_COMPARE(obj->contentX(), 1600. + 40. - obj->width());
605     QCOMPARE(obj->contentWidth(), 1600.);
606
607     // position to the far bottom, including margin
608     obj->setContentY(600 + 30 - obj->height());
609     obj->returnToBounds();
610     QTest::qWait(200);
611     QCOMPARE(obj->contentY(), 600. + 30. - obj->height());
612
613     // position beyond the far bottom, including margin
614     obj->setContentY(600 + 30 - obj->height() + 1.);
615     obj->returnToBounds();
616     QTRY_COMPARE(obj->contentY(), 600. + 30. - obj->height());
617
618     // Reduce bottom margin
619     obj->setBottomMargin(20);
620     QTRY_COMPARE(obj->contentY(), 600. + 20. - obj->height());
621     QCOMPARE(obj->contentHeight(), 600.);
622
623     delete root;
624 }
625
626 void tst_qsgflickable::flick(QSGView *canvas, const QPoint &from, const QPoint &to, int duration)
627 {
628     const int pointCount = 5;
629     QPoint diff = to - from;
630
631     // send press, five equally spaced moves, and release.
632     QTest::mousePress(canvas, Qt::LeftButton, 0, from);
633
634     for (int i = 0; i < pointCount; ++i) {
635         QMouseEvent mv(QEvent::MouseMove, from + (i+1)*diff/pointCount, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
636         QApplication::sendEvent(canvas, &mv);
637         QTest::qWait(duration/pointCount);
638         QCoreApplication::processEvents();
639     }
640
641     QTest::mouseRelease(canvas, Qt::LeftButton, 0, to);
642 }
643
644 template<typename T>
645 T *tst_qsgflickable::findItem(QSGItem *parent, const QString &objectName)
646 {
647     const QMetaObject &mo = T::staticMetaObject;
648     //qDebug() << parent->childItems().count() << "children";
649     for (int i = 0; i < parent->childItems().count(); ++i) {
650         QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
651         if(!item)
652             continue;
653         //qDebug() << "try" << item;
654         if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
655             return static_cast<T*>(item);
656         }
657         item = findItem<T>(item, objectName);
658         if (item)
659             return static_cast<T*>(item);
660     }
661
662     return 0;
663 }
664
665 QTEST_MAIN(tst_qsgflickable)
666
667 #include "tst_qsgflickable.moc"