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>
50 #include "../../../shared/util.h"
53 // In Symbian OS test data is located in applications private dir
57 class tst_qdeclarativeflickable : public QObject
61 tst_qdeclarativeflickable();
65 void horizontalViewportSize();
66 void verticalViewportSize();
68 void boundsBehavior();
69 void maximumFlickVelocity();
70 void flickDeceleration();
72 void disabledContent();
73 void nestedPressDelay();
74 void flickableDirection();
75 void qgraphicswidget();
77 void returnToBounds();
78 void testQtQuick11Attributes();
79 void testQtQuick11Attributes_data();
85 QDeclarativeEngine engine;
87 void flick(QGraphicsView *canvas, const QPoint &from, const QPoint &to, int duration);
89 T *findItem(QGraphicsObject *parent, const QString &objectName);
92 tst_qdeclarativeflickable::tst_qdeclarativeflickable()
96 void tst_qdeclarativeflickable::create()
98 QDeclarativeEngine engine;
99 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/flickable01.qml"));
100 QDeclarative1Flickable *obj = qobject_cast<QDeclarative1Flickable*>(c.create());
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.);
110 QCOMPARE(obj->horizontalVelocity(), 0.);
111 QCOMPARE(obj->verticalVelocity(), 0.);
113 QCOMPARE(obj->isInteractive(), true);
114 QCOMPARE(obj->boundsBehavior(), QDeclarative1Flickable::DragAndOvershootBounds);
115 QCOMPARE(obj->pressDelay(), 0);
116 QCOMPARE(obj->maximumFlickVelocity(), 2500.);
121 void tst_qdeclarativeflickable::horizontalViewportSize()
123 QDeclarativeEngine engine;
124 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/flickable02.qml"));
125 QDeclarative1Flickable *obj = qobject_cast<QDeclarative1Flickable*>(c.create());
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);
138 void tst_qdeclarativeflickable::verticalViewportSize()
140 QDeclarativeEngine engine;
141 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/flickable03.qml"));
142 QDeclarative1Flickable *obj = qobject_cast<QDeclarative1Flickable*>(c.create());
145 QCOMPARE(obj->contentWidth(), 200.);
146 QCOMPARE(obj->contentHeight(), 1200.);
147 QCOMPARE(obj->isAtXBeginning(), true);
148 QCOMPARE(obj->isAtXEnd(), false);
149 QCOMPARE(obj->isAtYBeginning(), true);
150 QCOMPARE(obj->isAtYEnd(), false);
155 void tst_qdeclarativeflickable::properties()
157 QDeclarativeEngine engine;
158 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/flickable04.qml"));
159 QDeclarative1Flickable *obj = qobject_cast<QDeclarative1Flickable*>(c.create());
162 QCOMPARE(obj->isInteractive(), false);
163 QCOMPARE(obj->boundsBehavior(), QDeclarative1Flickable::StopAtBounds);
164 QCOMPARE(obj->pressDelay(), 200);
165 QCOMPARE(obj->maximumFlickVelocity(), 2000.);
167 QVERIFY(obj->property("ok").toBool() == false);
168 QMetaObject::invokeMethod(obj, "check");
169 QVERIFY(obj->property("ok").toBool() == true);
174 void tst_qdeclarativeflickable::boundsBehavior()
176 QDeclarativeComponent component(&engine);
177 component.setData("import QtQuick 1.0; Flickable { boundsBehavior: Flickable.StopAtBounds }", QUrl::fromLocalFile(""));
178 QDeclarative1Flickable *flickable = qobject_cast<QDeclarative1Flickable*>(component.create());
179 QSignalSpy spy(flickable, SIGNAL(boundsBehaviorChanged()));
182 QVERIFY(flickable->boundsBehavior() == QDeclarative1Flickable::StopAtBounds);
184 flickable->setBoundsBehavior(QDeclarative1Flickable::DragAndOvershootBounds);
185 QVERIFY(flickable->boundsBehavior() == QDeclarative1Flickable::DragAndOvershootBounds);
186 QCOMPARE(spy.count(),1);
187 flickable->setBoundsBehavior(QDeclarative1Flickable::DragAndOvershootBounds);
188 QCOMPARE(spy.count(),1);
190 flickable->setBoundsBehavior(QDeclarative1Flickable::DragOverBounds);
191 QVERIFY(flickable->boundsBehavior() == QDeclarative1Flickable::DragOverBounds);
192 QCOMPARE(spy.count(),2);
193 flickable->setBoundsBehavior(QDeclarative1Flickable::DragOverBounds);
194 QCOMPARE(spy.count(),2);
196 flickable->setBoundsBehavior(QDeclarative1Flickable::StopAtBounds);
197 QVERIFY(flickable->boundsBehavior() == QDeclarative1Flickable::StopAtBounds);
198 QCOMPARE(spy.count(),3);
199 flickable->setBoundsBehavior(QDeclarative1Flickable::StopAtBounds);
200 QCOMPARE(spy.count(),3);
203 void tst_qdeclarativeflickable::maximumFlickVelocity()
205 QDeclarativeComponent component(&engine);
206 component.setData("import QtQuick 1.0; Flickable { maximumFlickVelocity: 1.0; }", QUrl::fromLocalFile(""));
207 QDeclarative1Flickable *flickable = qobject_cast<QDeclarative1Flickable*>(component.create());
208 QSignalSpy spy(flickable, SIGNAL(maximumFlickVelocityChanged()));
211 QCOMPARE(flickable->maximumFlickVelocity(), 1.0);
213 flickable->setMaximumFlickVelocity(2.0);
214 QCOMPARE(flickable->maximumFlickVelocity(), 2.0);
215 QCOMPARE(spy.count(),1);
216 flickable->setMaximumFlickVelocity(2.0);
217 QCOMPARE(spy.count(),1);
220 void tst_qdeclarativeflickable::flickDeceleration()
222 QDeclarativeComponent component(&engine);
223 component.setData("import QtQuick 1.0; Flickable { flickDeceleration: 1.0; }", QUrl::fromLocalFile(""));
224 QDeclarative1Flickable *flickable = qobject_cast<QDeclarative1Flickable*>(component.create());
225 QSignalSpy spy(flickable, SIGNAL(flickDecelerationChanged()));
228 QCOMPARE(flickable->flickDeceleration(), 1.0);
230 flickable->setFlickDeceleration(2.0);
231 QCOMPARE(flickable->flickDeceleration(), 2.0);
232 QCOMPARE(spy.count(),1);
233 flickable->setFlickDeceleration(2.0);
234 QCOMPARE(spy.count(),1);
237 void tst_qdeclarativeflickable::pressDelay()
239 QDeclarativeComponent component(&engine);
240 component.setData("import QtQuick 1.0; Flickable { pressDelay: 100; }", QUrl::fromLocalFile(""));
241 QDeclarative1Flickable *flickable = qobject_cast<QDeclarative1Flickable*>(component.create());
242 QSignalSpy spy(flickable, SIGNAL(pressDelayChanged()));
245 QCOMPARE(flickable->pressDelay(), 100);
247 flickable->setPressDelay(200);
248 QCOMPARE(flickable->pressDelay(), 200);
249 QCOMPARE(spy.count(),1);
250 flickable->setPressDelay(200);
251 QCOMPARE(spy.count(),1);
255 void tst_qdeclarativeflickable::disabledContent()
257 QDeclarativeView *canvas = new QDeclarativeView;
258 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/disabledcontent.qml"));
261 QVERIFY(canvas->rootObject() != 0);
263 QDeclarative1Flickable *flickable = qobject_cast<QDeclarative1Flickable*>(canvas->rootObject());
264 QVERIFY(flickable != 0);
266 QVERIFY(flickable->contentX() == 0);
267 QVERIFY(flickable->contentY() == 0);
269 QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(50, 50)));
271 QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(70,70)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
272 QApplication::sendEvent(canvas->viewport(), &mv);
275 QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(90,90)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
276 QApplication::sendEvent(canvas->viewport(), &mv);
279 QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(100,100)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
280 QApplication::sendEvent(canvas->viewport(), &mv);
283 QVERIFY(flickable->contentX() < 0);
284 QVERIFY(flickable->contentY() < 0);
286 QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(90, 90)));
293 void tst_qdeclarativeflickable::nestedPressDelay()
295 QDeclarativeView *canvas = new QDeclarativeView;
296 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/nestedPressDelay.qml"));
299 QVERIFY(canvas->rootObject() != 0);
301 QDeclarative1Flickable *outer = qobject_cast<QDeclarative1Flickable*>(canvas->rootObject());
304 QDeclarative1Flickable *inner = canvas->rootObject()->findChild<QDeclarative1Flickable*>("innerFlickable");
307 QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(150, 150)));
308 // the MouseArea is not pressed immediately
309 QVERIFY(outer->property("pressed").toBool() == false);
311 // The outer pressDelay will prevail (50ms, vs. 10sec)
312 // QTRY_VERIFY() has 5sec timeout, so will timeout well within 10sec.
313 QTRY_VERIFY(outer->property("pressed").toBool() == true);
315 QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(150, 150)));
320 void tst_qdeclarativeflickable::flickableDirection()
322 QDeclarativeComponent component(&engine);
323 component.setData("import QtQuick 1.0; Flickable { flickableDirection: Flickable.VerticalFlick; }", QUrl::fromLocalFile(""));
324 QDeclarative1Flickable *flickable = qobject_cast<QDeclarative1Flickable*>(component.create());
325 QSignalSpy spy(flickable, SIGNAL(flickableDirectionChanged()));
328 QCOMPARE(flickable->flickableDirection(), QDeclarative1Flickable::VerticalFlick);
330 flickable->setFlickableDirection(QDeclarative1Flickable::HorizontalAndVerticalFlick);
331 QCOMPARE(flickable->flickableDirection(), QDeclarative1Flickable::HorizontalAndVerticalFlick);
332 QCOMPARE(spy.count(),1);
334 flickable->setFlickableDirection(QDeclarative1Flickable::AutoFlickDirection);
335 QCOMPARE(flickable->flickableDirection(), QDeclarative1Flickable::AutoFlickDirection);
336 QCOMPARE(spy.count(),2);
338 flickable->setFlickableDirection(QDeclarative1Flickable::HorizontalFlick);
339 QCOMPARE(flickable->flickableDirection(), QDeclarative1Flickable::HorizontalFlick);
340 QCOMPARE(spy.count(),3);
342 flickable->setFlickableDirection(QDeclarative1Flickable::HorizontalFlick);
343 QCOMPARE(flickable->flickableDirection(), QDeclarative1Flickable::HorizontalFlick);
344 QCOMPARE(spy.count(),3);
347 void tst_qdeclarativeflickable::qgraphicswidget()
349 QDeclarativeEngine engine;
350 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/flickableqgraphicswidget.qml"));
351 QDeclarative1Flickable *flickable = qobject_cast<QDeclarative1Flickable*>(c.create());
353 QVERIFY(flickable != 0);
354 QGraphicsWidget *widget = findItem<QGraphicsWidget>(flickable->contentItem(), "widget1");
359 void tst_qdeclarativeflickable::resizeContent()
361 QDeclarativeEngine engine;
362 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/resize.qml"));
363 QDeclarativeItem *root = qobject_cast<QDeclarativeItem*>(c.create());
364 QDeclarative1Flickable *obj = findItem<QDeclarative1Flickable>(root, "flick");
367 QCOMPARE(obj->contentX(), 0.);
368 QCOMPARE(obj->contentY(), 0.);
369 QCOMPARE(obj->contentWidth(), 300.);
370 QCOMPARE(obj->contentHeight(), 300.);
372 QMetaObject::invokeMethod(root, "resizeContent");
374 QCOMPARE(obj->contentX(), 100.);
375 QCOMPARE(obj->contentY(), 100.);
376 QCOMPARE(obj->contentWidth(), 600.);
377 QCOMPARE(obj->contentHeight(), 600.);
383 void tst_qdeclarativeflickable::returnToBounds()
385 QDeclarativeEngine engine;
386 QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/resize.qml"));
387 QDeclarativeItem *root = qobject_cast<QDeclarativeItem*>(c.create());
388 QDeclarative1Flickable *obj = findItem<QDeclarative1Flickable>(root, "flick");
391 QCOMPARE(obj->contentX(), 0.);
392 QCOMPARE(obj->contentY(), 0.);
393 QCOMPARE(obj->contentWidth(), 300.);
394 QCOMPARE(obj->contentHeight(), 300.);
396 obj->setContentX(100);
397 obj->setContentY(400);
398 QTRY_COMPARE(obj->contentX(), 100.);
399 QTRY_COMPARE(obj->contentY(), 400.);
401 QMetaObject::invokeMethod(root, "returnToBounds");
403 QTRY_COMPARE(obj->contentX(), 0.);
404 QTRY_COMPARE(obj->contentY(), 0.);
409 void tst_qdeclarativeflickable::testQtQuick11Attributes()
411 QFETCH(QString, code);
412 QFETCH(QString, warning);
413 QFETCH(QString, error);
415 QDeclarativeEngine engine;
418 QDeclarativeComponent invalid(&engine);
419 invalid.setData("import QtQuick 1.0; Flickable { " + code.toUtf8() + " }", QUrl(""));
420 QTest::ignoreMessage(QtWarningMsg, warning.toUtf8());
421 obj = invalid.create();
422 QCOMPARE(invalid.errorString(), error);
425 QDeclarativeComponent valid(&engine);
426 valid.setData("import QtQuick 1.1; Flickable { " + code.toUtf8() + " }", QUrl(""));
427 obj = valid.create();
429 QVERIFY(valid.errorString().isEmpty());
433 void tst_qdeclarativeflickable::testQtQuick11Attributes_data()
435 QTest::addColumn<QString>("code");
436 QTest::addColumn<QString>("warning");
437 QTest::addColumn<QString>("error");
439 QTest::newRow("resizeContent") << "Component.onCompleted: resizeContent(100,100,Qt.point(50,50))"
440 << "<Unknown File>:1: ReferenceError: Can't find variable: resizeContent"
443 QTest::newRow("returnToBounds") << "Component.onCompleted: returnToBounds()"
444 << "<Unknown File>:1: ReferenceError: Can't find variable: returnToBounds"
449 void tst_qdeclarativeflickable::wheel()
451 QDeclarativeView *canvas = new QDeclarativeView;
452 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/wheel.qml"));
455 QVERIFY(canvas->rootObject() != 0);
457 QDeclarative1Flickable *flick = canvas->rootObject()->findChild<QDeclarative1Flickable*>("flick");
460 QGraphicsScene *scene = canvas->scene();
461 QGraphicsSceneWheelEvent event(QEvent::GraphicsSceneWheel);
462 event.setScenePos(QPointF(200, 200));
463 event.setDelta(-120);
464 event.setOrientation(Qt::Vertical);
465 event.setAccepted(false);
466 QApplication::sendEvent(scene, &event);
468 QTRY_VERIFY(flick->contentY() > 0);
469 QVERIFY(flick->contentX() == 0);
471 flick->setContentY(0);
472 QVERIFY(flick->contentY() == 0);
474 event.setScenePos(QPointF(200, 200));
475 event.setDelta(-120);
476 event.setOrientation(Qt::Horizontal);
477 event.setAccepted(false);
478 QApplication::sendEvent(scene, &event);
480 QTRY_VERIFY(flick->contentX() > 0);
481 QVERIFY(flick->contentY() == 0);
486 void tst_qdeclarativeflickable::disabled()
488 QDeclarativeView *canvas = new QDeclarativeView;
489 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/disabled.qml"));
492 QVERIFY(canvas->rootObject() != 0);
494 QDeclarative1Flickable *flick = canvas->rootObject()->findChild<QDeclarative1Flickable*>("flickable");
497 QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(50,90)));
499 QMouseEvent moveEvent(QEvent::MouseMove, canvas->mapFromScene(QPoint(50, 80)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
500 QApplication::sendEvent(canvas, &moveEvent);
502 moveEvent = QMouseEvent(QEvent::MouseMove, canvas->mapFromScene(QPoint(50, 70)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
503 QApplication::sendEvent(canvas, &moveEvent);
505 moveEvent = QMouseEvent(QEvent::MouseMove, canvas->mapFromScene(QPoint(50, 60)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
506 QApplication::sendEvent(canvas, &moveEvent);
508 QVERIFY(flick->isMoving() == false);
510 QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(50, 60)));
512 // verify that mouse clicks on other elements still work (QTBUG-20584)
513 QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(50, 10)));
514 QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(50, 10)));
516 QVERIFY(canvas->rootObject()->property("clicked").toBool() == true);
519 void tst_qdeclarativeflickable::flickVelocity()
522 QSKIP("Producing flicks on Mac CI impossible due to timing problems", SkipAll);
525 QDeclarativeView *canvas = new QDeclarativeView;
526 canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/flickable03.qml"));
529 QVERIFY(canvas->rootObject() != 0);
531 QDeclarative1Flickable *flickable = qobject_cast<QDeclarative1Flickable*>(canvas->rootObject());
532 QVERIFY(flickable != 0);
535 flick(canvas, QPoint(20,190), QPoint(20, 50), 200);
536 QVERIFY(flickable->verticalVelocity() > 0.0);
537 QTRY_VERIFY(flickable->verticalVelocity() == 0.0);
540 flick(canvas, QPoint(20,10), QPoint(20, 140), 200);
541 QVERIFY(flickable->verticalVelocity() < 0.0);
542 QTRY_VERIFY(flickable->verticalVelocity() == 0.0);
547 void tst_qdeclarativeflickable::flick(QGraphicsView *canvas, const QPoint &from, const QPoint &to, int duration)
549 const int pointCount = 5;
550 QPoint diff = to - from;
552 // send press, five equally spaced moves, and release.
553 QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(from));
555 for (int i = 0; i < pointCount; ++i) {
556 QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(from + (i+1)*diff/pointCount), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
557 QApplication::sendEvent(canvas->viewport(), &mv);
558 QTest::qWait(duration/pointCount);
559 QCoreApplication::processEvents();
562 QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(to));
567 T *tst_qdeclarativeflickable::findItem(QGraphicsObject *parent, const QString &objectName)
569 const QMetaObject &mo = T::staticMetaObject;
570 //qDebug() << parent->childItems().count() << "children";
571 for (int i = 0; i < parent->childItems().count(); ++i) {
572 QGraphicsObject *item = qobject_cast<QGraphicsObject*>(parent->childItems().at(i));
575 //qDebug() << "try" << item;
576 if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
577 return static_cast<T*>(item);
579 item = findItem<T>(item, objectName);
581 return static_cast<T*>(item);
587 QTEST_MAIN(tst_qdeclarativeflickable)
589 #include "tst_qdeclarativeflickable.moc"