1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include "qdeclarativepinchgenerator_p.h"
30
31#include <QtTest/QtTest>
32#include <QtGui/QGuiApplication>
33#include <QtGui/qpa/qwindowsysteminterface.h>
34#include <QtGui/QStyleHints>
35
36QT_BEGIN_NAMESPACE
37
38QDeclarativePinchGenerator::QDeclarativePinchGenerator():
39 target_(0),
40 state_(Invalid),
41 window_(0),
42 activeSwipe_(0),
43 replayTimer_(-1),
44 replayBookmark_(-1),
45 masterSwipe_(-1),
46 replaySpeedFactor_(1.0),
47 enabled_(true)
48{
49 setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton | Qt::RightButton);
50 swipeTimer_.invalidate();
51 device_ = new QTouchDevice;
52 device_->setType(QTouchDevice::TouchScreen);
53 QWindowSystemInterface::registerTouchDevice(device: device_);
54}
55
56QDeclarativePinchGenerator::~QDeclarativePinchGenerator()
57{
58 clear();
59}
60
61void QDeclarativePinchGenerator::componentComplete()
62{
63 QQuickItem::componentComplete();
64}
65
66void QDeclarativePinchGenerator::mousePressEvent(QMouseEvent *event)
67{
68 if (state_ != Idle || !enabled_) {
69 event->ignore();
70 return;
71 }
72 Q_ASSERT(!activeSwipe_);
73 Q_ASSERT(!swipeTimer_.isValid());
74 // Start recording a pinch gesture.
75 activeSwipe_ = new Swipe;
76 activeSwipe_->touchPoints << event->pos();
77 activeSwipe_->durations << 0;
78 swipeTimer_.start();
79 setState(Recording);
80}
81
82void QDeclarativePinchGenerator::mouseMoveEvent(QMouseEvent *event)
83{
84 if (state_ != Recording || !enabled_) {
85 event->ignore();
86 return;
87 }
88 Q_ASSERT(activeSwipe_);
89 Q_ASSERT(swipeTimer_.isValid());
90
91 activeSwipe_->touchPoints << event->pos();
92 activeSwipe_->durations << swipeTimer_.elapsed();
93 swipeTimer_.restart();
94}
95
96void QDeclarativePinchGenerator::mouseReleaseEvent(QMouseEvent *event)
97{
98 if (state_ != Recording || !enabled_) {
99 event->ignore();
100 return;
101 }
102 Q_ASSERT(activeSwipe_);
103 Q_ASSERT(swipeTimer_.isValid());
104 activeSwipe_->touchPoints << event->pos();
105 activeSwipe_->durations << swipeTimer_.elapsed();
106
107 if (swipes_.count() == SWIPES_REQUIRED)
108 delete swipes_.takeFirst();
109 swipes_ << activeSwipe_;
110 activeSwipe_ = 0;
111 swipeTimer_.invalidate();
112 if (window_ && target_) setState(Idle); else setState(Invalid);
113}
114
115void QDeclarativePinchGenerator::mouseDoubleClickEvent(QMouseEvent *event)
116{
117 Q_UNUSED(event);
118 if (!enabled_) {
119 event->ignore();
120 return;
121 }
122 stop();
123 clear();
124 if (window_ && target_) setState(Idle); else setState(Invalid);
125}
126
127void QDeclarativePinchGenerator::keyPressEvent(QKeyEvent *e)
128{
129 if (!enabled_) {
130 e->ignore();
131 }
132
133 if (e->key() == Qt::Key_C) {
134 clear();
135 } else if (e->key() == Qt::Key_R) {
136 replay();
137 } else if (e->key() == Qt::Key_S) {
138 stop();
139 } else if (e->key() == Qt::Key_Plus) {
140 setReplaySpeedFactor(replaySpeedFactor() + 0.1);
141 } else if (e->key() == Qt::Key_Minus) {
142 setReplaySpeedFactor(replaySpeedFactor() - 0.1);
143 } else {
144 qDebug() << metaObject()->className() << "Unsupported key event.";
145 }
146}
147
148bool QDeclarativePinchGenerator::enabled() const
149{
150 return enabled_;
151}
152
153
154void QDeclarativePinchGenerator::setEnabled(bool enabled)
155{
156 if (enabled == enabled_)
157 return;
158 enabled_ = enabled;
159 if (!enabled_) {
160 stop();
161 clear();
162 }
163 emit enabledChanged();
164}
165
166
167qreal QDeclarativePinchGenerator::replaySpeedFactor() const
168{
169 return replaySpeedFactor_;
170}
171
172void QDeclarativePinchGenerator::setReplaySpeedFactor(qreal factor)
173{
174 if (factor == replaySpeedFactor_ || factor < 0.001)
175 return;
176 replaySpeedFactor_ = factor;
177 emit replaySpeedFactorChanged();
178}
179
180
181QString QDeclarativePinchGenerator::state() const
182{
183 switch (state_) {
184 case Invalid:
185 return "Invalid";
186 case Idle:
187 return "Idle";
188 break;
189 case Recording:
190 return "Recording";
191 break;
192 case Replaying:
193 return "Replaying";
194 break;
195 default:
196 Q_ASSERT(false);
197 }
198 return "How emberassing";
199}
200
201void QDeclarativePinchGenerator::setState(GeneratorState state)
202{
203 if (state == state_)
204 return;
205 state_ = state;
206 emit stateChanged();
207}
208
209void QDeclarativePinchGenerator::itemChange(ItemChange change, const ItemChangeData & data)
210{
211 if (change == ItemSceneChange) {
212 window_ = data.window;
213 if (target_)
214 setState(Idle);
215 }
216}
217
218void QDeclarativePinchGenerator::timerEvent(QTimerEvent *event)
219{
220 Q_ASSERT(replayTimer_ == event->timerId());
221 Q_UNUSED(event);
222 Q_ASSERT(state_ == Replaying);
223
224 int slaveSwipe = masterSwipe_ ^ 1;
225
226 int masterCount = swipes_.at(i: masterSwipe_)->touchPoints.count();
227 int slaveCount = swipes_.at(i: slaveSwipe)->touchPoints.count();
228
229 if (replayBookmark_ == 0) {
230 QTest::touchEvent(window: window_, device: device_)
231 .press(touchId: 0, pt: swipes_.at(i: masterSwipe_)->touchPoints.at(i: replayBookmark_))
232 .press(touchId: 1, pt: swipes_.at(i: slaveSwipe)->touchPoints.at(i: replayBookmark_));
233 } else if (replayBookmark_ == (slaveCount - 1)) {
234 if (masterCount != slaveCount) {
235 QTest::touchEvent(window: window_, device: device_)
236 .move(touchId: 0, pt: swipes_.at(i: masterSwipe_)->touchPoints.at(i: replayBookmark_))
237 .release(touchId: 1, pt: swipes_.at(i: slaveSwipe)->touchPoints.at(i: replayBookmark_));
238 } else {
239 QTest::touchEvent(window: window_, device: device_)
240 .release(touchId: 0, pt: swipes_.at(i: masterSwipe_)->touchPoints.at(i: replayBookmark_))
241 .release(touchId: 1, pt: swipes_.at(i: slaveSwipe)->touchPoints.at(i: replayBookmark_));
242 }
243 } else if (replayBookmark_ == (masterCount - 1)) {
244 QTest::touchEvent(window: window_, device: device_)
245 .release(touchId: 0, pt: swipes_.at(i: masterSwipe_)->touchPoints.at(i: replayBookmark_));
246 }
247 else {
248 QTest::touchEvent(window: window_, device: device_)
249 .move(touchId: 0, pt: swipes_.at(i: masterSwipe_)->touchPoints.at(i: replayBookmark_))
250 .move(touchId: 1, pt: swipes_.at(i: slaveSwipe)->touchPoints.at(i: replayBookmark_));
251 }
252
253 replayBookmark_++;
254 if (replayBookmark_ >= swipes_.at(i: masterSwipe_)->touchPoints.count())
255 stop();
256 else {
257 killTimer(id: replayTimer_);
258 replayTimer_ = startTimer(interval: (swipes_.at(i: masterSwipe_)->durations.at(i: replayBookmark_) + 5) / replaySpeedFactor_ );
259 }
260}
261
262QQuickItem* QDeclarativePinchGenerator::target() const
263{
264 return target_;
265}
266
267void QDeclarativePinchGenerator::setTarget(QQuickItem* target)
268{
269 if (target == target_)
270 return;
271 target_ = target;
272 stop();
273 clear();
274 if (window_)
275 setState(Idle);
276 else
277 setState(Invalid);
278 emit targetChanged();
279}
280
281void QDeclarativePinchGenerator::pinch(QPoint point1From,
282 QPoint point1To,
283 QPoint point2From,
284 QPoint point2To,
285 int interval1,
286 int interval2,
287 int samples1,
288 int samples2)
289{
290 Q_ASSERT(interval1 > 10);
291 Q_ASSERT(interval2 > 10);
292 Q_ASSERT(samples1 >= 2); // we need press and release events at minimum
293 Q_ASSERT(samples2 >= 2);
294
295 clear();
296
297 Swipe* swipe1 = new Swipe;
298 Swipe* swipe2 = new Swipe;
299 for (int i = 0; i < samples1; ++i) {
300 swipe1->touchPoints << point1From + (point1To - point1From) / samples1 * i;
301 swipe1->durations << interval1;
302 }
303 for (int i = 0; i < samples2; ++i) {
304 swipe2->touchPoints << point2From + (point2To - point2From) / samples2 * i;
305 swipe2->durations << interval2;
306 }
307 swipes_ << swipe1 << swipe2;
308 Q_ASSERT(swipes_.at(0));
309 Q_ASSERT(swipes_.at(1));
310
311 masterSwipe_ = (samples1 >= samples2) ? 0 : 1;
312
313 replayTimer_ = startTimer(interval: swipes_.at(i: masterSwipe_)->durations.at(i: 0) / replaySpeedFactor_);
314 replayBookmark_ = 0;
315 setState(Replaying);
316}
317
318void QDeclarativePinchGenerator::pinchPress(QPoint point1From, QPoint point2From)
319{
320 QTest::touchEvent(window: window_, device: device_).press(touchId: 0, pt: point1From).press(touchId: 1, pt: point2From);
321}
322
323void QDeclarativePinchGenerator::pinchMoveTo(QPoint point1To, QPoint point2To)
324{
325 QTest::touchEvent(window: window_, device: device_).move(touchId: 0, pt: point1To).move(touchId: 1, pt: point2To);
326}
327
328void QDeclarativePinchGenerator::pinchRelease(QPoint point1To, QPoint point2To)
329{
330 QTest::touchEvent(window: window_, device: device_).release(touchId: 0, pt: point1To).release(touchId: 1, pt: point2To);
331}
332
333void QDeclarativePinchGenerator::replay()
334{
335 if (state_ != Idle) {
336 qDebug() << "Wrong state, will not replay pinch, state: " << state_;
337 return;
338 }
339 if (swipes_.count() < SWIPES_REQUIRED) {
340 qDebug() << "Too few swipes, cannot replay, amount: " << swipes_.count();
341 return;
342 }
343 if ((swipes_.at(i: 0)->touchPoints.count() < 2) || (swipes_.at(i: 1)->touchPoints.count() < 2)) {
344 qDebug() << "Too few touchpoints, won't replay, amount: " <<
345 swipes_.at(i: 0)->touchPoints.count() << (swipes_.at(i: 1)->touchPoints.count() < 2);
346 return;
347 }
348
349 masterSwipe_ = (swipes_.at(i: 0)->touchPoints.count() >= swipes_.at(i: 1)->touchPoints.count()) ? 0 : 1;
350
351 replayTimer_ = startTimer(interval: swipes_.at(i: masterSwipe_)->touchPoints.count() / replaySpeedFactor_);
352 replayBookmark_ = 0;
353 setState(Replaying);
354}
355
356void QDeclarativePinchGenerator::clear()
357{
358 stop();
359 delete activeSwipe_;
360 activeSwipe_ = 0;
361 if (!swipes_.isEmpty()) {
362 qDeleteAll(c: swipes_);
363 swipes_.clear();
364 }
365}
366
367void QDeclarativePinchGenerator::stop()
368{
369 if (state_ != Replaying)
370 return;
371 // stop replay
372 Q_ASSERT(replayTimer_ != -1);
373 killTimer(id: replayTimer_);
374 replayTimer_ = -1;
375 setState(Idle);
376}
377
378int QDeclarativePinchGenerator::startDragDistance()
379{
380 return qApp->styleHints()->startDragDistance();
381}
382
383QT_END_NAMESPACE
384

source code of qtlocation/tests/plugins/declarativetestplugin/qdeclarativepinchgenerator.cpp