1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the test suite of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 #include <QtTest/QtTest>
43 #include <QtTest/QSignalSpy>
44 #include <QtGui/QStyleHints>
45 #include <private/qquickpincharea_p.h>
46 #include <QtQuick/private/qquickrectangle_p.h>
47 #include <QtQuick/qquickview.h>
48 #include <QtQml/qqmlcontext.h>
49 #include "../../shared/util.h"
51 class tst_QQuickPinchArea: public QQmlDataTest
55 tst_QQuickPinchArea() : device(0) { }
58 void cleanupTestCase();
59 void pinchProperties();
63 void transformedPinchArea_data();
64 void transformedPinchArea();
67 QQuickView *createView();
70 void tst_QQuickPinchArea::initTestCase()
72 QQmlDataTest::initTestCase();
74 device = new QTouchDevice;
75 device->setType(QTouchDevice::TouchScreen);
76 QWindowSystemInterface::registerTouchDevice(device);
80 void tst_QQuickPinchArea::cleanupTestCase()
84 void tst_QQuickPinchArea::pinchProperties()
86 QQuickView *canvas = createView();
87 canvas->setSource(testFileUrl("pinchproperties.qml"));
89 canvas->requestActivateWindow();
90 QVERIFY(canvas->rootObject() != 0);
92 QQuickPinchArea *pinchArea = canvas->rootObject()->findChild<QQuickPinchArea*>("pincharea");
93 QQuickPinch *pinch = pinchArea->pinch();
94 QVERIFY(pinchArea != 0);
98 QQuickItem *blackRect = canvas->rootObject()->findChild<QQuickItem*>("blackrect");
99 QVERIFY(blackRect != 0);
100 QVERIFY(blackRect == pinch->target());
101 QQuickItem *rootItem = qobject_cast<QQuickItem*>(canvas->rootObject());
102 QVERIFY(rootItem != 0);
103 QSignalSpy targetSpy(pinch, SIGNAL(targetChanged()));
104 pinch->setTarget(rootItem);
105 QCOMPARE(targetSpy.count(),1);
106 pinch->setTarget(rootItem);
107 QCOMPARE(targetSpy.count(),1);
110 QCOMPARE(pinch->axis(), QQuickPinch::XandYAxis);
111 QSignalSpy axisSpy(pinch, SIGNAL(dragAxisChanged()));
112 pinch->setAxis(QQuickPinch::XAxis);
113 QCOMPARE(pinch->axis(), QQuickPinch::XAxis);
114 QCOMPARE(axisSpy.count(),1);
115 pinch->setAxis(QQuickPinch::XAxis);
116 QCOMPARE(axisSpy.count(),1);
118 // minimum and maximum drag properties
119 QSignalSpy xminSpy(pinch, SIGNAL(minimumXChanged()));
120 QSignalSpy xmaxSpy(pinch, SIGNAL(maximumXChanged()));
121 QSignalSpy yminSpy(pinch, SIGNAL(minimumYChanged()));
122 QSignalSpy ymaxSpy(pinch, SIGNAL(maximumYChanged()));
124 QCOMPARE(pinch->xmin(), 0.0);
125 QCOMPARE(pinch->xmax(), rootItem->width()-blackRect->width());
126 QCOMPARE(pinch->ymin(), 0.0);
127 QCOMPARE(pinch->ymax(), rootItem->height()-blackRect->height());
134 QCOMPARE(pinch->xmin(), 10.0);
135 QCOMPARE(pinch->xmax(), 10.0);
136 QCOMPARE(pinch->ymin(), 10.0);
137 QCOMPARE(pinch->ymax(), 10.0);
139 QCOMPARE(xminSpy.count(),1);
140 QCOMPARE(xmaxSpy.count(),1);
141 QCOMPARE(yminSpy.count(),1);
142 QCOMPARE(ymaxSpy.count(),1);
149 QCOMPARE(xminSpy.count(),1);
150 QCOMPARE(xmaxSpy.count(),1);
151 QCOMPARE(yminSpy.count(),1);
152 QCOMPARE(ymaxSpy.count(),1);
154 // minimum and maximum scale properties
155 QSignalSpy scaleMinSpy(pinch, SIGNAL(minimumScaleChanged()));
156 QSignalSpy scaleMaxSpy(pinch, SIGNAL(maximumScaleChanged()));
158 QCOMPARE(pinch->minimumScale(), 1.0);
159 QCOMPARE(pinch->maximumScale(), 2.0);
161 pinch->setMinimumScale(0.5);
162 pinch->setMaximumScale(1.5);
164 QCOMPARE(pinch->minimumScale(), 0.5);
165 QCOMPARE(pinch->maximumScale(), 1.5);
167 QCOMPARE(scaleMinSpy.count(),1);
168 QCOMPARE(scaleMaxSpy.count(),1);
170 pinch->setMinimumScale(0.5);
171 pinch->setMaximumScale(1.5);
173 QCOMPARE(scaleMinSpy.count(),1);
174 QCOMPARE(scaleMaxSpy.count(),1);
176 // minimum and maximum rotation properties
177 QSignalSpy rotMinSpy(pinch, SIGNAL(minimumRotationChanged()));
178 QSignalSpy rotMaxSpy(pinch, SIGNAL(maximumRotationChanged()));
180 QCOMPARE(pinch->minimumRotation(), 0.0);
181 QCOMPARE(pinch->maximumRotation(), 90.0);
183 pinch->setMinimumRotation(-90.0);
184 pinch->setMaximumRotation(45.0);
186 QCOMPARE(pinch->minimumRotation(), -90.0);
187 QCOMPARE(pinch->maximumRotation(), 45.0);
189 QCOMPARE(rotMinSpy.count(),1);
190 QCOMPARE(rotMaxSpy.count(),1);
192 pinch->setMinimumRotation(-90.0);
193 pinch->setMaximumRotation(45.0);
195 QCOMPARE(rotMinSpy.count(),1);
196 QCOMPARE(rotMaxSpy.count(),1);
201 QTouchEvent::TouchPoint makeTouchPoint(int id, QPoint p, QQuickView *v, QQuickItem *i)
203 QTouchEvent::TouchPoint touchPoint(id);
204 touchPoint.setPos(i->mapFromScene(p));
205 touchPoint.setScreenPos(v->mapToGlobal(p));
206 touchPoint.setScenePos(p);
210 void tst_QQuickPinchArea::scale()
212 QQuickView *canvas = createView();
213 canvas->setSource(testFileUrl("pinchproperties.qml"));
215 canvas->requestActivateWindow();
216 QTest::qWaitForWindowShown(canvas);
217 QVERIFY(canvas->rootObject() != 0);
218 qApp->processEvents();
220 QQuickPinchArea *pinchArea = canvas->rootObject()->findChild<QQuickPinchArea*>("pincharea");
221 QQuickPinch *pinch = pinchArea->pinch();
222 QVERIFY(pinchArea != 0);
225 QQuickItem *root = qobject_cast<QQuickItem*>(canvas->rootObject());
229 QQuickItem *blackRect = canvas->rootObject()->findChild<QQuickItem*>("blackrect");
230 QVERIFY(blackRect != 0);
235 QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(canvas, device);
236 pinchSequence.press(0, p1, canvas).commit();
237 // In order for the stationary point to remember its previous position,
238 // we have to reuse the same pinchSequence object. Otherwise if we let it
239 // be destroyed and then start a new sequence, point 0 will default to being
240 // stationary at 0, 0, and PinchArea will filter out that touchpoint because
241 // it is outside its bounds.
242 pinchSequence.stationary(0).press(1, p2, canvas).commit();
245 pinchSequence.move(0, p1,canvas).move(1, p2,canvas).commit();
247 QCOMPARE(root->property("scale").toReal(), 1.0);
248 QVERIFY(root->property("pinchActive").toBool());
252 pinchSequence.move(0, p1,canvas).move(1, p2,canvas).commit();
254 QCOMPARE(root->property("scale").toReal(), 1.5);
255 QCOMPARE(root->property("center").toPointF(), QPointF(40, 40)); // blackrect is at 50,50
256 QCOMPARE(blackRect->scale(), 1.5);
259 // scale beyond bound
263 QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(canvas, device);
264 pinchSequence.move(0, p1, canvas).move(1, p2, canvas).commit();
265 QCOMPARE(blackRect->scale(), 2.0);
266 pinchSequence.release(0, p1, canvas).release(1, p2, canvas).commit();
268 QVERIFY(!root->property("pinchActive").toBool());
273 void tst_QQuickPinchArea::pan()
275 QQuickView *canvas = createView();
276 canvas->setSource(testFileUrl("pinchproperties.qml"));
278 canvas->requestActivateWindow();
279 QTest::qWaitForWindowShown(canvas);
280 QVERIFY(canvas->rootObject() != 0);
281 qApp->processEvents();
283 QQuickPinchArea *pinchArea = canvas->rootObject()->findChild<QQuickPinchArea*>("pincharea");
284 QQuickPinch *pinch = pinchArea->pinch();
285 QVERIFY(pinchArea != 0);
288 QQuickItem *root = qobject_cast<QQuickItem*>(canvas->rootObject());
292 QQuickItem *blackRect = canvas->rootObject()->findChild<QQuickItem*>("blackrect");
293 QVERIFY(blackRect != 0);
298 QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(canvas, device);
299 pinchSequence.press(0, p1, canvas).commit();
300 // In order for the stationary point to remember its previous position,
301 // we have to reuse the same pinchSequence object.
302 pinchSequence.stationary(0).press(1, p2, canvas).commit();
305 pinchSequence.move(0, p1,canvas).move(1, p2,canvas).commit();
307 QCOMPARE(root->property("scale").toReal(), 1.0);
308 QVERIFY(root->property("pinchActive").toBool());
312 pinchSequence.move(0, p1,canvas).move(1, p2,canvas).commit();
315 QCOMPARE(root->property("center").toPointF(), QPointF(60, 60)); // blackrect is at 50,50
316 QCOMPARE(blackRect->x(), 60.0);
317 QCOMPARE(blackRect->y(), 60.0);
319 // pan x beyond bound
320 p1 += QPoint(100,100);
321 p2 += QPoint(100,100);
322 QTest::touchEvent(canvas, device).move(0, p1, canvas).move(1, p2, canvas);
324 QCOMPARE(blackRect->x(), 140.0);
325 QCOMPARE(blackRect->y(), 160.0);
327 QTest::touchEvent(canvas, device).release(0, p1, canvas).release(1, p2, canvas);
328 QVERIFY(!root->property("pinchActive").toBool());
333 // test pinch, release one point, touch again to continue pinch
334 void tst_QQuickPinchArea::retouch()
336 QQuickView *canvas = createView();
337 canvas->setSource(testFileUrl("pinchproperties.qml"));
339 canvas->requestActivateWindow();
340 QTest::qWaitForWindowShown(canvas);
341 QVERIFY(canvas->rootObject() != 0);
342 qApp->processEvents();
344 QQuickPinchArea *pinchArea = canvas->rootObject()->findChild<QQuickPinchArea*>("pincharea");
345 QQuickPinch *pinch = pinchArea->pinch();
346 QVERIFY(pinchArea != 0);
349 QQuickItem *root = qobject_cast<QQuickItem*>(canvas->rootObject());
352 QSignalSpy startedSpy(pinchArea, SIGNAL(pinchStarted(QQuickPinchEvent *)));
353 QSignalSpy finishedSpy(pinchArea, SIGNAL(pinchFinished(QQuickPinchEvent *)));
356 QQuickItem *blackRect = canvas->rootObject()->findChild<QQuickItem*>("blackrect");
357 QVERIFY(blackRect != 0);
362 QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(canvas, device);
363 pinchSequence.press(0, p1, canvas).commit();
364 // In order for the stationary point to remember its previous position,
365 // we have to reuse the same pinchSequence object.
366 pinchSequence.stationary(0).press(1, p2, canvas).commit();
369 pinchSequence.move(0, p1,canvas).move(1, p2,canvas).commit();
371 QCOMPARE(root->property("scale").toReal(), 1.0);
372 QVERIFY(root->property("pinchActive").toBool());
376 pinchSequence.move(0, p1,canvas).move(1, p2,canvas).commit();
378 QCOMPARE(startedSpy.count(), 1);
380 QCOMPARE(root->property("scale").toReal(), 1.5);
381 QCOMPARE(root->property("center").toPointF(), QPointF(40, 40)); // blackrect is at 50,50
382 QCOMPARE(blackRect->scale(), 1.5);
384 QCOMPARE(canvas->rootObject()->property("pointCount").toInt(), 2);
386 QCOMPARE(startedSpy.count(), 1);
387 QCOMPARE(finishedSpy.count(), 0);
389 // Hold down the first finger but release the second one
390 pinchSequence.stationary(0).release(1, p2, canvas).commit();
392 QCOMPARE(startedSpy.count(), 1);
393 QCOMPARE(finishedSpy.count(), 0);
395 QCOMPARE(canvas->rootObject()->property("pointCount").toInt(), 1);
397 // Keep holding down the first finger and re-touch the second one, then move them both
398 pinchSequence.stationary(0).press(1, p2, canvas).commit();
401 pinchSequence.move(0, p1, canvas).move(1, p2, canvas).commit();
403 // Lifting and retouching results in onPinchStarted being called again
404 QCOMPARE(startedSpy.count(), 2);
405 QCOMPARE(finishedSpy.count(), 0);
407 QCOMPARE(canvas->rootObject()->property("pointCount").toInt(), 2);
409 pinchSequence.release(0, p1, canvas).release(1, p2, canvas).commit();
411 QVERIFY(!root->property("pinchActive").toBool());
412 QCOMPARE(startedSpy.count(), 2);
413 QCOMPARE(finishedSpy.count(), 1);
419 void tst_QQuickPinchArea::transformedPinchArea_data()
421 QTest::addColumn<QPoint>("p1");
422 QTest::addColumn<QPoint>("p2");
423 QTest::addColumn<bool>("shouldPinch");
425 QTest::newRow("checking inner pinch 1")
426 << QPoint(200, 140) << QPoint(200, 260) << true;
428 QTest::newRow("checking inner pinch 2")
429 << QPoint(140, 200) << QPoint(200, 140) << true;
431 QTest::newRow("checking inner pinch 3")
432 << QPoint(140, 200) << QPoint(260, 200) << true;
434 QTest::newRow("checking outer pinch 1")
435 << QPoint(140, 140) << QPoint(260, 260) << false;
437 QTest::newRow("checking outer pinch 2")
438 << QPoint(140, 140) << QPoint(200, 200) << false;
440 QTest::newRow("checking outer pinch 3")
441 << QPoint(140, 260) << QPoint(260, 260) << false;
444 void tst_QQuickPinchArea::transformedPinchArea()
448 QFETCH(bool, shouldPinch);
450 QQuickView *canvas = createView();
451 canvas->setSource(testFileUrl("transformedPinchArea.qml"));
453 canvas->requestActivateWindow();
454 QTest::qWaitForWindowShown(canvas);
455 QVERIFY(canvas->rootObject() != 0);
456 qApp->processEvents();
458 QQuickPinchArea *pinchArea = canvas->rootObject()->findChild<QQuickPinchArea*>("pinchArea");
459 QVERIFY(pinchArea != 0);
461 const int threshold = qApp->styleHints()->startDragDistance();
464 QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(canvas, device);
466 pinchSequence.press(0, p1, canvas).commit();
467 // In order for the stationary point to remember its previous position,
468 // we have to reuse the same pinchSequence object.
469 pinchSequence.stationary(0).press(1, p2, canvas).commit();
470 pinchSequence.stationary(0).move(1, p2 + QPoint(threshold * 2, 0), canvas).commit();
471 QCOMPARE(pinchArea->property("pinching").toBool(), shouldPinch);
474 pinchSequence.release(0, p1, canvas).release(1, p2, canvas).commit();
475 QCOMPARE(pinchArea->property("pinching").toBool(), false);
481 QQuickView *tst_QQuickPinchArea::createView()
483 QQuickView *canvas = new QQuickView(0);
484 canvas->setGeometry(0,0,240,320);
489 QTEST_MAIN(tst_QQuickPinchArea)
491 #include "tst_qquickpincharea.moc"