summaryrefslogtreecommitdiff
path: root/tests/auto/other/gestures/tst_gestures.cpp
diff options
context:
space:
mode:
authorJo Asplin <jo.asplin@nokia.com>2011-11-25 09:30:03 +0100
committerQt by Nokia <qt-info@nokia.com>2011-11-30 09:30:22 +0100
commit9acec431c360379a21cdbe36d8e342083f344c3c (patch)
treedcd0e4d4d60f7f9cfb6f6d210b6ebaf016573d1b /tests/auto/other/gestures/tst_gestures.cpp
parent75b66dc8b036c4f4ef3ff8ea109efd698b72732d (diff)
downloadqtbase-9acec431c360379a21cdbe36d8e342083f344c3c.tar.gz
Moved integrationtests/* into other/
Currently there seems to be no precise definition of what an integrationtest is in the context of Qt testing. To avoid confusion, the tests under integrationtests/ are moved into other/ (which is effectively where we keep tests that don't clearly fit into any other category). Tests can be moved back into an integrationtests/ directory at a later point, should an unambiguous definition be established. Change-Id: I3bb289be2dc2aca11b51a8ce8fcc5942f06d6c5c Reviewed-by: Jason McDonald <jason.mcdonald@nokia.com>
Diffstat (limited to 'tests/auto/other/gestures/tst_gestures.cpp')
-rw-r--r--tests/auto/other/gestures/tst_gestures.cpp2345
1 files changed, 2345 insertions, 0 deletions
diff --git a/tests/auto/other/gestures/tst_gestures.cpp b/tests/auto/other/gestures/tst_gestures.cpp
new file mode 100644
index 0000000000..63345fbe88
--- /dev/null
+++ b/tests/auto/other/gestures/tst_gestures.cpp
@@ -0,0 +1,2345 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+#include <QtTest/qtesttouch.h>
+
+#include <qevent.h>
+#include <qwidget.h>
+#include <qlayout.h>
+#include <qgesture.h>
+#include <qgesturerecognizer.h>
+#include <qgraphicsitem.h>
+#include <qgraphicswidget.h>
+#include <qgraphicsview.h>
+#include <qmainwindow.h>
+
+#include <qdebug.h>
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+static QPointF mapToGlobal(const QPointF &pt, QGraphicsItem *item, QGraphicsView *view)
+{
+ return view->viewport()->mapToGlobal(view->mapFromScene(item->mapToScene(pt)));
+}
+
+class CustomGesture : public QGesture
+{
+ Q_OBJECT
+public:
+ static Qt::GestureType GestureType;
+
+ CustomGesture(QObject *parent = 0)
+ : QGesture(parent), serial(0)
+ {
+ }
+
+ int serial;
+
+ static const int SerialMaybeThreshold;
+ static const int SerialStartedThreshold;
+ static const int SerialFinishedThreshold;
+};
+Qt::GestureType CustomGesture::GestureType = Qt::CustomGesture;
+const int CustomGesture::SerialMaybeThreshold = 1;
+const int CustomGesture::SerialStartedThreshold = 3;
+const int CustomGesture::SerialFinishedThreshold = 6;
+
+class CustomEvent : public QEvent
+{
+public:
+ static int EventType;
+
+ CustomEvent(int serial_ = 0)
+ : QEvent(QEvent::Type(CustomEvent::EventType)),
+ serial(serial_), hasHotSpot(false)
+ {
+ }
+
+ int serial;
+ QPointF hotSpot;
+ bool hasHotSpot;
+};
+int CustomEvent::EventType = 0;
+
+class CustomGestureRecognizer : public QGestureRecognizer
+{
+public:
+ static bool ConsumeEvents;
+
+ CustomGestureRecognizer()
+ {
+ if (!CustomEvent::EventType)
+ CustomEvent::EventType = QEvent::registerEventType();
+ }
+
+ QGesture* create(QObject *)
+ {
+ return new CustomGesture;
+ }
+
+ QGestureRecognizer::Result recognize(QGesture *state, QObject*, QEvent *event)
+ {
+ if (event->type() == CustomEvent::EventType) {
+ QGestureRecognizer::Result result = 0;
+ if (CustomGestureRecognizer::ConsumeEvents)
+ result |= QGestureRecognizer::ConsumeEventHint;
+ CustomGesture *g = static_cast<CustomGesture*>(state);
+ CustomEvent *e = static_cast<CustomEvent*>(event);
+ g->serial = e->serial;
+ if (e->hasHotSpot)
+ g->setHotSpot(e->hotSpot);
+ if (g->serial >= CustomGesture::SerialFinishedThreshold)
+ result |= QGestureRecognizer::FinishGesture;
+ else if (g->serial >= CustomGesture::SerialStartedThreshold)
+ result |= QGestureRecognizer::TriggerGesture;
+ else if (g->serial >= CustomGesture::SerialMaybeThreshold)
+ result |= QGestureRecognizer::MayBeGesture;
+ else
+ result = QGestureRecognizer::CancelGesture;
+ return result;
+ }
+ return QGestureRecognizer::Ignore;
+ }
+
+ void reset(QGesture *state)
+ {
+ CustomGesture *g = static_cast<CustomGesture *>(state);
+ g->serial = 0;
+ QGestureRecognizer::reset(state);
+ }
+};
+bool CustomGestureRecognizer::ConsumeEvents = false;
+
+// same as CustomGestureRecognizer but triggers early without the maybe state
+class CustomContinuousGestureRecognizer : public QGestureRecognizer
+{
+public:
+ CustomContinuousGestureRecognizer()
+ {
+ if (!CustomEvent::EventType)
+ CustomEvent::EventType = QEvent::registerEventType();
+ }
+
+ QGesture* create(QObject *)
+ {
+ return new CustomGesture;
+ }
+
+ QGestureRecognizer::Result recognize(QGesture *state, QObject*, QEvent *event)
+ {
+ if (event->type() == CustomEvent::EventType) {
+ QGestureRecognizer::Result result = QGestureRecognizer::ConsumeEventHint;
+ CustomGesture *g = static_cast<CustomGesture *>(state);
+ CustomEvent *e = static_cast<CustomEvent *>(event);
+ g->serial = e->serial;
+ if (e->hasHotSpot)
+ g->setHotSpot(e->hotSpot);
+ if (g->serial >= CustomGesture::SerialFinishedThreshold)
+ result |= QGestureRecognizer::FinishGesture;
+ else if (g->serial >= CustomGesture::SerialMaybeThreshold)
+ result |= QGestureRecognizer::TriggerGesture;
+ else
+ result = QGestureRecognizer::CancelGesture;
+ return result;
+ }
+ return QGestureRecognizer::Ignore;
+ }
+
+ void reset(QGesture *state)
+ {
+ CustomGesture *g = static_cast<CustomGesture *>(state);
+ g->serial = 0;
+ QGestureRecognizer::reset(state);
+ }
+};
+
+class GestureWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ GestureWidget(const char *name = 0, QWidget *parent = 0)
+ : QWidget(parent)
+ {
+ if (name)
+ setObjectName(QLatin1String(name));
+ reset();
+ acceptGestureOverride = false;
+ }
+ void reset()
+ {
+ customEventsReceived = 0;
+ gestureEventsReceived = 0;
+ gestureOverrideEventsReceived = 0;
+ events.clear();
+ overrideEvents.clear();
+ ignoredGestures.clear();
+ }
+
+ int customEventsReceived;
+ int gestureEventsReceived;
+ int gestureOverrideEventsReceived;
+ struct Events
+ {
+ QList<Qt::GestureType> all;
+ QList<Qt::GestureType> started;
+ QList<Qt::GestureType> updated;
+ QList<Qt::GestureType> finished;
+ QList<Qt::GestureType> canceled;
+
+ void clear()
+ {
+ all.clear();
+ started.clear();
+ updated.clear();
+ finished.clear();
+ canceled.clear();
+ }
+ } events, overrideEvents;
+
+ bool acceptGestureOverride;
+ QSet<Qt::GestureType> ignoredGestures;
+
+protected:
+ bool event(QEvent *event)
+ {
+ Events *eventsPtr = 0;
+ if (event->type() == QEvent::Gesture) {
+ QGestureEvent *e = static_cast<QGestureEvent*>(event);
+ ++gestureEventsReceived;
+ eventsPtr = &events;
+ foreach(Qt::GestureType type, ignoredGestures)
+ e->ignore(e->gesture(type));
+ } else if (event->type() == QEvent::GestureOverride) {
+ ++gestureOverrideEventsReceived;
+ eventsPtr = &overrideEvents;
+ if (acceptGestureOverride)
+ event->accept();
+ }
+ if (eventsPtr) {
+ QGestureEvent *e = static_cast<QGestureEvent*>(event);
+ QList<QGesture*> gestures = e->gestures();
+ foreach(QGesture *g, gestures) {
+ eventsPtr->all << g->gestureType();
+ switch(g->state()) {
+ case Qt::GestureStarted:
+ emit gestureStarted(e->type(), g);
+ eventsPtr->started << g->gestureType();
+ break;
+ case Qt::GestureUpdated:
+ emit gestureUpdated(e->type(), g);
+ eventsPtr->updated << g->gestureType();
+ break;
+ case Qt::GestureFinished:
+ emit gestureFinished(e->type(), g);
+ eventsPtr->finished << g->gestureType();
+ break;
+ case Qt::GestureCanceled:
+ emit gestureCanceled(e->type(), g);
+ eventsPtr->canceled << g->gestureType();
+ break;
+ default:
+ qWarning() << "Unknown GestureState enum value:" << static_cast<int>(g->state());
+ }
+ }
+ } else if (event->type() == CustomEvent::EventType) {
+ ++customEventsReceived;
+ } else {
+ return QWidget::event(event);
+ }
+ return true;
+ }
+
+Q_SIGNALS:
+ void gestureStarted(QEvent::Type, QGesture *);
+ void gestureUpdated(QEvent::Type, QGesture *);
+ void gestureFinished(QEvent::Type, QGesture *);
+ void gestureCanceled(QEvent::Type, QGesture *);
+
+public Q_SLOTS:
+ void deleteThis() { delete this; }
+};
+
+// TODO rename to sendGestureSequence
+static void sendCustomGesture(CustomEvent *event, QObject *object, QGraphicsScene *scene = 0)
+{
+ QWeakPointer<QObject> receiver(object);
+ for (int i = CustomGesture::SerialMaybeThreshold;
+ i <= CustomGesture::SerialFinishedThreshold && receiver; ++i) {
+ event->serial = i;
+ if (scene)
+ scene->sendEvent(qobject_cast<QGraphicsObject *>(object), event);
+ else
+ QApplication::sendEvent(object, event);
+ }
+}
+
+class tst_Gestures : public QObject
+{
+Q_OBJECT
+
+public:
+ tst_Gestures();
+ virtual ~tst_Gestures();
+
+public slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void init();
+ void cleanup();
+
+private slots:
+ void customGesture();
+ void autoCancelingGestures();
+ void gestureOverChild();
+ void multipleWidgetOnlyGestureInTree();
+ void conflictingGestures();
+ void conflictingGesturesInGraphicsView();
+ void finishedWithoutStarted();
+ void unknownGesture();
+ void graphicsItemGesture();
+ void graphicsView();
+ void graphicsItemTreeGesture();
+ void explicitGraphicsObjectTarget();
+ void gestureOverChildGraphicsItem();
+ void twoGesturesOnDifferentLevel();
+ void multipleGesturesInTree();
+ void multipleGesturesInComplexTree();
+ void testMapToScene();
+ void ungrabGesture();
+ void consumeEventHint();
+ void unregisterRecognizer();
+ void autoCancelGestures();
+ void autoCancelGestures2();
+ void graphicsViewParentPropagation();
+ void panelPropagation();
+ void panelStacksBehindParent();
+ void deleteGestureTargetWidget();
+ void deleteGestureTargetItem_data();
+ void deleteGestureTargetItem();
+ void viewportCoordinates();
+ void partialGesturePropagation();
+ void testQGestureRecognizerCleanup();
+ void testReuseCanceledGestures();
+ void bug_13501_gesture_not_accepted();
+};
+
+tst_Gestures::tst_Gestures()
+{
+}
+
+tst_Gestures::~tst_Gestures()
+{
+}
+
+void tst_Gestures::initTestCase()
+{
+ CustomGesture::GestureType = QGestureRecognizer::registerRecognizer(new CustomGestureRecognizer);
+ QVERIFY(CustomGesture::GestureType != Qt::GestureType(0));
+ QVERIFY(CustomGesture::GestureType != Qt::CustomGesture);
+}
+
+void tst_Gestures::cleanupTestCase()
+{
+ QGestureRecognizer::unregisterRecognizer(CustomGesture::GestureType);
+}
+
+void tst_Gestures::init()
+{
+}
+
+void tst_Gestures::cleanup()
+{
+}
+
+void tst_Gestures::customGesture()
+{
+ GestureWidget widget;
+ widget.grabGesture(CustomGesture::GestureType, Qt::DontStartGestureOnChildren);
+ widget.show();
+ QTest::qWaitForWindowShown(&widget);
+
+ CustomEvent event;
+ event.hotSpot = widget.mapToGlobal(QPoint(5,5));
+ event.hasHotSpot = true;
+ sendCustomGesture(&event, &widget);
+
+ static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
+ static const int TotalCustomEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialMaybeThreshold + 1;
+ QCOMPARE(widget.customEventsReceived, TotalCustomEventsCount);
+ QCOMPARE(widget.gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(widget.gestureOverrideEventsReceived, 0);
+ QCOMPARE(widget.events.all.size(), TotalGestureEventsCount);
+ for(int i = 0; i < widget.events.all.size(); ++i)
+ QCOMPARE(widget.events.all.at(i), CustomGesture::GestureType);
+ QCOMPARE(widget.events.started.size(), 1);
+ QCOMPARE(widget.events.updated.size(), TotalGestureEventsCount - 2);
+ QCOMPARE(widget.events.finished.size(), 1);
+ QCOMPARE(widget.events.canceled.size(), 0);
+}
+
+void tst_Gestures::consumeEventHint()
+{
+ GestureWidget widget;
+ widget.grabGesture(CustomGesture::GestureType, Qt::DontStartGestureOnChildren);
+
+ CustomGestureRecognizer::ConsumeEvents = true;
+ CustomEvent event;
+ sendCustomGesture(&event, &widget);
+ CustomGestureRecognizer::ConsumeEvents = false;
+
+ QCOMPARE(widget.customEventsReceived, 0);
+}
+
+void tst_Gestures::autoCancelingGestures()
+{
+ GestureWidget widget;
+ widget.grabGesture(CustomGesture::GestureType, Qt::DontStartGestureOnChildren);
+ // send partial gesture. The gesture will be in the "maybe" state, but will
+ // never get enough events to fire, so Qt will have to kill it.
+ CustomEvent ev;
+ for (int i = CustomGesture::SerialMaybeThreshold;
+ i < CustomGesture::SerialStartedThreshold; ++i) {
+ ev.serial = i;
+ QApplication::sendEvent(&widget, &ev);
+ }
+ // wait long enough so the gesture manager will cancel the gesture
+ QTest::qWait(5000);
+ QCOMPARE(widget.customEventsReceived, CustomGesture::SerialStartedThreshold - CustomGesture::SerialMaybeThreshold);
+ QCOMPARE(widget.gestureEventsReceived, 0);
+ QCOMPARE(widget.gestureOverrideEventsReceived, 0);
+ QCOMPARE(widget.events.all.size(), 0);
+}
+
+void tst_Gestures::gestureOverChild()
+{
+ GestureWidget widget("widget");
+ QVBoxLayout *l = new QVBoxLayout(&widget);
+ GestureWidget *child = new GestureWidget("child");
+ l->addWidget(child);
+
+ widget.grabGesture(CustomGesture::GestureType, Qt::DontStartGestureOnChildren);
+
+ CustomEvent event;
+ sendCustomGesture(&event, child);
+
+ static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
+ static const int TotalCustomEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialMaybeThreshold + 1;
+
+ QCOMPARE(child->customEventsReceived, TotalCustomEventsCount);
+ QCOMPARE(widget.customEventsReceived, 0);
+ QCOMPARE(child->gestureEventsReceived, 0);
+ QCOMPARE(child->gestureOverrideEventsReceived, 0);
+ QCOMPARE(widget.gestureEventsReceived, 0);
+ QCOMPARE(widget.gestureOverrideEventsReceived, 0);
+
+ // enable gestures over the children
+ widget.grabGesture(CustomGesture::GestureType);
+
+ widget.reset();
+ child->reset();
+
+ sendCustomGesture(&event, child);
+
+ QCOMPARE(child->customEventsReceived, TotalCustomEventsCount);
+ QCOMPARE(widget.customEventsReceived, 0);
+
+ QCOMPARE(child->gestureEventsReceived, 0);
+ QCOMPARE(child->gestureOverrideEventsReceived, 0);
+ QCOMPARE(widget.gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(widget.gestureOverrideEventsReceived, 0);
+ for(int i = 0; i < widget.events.all.size(); ++i)
+ QCOMPARE(widget.events.all.at(i), CustomGesture::GestureType);
+ QCOMPARE(widget.events.started.size(), 1);
+ QCOMPARE(widget.events.updated.size(), TotalGestureEventsCount - 2);
+ QCOMPARE(widget.events.finished.size(), 1);
+ QCOMPARE(widget.events.canceled.size(), 0);
+}
+
+void tst_Gestures::multipleWidgetOnlyGestureInTree()
+{
+ GestureWidget parent("parent");
+ QVBoxLayout *l = new QVBoxLayout(&parent);
+ GestureWidget *child = new GestureWidget("child");
+ l->addWidget(child);
+
+ parent.grabGesture(CustomGesture::GestureType, Qt::DontStartGestureOnChildren);
+ child->grabGesture(CustomGesture::GestureType, Qt::DontStartGestureOnChildren);
+
+ static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
+ static const int TotalCustomEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialMaybeThreshold + 1;
+
+ // sending events to the child and making sure there is no conflict
+ CustomEvent event;
+ sendCustomGesture(&event, child);
+
+ QCOMPARE(child->customEventsReceived, TotalCustomEventsCount);
+ QCOMPARE(parent.customEventsReceived, 0);
+ QCOMPARE(child->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(child->gestureOverrideEventsReceived, 0);
+ QCOMPARE(parent.gestureEventsReceived, 0);
+ QCOMPARE(parent.gestureOverrideEventsReceived, 0);
+
+ parent.reset();
+ child->reset();
+
+ // same for the parent widget
+ sendCustomGesture(&event, &parent);
+
+ QCOMPARE(child->customEventsReceived, 0);
+ QCOMPARE(parent.customEventsReceived, TotalCustomEventsCount);
+ QCOMPARE(child->gestureEventsReceived, 0);
+ QCOMPARE(child->gestureOverrideEventsReceived, 0);
+ QCOMPARE(parent.gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(parent.gestureOverrideEventsReceived, 0);
+}
+
+void tst_Gestures::conflictingGestures()
+{
+ GestureWidget parent("parent");
+ QVBoxLayout *l = new QVBoxLayout(&parent);
+ GestureWidget *child = new GestureWidget("child");
+ l->addWidget(child);
+
+ parent.grabGesture(CustomGesture::GestureType);
+ child->grabGesture(CustomGesture::GestureType);
+
+ static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
+
+ // child accepts the override, parent will not receive anything
+ parent.acceptGestureOverride = false;
+ child->acceptGestureOverride = true;
+
+ // sending events to the child and making sure there is no conflict
+ CustomEvent event;
+ sendCustomGesture(&event, child);
+
+ QCOMPARE(child->gestureOverrideEventsReceived, 1);
+ QCOMPARE(child->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(parent.gestureOverrideEventsReceived, 0);
+ QCOMPARE(parent.gestureEventsReceived, 0);
+
+ parent.reset();
+ child->reset();
+
+ // parent accepts the override
+ parent.acceptGestureOverride = true;
+ child->acceptGestureOverride = false;
+
+ // sending events to the child and making sure there is no conflict
+ sendCustomGesture(&event, child);
+
+ QCOMPARE(child->gestureOverrideEventsReceived, 1);
+ QCOMPARE(child->gestureEventsReceived, 0);
+ QCOMPARE(parent.gestureOverrideEventsReceived, 1);
+ QCOMPARE(parent.gestureEventsReceived, TotalGestureEventsCount);
+
+ parent.reset();
+ child->reset();
+
+ // nobody accepts the override, we will send normal events to the closest
+ // context (i.e. to the child widget) and it will be propagated and
+ // accepted by the parent widget
+ parent.acceptGestureOverride = false;
+ child->acceptGestureOverride = false;
+ child->ignoredGestures << CustomGesture::GestureType;
+
+ // sending events to the child and making sure there is no conflict
+ sendCustomGesture(&event, child);
+
+ QCOMPARE(child->gestureOverrideEventsReceived, 1);
+ QCOMPARE(child->gestureEventsReceived, 1);
+ QCOMPARE(parent.gestureOverrideEventsReceived, 1);
+ QCOMPARE(parent.gestureEventsReceived, TotalGestureEventsCount);
+
+ parent.reset();
+ child->reset();
+
+ // nobody accepts the override, and nobody accepts the gesture event
+ parent.acceptGestureOverride = false;
+ child->acceptGestureOverride = false;
+ parent.ignoredGestures << CustomGesture::GestureType;
+ child->ignoredGestures << CustomGesture::GestureType;
+
+ // sending events to the child and making sure there is no conflict
+ sendCustomGesture(&event, child);
+
+ QCOMPARE(child->gestureOverrideEventsReceived, 1);
+ QCOMPARE(child->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(parent.gestureOverrideEventsReceived, 1);
+ QCOMPARE(parent.gestureEventsReceived, 1);
+
+ parent.reset();
+ child->reset();
+
+ // we set an attribute to make sure all gesture events are propagated
+ parent.grabGesture(CustomGesture::GestureType, Qt::ReceivePartialGestures);
+ parent.acceptGestureOverride = false;
+ child->acceptGestureOverride = false;
+ parent.ignoredGestures << CustomGesture::GestureType;
+ child->ignoredGestures << CustomGesture::GestureType;
+
+ // sending events to the child and making sure there is no conflict
+ sendCustomGesture(&event, child);
+
+ QCOMPARE(child->gestureOverrideEventsReceived, 1);
+ QCOMPARE(child->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(parent.gestureOverrideEventsReceived, 1);
+ QCOMPARE(parent.gestureEventsReceived, TotalGestureEventsCount);
+
+ parent.reset();
+ child->reset();
+
+ Qt::GestureType ContinuousGesture = QGestureRecognizer::registerRecognizer(new CustomContinuousGestureRecognizer);
+ static const int ContinuousGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialMaybeThreshold + 1;
+ child->grabGesture(ContinuousGesture);
+ // child accepts override. And it also receives another custom gesture.
+ parent.acceptGestureOverride = false;
+ child->acceptGestureOverride = true;
+ sendCustomGesture(&event, child);
+
+ QCOMPARE(child->gestureOverrideEventsReceived, 1);
+ QVERIFY(child->gestureEventsReceived > TotalGestureEventsCount);
+ QCOMPARE(child->events.all.count(), TotalGestureEventsCount + ContinuousGestureEventsCount);
+ QCOMPARE(parent.gestureOverrideEventsReceived, 0);
+ QCOMPARE(parent.gestureEventsReceived, 0);
+
+ QGestureRecognizer::unregisterRecognizer(ContinuousGesture);
+}
+
+void tst_Gestures::finishedWithoutStarted()
+{
+ GestureWidget widget;
+ widget.grabGesture(CustomGesture::GestureType, Qt::DontStartGestureOnChildren);
+
+ // the gesture will claim it finished, but it was never started.
+ CustomEvent ev;
+ ev.serial = CustomGesture::SerialFinishedThreshold;
+ QApplication::sendEvent(&widget, &ev);
+
+ QCOMPARE(widget.customEventsReceived, 1);
+ QCOMPARE(widget.gestureEventsReceived, 2);
+ QCOMPARE(widget.gestureOverrideEventsReceived, 0);
+ QCOMPARE(widget.events.all.size(), 2);
+ QCOMPARE(widget.events.started.size(), 1);
+ QCOMPARE(widget.events.updated.size(), 0);
+ QCOMPARE(widget.events.finished.size(), 1);
+ QCOMPARE(widget.events.canceled.size(), 0);
+}
+
+void tst_Gestures::unknownGesture()
+{
+ GestureWidget widget;
+ widget.grabGesture(CustomGesture::GestureType, Qt::DontStartGestureOnChildren);
+ widget.grabGesture(Qt::CustomGesture, Qt::DontStartGestureOnChildren);
+ widget.grabGesture(Qt::GestureType(Qt::PanGesture+512), Qt::DontStartGestureOnChildren);
+
+ CustomEvent event;
+ sendCustomGesture(&event, &widget);
+
+ static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
+
+ QCOMPARE(widget.gestureEventsReceived, TotalGestureEventsCount);
+}
+
+static const QColor InstanceColors[] = {
+ Qt::blue, Qt::red, Qt::green, Qt::gray, Qt::yellow
+};
+
+class GestureItem : public QGraphicsObject
+{
+ Q_OBJECT
+ static int InstanceCount;
+public:
+ GestureItem(const char *name = 0)
+ {
+ instanceNumber = InstanceCount++;
+ if (name) {
+ setObjectName(QLatin1String(name));
+ setToolTip(name);
+ }
+ size = QRectF(0, 0, 100, 100);
+ customEventsReceived = 0;
+ gestureEventsReceived = 0;
+ gestureOverrideEventsReceived = 0;
+ events.clear();
+ overrideEvents.clear();
+ acceptGestureOverride = false;
+
+ scene = 0;
+ }
+ ~GestureItem()
+ {
+ --InstanceCount;
+ }
+
+ int customEventsReceived;
+ int gestureEventsReceived;
+ int gestureOverrideEventsReceived;
+ struct Events
+ {
+ QList<Qt::GestureType> all;
+ QList<Qt::GestureType> started;
+ QList<Qt::GestureType> updated;
+ QList<Qt::GestureType> finished;
+ QList<Qt::GestureType> canceled;
+
+ void clear()
+ {
+ all.clear();
+ started.clear();
+ updated.clear();
+ finished.clear();
+ canceled.clear();
+ }
+ } events, overrideEvents;
+
+ bool acceptGestureOverride;
+ QSet<Qt::GestureType> ignoredGestures;
+ QSet<Qt::GestureType> ignoredStartedGestures;
+ QSet<Qt::GestureType> ignoredUpdatedGestures;
+ QSet<Qt::GestureType> ignoredFinishedGestures;
+
+ QRectF size;
+ int instanceNumber;
+
+ void reset()
+ {
+ customEventsReceived = 0;
+ gestureEventsReceived = 0;
+ gestureOverrideEventsReceived = 0;
+ events.clear();
+ overrideEvents.clear();
+ ignoredGestures.clear();
+ ignoredStartedGestures.clear();
+ ignoredUpdatedGestures.clear();
+ ignoredFinishedGestures.clear();
+ }
+
+ QRectF boundingRect() const
+ {
+ return size;
+ }
+ void paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *)
+ {
+ QColor color = InstanceColors[instanceNumber % (sizeof(InstanceColors)/sizeof(InstanceColors[0]))];
+ p->fillRect(boundingRect(), color);
+ }
+
+ bool event(QEvent *event)
+ {
+ Events *eventsPtr = 0;
+ if (event->type() == QEvent::Gesture) {
+ ++gestureEventsReceived;
+ eventsPtr = &events;
+ QGestureEvent *e = static_cast<QGestureEvent *>(event);
+ foreach(Qt::GestureType type, ignoredGestures)
+ e->ignore(e->gesture(type));
+ foreach(QGesture *g, e->gestures()) {
+ switch (g->state()) {
+ case Qt::GestureStarted:
+ if (ignoredStartedGestures.contains(g->gestureType()))
+ e->ignore(g);
+ break;
+ case Qt::GestureUpdated:
+ if (ignoredUpdatedGestures.contains(g->gestureType()))
+ e->ignore(g);
+ break;
+ case Qt::GestureFinished:
+ if (ignoredFinishedGestures.contains(g->gestureType()))
+ e->ignore(g);
+ break;
+ default:
+ break;
+ }
+ }
+ } else if (event->type() == QEvent::GestureOverride) {
+ ++gestureOverrideEventsReceived;
+ eventsPtr = &overrideEvents;
+ if (acceptGestureOverride)
+ event->accept();
+ }
+ if (eventsPtr) {
+ QGestureEvent *e = static_cast<QGestureEvent*>(event);
+ QList<QGesture*> gestures = e->gestures();
+ foreach(QGesture *g, gestures) {
+ eventsPtr->all << g->gestureType();
+ switch(g->state()) {
+ case Qt::GestureStarted:
+ eventsPtr->started << g->gestureType();
+ emit gestureStarted(e->type(), g);
+ break;
+ case Qt::GestureUpdated:
+ eventsPtr->updated << g->gestureType();
+ emit gestureUpdated(e->type(), g);
+ break;
+ case Qt::GestureFinished:
+ eventsPtr->finished << g->gestureType();
+ emit gestureFinished(e->type(), g);
+ break;
+ case Qt::GestureCanceled:
+ eventsPtr->canceled << g->gestureType();
+ emit gestureCanceled(e->type(), g);
+ break;
+ default:
+ qWarning() << "Unknown GestureState enum value:" << static_cast<int>(g->state());
+ }
+ }
+ } else if (event->type() == CustomEvent::EventType) {
+ ++customEventsReceived;
+ } else {
+ return QGraphicsObject::event(event);
+ }
+ return true;
+ }
+
+Q_SIGNALS:
+ void gestureStarted(QEvent::Type, QGesture *);
+ void gestureUpdated(QEvent::Type, QGesture *);
+ void gestureFinished(QEvent::Type, QGesture *);
+ void gestureCanceled(QEvent::Type, QGesture *);
+
+public:
+ // some arguments for the slots below:
+ QGraphicsScene *scene;
+
+public Q_SLOTS:
+ void deleteThis() { delete this; }
+ void addSelfToScene(QEvent::Type eventType, QGesture *)
+ {
+ if (eventType == QEvent::Gesture) {
+ disconnect(sender(), 0, this, SLOT(addSelfToScene(QEvent::Type,QGesture*)));
+ scene->addItem(this);
+ }
+ }
+};
+int GestureItem::InstanceCount = 0;
+
+void tst_Gestures::graphicsItemGesture()
+{
+ QGraphicsScene scene;
+ QGraphicsView view(&scene);
+ view.setWindowFlags(Qt::X11BypassWindowManagerHint);
+
+ GestureItem *item = new GestureItem("item");
+ scene.addItem(item);
+ item->setPos(100, 100);
+
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ view.ensureVisible(scene.sceneRect());
+
+ item->grabGesture(CustomGesture::GestureType);
+
+ static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
+ static const int TotalCustomEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialMaybeThreshold + 1;
+
+ CustomEvent event;
+ // gesture without hotspot should not be delivered to items in the view
+ QTest::ignoreMessage(QtWarningMsg, "QGestureManager::deliverEvent: could not find the target for gesture");
+ QTest::ignoreMessage(QtWarningMsg, "QGestureManager::deliverEvent: could not find the target for gesture");
+ QTest::ignoreMessage(QtWarningMsg, "QGestureManager::deliverEvent: could not find the target for gesture");
+ QTest::ignoreMessage(QtWarningMsg, "QGestureManager::deliverEvent: could not find the target for gesture");
+ sendCustomGesture(&event, item, &scene);
+
+ QCOMPARE(item->customEventsReceived, TotalCustomEventsCount);
+ QCOMPARE(item->gestureEventsReceived, 0);
+ QCOMPARE(item->gestureOverrideEventsReceived, 0);
+
+ item->reset();
+
+ // make sure the event is properly delivered if only the hotspot is set.
+ event.hotSpot = mapToGlobal(QPointF(10, 10), item, &view);
+ event.hasHotSpot = true;
+ sendCustomGesture(&event, item, &scene);
+
+ QCOMPARE(item->customEventsReceived, TotalCustomEventsCount);
+ QCOMPARE(item->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(item->gestureOverrideEventsReceived, 0);
+ QCOMPARE(item->events.all.size(), TotalGestureEventsCount);
+ for(int i = 0; i < item->events.all.size(); ++i)
+ QCOMPARE(item->events.all.at(i), CustomGesture::GestureType);
+ QCOMPARE(item->events.started.size(), 1);
+ QCOMPARE(item->events.updated.size(), TotalGestureEventsCount - 2);
+ QCOMPARE(item->events.finished.size(), 1);
+ QCOMPARE(item->events.canceled.size(), 0);
+
+ item->reset();
+
+ // send gesture to the item which ignores it.
+ item->ignoredGestures << CustomGesture::GestureType;
+
+ event.hotSpot = mapToGlobal(QPointF(10, 10), item, &view);
+ event.hasHotSpot = true;
+ sendCustomGesture(&event, item, &scene);
+ QCOMPARE(item->customEventsReceived, TotalCustomEventsCount);
+ QCOMPARE(item->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(item->gestureOverrideEventsReceived, 0);
+}
+
+void tst_Gestures::graphicsView()
+{
+ QGraphicsScene scene;
+ QGraphicsView view(&scene);
+ view.setWindowFlags(Qt::X11BypassWindowManagerHint);
+
+ GestureItem *item = new GestureItem("item");
+ scene.addItem(item);
+ item->setPos(100, 100);
+
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ view.ensureVisible(scene.sceneRect());
+
+ item->grabGesture(CustomGesture::GestureType);
+
+ static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
+ static const int TotalCustomEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialMaybeThreshold + 1;
+
+ CustomEvent event;
+ // make sure the event is properly delivered if only the hotspot is set.
+ event.hotSpot = mapToGlobal(QPointF(10, 10), item, &view);
+ event.hasHotSpot = true;
+ sendCustomGesture(&event, item, &scene);
+
+ QCOMPARE(item->customEventsReceived, TotalCustomEventsCount);
+ QCOMPARE(item->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(item->gestureOverrideEventsReceived, 0);
+
+ // change the viewport and try again
+ QWidget *newViewport = new QWidget;
+ view.setViewport(newViewport);
+
+ item->reset();
+ sendCustomGesture(&event, item, &scene);
+
+ QCOMPARE(item->customEventsReceived, TotalCustomEventsCount);
+ QCOMPARE(item->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(item->gestureOverrideEventsReceived, 0);
+
+ // change the scene and try again
+ QGraphicsScene newScene;
+ item = new GestureItem("newItem");
+ newScene.addItem(item);
+ item->setPos(100, 100);
+ view.setScene(&newScene);
+
+ item->reset();
+ // first without a gesture
+ sendCustomGesture(&event, item, &newScene);
+
+ QCOMPARE(item->customEventsReceived, TotalCustomEventsCount);
+ QCOMPARE(item->gestureEventsReceived, 0);
+ QCOMPARE(item->gestureOverrideEventsReceived, 0);
+
+ // then grab the gesture and try again
+ item->reset();
+ item->grabGesture(CustomGesture::GestureType);
+ sendCustomGesture(&event, item, &newScene);
+
+ QCOMPARE(item->customEventsReceived, TotalCustomEventsCount);
+ QCOMPARE(item->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(item->gestureOverrideEventsReceived, 0);
+}
+
+void tst_Gestures::graphicsItemTreeGesture()
+{
+ QGraphicsScene scene;
+ QGraphicsView view(&scene);
+ view.setWindowFlags(Qt::X11BypassWindowManagerHint);
+
+ GestureItem *item1 = new GestureItem("item1");
+ item1->setPos(100, 100);
+ item1->size = QRectF(0, 0, 350, 200);
+ scene.addItem(item1);
+
+ GestureItem *item1_child1 = new GestureItem("item1_child1");
+ item1_child1->setPos(50, 50);
+ item1_child1->size = QRectF(0, 0, 100, 100);
+ item1_child1->setParentItem(item1);
+
+ GestureItem *item1_child2 = new GestureItem("item1_child2");
+ item1_child2->size = QRectF(0, 0, 100, 100);
+ item1_child2->setPos(200, 50);
+ item1_child2->setParentItem(item1);
+
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ view.ensureVisible(scene.sceneRect());
+
+ item1->grabGesture(CustomGesture::GestureType);
+
+ static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
+
+ CustomEvent event;
+ event.hotSpot = mapToGlobal(QPointF(10, 10), item1_child1, &view);
+ event.hasHotSpot = true;
+
+ item1->ignoredGestures << CustomGesture::GestureType;
+ sendCustomGesture(&event, item1_child1, &scene);
+ QCOMPARE(item1_child1->gestureOverrideEventsReceived, 0);
+ QCOMPARE(item1_child1->gestureEventsReceived, 0);
+ QCOMPARE(item1_child2->gestureEventsReceived, 0);
+ QCOMPARE(item1_child2->gestureOverrideEventsReceived, 0);
+ QCOMPARE(item1->gestureOverrideEventsReceived, 0);
+ QCOMPARE(item1->gestureEventsReceived, TotalGestureEventsCount);
+
+ item1->reset(); item1_child1->reset(); item1_child2->reset();
+
+ item1_child1->grabGesture(CustomGesture::GestureType);
+
+ item1->ignoredGestures << CustomGesture::GestureType;
+ item1_child1->ignoredGestures << CustomGesture::GestureType;
+ sendCustomGesture(&event, item1_child1, &scene);
+ QCOMPARE(item1_child1->gestureOverrideEventsReceived, 1);
+ QCOMPARE(item1_child1->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(item1_child2->gestureEventsReceived, 0);
+ QCOMPARE(item1_child2->gestureOverrideEventsReceived, 0);
+ QCOMPARE(item1->gestureOverrideEventsReceived, 1);
+ QCOMPARE(item1->gestureEventsReceived, 1);
+}
+
+void tst_Gestures::explicitGraphicsObjectTarget()
+{
+ QGraphicsScene scene;
+ QGraphicsView view(&scene);
+ view.setWindowFlags(Qt::X11BypassWindowManagerHint);
+
+ GestureItem *item1 = new GestureItem("item1");
+ scene.addItem(item1);
+ item1->setPos(100, 100);
+ item1->setZValue(1);
+
+ GestureItem *item2 = new GestureItem("item2");
+ scene.addItem(item2);
+ item2->setPos(100, 100);
+ item2->setZValue(5);
+
+ GestureItem *item2_child1 = new GestureItem("item2_child1");
+ scene.addItem(item2_child1);
+ item2_child1->setParentItem(item2);
+ item2_child1->setPos(10, 10);
+
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ view.ensureVisible(scene.sceneRect());
+
+ item1->grabGesture(CustomGesture::GestureType, Qt::DontStartGestureOnChildren);
+ item2->grabGesture(CustomGesture::GestureType, Qt::DontStartGestureOnChildren);
+ item2_child1->grabGesture(CustomGesture::GestureType, Qt::DontStartGestureOnChildren);
+
+ static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
+
+ // sending events to item1, but the hotSpot is set to item2
+ CustomEvent event;
+ event.hotSpot = mapToGlobal(QPointF(15, 15), item2, &view);
+ event.hasHotSpot = true;
+
+ sendCustomGesture(&event, item1, &scene);
+
+ QCOMPARE(item1->gestureEventsReceived, 0);
+ QCOMPARE(item1->gestureOverrideEventsReceived, 1);
+ QCOMPARE(item2_child1->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(item2_child1->gestureOverrideEventsReceived, 1);
+ QCOMPARE(item2_child1->events.all.size(), TotalGestureEventsCount);
+ for(int i = 0; i < item2_child1->events.all.size(); ++i)
+ QCOMPARE(item2_child1->events.all.at(i), CustomGesture::GestureType);
+ QCOMPARE(item2_child1->events.started.size(), 1);
+ QCOMPARE(item2_child1->events.updated.size(), TotalGestureEventsCount - 2);
+ QCOMPARE(item2_child1->events.finished.size(), 1);
+ QCOMPARE(item2_child1->events.canceled.size(), 0);
+ QCOMPARE(item2->gestureEventsReceived, 0);
+ QCOMPARE(item2->gestureOverrideEventsReceived, 1);
+}
+
+void tst_Gestures::gestureOverChildGraphicsItem()
+{
+ QGraphicsScene scene;
+ QGraphicsView view(&scene);
+ view.setWindowFlags(Qt::X11BypassWindowManagerHint);
+
+ GestureItem *item0 = new GestureItem("item0");
+ scene.addItem(item0);
+ item0->setPos(0, 0);
+ item0->grabGesture(CustomGesture::GestureType);
+ item0->setZValue(1);
+
+ GestureItem *item1 = new GestureItem("item1");
+ scene.addItem(item1);
+ item1->setPos(100, 100);
+ item1->setZValue(5);
+
+ GestureItem *item2 = new GestureItem("item2");
+ scene.addItem(item2);
+ item2->setPos(100, 100);
+ item2->setZValue(10);
+
+ GestureItem *item2_child1 = new GestureItem("item2_child1");
+ scene.addItem(item2_child1);
+ item2_child1->setParentItem(item2);
+ item2_child1->setPos(0, 0);
+
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ view.ensureVisible(scene.sceneRect());
+
+ item1->grabGesture(CustomGesture::GestureType);
+
+ static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
+ static const int TotalCustomEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialMaybeThreshold + 1;
+
+ CustomEvent event;
+ event.hotSpot = mapToGlobal(QPointF(10, 10), item2_child1, &view);
+ event.hasHotSpot = true;
+ sendCustomGesture(&event, item0, &scene);
+
+ QCOMPARE(item0->customEventsReceived, TotalCustomEventsCount);
+ QCOMPARE(item2_child1->gestureEventsReceived, 0);
+ QCOMPARE(item2_child1->gestureOverrideEventsReceived, 0);
+ QCOMPARE(item2->gestureEventsReceived, 0);
+ QCOMPARE(item2->gestureOverrideEventsReceived, 0);
+ QCOMPARE(item1->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(item1->gestureOverrideEventsReceived, 0);
+
+ item0->reset(); item1->reset(); item2->reset(); item2_child1->reset();
+ item2->grabGesture(CustomGesture::GestureType);
+ item2->ignoredGestures << CustomGesture::GestureType;
+
+ event.hotSpot = mapToGlobal(QPointF(10, 10), item2_child1, &view);
+ event.hasHotSpot = true;
+ sendCustomGesture(&event, item0, &scene);
+
+ QCOMPARE(item2_child1->gestureEventsReceived, 0);
+ QCOMPARE(item2_child1->gestureOverrideEventsReceived, 0);
+ QCOMPARE(item2->gestureEventsReceived, 1);
+ QCOMPARE(item2->gestureOverrideEventsReceived, 1);
+ QCOMPARE(item1->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(item1->gestureOverrideEventsReceived, 1);
+
+ item0->reset(); item1->reset(); item2->reset(); item2_child1->reset();
+ item2->grabGesture(CustomGesture::GestureType);
+ item2->ignoredGestures << CustomGesture::GestureType;
+ item1->ignoredGestures << CustomGesture::GestureType;
+
+ event.hotSpot = mapToGlobal(QPointF(10, 10), item2_child1, &view);
+ event.hasHotSpot = true;
+ sendCustomGesture(&event, item0, &scene);
+
+ QCOMPARE(item2_child1->gestureEventsReceived, 0);
+ QCOMPARE(item2_child1->gestureOverrideEventsReceived, 0);
+ QCOMPARE(item2->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(item2->gestureOverrideEventsReceived, 1);
+ QCOMPARE(item1->gestureEventsReceived, 1);
+ QCOMPARE(item1->gestureOverrideEventsReceived, 1);
+
+ item0->reset(); item1->reset(); item2->reset(); item2_child1->reset();
+ item2->grabGesture(CustomGesture::GestureType);
+ item2->ignoredGestures << CustomGesture::GestureType;
+ item1->ignoredGestures << CustomGesture::GestureType;
+ item1->grabGesture(CustomGesture::GestureType, Qt::ReceivePartialGestures);
+
+ event.hotSpot = mapToGlobal(QPointF(10, 10), item2_child1, &view);
+ event.hasHotSpot = true;
+ sendCustomGesture(&event, item0, &scene);
+
+ QCOMPARE(item2_child1->gestureEventsReceived, 0);
+ QCOMPARE(item2_child1->gestureOverrideEventsReceived, 0);
+ QCOMPARE(item2->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(item2->gestureOverrideEventsReceived, 1);
+ QCOMPARE(item1->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(item1->gestureOverrideEventsReceived, 1);
+}
+
+void tst_Gestures::twoGesturesOnDifferentLevel()
+{
+ GestureWidget parent("parent");
+ QVBoxLayout *l = new QVBoxLayout(&parent);
+ GestureWidget *child = new GestureWidget("child");
+ l->addWidget(child);
+
+ Qt::GestureType SecondGesture = QGestureRecognizer::registerRecognizer(new CustomGestureRecognizer);
+
+ parent.grabGesture(CustomGesture::GestureType);
+ child->grabGesture(SecondGesture);
+
+ CustomEvent event;
+ // sending events that form a gesture to one widget, but they will be
+ // filtered by two different gesture recognizers and will generate two
+ // QGesture objects. Check that those gesture objects are delivered to
+ // different widgets properly.
+ sendCustomGesture(&event, child);
+
+ static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
+ static const int TotalCustomEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialMaybeThreshold + 1;
+
+ QCOMPARE(child->customEventsReceived, TotalCustomEventsCount);
+ QCOMPARE(child->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(child->gestureOverrideEventsReceived, 0);
+ QCOMPARE(child->events.all.size(), TotalGestureEventsCount);
+ for(int i = 0; i < child->events.all.size(); ++i)
+ QCOMPARE(child->events.all.at(i), SecondGesture);
+
+ QCOMPARE(parent.gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(parent.gestureOverrideEventsReceived, 0);
+ QCOMPARE(parent.events.all.size(), TotalGestureEventsCount);
+ for(int i = 0; i < child->events.all.size(); ++i)
+ QCOMPARE(parent.events.all.at(i), CustomGesture::GestureType);
+
+ QGestureRecognizer::unregisterRecognizer(SecondGesture);
+}
+
+void tst_Gestures::multipleGesturesInTree()
+{
+ GestureWidget a("A");
+ GestureWidget *A = &a;
+ GestureWidget *B = new GestureWidget("B", A);
+ GestureWidget *C = new GestureWidget("C", B);
+ GestureWidget *D = new GestureWidget("D", C);
+
+ Qt::GestureType FirstGesture = CustomGesture::GestureType;
+ Qt::GestureType SecondGesture = QGestureRecognizer::registerRecognizer(new CustomGestureRecognizer);
+ Qt::GestureType ThirdGesture = QGestureRecognizer::registerRecognizer(new CustomGestureRecognizer);
+
+ Qt::GestureFlags flags = Qt::ReceivePartialGestures;
+ A->grabGesture(FirstGesture, flags); // A [1 3]
+ A->grabGesture(ThirdGesture, flags); // |
+ B->grabGesture(SecondGesture, flags); // B [ 2 3]
+ B->grabGesture(ThirdGesture, flags); // |
+ C->grabGesture(FirstGesture, flags); // C [1 2 3]
+ C->grabGesture(SecondGesture, flags); // |
+ C->grabGesture(ThirdGesture, flags); // D [1 3]
+ D->grabGesture(FirstGesture, flags);
+ D->grabGesture(ThirdGesture, flags);
+
+ // make sure all widgets ignore events, so they get propagated.
+ A->ignoredGestures << FirstGesture << ThirdGesture;
+ B->ignoredGestures << SecondGesture << ThirdGesture;
+ C->ignoredGestures << FirstGesture << SecondGesture << ThirdGesture;
+ D->ignoredGestures << FirstGesture << ThirdGesture;
+
+ CustomEvent event;
+ sendCustomGesture(&event, D);
+
+ static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
+
+ // gesture override events
+ QCOMPARE(D->overrideEvents.all.count(FirstGesture), 1);
+ QCOMPARE(D->overrideEvents.all.count(SecondGesture), 0);
+ QCOMPARE(D->overrideEvents.all.count(ThirdGesture), 1);
+
+ QCOMPARE(C->overrideEvents.all.count(FirstGesture), 1);
+ QCOMPARE(C->overrideEvents.all.count(SecondGesture), 1);
+ QCOMPARE(C->overrideEvents.all.count(ThirdGesture), 1);
+
+ QCOMPARE(B->overrideEvents.all.count(FirstGesture), 0);
+ QCOMPARE(B->overrideEvents.all.count(SecondGesture), 1);
+ QCOMPARE(B->overrideEvents.all.count(ThirdGesture), 1);
+
+ QCOMPARE(A->overrideEvents.all.count(FirstGesture), 1);
+ QCOMPARE(A->overrideEvents.all.count(SecondGesture), 0);
+ QCOMPARE(A->overrideEvents.all.count(ThirdGesture), 1);
+
+ // normal gesture events
+ QCOMPARE(D->events.all.count(FirstGesture), TotalGestureEventsCount);
+ QCOMPARE(D->events.all.count(SecondGesture), 0);
+ QCOMPARE(D->events.all.count(ThirdGesture), TotalGestureEventsCount);
+
+ QCOMPARE(C->events.all.count(FirstGesture), TotalGestureEventsCount);
+ QCOMPARE(C->events.all.count(SecondGesture), TotalGestureEventsCount);
+ QCOMPARE(C->events.all.count(ThirdGesture), TotalGestureEventsCount);
+
+ QCOMPARE(B->events.all.count(FirstGesture), 0);
+ QCOMPARE(B->events.all.count(SecondGesture), TotalGestureEventsCount);
+ QCOMPARE(B->events.all.count(ThirdGesture), TotalGestureEventsCount);
+
+ QCOMPARE(A->events.all.count(FirstGesture), TotalGestureEventsCount);
+ QCOMPARE(A->events.all.count(SecondGesture), 0);
+ QCOMPARE(A->events.all.count(ThirdGesture), TotalGestureEventsCount);
+
+ QGestureRecognizer::unregisterRecognizer(SecondGesture);
+ QGestureRecognizer::unregisterRecognizer(ThirdGesture);
+}
+
+void tst_Gestures::multipleGesturesInComplexTree()
+{
+ GestureWidget a("A");
+ GestureWidget *A = &a;
+ GestureWidget *B = new GestureWidget("B", A);
+ GestureWidget *C = new GestureWidget("C", B);
+ GestureWidget *D = new GestureWidget("D", C);
+
+ Qt::GestureType FirstGesture = CustomGesture::GestureType;
+ Qt::GestureType SecondGesture = QGestureRecognizer::registerRecognizer(new CustomGestureRecognizer);
+ Qt::GestureType ThirdGesture = QGestureRecognizer::registerRecognizer(new CustomGestureRecognizer);
+ Qt::GestureType FourthGesture = QGestureRecognizer::registerRecognizer(new CustomGestureRecognizer);
+ Qt::GestureType FifthGesture = QGestureRecognizer::registerRecognizer(new CustomGestureRecognizer);
+ Qt::GestureType SixthGesture = QGestureRecognizer::registerRecognizer(new CustomGestureRecognizer);
+ Qt::GestureType SeventhGesture = QGestureRecognizer::registerRecognizer(new CustomGestureRecognizer);
+
+ Qt::GestureFlags flags = Qt::ReceivePartialGestures;
+ A->grabGesture(FirstGesture, flags); // A [1,3,4]
+ A->grabGesture(ThirdGesture, flags); // |
+ A->grabGesture(FourthGesture, flags); // B [2,3,5]
+ B->grabGesture(SecondGesture, flags); // |
+ B->grabGesture(ThirdGesture, flags); // C [1,2,3,6]
+ B->grabGesture(FifthGesture, flags); // |
+ C->grabGesture(FirstGesture, flags); // D [1,3,7]
+ C->grabGesture(SecondGesture, flags);
+ C->grabGesture(ThirdGesture, flags);
+ C->grabGesture(SixthGesture, flags);
+ D->grabGesture(FirstGesture, flags);
+ D->grabGesture(ThirdGesture, flags);
+ D->grabGesture(SeventhGesture, flags);
+
+ // make sure all widgets ignore events, so they get propagated.
+ QSet<Qt::GestureType> allGestureTypes;
+ allGestureTypes << FirstGesture << SecondGesture << ThirdGesture
+ << FourthGesture << FifthGesture << SixthGesture << SeventhGesture;
+ A->ignoredGestures = B->ignoredGestures = allGestureTypes;
+ C->ignoredGestures = D->ignoredGestures = allGestureTypes;
+
+ CustomEvent event;
+ sendCustomGesture(&event, D);
+
+ static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
+
+ // gesture override events
+ QCOMPARE(D->overrideEvents.all.count(FirstGesture), 1);
+ QCOMPARE(D->overrideEvents.all.count(SecondGesture), 0);
+ QCOMPARE(D->overrideEvents.all.count(ThirdGesture), 1);
+
+ QCOMPARE(C->overrideEvents.all.count(FirstGesture), 1);
+ QCOMPARE(C->overrideEvents.all.count(SecondGesture), 1);
+ QCOMPARE(C->overrideEvents.all.count(ThirdGesture), 1);
+
+ QCOMPARE(B->overrideEvents.all.count(FirstGesture), 0);
+ QCOMPARE(B->overrideEvents.all.count(SecondGesture), 1);
+ QCOMPARE(B->overrideEvents.all.count(ThirdGesture), 1);
+
+ QCOMPARE(A->overrideEvents.all.count(FirstGesture), 1);
+ QCOMPARE(A->overrideEvents.all.count(SecondGesture), 0);
+ QCOMPARE(A->overrideEvents.all.count(ThirdGesture), 1);
+
+ // normal gesture events
+ QCOMPARE(D->events.all.count(FirstGesture), TotalGestureEventsCount);
+ QCOMPARE(D->events.all.count(SecondGesture), 0);
+ QCOMPARE(D->events.all.count(ThirdGesture), TotalGestureEventsCount);
+ QCOMPARE(D->events.all.count(FourthGesture), 0);
+ QCOMPARE(D->events.all.count(FifthGesture), 0);
+ QCOMPARE(D->events.all.count(SixthGesture), 0);
+ QCOMPARE(D->events.all.count(SeventhGesture), TotalGestureEventsCount);
+
+ QCOMPARE(C->events.all.count(FirstGesture), TotalGestureEventsCount);
+ QCOMPARE(C->events.all.count(SecondGesture), TotalGestureEventsCount);
+ QCOMPARE(C->events.all.count(ThirdGesture), TotalGestureEventsCount);
+ QCOMPARE(C->events.all.count(FourthGesture), 0);
+ QCOMPARE(C->events.all.count(FifthGesture), 0);
+ QCOMPARE(C->events.all.count(SixthGesture), TotalGestureEventsCount);
+ QCOMPARE(C->events.all.count(SeventhGesture), 0);
+
+ QCOMPARE(B->events.all.count(FirstGesture), 0);
+ QCOMPARE(B->events.all.count(SecondGesture), TotalGestureEventsCount);
+ QCOMPARE(B->events.all.count(ThirdGesture), TotalGestureEventsCount);
+ QCOMPARE(B->events.all.count(FourthGesture), 0);
+ QCOMPARE(B->events.all.count(FifthGesture), TotalGestureEventsCount);
+ QCOMPARE(B->events.all.count(SixthGesture), 0);
+ QCOMPARE(B->events.all.count(SeventhGesture), 0);
+
+ QCOMPARE(A->events.all.count(FirstGesture), TotalGestureEventsCount);
+ QCOMPARE(A->events.all.count(SecondGesture), 0);
+ QCOMPARE(A->events.all.count(ThirdGesture), TotalGestureEventsCount);
+ QCOMPARE(A->events.all.count(FourthGesture), TotalGestureEventsCount);
+ QCOMPARE(A->events.all.count(FifthGesture), 0);
+ QCOMPARE(A->events.all.count(SixthGesture), 0);
+ QCOMPARE(A->events.all.count(SeventhGesture), 0);
+
+ QGestureRecognizer::unregisterRecognizer(SecondGesture);
+ QGestureRecognizer::unregisterRecognizer(ThirdGesture);
+ QGestureRecognizer::unregisterRecognizer(FourthGesture);
+ QGestureRecognizer::unregisterRecognizer(FifthGesture);
+ QGestureRecognizer::unregisterRecognizer(SixthGesture);
+ QGestureRecognizer::unregisterRecognizer(SeventhGesture);
+}
+
+void tst_Gestures::testMapToScene()
+{
+ QGesture gesture;
+ QList<QGesture*> list;
+ list << &gesture;
+ QGestureEvent event(list);
+ QCOMPARE(event.mapToGraphicsScene(gesture.hotSpot()), QPointF()); // not set, can't do much
+
+ QGraphicsScene scene;
+ QGraphicsView view(&scene);
+ view.setWindowFlags(Qt::X11BypassWindowManagerHint);
+
+ GestureItem *item0 = new GestureItem;
+ scene.addItem(item0);
+ item0->setPos(14, 16);
+
+ view.show(); // need to show to give it a global coordinate
+ QTest::qWaitForWindowShown(&view);
+ view.ensureVisible(scene.sceneRect());
+
+ QPoint origin = view.mapToGlobal(QPoint());
+ event.setWidget(view.viewport());
+
+ QCOMPARE(event.mapToGraphicsScene(origin + QPoint(100, 200)), view.mapToScene(QPoint(100, 200)));
+}
+
+void tst_Gestures::ungrabGesture() // a method on QWidget
+{
+ class MockGestureWidget : public GestureWidget {
+ public:
+ MockGestureWidget(const char *name = 0, QWidget *parent = 0)
+ : GestureWidget(name, parent) { }
+
+
+ QSet<QGesture*> gestures;
+ protected:
+ bool event(QEvent *event)
+ {
+ if (event->type() == QEvent::Gesture) {
+ QGestureEvent *gestureEvent = static_cast<QGestureEvent*>(event);
+ if (gestureEvent)
+ foreach (QGesture *g, gestureEvent->gestures())
+ gestures.insert(g);
+ }
+ return GestureWidget::event(event);
+ }
+ };
+
+ MockGestureWidget parent("A");
+ MockGestureWidget *a = &parent;
+ MockGestureWidget *b = new MockGestureWidget("B", a);
+
+ a->grabGesture(CustomGesture::GestureType, Qt::DontStartGestureOnChildren);
+ b->grabGesture(CustomGesture::GestureType);
+ b->ignoredGestures << CustomGesture::GestureType;
+
+ CustomEvent event;
+ // sending an event will cause the QGesture objects to be instantiated for the widgets
+ sendCustomGesture(&event, b);
+
+ QCOMPARE(a->gestures.count(), 1);
+ QPointer<QGesture> customGestureA;
+ customGestureA = *(a->gestures.begin());
+ QVERIFY(!customGestureA.isNull());
+ QCOMPARE(customGestureA->gestureType(), CustomGesture::GestureType);
+
+ QCOMPARE(b->gestures.count(), 1);
+ QPointer<QGesture> customGestureB;
+ customGestureB = *(b->gestures.begin());
+ QVERIFY(!customGestureB.isNull());
+ QVERIFY(customGestureA.data() == customGestureB.data());
+ QCOMPARE(customGestureB->gestureType(), CustomGesture::GestureType);
+
+ a->gestures.clear();
+ // sending an event will cause the QGesture objects to be instantiated for the widget
+ sendCustomGesture(&event, a);
+
+ QCOMPARE(a->gestures.count(), 1);
+ customGestureA = *(a->gestures.begin());
+ QVERIFY(!customGestureA.isNull());
+ QCOMPARE(customGestureA->gestureType(), CustomGesture::GestureType);
+ QVERIFY(customGestureA.data() != customGestureB.data());
+
+ a->ungrabGesture(CustomGesture::GestureType);
+ //We changed the deletion of Gestures to lazy during QT-4022, so we can't ensure the QGesture is deleted until now
+ QVERIFY(!customGestureB.isNull());
+
+ a->gestures.clear();
+ a->reset();
+ // send again to 'b' and make sure a never gets it.
+ sendCustomGesture(&event, b);
+ //After all Gestures are processed in the QGestureManager, we can ensure the QGesture is now deleted
+ QVERIFY(customGestureA.isNull());
+ QCOMPARE(a->gestureEventsReceived, 0);
+ QCOMPARE(a->gestureOverrideEventsReceived, 0);
+}
+
+void tst_Gestures::unregisterRecognizer() // a method on QApplication
+{
+ /*
+ The hardest usecase to get right is when we remove a recognizer while several
+ of the gestures it created are in active state and we immediately add a new recognizer
+ for the same type (thus replacing the old one).
+ The expected result is that all old gestures continue till they are finished/cancelled
+ and the new recognizer starts creating gestures immediately at registration.
+
+ This implies that deleting of the recognizer happens only when there are no more gestures
+ that it created. (since gestures might have a pointer to the recognizer)
+ */
+
+}
+
+void tst_Gestures::autoCancelGestures()
+{
+ class MockWidget : public GestureWidget {
+ public:
+ MockWidget(const char *name) : GestureWidget(name), badGestureEvents(0) { }
+
+ bool event(QEvent *event)
+ {
+ if (event->type() == QEvent::Gesture) {
+ QGestureEvent *ge = static_cast<QGestureEvent*>(event);
+ if (ge->gestures().count() != 1)
+ ++badGestureEvents; // event should contain exactly one gesture
+ ge->gestures().first()->setGestureCancelPolicy(QGesture::CancelAllInContext);
+ }
+ return GestureWidget::event(event);
+ }
+
+ int badGestureEvents;
+ };
+
+ const Qt::GestureType secondGesture = QGestureRecognizer::registerRecognizer(new CustomGestureRecognizer);
+
+ MockWidget parent("parent"); // this one sets the cancel policy to CancelAllInContext
+ parent.resize(300, 100);
+ parent.setWindowFlags(Qt::X11BypassWindowManagerHint);
+ GestureWidget *child = new GestureWidget("child", &parent);
+ child->setGeometry(10, 10, 100, 80);
+
+ parent.grabGesture(CustomGesture::GestureType);
+ child->grabGesture(secondGesture);
+ parent.show();
+ QTest::qWaitForWindowShown(&parent);
+
+ /*
+ An event is send to both the child and the parent, when the child gets it a gesture is triggered
+ and send to the child.
+ When the parent gets the event a new gesture is triggered and delivered to the parent. When the
+ parent gets it he accepts it and that causes the cancel policy to activate.
+ The cause of that is the gesture for the child is cancelled and send to the child as such.
+ */
+ CustomEvent event;
+ event.serial = CustomGesture::SerialStartedThreshold;
+ QApplication::sendEvent(child, &event);
+ QCOMPARE(child->events.all.count(), 2);
+ QCOMPARE(child->events.started.count(), 1);
+ QCOMPARE(child->events.canceled.count(), 1);
+ QCOMPARE(parent.events.all.count(), 1);
+
+ // clean up, make the parent gesture finish
+ event.serial = CustomGesture::SerialFinishedThreshold;
+ QApplication::sendEvent(child, &event);
+ QCOMPARE(parent.events.all.count(), 2);
+ QCOMPARE(parent.badGestureEvents, 0);
+}
+
+void tst_Gestures::autoCancelGestures2()
+{
+ class MockItem : public GestureItem {
+ public:
+ MockItem(const char *name) : GestureItem(name), badGestureEvents(0) { }
+
+ bool event(QEvent *event) {
+ if (event->type() == QEvent::Gesture) {
+ QGestureEvent *ge = static_cast<QGestureEvent*>(event);
+ if (ge->gestures().count() != 1)
+ ++badGestureEvents; // event should contain exactly one gesture
+ ge->gestures().first()->setGestureCancelPolicy(QGesture::CancelAllInContext);
+ }
+ return GestureItem::event(event);
+ }
+
+ int badGestureEvents;
+ };
+
+ const Qt::GestureType secondGesture = QGestureRecognizer ::registerRecognizer(new CustomGestureRecognizer);
+
+ QGraphicsScene scene;
+ QGraphicsView view(&scene);
+ view.setWindowFlags(Qt::X11BypassWindowManagerHint);
+
+ MockItem *parent = new MockItem("parent");
+ GestureItem *child = new GestureItem("child");
+ child->setParentItem(parent);
+ parent->setPos(0, 0);
+ child->setPos(10, 10);
+ scene.addItem(parent);
+ parent->grabGesture(CustomGesture::GestureType);
+ child->grabGesture(secondGesture);
+
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ view.ensureVisible(scene.sceneRect());
+
+ CustomEvent event;
+ event.serial = CustomGesture::SerialStartedThreshold;
+ event.hasHotSpot = true;
+ event.hotSpot = mapToGlobal(QPointF(5, 5), child, &view);
+ scene.sendEvent(child, &event);
+ QCOMPARE(parent->events.all.count(), 1);
+ QCOMPARE(child->events.started.count(), 1);
+ QCOMPARE(child->events.canceled.count(), 1);
+ QCOMPARE(child->events.all.count(), 2);
+
+ // clean up, make the parent gesture finish
+ event.serial = CustomGesture::SerialFinishedThreshold;
+ scene.sendEvent(child, &event);
+ QCOMPARE(parent->events.all.count(), 2);
+ QCOMPARE(parent->badGestureEvents, 0);
+}
+
+void tst_Gestures::graphicsViewParentPropagation()
+{
+ QGraphicsScene scene;
+ QGraphicsView view(&scene);
+ view.setWindowFlags(Qt::X11BypassWindowManagerHint);
+
+ GestureItem *item0 = new GestureItem("item0");
+ scene.addItem(item0);
+ item0->setPos(0, 0);
+ item0->grabGesture(CustomGesture::GestureType);
+ item0->setZValue(1);
+
+ GestureItem *item1 = new GestureItem("item1");
+ scene.addItem(item1);
+ item1->setPos(0, 0);
+ item1->setZValue(5);
+
+ GestureItem *item1_c1 = new GestureItem("item1_child1");
+ item1_c1->setParentItem(item1);
+ item1_c1->setPos(0, 0);
+
+ GestureItem *item1_c1_c1 = new GestureItem("item1_child1_child1");
+ item1_c1_c1->setParentItem(item1_c1);
+ item1_c1_c1->setPos(0, 0);
+
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ view.ensureVisible(scene.sceneRect());
+
+ item0->grabGesture(CustomGesture::GestureType, Qt::ReceivePartialGestures | Qt::IgnoredGesturesPropagateToParent);
+ item1->grabGesture(CustomGesture::GestureType, Qt::ReceivePartialGestures | Qt::IgnoredGesturesPropagateToParent);
+ item1_c1->grabGesture(CustomGesture::GestureType, Qt::IgnoredGesturesPropagateToParent);
+ item1_c1_c1->grabGesture(CustomGesture::GestureType, Qt::ReceivePartialGestures | Qt::IgnoredGesturesPropagateToParent);
+
+ item0->ignoredUpdatedGestures << CustomGesture::GestureType;
+ item0->ignoredFinishedGestures << CustomGesture::GestureType;
+ item1->ignoredUpdatedGestures << CustomGesture::GestureType;
+ item1->ignoredFinishedGestures << CustomGesture::GestureType;
+ item1_c1->ignoredUpdatedGestures << CustomGesture::GestureType;
+ item1_c1->ignoredFinishedGestures << CustomGesture::GestureType;
+ item1_c1_c1->ignoredUpdatedGestures << CustomGesture::GestureType;
+ item1_c1_c1->ignoredFinishedGestures << CustomGesture::GestureType;
+
+ static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
+
+ CustomEvent event;
+ event.hotSpot = mapToGlobal(QPointF(10, 10), item1_c1, &view);
+ event.hasHotSpot = true;
+ sendCustomGesture(&event, item0, &scene);
+
+ QCOMPARE(item1_c1_c1->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(item1_c1_c1->gestureOverrideEventsReceived, 1);
+ QCOMPARE(item1_c1->gestureEventsReceived, TotalGestureEventsCount-1);
+ QCOMPARE(item1_c1->gestureOverrideEventsReceived, 1);
+ QCOMPARE(item1->gestureEventsReceived, TotalGestureEventsCount-1);
+ QCOMPARE(item1->gestureOverrideEventsReceived, 1);
+ QCOMPARE(item0->gestureEventsReceived, 0);
+ QCOMPARE(item0->gestureOverrideEventsReceived, 1);
+}
+
+void tst_Gestures::panelPropagation()
+{
+ QGraphicsScene scene;
+ QGraphicsView view(&scene);
+ view.setWindowFlags(Qt::X11BypassWindowManagerHint);
+
+ GestureItem *item0 = new GestureItem("item0");
+ scene.addItem(item0);
+ item0->setPos(0, 0);
+ item0->size = QRectF(0, 0, 200, 200);
+ item0->grabGesture(CustomGesture::GestureType);
+ item0->setZValue(1);
+
+ GestureItem *item1 = new GestureItem("item1");
+ item1->grabGesture(CustomGesture::GestureType);
+ scene.addItem(item1);
+ item1->setPos(10, 10);
+ item1->size = QRectF(0, 0, 180, 180);
+ item1->setZValue(2);
+
+ GestureItem *item1_child1 = new GestureItem("item1_child1[panel]");
+ item1_child1->setFlags(QGraphicsItem::ItemIsPanel);
+ item1_child1->setParentItem(item1);
+ item1_child1->grabGesture(CustomGesture::GestureType);
+ item1_child1->setPos(10, 10);
+ item1_child1->size = QRectF(0, 0, 160, 160);
+ item1_child1->setZValue(5);
+
+ GestureItem *item1_child1_child1 = new GestureItem("item1_child1_child1");
+ item1_child1_child1->setParentItem(item1_child1);
+ item1_child1_child1->grabGesture(CustomGesture::GestureType);
+ item1_child1_child1->setPos(10, 10);
+ item1_child1_child1->size = QRectF(0, 0, 140, 140);
+ item1_child1_child1->setZValue(10);
+
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ view.ensureVisible(scene.sceneRect());
+
+ static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
+ static const int TotalCustomEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialMaybeThreshold + 1;
+
+ CustomEvent event;
+ event.hotSpot = mapToGlobal(QPointF(5, 5), item1_child1_child1, &view);
+ event.hasHotSpot = true;
+ sendCustomGesture(&event, item0, &scene);
+
+ QCOMPARE(item0->customEventsReceived, TotalCustomEventsCount);
+ QCOMPARE(item1_child1_child1->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(item1_child1_child1->gestureOverrideEventsReceived, 1);
+ QCOMPARE(item1_child1->gestureOverrideEventsReceived, 1);
+ QCOMPARE(item1->gestureEventsReceived, 0);
+ QCOMPARE(item1->gestureOverrideEventsReceived, 0);
+ QCOMPARE(item0->gestureEventsReceived, 0);
+ QCOMPARE(item0->gestureOverrideEventsReceived, 0);
+
+ item0->reset(); item1->reset(); item1_child1->reset(); item1_child1_child1->reset();
+
+ event.hotSpot = mapToGlobal(QPointF(5, 5), item1, &view);
+ event.hasHotSpot = true;
+ sendCustomGesture(&event, item1, &scene);
+
+ QCOMPARE(item1_child1_child1->gestureEventsReceived, 0);
+ QCOMPARE(item1_child1_child1->gestureOverrideEventsReceived, 0);
+ QCOMPARE(item1_child1->gestureEventsReceived, 0);
+ QCOMPARE(item1_child1->gestureOverrideEventsReceived, 0);
+ QCOMPARE(item1->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(item1->gestureOverrideEventsReceived, 1);
+ QCOMPARE(item0->gestureEventsReceived, 0);
+ QCOMPARE(item0->gestureOverrideEventsReceived, 1);
+
+ item0->reset(); item1->reset(); item1_child1->reset(); item1_child1_child1->reset();
+ // try with a modal panel
+ item1_child1->setPanelModality(QGraphicsItem::PanelModal);
+
+ event.hotSpot = mapToGlobal(QPointF(5, 5), item1, &view);
+ event.hasHotSpot = true;
+ sendCustomGesture(&event, item1, &scene);
+
+ QCOMPARE(item1_child1_child1->gestureEventsReceived, 0);
+ QCOMPARE(item1_child1_child1->gestureOverrideEventsReceived, 0);
+ QCOMPARE(item1_child1->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(item1_child1->gestureOverrideEventsReceived, 0);
+ QCOMPARE(item1->gestureEventsReceived, 0);
+ QCOMPARE(item1->gestureOverrideEventsReceived, 0);
+ QCOMPARE(item0->gestureEventsReceived, 0);
+ QCOMPARE(item0->gestureOverrideEventsReceived, 0);
+
+ item0->reset(); item1->reset(); item1_child1->reset(); item1_child1_child1->reset();
+ // try with a modal panel, however set the hotspot to be outside of the
+ // panel and its parent
+ item1_child1->setPanelModality(QGraphicsItem::PanelModal);
+
+ event.hotSpot = mapToGlobal(QPointF(5, 5), item0, &view);
+ event.hasHotSpot = true;
+ sendCustomGesture(&event, item1, &scene);
+
+ QCOMPARE(item1_child1_child1->gestureEventsReceived, 0);
+ QCOMPARE(item1_child1_child1->gestureOverrideEventsReceived, 0);
+ QCOMPARE(item1_child1->gestureEventsReceived, 0);
+ QCOMPARE(item1_child1->gestureOverrideEventsReceived, 0);
+ QCOMPARE(item1->gestureEventsReceived, 0);
+ QCOMPARE(item1->gestureOverrideEventsReceived, 0);
+ QCOMPARE(item0->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(item0->gestureOverrideEventsReceived, 0);
+
+ item0->reset(); item1->reset(); item1_child1->reset(); item1_child1_child1->reset();
+ // try with a scene modal panel
+ item1_child1->setPanelModality(QGraphicsItem::SceneModal);
+
+ event.hotSpot = mapToGlobal(QPointF(5, 5), item0, &view);
+ event.hasHotSpot = true;
+ sendCustomGesture(&event, item0, &scene);
+
+ QCOMPARE(item1_child1_child1->gestureEventsReceived, 0);
+ QCOMPARE(item1_child1_child1->gestureOverrideEventsReceived, 0);
+ QCOMPARE(item1_child1->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(item1_child1->gestureOverrideEventsReceived, 0);
+ QCOMPARE(item1->gestureEventsReceived, 0);
+ QCOMPARE(item1->gestureOverrideEventsReceived, 0);
+ QCOMPARE(item0->gestureEventsReceived, 0);
+ QCOMPARE(item0->gestureOverrideEventsReceived, 0);
+}
+
+void tst_Gestures::panelStacksBehindParent()
+{
+ QGraphicsScene scene;
+ QGraphicsView view(&scene);
+ view.setWindowFlags(Qt::X11BypassWindowManagerHint);
+
+ GestureItem *item1 = new GestureItem("item1");
+ item1->grabGesture(CustomGesture::GestureType);
+ scene.addItem(item1);
+ item1->setPos(10, 10);
+ item1->size = QRectF(0, 0, 180, 180);
+ item1->setZValue(2);
+
+ GestureItem *panel = new GestureItem("panel");
+ panel->setFlags(QGraphicsItem::ItemIsPanel | QGraphicsItem::ItemStacksBehindParent);
+ panel->setPanelModality(QGraphicsItem::PanelModal);
+ panel->setParentItem(item1);
+ panel->grabGesture(CustomGesture::GestureType);
+ panel->setPos(-10, -10);
+ panel->size = QRectF(0, 0, 200, 200);
+ panel->setZValue(5);
+
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ view.ensureVisible(scene.sceneRect());
+
+ static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
+
+ CustomEvent event;
+ event.hotSpot = mapToGlobal(QPointF(5, 5), item1, &view);
+ event.hasHotSpot = true;
+ sendCustomGesture(&event, item1, &scene);
+
+ QCOMPARE(item1->gestureEventsReceived, 0);
+ QCOMPARE(item1->gestureOverrideEventsReceived, 0);
+ QCOMPARE(panel->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(panel->gestureOverrideEventsReceived, 0);
+}
+
+void tst_Gestures::deleteGestureTargetWidget()
+{
+}
+
+void tst_Gestures::deleteGestureTargetItem_data()
+{
+ QTest::addColumn<bool>("propagateUpdateGesture");
+ QTest::addColumn<QString>("emitter");
+ QTest::addColumn<QString>("receiver");
+ QTest::addColumn<QByteArray>("signalName");
+ QTest::addColumn<QByteArray>("slotName");
+
+ QByteArray gestureUpdated = SIGNAL(gestureUpdated(QEvent::Type,QGesture*));
+ QByteArray gestureFinished = SIGNAL(gestureFinished(QEvent::Type,QGesture*));
+ QByteArray deleteThis = SLOT(deleteThis());
+ QByteArray deleteLater = SLOT(deleteLater());
+
+ QTest::newRow("delete1")
+ << false << "item1" << "item1" << gestureUpdated << deleteThis;
+ QTest::newRow("delete2")
+ << false << "item2" << "item2" << gestureUpdated << deleteThis;
+ QTest::newRow("delete3")
+ << false << "item1" << "item2" << gestureUpdated << deleteThis;
+
+ QTest::newRow("deleteLater1")
+ << false << "item1" << "item1" << gestureUpdated << deleteLater;
+ QTest::newRow("deleteLater2")
+ << false << "item2" << "item2" << gestureUpdated << deleteLater;
+ QTest::newRow("deleteLater3")
+ << false << "item1" << "item2" << gestureUpdated << deleteLater;
+ QTest::newRow("deleteLater4")
+ << false << "item2" << "item1" << gestureUpdated << deleteLater;
+
+ QTest::newRow("delete-self-and-propagate")
+ << true << "item2" << "item2" << gestureUpdated << deleteThis;
+ QTest::newRow("deleteLater-self-and-propagate")
+ << true << "item2" << "item2" << gestureUpdated << deleteLater;
+ QTest::newRow("propagate-to-deletedLater")
+ << true << "item2" << "item1" << gestureUpdated << deleteLater;
+}
+
+void tst_Gestures::deleteGestureTargetItem()
+{
+ QFETCH(bool, propagateUpdateGesture);
+ QFETCH(QString, emitter);
+ QFETCH(QString, receiver);
+ QFETCH(QByteArray, signalName);
+ QFETCH(QByteArray, slotName);
+
+ QGraphicsScene scene;
+ QGraphicsView view(&scene);
+ view.setWindowFlags(Qt::X11BypassWindowManagerHint);
+
+ GestureItem *item1 = new GestureItem("item1");
+ item1->grabGesture(CustomGesture::GestureType);
+ item1->setZValue(2);
+ scene.addItem(item1);
+
+ GestureItem *item2 = new GestureItem("item2");
+ item2->grabGesture(CustomGesture::GestureType);
+ item2->setZValue(5);
+ scene.addItem(item2);
+
+ QMap<QString, GestureItem *> items;
+ items.insert(item1->objectName(), item1);
+ items.insert(item2->objectName(), item2);
+
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ view.ensureVisible(scene.sceneRect());
+
+ if (propagateUpdateGesture)
+ item2->ignoredUpdatedGestures << CustomGesture::GestureType;
+ connect(items.value(emitter, 0), signalName, items.value(receiver, 0), slotName);
+
+ // some debug output to see the current test data tag, so if we crash
+ // we know which one caused the crash.
+ qDebug() << "<-- testing";
+
+ CustomEvent event;
+ event.hotSpot = mapToGlobal(QPointF(5, 5), item2, &view);
+ event.hasHotSpot = true;
+ sendCustomGesture(&event, item1, &scene);
+}
+
+class GraphicsView : public QGraphicsView
+{
+public:
+ GraphicsView(QGraphicsScene *scene, QWidget *parent = 0)
+ : QGraphicsView(scene, parent)
+ {
+ }
+
+ using QGraphicsView::setViewportMargins;
+};
+
+// just making sure that even if the graphicsview has margins hotspot still
+// works properly. It should use viewport for converting global coordinates to
+// scene coordinates.
+void tst_Gestures::viewportCoordinates()
+{
+ QGraphicsScene scene;
+ GraphicsView view(&scene);
+ view.setViewportMargins(10,20,15,25);
+ view.setWindowFlags(Qt::X11BypassWindowManagerHint);
+
+ GestureItem *item1 = new GestureItem("item1");
+ item1->grabGesture(CustomGesture::GestureType);
+ item1->size = QRectF(0, 0, 3, 3);
+ item1->setZValue(2);
+ scene.addItem(item1);
+
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ view.ensureVisible(scene.sceneRect());
+
+ CustomEvent event;
+ event.hotSpot = mapToGlobal(item1->boundingRect().center(), item1, &view);
+ event.hasHotSpot = true;
+ sendCustomGesture(&event, item1, &scene);
+ QVERIFY(item1->gestureEventsReceived != 0);
+}
+
+void tst_Gestures::partialGesturePropagation()
+{
+ QGraphicsScene scene;
+ QGraphicsView view(&scene);
+ view.setWindowFlags(Qt::X11BypassWindowManagerHint);
+
+ GestureItem *item1 = new GestureItem("item1");
+ item1->grabGesture(CustomGesture::GestureType);
+ item1->setZValue(8);
+ scene.addItem(item1);
+
+ GestureItem *item2 = new GestureItem("item2[partial]");
+ item2->grabGesture(CustomGesture::GestureType, Qt::ReceivePartialGestures);
+ item2->setZValue(6);
+ scene.addItem(item2);
+
+ GestureItem *item3 = new GestureItem("item3");
+ item3->grabGesture(CustomGesture::GestureType);
+ item3->setZValue(4);
+ scene.addItem(item3);
+
+ GestureItem *item4 = new GestureItem("item4[partial]");
+ item4->grabGesture(CustomGesture::GestureType, Qt::ReceivePartialGestures);
+ item4->setZValue(2);
+ scene.addItem(item4);
+
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ view.ensureVisible(scene.sceneRect());
+
+ item1->ignoredUpdatedGestures << CustomGesture::GestureType;
+
+ CustomEvent event;
+ event.hotSpot = mapToGlobal(QPointF(5, 5), item1, &view);
+ event.hasHotSpot = true;
+ sendCustomGesture(&event, item1, &scene);
+
+ static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
+
+ QCOMPARE(item1->gestureOverrideEventsReceived, 1);
+ QCOMPARE(item2->gestureOverrideEventsReceived, 1);
+ QCOMPARE(item3->gestureOverrideEventsReceived, 1);
+ QCOMPARE(item4->gestureOverrideEventsReceived, 1);
+
+ QCOMPARE(item1->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(item2->gestureEventsReceived, TotalGestureEventsCount-2); // except for started and finished
+ QCOMPARE(item3->gestureEventsReceived, 0);
+ QCOMPARE(item4->gestureEventsReceived, 0);
+}
+
+class WinNativePan : public QPanGesture {
+public:
+ WinNativePan() {}
+};
+
+class Pan : public QPanGesture {
+public:
+ Pan() {}
+};
+
+class CustomPan : public QPanGesture {
+public:
+ CustomPan() {}
+};
+
+// Recognizer for active gesture triggers on mouse press
+class PanRecognizer : public QGestureRecognizer {
+public:
+ enum PanType { Platform, Default, Custom };
+
+ PanRecognizer(int id) : m_id(id) {}
+ QGesture *create(QObject *) {
+ switch(m_id) {
+ case Platform: return new WinNativePan();
+ case Default: return new Pan();
+ default: return new CustomPan();
+ }
+ }
+
+ Result recognize(QGesture *, QObject *, QEvent *) { return QGestureRecognizer::Ignore; }
+
+ const int m_id;
+};
+
+void tst_Gestures::testQGestureRecognizerCleanup()
+{
+ // Clean first the current recognizers in QGManager
+ QGestureRecognizer::unregisterRecognizer(Qt::PanGesture);
+
+ // v-- Qt singleton QGManager initialization
+
+ // Mimic QGestureManager: register both default and "platform" recognizers
+ // (this is done in windows when QT_NO_NATIVE_GESTURES is not defined)
+ PanRecognizer *def = new PanRecognizer(PanRecognizer::Default);
+ QGestureRecognizer::registerRecognizer(def);
+ PanRecognizer *plt = new PanRecognizer(PanRecognizer::Platform);
+ QGestureRecognizer::registerRecognizer(plt);
+ qDebug () << "register: default =" << def << "; platform =" << plt;
+
+ // ^-- Qt singleton QGManager initialization
+
+ // Here, application code would start
+
+ // Create QGV (has a QAScrollArea, which uses Qt::PanGesture)
+ QMainWindow *w = new QMainWindow;
+ QGraphicsView *v = new QGraphicsView();
+ w->setCentralWidget(v);
+
+ // Unregister Qt recognizers
+ QGestureRecognizer::unregisterRecognizer(Qt::PanGesture);
+
+ // Register a custom Pan recognizer
+ //QGestureRecognizer::registerRecognizer(new PanRecognizer(PanRecognizer::Custom));
+
+ w->show();
+ QTest::qWaitForWindowShown(w);
+ delete w;
+}
+
+class ReuseCanceledGesturesRecognizer : public QGestureRecognizer
+{
+public:
+ enum Type {
+ RmbAndCancelAllType,
+ LmbType
+ };
+
+ ReuseCanceledGesturesRecognizer(Type type) : m_type(type) {}
+
+ QGesture *create(QObject *) {
+ QGesture *g = new QGesture;
+ return g;
+ }
+
+ Result recognize(QGesture *gesture, QObject *, QEvent *event) {
+ QMouseEvent *me = static_cast<QMouseEvent *>(event);
+ Qt::MouseButton mouseButton(m_type == LmbType ? Qt::LeftButton : Qt::RightButton);
+
+ switch(event->type()) {
+ case QEvent::MouseButtonPress:
+ if (me->button() == mouseButton && gesture->state() == Qt::NoGesture) {
+ gesture->setHotSpot(QPointF(me->globalPos()));
+ if (m_type == RmbAndCancelAllType)
+ gesture->setGestureCancelPolicy(QGesture::CancelAllInContext);
+ return QGestureRecognizer::TriggerGesture;
+ }
+ break;
+ case QEvent::MouseButtonRelease:
+ if (me->button() == mouseButton && gesture->state() > Qt::NoGesture)
+ return QGestureRecognizer::FinishGesture;
+ default:
+ break;
+ }
+ return QGestureRecognizer::Ignore;
+ }
+private:
+ Type m_type;
+};
+
+class ReuseCanceledGesturesWidget : public QGraphicsWidget
+{
+ public:
+ ReuseCanceledGesturesWidget(Qt::GestureType gestureType = Qt::TapGesture, QGraphicsItem *parent = 0)
+ : QGraphicsWidget(parent),
+ m_gestureType(gestureType),
+ m_started(0), m_updated(0), m_canceled(0), m_finished(0)
+ {
+ }
+
+ bool event(QEvent *event) {
+ if (event->type() == QEvent::Gesture) {
+ QGesture *gesture = static_cast<QGestureEvent*>(event)->gesture(m_gestureType);
+ if (gesture) {
+ switch(gesture->state()) {
+ case Qt::GestureStarted: m_started++; break;
+ case Qt::GestureUpdated: m_updated++; break;
+ case Qt::GestureFinished: m_finished++; break;
+ case Qt::GestureCanceled: m_canceled++; break;
+ default: break;
+ }
+ }
+ return true;
+ }
+ if (event->type() == QEvent::GraphicsSceneMousePress) {
+ return true;
+ }
+ return QGraphicsWidget::event(event);
+ }
+
+ int started() { return m_started; }
+ int updated() { return m_updated; }
+ int finished() { return m_finished; }
+ int canceled() { return m_canceled; }
+
+ private:
+ Qt::GestureType m_gestureType;
+ int m_started;
+ int m_updated;
+ int m_canceled;
+ int m_finished;
+};
+
+void tst_Gestures::testReuseCanceledGestures()
+{
+ Qt::GestureType cancellingGestureTypeId = QGestureRecognizer::registerRecognizer(
+ new ReuseCanceledGesturesRecognizer(ReuseCanceledGesturesRecognizer::RmbAndCancelAllType));
+ Qt::GestureType tapGestureTypeId = QGestureRecognizer::registerRecognizer(
+ new ReuseCanceledGesturesRecognizer(ReuseCanceledGesturesRecognizer::LmbType));
+
+ QMainWindow mw;
+ mw.setWindowFlags(Qt::X11BypassWindowManagerHint);
+ QGraphicsView *gv = new QGraphicsView(&mw);
+ QGraphicsScene *scene = new QGraphicsScene;
+
+ gv->setScene(scene);
+ scene->setSceneRect(0,0,100,100);
+
+ // Create container and add to the scene
+ ReuseCanceledGesturesWidget *container = new ReuseCanceledGesturesWidget;
+ container->grabGesture(cancellingGestureTypeId); // << container grabs canceling gesture
+
+ // Create widget and add to the scene
+ ReuseCanceledGesturesWidget *target = new ReuseCanceledGesturesWidget(tapGestureTypeId, container);
+ target->grabGesture(tapGestureTypeId);
+
+ container->setGeometry(scene->sceneRect());
+
+ scene->addItem(container);
+
+ mw.setCentralWidget(gv);
+
+ // Viewport needs to grab all gestures that widgets in scene grab
+ gv->viewport()->grabGesture(cancellingGestureTypeId);
+ gv->viewport()->grabGesture(tapGestureTypeId);
+
+ mw.show();
+ QTest::qWaitForWindowShown(&mw);
+
+ QPoint targetPos(gv->mapFromScene(target->mapToScene(target->rect().center())));
+ targetPos = gv->viewport()->mapFromParent(targetPos);
+
+ // "Tap" starts on child widget
+ QTest::mousePress(gv->viewport(), Qt::LeftButton, 0, targetPos);
+ QCOMPARE(target->started(), 1);
+ QCOMPARE(target->updated(), 0);
+ QCOMPARE(target->finished(), 0);
+ QCOMPARE(target->canceled(), 0);
+
+ // Canceling gesture starts on parent
+ QTest::mousePress(gv->viewport(), Qt::RightButton, 0, targetPos);
+ QCOMPARE(target->started(), 1);
+ QCOMPARE(target->updated(), 0);
+ QCOMPARE(target->finished(), 0);
+ QCOMPARE(target->canceled(), 1); // <- child canceled
+
+ // Canceling gesture ends
+ QTest::mouseRelease(gv->viewport(), Qt::RightButton, 0, targetPos);
+ QCOMPARE(target->started(), 1);
+ QCOMPARE(target->updated(), 0);
+ QCOMPARE(target->finished(), 0);
+ QCOMPARE(target->canceled(), 1);
+
+ // Tap would end if not canceled
+ QTest::mouseRelease(gv->viewport(), Qt::LeftButton, 0, targetPos);
+ QCOMPARE(target->started(), 1);
+ QCOMPARE(target->updated(), 0);
+ QCOMPARE(target->finished(), 0);
+ QCOMPARE(target->canceled(), 1);
+
+ // New "Tap" starts
+ QTest::mousePress(gv->viewport(), Qt::LeftButton, 0, targetPos);
+ QCOMPARE(target->started(), 2);
+ QCOMPARE(target->updated(), 0);
+ QCOMPARE(target->finished(), 0);
+ QCOMPARE(target->canceled(), 1);
+
+ QTest::mouseRelease(gv->viewport(), Qt::LeftButton, 0, targetPos);
+ QCOMPARE(target->started(), 2);
+ QCOMPARE(target->updated(), 0);
+ QCOMPARE(target->finished(), 1);
+ QCOMPARE(target->canceled(), 1);
+}
+
+void tst_Gestures::conflictingGesturesInGraphicsView()
+{
+ QGraphicsScene scene;
+ GraphicsView view(&scene);
+ view.setWindowFlags(Qt::X11BypassWindowManagerHint);
+
+ GestureItem *item1 = new GestureItem("item1");
+ item1->grabGesture(CustomGesture::GestureType);
+ item1->size = QRectF(0, 0, 100, 100);
+ item1->setZValue(2);
+ scene.addItem(item1);
+
+ GestureItem *item2 = new GestureItem("item2");
+ item2->grabGesture(CustomGesture::GestureType);
+ item2->size = QRectF(0, 0, 100, 100);
+ item2->setZValue(5);
+ scene.addItem(item2);
+
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ view.ensureVisible(scene.sceneRect());
+
+ static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1;
+
+ CustomEvent event;
+
+ // nobody accepts override
+ item1->acceptGestureOverride = false;
+ item2->acceptGestureOverride = false;
+ event.hotSpot = mapToGlobal(item2->boundingRect().center(), item2, &view);
+ event.hasHotSpot = true;
+ sendCustomGesture(&event, item2, &scene);
+ QCOMPARE(item2->gestureOverrideEventsReceived, 1);
+ QCOMPARE(item2->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(item1->gestureOverrideEventsReceived, 1);
+ QCOMPARE(item1->gestureEventsReceived, 0);
+
+ item1->reset(); item2->reset();
+
+ // the original target accepts override
+ item1->acceptGestureOverride = false;
+ item2->acceptGestureOverride = true;
+ event.hotSpot = mapToGlobal(item2->boundingRect().center(), item2, &view);
+ event.hasHotSpot = true;
+ sendCustomGesture(&event, item2, &scene);
+ QCOMPARE(item2->gestureOverrideEventsReceived, 1);
+ QCOMPARE(item2->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(item1->gestureOverrideEventsReceived, 0);
+ QCOMPARE(item1->gestureEventsReceived, 0);
+
+ item1->reset(); item2->reset();
+
+ // the item behind accepts override
+ item1->acceptGestureOverride = true;
+ item2->acceptGestureOverride = false;
+ event.hotSpot = mapToGlobal(item2->boundingRect().center(), item2, &view);
+ event.hasHotSpot = true;
+ sendCustomGesture(&event, item2, &scene);
+
+ QCOMPARE(item2->gestureOverrideEventsReceived, 1);
+ QCOMPARE(item2->gestureEventsReceived, 0);
+ QCOMPARE(item1->gestureOverrideEventsReceived, 1);
+ QCOMPARE(item1->gestureEventsReceived, TotalGestureEventsCount);
+}
+
+class NoConsumeWidgetBug13501 :public QWidget
+{
+ Q_OBJECT
+protected:
+ bool event(QEvent *e) {
+ if(e->type() == QEvent::Gesture) {
+ return false;
+ }
+ return QWidget::event(e);
+ }
+};
+
+void tst_Gestures::bug_13501_gesture_not_accepted()
+{
+ // Create a gesture event that is not accepted by any widget
+ // make sure this does not lead to an assert in QGestureManager
+ NoConsumeWidgetBug13501 w;
+ w.grabGesture(Qt::TapGesture);
+ w.show();
+ QTest::qWaitForWindowShown(&w);
+ //QTest::mousePress(&ignoreEvent, Qt::LeftButton);
+ QTest::touchEvent(&w).press(0, QPoint(10, 10), &w);
+}
+
+QTEST_MAIN(tst_Gestures)
+#include "tst_gestures.moc"