1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the test suite of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include <QtTest/QSignalSpy>
43 #include <QtDeclarative/qdeclarativeengine.h>
44 #include <QtDeclarative/qdeclarativecomponent.h>
45 #include <QtQuick1/qdeclarativeview.h>
46 #include <private/qdeclarativeflickable_p.h>
47 #include <private/qdeclarativevaluetype_p.h>
48 #include <QtWidgets/qgraphicswidget.h>
51 class tst_qdeclarativeflickable : public QObject
55 tst_qdeclarativeflickable();
59 void horizontalViewportSize();
60 void verticalViewportSize();
62 void boundsBehavior();
63 void maximumFlickVelocity();
64 void flickDeceleration();
66 void disabledContent();
67 void nestedPressDelay();
68 void flickableDirection();
69 void qgraphicswidget();
71 void returnToBounds();
72 void testQtQuick11Attributes();
73 void testQtQuick11Attributes_data();
79 QDeclarativeEngine engine;
81 void flick(QGraphicsView *canvas, const QPoint &from, const QPoint &to, int duration);
83 T *findItem(QGraphicsObject *parent, const QString &objectName);
86 tst_qdeclarativeflickable::tst_qdeclarativeflickable()
90 void tst_qdeclarativeflickable::create()
92 QDeclarativeEngine engine;
93 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/flickable01.qml"));
94 QDeclarative1Flickable *obj = qobject_cast<QDeclarative1Flickable*>(c.create());
97 QCOMPARE(obj->isAtXBeginning(), true);
98 QCOMPARE(obj->isAtXEnd(), false);
99 QCOMPARE(obj->isAtYBeginning(), true);
100 QCOMPARE(obj->isAtYEnd(), false);
101 QCOMPARE(obj->contentX(), 0.);
102 QCOMPARE(obj->contentY(), 0.);
104 QCOMPARE(obj->horizontalVelocity(), 0.);
105 QCOMPARE(obj->verticalVelocity(), 0.);
107 QCOMPARE(obj->isInteractive(), true);
108 QCOMPARE(obj->boundsBehavior(), QDeclarative1Flickable::DragAndOvershootBounds);
109 QCOMPARE(obj->pressDelay(), 0);
110 QCOMPARE(obj->maximumFlickVelocity(), 2500.);
115 void tst_qdeclarativeflickable::horizontalViewportSize()
117 QDeclarativeEngine engine;
118 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/flickable02.qml"));
119 QDeclarative1Flickable *obj = qobject_cast<QDeclarative1Flickable*>(c.create());
122 QCOMPARE(obj->contentWidth(), 800.);
123 QCOMPARE(obj->contentHeight(), 300.);
124 QCOMPARE(obj->isAtXBeginning(), true);
125 QCOMPARE(obj->isAtXEnd(), false);
126 QCOMPARE(obj->isAtYBeginning(), true);
127 QCOMPARE(obj->isAtYEnd(), false);
132 void tst_qdeclarativeflickable::verticalViewportSize()
134 QDeclarativeEngine engine;
135 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/flickable03.qml"));
136 QDeclarative1Flickable *obj = qobject_cast<QDeclarative1Flickable*>(c.create());
139 QCOMPARE(obj->contentWidth(), 200.);
140 QCOMPARE(obj->contentHeight(), 1200.);
141 QCOMPARE(obj->isAtXBeginning(), true);
142 QCOMPARE(obj->isAtXEnd(), false);
143 QCOMPARE(obj->isAtYBeginning(), true);
144 QCOMPARE(obj->isAtYEnd(), false);
149 void tst_qdeclarativeflickable::properties()
151 QDeclarativeEngine engine;
152 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/flickable04.qml"));
153 QDeclarative1Flickable *obj = qobject_cast<QDeclarative1Flickable*>(c.create());
156 QCOMPARE(obj->isInteractive(), false);
157 QCOMPARE(obj->boundsBehavior(), QDeclarative1Flickable::StopAtBounds);
158 QCOMPARE(obj->pressDelay(), 200);
159 QCOMPARE(obj->maximumFlickVelocity(), 2000.);
161 QVERIFY(obj->property("ok").toBool() == false);
162 QMetaObject::invokeMethod(obj, "check");
163 QVERIFY(obj->property("ok").toBool() == true);
168 void tst_qdeclarativeflickable::boundsBehavior()
170 QDeclarativeComponent component(&engine);
171 component.setData("import QtQuick 1.0; Flickable { boundsBehavior: Flickable.StopAtBounds }", QUrl::fromLocalFile(""));
172 QDeclarative1Flickable *flickable = qobject_cast<QDeclarative1Flickable*>(component.create());
173 QSignalSpy spy(flickable, SIGNAL(boundsBehaviorChanged()));
176 QVERIFY(flickable->boundsBehavior() == QDeclarative1Flickable::StopAtBounds);
178 flickable->setBoundsBehavior(QDeclarative1Flickable::DragAndOvershootBounds);
179 QVERIFY(flickable->boundsBehavior() == QDeclarative1Flickable::DragAndOvershootBounds);
180 QCOMPARE(spy.count(),1);
181 flickable->setBoundsBehavior(QDeclarative1Flickable::DragAndOvershootBounds);
182 QCOMPARE(spy.count(),1);
184 flickable->setBoundsBehavior(QDeclarative1Flickable::DragOverBounds);
185 QVERIFY(flickable->boundsBehavior() == QDeclarative1Flickable::DragOverBounds);
186 QCOMPARE(spy.count(),2);
187 flickable->setBoundsBehavior(QDeclarative1Flickable::DragOverBounds);
188 QCOMPARE(spy.count(),2);
190 flickable->setBoundsBehavior(QDeclarative1Flickable::StopAtBounds);
191 QVERIFY(flickable->boundsBehavior() == QDeclarative1Flickable::StopAtBounds);
192 QCOMPARE(spy.count(),3);
193 flickable->setBoundsBehavior(QDeclarative1Flickable::StopAtBounds);
194 QCOMPARE(spy.count(),3);
197 void tst_qdeclarativeflickable::maximumFlickVelocity()
199 QDeclarativeComponent component(&engine);
200 component.setData("import QtQuick 1.0; Flickable { maximumFlickVelocity: 1.0; }", QUrl::fromLocalFile(""));
201 QDeclarative1Flickable *flickable = qobject_cast<QDeclarative1Flickable*>(component.create());
202 QSignalSpy spy(flickable, SIGNAL(maximumFlickVelocityChanged()));
205 QCOMPARE(flickable->maximumFlickVelocity(), 1.0);
207 flickable->setMaximumFlickVelocity(2.0);
208 QCOMPARE(flickable->maximumFlickVelocity(), 2.0);
209 QCOMPARE(spy.count(),1);
210 flickable->setMaximumFlickVelocity(2.0);
211 QCOMPARE(spy.count(),1);
214 void tst_qdeclarativeflickable::flickDeceleration()
216 QDeclarativeComponent component(&engine);
217 component.setData("import QtQuick 1.0; Flickable { flickDeceleration: 1.0; }", QUrl::fromLocalFile(""));
218 QDeclarative1Flickable *flickable = qobject_cast<QDeclarative1Flickable*>(component.create());
219 QSignalSpy spy(flickable, SIGNAL(flickDecelerationChanged()));
222 QCOMPARE(flickable->flickDeceleration(), 1.0);
224 flickable->setFlickDeceleration(2.0);
225 QCOMPARE(flickable->flickDeceleration(), 2.0);
226 QCOMPARE(spy.count(),1);
227 flickable->setFlickDeceleration(2.0);
228 QCOMPARE(spy.count(),1);
231 void tst_qdeclarativeflickable::pressDelay()
233 QDeclarativeComponent component(&engine);
234 component.setData("import QtQuick 1.0; Flickable { pressDelay: 100; }", QUrl::fromLocalFile(""));
235 QDeclarative1Flickable *flickable = qobject_cast<QDeclarative1Flickable*>(component.create());
236 QSignalSpy spy(flickable, SIGNAL(pressDelayChanged()));
239 QCOMPARE(flickable->pressDelay(), 100);
241 flickable->setPressDelay(200);
242 QCOMPARE(flickable->pressDelay(), 200);
243 QCOMPARE(spy.count(),1);
244 flickable->setPressDelay(200);
245 QCOMPARE(spy.count(),1);
249 void tst_qdeclarativeflickable::disabledContent()
251 QDeclarativeView *canvas = new QDeclarativeView;
252 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/disabledcontent.qml"));
255 QVERIFY(canvas->rootObject() != 0);
257 QDeclarative1Flickable *flickable = qobject_cast<QDeclarative1Flickable*>(canvas->rootObject());
258 QVERIFY(flickable != 0);
260 QVERIFY(flickable->contentX() == 0);
261 QVERIFY(flickable->contentY() == 0);
263 QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(50, 50)));
265 QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(70,70)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
266 QApplication::sendEvent(canvas->viewport(), &mv);
269 QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(90,90)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
270 QApplication::sendEvent(canvas->viewport(), &mv);
273 QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(100,100)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
274 QApplication::sendEvent(canvas->viewport(), &mv);
277 QVERIFY(flickable->contentX() < 0);
278 QVERIFY(flickable->contentY() < 0);
280 QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(90, 90)));
287 void tst_qdeclarativeflickable::nestedPressDelay()
289 QDeclarativeView *canvas = new QDeclarativeView;
290 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/nestedPressDelay.qml"));
293 QVERIFY(canvas->rootObject() != 0);
295 QDeclarative1Flickable *outer = qobject_cast<QDeclarative1Flickable*>(canvas->rootObject());
298 QDeclarative1Flickable *inner = canvas->rootObject()->findChild<QDeclarative1Flickable*>("innerFlickable");
301 QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(150, 150)));
302 // the MouseArea is not pressed immediately
303 QVERIFY(outer->property("pressed").toBool() == false);
305 // The outer pressDelay will prevail (50ms, vs. 10sec)
306 // QTRY_VERIFY() has 5sec timeout, so will timeout well within 10sec.
307 QTRY_VERIFY(outer->property("pressed").toBool() == true);
309 QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(150, 150)));
314 void tst_qdeclarativeflickable::flickableDirection()
316 QDeclarativeComponent component(&engine);
317 component.setData("import QtQuick 1.0; Flickable { flickableDirection: Flickable.VerticalFlick; }", QUrl::fromLocalFile(""));
318 QDeclarative1Flickable *flickable = qobject_cast<QDeclarative1Flickable*>(component.create());
319 QSignalSpy spy(flickable, SIGNAL(flickableDirectionChanged()));
322 QCOMPARE(flickable->flickableDirection(), QDeclarative1Flickable::VerticalFlick);
324 flickable->setFlickableDirection(QDeclarative1Flickable::HorizontalAndVerticalFlick);
325 QCOMPARE(flickable->flickableDirection(), QDeclarative1Flickable::HorizontalAndVerticalFlick);
326 QCOMPARE(spy.count(),1);
328 flickable->setFlickableDirection(QDeclarative1Flickable::AutoFlickDirection);
329 QCOMPARE(flickable->flickableDirection(), QDeclarative1Flickable::AutoFlickDirection);
330 QCOMPARE(spy.count(),2);
332 flickable->setFlickableDirection(QDeclarative1Flickable::HorizontalFlick);
333 QCOMPARE(flickable->flickableDirection(), QDeclarative1Flickable::HorizontalFlick);
334 QCOMPARE(spy.count(),3);
336 flickable->setFlickableDirection(QDeclarative1Flickable::HorizontalFlick);
337 QCOMPARE(flickable->flickableDirection(), QDeclarative1Flickable::HorizontalFlick);
338 QCOMPARE(spy.count(),3);
341 void tst_qdeclarativeflickable::qgraphicswidget()
343 QDeclarativeEngine engine;
344 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/flickableqgraphicswidget.qml"));
345 QDeclarative1Flickable *flickable = qobject_cast<QDeclarative1Flickable*>(c.create());
347 QVERIFY(flickable != 0);
348 QGraphicsWidget *widget = findItem<QGraphicsWidget>(flickable->contentItem(), "widget1");
353 void tst_qdeclarativeflickable::resizeContent()
355 QDeclarativeEngine engine;
356 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/resize.qml"));
357 QDeclarativeItem *root = qobject_cast<QDeclarativeItem*>(c.create());
358 QDeclarative1Flickable *obj = findItem<QDeclarative1Flickable>(root, "flick");
361 QCOMPARE(obj->contentX(), 0.);
362 QCOMPARE(obj->contentY(), 0.);
363 QCOMPARE(obj->contentWidth(), 300.);
364 QCOMPARE(obj->contentHeight(), 300.);
366 QMetaObject::invokeMethod(root, "resizeContent");
368 QCOMPARE(obj->contentX(), 100.);
369 QCOMPARE(obj->contentY(), 100.);
370 QCOMPARE(obj->contentWidth(), 600.);
371 QCOMPARE(obj->contentHeight(), 600.);
377 void tst_qdeclarativeflickable::returnToBounds()
379 QDeclarativeEngine engine;
380 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/resize.qml"));
381 QDeclarativeItem *root = qobject_cast<QDeclarativeItem*>(c.create());
382 QDeclarative1Flickable *obj = findItem<QDeclarative1Flickable>(root, "flick");
385 QCOMPARE(obj->contentX(), 0.);
386 QCOMPARE(obj->contentY(), 0.);
387 QCOMPARE(obj->contentWidth(), 300.);
388 QCOMPARE(obj->contentHeight(), 300.);
390 obj->setContentX(100);
391 obj->setContentY(400);
392 QTRY_COMPARE(obj->contentX(), 100.);
393 QTRY_COMPARE(obj->contentY(), 400.);
395 QMetaObject::invokeMethod(root, "returnToBounds");
397 QTRY_COMPARE(obj->contentX(), 0.);
398 QTRY_COMPARE(obj->contentY(), 0.);
403 void tst_qdeclarativeflickable::testQtQuick11Attributes()
405 QFETCH(QString, code);
406 QFETCH(QString, warning);
407 QFETCH(QString, error);
409 QDeclarativeEngine engine;
412 QDeclarativeComponent invalid(&engine);
413 invalid.setData("import QtQuick 1.0; Flickable { " + code.toUtf8() + " }", QUrl(""));
414 QTest::ignoreMessage(QtWarningMsg, warning.toUtf8());
415 obj = invalid.create();
416 QCOMPARE(invalid.errorString(), error);
419 QDeclarativeComponent valid(&engine);
420 valid.setData("import QtQuick 1.1; Flickable { " + code.toUtf8() + " }", QUrl(""));
421 obj = valid.create();
423 QVERIFY(valid.errorString().isEmpty());
427 void tst_qdeclarativeflickable::testQtQuick11Attributes_data()
429 QTest::addColumn<QString>("code");
430 QTest::addColumn<QString>("warning");
431 QTest::addColumn<QString>("error");
433 QTest::newRow("resizeContent") << "Component.onCompleted: resizeContent(100,100,Qt.point(50,50))"
434 << "<Unknown File>:1: ReferenceError: Can't find variable: resizeContent"
437 QTest::newRow("returnToBounds") << "Component.onCompleted: returnToBounds()"
438 << "<Unknown File>:1: ReferenceError: Can't find variable: returnToBounds"
443 void tst_qdeclarativeflickable::wheel()
445 QDeclarativeView *canvas = new QDeclarativeView;
446 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/wheel.qml"));
449 QVERIFY(canvas->rootObject() != 0);
451 QDeclarative1Flickable *flick = canvas->rootObject()->findChild<QDeclarative1Flickable*>("flick");
454 QGraphicsScene *scene = canvas->scene();
455 QGraphicsSceneWheelEvent event(QEvent::GraphicsSceneWheel);
456 event.setScenePos(QPointF(200, 200));
457 event.setDelta(-120);
458 event.setOrientation(Qt::Vertical);
459 event.setAccepted(false);
460 QApplication::sendEvent(scene, &event);
462 QTRY_VERIFY(flick->contentY() > 0);
463 QVERIFY(flick->contentX() == 0);
465 flick->setContentY(0);
466 QVERIFY(flick->contentY() == 0);
468 event.setScenePos(QPointF(200, 200));
469 event.setDelta(-120);
470 event.setOrientation(Qt::Horizontal);
471 event.setAccepted(false);
472 QApplication::sendEvent(scene, &event);
474 QTRY_VERIFY(flick->contentX() > 0);
475 QVERIFY(flick->contentY() == 0);
480 void tst_qdeclarativeflickable::disabled()
482 QDeclarativeView *canvas = new QDeclarativeView;
483 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/disabled.qml"));
486 QVERIFY(canvas->rootObject() != 0);
488 QDeclarative1Flickable *flick = canvas->rootObject()->findChild<QDeclarative1Flickable*>("flickable");
491 QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(50,90)));
493 QMouseEvent moveEvent(QEvent::MouseMove, canvas->mapFromScene(QPoint(50, 80)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
494 QApplication::sendEvent(canvas, &moveEvent);
496 moveEvent = QMouseEvent(QEvent::MouseMove, canvas->mapFromScene(QPoint(50, 70)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
497 QApplication::sendEvent(canvas, &moveEvent);
499 moveEvent = QMouseEvent(QEvent::MouseMove, canvas->mapFromScene(QPoint(50, 60)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
500 QApplication::sendEvent(canvas, &moveEvent);
502 QVERIFY(flick->isMoving() == false);
504 QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(50, 60)));
506 // verify that mouse clicks on other elements still work (QTBUG-20584)
507 QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(50, 10)));
508 QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(50, 10)));
510 QVERIFY(canvas->rootObject()->property("clicked").toBool() == true);
513 void tst_qdeclarativeflickable::flickVelocity()
516 QSKIP("Producing flicks on Mac CI impossible due to timing problems");
519 QDeclarativeView *canvas = new QDeclarativeView;
520 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/flickable03.qml"));
523 QVERIFY(canvas->rootObject() != 0);
525 QDeclarative1Flickable *flickable = qobject_cast<QDeclarative1Flickable*>(canvas->rootObject());
526 QVERIFY(flickable != 0);
529 flick(canvas, QPoint(20,190), QPoint(20, 50), 200);
530 QVERIFY(flickable->verticalVelocity() > 0.0);
531 QTRY_VERIFY(flickable->verticalVelocity() == 0.0);
534 flick(canvas, QPoint(20,10), QPoint(20, 140), 200);
535 QVERIFY(flickable->verticalVelocity() < 0.0);
536 QTRY_VERIFY(flickable->verticalVelocity() == 0.0);
541 void tst_qdeclarativeflickable::flick(QGraphicsView *canvas, const QPoint &from, const QPoint &to, int duration)
543 const int pointCount = 5;
544 QPoint diff = to - from;
546 // send press, five equally spaced moves, and release.
547 QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(from));
549 for (int i = 0; i < pointCount; ++i) {
550 QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(from + (i+1)*diff/pointCount), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
551 QApplication::sendEvent(canvas->viewport(), &mv);
552 QTest::qWait(duration/pointCount);
553 QCoreApplication::processEvents();
556 QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(to));
561 T *tst_qdeclarativeflickable::findItem(QGraphicsObject *parent, const QString &objectName)
563 const QMetaObject &mo = T::staticMetaObject;
564 //qDebug() << parent->childItems().count() << "children";
565 for (int i = 0; i < parent->childItems().count(); ++i) {
566 QGraphicsObject *item = qobject_cast<QGraphicsObject*>(parent->childItems().at(i));
569 //qDebug() << "try" << item;
570 if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
571 return static_cast<T*>(item);
573 item = findItem<T>(item, objectName);
575 return static_cast<T*>(item);
581 QTEST_MAIN(tst_qdeclarativeflickable)
583 #include "tst_qdeclarativeflickable.moc"