on bb5feb3 help sign in
unity8/tests/qmltests/Components/tst_DragHandle.cpp
395 lines 13 kB history raw
1/*
2 * Copyright (C) 2013 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
17#include <functional>
18#include <QtTest/QtTest>
19#include <QtCore/QObject>
20#include <qpa/qwindowsysteminterface.h>
21#include <QtQuick/QQuickView>
22#include <QtQml/QQmlEngine>
24#include <DirectionalDragArea.h>
26class FakeTimer : public UbuntuGestures::AbstractTimer
28 Q_OBJECT
29public:
30 FakeTimer(QObject *parent = 0)
31 : UbuntuGestures::AbstractTimer(parent)
32 {}
34 virtual int interval() const { return m_duration; }
35 virtual void setInterval(int msecs) { m_duration = msecs; }
36private:
37 int m_duration;
38};
40class FakeTimeSource : public UbuntuGestures::TimeSource
42public:
43 FakeTimeSource() { m_msecsSinceReference = 0; }
44 virtual qint64 msecsSinceReference() {return m_msecsSinceReference;}
45 qint64 m_msecsSinceReference;
46};
48class tst_DragHandle: public QObject
50 Q_OBJECT
51public:
52 tst_DragHandle() : m_device(0) { }
53private Q_SLOTS:
54 void initTestCase(); // will be called before the first test function is executed
55 void cleanupTestCase(); // will be called after the last test function was executed.
57 void init(); // called right before each and every test function is executed
58 void cleanup(); // called right after each and every test function is executed
60 void dragThreshold_horizontal();
61 void dragThreshold_vertical();
62 void stretch_horizontal();
63 void stretch_vertical();
64 void hintingAnimation();
66private:
67 void flickAndHold(DirectionalDragArea *dragHandle, qreal distance);
68 DirectionalDragArea *fetchAndSetupDragHandle(const char *objectName);
69 qreal fetchDragThreshold(DirectionalDragArea *dragHandle);
70 void tryCompare(std::function<qreal ()> actualFunc, qreal expectedValue);
72 QQuickView *createView();
73 QQuickView *m_view;
74 QTouchDevice *m_device;
75 FakeTimer *m_fakeTimer;
76 FakeTimeSource *m_fakeTimeSource;
77};
80void tst_DragHandle::initTestCase()
82 if (!m_device) {
83 m_device = new QTouchDevice;
84 m_device->setType(QTouchDevice::TouchScreen);
85 QWindowSystemInterface::registerTouchDevice(m_device);
86 }
88 m_view = 0;
91void tst_DragHandle::cleanupTestCase()
95void tst_DragHandle::init()
97 m_view = createView();
98 m_view->setSource(QUrl::fromLocalFile(TEST_DIR"/tst_DragHandle.qml"));
99 m_view->show();
100 QVERIFY(QTest::qWaitForWindowExposed(m_view));
101 QVERIFY(m_view->rootObject() != 0);
102 qApp->processEvents();
104 m_fakeTimer = new FakeTimer;
105 m_fakeTimeSource = new FakeTimeSource;
108void tst_DragHandle::cleanup()
110 delete m_view;
111 m_view = 0;
113 delete m_fakeTimer;
114 m_fakeTimer = 0;
116 delete m_fakeTimeSource;
117 m_fakeTimeSource = 0;
120QQuickView *tst_DragHandle::createView()
122 QQuickView *window = new QQuickView(0);
123 window->setResizeMode(QQuickView::SizeRootObjectToView);
124 window->resize(600, 600);
125 window->engine()->addImportPath(QLatin1String(UBUNTU_GESTURES_PLUGIN_DIR));
126 window->engine()->addImportPath(QLatin1String(TEST_DIR));
128 return window;
131void tst_DragHandle::tryCompare(std::function<qreal ()> actualFunc,
132 qreal expectedValue)
134 int waitCount = 0;
135 while (actualFunc() != expectedValue && waitCount < 100) {
136 QTest::qWait(50);
137 ++waitCount;
138 }
139 QCOMPARE(actualFunc(), expectedValue);
142namespace {
143QPointF calculateDirectionVector(DirectionalDragArea *edgeDragArea)
146 switch (edgeDragArea->direction()) {
147 case Direction::Upwards:
148 return QPointF(0, -1);
149 case Direction::Downwards:
150 return QPointF(0, 1);
151 case Direction::Leftwards:
152 return QPointF(-1, 0);
153 default: // Direction::Rightwards:
154 return QPointF(1, 0);
155 }
159void tst_DragHandle::flickAndHold(DirectionalDragArea *dragHandle,
160 qreal distance)
162 QPointF initialTouchPos = dragHandle->mapToScene(
163 QPointF(dragHandle->width() / 2.0, dragHandle->height() / 2.0));
164 QPointF touchPoint = initialTouchPos;
165 int numSteps = 10;
166 qint64 flickTimeMs = 500;
167 qint64 timeStep = flickTimeMs / numSteps;
169 QPointF dragDirectionVector = calculateDirectionVector(dragHandle);
170 QPointF touchMovement = dragDirectionVector * (distance / (qreal)numSteps);
172 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
174 for (int i = 0; i < numSteps; ++i) {
175 touchPoint += touchMovement;
176 m_fakeTimeSource->m_msecsSinceReference += timeStep;
177 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
178 }
180 // Wait for quite a bit before finally releasing to make a very low flick/release
181 // speed.
182 m_fakeTimeSource->m_msecsSinceReference += 5000;
183 QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
186DirectionalDragArea *tst_DragHandle::fetchAndSetupDragHandle(const char *objectName)
188 DirectionalDragArea *dragHandle =
189 m_view->rootObject()->findChild<DirectionalDragArea*>(objectName);
190 Q_ASSERT(dragHandle != 0);
191 dragHandle->setRecognitionTimer(m_fakeTimer);
192 dragHandle->setTimeSource(m_fakeTimeSource);
194 AxisVelocityCalculator *edgeDragEvaluator =
195 dragHandle->findChild<AxisVelocityCalculator*>("edgeDragEvaluator");
196 Q_ASSERT(edgeDragEvaluator != 0);
197 edgeDragEvaluator->setTimeSource(m_fakeTimeSource);
199 return dragHandle;
202qreal tst_DragHandle::fetchDragThreshold(DirectionalDragArea *dragHandle)
204 AxisVelocityCalculator *edgeDragEvaluator =
205 dragHandle->findChild<AxisVelocityCalculator*>("edgeDragEvaluator");
206 Q_ASSERT(edgeDragEvaluator != 0);
208 return edgeDragEvaluator->property("dragThreshold").toReal();
211/*
212 Checks that ending a low-speed drag before dragThreshold results in the
213 Showable getting back to its original position, whereas ending after dragThreshold
214 results in Showable continuing until reaching its new states (shown or hidden)
215 */
216void tst_DragHandle::dragThreshold_horizontal()
218 DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("rightwardsDragHandle");
220 qreal dragThreshold = fetchDragThreshold(dragHandle);
222 // end before the threshold
223 flickAndHold(dragHandle, dragThreshold * 0.7);
225 // should rollback
226 QQuickItem *parentItem = dragHandle->parentItem();
227 tryCompare([&](){ return parentItem->x(); }, -parentItem->width());
228 QCOMPARE(parentItem->property("shown").toBool(), false);
230 // end after the threshold
231 flickAndHold(dragHandle, dragThreshold * 1.2);
233 // should keep going until completion
234 tryCompare([&](){ return parentItem->x(); }, 0);
235 QCOMPARE(parentItem->property("shown").toBool(), true);
237 dragHandle = fetchAndSetupDragHandle("leftwardsDragHandle");
239 dragThreshold = fetchDragThreshold(dragHandle);
241 // end before the threshold
242 flickAndHold(dragHandle, dragThreshold * 0.7);
244 // should rollback
245 tryCompare([&](){ return parentItem->x(); }, 0);
246 QCOMPARE(parentItem->property("shown").toBool(), true);
248 // end after the threshold
249 flickAndHold(dragHandle, dragThreshold * 1.2);
251 // should keep going until completion
252 tryCompare([&](){ return parentItem->x(); }, -parentItem->width());
253 QCOMPARE(parentItem->property("shown").toBool(), false);
256void tst_DragHandle::dragThreshold_vertical()
258 DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
260 qreal dragThreshold = fetchDragThreshold(dragHandle);
262 // end before the threshold
263 flickAndHold(dragHandle, dragThreshold * 0.7);
265 // should rollback
266 QQuickItem *parentItem = dragHandle->parentItem();
267 tryCompare([&](){ return parentItem->y(); }, -parentItem->height());
268 QCOMPARE(parentItem->property("shown").toBool(), false);
270 // end after the threshold
271 flickAndHold(dragHandle, dragThreshold * 1.2);
273 // should keep going until completion
274 tryCompare([&](){ return parentItem->y(); }, 0);
275 QCOMPARE(parentItem->property("shown").toBool(), true);
277 dragHandle = fetchAndSetupDragHandle("upwardsDragHandle");
279 dragThreshold = fetchDragThreshold(dragHandle);
281 // end before the threshold
282 flickAndHold(dragHandle, dragThreshold * 0.7);
284 // should rollback
285 tryCompare([&](){ return parentItem->y(); }, 0);
286 QCOMPARE(parentItem->property("shown").toBool(), true);
288 // end after the threshold
289 flickAndHold(dragHandle, dragThreshold * 1.2);
291 // should keep going until completion
292 tryCompare([&](){ return parentItem->y(); }, -parentItem->height());
293 QCOMPARE(parentItem->property("shown").toBool(), false);
296/*
297 Checks that when the stretch property is true, dragging the DragHandle increases
298 the width or height (depending on its direction) of its parent Showable
299 */
300void tst_DragHandle::stretch_horizontal()
302 DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("rightwardsDragHandle");
303 qreal totalDragDistance = dragHandle->property("maxTotalDragDistance").toReal();
304 QQuickItem *parentItem = dragHandle->parentItem();
306 // enable strech mode
307 m_view->rootObject()->setProperty("stretch", QVariant(true));
309 QCOMPARE(parentItem->width(), 0.0);
311 // flick all the way
312 flickAndHold(dragHandle, totalDragDistance);
314 // should keep going until completion
315 // Parent item should now have its full height
316 tryCompare([&](){ return parentItem->width(); }, totalDragDistance);
317 QCOMPARE(parentItem->property("shown").toBool(), true);
319 dragHandle = fetchAndSetupDragHandle("leftwardsDragHandle");
321 // flick all the way
322 flickAndHold(dragHandle, totalDragDistance);
324 // should keep going until completion
325 // Parent item should now have its full height
326 tryCompare([&](){ return parentItem->width(); }, 0.0);
327 QCOMPARE(parentItem->property("shown").toBool(), false);
330void tst_DragHandle::stretch_vertical()
332 DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
333 qreal totalDragDistance = dragHandle->property("maxTotalDragDistance").toReal();
334 QQuickItem *parentItem = dragHandle->parentItem();
336 // enable strech mode
337 m_view->rootObject()->setProperty("stretch", QVariant(true));
339 QCOMPARE(parentItem->height(), 0.0);
341 // flick all the way
342 flickAndHold(dragHandle, totalDragDistance);
344 // should keep going until completion
345 // Parent item should now have its full height
346 tryCompare([&](){ return parentItem->height(); }, totalDragDistance);
347 QCOMPARE(parentItem->property("shown").toBool(), true);
349 dragHandle = fetchAndSetupDragHandle("upwardsDragHandle");
351 // flick all the way
352 flickAndHold(dragHandle, totalDragDistance);
354 // should keep going until completion
355 // Parent item should now have its full height
356 tryCompare([&](){ return parentItem->height(); }, 0.0);
357 QCOMPARE(parentItem->property("shown").toBool(), false);
360/*
361 Set DragHandle.hintDisplacement to a value bigger than zero.
362 Then lay a finger on the DragHandle.
363 The expected behavior is that it will move or strech its parent Showable
364 by hintDisplacement pixels.
365 */
366void tst_DragHandle::hintingAnimation()
368 DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
369 QQuickItem *parentItem = dragHandle->parentItem();
370 qreal hintDisplacement = 100.0;
372 // enable hinting animations and stretch mode
373 m_view->rootObject()->setProperty("hintDisplacement", QVariant(hintDisplacement));
374 m_view->rootObject()->setProperty("stretch", QVariant(true));
376 QCOMPARE(parentItem->height(), 0.0);
378 QPointF initialTouchPos = dragHandle->mapToScene(
379 QPointF(dragHandle->width() / 2.0, dragHandle->height() / 2.0));
380 QPointF touchPoint = initialTouchPos;
382 // Pressing causes the Showable to be stretched by hintDisplacement pixels
383 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
384 tryCompare([&](){ return parentItem->height(); }, hintDisplacement);
386 // Releasing causes the Showable to shrink back to 0 pixels.
387 QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
388 tryCompare([&](){ return parentItem->height(); }, 0.0);
390 QCOMPARE(parentItem->property("shown").toBool(), false);
393QTEST_MAIN(tst_DragHandle)
395#include "tst_DragHandle.moc"