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