X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=tests%2Fauto%2Fquick%2Fqquickflickable%2Ftst_qquickflickable.cpp;h=cb8dba31c44bd2abdc0a210a0dc99ccbe5e97e31;hb=feb996e3ab44e68082c97102556ea396f5df3f44;hp=4b157a434b60e0c950a47ce8713acc9f406c09d9;hpb=4821058f10118be55a541ad39e25ec9165cca3b3;p=profile%2Fivi%2Fqtdeclarative.git diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index 4b157a4..cb8dba3 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -40,11 +40,13 @@ ****************************************************************************/ #include #include +#include #include #include #include #include #include +#include #include #include #include "../../shared/util.h" @@ -65,6 +67,7 @@ private slots: void verticalViewportSize(); void properties(); void boundsBehavior(); + void rebound(); void maximumFlickVelocity(); void flickDeceleration(); void pressDelay(); @@ -72,11 +75,19 @@ private slots: void flickableDirection(); void resizeContent(); void returnToBounds(); + void returnToBounds_data(); void wheel(); + void movingAndFlicking(); + void movingAndFlicking_data(); void movingAndDragging(); + void movingAndDragging_data(); + void flickOnRelease(); + void pressWhileFlicking(); void disabled(); void flickVelocity(); void margins(); + void cancelOnMouseGrab(); + void clickAndDragWhenTransformed(); private: QQmlEngine engine; @@ -189,6 +200,108 @@ void tst_qquickflickable::boundsBehavior() QCOMPARE(spy.count(),3); } +void tst_qquickflickable::rebound() +{ +#ifdef Q_OS_MAC + QSKIP("Producing flicks on Mac CI impossible due to timing problems"); +#endif + + QQuickView *window = new QQuickView; + window->setSource(testFileUrl("rebound.qml")); + window->show(); + window->requestActivateWindow(); + QVERIFY(window->rootObject() != 0); + + QQuickFlickable *flickable = qobject_cast(window->rootObject()); + QVERIFY(flickable != 0); + + QQuickTransition *rebound = window->rootObject()->findChild("rebound"); + QVERIFY(rebound); + QSignalSpy reboundSpy(rebound, SIGNAL(runningChanged())); + + QSignalSpy movementStartedSpy(flickable, SIGNAL(movementStarted())); + QSignalSpy movementEndedSpy(flickable, SIGNAL(movementEnded())); + QSignalSpy vMoveSpy(flickable, SIGNAL(movingVerticallyChanged())); + QSignalSpy hMoveSpy(flickable, SIGNAL(movingHorizontallyChanged())); + + // flick and test the transition is run + flick(window, QPoint(20,20), QPoint(120,120), 200); + + QTRY_COMPARE(window->rootObject()->property("transitionsStarted").toInt(), 2); + QCOMPARE(hMoveSpy.count(), 1); + QCOMPARE(vMoveSpy.count(), 1); + QCOMPARE(movementStartedSpy.count(), 1); + QCOMPARE(movementEndedSpy.count(), 0); + QVERIFY(rebound->running()); + + QTRY_VERIFY(!flickable->isMoving()); + QCOMPARE(flickable->contentX(), 0.0); + QCOMPARE(flickable->contentY(), 0.0); + + QCOMPARE(hMoveSpy.count(), 2); + QCOMPARE(vMoveSpy.count(), 2); + QCOMPARE(movementStartedSpy.count(), 1); + QCOMPARE(movementEndedSpy.count(), 1); + QCOMPARE(window->rootObject()->property("transitionsStarted").toInt(), 2); + QVERIFY(!rebound->running()); + QCOMPARE(reboundSpy.count(), 2); + + hMoveSpy.clear(); + vMoveSpy.clear(); + movementStartedSpy.clear(); + movementEndedSpy.clear(); + window->rootObject()->setProperty("transitionsStarted", 0); + window->rootObject()->setProperty("transitionsFinished", 0); + + // flick and trigger the transition multiple times + // (moving signals are emitted as soon as the first transition starts) + flick(window, QPoint(20,20), QPoint(120,120), 200); // both x and y will bounce back + flick(window, QPoint(20,120), QPoint(120,20), 200); // only x will bounce back + + QVERIFY(flickable->isMoving()); + QVERIFY(window->rootObject()->property("transitionsStarted").toInt() >= 1); + QCOMPARE(hMoveSpy.count(), 1); + QCOMPARE(vMoveSpy.count(), 1); + QCOMPARE(movementStartedSpy.count(), 1); + + QTRY_VERIFY(!flickable->isMoving()); + QCOMPARE(flickable->contentX(), 0.0); + + // moving started/stopped signals should only have been emitted once, + // and when they are, all transitions should have finished + QCOMPARE(hMoveSpy.count(), 2); + QCOMPARE(vMoveSpy.count(), 2); + QCOMPARE(movementStartedSpy.count(), 1); + QCOMPARE(movementEndedSpy.count(), 1); + + hMoveSpy.clear(); + vMoveSpy.clear(); + movementStartedSpy.clear(); + movementEndedSpy.clear(); + window->rootObject()->setProperty("transitionsStarted", 0); + window->rootObject()->setProperty("transitionsFinished", 0); + + // disable and the default transition should run + // (i.e. moving but transition->running = false) + window->rootObject()->setProperty("transitionEnabled", false); + + flick(window, QPoint(20,20), QPoint(120,120), 200); + QCOMPARE(window->rootObject()->property("transitionsStarted").toInt(), 0); + QCOMPARE(hMoveSpy.count(), 1); + QCOMPARE(vMoveSpy.count(), 1); + QCOMPARE(movementStartedSpy.count(), 1); + QCOMPARE(movementEndedSpy.count(), 0); + + QTRY_VERIFY(!flickable->isMoving()); + QCOMPARE(hMoveSpy.count(), 2); + QCOMPARE(vMoveSpy.count(), 2); + QCOMPARE(movementStartedSpy.count(), 1); + QCOMPARE(movementEndedSpy.count(), 1); + QCOMPARE(window->rootObject()->property("transitionsStarted").toInt(), 0); + + delete window; +} + void tst_qquickflickable::maximumFlickVelocity() { QQmlComponent component(&engine); @@ -243,19 +356,19 @@ void tst_qquickflickable::pressDelay() // QTBUG-17361 void tst_qquickflickable::nestedPressDelay() { - QQuickView *canvas = new QQuickView; - canvas->setSource(testFileUrl("nestedPressDelay.qml")); - canvas->show(); - canvas->requestActivateWindow(); - QVERIFY(canvas->rootObject() != 0); + QQuickView *window = new QQuickView; + window->setSource(testFileUrl("nestedPressDelay.qml")); + window->show(); + window->requestActivateWindow(); + QVERIFY(window->rootObject() != 0); - QQuickFlickable *outer = qobject_cast(canvas->rootObject()); + QQuickFlickable *outer = qobject_cast(window->rootObject()); QVERIFY(outer != 0); - QQuickFlickable *inner = canvas->rootObject()->findChild("innerFlickable"); + QQuickFlickable *inner = window->rootObject()->findChild("innerFlickable"); QVERIFY(inner != 0); - QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(150, 150)); + QTest::mousePress(window, Qt::LeftButton, 0, QPoint(150, 150)); // the MouseArea is not pressed immediately QVERIFY(outer->property("pressed").toBool() == false); @@ -263,9 +376,9 @@ void tst_qquickflickable::nestedPressDelay() // QTRY_VERIFY() has 5sec timeout, so will timeout well within 10sec. QTRY_VERIFY(outer->property("pressed").toBool() == true); - QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(150, 150)); + QTest::mouseRelease(window, Qt::LeftButton, 0, QPoint(150, 150)); - delete canvas; + delete window; } void tst_qquickflickable::flickableDirection() @@ -319,13 +432,19 @@ void tst_qquickflickable::resizeContent() delete root; } -// QtQuick 1.1 void tst_qquickflickable::returnToBounds() { - QQmlEngine engine; - QQmlComponent c(&engine, testFileUrl("resize.qml")); - QQuickItem *root = qobject_cast(c.create()); - QQuickFlickable *obj = findItem(root, "flick"); + QFETCH(bool, setRebound); + + QQuickView *window = new QQuickView; + window->rootContext()->setContextProperty("setRebound", setRebound); + window->setSource(testFileUrl("resize.qml")); + QVERIFY(window->rootObject() != 0); + QQuickFlickable *obj = findItem(window->rootObject(), "flick"); + + QQuickTransition *rebound = window->rootObject()->findChild("rebound"); + QVERIFY(rebound); + QSignalSpy reboundSpy(rebound, SIGNAL(runningChanged())); QVERIFY(obj != 0); QCOMPARE(obj->contentX(), 0.); @@ -338,29 +457,44 @@ void tst_qquickflickable::returnToBounds() QTRY_COMPARE(obj->contentX(), 100.); QTRY_COMPARE(obj->contentY(), 400.); - QMetaObject::invokeMethod(root, "returnToBounds"); + QMetaObject::invokeMethod(window->rootObject(), "returnToBounds"); + + if (setRebound) + QTRY_VERIFY(rebound->running()); QTRY_COMPARE(obj->contentX(), 0.); QTRY_COMPARE(obj->contentY(), 0.); - delete root; + QVERIFY(!rebound->running()); + QCOMPARE(reboundSpy.count(), setRebound ? 2 : 0); + + delete window; +} + +void tst_qquickflickable::returnToBounds_data() +{ + QTest::addColumn("setRebound"); + + QTest::newRow("with bounds transition") << true; + QTest::newRow("with bounds transition") << false; } void tst_qquickflickable::wheel() { - QQuickView *canvas = new QQuickView; - canvas->setSource(testFileUrl("wheel.qml")); - canvas->show(); - canvas->requestActivateWindow(); - QVERIFY(canvas->rootObject() != 0); + QQuickView *window = new QQuickView; + window->setSource(testFileUrl("wheel.qml")); + window->show(); + window->requestActivateWindow(); + QVERIFY(window->rootObject() != 0); - QQuickFlickable *flick = canvas->rootObject()->findChild("flick"); + QQuickFlickable *flick = window->rootObject()->findChild("flick"); QVERIFY(flick != 0); { - QWheelEvent event(QPoint(200, 200), -120, Qt::NoButton, Qt::NoModifier, Qt::Vertical); + QPoint pos(200, 200); + QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(), QPoint(0,-120), -120, Qt::Vertical, Qt::NoButton, Qt::NoModifier); event.setAccepted(false); - QGuiApplication::sendEvent(canvas, &event); + QGuiApplication::sendEvent(window, &event); } QTRY_VERIFY(flick->contentY() > 0); @@ -370,27 +504,223 @@ void tst_qquickflickable::wheel() QVERIFY(flick->contentY() == 0); { - QWheelEvent event(QPoint(200, 200), -120, Qt::NoButton, Qt::NoModifier, Qt::Horizontal); + QPoint pos(200, 200); + QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(), QPoint(-120,0), -120, Qt::Horizontal, Qt::NoButton, Qt::NoModifier); + event.setAccepted(false); - QGuiApplication::sendEvent(canvas, &event); + QGuiApplication::sendEvent(window, &event); } QTRY_VERIFY(flick->contentX() > 0); QVERIFY(flick->contentY() == 0); - delete canvas; + delete window; +} + +void tst_qquickflickable::movingAndFlicking_data() +{ + QTest::addColumn("verticalEnabled"); + QTest::addColumn("horizontalEnabled"); + QTest::addColumn("flickToWithoutSnapBack"); + QTest::addColumn("flickToWithSnapBack"); + + QTest::newRow("vertical") + << true << false + << QPoint(50, 100) + << QPoint(50, 300); + + QTest::newRow("horizontal") + << false << true + << QPoint(-50, 200) + << QPoint(150, 200); + + QTest::newRow("both") + << true << true + << QPoint(-50, 100) + << QPoint(150, 300); +} + +void tst_qquickflickable::movingAndFlicking() +{ +#ifdef Q_OS_MAC + QSKIP("Producing flicks on Mac CI impossible due to timing problems"); +#endif + + QFETCH(bool, verticalEnabled); + QFETCH(bool, horizontalEnabled); + QFETCH(QPoint, flickToWithoutSnapBack); + QFETCH(QPoint, flickToWithSnapBack); + + const QPoint flickFrom(50, 200); // centre + + QQuickView *window = new QQuickView; + window->setSource(testFileUrl("flickable03.qml")); + window->show(); + window->requestActivateWindow(); + QTest::qWaitForWindowActive(window); + QVERIFY(window->rootObject() != 0); + + QQuickFlickable *flickable = qobject_cast(window->rootObject()); + QVERIFY(flickable != 0); + + QSignalSpy vMoveSpy(flickable, SIGNAL(movingVerticallyChanged())); + QSignalSpy hMoveSpy(flickable, SIGNAL(movingHorizontallyChanged())); + QSignalSpy moveSpy(flickable, SIGNAL(movingChanged())); + QSignalSpy vFlickSpy(flickable, SIGNAL(flickingVerticallyChanged())); + QSignalSpy hFlickSpy(flickable, SIGNAL(flickingHorizontallyChanged())); + QSignalSpy flickSpy(flickable, SIGNAL(flickingChanged())); + + QSignalSpy moveStartSpy(flickable, SIGNAL(movementStarted())); + QSignalSpy moveEndSpy(flickable, SIGNAL(movementEnded())); + QSignalSpy flickStartSpy(flickable, SIGNAL(flickStarted())); + QSignalSpy flickEndSpy(flickable, SIGNAL(flickEnded())); + + // do a flick that keeps the view within the bounds + flick(window, flickFrom, flickToWithoutSnapBack, 200); + + QVERIFY(flickable->isMoving()); + QCOMPARE(flickable->isMovingHorizontally(), horizontalEnabled); + QCOMPARE(flickable->isMovingVertically(), verticalEnabled); + QVERIFY(flickable->isFlicking()); + QCOMPARE(flickable->isFlickingHorizontally(), horizontalEnabled); + QCOMPARE(flickable->isFlickingVertically(), verticalEnabled); + + QCOMPARE(moveSpy.count(), 1); + QCOMPARE(vMoveSpy.count(), verticalEnabled ? 1 : 0); + QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 1 : 0); + QCOMPARE(flickSpy.count(), 1); + QCOMPARE(vFlickSpy.count(), verticalEnabled ? 1 : 0); + QCOMPARE(hFlickSpy.count(), horizontalEnabled ? 1 : 0); + + QCOMPARE(moveStartSpy.count(), 1); + QCOMPARE(flickStartSpy.count(), 1); + + // wait for any motion to end + QTRY_VERIFY(!flickable->isMoving()); + + QVERIFY(!flickable->isMovingHorizontally()); + QVERIFY(!flickable->isMovingVertically()); + QVERIFY(!flickable->isFlicking()); + QVERIFY(!flickable->isFlickingHorizontally()); + QVERIFY(!flickable->isFlickingVertically()); + + QCOMPARE(moveSpy.count(), 2); + QCOMPARE(vMoveSpy.count(), verticalEnabled ? 2 : 0); + QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 2 : 0); + QCOMPARE(flickSpy.count(), 2); + QCOMPARE(vFlickSpy.count(), verticalEnabled ? 2 : 0); + QCOMPARE(hFlickSpy.count(), horizontalEnabled ? 2 : 0); + + QCOMPARE(moveStartSpy.count(), 1); + QCOMPARE(moveEndSpy.count(), 1); + QCOMPARE(flickStartSpy.count(), 1); + QCOMPARE(flickEndSpy.count(), 1); + + // Stop on a full pixel after user interaction + if (verticalEnabled) + QCOMPARE(flickable->contentY(), (qreal)qRound(flickable->contentY())); + if (horizontalEnabled) + QCOMPARE(flickable->contentX(), (qreal)qRound(flickable->contentX())); + + // clear for next flick + vMoveSpy.clear(); hMoveSpy.clear(); moveSpy.clear(); + vFlickSpy.clear(); hFlickSpy.clear(); flickSpy.clear(); + moveStartSpy.clear(); moveEndSpy.clear(); + flickStartSpy.clear(); flickEndSpy.clear(); + + // do a flick that flicks the view out of bounds + flickable->setContentX(0); + flickable->setContentY(0); + QTRY_VERIFY(!flickable->isMoving()); + flick(window, flickFrom, flickToWithSnapBack, 200); + + QVERIFY(flickable->isMoving()); + QCOMPARE(flickable->isMovingHorizontally(), horizontalEnabled); + QCOMPARE(flickable->isMovingVertically(), verticalEnabled); + QVERIFY(flickable->isFlicking()); + QCOMPARE(flickable->isFlickingHorizontally(), horizontalEnabled); + QCOMPARE(flickable->isFlickingVertically(), verticalEnabled); + + QCOMPARE(moveSpy.count(), 1); + QCOMPARE(vMoveSpy.count(), verticalEnabled ? 1 : 0); + QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 1 : 0); + QCOMPARE(flickSpy.count(), 1); + QCOMPARE(vFlickSpy.count(), verticalEnabled ? 1 : 0); + QCOMPARE(hFlickSpy.count(), horizontalEnabled ? 1 : 0); + + QCOMPARE(moveStartSpy.count(), 1); + QCOMPARE(moveEndSpy.count(), 0); + QCOMPARE(flickStartSpy.count(), 1); + QCOMPARE(flickEndSpy.count(), 0); + + // wait for any motion to end + QTRY_VERIFY(!flickable->isMoving()); + + QVERIFY(!flickable->isMovingHorizontally()); + QVERIFY(!flickable->isMovingVertically()); + QVERIFY(!flickable->isFlicking()); + QVERIFY(!flickable->isFlickingHorizontally()); + QVERIFY(!flickable->isFlickingVertically()); + + QCOMPARE(moveSpy.count(), 2); + QCOMPARE(vMoveSpy.count(), verticalEnabled ? 2 : 0); + QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 2 : 0); + QCOMPARE(flickSpy.count(), 2); + QCOMPARE(vFlickSpy.count(), verticalEnabled ? 2 : 0); + QCOMPARE(hFlickSpy.count(), horizontalEnabled ? 2 : 0); + + QCOMPARE(moveStartSpy.count(), 1); + QCOMPARE(moveEndSpy.count(), 1); + QCOMPARE(flickStartSpy.count(), 1); + QCOMPARE(flickEndSpy.count(), 1); + + QCOMPARE(flickable->contentX(), 0.0); + QCOMPARE(flickable->contentY(), 0.0); + + delete window; +} + + +void tst_qquickflickable::movingAndDragging_data() +{ + QTest::addColumn("verticalEnabled"); + QTest::addColumn("horizontalEnabled"); + QTest::addColumn("moveByWithoutSnapBack"); + QTest::addColumn("moveByWithSnapBack"); + + QTest::newRow("vertical") + << true << false + << QPoint(0, -10) + << QPoint(0, 20); + + QTest::newRow("horizontal") + << false << true + << QPoint(-10, 0) + << QPoint(20, 0); + + QTest::newRow("both") + << true << true + << QPoint(-10, -10) + << QPoint(20, 20); } void tst_qquickflickable::movingAndDragging() { - QQuickView *canvas = new QQuickView; - canvas->setSource(testFileUrl("flickable03.qml")); - canvas->show(); - canvas->requestActivateWindow(); - QTest::qWaitForWindowShown(canvas); - QVERIFY(canvas->rootObject() != 0); - - QQuickFlickable *flickable = qobject_cast(canvas->rootObject()); + QFETCH(bool, verticalEnabled); + QFETCH(bool, horizontalEnabled); + QFETCH(QPoint, moveByWithoutSnapBack); + QFETCH(QPoint, moveByWithSnapBack); + + const QPoint moveFrom(50, 200); // centre + + QQuickView *window = new QQuickView; + window->setSource(testFileUrl("flickable03.qml")); + window->show(); + window->requestActivateWindow(); + QTest::qWaitForWindowShown(window); + QVERIFY(window->rootObject() != 0); + + QQuickFlickable *flickable = qobject_cast(window->rootObject()); QVERIFY(flickable != 0); QSignalSpy vDragSpy(flickable, SIGNAL(draggingVerticallyChanged())); @@ -399,106 +729,218 @@ void tst_qquickflickable::movingAndDragging() QSignalSpy vMoveSpy(flickable, SIGNAL(movingVerticallyChanged())); QSignalSpy hMoveSpy(flickable, SIGNAL(movingHorizontallyChanged())); QSignalSpy moveSpy(flickable, SIGNAL(movingChanged())); + QSignalSpy dragStartSpy(flickable, SIGNAL(dragStarted())); QSignalSpy dragEndSpy(flickable, SIGNAL(dragEnded())); + QSignalSpy moveStartSpy(flickable, SIGNAL(movementStarted())); + QSignalSpy moveEndSpy(flickable, SIGNAL(movementEnded())); - //Vertical - QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50, 90)); - - QTest::mouseMove(canvas, QPoint(50, 80)); - QTest::mouseMove(canvas, QPoint(50, 70)); - QTest::mouseMove(canvas, QPoint(50, 60)); + // start the drag + QTest::mousePress(window, Qt::LeftButton, 0, moveFrom); + QTest::mouseMove(window, moveFrom + moveByWithoutSnapBack); + QTest::mouseMove(window, moveFrom + moveByWithoutSnapBack*2); + QTest::mouseMove(window, moveFrom + moveByWithoutSnapBack*3); - QMouseEvent moveEvent(QEvent::MouseMove, QPoint(50, 80), Qt::LeftButton, Qt::LeftButton, 0); - - QVERIFY(!flickable->isDraggingHorizontally()); - QVERIFY(flickable->isDraggingVertically()); + QVERIFY(flickable->isMoving()); + QCOMPARE(flickable->isMovingHorizontally(), horizontalEnabled); + QCOMPARE(flickable->isMovingVertically(), verticalEnabled); QVERIFY(flickable->isDragging()); - QCOMPARE(vDragSpy.count(), 1); - QCOMPARE(dragSpy.count(), 1); - QCOMPARE(hDragSpy.count(), 0); - QCOMPARE(dragStartSpy.count(), 1); - QCOMPARE(dragEndSpy.count(), 0); + QCOMPARE(flickable->isDraggingHorizontally(), horizontalEnabled); + QCOMPARE(flickable->isDraggingVertically(), verticalEnabled); - QVERIFY(!flickable->isMovingHorizontally()); - QVERIFY(flickable->isMovingVertically()); - QVERIFY(flickable->isMoving()); - QCOMPARE(vMoveSpy.count(), 1); QCOMPARE(moveSpy.count(), 1); - QCOMPARE(hMoveSpy.count(), 0); + QCOMPARE(vMoveSpy.count(), verticalEnabled ? 1 : 0); + QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 1 : 0); + QCOMPARE(dragSpy.count(), 1); + QCOMPARE(vDragSpy.count(), verticalEnabled ? 1 : 0); + QCOMPARE(hDragSpy.count(), horizontalEnabled ? 1 : 0); + + QCOMPARE(moveStartSpy.count(), 1); + QCOMPARE(dragStartSpy.count(), 1); - QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50, 60)); + QTest::mouseRelease(window, Qt::LeftButton, 0, moveFrom + moveByWithoutSnapBack*3); - QTRY_VERIFY(!flickable->isDraggingVertically()); QVERIFY(!flickable->isDragging()); - QCOMPARE(vDragSpy.count(), 2); + QVERIFY(!flickable->isDraggingHorizontally()); + QVERIFY(!flickable->isDraggingVertically()); QCOMPARE(dragSpy.count(), 2); - QCOMPARE(hDragSpy.count(), 0); + QCOMPARE(vDragSpy.count(), verticalEnabled ? 2 : 0); + QCOMPARE(hDragSpy.count(), horizontalEnabled ? 2 : 0); QCOMPARE(dragStartSpy.count(), 1); QCOMPARE(dragEndSpy.count(), 1); + // Don't test whether moving finished because a flick could occur // wait for any motion to end QTRY_VERIFY(flickable->isMoving() == false); - //Horizontal - vDragSpy.clear(); - hDragSpy.clear(); - dragSpy.clear(); - vMoveSpy.clear(); - hMoveSpy.clear(); - moveSpy.clear(); - dragStartSpy.clear(); - dragEndSpy.clear(); - - QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(90, 50)); + QVERIFY(!flickable->isMovingHorizontally()); + QVERIFY(!flickable->isMovingVertically()); + QVERIFY(!flickable->isDragging()); + QVERIFY(!flickable->isDraggingHorizontally()); + QVERIFY(!flickable->isDraggingVertically()); - QTest::mouseMove(canvas, QPoint(80, 50)); - QTest::mouseMove(canvas, QPoint(70, 50)); - QTest::mouseMove(canvas, QPoint(60, 50)); + QCOMPARE(dragSpy.count(), 2); + QCOMPARE(vDragSpy.count(), verticalEnabled ? 2 : 0); + QCOMPARE(hDragSpy.count(), horizontalEnabled ? 2 : 0); + QCOMPARE(moveSpy.count(), 2); + QCOMPARE(vMoveSpy.count(), verticalEnabled ? 2 : 0); + QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 2 : 0); - QVERIFY(!flickable->isDraggingVertically()); - QVERIFY(flickable->isDraggingHorizontally()); - QVERIFY(flickable->isDragging()); - QCOMPARE(vDragSpy.count(), 0); - QCOMPARE(dragSpy.count(), 1); - QCOMPARE(hDragSpy.count(), 1); QCOMPARE(dragStartSpy.count(), 1); - QCOMPARE(dragEndSpy.count(), 0); + QCOMPARE(dragEndSpy.count(), 1); + QCOMPARE(moveStartSpy.count(), 1); + QCOMPARE(moveEndSpy.count(), 1); + + // Stop on a full pixel after user interaction + if (verticalEnabled) + QCOMPARE(flickable->contentY(), (qreal)qRound(flickable->contentY())); + if (horizontalEnabled) + QCOMPARE(flickable->contentX(), (qreal)qRound(flickable->contentX())); + + // clear for next drag + vMoveSpy.clear(); hMoveSpy.clear(); moveSpy.clear(); + vDragSpy.clear(); hDragSpy.clear(); dragSpy.clear(); + moveStartSpy.clear(); moveEndSpy.clear(); + dragStartSpy.clear(); dragEndSpy.clear(); + + // do a drag that drags the view out of bounds + flickable->setContentX(0); + flickable->setContentY(0); + QTRY_VERIFY(!flickable->isMoving()); + QTest::mousePress(window, Qt::LeftButton, 0, moveFrom); + QTest::mouseMove(window, moveFrom + moveByWithSnapBack); + QTest::mouseMove(window, moveFrom + moveByWithSnapBack*2); + QTest::mouseMove(window, moveFrom + moveByWithSnapBack*3); + + QVERIFY(flickable->isMoving()); + QCOMPARE(flickable->isMovingHorizontally(), horizontalEnabled); + QCOMPARE(flickable->isMovingVertically(), verticalEnabled); + QVERIFY(flickable->isDragging()); + QCOMPARE(flickable->isDraggingHorizontally(), horizontalEnabled); + QCOMPARE(flickable->isDraggingVertically(), verticalEnabled); + + QCOMPARE(moveSpy.count(), 1); + QCOMPARE(vMoveSpy.count(), verticalEnabled ? 1 : 0); + QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 1 : 0); + QCOMPARE(dragSpy.count(), 1); + QCOMPARE(vDragSpy.count(), verticalEnabled ? 1 : 0); + QCOMPARE(hDragSpy.count(), horizontalEnabled ? 1 : 0); + + QCOMPARE(moveStartSpy.count(), 1); + QCOMPARE(moveEndSpy.count(), 0); + QCOMPARE(dragStartSpy.count(), 1); + QCOMPARE(dragEndSpy.count(), 0); + + QTest::mouseRelease(window, Qt::LeftButton, 0, moveFrom + moveByWithSnapBack*3); + + // should now start snapping back to bounds (moving but not dragging) + QVERIFY(flickable->isMoving()); + QCOMPARE(flickable->isMovingHorizontally(), horizontalEnabled); + QCOMPARE(flickable->isMovingVertically(), verticalEnabled); + QVERIFY(!flickable->isDragging()); + QVERIFY(!flickable->isDraggingHorizontally()); + QVERIFY(!flickable->isDraggingVertically()); + + QCOMPARE(moveSpy.count(), 1); + QCOMPARE(vMoveSpy.count(), verticalEnabled ? 1 : 0); + QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 1 : 0); + QCOMPARE(dragSpy.count(), 2); + QCOMPARE(vDragSpy.count(), verticalEnabled ? 2 : 0); + QCOMPARE(hDragSpy.count(), horizontalEnabled ? 2 : 0); + + QCOMPARE(moveStartSpy.count(), 1); + QCOMPARE(moveEndSpy.count(), 0); + + // wait for any motion to end + QTRY_VERIFY(!flickable->isMoving()); + + QVERIFY(!flickable->isMovingHorizontally()); + QVERIFY(!flickable->isMovingVertically()); + QVERIFY(!flickable->isDragging()); + QVERIFY(!flickable->isDraggingHorizontally()); + QVERIFY(!flickable->isDraggingVertically()); + + QCOMPARE(moveSpy.count(), 2); + QCOMPARE(vMoveSpy.count(), verticalEnabled ? 2 : 0); + QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 2 : 0); + QCOMPARE(dragSpy.count(), 2); + QCOMPARE(vDragSpy.count(), verticalEnabled ? 2 : 0); + QCOMPARE(hDragSpy.count(), horizontalEnabled ? 2 : 0); + + QCOMPARE(moveStartSpy.count(), 1); + QCOMPARE(moveEndSpy.count(), 1); + QCOMPARE(dragStartSpy.count(), 1); + QCOMPARE(dragEndSpy.count(), 1); + + QCOMPARE(flickable->contentX(), 0.0); + QCOMPARE(flickable->contentY(), 0.0); + + delete window; +} - QVERIFY(!flickable->isMovingVertically()); - QVERIFY(flickable->isMovingHorizontally()); - QVERIFY(flickable->isMoving()); - QCOMPARE(vMoveSpy.count(), 0); - QCOMPARE(moveSpy.count(), 1); - QCOMPARE(hMoveSpy.count(), 1); +void tst_qquickflickable::flickOnRelease() +{ +#ifdef Q_OS_MAC + QSKIP("Producing flicks on Mac CI impossible due to timing problems"); +#endif + QQuickView *window = new QQuickView; + window->setSource(testFileUrl("flickable03.qml")); + window->show(); + window->requestActivateWindow(); + QTest::qWaitForWindowShown(window); + QVERIFY(window->rootObject() != 0); + + QQuickFlickable *flickable = qobject_cast(window->rootObject()); + QVERIFY(flickable != 0); - QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(60, 50)); + // Vertical with a quick press-move-release: should cause a flick in release. + QSignalSpy vFlickSpy(flickable, SIGNAL(flickingVerticallyChanged())); + // Use something that generates a huge velocity just to make it testable. + // In practice this feature matters on touchscreen devices where the + // underlying drivers will hopefully provide a pre-calculated velocity + // (based on more data than what the UI gets), thus making this use case + // working even with small movements. + QTest::mousePress(window, Qt::LeftButton, 0, QPoint(50, 300)); + QTest::mouseMove(window, QPoint(50, 10), 10); + QTest::mouseRelease(window, Qt::LeftButton, 0, QPoint(50, 10), 10); - QTRY_VERIFY(!flickable->isDraggingHorizontally()); - QVERIFY(!flickable->isDragging()); - QCOMPARE(vDragSpy.count(), 0); - QCOMPARE(dragSpy.count(), 2); - QCOMPARE(hDragSpy.count(), 2); - QCOMPARE(dragStartSpy.count(), 1); - QCOMPARE(dragEndSpy.count(), 1); - // Don't test moving because a flick could occur + QCOMPARE(vFlickSpy.count(), 1); + + // wait for any motion to end + QTRY_VERIFY(flickable->isMoving() == false); + + // Stop on a full pixel after user interaction + QCOMPARE(flickable->contentY(), (qreal)qRound(flickable->contentY())); + delete window; +} + +void tst_qquickflickable::pressWhileFlicking() +{ #ifdef Q_OS_MAC QSKIP("Producing flicks on Mac CI impossible due to timing problems"); #endif - QTRY_VERIFY(!flickable->isMoving()); + QQuickView *window = new QQuickView; + window->setSource(testFileUrl("flickable03.qml")); + window->show(); + window->requestActivateWindow(); + QTest::qWaitForWindowShown(window); + QVERIFY(window->rootObject() != 0); - vMoveSpy.clear(); - hMoveSpy.clear(); - moveSpy.clear(); - QSignalSpy vFlickSpy(flickable, SIGNAL(flickingVerticallyChanged())); + QQuickFlickable *flickable = qobject_cast(window->rootObject()); + QVERIFY(flickable != 0); + + QSignalSpy vMoveSpy(flickable, SIGNAL(movingVerticallyChanged())); + QSignalSpy hMoveSpy(flickable, SIGNAL(movingHorizontallyChanged())); + QSignalSpy moveSpy(flickable, SIGNAL(movingChanged())); QSignalSpy hFlickSpy(flickable, SIGNAL(flickingHorizontallyChanged())); + QSignalSpy vFlickSpy(flickable, SIGNAL(flickingVerticallyChanged())); QSignalSpy flickSpy(flickable, SIGNAL(flickingChanged())); // flick then press while it is still moving // flicking == false, moving == true; - flick(canvas, QPoint(20,190), QPoint(20, 50), 200); + flick(window, QPoint(20,190), QPoint(20, 50), 200); QVERIFY(flickable->verticalVelocity() > 0.0); QVERIFY(flickable->isFlicking()); QVERIFY(flickable->isFlickingVertically()); @@ -513,47 +955,49 @@ void tst_qquickflickable::movingAndDragging() QCOMPARE(hFlickSpy.count(), 0); QCOMPARE(flickSpy.count(), 1); - QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(20, 50)); + QTest::mousePress(window, Qt::LeftButton, 0, QPoint(20, 50)); QTRY_VERIFY(!flickable->isFlicking()); QVERIFY(!flickable->isFlickingVertically()); QVERIFY(flickable->isMoving()); QVERIFY(flickable->isMovingVertically()); - QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(20,50)); + QTest::mouseRelease(window, Qt::LeftButton, 0, QPoint(20,50)); QVERIFY(!flickable->isFlicking()); QVERIFY(!flickable->isFlickingVertically()); QTRY_VERIFY(!flickable->isMoving()); QVERIFY(!flickable->isMovingVertically()); + // Stop on a full pixel after user interaction + QCOMPARE(flickable->contentX(), (qreal)qRound(flickable->contentX())); - delete canvas; + delete window; } void tst_qquickflickable::disabled() { - QQuickView *canvas = new QQuickView; - canvas->setSource(testFileUrl("disabled.qml")); - canvas->show(); - canvas->requestActivateWindow(); - QVERIFY(canvas->rootObject() != 0); + QQuickView *window = new QQuickView; + window->setSource(testFileUrl("disabled.qml")); + window->show(); + window->requestActivateWindow(); + QVERIFY(window->rootObject() != 0); - QQuickFlickable *flick = canvas->rootObject()->findChild("flickable"); + QQuickFlickable *flick = window->rootObject()->findChild("flickable"); QVERIFY(flick != 0); - QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50, 90)); + QTest::mousePress(window, Qt::LeftButton, 0, QPoint(50, 90)); - QTest::mouseMove(canvas, QPoint(50, 80)); - QTest::mouseMove(canvas, QPoint(50, 70)); - QTest::mouseMove(canvas, QPoint(50, 60)); + QTest::mouseMove(window, QPoint(50, 80)); + QTest::mouseMove(window, QPoint(50, 70)); + QTest::mouseMove(window, QPoint(50, 60)); QVERIFY(flick->isMoving() == false); - QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50, 60)); + QTest::mouseRelease(window, Qt::LeftButton, 0, QPoint(50, 60)); // verify that mouse clicks on other elements still work (QTBUG-20584) - QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(50, 10)); - QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50, 10)); + QTest::mousePress(window, Qt::LeftButton, 0, QPoint(50, 10)); + QTest::mouseRelease(window, Qt::LeftButton, 0, QPoint(50, 10)); - QTRY_VERIFY(canvas->rootObject()->property("clicked").toBool() == true); + QTRY_VERIFY(window->rootObject()->property("clicked").toBool() == true); } void tst_qquickflickable::flickVelocity() @@ -562,22 +1006,22 @@ void tst_qquickflickable::flickVelocity() QSKIP("Producing flicks on Mac CI impossible due to timing problems"); #endif - QQuickView *canvas = new QQuickView; - canvas->setSource(testFileUrl("flickable03.qml")); - canvas->show(); - canvas->requestActivateWindow(); - QVERIFY(canvas->rootObject() != 0); + QQuickView *window = new QQuickView; + window->setSource(testFileUrl("flickable03.qml")); + window->show(); + window->requestActivateWindow(); + QVERIFY(window->rootObject() != 0); - QQuickFlickable *flickable = qobject_cast(canvas->rootObject()); + QQuickFlickable *flickable = qobject_cast(window->rootObject()); QVERIFY(flickable != 0); // flick up - flick(canvas, QPoint(20,190), QPoint(20, 50), 200); + flick(window, QPoint(20,190), QPoint(20, 50), 200); QVERIFY(flickable->verticalVelocity() > 0.0); QTRY_VERIFY(flickable->verticalVelocity() == 0.0); // flick down - flick(canvas, QPoint(20,10), QPoint(20, 140), 200); + flick(window, QPoint(20,10), QPoint(20, 140), 200); QVERIFY(flickable->verticalVelocity() < 0.0); QTRY_VERIFY(flickable->verticalVelocity() == 0.0); @@ -585,17 +1029,17 @@ void tst_qquickflickable::flickVelocity() QQuickFlickablePrivate *fp = QQuickFlickablePrivate::get(flickable); bool boosted = false; for (int i = 0; i < 6; ++i) { - flick(canvas, QPoint(20,390), QPoint(20, 50), 100); + flick(window, QPoint(20,390), QPoint(20, 50), 100); boosted |= fp->flickBoost > 1.0; } QVERIFY(boosted); // Flick in opposite direction -> boost cancelled. - flick(canvas, QPoint(20,10), QPoint(20, 340), 200); + flick(window, QPoint(20,10), QPoint(20, 340), 200); QTRY_VERIFY(flickable->verticalVelocity() < 0.0); QVERIFY(fp->flickBoost == 1.0); - delete canvas; + delete window; } void tst_qquickflickable::margins() @@ -611,8 +1055,8 @@ void tst_qquickflickable::margins() QCOMPARE(obj->contentY(), -20.); QCOMPARE(obj->contentWidth(), 1600.); QCOMPARE(obj->contentHeight(), 600.); - QCOMPARE(obj->xOrigin(), 0.); - QCOMPARE(obj->yOrigin(), 0.); + QCOMPARE(obj->originX(), 0.); + QCOMPARE(obj->originY(), 0.); // Reduce left margin obj->setLeftMargin(30); @@ -657,6 +1101,87 @@ void tst_qquickflickable::margins() delete root; } +void tst_qquickflickable::cancelOnMouseGrab() +{ + QQuickView *window = new QQuickView; + window->setSource(testFileUrl("cancel.qml")); + window->show(); + window->requestActivateWindow(); + QVERIFY(window->rootObject() != 0); + + QQuickFlickable *flickable = qobject_cast(window->rootObject()); + QVERIFY(flickable != 0); + + QTest::mousePress(window, Qt::LeftButton, 0, QPoint(10, 10)); + // drag out of bounds + QTest::mouseMove(window, QPoint(50, 50)); + QTest::mouseMove(window, QPoint(100, 100)); + QTest::mouseMove(window, QPoint(150, 150)); + + QVERIFY(flickable->contentX() != 0); + QVERIFY(flickable->contentY() != 0); + QVERIFY(flickable->isMoving()); + QVERIFY(flickable->isDragging()); + + // grabbing mouse will cancel flickable interaction. + QQuickItem *item = window->rootObject()->findChild("row"); + item->grabMouse(); + + QTRY_COMPARE(flickable->contentX(), 0.); + QTRY_COMPARE(flickable->contentY(), 0.); + QTRY_VERIFY(!flickable->isMoving()); + QTRY_VERIFY(!flickable->isDragging()); + + QTest::mouseRelease(window, Qt::LeftButton, 0, QPoint(50, 10)); +} + +void tst_qquickflickable::clickAndDragWhenTransformed() +{ + QQuickView *view = new QQuickView; + view->setSource(testFileUrl("transformedFlickable.qml")); + view->show(); + view->requestActivateWindow(); + QTest::qWaitForWindowShown(view); + QVERIFY(view->rootObject() != 0); + + QQuickFlickable *flickable = view->rootObject()->findChild("flickable"); + QVERIFY(flickable != 0); + + // click outside child rect + QTest::mousePress(view, Qt::LeftButton, 0, QPoint(190, 190)); + QTest::qWait(10); + QCOMPARE(flickable->property("itemPressed").toBool(), false); + QTest::mouseRelease(view, Qt::LeftButton, 0, QPoint(190, 190)); + + // click inside child rect + QTest::mousePress(view, Qt::LeftButton, 0, QPoint(200, 200)); + QTest::qWait(10); + QCOMPARE(flickable->property("itemPressed").toBool(), true); + QTest::mouseRelease(view, Qt::LeftButton, 0, QPoint(200, 200)); + + const int threshold = qApp->styleHints()->startDragDistance(); + + // drag outside bounds + QTest::mousePress(view, Qt::LeftButton, 0, QPoint(160, 160)); + QTest::qWait(10); + QTest::mouseMove(view, QPoint(160 + threshold * 2, 160)); + QTest::mouseMove(view, QPoint(160 + threshold * 3, 160)); + QCOMPARE(flickable->isDragging(), false); + QCOMPARE(flickable->property("itemPressed").toBool(), false); + QTest::mouseRelease(view, Qt::LeftButton, 0, QPoint(180, 160)); + + // drag inside bounds + QTest::mousePress(view, Qt::LeftButton, 0, QPoint(200, 140)); + QTest::qWait(10); + QTest::mouseMove(view, QPoint(200 + threshold * 2, 140)); + QTest::mouseMove(view, QPoint(200 + threshold * 3, 140)); + QCOMPARE(flickable->isDragging(), true); + QCOMPARE(flickable->property("itemPressed").toBool(), false); + QTest::mouseRelease(view, Qt::LeftButton, 0, QPoint(220, 140)); + + delete view; +} + QTEST_MAIN(tst_qquickflickable) #include "tst_qquickflickable.moc"