2 * Copyright (C) 2013-2014 Canonical, Ltd.
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.
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.
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/>.
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>
26#include <TouchRegistry.h>
28using namespace UbuntuGestures;
30class FakeTimeSource : public TimeSource
33 FakeTimeSource() { m_msecsSinceReference = 0; }
34 qint64 msecsSinceReference() override {return m_msecsSinceReference;}
35 qint64 m_msecsSinceReference;
38class tst_DragHandle: public QObject
42 tst_DragHandle() : m_device(0) { }
44 void initTestCase(); // will be called before the first test function is executed
45 void cleanupTestCase(); // will be called after the last test function was executed.
47 void init(); // called right before each and every test function is executed
48 void cleanup(); // called right after each and every test function is executed
50 void dragThreshold_horizontal();
51 void dragThreshold_horizontal_data();
52 void dragThreshold_vertical();
53 void dragThreshold_vertical_data();
54 void stretch_horizontal();
55 void stretch_vertical();
56 void hintingAnimation();
57 void hintingAnimation_dontRestartAfterFinishedAndStillPressed();
61 void flickAndHold(DirectionalDragArea *dragHandle, qreal distance);
62 void drag(QPointF &touchPoint, const QPointF& direction, qreal distance,
63 int numSteps, qint64 timeMs = 500);
64 DirectionalDragArea *fetchAndSetupDragHandle(const char *objectName);
65 qreal fetchDragThreshold(DirectionalDragArea *dragHandle);
66 void tryCompare(std::function<qreal ()> actualFunc, qreal expectedValue);
68 QQuickView *createView();
70 TouchRegistry *m_touchRegistry;
71 QTouchDevice *m_device;
72 FakeTimer *m_fakeTimer;
73 QSharedPointer<FakeTimeSource> m_fakeTimeSource;
77void tst_DragHandle::initTestCase()
80 m_device = new QTouchDevice;
81 m_device->setType(QTouchDevice::TouchScreen);
82 QWindowSystemInterface::registerTouchDevice(m_device);
88void tst_DragHandle::cleanupTestCase()
92void tst_DragHandle::init()
94 m_touchRegistry = new TouchRegistry;
96 m_view = createView();
97 m_view->installEventFilter(m_touchRegistry);
98 m_view->setSource(QUrl::fromLocalFile(TEST_DIR"/tst_DragHandle.qml"));
100 QVERIFY(QTest::qWaitForWindowExposed(m_view));
101 QVERIFY(m_view->rootObject() != 0);
102 qApp->processEvents();
104 m_fakeTimer = new FakeTimer;
105 m_fakeTimeSource.reset(new FakeTimeSource);
108void tst_DragHandle::cleanup()
113 delete m_touchRegistry;
119 m_fakeTimeSource.reset();
122QQuickView *tst_DragHandle::createView()
124 QQuickView *window = new QQuickView(0);
125 window->setResizeMode(QQuickView::SizeRootObjectToView);
126 window->engine()->addImportPath(QLatin1String(UBUNTU_GESTURES_PLUGIN_DIR));
127 window->engine()->addImportPath(QLatin1String(TEST_DIR));
132void tst_DragHandle::tryCompare(std::function<qreal ()> actualFunc,
136 while (actualFunc() != expectedValue && waitCount < 100) {
140 QCOMPARE(actualFunc(), expectedValue);
144QPointF calculateDirectionVector(DirectionalDragArea *edgeDragArea)
146 QPointF localOrigin(0., 0.);
147 QPointF localDirection;
148 switch (edgeDragArea->direction()) {
149 case Direction::Upwards:
150 localDirection.rx() = 0.;
151 localDirection.ry() = -1.;
153 case Direction::Downwards:
154 localDirection.rx() = 0.;
155 localDirection.ry() = 1;
157 case Direction::Leftwards:
158 localDirection.rx() = -1.;
159 localDirection.ry() = 0.;
161 default: // Direction::Rightwards:
162 localDirection.rx() = 1.;
163 localDirection.ry() = 0.;
166 QPointF sceneOrigin = edgeDragArea->mapToScene(localOrigin);
167 QPointF sceneDirection = edgeDragArea->mapToScene(localDirection);
168 return sceneDirection - sceneOrigin;
172void tst_DragHandle::flickAndHold(DirectionalDragArea *dragHandle,
175 QPointF initialTouchPos = dragHandle->mapToScene(
176 QPointF(dragHandle->width() / 2.0, dragHandle->height() / 2.0));
177 QPointF touchPoint = initialTouchPos;
179 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
182 QPointF dragDirectionVector = calculateDirectionVector(dragHandle);
183 drag(touchPoint, dragDirectionVector, distance, numSteps);
185 // Wait for quite a bit before finally releasing to make a very low flick/release
187 m_fakeTimeSource->m_msecsSinceReference += 5000;
188 QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
191void tst_DragHandle::drag(QPointF &touchPoint, const QPointF& direction, qreal distance,
192 int numSteps, qint64 timeMs)
194 qint64 timeStep = timeMs / numSteps;
195 QPointF touchMovement = direction * (distance / (qreal)numSteps);
196 for (int i = 0; i < numSteps; ++i) {
197 touchPoint += touchMovement;
198 m_fakeTimeSource->m_msecsSinceReference += timeStep;
199 QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
203DirectionalDragArea *tst_DragHandle::fetchAndSetupDragHandle(const char *objectName)
205 DirectionalDragArea *dragHandle =
206 m_view->rootObject()->findChild<DirectionalDragArea*>(objectName);
207 Q_ASSERT(dragHandle != 0);
208 dragHandle->setRecognitionTimer(m_fakeTimer);
209 dragHandle->setTimeSource(m_fakeTimeSource);
211 AxisVelocityCalculator *edgeDragEvaluator =
212 dragHandle->findChild<AxisVelocityCalculator*>("edgeDragEvaluator");
213 Q_ASSERT(edgeDragEvaluator != 0);
214 edgeDragEvaluator->setTimeSource(m_fakeTimeSource);
219qreal tst_DragHandle::fetchDragThreshold(DirectionalDragArea *dragHandle)
221 AxisVelocityCalculator *edgeDragEvaluator =
222 dragHandle->findChild<AxisVelocityCalculator*>("edgeDragEvaluator");
223 Q_ASSERT(edgeDragEvaluator != 0);
225 return edgeDragEvaluator->property("dragThreshold").toReal();
229 Checks that ending a low-speed drag before dragThreshold results in the
230 Showable getting back to its original position, whereas ending after dragThreshold
231 results in Showable continuing until reaching its new states (shown or hidden)
233void tst_DragHandle::dragThreshold_horizontal()
235 QFETCH(qreal, rotation);
237 QQuickItem *baseItem = m_view->rootObject()->findChild<QQuickItem*>("baseItem");
238 baseItem->setRotation(rotation);
240 DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("rightwardsDragHandle");
242 qreal dragThreshold = fetchDragThreshold(dragHandle);
244 // end before the threshold
245 flickAndHold(dragHandle, dragThreshold * 0.7);
248 QQuickItem *parentItem = dragHandle->parentItem();
249 tryCompare([&](){ return parentItem->x(); }, -parentItem->width());
250 QCOMPARE(parentItem->property("shown").toBool(), false);
252 // end after the threshold
253 flickAndHold(dragHandle, dragThreshold * 1.2);
255 // should keep going until completion
256 tryCompare([&](){ return parentItem->x(); }, 0);
257 QCOMPARE(parentItem->property("shown").toBool(), true);
259 dragHandle = fetchAndSetupDragHandle("leftwardsDragHandle");
261 dragThreshold = fetchDragThreshold(dragHandle);
263 // end before the threshold
264 flickAndHold(dragHandle, dragThreshold * 0.7);
267 tryCompare([&](){ return parentItem->x(); }, 0);
268 QCOMPARE(parentItem->property("shown").toBool(), true);
270 // end after the threshold
271 flickAndHold(dragHandle, dragThreshold * 1.2);
273 // should keep going until completion
274 tryCompare([&](){ return parentItem->x(); }, -parentItem->width());
275 QCOMPARE(parentItem->property("shown").toBool(), false);
278void tst_DragHandle::dragThreshold_horizontal_data()
280 QTest::addColumn<qreal>("rotation");
282 QTest::newRow("not rotated") << 0.;
283 QTest::newRow("rotated 90") << 90.;
286void tst_DragHandle::dragThreshold_vertical()
288 QFETCH(qreal, rotation);
290 QQuickItem *baseItem = m_view->rootObject()->findChild<QQuickItem*>("baseItem");
291 baseItem->setRotation(rotation);
293 DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
295 qreal dragThreshold = fetchDragThreshold(dragHandle);
297 // end before the threshold
298 flickAndHold(dragHandle, dragThreshold * 0.7);
301 QQuickItem *parentItem = dragHandle->parentItem();
302 tryCompare([&](){ return parentItem->y(); }, -parentItem->height());
303 QCOMPARE(parentItem->property("shown").toBool(), false);
305 // end after the threshold
306 flickAndHold(dragHandle, dragThreshold * 1.2);
308 // should keep going until completion
309 tryCompare([&](){ return parentItem->y(); }, 0);
310 QCOMPARE(parentItem->property("shown").toBool(), true);
312 dragHandle = fetchAndSetupDragHandle("upwardsDragHandle");
314 dragThreshold = fetchDragThreshold(dragHandle);
316 // end before the threshold
317 flickAndHold(dragHandle, dragThreshold * 0.7);
320 tryCompare([&](){ return parentItem->y(); }, 0);
321 QCOMPARE(parentItem->property("shown").toBool(), true);
323 // end after the threshold
324 flickAndHold(dragHandle, dragThreshold * 1.2);
326 // should keep going until completion
327 tryCompare([&](){ return parentItem->y(); }, -parentItem->height());
328 QCOMPARE(parentItem->property("shown").toBool(), false);
331void tst_DragHandle::dragThreshold_vertical_data()
333 QTest::addColumn<qreal>("rotation");
335 QTest::newRow("not rotated") << 0.;
336 QTest::newRow("rotated 90") << 90.;
340 Checks that when the stretch property is true, dragging the DragHandle increases
341 the width or height (depending on its direction) of its parent Showable
343void tst_DragHandle::stretch_horizontal()
345 DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("rightwardsDragHandle");
346 qreal totalDragDistance = dragHandle->property("maxTotalDragDistance").toReal();
347 QQuickItem *parentItem = dragHandle->parentItem();
349 // enable strech mode
350 m_view->rootObject()->setProperty("stretch", QVariant(true));
352 QCOMPARE(parentItem->width(), 0.0);
355 flickAndHold(dragHandle, totalDragDistance);
357 // should keep going until completion
358 // Parent item should now have its full height
359 tryCompare([&](){ return parentItem->width(); }, totalDragDistance);
360 QCOMPARE(parentItem->property("shown").toBool(), true);
362 dragHandle = fetchAndSetupDragHandle("leftwardsDragHandle");
365 flickAndHold(dragHandle, totalDragDistance);
367 // should keep going until completion
368 // Parent item should now have its full height
369 tryCompare([&](){ return parentItem->width(); }, 0.0);
370 QCOMPARE(parentItem->property("shown").toBool(), false);
373void tst_DragHandle::stretch_vertical()
375 DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
376 qreal totalDragDistance = dragHandle->property("maxTotalDragDistance").toReal();
377 QQuickItem *parentItem = dragHandle->parentItem();
379 // enable strech mode
380 m_view->rootObject()->setProperty("stretch", QVariant(true));
382 QCOMPARE(parentItem->height(), 0.0);
385 flickAndHold(dragHandle, totalDragDistance);
387 // should keep going until completion
388 // Parent item should now have its full height
389 tryCompare([&](){ return parentItem->height(); }, totalDragDistance);
390 QCOMPARE(parentItem->property("shown").toBool(), true);
392 dragHandle = fetchAndSetupDragHandle("upwardsDragHandle");
395 flickAndHold(dragHandle, totalDragDistance);
397 // should keep going until completion
398 // Parent item should now have its full height
399 tryCompare([&](){ return parentItem->height(); }, 0.0);
400 QCOMPARE(parentItem->property("shown").toBool(), false);
404 Set DragHandle.hintDisplacement to a value bigger than zero.
405 Then lay a finger on the DragHandle.
406 The expected behavior is that it will move or strech its parent Showable
407 by hintDisplacement pixels.
409void tst_DragHandle::hintingAnimation()
411 DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
412 QQuickItem *parentItem = dragHandle->parentItem();
413 qreal hintDisplacement = 100.0;
415 // enable hinting animations and stretch mode
416 m_view->rootObject()->setProperty("hintDisplacement", QVariant(hintDisplacement));
417 m_view->rootObject()->setProperty("stretch", QVariant(true));
419 QCOMPARE(parentItem->height(), 0.0);
421 QPointF initialTouchPos = dragHandle->mapToScene(
422 QPointF(dragHandle->width() / 2.0, dragHandle->height() / 2.0));
423 QPointF touchPoint = initialTouchPos;
425 // Pressing causes the Showable to be stretched by hintDisplacement pixels
426 QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
427 tryCompare([&](){ return parentItem->height(); }, hintDisplacement);
429 // Releasing causes the Showable to shrink back to 0 pixels.
430 QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
431 tryCompare([&](){ return parentItem->height(); }, 0.0);
433 QCOMPARE(parentItem->property("shown").toBool(), false);
437 Regression test for LP#1269022: https://bugs.launchpad.net/unity8/+bug/1269022
440 2) wait for hint portion to appear
441 3) slowly drag handle, only a few pixels
447 Handle will momentarily move back to zero position, then back down to the
448 hint displacement location.
450void tst_DragHandle::hintingAnimation_dontRestartAfterFinishedAndStillPressed()
452 DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
453 QQuickItem *parentItem = dragHandle->parentItem();
454 qreal hintDisplacement = 100.0;
456 // enable hinting animations
457 m_view->rootObject()->setProperty("hintDisplacement", QVariant(hintDisplacement));
458 m_view->rootObject()->setProperty("stretch", QVariant(true));
460 QCOMPARE(parentItem->height(), 0.0);
462 QPointF initialTouchPos = dragHandle->mapToScene(
463 QPointF(dragHandle->width() / 2.0, dragHandle->height() / 2.0));
464 QPointF touchPoint = initialTouchPos;
466 // Pressing causes the Showable to be stretched by hintDisplacement pixels
467 const int touchId = 0;
468 QTest::touchEvent(m_view, m_device).press(touchId, touchPoint.toPoint());
469 tryCompare([&](){ return parentItem->height(); }, hintDisplacement);
472 QSignalSpy parentHeightChangedSpy(parentItem, SIGNAL(heightChanged()));
474 drag(touchPoint, QPointF(0.0, -1.0) /*dragDirectionVector*/, 15 /*distance*/, 3 /*numSteps*/);
476 // Give some time for animations to run, if any
479 // parentItem height shouldn't have changed at all
480 QVERIFY(parentHeightChangedSpy.isEmpty());
483QTEST_MAIN(tst_DragHandle)
485#include "tst_DragHandle.moc"
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list