90f4b6c3118b071ce1857c35a721357e8be504f7
[profile/ivi/qtdeclarative.git] / tests / auto / quick / 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 <QtGui/QStyleHints>
44 #include <QtQml/qqmlengine.h>
45 #include <QtQml/qqmlcomponent.h>
46 #include <QtQuick/qquickview.h>
47 #include <private/qquickflickable_p.h>
48 #include <private/qquickflickable_p_p.h>
49 #include <private/qquicktransition_p.h>
50 #include <private/qqmlvaluetype_p.h>
51 #include <math.h>
52 #include "../../shared/util.h"
53 #include "../shared/viewtestutil.h"
54 #include "../shared/visualtestutil.h"
55
56 using namespace QQuickViewTestUtil;
57 using namespace QQuickVisualTestUtil;
58
59 class tst_qquickflickable : public QQmlDataTest
60 {
61     Q_OBJECT
62 public:
63
64 private slots:
65     void create();
66     void horizontalViewportSize();
67     void verticalViewportSize();
68     void properties();
69     void boundsBehavior();
70     void rebound();
71     void maximumFlickVelocity();
72     void flickDeceleration();
73     void pressDelay();
74     void nestedPressDelay();
75     void flickableDirection();
76     void resizeContent();
77     void returnToBounds();
78     void returnToBounds_data();
79     void wheel();
80     void movingAndFlicking();
81     void movingAndFlicking_data();
82     void movingAndDragging();
83     void movingAndDragging_data();
84     void flickOnRelease();
85     void pressWhileFlicking();
86     void disabled();
87     void flickVelocity();
88     void margins();
89     void cancelOnMouseGrab();
90     void clickAndDragWhenTransformed();
91
92 private:
93     QQmlEngine engine;
94 };
95
96 void tst_qquickflickable::create()
97 {
98     QQmlEngine engine;
99     QQmlComponent c(&engine, testFileUrl("flickable01.qml"));
100     QQuickFlickable *obj = qobject_cast<QQuickFlickable*>(c.create());
101
102     QVERIFY(obj != 0);
103     QCOMPARE(obj->isAtXBeginning(), true);
104     QCOMPARE(obj->isAtXEnd(), false);
105     QCOMPARE(obj->isAtYBeginning(), true);
106     QCOMPARE(obj->isAtYEnd(), false);
107     QCOMPARE(obj->contentX(), 0.);
108     QCOMPARE(obj->contentY(), 0.);
109
110     QCOMPARE(obj->horizontalVelocity(), 0.);
111     QCOMPARE(obj->verticalVelocity(), 0.);
112
113     QCOMPARE(obj->isInteractive(), true);
114     QCOMPARE(obj->boundsBehavior(), QQuickFlickable::DragAndOvershootBounds);
115     QCOMPARE(obj->pressDelay(), 0);
116     QCOMPARE(obj->maximumFlickVelocity(), 2500.);
117
118     delete obj;
119 }
120
121 void tst_qquickflickable::horizontalViewportSize()
122 {
123     QQmlEngine engine;
124     QQmlComponent c(&engine, testFileUrl("flickable02.qml"));
125     QQuickFlickable *obj = qobject_cast<QQuickFlickable*>(c.create());
126
127     QVERIFY(obj != 0);
128     QCOMPARE(obj->contentWidth(), 800.);
129     QCOMPARE(obj->contentHeight(), 300.);
130     QCOMPARE(obj->isAtXBeginning(), true);
131     QCOMPARE(obj->isAtXEnd(), false);
132     QCOMPARE(obj->isAtYBeginning(), true);
133     QCOMPARE(obj->isAtYEnd(), false);
134
135     delete obj;
136 }
137
138 void tst_qquickflickable::verticalViewportSize()
139 {
140     QQmlEngine engine;
141     QQmlComponent c(&engine, testFileUrl("flickable03.qml"));
142     QQuickFlickable *obj = qobject_cast<QQuickFlickable*>(c.create());
143
144     QVERIFY(obj != 0);
145     QCOMPARE(obj->contentWidth(), 200.);
146     QCOMPARE(obj->contentHeight(), 6000.);
147     QCOMPARE(obj->isAtXBeginning(), true);
148     QCOMPARE(obj->isAtXEnd(), false);
149     QCOMPARE(obj->isAtYBeginning(), true);
150     QCOMPARE(obj->isAtYEnd(), false);
151
152     delete obj;
153 }
154
155 void tst_qquickflickable::properties()
156 {
157     QQmlEngine engine;
158     QQmlComponent c(&engine, testFileUrl("flickable04.qml"));
159     QQuickFlickable *obj = qobject_cast<QQuickFlickable*>(c.create());
160
161     QVERIFY(obj != 0);
162     QCOMPARE(obj->isInteractive(), false);
163     QCOMPARE(obj->boundsBehavior(), QQuickFlickable::StopAtBounds);
164     QCOMPARE(obj->pressDelay(), 200);
165     QCOMPARE(obj->maximumFlickVelocity(), 2000.);
166
167     QVERIFY(obj->property("ok").toBool() == false);
168     QMetaObject::invokeMethod(obj, "check");
169     QVERIFY(obj->property("ok").toBool() == true);
170
171     delete obj;
172 }
173
174 void tst_qquickflickable::boundsBehavior()
175 {
176     QQmlComponent component(&engine);
177     component.setData("import QtQuick 2.0; Flickable { boundsBehavior: Flickable.StopAtBounds }", QUrl::fromLocalFile(""));
178     QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(component.create());
179     QSignalSpy spy(flickable, SIGNAL(boundsBehaviorChanged()));
180
181     QVERIFY(flickable);
182     QVERIFY(flickable->boundsBehavior() == QQuickFlickable::StopAtBounds);
183
184     flickable->setBoundsBehavior(QQuickFlickable::DragAndOvershootBounds);
185     QVERIFY(flickable->boundsBehavior() == QQuickFlickable::DragAndOvershootBounds);
186     QCOMPARE(spy.count(),1);
187     flickable->setBoundsBehavior(QQuickFlickable::DragAndOvershootBounds);
188     QCOMPARE(spy.count(),1);
189
190     flickable->setBoundsBehavior(QQuickFlickable::DragOverBounds);
191     QVERIFY(flickable->boundsBehavior() == QQuickFlickable::DragOverBounds);
192     QCOMPARE(spy.count(),2);
193     flickable->setBoundsBehavior(QQuickFlickable::DragOverBounds);
194     QCOMPARE(spy.count(),2);
195
196     flickable->setBoundsBehavior(QQuickFlickable::StopAtBounds);
197     QVERIFY(flickable->boundsBehavior() == QQuickFlickable::StopAtBounds);
198     QCOMPARE(spy.count(),3);
199     flickable->setBoundsBehavior(QQuickFlickable::StopAtBounds);
200     QCOMPARE(spy.count(),3);
201 }
202
203 void tst_qquickflickable::rebound()
204 {
205 #ifdef Q_OS_MAC
206     QSKIP("Producing flicks on Mac CI impossible due to timing problems");
207 #endif
208
209     QQuickView *canvas = new QQuickView;
210     canvas->setSource(testFileUrl("rebound.qml"));
211     canvas->show();
212     canvas->requestActivateWindow();
213     QVERIFY(canvas->rootObject() != 0);
214
215     QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(canvas->rootObject());
216     QVERIFY(flickable != 0);
217
218     QQuickTransition *rebound = canvas->rootObject()->findChild<QQuickTransition*>("rebound");
219     QVERIFY(rebound);
220     QSignalSpy reboundSpy(rebound, SIGNAL(runningChanged()));
221
222     QSignalSpy movementStartedSpy(flickable, SIGNAL(movementStarted()));
223     QSignalSpy movementEndedSpy(flickable, SIGNAL(movementEnded()));
224     QSignalSpy vMoveSpy(flickable, SIGNAL(movingVerticallyChanged()));
225     QSignalSpy hMoveSpy(flickable, SIGNAL(movingHorizontallyChanged()));
226
227     // flick and test the transition is run
228     flick(canvas, QPoint(20,20), QPoint(120,120), 200);
229
230     QTRY_COMPARE(canvas->rootObject()->property("transitionsStarted").toInt(), 2);
231     QCOMPARE(hMoveSpy.count(), 1);
232     QCOMPARE(vMoveSpy.count(), 1);
233     QCOMPARE(movementStartedSpy.count(), 1);
234     QCOMPARE(movementEndedSpy.count(), 0);
235     QVERIFY(rebound->running());
236
237     QTRY_VERIFY(!flickable->isMoving());
238     QCOMPARE(flickable->contentX(), 0.0);
239     QCOMPARE(flickable->contentY(), 0.0);
240
241     QCOMPARE(hMoveSpy.count(), 2);
242     QCOMPARE(vMoveSpy.count(), 2);
243     QCOMPARE(movementStartedSpy.count(), 1);
244     QCOMPARE(movementEndedSpy.count(), 1);
245     QCOMPARE(canvas->rootObject()->property("transitionsStarted").toInt(), 2);
246     QVERIFY(!rebound->running());
247     QCOMPARE(reboundSpy.count(), 2);
248
249     hMoveSpy.clear();
250     vMoveSpy.clear();
251     movementStartedSpy.clear();
252     movementEndedSpy.clear();
253     canvas->rootObject()->setProperty("transitionsStarted", 0);
254     canvas->rootObject()->setProperty("transitionsFinished", 0);
255
256     // flick and trigger the transition multiple times
257     // (moving signals are emitted as soon as the first transition starts)
258     flick(canvas, QPoint(20,20), QPoint(120,120), 200);     // both x and y will bounce back
259     flick(canvas, QPoint(20,120), QPoint(120,20), 200);     // only x will bounce back
260
261     QVERIFY(flickable->isMoving());
262     QVERIFY(canvas->rootObject()->property("transitionsStarted").toInt() >= 1);
263     QCOMPARE(hMoveSpy.count(), 1);
264     QCOMPARE(vMoveSpy.count(), 1);
265     QCOMPARE(movementStartedSpy.count(), 1);
266
267     QTRY_VERIFY(!flickable->isMoving());
268     QCOMPARE(flickable->contentX(), 0.0);
269
270     // moving started/stopped signals should only have been emitted once,
271     // and when they are, all transitions should have finished
272     QCOMPARE(hMoveSpy.count(), 2);
273     QCOMPARE(vMoveSpy.count(), 2);
274     QCOMPARE(movementStartedSpy.count(), 1);
275     QCOMPARE(movementEndedSpy.count(), 1);
276
277     hMoveSpy.clear();
278     vMoveSpy.clear();
279     movementStartedSpy.clear();
280     movementEndedSpy.clear();
281     canvas->rootObject()->setProperty("transitionsStarted", 0);
282     canvas->rootObject()->setProperty("transitionsFinished", 0);
283
284     // disable and the default transition should run
285     // (i.e. moving but transition->running = false)
286     canvas->rootObject()->setProperty("transitionEnabled", false);
287
288     flick(canvas, QPoint(20,20), QPoint(120,120), 200);
289     QCOMPARE(canvas->rootObject()->property("transitionsStarted").toInt(), 0);
290     QCOMPARE(hMoveSpy.count(), 1);
291     QCOMPARE(vMoveSpy.count(), 1);
292     QCOMPARE(movementStartedSpy.count(), 1);
293     QCOMPARE(movementEndedSpy.count(), 0);
294
295     QTRY_VERIFY(!flickable->isMoving());
296     QCOMPARE(hMoveSpy.count(), 2);
297     QCOMPARE(vMoveSpy.count(), 2);
298     QCOMPARE(movementStartedSpy.count(), 1);
299     QCOMPARE(movementEndedSpy.count(), 1);
300     QCOMPARE(canvas->rootObject()->property("transitionsStarted").toInt(), 0);
301
302     delete canvas;
303 }
304
305 void tst_qquickflickable::maximumFlickVelocity()
306 {
307     QQmlComponent component(&engine);
308     component.setData("import QtQuick 2.0; Flickable { maximumFlickVelocity: 1.0; }", QUrl::fromLocalFile(""));
309     QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(component.create());
310     QSignalSpy spy(flickable, SIGNAL(maximumFlickVelocityChanged()));
311
312     QVERIFY(flickable);
313     QCOMPARE(flickable->maximumFlickVelocity(), 1.0);
314
315     flickable->setMaximumFlickVelocity(2.0);
316     QCOMPARE(flickable->maximumFlickVelocity(), 2.0);
317     QCOMPARE(spy.count(),1);
318     flickable->setMaximumFlickVelocity(2.0);
319     QCOMPARE(spy.count(),1);
320 }
321
322 void tst_qquickflickable::flickDeceleration()
323 {
324     QQmlComponent component(&engine);
325     component.setData("import QtQuick 2.0; Flickable { flickDeceleration: 1.0; }", QUrl::fromLocalFile(""));
326     QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(component.create());
327     QSignalSpy spy(flickable, SIGNAL(flickDecelerationChanged()));
328
329     QVERIFY(flickable);
330     QCOMPARE(flickable->flickDeceleration(), 1.0);
331
332     flickable->setFlickDeceleration(2.0);
333     QCOMPARE(flickable->flickDeceleration(), 2.0);
334     QCOMPARE(spy.count(),1);
335     flickable->setFlickDeceleration(2.0);
336     QCOMPARE(spy.count(),1);
337 }
338
339 void tst_qquickflickable::pressDelay()
340 {
341     QQmlComponent component(&engine);
342     component.setData("import QtQuick 2.0; Flickable { pressDelay: 100; }", QUrl::fromLocalFile(""));
343     QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(component.create());
344     QSignalSpy spy(flickable, SIGNAL(pressDelayChanged()));
345
346     QVERIFY(flickable);
347     QCOMPARE(flickable->pressDelay(), 100);
348
349     flickable->setPressDelay(200);
350     QCOMPARE(flickable->pressDelay(), 200);
351     QCOMPARE(spy.count(),1);
352     flickable->setPressDelay(200);
353     QCOMPARE(spy.count(),1);
354 }
355
356 // QTBUG-17361
357 void tst_qquickflickable::nestedPressDelay()
358 {
359     QQuickView *canvas = new QQuickView;
360     canvas->setSource(testFileUrl("nestedPressDelay.qml"));
361     canvas->show();
362     canvas->requestActivateWindow();
363     QVERIFY(canvas->rootObject() != 0);
364
365     QQuickFlickable *outer = qobject_cast<QQuickFlickable*>(canvas->rootObject());
366     QVERIFY(outer != 0);
367
368     QQuickFlickable *inner = canvas->rootObject()->findChild<QQuickFlickable*>("innerFlickable");
369     QVERIFY(inner != 0);
370
371     QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(150, 150));
372     // the MouseArea is not pressed immediately
373     QVERIFY(outer->property("pressed").toBool() == false);
374
375     // The outer pressDelay will prevail (50ms, vs. 10sec)
376     // QTRY_VERIFY() has 5sec timeout, so will timeout well within 10sec.
377     QTRY_VERIFY(outer->property("pressed").toBool() == true);
378
379     QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(150, 150));
380
381     delete canvas;
382 }
383
384 void tst_qquickflickable::flickableDirection()
385 {
386     QQmlComponent component(&engine);
387     component.setData("import QtQuick 2.0; Flickable { flickableDirection: Flickable.VerticalFlick; }", QUrl::fromLocalFile(""));
388     QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(component.create());
389     QSignalSpy spy(flickable, SIGNAL(flickableDirectionChanged()));
390
391     QVERIFY(flickable);
392     QCOMPARE(flickable->flickableDirection(), QQuickFlickable::VerticalFlick);
393
394     flickable->setFlickableDirection(QQuickFlickable::HorizontalAndVerticalFlick);
395     QCOMPARE(flickable->flickableDirection(), QQuickFlickable::HorizontalAndVerticalFlick);
396     QCOMPARE(spy.count(),1);
397
398     flickable->setFlickableDirection(QQuickFlickable::AutoFlickDirection);
399     QCOMPARE(flickable->flickableDirection(), QQuickFlickable::AutoFlickDirection);
400     QCOMPARE(spy.count(),2);
401
402     flickable->setFlickableDirection(QQuickFlickable::HorizontalFlick);
403     QCOMPARE(flickable->flickableDirection(), QQuickFlickable::HorizontalFlick);
404     QCOMPARE(spy.count(),3);
405
406     flickable->setFlickableDirection(QQuickFlickable::HorizontalFlick);
407     QCOMPARE(flickable->flickableDirection(), QQuickFlickable::HorizontalFlick);
408     QCOMPARE(spy.count(),3);
409 }
410
411 // QtQuick 1.1
412 void tst_qquickflickable::resizeContent()
413 {
414     QQmlEngine engine;
415     QQmlComponent c(&engine, testFileUrl("resize.qml"));
416     QQuickItem *root = qobject_cast<QQuickItem*>(c.create());
417     QQuickFlickable *obj = findItem<QQuickFlickable>(root, "flick");
418
419     QVERIFY(obj != 0);
420     QCOMPARE(obj->contentX(), 0.);
421     QCOMPARE(obj->contentY(), 0.);
422     QCOMPARE(obj->contentWidth(), 300.);
423     QCOMPARE(obj->contentHeight(), 300.);
424
425     QMetaObject::invokeMethod(root, "resizeContent");
426
427     QCOMPARE(obj->contentX(), 100.);
428     QCOMPARE(obj->contentY(), 100.);
429     QCOMPARE(obj->contentWidth(), 600.);
430     QCOMPARE(obj->contentHeight(), 600.);
431
432     delete root;
433 }
434
435 void tst_qquickflickable::returnToBounds()
436 {
437     QFETCH(bool, setRebound);
438
439     QQuickView *canvas = new QQuickView;
440     canvas->rootContext()->setContextProperty("setRebound", setRebound);
441     canvas->setSource(testFileUrl("resize.qml"));
442     QVERIFY(canvas->rootObject() != 0);
443     QQuickFlickable *obj = findItem<QQuickFlickable>(canvas->rootObject(), "flick");
444
445     QQuickTransition *rebound = canvas->rootObject()->findChild<QQuickTransition*>("rebound");
446     QVERIFY(rebound);
447     QSignalSpy reboundSpy(rebound, SIGNAL(runningChanged()));
448
449     QVERIFY(obj != 0);
450     QCOMPARE(obj->contentX(), 0.);
451     QCOMPARE(obj->contentY(), 0.);
452     QCOMPARE(obj->contentWidth(), 300.);
453     QCOMPARE(obj->contentHeight(), 300.);
454
455     obj->setContentX(100);
456     obj->setContentY(400);
457     QTRY_COMPARE(obj->contentX(), 100.);
458     QTRY_COMPARE(obj->contentY(), 400.);
459
460     QMetaObject::invokeMethod(canvas->rootObject(), "returnToBounds");
461
462     if (setRebound)
463         QTRY_VERIFY(rebound->running());
464
465     QTRY_COMPARE(obj->contentX(), 0.);
466     QTRY_COMPARE(obj->contentY(), 0.);
467
468     QVERIFY(!rebound->running());
469     QCOMPARE(reboundSpy.count(), setRebound ? 2 : 0);
470
471     delete canvas;
472 }
473
474 void tst_qquickflickable::returnToBounds_data()
475 {
476     QTest::addColumn<bool>("setRebound");
477
478     QTest::newRow("with bounds transition") << true;
479     QTest::newRow("with bounds transition") << false;
480 }
481
482 void tst_qquickflickable::wheel()
483 {
484     QQuickView *canvas = new QQuickView;
485     canvas->setSource(testFileUrl("wheel.qml"));
486     canvas->show();
487     canvas->requestActivateWindow();
488     QVERIFY(canvas->rootObject() != 0);
489
490     QQuickFlickable *flick = canvas->rootObject()->findChild<QQuickFlickable*>("flick");
491     QVERIFY(flick != 0);
492
493     {
494         QPoint pos(200, 200);
495         QWheelEvent event(pos, canvas->mapToGlobal(pos), QPoint(), QPoint(0,-120), -120, Qt::Vertical, Qt::NoButton, Qt::NoModifier);
496         event.setAccepted(false);
497         QGuiApplication::sendEvent(canvas, &event);
498     }
499
500     QTRY_VERIFY(flick->contentY() > 0);
501     QVERIFY(flick->contentX() == 0);
502
503     flick->setContentY(0);
504     QVERIFY(flick->contentY() == 0);
505
506     {
507         QPoint pos(200, 200);
508         QWheelEvent event(pos, canvas->mapToGlobal(pos), QPoint(), QPoint(-120,0), -120, Qt::Horizontal, Qt::NoButton, Qt::NoModifier);
509
510         event.setAccepted(false);
511         QGuiApplication::sendEvent(canvas, &event);
512     }
513
514     QTRY_VERIFY(flick->contentX() > 0);
515     QVERIFY(flick->contentY() == 0);
516
517     delete canvas;
518 }
519
520 void tst_qquickflickable::movingAndFlicking_data()
521 {
522     QTest::addColumn<bool>("verticalEnabled");
523     QTest::addColumn<bool>("horizontalEnabled");
524     QTest::addColumn<QPoint>("flickToWithoutSnapBack");
525     QTest::addColumn<QPoint>("flickToWithSnapBack");
526
527     QTest::newRow("vertical")
528             << true << false
529             << QPoint(50, 100)
530             << QPoint(50, 300);
531
532     QTest::newRow("horizontal")
533             << false << true
534             << QPoint(-50, 200)
535             << QPoint(150, 200);
536
537     QTest::newRow("both")
538             << true << true
539             << QPoint(-50, 100)
540             << QPoint(150, 300);
541 }
542
543 void tst_qquickflickable::movingAndFlicking()
544 {
545 #ifdef Q_OS_MAC
546     QSKIP("Producing flicks on Mac CI impossible due to timing problems");
547 #endif
548
549     QFETCH(bool, verticalEnabled);
550     QFETCH(bool, horizontalEnabled);
551     QFETCH(QPoint, flickToWithoutSnapBack);
552     QFETCH(QPoint, flickToWithSnapBack);
553
554     const QPoint flickFrom(50, 200);   // centre
555
556     QQuickView *canvas = new QQuickView;
557     canvas->setSource(testFileUrl("flickable03.qml"));
558     canvas->show();
559     canvas->requestActivateWindow();
560     QTest::qWaitForWindowActive(canvas);
561     QVERIFY(canvas->rootObject() != 0);
562
563     QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(canvas->rootObject());
564     QVERIFY(flickable != 0);
565
566     QSignalSpy vMoveSpy(flickable, SIGNAL(movingVerticallyChanged()));
567     QSignalSpy hMoveSpy(flickable, SIGNAL(movingHorizontallyChanged()));
568     QSignalSpy moveSpy(flickable, SIGNAL(movingChanged()));
569     QSignalSpy vFlickSpy(flickable, SIGNAL(flickingVerticallyChanged()));
570     QSignalSpy hFlickSpy(flickable, SIGNAL(flickingHorizontallyChanged()));
571     QSignalSpy flickSpy(flickable, SIGNAL(flickingChanged()));
572
573     QSignalSpy moveStartSpy(flickable, SIGNAL(movementStarted()));
574     QSignalSpy moveEndSpy(flickable, SIGNAL(movementEnded()));
575     QSignalSpy flickStartSpy(flickable, SIGNAL(flickStarted()));
576     QSignalSpy flickEndSpy(flickable, SIGNAL(flickEnded()));
577
578     // do a flick that keeps the view within the bounds
579     flick(canvas, flickFrom, flickToWithoutSnapBack, 200);
580
581     QVERIFY(flickable->isMoving());
582     QCOMPARE(flickable->isMovingHorizontally(), horizontalEnabled);
583     QCOMPARE(flickable->isMovingVertically(), verticalEnabled);
584     QVERIFY(flickable->isFlicking());
585     QCOMPARE(flickable->isFlickingHorizontally(), horizontalEnabled);
586     QCOMPARE(flickable->isFlickingVertically(), verticalEnabled);
587
588     QCOMPARE(moveSpy.count(), 1);
589     QCOMPARE(vMoveSpy.count(), verticalEnabled ? 1 : 0);
590     QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 1 : 0);
591     QCOMPARE(flickSpy.count(), 1);
592     QCOMPARE(vFlickSpy.count(), verticalEnabled ? 1 : 0);
593     QCOMPARE(hFlickSpy.count(), horizontalEnabled ? 1 : 0);
594
595     QCOMPARE(moveStartSpy.count(), 1);
596     QCOMPARE(flickStartSpy.count(), 1);
597
598     // wait for any motion to end
599     QTRY_VERIFY(!flickable->isMoving());
600
601     QVERIFY(!flickable->isMovingHorizontally());
602     QVERIFY(!flickable->isMovingVertically());
603     QVERIFY(!flickable->isFlicking());
604     QVERIFY(!flickable->isFlickingHorizontally());
605     QVERIFY(!flickable->isFlickingVertically());
606
607     QCOMPARE(moveSpy.count(), 2);
608     QCOMPARE(vMoveSpy.count(), verticalEnabled ? 2 : 0);
609     QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 2 : 0);
610     QCOMPARE(flickSpy.count(), 2);
611     QCOMPARE(vFlickSpy.count(), verticalEnabled ? 2 : 0);
612     QCOMPARE(hFlickSpy.count(), horizontalEnabled ? 2 : 0);
613
614     QCOMPARE(moveStartSpy.count(), 1);
615     QCOMPARE(moveEndSpy.count(), 1);
616     QCOMPARE(flickStartSpy.count(), 1);
617     QCOMPARE(flickEndSpy.count(), 1);
618
619     // Stop on a full pixel after user interaction
620     if (verticalEnabled)
621         QCOMPARE(flickable->contentY(), (qreal)qRound(flickable->contentY()));
622     if (horizontalEnabled)
623         QCOMPARE(flickable->contentX(), (qreal)qRound(flickable->contentX()));
624
625     // clear for next flick
626     vMoveSpy.clear(); hMoveSpy.clear(); moveSpy.clear();
627     vFlickSpy.clear(); hFlickSpy.clear(); flickSpy.clear();
628     moveStartSpy.clear(); moveEndSpy.clear();
629     flickStartSpy.clear(); flickEndSpy.clear();
630
631     // do a flick that flicks the view out of bounds
632     flickable->setContentX(0);
633     flickable->setContentY(0);
634     QTRY_VERIFY(!flickable->isMoving());
635     flick(canvas, flickFrom, flickToWithSnapBack, 200);
636
637     QVERIFY(flickable->isMoving());
638     QCOMPARE(flickable->isMovingHorizontally(), horizontalEnabled);
639     QCOMPARE(flickable->isMovingVertically(), verticalEnabled);
640     QVERIFY(flickable->isFlicking());
641     QCOMPARE(flickable->isFlickingHorizontally(), horizontalEnabled);
642     QCOMPARE(flickable->isFlickingVertically(), verticalEnabled);
643
644     QCOMPARE(moveSpy.count(), 1);
645     QCOMPARE(vMoveSpy.count(), verticalEnabled ? 1 : 0);
646     QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 1 : 0);
647     QCOMPARE(flickSpy.count(), 1);
648     QCOMPARE(vFlickSpy.count(), verticalEnabled ? 1 : 0);
649     QCOMPARE(hFlickSpy.count(), horizontalEnabled ? 1 : 0);
650
651     QCOMPARE(moveStartSpy.count(), 1);
652     QCOMPARE(moveEndSpy.count(), 0);
653     QCOMPARE(flickStartSpy.count(), 1);
654     QCOMPARE(flickEndSpy.count(), 0);
655
656     // wait for any motion to end
657     QTRY_VERIFY(!flickable->isMoving());
658
659     QVERIFY(!flickable->isMovingHorizontally());
660     QVERIFY(!flickable->isMovingVertically());
661     QVERIFY(!flickable->isFlicking());
662     QVERIFY(!flickable->isFlickingHorizontally());
663     QVERIFY(!flickable->isFlickingVertically());
664
665     QCOMPARE(moveSpy.count(), 2);
666     QCOMPARE(vMoveSpy.count(), verticalEnabled ? 2 : 0);
667     QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 2 : 0);
668     QCOMPARE(flickSpy.count(), 2);
669     QCOMPARE(vFlickSpy.count(), verticalEnabled ? 2 : 0);
670     QCOMPARE(hFlickSpy.count(), horizontalEnabled ? 2 : 0);
671
672     QCOMPARE(moveStartSpy.count(), 1);
673     QCOMPARE(moveEndSpy.count(), 1);
674     QCOMPARE(flickStartSpy.count(), 1);
675     QCOMPARE(flickEndSpy.count(), 1);
676
677     QCOMPARE(flickable->contentX(), 0.0);
678     QCOMPARE(flickable->contentY(), 0.0);
679
680     delete canvas;
681 }
682
683
684 void tst_qquickflickable::movingAndDragging_data()
685 {
686     QTest::addColumn<bool>("verticalEnabled");
687     QTest::addColumn<bool>("horizontalEnabled");
688     QTest::addColumn<QPoint>("moveByWithoutSnapBack");
689     QTest::addColumn<QPoint>("moveByWithSnapBack");
690
691     QTest::newRow("vertical")
692             << true << false
693             << QPoint(0, -10)
694             << QPoint(0, 20);
695
696     QTest::newRow("horizontal")
697             << false << true
698             << QPoint(-10, 0)
699             << QPoint(20, 0);
700
701     QTest::newRow("both")
702             << true << true
703             << QPoint(-10, -10)
704             << QPoint(20, 20);
705 }
706
707 void tst_qquickflickable::movingAndDragging()
708 {
709     QFETCH(bool, verticalEnabled);
710     QFETCH(bool, horizontalEnabled);
711     QFETCH(QPoint, moveByWithoutSnapBack);
712     QFETCH(QPoint, moveByWithSnapBack);
713
714     const QPoint moveFrom(50, 200);   // centre
715
716     QQuickView *canvas = new QQuickView;
717     canvas->setSource(testFileUrl("flickable03.qml"));
718     canvas->show();
719     canvas->requestActivateWindow();
720     QTest::qWaitForWindowShown(canvas);
721     QVERIFY(canvas->rootObject() != 0);
722
723     QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(canvas->rootObject());
724     QVERIFY(flickable != 0);
725
726     QSignalSpy vDragSpy(flickable, SIGNAL(draggingVerticallyChanged()));
727     QSignalSpy hDragSpy(flickable, SIGNAL(draggingHorizontallyChanged()));
728     QSignalSpy dragSpy(flickable, SIGNAL(draggingChanged()));
729     QSignalSpy vMoveSpy(flickable, SIGNAL(movingVerticallyChanged()));
730     QSignalSpy hMoveSpy(flickable, SIGNAL(movingHorizontallyChanged()));
731     QSignalSpy moveSpy(flickable, SIGNAL(movingChanged()));
732
733     QSignalSpy dragStartSpy(flickable, SIGNAL(dragStarted()));
734     QSignalSpy dragEndSpy(flickable, SIGNAL(dragEnded()));
735     QSignalSpy moveStartSpy(flickable, SIGNAL(movementStarted()));
736     QSignalSpy moveEndSpy(flickable, SIGNAL(movementEnded()));
737
738     // start the drag
739     QTest::mousePress(canvas, Qt::LeftButton, 0, moveFrom);
740     QTest::mouseMove(canvas, moveFrom + moveByWithoutSnapBack);
741     QTest::mouseMove(canvas, moveFrom + moveByWithoutSnapBack*2);
742     QTest::mouseMove(canvas, moveFrom + moveByWithoutSnapBack*3);
743
744     QVERIFY(flickable->isMoving());
745     QCOMPARE(flickable->isMovingHorizontally(), horizontalEnabled);
746     QCOMPARE(flickable->isMovingVertically(), verticalEnabled);
747     QVERIFY(flickable->isDragging());
748     QCOMPARE(flickable->isDraggingHorizontally(), horizontalEnabled);
749     QCOMPARE(flickable->isDraggingVertically(), verticalEnabled);
750
751     QCOMPARE(moveSpy.count(), 1);
752     QCOMPARE(vMoveSpy.count(), verticalEnabled ? 1 : 0);
753     QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 1 : 0);
754     QCOMPARE(dragSpy.count(), 1);
755     QCOMPARE(vDragSpy.count(), verticalEnabled ? 1 : 0);
756     QCOMPARE(hDragSpy.count(), horizontalEnabled ? 1 : 0);
757
758     QCOMPARE(moveStartSpy.count(), 1);
759     QCOMPARE(dragStartSpy.count(), 1);
760
761     QTest::mouseRelease(canvas, Qt::LeftButton, 0, moveFrom + moveByWithoutSnapBack*3);
762
763     QVERIFY(!flickable->isDragging());
764     QVERIFY(!flickable->isDraggingHorizontally());
765     QVERIFY(!flickable->isDraggingVertically());
766     QCOMPARE(dragSpy.count(), 2);
767     QCOMPARE(vDragSpy.count(), verticalEnabled ? 2 : 0);
768     QCOMPARE(hDragSpy.count(), horizontalEnabled ? 2 : 0);
769     QCOMPARE(dragStartSpy.count(), 1);
770     QCOMPARE(dragEndSpy.count(), 1);
771     // Don't test whether moving finished because a flick could occur
772
773     // wait for any motion to end
774     QTRY_VERIFY(flickable->isMoving() == false);
775
776     QVERIFY(!flickable->isMovingHorizontally());
777     QVERIFY(!flickable->isMovingVertically());
778     QVERIFY(!flickable->isDragging());
779     QVERIFY(!flickable->isDraggingHorizontally());
780     QVERIFY(!flickable->isDraggingVertically());
781
782     QCOMPARE(dragSpy.count(), 2);
783     QCOMPARE(vDragSpy.count(), verticalEnabled ? 2 : 0);
784     QCOMPARE(hDragSpy.count(), horizontalEnabled ? 2 : 0);
785     QCOMPARE(moveSpy.count(), 2);
786     QCOMPARE(vMoveSpy.count(), verticalEnabled ? 2 : 0);
787     QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 2 : 0);
788
789     QCOMPARE(dragStartSpy.count(), 1);
790     QCOMPARE(dragEndSpy.count(), 1);
791     QCOMPARE(moveStartSpy.count(), 1);
792     QCOMPARE(moveEndSpy.count(), 1);
793
794     // Stop on a full pixel after user interaction
795     if (verticalEnabled)
796         QCOMPARE(flickable->contentY(), (qreal)qRound(flickable->contentY()));
797     if (horizontalEnabled)
798         QCOMPARE(flickable->contentX(), (qreal)qRound(flickable->contentX()));
799
800     // clear for next drag
801      vMoveSpy.clear(); hMoveSpy.clear(); moveSpy.clear();
802      vDragSpy.clear(); hDragSpy.clear(); dragSpy.clear();
803      moveStartSpy.clear(); moveEndSpy.clear();
804      dragStartSpy.clear(); dragEndSpy.clear();
805
806      // do a drag that drags the view out of bounds
807      flickable->setContentX(0);
808      flickable->setContentY(0);
809      QTRY_VERIFY(!flickable->isMoving());
810      QTest::mousePress(canvas, Qt::LeftButton, 0, moveFrom);
811      QTest::mouseMove(canvas, moveFrom + moveByWithSnapBack);
812      QTest::mouseMove(canvas, moveFrom + moveByWithSnapBack*2);
813      QTest::mouseMove(canvas, moveFrom + moveByWithSnapBack*3);
814
815      QVERIFY(flickable->isMoving());
816      QCOMPARE(flickable->isMovingHorizontally(), horizontalEnabled);
817      QCOMPARE(flickable->isMovingVertically(), verticalEnabled);
818      QVERIFY(flickable->isDragging());
819      QCOMPARE(flickable->isDraggingHorizontally(), horizontalEnabled);
820      QCOMPARE(flickable->isDraggingVertically(), verticalEnabled);
821
822      QCOMPARE(moveSpy.count(), 1);
823      QCOMPARE(vMoveSpy.count(), verticalEnabled ? 1 : 0);
824      QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 1 : 0);
825      QCOMPARE(dragSpy.count(), 1);
826      QCOMPARE(vDragSpy.count(), verticalEnabled ? 1 : 0);
827      QCOMPARE(hDragSpy.count(), horizontalEnabled ? 1 : 0);
828
829      QCOMPARE(moveStartSpy.count(), 1);
830      QCOMPARE(moveEndSpy.count(), 0);
831      QCOMPARE(dragStartSpy.count(), 1);
832      QCOMPARE(dragEndSpy.count(), 0);
833
834      QTest::mouseRelease(canvas, Qt::LeftButton, 0, moveFrom + moveByWithSnapBack*3);
835
836      // should now start snapping back to bounds (moving but not dragging)
837      QVERIFY(flickable->isMoving());
838      QCOMPARE(flickable->isMovingHorizontally(), horizontalEnabled);
839      QCOMPARE(flickable->isMovingVertically(), verticalEnabled);
840      QVERIFY(!flickable->isDragging());
841      QVERIFY(!flickable->isDraggingHorizontally());
842      QVERIFY(!flickable->isDraggingVertically());
843
844      QCOMPARE(moveSpy.count(), 1);
845      QCOMPARE(vMoveSpy.count(), verticalEnabled ? 1 : 0);
846      QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 1 : 0);
847      QCOMPARE(dragSpy.count(), 2);
848      QCOMPARE(vDragSpy.count(), verticalEnabled ? 2 : 0);
849      QCOMPARE(hDragSpy.count(), horizontalEnabled ? 2 : 0);
850
851      QCOMPARE(moveStartSpy.count(), 1);
852      QCOMPARE(moveEndSpy.count(), 0);
853
854      // wait for any motion to end
855      QTRY_VERIFY(!flickable->isMoving());
856
857      QVERIFY(!flickable->isMovingHorizontally());
858      QVERIFY(!flickable->isMovingVertically());
859      QVERIFY(!flickable->isDragging());
860      QVERIFY(!flickable->isDraggingHorizontally());
861      QVERIFY(!flickable->isDraggingVertically());
862
863      QCOMPARE(moveSpy.count(), 2);
864      QCOMPARE(vMoveSpy.count(), verticalEnabled ? 2 : 0);
865      QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 2 : 0);
866      QCOMPARE(dragSpy.count(), 2);
867      QCOMPARE(vDragSpy.count(), verticalEnabled ? 2 : 0);
868      QCOMPARE(hDragSpy.count(), horizontalEnabled ? 2 : 0);
869
870      QCOMPARE(moveStartSpy.count(), 1);
871      QCOMPARE(moveEndSpy.count(), 1);
872      QCOMPARE(dragStartSpy.count(), 1);
873      QCOMPARE(dragEndSpy.count(), 1);
874
875      QCOMPARE(flickable->contentX(), 0.0);
876      QCOMPARE(flickable->contentY(), 0.0);
877
878     delete canvas;
879 }
880
881 void tst_qquickflickable::flickOnRelease()
882 {
883 #ifdef Q_OS_MAC
884     QSKIP("Producing flicks on Mac CI impossible due to timing problems");
885 #endif
886     QQuickView *canvas = new QQuickView;
887     canvas->setSource(testFileUrl("flickable03.qml"));
888     canvas->show();
889     canvas->requestActivateWindow();
890     QTest::qWaitForWindowShown(canvas);
891     QVERIFY(canvas->rootObject() != 0);
892
893     QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(canvas->rootObject());
894     QVERIFY(flickable != 0);
895
896     // Vertical with a quick press-move-release: should cause a flick in release.
897     QSignalSpy vFlickSpy(flickable, SIGNAL(flickingVerticallyChanged()));
898     // Use something that generates a huge velocity just to make it testable.
899     // In practice this feature matters on touchscreen devices where the
900     // underlying drivers will hopefully provide a pre-calculated velocity
901     // (based on more data than what the UI gets), thus making this use case
902     // working even with small movements.
903     QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50, 300));
904     QTest::mouseMove(canvas, QPoint(50, 10), 10);
905     QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50, 10), 10);
906
907     QCOMPARE(vFlickSpy.count(), 1);
908
909     // wait for any motion to end
910     QTRY_VERIFY(flickable->isMoving() == false);
911
912     // Stop on a full pixel after user interaction
913     QCOMPARE(flickable->contentY(), (qreal)qRound(flickable->contentY()));
914
915     delete canvas;
916 }
917
918 void tst_qquickflickable::pressWhileFlicking()
919 {
920 #ifdef Q_OS_MAC
921     QSKIP("Producing flicks on Mac CI impossible due to timing problems");
922 #endif
923
924     QQuickView *canvas = new QQuickView;
925     canvas->setSource(testFileUrl("flickable03.qml"));
926     canvas->show();
927     canvas->requestActivateWindow();
928     QTest::qWaitForWindowShown(canvas);
929     QVERIFY(canvas->rootObject() != 0);
930
931     QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(canvas->rootObject());
932     QVERIFY(flickable != 0);
933
934     QSignalSpy vMoveSpy(flickable, SIGNAL(movingVerticallyChanged()));
935     QSignalSpy hMoveSpy(flickable, SIGNAL(movingHorizontallyChanged()));
936     QSignalSpy moveSpy(flickable, SIGNAL(movingChanged()));
937     QSignalSpy hFlickSpy(flickable, SIGNAL(flickingHorizontallyChanged()));
938     QSignalSpy vFlickSpy(flickable, SIGNAL(flickingVerticallyChanged()));
939     QSignalSpy flickSpy(flickable, SIGNAL(flickingChanged()));
940
941     // flick then press while it is still moving
942     // flicking == false, moving == true;
943     flick(canvas, QPoint(20,190), QPoint(20, 50), 200);
944     QVERIFY(flickable->verticalVelocity() > 0.0);
945     QVERIFY(flickable->isFlicking());
946     QVERIFY(flickable->isFlickingVertically());
947     QVERIFY(!flickable->isFlickingHorizontally());
948     QVERIFY(flickable->isMoving());
949     QVERIFY(flickable->isMovingVertically());
950     QVERIFY(!flickable->isMovingHorizontally());
951     QCOMPARE(vMoveSpy.count(), 1);
952     QCOMPARE(hMoveSpy.count(), 0);
953     QCOMPARE(moveSpy.count(), 1);
954     QCOMPARE(vFlickSpy.count(), 1);
955     QCOMPARE(hFlickSpy.count(), 0);
956     QCOMPARE(flickSpy.count(), 1);
957
958     QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(20, 50));
959     QTRY_VERIFY(!flickable->isFlicking());
960     QVERIFY(!flickable->isFlickingVertically());
961     QVERIFY(flickable->isMoving());
962     QVERIFY(flickable->isMovingVertically());
963
964     QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(20,50));
965     QVERIFY(!flickable->isFlicking());
966     QVERIFY(!flickable->isFlickingVertically());
967     QTRY_VERIFY(!flickable->isMoving());
968     QVERIFY(!flickable->isMovingVertically());
969     // Stop on a full pixel after user interaction
970     QCOMPARE(flickable->contentX(), (qreal)qRound(flickable->contentX()));
971
972     delete canvas;
973 }
974
975 void tst_qquickflickable::disabled()
976 {
977     QQuickView *canvas = new QQuickView;
978     canvas->setSource(testFileUrl("disabled.qml"));
979     canvas->show();
980     canvas->requestActivateWindow();
981     QVERIFY(canvas->rootObject() != 0);
982
983     QQuickFlickable *flick = canvas->rootObject()->findChild<QQuickFlickable*>("flickable");
984     QVERIFY(flick != 0);
985
986     QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50, 90));
987
988     QTest::mouseMove(canvas, QPoint(50, 80));
989     QTest::mouseMove(canvas, QPoint(50, 70));
990     QTest::mouseMove(canvas, QPoint(50, 60));
991
992     QVERIFY(flick->isMoving() == false);
993
994     QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50, 60));
995
996     // verify that mouse clicks on other elements still work (QTBUG-20584)
997     QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50, 10));
998     QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50, 10));
999
1000     QTRY_VERIFY(canvas->rootObject()->property("clicked").toBool() == true);
1001 }
1002
1003 void tst_qquickflickable::flickVelocity()
1004 {
1005 #ifdef Q_OS_MAC
1006     QSKIP("Producing flicks on Mac CI impossible due to timing problems");
1007 #endif
1008
1009     QQuickView *canvas = new QQuickView;
1010     canvas->setSource(testFileUrl("flickable03.qml"));
1011     canvas->show();
1012     canvas->requestActivateWindow();
1013     QVERIFY(canvas->rootObject() != 0);
1014
1015     QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(canvas->rootObject());
1016     QVERIFY(flickable != 0);
1017
1018     // flick up
1019     flick(canvas, QPoint(20,190), QPoint(20, 50), 200);
1020     QVERIFY(flickable->verticalVelocity() > 0.0);
1021     QTRY_VERIFY(flickable->verticalVelocity() == 0.0);
1022
1023     // flick down
1024     flick(canvas, QPoint(20,10), QPoint(20, 140), 200);
1025     QVERIFY(flickable->verticalVelocity() < 0.0);
1026     QTRY_VERIFY(flickable->verticalVelocity() == 0.0);
1027
1028     // Flick multiple times and verify that flick acceleration is applied.
1029     QQuickFlickablePrivate *fp = QQuickFlickablePrivate::get(flickable);
1030     bool boosted = false;
1031     for (int i = 0; i < 6; ++i) {
1032         flick(canvas, QPoint(20,390), QPoint(20, 50), 100);
1033         boosted |= fp->flickBoost > 1.0;
1034     }
1035     QVERIFY(boosted);
1036
1037     // Flick in opposite direction -> boost cancelled.
1038     flick(canvas, QPoint(20,10), QPoint(20, 340), 200);
1039     QTRY_VERIFY(flickable->verticalVelocity() < 0.0);
1040     QVERIFY(fp->flickBoost == 1.0);
1041
1042     delete canvas;
1043 }
1044
1045 void tst_qquickflickable::margins()
1046 {
1047     QQmlEngine engine;
1048     QQmlComponent c(&engine, testFileUrl("margins.qml"));
1049     QQuickItem *root = qobject_cast<QQuickItem*>(c.create());
1050     QQuickFlickable *obj = qobject_cast<QQuickFlickable*>(root);
1051     QVERIFY(obj != 0);
1052
1053     // starting state
1054     QCOMPARE(obj->contentX(), -40.);
1055     QCOMPARE(obj->contentY(), -20.);
1056     QCOMPARE(obj->contentWidth(), 1600.);
1057     QCOMPARE(obj->contentHeight(), 600.);
1058     QCOMPARE(obj->originX(), 0.);
1059     QCOMPARE(obj->originY(), 0.);
1060
1061     // Reduce left margin
1062     obj->setLeftMargin(30);
1063     QTRY_COMPARE(obj->contentX(), -30.);
1064
1065     // Reduce top margin
1066     obj->setTopMargin(20);
1067     QTRY_COMPARE(obj->contentY(), -20.);
1068
1069     // position to the far right, including margin
1070     obj->setContentX(1600 + 50 - obj->width());
1071     obj->returnToBounds();
1072     QTest::qWait(200);
1073     QCOMPARE(obj->contentX(), 1600. + 50. - obj->width());
1074
1075     // position beyond the far right, including margin
1076     obj->setContentX(1600 + 50 - obj->width() + 1.);
1077     obj->returnToBounds();
1078     QTRY_COMPARE(obj->contentX(), 1600. + 50. - obj->width());
1079
1080     // Reduce right margin
1081     obj->setRightMargin(40);
1082     QTRY_COMPARE(obj->contentX(), 1600. + 40. - obj->width());
1083     QCOMPARE(obj->contentWidth(), 1600.);
1084
1085     // position to the far bottom, including margin
1086     obj->setContentY(600 + 30 - obj->height());
1087     obj->returnToBounds();
1088     QTest::qWait(200);
1089     QCOMPARE(obj->contentY(), 600. + 30. - obj->height());
1090
1091     // position beyond the far bottom, including margin
1092     obj->setContentY(600 + 30 - obj->height() + 1.);
1093     obj->returnToBounds();
1094     QTRY_COMPARE(obj->contentY(), 600. + 30. - obj->height());
1095
1096     // Reduce bottom margin
1097     obj->setBottomMargin(20);
1098     QTRY_COMPARE(obj->contentY(), 600. + 20. - obj->height());
1099     QCOMPARE(obj->contentHeight(), 600.);
1100
1101     delete root;
1102 }
1103
1104 void tst_qquickflickable::cancelOnMouseGrab()
1105 {
1106     QQuickView *canvas = new QQuickView;
1107     canvas->setSource(testFileUrl("cancel.qml"));
1108     canvas->show();
1109     canvas->requestActivateWindow();
1110     QVERIFY(canvas->rootObject() != 0);
1111
1112     QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(canvas->rootObject());
1113     QVERIFY(flickable != 0);
1114
1115     QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(10, 10));
1116     // drag out of bounds
1117     QTest::mouseMove(canvas, QPoint(50, 50));
1118     QTest::mouseMove(canvas, QPoint(100, 100));
1119     QTest::mouseMove(canvas, QPoint(150, 150));
1120
1121     QVERIFY(flickable->contentX() != 0);
1122     QVERIFY(flickable->contentY() != 0);
1123     QVERIFY(flickable->isMoving());
1124     QVERIFY(flickable->isDragging());
1125
1126     // grabbing mouse will cancel flickable interaction.
1127     QQuickItem *item = canvas->rootObject()->findChild<QQuickItem*>("row");
1128     item->grabMouse();
1129
1130     QTRY_COMPARE(flickable->contentX(), 0.);
1131     QTRY_COMPARE(flickable->contentY(), 0.);
1132     QTRY_VERIFY(!flickable->isMoving());
1133     QTRY_VERIFY(!flickable->isDragging());
1134
1135     QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50, 10));
1136 }
1137
1138 void tst_qquickflickable::clickAndDragWhenTransformed()
1139 {
1140     QQuickView *canvas = new QQuickView;
1141     canvas->setSource(testFileUrl("transformedFlickable.qml"));
1142     canvas->show();
1143     canvas->requestActivateWindow();
1144     QTest::qWaitForWindowShown(canvas);
1145     QVERIFY(canvas->rootObject() != 0);
1146
1147     QQuickFlickable *flickable = canvas->rootObject()->findChild<QQuickFlickable*>("flickable");
1148     QVERIFY(flickable != 0);
1149
1150     // click outside child rect
1151     QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(190, 190));
1152     QTest::qWait(10);
1153     QCOMPARE(flickable->property("itemPressed").toBool(), false);
1154     QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(190, 190));
1155
1156     // click inside child rect
1157     QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(200, 200));
1158     QTest::qWait(10);
1159     QCOMPARE(flickable->property("itemPressed").toBool(), true);
1160     QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(200, 200));
1161
1162     const int threshold = qApp->styleHints()->startDragDistance();
1163
1164     // drag outside bounds
1165     QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(160, 160));
1166     QTest::qWait(10);
1167     QTest::mouseMove(canvas, QPoint(160 + threshold * 2, 160));
1168     QTest::mouseMove(canvas, QPoint(160 + threshold * 3, 160));
1169     QCOMPARE(flickable->isDragging(), false);
1170     QCOMPARE(flickable->property("itemPressed").toBool(), false);
1171     QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(180, 160));
1172
1173     // drag inside bounds
1174     QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(200, 140));
1175     QTest::qWait(10);
1176     QTest::mouseMove(canvas, QPoint(200 + threshold * 2, 140));
1177     QTest::mouseMove(canvas, QPoint(200 + threshold * 3, 140));
1178     QCOMPARE(flickable->isDragging(), true);
1179     QCOMPARE(flickable->property("itemPressed").toBool(), false);
1180     QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(220, 140));
1181
1182     delete canvas;
1183 }
1184
1185 QTEST_MAIN(tst_qquickflickable)
1186
1187 #include "tst_qquickflickable.moc"