on 3e4155e help sign in
unity8/tests/qmltests/Components/tst_DragHandle.cpp
295 lines 9.2 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();
63private:
64 void flickAndHold(DirectionalDragArea *dragHandle, qreal distance);
65 DirectionalDragArea *fetchAndSetupDragHandle(const char *objectName);
66 qreal fetchDragThreshold(DirectionalDragArea *dragHandle);
67 void tryCompare(std::function<qreal ()> actualFunc, qreal expectedValue);
69 QQuickView *createView();
70 QQuickView *m_view;
71 QTouchDevice *m_device;
72 FakeTimer *m_fakeTimer;
73 FakeTimeSource *m_fakeTimeSource;
74};
77void tst_DragHandle::initTestCase()
79 if (!m_device) {
80 m_device = new QTouchDevice;
81 m_device->setType(QTouchDevice::TouchScreen);
82 QWindowSystemInterface::registerTouchDevice(m_device);
83 }
85 m_view = 0;
88void tst_DragHandle::cleanupTestCase()
92void tst_DragHandle::init()
94 m_view = createView();
95 m_view->setSource(QUrl::fromLocalFile(TEST_DIR"/tst_DragHandle.qml"));
96 m_view->show();
97 QVERIFY(QTest::qWaitForWindowExposed(m_view));
98 QVERIFY(m_view->rootObject() != 0);
99 qApp->processEvents();
101 m_fakeTimer = new FakeTimer;
102 m_fakeTimeSource = new FakeTimeSource;
105void tst_DragHandle::cleanup()
107 delete m_view;
108 m_view = 0;
110 delete m_fakeTimer;
111 m_fakeTimer = 0;
113 delete m_fakeTimeSource;
114 m_fakeTimeSource = 0;
117QQuickView *tst_DragHandle::createView()
119 QQuickView *window = new QQuickView(0);
120 window->setResizeMode(QQuickView::SizeRootObjectToView);
121 window->resize(600, 600);
122 window->engine()->addImportPath(QLatin1String(UBUNTU_GESTURES_PLUGIN_DIR));
123 window->engine()->addImportPath(QLatin1String(TEST_DIR));
125 return window;
128void tst_DragHandle::tryCompare(std::function<qreal ()> actualFunc,
129 qreal expectedValue)
131 int waitCount = 0;
132 while (actualFunc() != expectedValue && waitCount < 100) {
133 QTest::qWait(50);
134 ++waitCount;
135 }
136 QCOMPARE(actualFunc(), expectedValue);
139namespace {
140QPointF calculateDirectionVector(DirectionalDragArea *edgeDragArea)
143 switch (edgeDragArea->direction()) {
144 case Direction::Upwards:
145 return QPointF(0, -1);
146 case Direction::Downwards:
147 return QPointF(0, 1);
148 case Direction::Leftwards:
149 return QPointF(-1, 0);
150 default: // Direction::Rightwards:
151 return QPointF(1, 0);
152 }
156void tst_DragHandle::flickAndHold(DirectionalDragArea *dragHandle,
157 qreal distance)
159 QPointF initialTouchPos = dragHandle->mapToScene(
160 QPointF(dragHandle->width() / 2.0, dragHandle->height() / 2.0));
161 QPointF touchPoint = initialTouchPos;
162 int numSteps = 10;
163 qint64 flickTimeMs = 500;
164 qint64 timeStep = flickTimeMs / numSteps;
166 QPointF dragDirectionVector = calculateDirectionVector(dragHandle);
167 QPointF touchMovement = dragDirectionVector * (distance / (qreal)numSteps);
169 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
171 for (int i = 0; i < numSteps; ++i) {
172 touchPoint += touchMovement;
173 m_fakeTimeSource->m_msecsSinceReference += timeStep;
174 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
175 }
177 // Wait for quite a bit before finally releasing to make a very low flick/release
178 // speed.
179 m_fakeTimeSource->m_msecsSinceReference += 5000;
180 QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
183DirectionalDragArea *tst_DragHandle::fetchAndSetupDragHandle(const char *objectName)
185 DirectionalDragArea *dragHandle =
186 m_view->rootObject()->findChild<DirectionalDragArea*>(objectName);
187 Q_ASSERT(dragHandle != 0);
188 dragHandle->setRecognitionTimer(m_fakeTimer);
189 dragHandle->setTimeSource(m_fakeTimeSource);
191 AxisVelocityCalculator *edgeDragEvaluator =
192 dragHandle->findChild<AxisVelocityCalculator*>("edgeDragEvaluator");
193 Q_ASSERT(edgeDragEvaluator != 0);
194 edgeDragEvaluator->setTimeSource(m_fakeTimeSource);
196 return dragHandle;
199qreal tst_DragHandle::fetchDragThreshold(DirectionalDragArea *dragHandle)
201 AxisVelocityCalculator *edgeDragEvaluator =
202 dragHandle->findChild<AxisVelocityCalculator*>("edgeDragEvaluator");
203 Q_ASSERT(edgeDragEvaluator != 0);
205 return edgeDragEvaluator->property("dragThreshold").toReal();
208/*
209 Checks that ending a low-speed drag before dragThreshold results in the
210 Showable getting back to its original position, whereas ending after dragThreshold
211 results in Showable continuing until reaching its new states (shown or hidden)
212 */
213void tst_DragHandle::dragThreshold_horizontal()
215 DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("rightwardsDragHandle");
217 qreal dragThreshold = fetchDragThreshold(dragHandle);
219 // end before the threshold
220 flickAndHold(dragHandle, dragThreshold * 0.7);
222 // should rollback
223 QQuickItem *parentItem = dragHandle->parentItem();
224 tryCompare([&](){ return parentItem->x(); }, -parentItem->width());
225 QCOMPARE(parentItem->property("shown").toBool(), false);
227 // end after the threshold
228 flickAndHold(dragHandle, dragThreshold * 1.2);
230 // should keep going until completion
231 tryCompare([&](){ return parentItem->x(); }, 0);
232 QCOMPARE(parentItem->property("shown").toBool(), true);
234 dragHandle = fetchAndSetupDragHandle("leftwardsDragHandle");
236 dragThreshold = fetchDragThreshold(dragHandle);
238 // end before the threshold
239 flickAndHold(dragHandle, dragThreshold * 0.7);
241 // should rollback
242 tryCompare([&](){ return parentItem->x(); }, 0);
243 QCOMPARE(parentItem->property("shown").toBool(), true);
245 // end after the threshold
246 flickAndHold(dragHandle, dragThreshold * 1.2);
248 // should keep going until completion
249 tryCompare([&](){ return parentItem->x(); }, -parentItem->width());
250 QCOMPARE(parentItem->property("shown").toBool(), false);
253void tst_DragHandle::dragThreshold_vertical()
255 DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
257 qreal dragThreshold = fetchDragThreshold(dragHandle);
259 // end before the threshold
260 flickAndHold(dragHandle, dragThreshold * 0.7);
262 // should rollback
263 QQuickItem *parentItem = dragHandle->parentItem();
264 tryCompare([&](){ return parentItem->y(); }, -parentItem->height());
265 QCOMPARE(parentItem->property("shown").toBool(), false);
267 // end after the threshold
268 flickAndHold(dragHandle, dragThreshold * 1.2);
270 // should keep going until completion
271 tryCompare([&](){ return parentItem->y(); }, 0);
272 QCOMPARE(parentItem->property("shown").toBool(), true);
274 dragHandle = fetchAndSetupDragHandle("upwardsDragHandle");
276 dragThreshold = fetchDragThreshold(dragHandle);
278 // end before the threshold
279 flickAndHold(dragHandle, dragThreshold * 0.7);
281 // should rollback
282 tryCompare([&](){ return parentItem->y(); }, 0);
283 QCOMPARE(parentItem->property("shown").toBool(), true);
285 // end after the threshold
286 flickAndHold(dragHandle, dragThreshold * 1.2);
288 // should keep going until completion
289 tryCompare([&](){ return parentItem->y(); }, -parentItem->height());
290 QCOMPARE(parentItem->property("shown").toBool(), false);
293QTEST_MAIN(tst_DragHandle)
295#include "tst_DragHandle.moc"