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 | |
46 | static QPointF mapToGlobal(const QPointF &pt, QGraphicsItem *item, QGraphicsView *view) |
47 | { |
48 | return view->viewport()->mapToGlobal(view->mapFromScene(point: item->mapToScene(point: pt))); |
49 | } |
50 | |
51 | class CustomGesture : public QGesture |
52 | { |
53 | Q_OBJECT |
54 | public: |
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 | }; |
68 | Qt::GestureType CustomGesture::GestureType = Qt::CustomGesture; |
69 | const int CustomGesture::SerialMaybeThreshold = 1; |
70 | const int CustomGesture::SerialStartedThreshold = 3; |
71 | const int CustomGesture::SerialFinishedThreshold = 6; |
72 | |
73 | class CustomEvent : public QEvent |
74 | { |
75 | public: |
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 | }; |
88 | int CustomEvent::EventType = 0; |
89 | |
90 | class CustomGestureRecognizer : public QGestureRecognizer |
91 | { |
92 | public: |
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 | }; |
137 | bool CustomGestureRecognizer::ConsumeEvents = false; |
138 | |
139 | // same as CustomGestureRecognizer but triggers early without the maybe state |
140 | class CustomContinuousGestureRecognizer : public QGestureRecognizer |
141 | { |
142 | public: |
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 | |
182 | class GestureWidget : public QWidget |
183 | { |
184 | Q_OBJECT |
185 | public: |
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 | |
228 | protected: |
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 | |
278 | Q_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 | |
284 | public Q_SLOTS: |
285 | void deleteThis() { delete this; } |
286 | }; |
287 | |
288 | // TODO rename to sendGestureSequence |
289 | static 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 | |
302 | class tst_Gestures : public QObject |
303 | { |
304 | Q_OBJECT |
305 | |
306 | private 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 | |
347 | void 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 | |
354 | void tst_Gestures::cleanupTestCase() |
355 | { |
356 | QGestureRecognizer::unregisterRecognizer(type: CustomGesture::GestureType); |
357 | } |
358 | |
359 | void 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 | |
385 | void 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 | |
398 | void 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 | |
418 | void 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 | |
463 | void 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 | |
501 | void 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 | |
614 | void 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 | |
634 | void 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 | |
649 | static const QColor InstanceColors[] = { |
650 | Qt::blue, Qt::red, Qt::green, Qt::gray, Qt::yellow |
651 | }; |
652 | |
653 | class GestureItem : public QGraphicsObject |
654 | { |
655 | Q_OBJECT |
656 | static int InstanceCount; |
657 | public: |
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 | |
800 | Q_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 | |
806 | public: |
807 | // some arguments for the slots below: |
808 | QGraphicsScene *scene; |
809 | |
810 | public 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 | }; |
820 | int GestureItem::InstanceCount = 0; |
821 | |
822 | void 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 | |
884 | void 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 | |
949 | void 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 | |
1006 | void 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 | |
1059 | void 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 | |
1157 | void 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 | |
1195 | void 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 | |
1267 | void 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 | |
1368 | void 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 | |
1394 | void 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 | |
1465 | void 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 | |
1480 | void 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 | |
1535 | void 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 | |
1590 | void 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 | |
1650 | void 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 | |
1774 | void 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 |
1814 | void 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 | |
1838 | void tst_Gestures::deleteGestureTargetWidget() |
1839 | { |
1840 | } |
1841 | |
1842 | void 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 | |
1879 | void 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 | |
1923 | class GraphicsView : public QGraphicsView |
1924 | { |
1925 | public: |
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. |
1937 | void 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 | |
1961 | void 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 | |
2011 | class WinNativePan : public QPanGesture { |
2012 | public: |
2013 | WinNativePan() {} |
2014 | }; |
2015 | |
2016 | class Pan : public QPanGesture { |
2017 | public: |
2018 | Pan() {} |
2019 | }; |
2020 | |
2021 | class CustomPan : public QPanGesture { |
2022 | public: |
2023 | CustomPan() {} |
2024 | }; |
2025 | |
2026 | // Recognizer for active gesture triggers on mouse press |
2027 | class PanRecognizer : public QGestureRecognizer { |
2028 | public: |
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 | |
2045 | void 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 | |
2080 | class ReuseCanceledGesturesRecognizer : public QGestureRecognizer |
2081 | { |
2082 | public: |
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 | } |
2116 | private: |
2117 | Type m_type; |
2118 | }; |
2119 | |
2120 | class 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 | |
2163 | void 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 | |
2244 | void 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 | |
2309 | class NoConsumeWidgetBug13501 :public QWidget |
2310 | { |
2311 | Q_OBJECT |
2312 | protected: |
2313 | bool event(QEvent *e) { |
2314 | if(e->type() == QEvent::Gesture) { |
2315 | return false; |
2316 | } |
2317 | return QWidget::event(event: e); |
2318 | } |
2319 | }; |
2320 | |
2321 | void 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 | |
2334 | QTEST_MAIN(tst_Gestures) |
2335 | #include "tst_gestures.moc" |
2336 | |