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
30#include <QtTest/QtTest>
31#include <QtTest/qtesttouch.h>
32
33#include <qevent.h>
34#include <qtouchdevice.h>
35#include <qwidget.h>
36#include <qlayout.h>
37#include <qgesture.h>
38#include <qgesturerecognizer.h>
39#include <qgraphicsitem.h>
40#include <qgraphicswidget.h>
41#include <qgraphicsview.h>
42#include <qmainwindow.h>
43
44#include <qdebug.h>
45
46static QPointF mapToGlobal(const QPointF &pt, QGraphicsItem *item, QGraphicsView *view)
47{
48 return view->viewport()->mapToGlobal(view->mapFromScene(point: item->mapToScene(point: pt)));
49}
50
51class CustomGesture : public QGesture
52{
53 Q_OBJECT
54public:
55 static Qt::GestureType GestureType;
56
57 CustomGesture(QObject *parent = 0)
58 : QGesture(parent), serial(0)
59 {
60 }
61
62 int serial;
63
64 static const int SerialMaybeThreshold;
65 static const int SerialStartedThreshold;
66 static const int SerialFinishedThreshold;
67};
68Qt::GestureType CustomGesture::GestureType = Qt::CustomGesture;
69const int CustomGesture::SerialMaybeThreshold = 1;
70const int CustomGesture::SerialStartedThreshold = 3;
71const int CustomGesture::SerialFinishedThreshold = 6;
72
73class CustomEvent : public QEvent
74{
75public:
76 static int EventType;
77
78 explicit CustomEvent(int serial_ = 0)
79 : QEvent(QEvent::Type(CustomEvent::EventType)),
80 serial(serial_), hasHotSpot(false)
81 {
82 }
83
84 int serial;
85 QPointF hotSpot;
86 bool hasHotSpot;
87};
88int CustomEvent::EventType = 0;
89
90class CustomGestureRecognizer : public QGestureRecognizer
91{
92public:
93 static bool ConsumeEvents;
94
95 CustomGestureRecognizer()
96 {
97 if (!CustomEvent::EventType)
98 CustomEvent::EventType = QEvent::registerEventType();
99 }
100
101 QGesture* create(QObject *)
102 {
103 return new CustomGesture;
104 }
105
106 QGestureRecognizer::Result recognize(QGesture *state, QObject*, QEvent *event)
107 {
108 if (event->type() == CustomEvent::EventType) {
109 QGestureRecognizer::Result result;
110 if (CustomGestureRecognizer::ConsumeEvents)
111 result |= QGestureRecognizer::ConsumeEventHint;
112 CustomGesture *g = static_cast<CustomGesture*>(state);
113 CustomEvent *e = static_cast<CustomEvent*>(event);
114 g->serial = e->serial;
115 if (e->hasHotSpot)
116 g->setHotSpot(e->hotSpot);
117 if (g->serial >= CustomGesture::SerialFinishedThreshold)
118 result |= QGestureRecognizer::FinishGesture;
119 else if (g->serial >= CustomGesture::SerialStartedThreshold)
120 result |= QGestureRecognizer::TriggerGesture;
121 else if (g->serial >= CustomGesture::SerialMaybeThreshold)
122 result |= QGestureRecognizer::MayBeGesture;
123 else
124 result = QGestureRecognizer::CancelGesture;
125 return result;
126 }
127 return QGestureRecognizer::Ignore;
128 }
129
130 void reset(QGesture *state)
131 {
132 CustomGesture *g = static_cast<CustomGesture *>(state);
133 g->serial = 0;
134 QGestureRecognizer::reset(state);
135 }
136};
137bool CustomGestureRecognizer::ConsumeEvents = false;
138
139// same as CustomGestureRecognizer but triggers early without the maybe state
140class CustomContinuousGestureRecognizer : public QGestureRecognizer
141{
142public:
143 CustomContinuousGestureRecognizer()
144 {
145 if (!CustomEvent::EventType)
146 CustomEvent::EventType = QEvent::registerEventType();
147 }
148
149 QGesture* create(QObject *)
150 {
151 return new CustomGesture;
152 }
153
154 QGestureRecognizer::Result recognize(QGesture *state, QObject*, QEvent *event)
155 {
156 if (event->type() == CustomEvent::EventType) {
157 QGestureRecognizer::Result result = QGestureRecognizer::ConsumeEventHint;
158 CustomGesture *g = static_cast<CustomGesture *>(state);
159 CustomEvent *e = static_cast<CustomEvent *>(event);
160 g->serial = e->serial;
161 if (e->hasHotSpot)
162 g->setHotSpot(e->hotSpot);
163 if (g->serial >= CustomGesture::SerialFinishedThreshold)
164 result |= QGestureRecognizer::FinishGesture;
165 else if (g->serial >= CustomGesture::SerialMaybeThreshold)
166 result |= QGestureRecognizer::TriggerGesture;
167 else
168 result = QGestureRecognizer::CancelGesture;
169 return result;
170 }
171 return QGestureRecognizer::Ignore;
172 }
173
174 void reset(QGesture *state)
175 {
176 CustomGesture *g = static_cast<CustomGesture *>(state);
177 g->serial = 0;
178 QGestureRecognizer::reset(state);
179 }
180};
181
182class GestureWidget : public QWidget
183{
184 Q_OBJECT
185public:
186 GestureWidget(const char *name = 0, QWidget *parent = 0)
187 : QWidget(parent)
188 {
189 if (name)
190 setObjectName(QLatin1String(name));
191 reset();
192 acceptGestureOverride = false;
193 }
194 void reset()
195 {
196 customEventsReceived = 0;
197 gestureEventsReceived = 0;
198 gestureOverrideEventsReceived = 0;
199 events.clear();
200 overrideEvents.clear();
201 ignoredGestures.clear();
202 }
203
204 int customEventsReceived;
205 int gestureEventsReceived;
206 int gestureOverrideEventsReceived;
207 struct Events
208 {
209 QList<Qt::GestureType> all;
210 QList<Qt::GestureType> started;
211 QList<Qt::GestureType> updated;
212 QList<Qt::GestureType> finished;
213 QList<Qt::GestureType> canceled;
214
215 void clear()
216 {
217 all.clear();
218 started.clear();
219 updated.clear();
220 finished.clear();
221 canceled.clear();
222 }
223 } events, overrideEvents;
224
225 bool acceptGestureOverride;
226 QSet<Qt::GestureType> ignoredGestures;
227
228protected:
229 bool event(QEvent *event)
230 {
231 Events *eventsPtr = 0;
232 if (event->type() == QEvent::Gesture) {
233 QGestureEvent *e = static_cast<QGestureEvent*>(event);
234 ++gestureEventsReceived;
235 eventsPtr = &events;
236 foreach(Qt::GestureType type, ignoredGestures)
237 e->ignore(e->gesture(type));
238 } else if (event->type() == QEvent::GestureOverride) {
239 ++gestureOverrideEventsReceived;
240 eventsPtr = &overrideEvents;
241 if (acceptGestureOverride)
242 event->accept();
243 }
244 if (eventsPtr) {
245 QGestureEvent *e = static_cast<QGestureEvent*>(event);
246 QList<QGesture*> gestures = e->gestures();
247 foreach(QGesture *g, gestures) {
248 eventsPtr->all << g->gestureType();
249 switch(g->state()) {
250 case Qt::GestureStarted:
251 emit gestureStarted(e->type(), g);
252 eventsPtr->started << g->gestureType();
253 break;
254 case Qt::GestureUpdated:
255 emit gestureUpdated(e->type(), g);
256 eventsPtr->updated << g->gestureType();
257 break;
258 case Qt::GestureFinished:
259 emit gestureFinished(e->type(), g);
260 eventsPtr->finished << g->gestureType();
261 break;
262 case Qt::GestureCanceled:
263 emit gestureCanceled(e->type(), g);
264 eventsPtr->canceled << g->gestureType();
265 break;
266 default:
267 qWarning() << "Unknown GestureState enum value:" << static_cast<int>(g->state());
268 }
269 }
270 } else if (event->type() == CustomEvent::EventType) {
271 ++customEventsReceived;
272 } else {
273 return QWidget::event(event);
274 }
275 return true;
276 }
277
278Q_SIGNALS:
279 void gestureStarted(QEvent::Type, QGesture *);
280 void gestureUpdated(QEvent::Type, QGesture *);
281 void gestureFinished(QEvent::Type, QGesture *);
282 void gestureCanceled(QEvent::Type, QGesture *);
283
284public Q_SLOTS:
285 void deleteThis() { delete this; }
286};
287
288// TODO rename to sendGestureSequence
289static void sendCustomGesture(CustomEvent *event, QObject *object, QGraphicsScene *scene = 0)
290{
291 QPointer<QObject> receiver(object);
292 for (int i = CustomGesture::SerialMaybeThreshold;
293 i <= CustomGesture::SerialFinishedThreshold && receiver; ++i) {
294 event->serial = i;
295 if (scene)
296 scene->sendEvent(item: qobject_cast<QGraphicsObject *>(object), event);
297 else
298 QApplication::sendEvent(receiver: object, event);
299 }
300}
301
302class tst_Gestures : public QObject
303{
304Q_OBJECT
305
306private slots:
307 void initTestCase();
308 void cleanupTestCase();
309 void customGesture();
310 void autoCancelingGestures();
311 void gestureOverChild();
312 void multipleWidgetOnlyGestureInTree();
313 void conflictingGestures();
314 void conflictingGesturesInGraphicsView();
315 void finishedWithoutStarted();
316 void unknownGesture();
317 void graphicsItemGesture();
318 void graphicsView();
319 void graphicsItemTreeGesture();
320 void explicitGraphicsObjectTarget();
321 void gestureOverChildGraphicsItem();
322 void twoGesturesOnDifferentLevel();
323 void multipleGesturesInTree();
324 void multipleGesturesInComplexTree();
325 void testMapToScene();
326 void ungrabGesture();
327 void consumeEventHint();
328 void unregisterRecognizer();
329 void autoCancelGestures();
330 void autoCancelGestures2();
331 void graphicsViewParentPropagation();
332 void panelPropagation();
333 void panelStacksBehindParent();
334#ifdef Q_OS_MACOS
335 void deleteMacPanGestureRecognizerTargetWidget();
336#endif
337 void deleteGestureTargetWidget();
338 void deleteGestureTargetItem_data();
339 void deleteGestureTargetItem();
340 void viewportCoordinates();
341 void partialGesturePropagation();
342 void testQGestureRecognizerCleanup();
343 void testReuseCanceledGestures();
344 void bug_13501_gesture_not_accepted();
345};
346
347void tst_Gestures::initTestCase()
348{
349 CustomGesture::GestureType = QGestureRecognizer::registerRecognizer(recognizer: new CustomGestureRecognizer);
350 QVERIFY(CustomGesture::GestureType != Qt::GestureType(0));
351 QVERIFY(CustomGesture::GestureType != Qt::CustomGesture);
352}
353
354void tst_Gestures::cleanupTestCase()
355{
356 QGestureRecognizer::unregisterRecognizer(type: CustomGesture::GestureType);
357}
358
359void tst_Gestures::customGesture()
360{
361 GestureWidget widget;
362 widget.grabGesture(type: CustomGesture::GestureType, flags: Qt::DontStartGestureOnChildren);
363 widget.show();
364 QVERIFY(QTest::qWaitForWindowExposed(&widget));
365
366 CustomEvent event;
367 event.hotSpot = widget.mapToGlobal(QPoint(5,5));
368 event.hasHotSpot = true;
369 sendCustomGesture(event: &event, object: &widget);
370
371 static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
372 static const int TotalCustomEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialMaybeThreshold + 1;
373 QCOMPARE(widget.customEventsReceived, TotalCustomEventsCount);
374 QCOMPARE(widget.gestureEventsReceived, TotalGestureEventsCount);
375 QCOMPARE(widget.gestureOverrideEventsReceived, 0);
376 QCOMPARE(widget.events.all.size(), TotalGestureEventsCount);
377 for(int i = 0; i < widget.events.all.size(); ++i)
378 QCOMPARE(widget.events.all.at(i), CustomGesture::GestureType);
379 QCOMPARE(widget.events.started.size(), 1);
380 QCOMPARE(widget.events.updated.size(), TotalGestureEventsCount - 2);
381 QCOMPARE(widget.events.finished.size(), 1);
382 QCOMPARE(widget.events.canceled.size(), 0);
383}
384
385void tst_Gestures::consumeEventHint()
386{
387 GestureWidget widget;
388 widget.grabGesture(type: CustomGesture::GestureType, flags: Qt::DontStartGestureOnChildren);
389
390 CustomGestureRecognizer::ConsumeEvents = true;
391 CustomEvent event;
392 sendCustomGesture(event: &event, object: &widget);
393 CustomGestureRecognizer::ConsumeEvents = false;
394
395 QCOMPARE(widget.customEventsReceived, 0);
396}
397
398void tst_Gestures::autoCancelingGestures()
399{
400 GestureWidget widget;
401 widget.grabGesture(type: CustomGesture::GestureType, flags: Qt::DontStartGestureOnChildren);
402 // send partial gesture. The gesture will be in the "maybe" state, but will
403 // never get enough events to fire, so Qt will have to kill it.
404 CustomEvent ev;
405 for (int i = CustomGesture::SerialMaybeThreshold;
406 i < CustomGesture::SerialStartedThreshold; ++i) {
407 ev.serial = i;
408 QApplication::sendEvent(receiver: &widget, event: &ev);
409 }
410 // wait long enough so the gesture manager will cancel the gesture
411 QTest::qWait(ms: 5000);
412 QCOMPARE(widget.customEventsReceived, CustomGesture::SerialStartedThreshold - CustomGesture::SerialMaybeThreshold);
413 QCOMPARE(widget.gestureEventsReceived, 0);
414 QCOMPARE(widget.gestureOverrideEventsReceived, 0);
415 QCOMPARE(widget.events.all.size(), 0);
416}
417
418void tst_Gestures::gestureOverChild()
419{
420 GestureWidget widget("widget");
421 QVBoxLayout *l = new QVBoxLayout(&widget);
422 GestureWidget *child = new GestureWidget("child");
423 l->addWidget(child);
424
425 widget.grabGesture(type: CustomGesture::GestureType, flags: Qt::DontStartGestureOnChildren);
426
427 CustomEvent event;
428 sendCustomGesture(event: &event, object: child);
429
430 static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
431 static const int TotalCustomEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialMaybeThreshold + 1;
432
433 QCOMPARE(child->customEventsReceived, TotalCustomEventsCount);
434 QCOMPARE(widget.customEventsReceived, 0);
435 QCOMPARE(child->gestureEventsReceived, 0);
436 QCOMPARE(child->gestureOverrideEventsReceived, 0);
437 QCOMPARE(widget.gestureEventsReceived, 0);
438 QCOMPARE(widget.gestureOverrideEventsReceived, 0);
439
440 // enable gestures over the children
441 widget.grabGesture(type: CustomGesture::GestureType);
442
443 widget.reset();
444 child->reset();
445
446 sendCustomGesture(event: &event, object: child);
447
448 QCOMPARE(child->customEventsReceived, TotalCustomEventsCount);
449 QCOMPARE(widget.customEventsReceived, 0);
450
451 QCOMPARE(child->gestureEventsReceived, 0);
452 QCOMPARE(child->gestureOverrideEventsReceived, 0);
453 QCOMPARE(widget.gestureEventsReceived, TotalGestureEventsCount);
454 QCOMPARE(widget.gestureOverrideEventsReceived, 0);
455 for(int i = 0; i < widget.events.all.size(); ++i)
456 QCOMPARE(widget.events.all.at(i), CustomGesture::GestureType);
457 QCOMPARE(widget.events.started.size(), 1);
458 QCOMPARE(widget.events.updated.size(), TotalGestureEventsCount - 2);
459 QCOMPARE(widget.events.finished.size(), 1);
460 QCOMPARE(widget.events.canceled.size(), 0);
461}
462
463void tst_Gestures::multipleWidgetOnlyGestureInTree()
464{
465 GestureWidget parent("parent");
466 QVBoxLayout *l = new QVBoxLayout(&parent);
467 GestureWidget *child = new GestureWidget("child");
468 l->addWidget(child);
469
470 parent.grabGesture(type: CustomGesture::GestureType, flags: Qt::DontStartGestureOnChildren);
471 child->grabGesture(type: CustomGesture::GestureType, flags: Qt::DontStartGestureOnChildren);
472
473 static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
474 static const int TotalCustomEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialMaybeThreshold + 1;
475
476 // sending events to the child and making sure there is no conflict
477 CustomEvent event;
478 sendCustomGesture(event: &event, object: child);
479
480 QCOMPARE(child->customEventsReceived, TotalCustomEventsCount);
481 QCOMPARE(parent.customEventsReceived, 0);
482 QCOMPARE(child->gestureEventsReceived, TotalGestureEventsCount);
483 QCOMPARE(child->gestureOverrideEventsReceived, 0);
484 QCOMPARE(parent.gestureEventsReceived, 0);
485 QCOMPARE(parent.gestureOverrideEventsReceived, 0);
486
487 parent.reset();
488 child->reset();
489
490 // same for the parent widget
491 sendCustomGesture(event: &event, object: &parent);
492
493 QCOMPARE(child->customEventsReceived, 0);
494 QCOMPARE(parent.customEventsReceived, TotalCustomEventsCount);
495 QCOMPARE(child->gestureEventsReceived, 0);
496 QCOMPARE(child->gestureOverrideEventsReceived, 0);
497 QCOMPARE(parent.gestureEventsReceived, TotalGestureEventsCount);
498 QCOMPARE(parent.gestureOverrideEventsReceived, 0);
499}
500
501void tst_Gestures::conflictingGestures()
502{
503 GestureWidget parent("parent");
504 QVBoxLayout *l = new QVBoxLayout(&parent);
505 GestureWidget *child = new GestureWidget("child");
506 l->addWidget(child);
507
508 parent.grabGesture(type: CustomGesture::GestureType);
509 child->grabGesture(type: CustomGesture::GestureType);
510
511 static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
512
513 // child accepts the override, parent will not receive anything
514 parent.acceptGestureOverride = false;
515 child->acceptGestureOverride = true;
516
517 // sending events to the child and making sure there is no conflict
518 CustomEvent event;
519 sendCustomGesture(event: &event, object: child);
520
521 QCOMPARE(child->gestureOverrideEventsReceived, 1);
522 QCOMPARE(child->gestureEventsReceived, TotalGestureEventsCount);
523 QCOMPARE(parent.gestureOverrideEventsReceived, 0);
524 QCOMPARE(parent.gestureEventsReceived, 0);
525
526 parent.reset();
527 child->reset();
528
529 // parent accepts the override
530 parent.acceptGestureOverride = true;
531 child->acceptGestureOverride = false;
532
533 // sending events to the child and making sure there is no conflict
534 sendCustomGesture(event: &event, object: child);
535
536 QCOMPARE(child->gestureOverrideEventsReceived, 1);
537 QCOMPARE(child->gestureEventsReceived, 0);
538 QCOMPARE(parent.gestureOverrideEventsReceived, 1);
539 QCOMPARE(parent.gestureEventsReceived, TotalGestureEventsCount);
540
541 parent.reset();
542 child->reset();
543
544 // nobody accepts the override, we will send normal events to the closest
545 // context (i.e. to the child widget) and it will be propagated and
546 // accepted by the parent widget
547 parent.acceptGestureOverride = false;
548 child->acceptGestureOverride = false;
549 child->ignoredGestures << CustomGesture::GestureType;
550
551 // sending events to the child and making sure there is no conflict
552 sendCustomGesture(event: &event, object: child);
553
554 QCOMPARE(child->gestureOverrideEventsReceived, 1);
555 QCOMPARE(child->gestureEventsReceived, 1);
556 QCOMPARE(parent.gestureOverrideEventsReceived, 1);
557 QCOMPARE(parent.gestureEventsReceived, TotalGestureEventsCount);
558
559 parent.reset();
560 child->reset();
561
562 // nobody accepts the override, and nobody accepts the gesture event
563 parent.acceptGestureOverride = false;
564 child->acceptGestureOverride = false;
565 parent.ignoredGestures << CustomGesture::GestureType;
566 child->ignoredGestures << CustomGesture::GestureType;
567
568 // sending events to the child and making sure there is no conflict
569 sendCustomGesture(event: &event, object: child);
570
571 QCOMPARE(child->gestureOverrideEventsReceived, 1);
572 QCOMPARE(child->gestureEventsReceived, TotalGestureEventsCount);
573 QCOMPARE(parent.gestureOverrideEventsReceived, 1);
574 QCOMPARE(parent.gestureEventsReceived, 1);
575
576 parent.reset();
577 child->reset();
578
579 // we set an attribute to make sure all gesture events are propagated
580 parent.grabGesture(type: CustomGesture::GestureType, flags: Qt::ReceivePartialGestures);
581 parent.acceptGestureOverride = false;
582 child->acceptGestureOverride = false;
583 parent.ignoredGestures << CustomGesture::GestureType;
584 child->ignoredGestures << CustomGesture::GestureType;
585
586 // sending events to the child and making sure there is no conflict
587 sendCustomGesture(event: &event, object: child);
588
589 QCOMPARE(child->gestureOverrideEventsReceived, 1);
590 QCOMPARE(child->gestureEventsReceived, TotalGestureEventsCount);
591 QCOMPARE(parent.gestureOverrideEventsReceived, 1);
592 QCOMPARE(parent.gestureEventsReceived, TotalGestureEventsCount);
593
594 parent.reset();
595 child->reset();
596
597 Qt::GestureType ContinuousGesture = QGestureRecognizer::registerRecognizer(recognizer: new CustomContinuousGestureRecognizer);
598 static const int ContinuousGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialMaybeThreshold + 1;
599 child->grabGesture(type: ContinuousGesture);
600 // child accepts override. And it also receives another custom gesture.
601 parent.acceptGestureOverride = false;
602 child->acceptGestureOverride = true;
603 sendCustomGesture(event: &event, object: child);
604
605 QCOMPARE(child->gestureOverrideEventsReceived, 1);
606 QVERIFY(child->gestureEventsReceived > TotalGestureEventsCount);
607 QCOMPARE(child->events.all.count(), TotalGestureEventsCount + ContinuousGestureEventsCount);
608 QCOMPARE(parent.gestureOverrideEventsReceived, 0);
609 QCOMPARE(parent.gestureEventsReceived, 0);
610
611 QGestureRecognizer::unregisterRecognizer(type: ContinuousGesture);
612}
613
614void tst_Gestures::finishedWithoutStarted()
615{
616 GestureWidget widget;
617 widget.grabGesture(type: CustomGesture::GestureType, flags: Qt::DontStartGestureOnChildren);
618
619 // the gesture will claim it finished, but it was never started.
620 CustomEvent ev;
621 ev.serial = CustomGesture::SerialFinishedThreshold;
622 QApplication::sendEvent(receiver: &widget, event: &ev);
623
624 QCOMPARE(widget.customEventsReceived, 1);
625 QCOMPARE(widget.gestureEventsReceived, 2);
626 QCOMPARE(widget.gestureOverrideEventsReceived, 0);
627 QCOMPARE(widget.events.all.size(), 2);
628 QCOMPARE(widget.events.started.size(), 1);
629 QCOMPARE(widget.events.updated.size(), 0);
630 QCOMPARE(widget.events.finished.size(), 1);
631 QCOMPARE(widget.events.canceled.size(), 0);
632}
633
634void tst_Gestures::unknownGesture()
635{
636 GestureWidget widget;
637 widget.grabGesture(type: CustomGesture::GestureType, flags: Qt::DontStartGestureOnChildren);
638 widget.grabGesture(type: Qt::CustomGesture, flags: Qt::DontStartGestureOnChildren);
639 widget.grabGesture(type: Qt::GestureType(Qt::PanGesture+512), flags: Qt::DontStartGestureOnChildren);
640
641 CustomEvent event;
642 sendCustomGesture(event: &event, object: &widget);
643
644 static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
645
646 QCOMPARE(widget.gestureEventsReceived, TotalGestureEventsCount);
647}
648
649static const QColor InstanceColors[] = {
650 Qt::blue, Qt::red, Qt::green, Qt::gray, Qt::yellow
651};
652
653class GestureItem : public QGraphicsObject
654{
655 Q_OBJECT
656 static int InstanceCount;
657public:
658 GestureItem(const char *name = 0)
659 {
660 instanceNumber = InstanceCount++;
661 if (name) {
662 setObjectName(QLatin1String(name));
663 setToolTip(name);
664 }
665 size = QRectF(0, 0, 100, 100);
666 customEventsReceived = 0;
667 gestureEventsReceived = 0;
668 gestureOverrideEventsReceived = 0;
669 events.clear();
670 overrideEvents.clear();
671 acceptGestureOverride = false;
672
673 scene = 0;
674 }
675 ~GestureItem()
676 {
677 --InstanceCount;
678 }
679
680 int customEventsReceived;
681 int gestureEventsReceived;
682 int gestureOverrideEventsReceived;
683 struct Events
684 {
685 QList<Qt::GestureType> all;
686 QList<Qt::GestureType> started;
687 QList<Qt::GestureType> updated;
688 QList<Qt::GestureType> finished;
689 QList<Qt::GestureType> canceled;
690
691 void clear()
692 {
693 all.clear();
694 started.clear();
695 updated.clear();
696 finished.clear();
697 canceled.clear();
698 }
699 } events, overrideEvents;
700
701 bool acceptGestureOverride;
702 QSet<Qt::GestureType> ignoredGestures;
703 QSet<Qt::GestureType> ignoredStartedGestures;
704 QSet<Qt::GestureType> ignoredUpdatedGestures;
705 QSet<Qt::GestureType> ignoredFinishedGestures;
706
707 QRectF size;
708 int instanceNumber;
709
710 void reset()
711 {
712 customEventsReceived = 0;
713 gestureEventsReceived = 0;
714 gestureOverrideEventsReceived = 0;
715 events.clear();
716 overrideEvents.clear();
717 ignoredGestures.clear();
718 ignoredStartedGestures.clear();
719 ignoredUpdatedGestures.clear();
720 ignoredFinishedGestures.clear();
721 }
722
723 QRectF boundingRect() const
724 {
725 return size;
726 }
727 void paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *)
728 {
729 QColor color = InstanceColors[instanceNumber % (sizeof(InstanceColors)/sizeof(InstanceColors[0]))];
730 p->fillRect(boundingRect(), color);
731 }
732
733 bool event(QEvent *event)
734 {
735 Events *eventsPtr = 0;
736 if (event->type() == QEvent::Gesture) {
737 ++gestureEventsReceived;
738 eventsPtr = &events;
739 QGestureEvent *e = static_cast<QGestureEvent *>(event);
740 foreach(Qt::GestureType type, ignoredGestures)
741 e->ignore(e->gesture(type));
742 foreach(QGesture *g, e->gestures()) {
743 switch (g->state()) {
744 case Qt::GestureStarted:
745 if (ignoredStartedGestures.contains(value: g->gestureType()))
746 e->ignore(g);
747 break;
748 case Qt::GestureUpdated:
749 if (ignoredUpdatedGestures.contains(value: g->gestureType()))
750 e->ignore(g);
751 break;
752 case Qt::GestureFinished:
753 if (ignoredFinishedGestures.contains(value: g->gestureType()))
754 e->ignore(g);
755 break;
756 default:
757 break;
758 }
759 }
760 } else if (event->type() == QEvent::GestureOverride) {
761 ++gestureOverrideEventsReceived;
762 eventsPtr = &overrideEvents;
763 if (acceptGestureOverride)
764 event->accept();
765 }
766 if (eventsPtr) {
767 QGestureEvent *e = static_cast<QGestureEvent*>(event);
768 QList<QGesture*> gestures = e->gestures();
769 foreach(QGesture *g, gestures) {
770 eventsPtr->all << g->gestureType();
771 switch(g->state()) {
772 case Qt::GestureStarted:
773 eventsPtr->started << g->gestureType();
774 emit gestureStarted(e->type(), g);
775 break;
776 case Qt::GestureUpdated:
777 eventsPtr->updated << g->gestureType();
778 emit gestureUpdated(e->type(), g);
779 break;
780 case Qt::GestureFinished:
781 eventsPtr->finished << g->gestureType();
782 emit gestureFinished(e->type(), g);
783 break;
784 case Qt::GestureCanceled:
785 eventsPtr->canceled << g->gestureType();
786 emit gestureCanceled(e->type(), g);
787 break;
788 default:
789 qWarning() << "Unknown GestureState enum value:" << static_cast<int>(g->state());
790 }
791 }
792 } else if (event->type() == CustomEvent::EventType) {
793 ++customEventsReceived;
794 } else {
795 return QGraphicsObject::event(ev: event);
796 }
797 return true;
798 }
799
800Q_SIGNALS:
801 void gestureStarted(QEvent::Type, QGesture *);
802 void gestureUpdated(QEvent::Type, QGesture *);
803 void gestureFinished(QEvent::Type, QGesture *);
804 void gestureCanceled(QEvent::Type, QGesture *);
805
806public:
807 // some arguments for the slots below:
808 QGraphicsScene *scene;
809
810public Q_SLOTS:
811 void deleteThis() { delete this; }
812 void addSelfToScene(QEvent::Type eventType, QGesture *)
813 {
814 if (eventType == QEvent::Gesture) {
815 disconnect(sender: sender(), signal: 0, receiver: this, SLOT(addSelfToScene(QEvent::Type,QGesture*)));
816 scene->addItem(item: this);
817 }
818 }
819};
820int GestureItem::InstanceCount = 0;
821
822void tst_Gestures::graphicsItemGesture()
823{
824 QGraphicsScene scene;
825 QGraphicsView view(&scene);
826 view.setWindowFlags(Qt::X11BypassWindowManagerHint);
827
828 GestureItem *item = new GestureItem("item");
829 scene.addItem(item);
830 item->setPos(ax: 100, ay: 100);
831
832 view.show();
833 QVERIFY(QTest::qWaitForWindowExposed(&view));
834 view.ensureVisible(rect: scene.sceneRect());
835
836 item->grabGesture(type: CustomGesture::GestureType);
837
838 static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
839 static const int TotalCustomEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialMaybeThreshold + 1;
840
841 CustomEvent event;
842 // gesture without hotspot should not be delivered to items in the view
843 QTest::ignoreMessage(type: QtWarningMsg, message: "QGestureManager::deliverEvent: could not find the target for gesture");
844 QTest::ignoreMessage(type: QtWarningMsg, message: "QGestureManager::deliverEvent: could not find the target for gesture");
845 QTest::ignoreMessage(type: QtWarningMsg, message: "QGestureManager::deliverEvent: could not find the target for gesture");
846 QTest::ignoreMessage(type: QtWarningMsg, message: "QGestureManager::deliverEvent: could not find the target for gesture");
847 sendCustomGesture(event: &event, object: item, scene: &scene);
848
849 QCOMPARE(item->customEventsReceived, TotalCustomEventsCount);
850 QCOMPARE(item->gestureEventsReceived, 0);
851 QCOMPARE(item->gestureOverrideEventsReceived, 0);
852
853 item->reset();
854
855 // make sure the event is properly delivered if only the hotspot is set.
856 event.hotSpot = mapToGlobal(pt: QPointF(10, 10), item, view: &view);
857 event.hasHotSpot = true;
858 sendCustomGesture(event: &event, object: item, scene: &scene);
859
860 QCOMPARE(item->customEventsReceived, TotalCustomEventsCount);
861 QCOMPARE(item->gestureEventsReceived, TotalGestureEventsCount);
862 QCOMPARE(item->gestureOverrideEventsReceived, 0);
863 QCOMPARE(item->events.all.size(), TotalGestureEventsCount);
864 for(int i = 0; i < item->events.all.size(); ++i)
865 QCOMPARE(item->events.all.at(i), CustomGesture::GestureType);
866 QCOMPARE(item->events.started.size(), 1);
867 QCOMPARE(item->events.updated.size(), TotalGestureEventsCount - 2);
868 QCOMPARE(item->events.finished.size(), 1);
869 QCOMPARE(item->events.canceled.size(), 0);
870
871 item->reset();
872
873 // send gesture to the item which ignores it.
874 item->ignoredGestures << CustomGesture::GestureType;
875
876 event.hotSpot = mapToGlobal(pt: QPointF(10, 10), item, view: &view);
877 event.hasHotSpot = true;
878 sendCustomGesture(event: &event, object: item, scene: &scene);
879 QCOMPARE(item->customEventsReceived, TotalCustomEventsCount);
880 QCOMPARE(item->gestureEventsReceived, TotalGestureEventsCount);
881 QCOMPARE(item->gestureOverrideEventsReceived, 0);
882}
883
884void tst_Gestures::graphicsView()
885{
886 QGraphicsScene scene;
887 QGraphicsView view(&scene);
888 view.setWindowFlags(Qt::X11BypassWindowManagerHint);
889
890 GestureItem *item = new GestureItem("item");
891 scene.addItem(item);
892 item->setPos(ax: 100, ay: 100);
893
894 view.show();
895 QVERIFY(QTest::qWaitForWindowExposed(&view));
896 view.ensureVisible(rect: scene.sceneRect());
897
898 item->grabGesture(type: CustomGesture::GestureType);
899
900 static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
901 static const int TotalCustomEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialMaybeThreshold + 1;
902
903 CustomEvent event;
904 // make sure the event is properly delivered if only the hotspot is set.
905 event.hotSpot = mapToGlobal(pt: QPointF(10, 10), item, view: &view);
906 event.hasHotSpot = true;
907 sendCustomGesture(event: &event, object: item, scene: &scene);
908
909 QCOMPARE(item->customEventsReceived, TotalCustomEventsCount);
910 QCOMPARE(item->gestureEventsReceived, TotalGestureEventsCount);
911 QCOMPARE(item->gestureOverrideEventsReceived, 0);
912
913 // change the viewport and try again
914 QWidget *newViewport = new QWidget;
915 view.setViewport(newViewport);
916
917 item->reset();
918 sendCustomGesture(event: &event, object: item, scene: &scene);
919
920 QCOMPARE(item->customEventsReceived, TotalCustomEventsCount);
921 QCOMPARE(item->gestureEventsReceived, TotalGestureEventsCount);
922 QCOMPARE(item->gestureOverrideEventsReceived, 0);
923
924 // change the scene and try again
925 QGraphicsScene newScene;
926 item = new GestureItem("newItem");
927 newScene.addItem(item);
928 item->setPos(ax: 100, ay: 100);
929 view.setScene(&newScene);
930
931 item->reset();
932 // first without a gesture
933 sendCustomGesture(event: &event, object: item, scene: &newScene);
934
935 QCOMPARE(item->customEventsReceived, TotalCustomEventsCount);
936 QCOMPARE(item->gestureEventsReceived, 0);
937 QCOMPARE(item->gestureOverrideEventsReceived, 0);
938
939 // then grab the gesture and try again
940 item->reset();
941 item->grabGesture(type: CustomGesture::GestureType);
942 sendCustomGesture(event: &event, object: item, scene: &newScene);
943
944 QCOMPARE(item->customEventsReceived, TotalCustomEventsCount);
945 QCOMPARE(item->gestureEventsReceived, TotalGestureEventsCount);
946 QCOMPARE(item->gestureOverrideEventsReceived, 0);
947}
948
949void tst_Gestures::graphicsItemTreeGesture()
950{
951 QGraphicsScene scene;
952 QGraphicsView view(&scene);
953 view.setWindowFlags(Qt::X11BypassWindowManagerHint);
954
955 GestureItem *item1 = new GestureItem("item1");
956 item1->setPos(ax: 100, ay: 100);
957 item1->size = QRectF(0, 0, 350, 200);
958 scene.addItem(item: item1);
959
960 GestureItem *item1_child1 = new GestureItem("item1_child1");
961 item1_child1->setPos(ax: 50, ay: 50);
962 item1_child1->size = QRectF(0, 0, 100, 100);
963 item1_child1->setParentItem(item1);
964
965 GestureItem *item1_child2 = new GestureItem("item1_child2");
966 item1_child2->size = QRectF(0, 0, 100, 100);
967 item1_child2->setPos(ax: 200, ay: 50);
968 item1_child2->setParentItem(item1);
969
970 view.show();
971 QVERIFY(QTest::qWaitForWindowExposed(&view));
972 view.ensureVisible(rect: scene.sceneRect());
973
974 item1->grabGesture(type: CustomGesture::GestureType);
975
976 static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
977
978 CustomEvent event;
979 event.hotSpot = mapToGlobal(pt: QPointF(10, 10), item: item1_child1, view: &view);
980 event.hasHotSpot = true;
981
982 item1->ignoredGestures << CustomGesture::GestureType;
983 sendCustomGesture(event: &event, object: item1_child1, scene: &scene);
984 QCOMPARE(item1_child1->gestureOverrideEventsReceived, 0);
985 QCOMPARE(item1_child1->gestureEventsReceived, 0);
986 QCOMPARE(item1_child2->gestureEventsReceived, 0);
987 QCOMPARE(item1_child2->gestureOverrideEventsReceived, 0);
988 QCOMPARE(item1->gestureOverrideEventsReceived, 0);
989 QCOMPARE(item1->gestureEventsReceived, TotalGestureEventsCount);
990
991 item1->reset(); item1_child1->reset(); item1_child2->reset();
992
993 item1_child1->grabGesture(type: CustomGesture::GestureType);
994
995 item1->ignoredGestures << CustomGesture::GestureType;
996 item1_child1->ignoredGestures << CustomGesture::GestureType;
997 sendCustomGesture(event: &event, object: item1_child1, scene: &scene);
998 QCOMPARE(item1_child1->gestureOverrideEventsReceived, 1);
999 QCOMPARE(item1_child1->gestureEventsReceived, TotalGestureEventsCount);
1000 QCOMPARE(item1_child2->gestureEventsReceived, 0);
1001 QCOMPARE(item1_child2->gestureOverrideEventsReceived, 0);
1002 QCOMPARE(item1->gestureOverrideEventsReceived, 1);
1003 QCOMPARE(item1->gestureEventsReceived, 1);
1004}
1005
1006void tst_Gestures::explicitGraphicsObjectTarget()
1007{
1008 QGraphicsScene scene;
1009 QGraphicsView view(&scene);
1010 view.setWindowFlags(Qt::X11BypassWindowManagerHint);
1011
1012 GestureItem *item1 = new GestureItem("item1");
1013 scene.addItem(item: item1);
1014 item1->setPos(ax: 100, ay: 100);
1015 item1->setZValue(1);
1016
1017 GestureItem *item2 = new GestureItem("item2");
1018 scene.addItem(item: item2);
1019 item2->setPos(ax: 100, ay: 100);
1020 item2->setZValue(5);
1021
1022 GestureItem *item2_child1 = new GestureItem("item2_child1");
1023 scene.addItem(item: item2_child1);
1024 item2_child1->setParentItem(item2);
1025 item2_child1->setPos(ax: 10, ay: 10);
1026
1027 view.show();
1028 QVERIFY(QTest::qWaitForWindowExposed(&view));
1029 view.ensureVisible(rect: scene.sceneRect());
1030
1031 item1->grabGesture(type: CustomGesture::GestureType, flags: Qt::DontStartGestureOnChildren);
1032 item2->grabGesture(type: CustomGesture::GestureType, flags: Qt::DontStartGestureOnChildren);
1033 item2_child1->grabGesture(type: CustomGesture::GestureType, flags: Qt::DontStartGestureOnChildren);
1034
1035 static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
1036
1037 // sending events to item1, but the hotSpot is set to item2
1038 CustomEvent event;
1039 event.hotSpot = mapToGlobal(pt: QPointF(15, 15), item: item2, view: &view);
1040 event.hasHotSpot = true;
1041
1042 sendCustomGesture(event: &event, object: item1, scene: &scene);
1043
1044 QCOMPARE(item1->gestureEventsReceived, 0);
1045 QCOMPARE(item1->gestureOverrideEventsReceived, 1);
1046 QCOMPARE(item2_child1->gestureEventsReceived, TotalGestureEventsCount);
1047 QCOMPARE(item2_child1->gestureOverrideEventsReceived, 1);
1048 QCOMPARE(item2_child1->events.all.size(), TotalGestureEventsCount);
1049 for(int i = 0; i < item2_child1->events.all.size(); ++i)
1050 QCOMPARE(item2_child1->events.all.at(i), CustomGesture::GestureType);
1051 QCOMPARE(item2_child1->events.started.size(), 1);
1052 QCOMPARE(item2_child1->events.updated.size(), TotalGestureEventsCount - 2);
1053 QCOMPARE(item2_child1->events.finished.size(), 1);
1054 QCOMPARE(item2_child1->events.canceled.size(), 0);
1055 QCOMPARE(item2->gestureEventsReceived, 0);
1056 QCOMPARE(item2->gestureOverrideEventsReceived, 1);
1057}
1058
1059void tst_Gestures::gestureOverChildGraphicsItem()
1060{
1061 QGraphicsScene scene;
1062 QGraphicsView view(&scene);
1063 view.setWindowFlags(Qt::X11BypassWindowManagerHint);
1064
1065 GestureItem *item0 = new GestureItem("item0");
1066 scene.addItem(item: item0);
1067 item0->setPos(ax: 0, ay: 0);
1068 item0->grabGesture(type: CustomGesture::GestureType);
1069 item0->setZValue(1);
1070
1071 GestureItem *item1 = new GestureItem("item1");
1072 scene.addItem(item: item1);
1073 item1->setPos(ax: 100, ay: 100);
1074 item1->setZValue(5);
1075
1076 GestureItem *item2 = new GestureItem("item2");
1077 scene.addItem(item: item2);
1078 item2->setPos(ax: 100, ay: 100);
1079 item2->setZValue(10);
1080
1081 GestureItem *item2_child1 = new GestureItem("item2_child1");
1082 scene.addItem(item: item2_child1);
1083 item2_child1->setParentItem(item2);
1084 item2_child1->setPos(ax: 0, ay: 0);
1085
1086 view.show();
1087 QVERIFY(QTest::qWaitForWindowExposed(&view));
1088 view.ensureVisible(rect: scene.sceneRect());
1089
1090 item1->grabGesture(type: CustomGesture::GestureType);
1091
1092 static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
1093 static const int TotalCustomEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialMaybeThreshold + 1;
1094
1095 CustomEvent event;
1096 event.hotSpot = mapToGlobal(pt: QPointF(10, 10), item: item2_child1, view: &view);
1097 event.hasHotSpot = true;
1098 sendCustomGesture(event: &event, object: item0, scene: &scene);
1099
1100 QCOMPARE(item0->customEventsReceived, TotalCustomEventsCount);
1101 QCOMPARE(item2_child1->gestureEventsReceived, 0);
1102 QCOMPARE(item2_child1->gestureOverrideEventsReceived, 0);
1103 QCOMPARE(item2->gestureEventsReceived, 0);
1104 QCOMPARE(item2->gestureOverrideEventsReceived, 0);
1105 QCOMPARE(item1->gestureEventsReceived, TotalGestureEventsCount);
1106 QCOMPARE(item1->gestureOverrideEventsReceived, 0);
1107
1108 item0->reset(); item1->reset(); item2->reset(); item2_child1->reset();
1109 item2->grabGesture(type: CustomGesture::GestureType);
1110 item2->ignoredGestures << CustomGesture::GestureType;
1111
1112 event.hotSpot = mapToGlobal(pt: QPointF(10, 10), item: item2_child1, view: &view);
1113 event.hasHotSpot = true;
1114 sendCustomGesture(event: &event, object: item0, scene: &scene);
1115
1116 QCOMPARE(item2_child1->gestureEventsReceived, 0);
1117 QCOMPARE(item2_child1->gestureOverrideEventsReceived, 0);
1118 QCOMPARE(item2->gestureEventsReceived, 1);
1119 QCOMPARE(item2->gestureOverrideEventsReceived, 1);
1120 QCOMPARE(item1->gestureEventsReceived, TotalGestureEventsCount);
1121 QCOMPARE(item1->gestureOverrideEventsReceived, 1);
1122
1123 item0->reset(); item1->reset(); item2->reset(); item2_child1->reset();
1124 item2->grabGesture(type: CustomGesture::GestureType);
1125 item2->ignoredGestures << CustomGesture::GestureType;
1126 item1->ignoredGestures << CustomGesture::GestureType;
1127
1128 event.hotSpot = mapToGlobal(pt: QPointF(10, 10), item: item2_child1, view: &view);
1129 event.hasHotSpot = true;
1130 sendCustomGesture(event: &event, object: item0, scene: &scene);
1131
1132 QCOMPARE(item2_child1->gestureEventsReceived, 0);
1133 QCOMPARE(item2_child1->gestureOverrideEventsReceived, 0);
1134 QCOMPARE(item2->gestureEventsReceived, TotalGestureEventsCount);
1135 QCOMPARE(item2->gestureOverrideEventsReceived, 1);
1136 QCOMPARE(item1->gestureEventsReceived, 1);
1137 QCOMPARE(item1->gestureOverrideEventsReceived, 1);
1138
1139 item0->reset(); item1->reset(); item2->reset(); item2_child1->reset();
1140 item2->grabGesture(type: CustomGesture::GestureType);
1141 item2->ignoredGestures << CustomGesture::GestureType;
1142 item1->ignoredGestures << CustomGesture::GestureType;
1143 item1->grabGesture(type: CustomGesture::GestureType, flags: Qt::ReceivePartialGestures);
1144
1145 event.hotSpot = mapToGlobal(pt: QPointF(10, 10), item: item2_child1, view: &view);
1146 event.hasHotSpot = true;
1147 sendCustomGesture(event: &event, object: item0, scene: &scene);
1148
1149 QCOMPARE(item2_child1->gestureEventsReceived, 0);
1150 QCOMPARE(item2_child1->gestureOverrideEventsReceived, 0);
1151 QCOMPARE(item2->gestureEventsReceived, TotalGestureEventsCount);
1152 QCOMPARE(item2->gestureOverrideEventsReceived, 1);
1153 QCOMPARE(item1->gestureEventsReceived, TotalGestureEventsCount);
1154 QCOMPARE(item1->gestureOverrideEventsReceived, 1);
1155}
1156
1157void tst_Gestures::twoGesturesOnDifferentLevel()
1158{
1159 GestureWidget parent("parent");
1160 QVBoxLayout *l = new QVBoxLayout(&parent);
1161 GestureWidget *child = new GestureWidget("child");
1162 l->addWidget(child);
1163
1164 Qt::GestureType SecondGesture = QGestureRecognizer::registerRecognizer(recognizer: new CustomGestureRecognizer);
1165
1166 parent.grabGesture(type: CustomGesture::GestureType);
1167 child->grabGesture(type: SecondGesture);
1168
1169 CustomEvent event;
1170 // sending events that form a gesture to one widget, but they will be
1171 // filtered by two different gesture recognizers and will generate two
1172 // QGesture objects. Check that those gesture objects are delivered to
1173 // different widgets properly.
1174 sendCustomGesture(event: &event, object: child);
1175
1176 static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
1177 static const int TotalCustomEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialMaybeThreshold + 1;
1178
1179 QCOMPARE(child->customEventsReceived, TotalCustomEventsCount);
1180 QCOMPARE(child->gestureEventsReceived, TotalGestureEventsCount);
1181 QCOMPARE(child->gestureOverrideEventsReceived, 0);
1182 QCOMPARE(child->events.all.size(), TotalGestureEventsCount);
1183 for(int i = 0; i < child->events.all.size(); ++i)
1184 QCOMPARE(child->events.all.at(i), SecondGesture);
1185
1186 QCOMPARE(parent.gestureEventsReceived, TotalGestureEventsCount);
1187 QCOMPARE(parent.gestureOverrideEventsReceived, 0);
1188 QCOMPARE(parent.events.all.size(), TotalGestureEventsCount);
1189 for(int i = 0; i < child->events.all.size(); ++i)
1190 QCOMPARE(parent.events.all.at(i), CustomGesture::GestureType);
1191
1192 QGestureRecognizer::unregisterRecognizer(type: SecondGesture);
1193}
1194
1195void tst_Gestures::multipleGesturesInTree()
1196{
1197 GestureWidget a("A");
1198 GestureWidget *A = &a;
1199 GestureWidget *B = new GestureWidget("B", A);
1200 GestureWidget *C = new GestureWidget("C", B);
1201 GestureWidget *D = new GestureWidget("D", C);
1202
1203 Qt::GestureType FirstGesture = CustomGesture::GestureType;
1204 Qt::GestureType SecondGesture = QGestureRecognizer::registerRecognizer(recognizer: new CustomGestureRecognizer);
1205 Qt::GestureType ThirdGesture = QGestureRecognizer::registerRecognizer(recognizer: new CustomGestureRecognizer);
1206
1207 Qt::GestureFlags flags = Qt::ReceivePartialGestures;
1208 A->grabGesture(type: FirstGesture, flags); // A [1 3]
1209 A->grabGesture(type: ThirdGesture, flags); // |
1210 B->grabGesture(type: SecondGesture, flags); // B [ 2 3]
1211 B->grabGesture(type: ThirdGesture, flags); // |
1212 C->grabGesture(type: FirstGesture, flags); // C [1 2 3]
1213 C->grabGesture(type: SecondGesture, flags); // |
1214 C->grabGesture(type: ThirdGesture, flags); // D [1 3]
1215 D->grabGesture(type: FirstGesture, flags);
1216 D->grabGesture(type: ThirdGesture, flags);
1217
1218 // make sure all widgets ignore events, so they get propagated.
1219 A->ignoredGestures << FirstGesture << ThirdGesture;
1220 B->ignoredGestures << SecondGesture << ThirdGesture;
1221 C->ignoredGestures << FirstGesture << SecondGesture << ThirdGesture;
1222 D->ignoredGestures << FirstGesture << ThirdGesture;
1223
1224 CustomEvent event;
1225 sendCustomGesture(event: &event, object: D);
1226
1227 static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
1228
1229 // gesture override events
1230 QCOMPARE(D->overrideEvents.all.count(FirstGesture), 1);
1231 QCOMPARE(D->overrideEvents.all.count(SecondGesture), 0);
1232 QCOMPARE(D->overrideEvents.all.count(ThirdGesture), 1);
1233
1234 QCOMPARE(C->overrideEvents.all.count(FirstGesture), 1);
1235 QCOMPARE(C->overrideEvents.all.count(SecondGesture), 1);
1236 QCOMPARE(C->overrideEvents.all.count(ThirdGesture), 1);
1237
1238 QCOMPARE(B->overrideEvents.all.count(FirstGesture), 0);
1239 QCOMPARE(B->overrideEvents.all.count(SecondGesture), 1);
1240 QCOMPARE(B->overrideEvents.all.count(ThirdGesture), 1);
1241
1242 QCOMPARE(A->overrideEvents.all.count(FirstGesture), 1);
1243 QCOMPARE(A->overrideEvents.all.count(SecondGesture), 0);
1244 QCOMPARE(A->overrideEvents.all.count(ThirdGesture), 1);
1245
1246 // normal gesture events
1247 QCOMPARE(D->events.all.count(FirstGesture), TotalGestureEventsCount);
1248 QCOMPARE(D->events.all.count(SecondGesture), 0);
1249 QCOMPARE(D->events.all.count(ThirdGesture), TotalGestureEventsCount);
1250
1251 QCOMPARE(C->events.all.count(FirstGesture), TotalGestureEventsCount);
1252 QCOMPARE(C->events.all.count(SecondGesture), TotalGestureEventsCount);
1253 QCOMPARE(C->events.all.count(ThirdGesture), TotalGestureEventsCount);
1254
1255 QCOMPARE(B->events.all.count(FirstGesture), 0);
1256 QCOMPARE(B->events.all.count(SecondGesture), TotalGestureEventsCount);
1257 QCOMPARE(B->events.all.count(ThirdGesture), TotalGestureEventsCount);
1258
1259 QCOMPARE(A->events.all.count(FirstGesture), TotalGestureEventsCount);
1260 QCOMPARE(A->events.all.count(SecondGesture), 0);
1261 QCOMPARE(A->events.all.count(ThirdGesture), TotalGestureEventsCount);
1262
1263 QGestureRecognizer::unregisterRecognizer(type: SecondGesture);
1264 QGestureRecognizer::unregisterRecognizer(type: ThirdGesture);
1265}
1266
1267void tst_Gestures::multipleGesturesInComplexTree()
1268{
1269 GestureWidget a("A");
1270 GestureWidget *A = &a;
1271 GestureWidget *B = new GestureWidget("B", A);
1272 GestureWidget *C = new GestureWidget("C", B);
1273 GestureWidget *D = new GestureWidget("D", C);
1274
1275 Qt::GestureType FirstGesture = CustomGesture::GestureType;
1276 Qt::GestureType SecondGesture = QGestureRecognizer::registerRecognizer(recognizer: new CustomGestureRecognizer);
1277 Qt::GestureType ThirdGesture = QGestureRecognizer::registerRecognizer(recognizer: new CustomGestureRecognizer);
1278 Qt::GestureType FourthGesture = QGestureRecognizer::registerRecognizer(recognizer: new CustomGestureRecognizer);
1279 Qt::GestureType FifthGesture = QGestureRecognizer::registerRecognizer(recognizer: new CustomGestureRecognizer);
1280 Qt::GestureType SixthGesture = QGestureRecognizer::registerRecognizer(recognizer: new CustomGestureRecognizer);
1281 Qt::GestureType SeventhGesture = QGestureRecognizer::registerRecognizer(recognizer: new CustomGestureRecognizer);
1282
1283 Qt::GestureFlags flags = Qt::ReceivePartialGestures;
1284 A->grabGesture(type: FirstGesture, flags); // A [1,3,4]
1285 A->grabGesture(type: ThirdGesture, flags); // |
1286 A->grabGesture(type: FourthGesture, flags); // B [2,3,5]
1287 B->grabGesture(type: SecondGesture, flags); // |
1288 B->grabGesture(type: ThirdGesture, flags); // C [1,2,3,6]
1289 B->grabGesture(type: FifthGesture, flags); // |
1290 C->grabGesture(type: FirstGesture, flags); // D [1,3,7]
1291 C->grabGesture(type: SecondGesture, flags);
1292 C->grabGesture(type: ThirdGesture, flags);
1293 C->grabGesture(type: SixthGesture, flags);
1294 D->grabGesture(type: FirstGesture, flags);
1295 D->grabGesture(type: ThirdGesture, flags);
1296 D->grabGesture(type: SeventhGesture, flags);
1297
1298 // make sure all widgets ignore events, so they get propagated.
1299 QSet<Qt::GestureType> allGestureTypes;
1300 allGestureTypes << FirstGesture << SecondGesture << ThirdGesture
1301 << FourthGesture << FifthGesture << SixthGesture << SeventhGesture;
1302 A->ignoredGestures = B->ignoredGestures = allGestureTypes;
1303 C->ignoredGestures = D->ignoredGestures = allGestureTypes;
1304
1305 CustomEvent event;
1306 sendCustomGesture(event: &event, object: D);
1307
1308 static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
1309
1310 // gesture override events
1311 QCOMPARE(D->overrideEvents.all.count(FirstGesture), 1);
1312 QCOMPARE(D->overrideEvents.all.count(SecondGesture), 0);
1313 QCOMPARE(D->overrideEvents.all.count(ThirdGesture), 1);
1314
1315 QCOMPARE(C->overrideEvents.all.count(FirstGesture), 1);
1316 QCOMPARE(C->overrideEvents.all.count(SecondGesture), 1);
1317 QCOMPARE(C->overrideEvents.all.count(ThirdGesture), 1);
1318
1319 QCOMPARE(B->overrideEvents.all.count(FirstGesture), 0);
1320 QCOMPARE(B->overrideEvents.all.count(SecondGesture), 1);
1321 QCOMPARE(B->overrideEvents.all.count(ThirdGesture), 1);
1322
1323 QCOMPARE(A->overrideEvents.all.count(FirstGesture), 1);
1324 QCOMPARE(A->overrideEvents.all.count(SecondGesture), 0);
1325 QCOMPARE(A->overrideEvents.all.count(ThirdGesture), 1);
1326
1327 // normal gesture events
1328 QCOMPARE(D->events.all.count(FirstGesture), TotalGestureEventsCount);
1329 QCOMPARE(D->events.all.count(SecondGesture), 0);
1330 QCOMPARE(D->events.all.count(ThirdGesture), TotalGestureEventsCount);
1331 QCOMPARE(D->events.all.count(FourthGesture), 0);
1332 QCOMPARE(D->events.all.count(FifthGesture), 0);
1333 QCOMPARE(D->events.all.count(SixthGesture), 0);
1334 QCOMPARE(D->events.all.count(SeventhGesture), TotalGestureEventsCount);
1335
1336 QCOMPARE(C->events.all.count(FirstGesture), TotalGestureEventsCount);
1337 QCOMPARE(C->events.all.count(SecondGesture), TotalGestureEventsCount);
1338 QCOMPARE(C->events.all.count(ThirdGesture), TotalGestureEventsCount);
1339 QCOMPARE(C->events.all.count(FourthGesture), 0);
1340 QCOMPARE(C->events.all.count(FifthGesture), 0);
1341 QCOMPARE(C->events.all.count(SixthGesture), TotalGestureEventsCount);
1342 QCOMPARE(C->events.all.count(SeventhGesture), 0);
1343
1344 QCOMPARE(B->events.all.count(FirstGesture), 0);
1345 QCOMPARE(B->events.all.count(SecondGesture), TotalGestureEventsCount);
1346 QCOMPARE(B->events.all.count(ThirdGesture), TotalGestureEventsCount);
1347 QCOMPARE(B->events.all.count(FourthGesture), 0);
1348 QCOMPARE(B->events.all.count(FifthGesture), TotalGestureEventsCount);
1349 QCOMPARE(B->events.all.count(SixthGesture), 0);
1350 QCOMPARE(B->events.all.count(SeventhGesture), 0);
1351
1352 QCOMPARE(A->events.all.count(FirstGesture), TotalGestureEventsCount);
1353 QCOMPARE(A->events.all.count(SecondGesture), 0);
1354 QCOMPARE(A->events.all.count(ThirdGesture), TotalGestureEventsCount);
1355 QCOMPARE(A->events.all.count(FourthGesture), TotalGestureEventsCount);
1356 QCOMPARE(A->events.all.count(FifthGesture), 0);
1357 QCOMPARE(A->events.all.count(SixthGesture), 0);
1358 QCOMPARE(A->events.all.count(SeventhGesture), 0);
1359
1360 QGestureRecognizer::unregisterRecognizer(type: SecondGesture);
1361 QGestureRecognizer::unregisterRecognizer(type: ThirdGesture);
1362 QGestureRecognizer::unregisterRecognizer(type: FourthGesture);
1363 QGestureRecognizer::unregisterRecognizer(type: FifthGesture);
1364 QGestureRecognizer::unregisterRecognizer(type: SixthGesture);
1365 QGestureRecognizer::unregisterRecognizer(type: SeventhGesture);
1366}
1367
1368void tst_Gestures::testMapToScene()
1369{
1370 QGesture gesture;
1371 QList<QGesture*> list;
1372 list << &gesture;
1373 QGestureEvent event(list);
1374 QCOMPARE(event.mapToGraphicsScene(gesture.hotSpot()), QPointF()); // not set, can't do much
1375
1376 QGraphicsScene scene;
1377 QGraphicsView view(&scene);
1378 view.setWindowFlags(Qt::X11BypassWindowManagerHint);
1379
1380 GestureItem *item0 = new GestureItem;
1381 scene.addItem(item: item0);
1382 item0->setPos(ax: 14, ay: 16);
1383
1384 view.show(); // need to show to give it a global coordinate
1385 QVERIFY(QTest::qWaitForWindowExposed(&view));
1386 view.ensureVisible(rect: scene.sceneRect());
1387
1388 QPoint origin = view.mapToGlobal(QPoint());
1389 event.setWidget(view.viewport());
1390
1391 QCOMPARE(event.mapToGraphicsScene(origin + QPoint(100, 200)), view.mapToScene(QPoint(100, 200)));
1392}
1393
1394void tst_Gestures::ungrabGesture() // a method on QWidget
1395{
1396 class MockGestureWidget : public GestureWidget {
1397 public:
1398 MockGestureWidget(const char *name = 0, QWidget *parent = 0)
1399 : GestureWidget(name, parent) { }
1400
1401
1402 QSet<QGesture*> gestures;
1403 protected:
1404 bool event(QEvent *event) override
1405 {
1406 if (event->type() == QEvent::Gesture) {
1407 QGestureEvent *gestureEvent = static_cast<QGestureEvent*>(event);
1408 const auto eventGestures = gestureEvent->gestures();
1409 for (QGesture *g : eventGestures)
1410 gestures.insert(value: g);
1411 }
1412 return GestureWidget::event(event);
1413 }
1414 };
1415
1416 MockGestureWidget parent("A");
1417 MockGestureWidget *a = &parent;
1418 MockGestureWidget *b = new MockGestureWidget("B", a);
1419
1420 a->grabGesture(type: CustomGesture::GestureType, flags: Qt::DontStartGestureOnChildren);
1421 b->grabGesture(type: CustomGesture::GestureType);
1422 b->ignoredGestures << CustomGesture::GestureType;
1423
1424 CustomEvent event;
1425 // sending an event will cause the QGesture objects to be instantiated for the widgets
1426 sendCustomGesture(event: &event, object: b);
1427
1428 QCOMPARE(a->gestures.count(), 1);
1429 QPointer<QGesture> customGestureA;
1430 customGestureA = *(a->gestures.begin());
1431 QVERIFY(!customGestureA.isNull());
1432 QCOMPARE(customGestureA->gestureType(), CustomGesture::GestureType);
1433
1434 QCOMPARE(b->gestures.count(), 1);
1435 QPointer<QGesture> customGestureB;
1436 customGestureB = *(b->gestures.begin());
1437 QVERIFY(!customGestureB.isNull());
1438 QCOMPARE(customGestureA.data(), customGestureB.data());
1439 QCOMPARE(customGestureB->gestureType(), CustomGesture::GestureType);
1440
1441 a->gestures.clear();
1442 // sending an event will cause the QGesture objects to be instantiated for the widget
1443 sendCustomGesture(event: &event, object: a);
1444
1445 QCOMPARE(a->gestures.count(), 1);
1446 customGestureA = *(a->gestures.begin());
1447 QVERIFY(!customGestureA.isNull());
1448 QCOMPARE(customGestureA->gestureType(), CustomGesture::GestureType);
1449 QVERIFY(customGestureA.data() != customGestureB.data());
1450
1451 a->ungrabGesture(type: CustomGesture::GestureType);
1452 //We changed the deletion of Gestures to lazy during QT-4022, so we can't ensure the QGesture is deleted until now
1453 QVERIFY(!customGestureB.isNull());
1454
1455 a->gestures.clear();
1456 a->reset();
1457 // send again to 'b' and make sure a never gets it.
1458 sendCustomGesture(event: &event, object: b);
1459 //After all Gestures are processed in the QGestureManager, we can ensure the QGesture is now deleted
1460 QVERIFY(customGestureA.isNull());
1461 QCOMPARE(a->gestureEventsReceived, 0);
1462 QCOMPARE(a->gestureOverrideEventsReceived, 0);
1463}
1464
1465void tst_Gestures::unregisterRecognizer() // a method on QApplication
1466{
1467 /*
1468 The hardest usecase to get right is when we remove a recognizer while several
1469 of the gestures it created are in active state and we immediately add a new recognizer
1470 for the same type (thus replacing the old one).
1471 The expected result is that all old gestures continue till they are finished/cancelled
1472 and the new recognizer starts creating gestures immediately at registration.
1473
1474 This implies that deleting of the recognizer happens only when there are no more gestures
1475 that it created. (since gestures might have a pointer to the recognizer)
1476 */
1477
1478}
1479
1480void tst_Gestures::autoCancelGestures()
1481{
1482 class MockWidget : public GestureWidget {
1483 public:
1484 MockWidget(const char *name) : GestureWidget(name), badGestureEvents(0) { }
1485
1486 bool event(QEvent *event)
1487 {
1488 if (event->type() == QEvent::Gesture) {
1489 QGestureEvent *ge = static_cast<QGestureEvent*>(event);
1490 if (ge->gestures().count() != 1)
1491 ++badGestureEvents; // event should contain exactly one gesture
1492 ge->gestures().first()->setGestureCancelPolicy(QGesture::CancelAllInContext);
1493 }
1494 return GestureWidget::event(event);
1495 }
1496
1497 int badGestureEvents;
1498 };
1499
1500 const Qt::GestureType secondGesture = QGestureRecognizer::registerRecognizer(recognizer: new CustomGestureRecognizer);
1501
1502 MockWidget parent("parent"); // this one sets the cancel policy to CancelAllInContext
1503 parent.resize(w: 300, h: 100);
1504 parent.setWindowFlags(Qt::X11BypassWindowManagerHint);
1505 GestureWidget *child = new GestureWidget("child", &parent);
1506 child->setGeometry(ax: 10, ay: 10, aw: 100, ah: 80);
1507
1508 parent.grabGesture(type: CustomGesture::GestureType);
1509 child->grabGesture(type: secondGesture);
1510 parent.show();
1511 QVERIFY(QTest::qWaitForWindowExposed(&parent));
1512
1513 /*
1514 An event is sent to both the child and the parent, when the child gets it a gesture is triggered
1515 and send to the child.
1516 When the parent gets the event a new gesture is triggered and delivered to the parent. When the
1517 parent gets it he accepts it and that causes the cancel policy to activate.
1518 The cause of that is the gesture for the child is cancelled and send to the child as such.
1519 */
1520 CustomEvent event;
1521 event.serial = CustomGesture::SerialStartedThreshold;
1522 QApplication::sendEvent(receiver: child, event: &event);
1523 QCOMPARE(child->events.all.count(), 2);
1524 QCOMPARE(child->events.started.count(), 1);
1525 QCOMPARE(child->events.canceled.count(), 1);
1526 QCOMPARE(parent.events.all.count(), 1);
1527
1528 // clean up, make the parent gesture finish
1529 event.serial = CustomGesture::SerialFinishedThreshold;
1530 QApplication::sendEvent(receiver: child, event: &event);
1531 QCOMPARE(parent.events.all.count(), 2);
1532 QCOMPARE(parent.badGestureEvents, 0);
1533}
1534
1535void tst_Gestures::autoCancelGestures2()
1536{
1537 class MockItem : public GestureItem {
1538 public:
1539 MockItem(const char *name) : GestureItem(name), badGestureEvents(0) { }
1540
1541 bool event(QEvent *event) {
1542 if (event->type() == QEvent::Gesture) {
1543 QGestureEvent *ge = static_cast<QGestureEvent*>(event);
1544 if (ge->gestures().count() != 1)
1545 ++badGestureEvents; // event should contain exactly one gesture
1546 ge->gestures().first()->setGestureCancelPolicy(QGesture::CancelAllInContext);
1547 }
1548 return GestureItem::event(event);
1549 }
1550
1551 int badGestureEvents;
1552 };
1553
1554 const Qt::GestureType secondGesture = QGestureRecognizer ::registerRecognizer(recognizer: new CustomGestureRecognizer);
1555
1556 QGraphicsScene scene;
1557 QGraphicsView view(&scene);
1558 view.setWindowFlags(Qt::X11BypassWindowManagerHint);
1559
1560 MockItem *parent = new MockItem("parent");
1561 GestureItem *child = new GestureItem("child");
1562 child->setParentItem(parent);
1563 parent->setPos(ax: 0, ay: 0);
1564 child->setPos(ax: 10, ay: 10);
1565 scene.addItem(item: parent);
1566 parent->grabGesture(type: CustomGesture::GestureType);
1567 child->grabGesture(type: secondGesture);
1568
1569 view.show();
1570 QVERIFY(QTest::qWaitForWindowExposed(&view));
1571 view.ensureVisible(rect: scene.sceneRect());
1572
1573 CustomEvent event;
1574 event.serial = CustomGesture::SerialStartedThreshold;
1575 event.hasHotSpot = true;
1576 event.hotSpot = mapToGlobal(pt: QPointF(5, 5), item: child, view: &view);
1577 scene.sendEvent(item: child, event: &event);
1578 QCOMPARE(parent->events.all.count(), 1);
1579 QCOMPARE(child->events.started.count(), 1);
1580 QCOMPARE(child->events.canceled.count(), 1);
1581 QCOMPARE(child->events.all.count(), 2);
1582
1583 // clean up, make the parent gesture finish
1584 event.serial = CustomGesture::SerialFinishedThreshold;
1585 scene.sendEvent(item: child, event: &event);
1586 QCOMPARE(parent->events.all.count(), 2);
1587 QCOMPARE(parent->badGestureEvents, 0);
1588}
1589
1590void tst_Gestures::graphicsViewParentPropagation()
1591{
1592 QGraphicsScene scene;
1593 QGraphicsView view(&scene);
1594 view.setWindowFlags(Qt::X11BypassWindowManagerHint);
1595
1596 GestureItem *item0 = new GestureItem("item0");
1597 scene.addItem(item: item0);
1598 item0->setPos(ax: 0, ay: 0);
1599 item0->grabGesture(type: CustomGesture::GestureType);
1600 item0->setZValue(1);
1601
1602 GestureItem *item1 = new GestureItem("item1");
1603 scene.addItem(item: item1);
1604 item1->setPos(ax: 0, ay: 0);
1605 item1->setZValue(5);
1606
1607 GestureItem *item1_c1 = new GestureItem("item1_child1");
1608 item1_c1->setParentItem(item1);
1609 item1_c1->setPos(ax: 0, ay: 0);
1610
1611 GestureItem *item1_c1_c1 = new GestureItem("item1_child1_child1");
1612 item1_c1_c1->setParentItem(item1_c1);
1613 item1_c1_c1->setPos(ax: 0, ay: 0);
1614
1615 view.show();
1616 QVERIFY(QTest::qWaitForWindowExposed(&view));
1617 view.ensureVisible(rect: scene.sceneRect());
1618
1619 item0->grabGesture(type: CustomGesture::GestureType, flags: Qt::ReceivePartialGestures | Qt::IgnoredGesturesPropagateToParent);
1620 item1->grabGesture(type: CustomGesture::GestureType, flags: Qt::ReceivePartialGestures | Qt::IgnoredGesturesPropagateToParent);
1621 item1_c1->grabGesture(type: CustomGesture::GestureType, flags: Qt::IgnoredGesturesPropagateToParent);
1622 item1_c1_c1->grabGesture(type: CustomGesture::GestureType, flags: Qt::ReceivePartialGestures | Qt::IgnoredGesturesPropagateToParent);
1623
1624 item0->ignoredUpdatedGestures << CustomGesture::GestureType;
1625 item0->ignoredFinishedGestures << CustomGesture::GestureType;
1626 item1->ignoredUpdatedGestures << CustomGesture::GestureType;
1627 item1->ignoredFinishedGestures << CustomGesture::GestureType;
1628 item1_c1->ignoredUpdatedGestures << CustomGesture::GestureType;
1629 item1_c1->ignoredFinishedGestures << CustomGesture::GestureType;
1630 item1_c1_c1->ignoredUpdatedGestures << CustomGesture::GestureType;
1631 item1_c1_c1->ignoredFinishedGestures << CustomGesture::GestureType;
1632
1633 static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
1634
1635 CustomEvent event;
1636 event.hotSpot = mapToGlobal(pt: QPointF(10, 10), item: item1_c1, view: &view);
1637 event.hasHotSpot = true;
1638 sendCustomGesture(event: &event, object: item0, scene: &scene);
1639
1640 QCOMPARE(item1_c1_c1->gestureEventsReceived, TotalGestureEventsCount);
1641 QCOMPARE(item1_c1_c1->gestureOverrideEventsReceived, 1);
1642 QCOMPARE(item1_c1->gestureEventsReceived, TotalGestureEventsCount-1);
1643 QCOMPARE(item1_c1->gestureOverrideEventsReceived, 1);
1644 QCOMPARE(item1->gestureEventsReceived, TotalGestureEventsCount-1);
1645 QCOMPARE(item1->gestureOverrideEventsReceived, 1);
1646 QCOMPARE(item0->gestureEventsReceived, 0);
1647 QCOMPARE(item0->gestureOverrideEventsReceived, 1);
1648}
1649
1650void tst_Gestures::panelPropagation()
1651{
1652 QGraphicsScene scene;
1653 QGraphicsView view(&scene);
1654 view.setWindowFlags(Qt::X11BypassWindowManagerHint);
1655
1656 GestureItem *item0 = new GestureItem("item0");
1657 scene.addItem(item: item0);
1658 item0->setPos(ax: 0, ay: 0);
1659 item0->size = QRectF(0, 0, 200, 200);
1660 item0->grabGesture(type: CustomGesture::GestureType);
1661 item0->setZValue(1);
1662
1663 GestureItem *item1 = new GestureItem("item1");
1664 item1->grabGesture(type: CustomGesture::GestureType);
1665 scene.addItem(item: item1);
1666 item1->setPos(ax: 10, ay: 10);
1667 item1->size = QRectF(0, 0, 180, 180);
1668 item1->setZValue(2);
1669
1670 GestureItem *item1_child1 = new GestureItem("item1_child1[panel]");
1671 item1_child1->setFlags(QGraphicsItem::ItemIsPanel);
1672 item1_child1->setParentItem(item1);
1673 item1_child1->grabGesture(type: CustomGesture::GestureType);
1674 item1_child1->setPos(ax: 10, ay: 10);
1675 item1_child1->size = QRectF(0, 0, 160, 160);
1676 item1_child1->setZValue(5);
1677
1678 GestureItem *item1_child1_child1 = new GestureItem("item1_child1_child1");
1679 item1_child1_child1->setParentItem(item1_child1);
1680 item1_child1_child1->grabGesture(type: CustomGesture::GestureType);
1681 item1_child1_child1->setPos(ax: 10, ay: 10);
1682 item1_child1_child1->size = QRectF(0, 0, 140, 140);
1683 item1_child1_child1->setZValue(10);
1684
1685 view.show();
1686 QVERIFY(QTest::qWaitForWindowExposed(&view));
1687 view.ensureVisible(rect: scene.sceneRect());
1688
1689 static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
1690 static const int TotalCustomEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialMaybeThreshold + 1;
1691
1692 CustomEvent event;
1693 event.hotSpot = mapToGlobal(pt: QPointF(5, 5), item: item1_child1_child1, view: &view);
1694 event.hasHotSpot = true;
1695 sendCustomGesture(event: &event, object: item0, scene: &scene);
1696
1697 QCOMPARE(item0->customEventsReceived, TotalCustomEventsCount);
1698 QCOMPARE(item1_child1_child1->gestureEventsReceived, TotalGestureEventsCount);
1699 QCOMPARE(item1_child1_child1->gestureOverrideEventsReceived, 1);
1700 QCOMPARE(item1_child1->gestureOverrideEventsReceived, 1);
1701 QCOMPARE(item1->gestureEventsReceived, 0);
1702 QCOMPARE(item1->gestureOverrideEventsReceived, 0);
1703 QCOMPARE(item0->gestureEventsReceived, 0);
1704 QCOMPARE(item0->gestureOverrideEventsReceived, 0);
1705
1706 item0->reset(); item1->reset(); item1_child1->reset(); item1_child1_child1->reset();
1707
1708 event.hotSpot = mapToGlobal(pt: QPointF(5, 5), item: item1, view: &view);
1709 event.hasHotSpot = true;
1710 sendCustomGesture(event: &event, object: item1, scene: &scene);
1711
1712 QCOMPARE(item1_child1_child1->gestureEventsReceived, 0);
1713 QCOMPARE(item1_child1_child1->gestureOverrideEventsReceived, 0);
1714 QCOMPARE(item1_child1->gestureEventsReceived, 0);
1715 QCOMPARE(item1_child1->gestureOverrideEventsReceived, 0);
1716 QCOMPARE(item1->gestureEventsReceived, TotalGestureEventsCount);
1717 QCOMPARE(item1->gestureOverrideEventsReceived, 1);
1718 QCOMPARE(item0->gestureEventsReceived, 0);
1719 QCOMPARE(item0->gestureOverrideEventsReceived, 1);
1720
1721 item0->reset(); item1->reset(); item1_child1->reset(); item1_child1_child1->reset();
1722 // try with a modal panel
1723 item1_child1->setPanelModality(QGraphicsItem::PanelModal);
1724
1725 event.hotSpot = mapToGlobal(pt: QPointF(5, 5), item: item1, view: &view);
1726 event.hasHotSpot = true;
1727 sendCustomGesture(event: &event, object: item1, scene: &scene);
1728
1729 QCOMPARE(item1_child1_child1->gestureEventsReceived, 0);
1730 QCOMPARE(item1_child1_child1->gestureOverrideEventsReceived, 0);
1731 QCOMPARE(item1_child1->gestureEventsReceived, TotalGestureEventsCount);
1732 QCOMPARE(item1_child1->gestureOverrideEventsReceived, 0);
1733 QCOMPARE(item1->gestureEventsReceived, 0);
1734 QCOMPARE(item1->gestureOverrideEventsReceived, 0);
1735 QCOMPARE(item0->gestureEventsReceived, 0);
1736 QCOMPARE(item0->gestureOverrideEventsReceived, 0);
1737
1738 item0->reset(); item1->reset(); item1_child1->reset(); item1_child1_child1->reset();
1739 // try with a modal panel, however set the hotspot to be outside of the
1740 // panel and its parent
1741 item1_child1->setPanelModality(QGraphicsItem::PanelModal);
1742
1743 event.hotSpot = mapToGlobal(pt: QPointF(5, 5), item: item0, view: &view);
1744 event.hasHotSpot = true;
1745 sendCustomGesture(event: &event, object: item1, scene: &scene);
1746
1747 QCOMPARE(item1_child1_child1->gestureEventsReceived, 0);
1748 QCOMPARE(item1_child1_child1->gestureOverrideEventsReceived, 0);
1749 QCOMPARE(item1_child1->gestureEventsReceived, 0);
1750 QCOMPARE(item1_child1->gestureOverrideEventsReceived, 0);
1751 QCOMPARE(item1->gestureEventsReceived, 0);
1752 QCOMPARE(item1->gestureOverrideEventsReceived, 0);
1753 QCOMPARE(item0->gestureEventsReceived, TotalGestureEventsCount);
1754 QCOMPARE(item0->gestureOverrideEventsReceived, 0);
1755
1756 item0->reset(); item1->reset(); item1_child1->reset(); item1_child1_child1->reset();
1757 // try with a scene modal panel
1758 item1_child1->setPanelModality(QGraphicsItem::SceneModal);
1759
1760 event.hotSpot = mapToGlobal(pt: QPointF(5, 5), item: item0, view: &view);
1761 event.hasHotSpot = true;
1762 sendCustomGesture(event: &event, object: item0, scene: &scene);
1763
1764 QCOMPARE(item1_child1_child1->gestureEventsReceived, 0);
1765 QCOMPARE(item1_child1_child1->gestureOverrideEventsReceived, 0);
1766 QCOMPARE(item1_child1->gestureEventsReceived, TotalGestureEventsCount);
1767 QCOMPARE(item1_child1->gestureOverrideEventsReceived, 0);
1768 QCOMPARE(item1->gestureEventsReceived, 0);
1769 QCOMPARE(item1->gestureOverrideEventsReceived, 0);
1770 QCOMPARE(item0->gestureEventsReceived, 0);
1771 QCOMPARE(item0->gestureOverrideEventsReceived, 0);
1772}
1773
1774void tst_Gestures::panelStacksBehindParent()
1775{
1776 QGraphicsScene scene;
1777 QGraphicsView view(&scene);
1778 view.setWindowFlags(Qt::X11BypassWindowManagerHint);
1779
1780 GestureItem *item1 = new GestureItem("item1");
1781 item1->grabGesture(type: CustomGesture::GestureType);
1782 scene.addItem(item: item1);
1783 item1->setPos(ax: 10, ay: 10);
1784 item1->size = QRectF(0, 0, 180, 180);
1785 item1->setZValue(2);
1786
1787 GestureItem *panel = new GestureItem("panel");
1788 panel->setFlags(QGraphicsItem::ItemIsPanel | QGraphicsItem::ItemStacksBehindParent);
1789 panel->setPanelModality(QGraphicsItem::PanelModal);
1790 panel->setParentItem(item1);
1791 panel->grabGesture(type: CustomGesture::GestureType);
1792 panel->setPos(ax: -10, ay: -10);
1793 panel->size = QRectF(0, 0, 200, 200);
1794 panel->setZValue(5);
1795
1796 view.show();
1797 QVERIFY(QTest::qWaitForWindowExposed(&view));
1798 view.ensureVisible(rect: scene.sceneRect());
1799
1800 static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
1801
1802 CustomEvent event;
1803 event.hotSpot = mapToGlobal(pt: QPointF(5, 5), item: item1, view: &view);
1804 event.hasHotSpot = true;
1805 sendCustomGesture(event: &event, object: item1, scene: &scene);
1806
1807 QCOMPARE(item1->gestureEventsReceived, 0);
1808 QCOMPARE(item1->gestureOverrideEventsReceived, 0);
1809 QCOMPARE(panel->gestureEventsReceived, TotalGestureEventsCount);
1810 QCOMPARE(panel->gestureOverrideEventsReceived, 0);
1811}
1812
1813#ifdef Q_OS_MACOS
1814void tst_Gestures::deleteMacPanGestureRecognizerTargetWidget()
1815{
1816 QWidget window;
1817 window.resize(400,400);
1818 QGraphicsScene scene;
1819 QGraphicsView *view = new QGraphicsView(&scene, &window);
1820 view->resize(400, 400);
1821 window.show();
1822
1823 QVERIFY(QTest::qWaitForWindowExposed(&window));
1824 QTouchDevice *device = QTest::createTouchDevice();
1825 // QMacOSPenGestureRecognizer will start a timer on a touch press event
1826 QTest::touchEvent(&window, device).press(1, QPoint(100, 100), &window);
1827 delete view;
1828
1829 // wait until after that the QMacOSPenGestureRecognizer timer (300ms) is triggered.
1830 // This is needed so that the whole test does not finish before the timer triggers
1831 // and to make sure it crashes while executing *this* function. (otherwise it might give the
1832 // impression that some of the subsequent test function caused the crash...)
1833
1834 QTest::qWait(400); // DO NOT CRASH while waiting
1835}
1836#endif
1837
1838void tst_Gestures::deleteGestureTargetWidget()
1839{
1840}
1841
1842void tst_Gestures::deleteGestureTargetItem_data()
1843{
1844 QTest::addColumn<bool>(name: "propagateUpdateGesture");
1845 QTest::addColumn<QString>(name: "emitter");
1846 QTest::addColumn<QString>(name: "receiver");
1847 QTest::addColumn<QByteArray>(name: "signalName");
1848 QTest::addColumn<QByteArray>(name: "slotName");
1849
1850 QByteArray gestureUpdated = SIGNAL(gestureUpdated(QEvent::Type,QGesture*));
1851 QByteArray gestureFinished = SIGNAL(gestureFinished(QEvent::Type,QGesture*));
1852 QByteArray deleteThis = SLOT(deleteThis());
1853 QByteArray deleteLater = SLOT(deleteLater());
1854
1855 QTest::newRow(dataTag: "delete1")
1856 << false << "item1" << "item1" << gestureUpdated << deleteThis;
1857 QTest::newRow(dataTag: "delete2")
1858 << false << "item2" << "item2" << gestureUpdated << deleteThis;
1859 QTest::newRow(dataTag: "delete3")
1860 << false << "item1" << "item2" << gestureUpdated << deleteThis;
1861
1862 QTest::newRow(dataTag: "deleteLater1")
1863 << false << "item1" << "item1" << gestureUpdated << deleteLater;
1864 QTest::newRow(dataTag: "deleteLater2")
1865 << false << "item2" << "item2" << gestureUpdated << deleteLater;
1866 QTest::newRow(dataTag: "deleteLater3")
1867 << false << "item1" << "item2" << gestureUpdated << deleteLater;
1868 QTest::newRow(dataTag: "deleteLater4")
1869 << false << "item2" << "item1" << gestureUpdated << deleteLater;
1870
1871 QTest::newRow(dataTag: "delete-self-and-propagate")
1872 << true << "item2" << "item2" << gestureUpdated << deleteThis;
1873 QTest::newRow(dataTag: "deleteLater-self-and-propagate")
1874 << true << "item2" << "item2" << gestureUpdated << deleteLater;
1875 QTest::newRow(dataTag: "propagate-to-deletedLater")
1876 << true << "item2" << "item1" << gestureUpdated << deleteLater;
1877}
1878
1879void tst_Gestures::deleteGestureTargetItem()
1880{
1881 QFETCH(bool, propagateUpdateGesture);
1882 QFETCH(QString, emitter);
1883 QFETCH(QString, receiver);
1884 QFETCH(QByteArray, signalName);
1885 QFETCH(QByteArray, slotName);
1886
1887 QGraphicsScene scene;
1888 QGraphicsView view(&scene);
1889 view.setWindowFlags(Qt::X11BypassWindowManagerHint);
1890
1891 GestureItem *item1 = new GestureItem("item1");
1892 item1->grabGesture(type: CustomGesture::GestureType);
1893 item1->setZValue(2);
1894 scene.addItem(item: item1);
1895
1896 GestureItem *item2 = new GestureItem("item2");
1897 item2->grabGesture(type: CustomGesture::GestureType);
1898 item2->setZValue(5);
1899 scene.addItem(item: item2);
1900
1901 QMap<QString, GestureItem *> items;
1902 items.insert(key: item1->objectName(), value: item1);
1903 items.insert(key: item2->objectName(), value: item2);
1904
1905 view.show();
1906 QVERIFY(QTest::qWaitForWindowExposed(&view));
1907 view.ensureVisible(rect: scene.sceneRect());
1908
1909 if (propagateUpdateGesture)
1910 item2->ignoredUpdatedGestures << CustomGesture::GestureType;
1911 connect(sender: items.value(key: emitter, defaultValue: 0), signal: signalName, receiver: items.value(key: receiver, defaultValue: 0), member: slotName);
1912
1913 // some debug output to see the current test data tag, so if we crash
1914 // we know which one caused the crash.
1915 qDebug() << "<-- testing";
1916
1917 CustomEvent event;
1918 event.hotSpot = mapToGlobal(pt: QPointF(5, 5), item: item2, view: &view);
1919 event.hasHotSpot = true;
1920 sendCustomGesture(event: &event, object: item1, scene: &scene);
1921}
1922
1923class GraphicsView : public QGraphicsView
1924{
1925public:
1926 GraphicsView(QGraphicsScene *scene, QWidget *parent = 0)
1927 : QGraphicsView(scene, parent)
1928 {
1929 }
1930
1931 using QGraphicsView::setViewportMargins;
1932};
1933
1934// just making sure that even if the graphicsview has margins hotspot still
1935// works properly. It should use viewport for converting global coordinates to
1936// scene coordinates.
1937void tst_Gestures::viewportCoordinates()
1938{
1939 QGraphicsScene scene;
1940 GraphicsView view(&scene);
1941 view.setViewportMargins(left: 10,top: 20,right: 15,bottom: 25);
1942 view.setWindowFlags(Qt::X11BypassWindowManagerHint);
1943
1944 GestureItem *item1 = new GestureItem("item1");
1945 item1->grabGesture(type: CustomGesture::GestureType);
1946 item1->size = QRectF(0, 0, 3, 3);
1947 item1->setZValue(2);
1948 scene.addItem(item: item1);
1949
1950 view.show();
1951 QVERIFY(QTest::qWaitForWindowExposed(&view));
1952 view.ensureVisible(rect: scene.sceneRect());
1953
1954 CustomEvent event;
1955 event.hotSpot = mapToGlobal(pt: item1->boundingRect().center(), item: item1, view: &view);
1956 event.hasHotSpot = true;
1957 sendCustomGesture(event: &event, object: item1, scene: &scene);
1958 QVERIFY(item1->gestureEventsReceived != 0);
1959}
1960
1961void tst_Gestures::partialGesturePropagation()
1962{
1963 QGraphicsScene scene;
1964 QGraphicsView view(&scene);
1965 view.setWindowFlags(Qt::X11BypassWindowManagerHint);
1966
1967 GestureItem *item1 = new GestureItem("item1");
1968 item1->grabGesture(type: CustomGesture::GestureType);
1969 item1->setZValue(8);
1970 scene.addItem(item: item1);
1971
1972 GestureItem *item2 = new GestureItem("item2[partial]");
1973 item2->grabGesture(type: CustomGesture::GestureType, flags: Qt::ReceivePartialGestures);
1974 item2->setZValue(6);
1975 scene.addItem(item: item2);
1976
1977 GestureItem *item3 = new GestureItem("item3");
1978 item3->grabGesture(type: CustomGesture::GestureType);
1979 item3->setZValue(4);
1980 scene.addItem(item: item3);
1981
1982 GestureItem *item4 = new GestureItem("item4[partial]");
1983 item4->grabGesture(type: CustomGesture::GestureType, flags: Qt::ReceivePartialGestures);
1984 item4->setZValue(2);
1985 scene.addItem(item: item4);
1986
1987 view.show();
1988 QVERIFY(QTest::qWaitForWindowExposed(&view));
1989 view.ensureVisible(rect: scene.sceneRect());
1990
1991 item1->ignoredUpdatedGestures << CustomGesture::GestureType;
1992
1993 CustomEvent event;
1994 event.hotSpot = mapToGlobal(pt: QPointF(5, 5), item: item1, view: &view);
1995 event.hasHotSpot = true;
1996 sendCustomGesture(event: &event, object: item1, scene: &scene);
1997
1998 static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
1999
2000 QCOMPARE(item1->gestureOverrideEventsReceived, 1);
2001 QCOMPARE(item2->gestureOverrideEventsReceived, 1);
2002 QCOMPARE(item3->gestureOverrideEventsReceived, 1);
2003 QCOMPARE(item4->gestureOverrideEventsReceived, 1);
2004
2005 QCOMPARE(item1->gestureEventsReceived, TotalGestureEventsCount);
2006 QCOMPARE(item2->gestureEventsReceived, TotalGestureEventsCount-2); // except for started and finished
2007 QCOMPARE(item3->gestureEventsReceived, 0);
2008 QCOMPARE(item4->gestureEventsReceived, 0);
2009}
2010
2011class WinNativePan : public QPanGesture {
2012public:
2013 WinNativePan() {}
2014};
2015
2016class Pan : public QPanGesture {
2017public:
2018 Pan() {}
2019};
2020
2021class CustomPan : public QPanGesture {
2022public:
2023 CustomPan() {}
2024};
2025
2026// Recognizer for active gesture triggers on mouse press
2027class PanRecognizer : public QGestureRecognizer {
2028public:
2029 enum PanType { Platform, Default, Custom };
2030
2031 PanRecognizer(int id) : m_id(id) {}
2032 QGesture *create(QObject *) {
2033 switch(m_id) {
2034 case Platform: return new WinNativePan();
2035 case Default: return new Pan();
2036 default: return new CustomPan();
2037 }
2038 }
2039
2040 Result recognize(QGesture *, QObject *, QEvent *) { return QGestureRecognizer::Ignore; }
2041
2042 const int m_id;
2043};
2044
2045void tst_Gestures::testQGestureRecognizerCleanup()
2046{
2047 // Clean first the current recognizers in QGManager
2048 QGestureRecognizer::unregisterRecognizer(type: Qt::PanGesture);
2049
2050 // v-- Qt singleton QGManager initialization
2051
2052 // Mimic QGestureManager: register both default and "platform" recognizers
2053 // (this is done in windows when QT_NO_NATIVE_GESTURES is not defined)
2054 PanRecognizer *def = new PanRecognizer(PanRecognizer::Default);
2055 QGestureRecognizer::registerRecognizer(recognizer: def);
2056 PanRecognizer *plt = new PanRecognizer(PanRecognizer::Platform);
2057 QGestureRecognizer::registerRecognizer(recognizer: plt);
2058 qDebug () << "register: default =" << def << "; platform =" << plt;
2059
2060 // ^-- Qt singleton QGManager initialization
2061
2062 // Here, application code would start
2063
2064 // Create QGV (has a QAScrollArea, which uses Qt::PanGesture)
2065 QMainWindow *w = new QMainWindow;
2066 QGraphicsView *v = new QGraphicsView();
2067 w->setCentralWidget(v);
2068
2069 // Unregister Qt recognizers
2070 QGestureRecognizer::unregisterRecognizer(type: Qt::PanGesture);
2071
2072 // Register a custom Pan recognizer
2073 //QGestureRecognizer::registerRecognizer(new PanRecognizer(PanRecognizer::Custom));
2074
2075 w->show();
2076 QVERIFY(QTest::qWaitForWindowExposed(w));
2077 delete w;
2078}
2079
2080class ReuseCanceledGesturesRecognizer : public QGestureRecognizer
2081{
2082public:
2083 enum Type {
2084 RmbAndCancelAllType,
2085 LmbType
2086 };
2087
2088 ReuseCanceledGesturesRecognizer(Type type) : m_type(type) {}
2089
2090 QGesture *create(QObject *) {
2091 QGesture *g = new QGesture;
2092 return g;
2093 }
2094
2095 Result recognize(QGesture *gesture, QObject *, QEvent *event) {
2096 QMouseEvent *me = static_cast<QMouseEvent *>(event);
2097 Qt::MouseButton mouseButton(m_type == LmbType ? Qt::LeftButton : Qt::RightButton);
2098
2099 switch(event->type()) {
2100 case QEvent::MouseButtonPress:
2101 if (me->button() == mouseButton && gesture->state() == Qt::NoGesture) {
2102 gesture->setHotSpot(QPointF(me->globalPos()));
2103 if (m_type == RmbAndCancelAllType)
2104 gesture->setGestureCancelPolicy(QGesture::CancelAllInContext);
2105 return QGestureRecognizer::TriggerGesture;
2106 }
2107 break;
2108 case QEvent::MouseButtonRelease:
2109 if (me->button() == mouseButton && gesture->state() > Qt::NoGesture)
2110 return QGestureRecognizer::FinishGesture;
2111 default:
2112 break;
2113 }
2114 return QGestureRecognizer::Ignore;
2115 }
2116private:
2117 Type m_type;
2118};
2119
2120class ReuseCanceledGesturesWidget : public QGraphicsWidget
2121{
2122 public:
2123 ReuseCanceledGesturesWidget(Qt::GestureType gestureType = Qt::TapGesture, QGraphicsItem *parent = 0)
2124 : QGraphicsWidget(parent),
2125 m_gestureType(gestureType),
2126 m_started(0), m_updated(0), m_canceled(0), m_finished(0)
2127 {
2128 }
2129
2130 bool event(QEvent *event) {
2131 if (event->type() == QEvent::Gesture) {
2132 QGesture *gesture = static_cast<QGestureEvent*>(event)->gesture(type: m_gestureType);
2133 if (gesture) {
2134 switch(gesture->state()) {
2135 case Qt::GestureStarted: m_started++; break;
2136 case Qt::GestureUpdated: m_updated++; break;
2137 case Qt::GestureFinished: m_finished++; break;
2138 case Qt::GestureCanceled: m_canceled++; break;
2139 default: break;
2140 }
2141 }
2142 return true;
2143 }
2144 if (event->type() == QEvent::GraphicsSceneMousePress) {
2145 return true;
2146 }
2147 return QGraphicsWidget::event(event);
2148 }
2149
2150 int started() { return m_started; }
2151 int updated() { return m_updated; }
2152 int finished() { return m_finished; }
2153 int canceled() { return m_canceled; }
2154
2155 private:
2156 Qt::GestureType m_gestureType;
2157 int m_started;
2158 int m_updated;
2159 int m_canceled;
2160 int m_finished;
2161};
2162
2163void tst_Gestures::testReuseCanceledGestures()
2164{
2165 Qt::GestureType cancellingGestureTypeId = QGestureRecognizer::registerRecognizer(
2166 recognizer: new ReuseCanceledGesturesRecognizer(ReuseCanceledGesturesRecognizer::RmbAndCancelAllType));
2167 Qt::GestureType tapGestureTypeId = QGestureRecognizer::registerRecognizer(
2168 recognizer: new ReuseCanceledGesturesRecognizer(ReuseCanceledGesturesRecognizer::LmbType));
2169
2170 QMainWindow mw;
2171 mw.setWindowFlags(Qt::X11BypassWindowManagerHint);
2172 QGraphicsView *gv = new QGraphicsView(&mw);
2173 QGraphicsScene *scene = new QGraphicsScene;
2174
2175 gv->setScene(scene);
2176 scene->setSceneRect(x: 0,y: 0,w: 100,h: 100);
2177
2178 // Create container and add to the scene
2179 ReuseCanceledGesturesWidget *container = new ReuseCanceledGesturesWidget;
2180 container->grabGesture(type: cancellingGestureTypeId); // << container grabs canceling gesture
2181
2182 // Create widget and add to the scene
2183 ReuseCanceledGesturesWidget *target = new ReuseCanceledGesturesWidget(tapGestureTypeId, container);
2184 target->grabGesture(type: tapGestureTypeId);
2185
2186 container->setGeometry(scene->sceneRect());
2187
2188 scene->addItem(item: container);
2189
2190 mw.setCentralWidget(gv);
2191
2192 // Viewport needs to grab all gestures that widgets in scene grab
2193 gv->viewport()->grabGesture(type: cancellingGestureTypeId);
2194 gv->viewport()->grabGesture(type: tapGestureTypeId);
2195
2196 mw.show();
2197 QVERIFY(QTest::qWaitForWindowExposed(&mw));
2198
2199 QPoint targetPos(gv->mapFromScene(point: target->mapToScene(point: target->rect().center())));
2200 targetPos = gv->viewport()->mapFromParent(targetPos);
2201
2202 // "Tap" starts on child widget
2203 QTest::mousePress(widget: gv->viewport(), button: Qt::LeftButton, stateKey: { }, pos: targetPos);
2204 QCOMPARE(target->started(), 1);
2205 QCOMPARE(target->updated(), 0);
2206 QCOMPARE(target->finished(), 0);
2207 QCOMPARE(target->canceled(), 0);
2208
2209 // Canceling gesture starts on parent
2210 QTest::mousePress(widget: gv->viewport(), button: Qt::RightButton, stateKey: { }, pos: targetPos);
2211 QCOMPARE(target->started(), 1);
2212 QCOMPARE(target->updated(), 0);
2213 QCOMPARE(target->finished(), 0);
2214 QCOMPARE(target->canceled(), 1); // <- child canceled
2215
2216 // Canceling gesture ends
2217 QTest::mouseRelease(widget: gv->viewport(), button: Qt::RightButton, stateKey: { }, pos: targetPos);
2218 QCOMPARE(target->started(), 1);
2219 QCOMPARE(target->updated(), 0);
2220 QCOMPARE(target->finished(), 0);
2221 QCOMPARE(target->canceled(), 1);
2222
2223 // Tap would end if not canceled
2224 QTest::mouseRelease(widget: gv->viewport(), button: Qt::LeftButton, stateKey: { }, pos: targetPos);
2225 QCOMPARE(target->started(), 1);
2226 QCOMPARE(target->updated(), 0);
2227 QCOMPARE(target->finished(), 0);
2228 QCOMPARE(target->canceled(), 1);
2229
2230 // New "Tap" starts
2231 QTest::mousePress(widget: gv->viewport(), button: Qt::LeftButton, stateKey: { }, pos: targetPos);
2232 QCOMPARE(target->started(), 2);
2233 QCOMPARE(target->updated(), 0);
2234 QCOMPARE(target->finished(), 0);
2235 QCOMPARE(target->canceled(), 1);
2236
2237 QTest::mouseRelease(widget: gv->viewport(), button: Qt::LeftButton, stateKey: { }, pos: targetPos);
2238 QCOMPARE(target->started(), 2);
2239 QCOMPARE(target->updated(), 0);
2240 QCOMPARE(target->finished(), 1);
2241 QCOMPARE(target->canceled(), 1);
2242}
2243
2244void tst_Gestures::conflictingGesturesInGraphicsView()
2245{
2246 QGraphicsScene scene;
2247 GraphicsView view(&scene);
2248 view.setWindowFlags(Qt::X11BypassWindowManagerHint);
2249
2250 GestureItem *item1 = new GestureItem("item1");
2251 item1->grabGesture(type: CustomGesture::GestureType);
2252 item1->size = QRectF(0, 0, 100, 100);
2253 item1->setZValue(2);
2254 scene.addItem(item: item1);
2255
2256 GestureItem *item2 = new GestureItem("item2");
2257 item2->grabGesture(type: CustomGesture::GestureType);
2258 item2->size = QRectF(0, 0, 100, 100);
2259 item2->setZValue(5);
2260 scene.addItem(item: item2);
2261
2262 view.show();
2263 QVERIFY(QTest::qWaitForWindowExposed(&view));
2264 view.ensureVisible(rect: scene.sceneRect());
2265
2266 static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
2267
2268 CustomEvent event;
2269
2270 // nobody accepts override
2271 item1->acceptGestureOverride = false;
2272 item2->acceptGestureOverride = false;
2273 event.hotSpot = mapToGlobal(pt: item2->boundingRect().center(), item: item2, view: &view);
2274 event.hasHotSpot = true;
2275 sendCustomGesture(event: &event, object: item2, scene: &scene);
2276 QCOMPARE(item2->gestureOverrideEventsReceived, 1);
2277 QCOMPARE(item2->gestureEventsReceived, TotalGestureEventsCount);
2278 QCOMPARE(item1->gestureOverrideEventsReceived, 1);
2279 QCOMPARE(item1->gestureEventsReceived, 0);
2280
2281 item1->reset(); item2->reset();
2282
2283 // the original target accepts override
2284 item1->acceptGestureOverride = false;
2285 item2->acceptGestureOverride = true;
2286 event.hotSpot = mapToGlobal(pt: item2->boundingRect().center(), item: item2, view: &view);
2287 event.hasHotSpot = true;
2288 sendCustomGesture(event: &event, object: item2, scene: &scene);
2289 QCOMPARE(item2->gestureOverrideEventsReceived, 1);
2290 QCOMPARE(item2->gestureEventsReceived, TotalGestureEventsCount);
2291 QCOMPARE(item1->gestureOverrideEventsReceived, 0);
2292 QCOMPARE(item1->gestureEventsReceived, 0);
2293
2294 item1->reset(); item2->reset();
2295
2296 // the item behind accepts override
2297 item1->acceptGestureOverride = true;
2298 item2->acceptGestureOverride = false;
2299 event.hotSpot = mapToGlobal(pt: item2->boundingRect().center(), item: item2, view: &view);
2300 event.hasHotSpot = true;
2301 sendCustomGesture(event: &event, object: item2, scene: &scene);
2302
2303 QCOMPARE(item2->gestureOverrideEventsReceived, 1);
2304 QCOMPARE(item2->gestureEventsReceived, 0);
2305 QCOMPARE(item1->gestureOverrideEventsReceived, 1);
2306 QCOMPARE(item1->gestureEventsReceived, TotalGestureEventsCount);
2307}
2308
2309class NoConsumeWidgetBug13501 :public QWidget
2310{
2311 Q_OBJECT
2312protected:
2313 bool event(QEvent *e) {
2314 if(e->type() == QEvent::Gesture) {
2315 return false;
2316 }
2317 return QWidget::event(event: e);
2318 }
2319};
2320
2321void tst_Gestures::bug_13501_gesture_not_accepted()
2322{
2323 // Create a gesture event that is not accepted by any widget
2324 // make sure this does not lead to an assert in QGestureManager
2325 NoConsumeWidgetBug13501 w;
2326 w.grabGesture(type: Qt::TapGesture);
2327 w.show();
2328 QVERIFY(QTest::qWaitForWindowExposed(&w));
2329 //QTest::mousePress(&ignoreEvent, Qt::LeftButton);
2330 QTouchDevice *device = QTest::createTouchDevice();
2331 QTest::touchEvent(widget: &w, device).press(touchId: 0, pt: QPoint(10, 10), widget: &w);
2332}
2333
2334QTEST_MAIN(tst_Gestures)
2335#include "tst_gestures.moc"
2336

source code of qtbase/tests/auto/other/gestures/tst_gestures.cpp