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