From d1a60dcbddbae46aaea655bb55c0c8fd46f38b2c Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Tue, 13 Oct 2009 10:11:54 +0200 Subject: Improved gesture event filtering inside QGraphicsView for QGraphicObjects Reviewed-by: trustme --- src/corelib/global/qnamespace.h | 5 +- src/gui/graphicsview/qgraphicsitem.h | 2 +- src/gui/graphicsview/qgraphicsscene.cpp | 40 +++++- src/gui/graphicsview/qgraphicsscene_p.h | 2 + src/gui/graphicsview/qgraphicsview.cpp | 13 ++ src/gui/kernel/qapplication.cpp | 9 +- src/gui/kernel/qevent.cpp | 16 +++ src/gui/kernel/qevent.h | 5 + src/gui/kernel/qgesture.cpp | 10 -- src/gui/kernel/qgesture.h | 4 - src/gui/kernel/qgesturemanager.cpp | 226 +++++++++++++++++--------------- src/gui/kernel/qgesturemanager_p.h | 10 +- tests/auto/gestures/tst_gestures.cpp | 215 ++++++++++++++++++++++-------- 13 files changed, 372 insertions(+), 185 deletions(-) diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index f28f94e..2b62c6b 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -1631,7 +1631,10 @@ public: enum GestureContext { WidgetGesture = 0, - WidgetWithChildrenGesture = 3 + WidgetWithChildrenGesture = 3, + + ItemGesture = WidgetGesture, + ItemWithChildrenGesture = WidgetWithChildrenGesture }; enum NavigationMode diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h index 2665235..54a7a64 100644 --- a/src/gui/graphicsview/qgraphicsitem.h +++ b/src/gui/graphicsview/qgraphicsitem.h @@ -555,7 +555,7 @@ public: using QObject::children; #endif - void grabGesture(Qt::GestureType type, Qt::GestureContext context = Qt::WidgetWithChildrenGesture); + void grabGesture(Qt::GestureType type, Qt::GestureContext context = Qt::ItemWithChildrenGesture); Q_SIGNALS: void parentChanged(); diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index a624b10..373ee89 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -242,7 +242,6 @@ #include #include #include -#include #include #include #include @@ -251,6 +250,7 @@ #include #endif #include +#include QT_BEGIN_NAMESPACE @@ -1052,6 +1052,14 @@ bool QGraphicsScenePrivate::filterEvent(QGraphicsItem *item, QEvent *event) */ bool QGraphicsScenePrivate::sendEvent(QGraphicsItem *item, QEvent *event) { + if (QGraphicsObject *object = item->toGraphicsObject()) { + QApplicationPrivate *qAppPriv = QApplicationPrivate::instance(); + if (qAppPriv->gestureManager) { + if (qAppPriv->gestureManager->filterEvent(object, event)) + return true; + } + } + if (filterEvent(item, event)) return false; if (filterDescendantEvent(item, event)) @@ -3365,6 +3373,10 @@ bool QGraphicsScene::event(QEvent *event) case QEvent::TouchEnd: d->touchEventHandler(static_cast(event)); break; + case QEvent::Gesture: + case QEvent::GestureOverride: + d->gestureEventHandler(static_cast(event)); + break; default: return QObject::event(event); } @@ -5699,6 +5711,32 @@ void QGraphicsScenePrivate::leaveModal(QGraphicsItem *panel) dispatchHoverEvent(&hoverEvent); } +void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event) +{ + QWidget *viewport = event->widget(); + QList gestures = event->allGestures(); + for (int i = 0; i < gestures.size(); ++i) { + QGesture *gesture = gestures.at(i); + Qt::GestureType gestureType = gesture->gestureType(); + QPoint screenPos = gesture->hotSpot().toPoint(); + QList items = itemsAtPosition(screenPos, QPointF(), viewport); + for (int j = 0; j < items.size(); ++j) { + QGraphicsObject *item = items.at(j)->toGraphicsObject(); + if (!item) + continue; + QGraphicsItemPrivate *d = item->QGraphicsItem::d_func(); + if (d->gestureContext.contains(gestureType)) { + QGestureEvent ev(QList() << gesture); + ev.t = event->t; + ev.spont = event->spont; + ev.setWidget(event->widget()); + sendEvent(item, &ev); + break; + } + } + } +} + QT_END_NAMESPACE #include "moc_qgraphicsscene.cpp" diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index 8073695..4c82b49 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -282,6 +282,8 @@ public: bool allItemsIgnoreTouchEvents; void enableTouchEventsOnViews(); + void gestureEventHandler(QGestureEvent *event); + void updateInputMethodSensitivityInViews(); QList modalPanels; diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 32747cc..710c745 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -2701,6 +2701,19 @@ bool QGraphicsView::viewportEvent(QEvent *event) return true; } + case QEvent::Gesture: + case QEvent::GestureOverride: + { + if (!isEnabled()) + return false; + + if (d->scene && d->sceneInteractionAllowed) { + QGestureEvent *gestureEvent = static_cast(event); + gestureEvent->setWidget(viewport()); + (void) QApplication::sendEvent(d->scene, gestureEvent); + } + return true; + } default: break; } diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index c4249d9..30440eb 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -3639,8 +3639,13 @@ bool QApplication::notify(QObject *receiver, QEvent *e) // walk through parents and check for gestures if (d->gestureManager) { - if (d->gestureManager->filterEvent(receiver, e)) - return true; + if (receiver->isWidgetType()) { + if (d->gestureManager->filterEvent(static_cast(receiver), e)) + return true; + } else if (QGesture *gesture = qobject_cast(receiver)) { + if (d->gestureManager->filterEvent(gesture, e)) + return true; + } } diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index 2ff6d65..e49de02 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -4318,6 +4318,22 @@ bool QGestureEvent::isAccepted(QGesture *gesture) const return gesture ? gesture->d_func()->accept : false; } +/*! + \internal +*/ +void QGestureEvent::setWidget(QWidget *widget) +{ + widget_ = widget; +} + +/*! + \internal +*/ +QWidget *QGestureEvent::widget() const +{ + return widget_; +} + #ifdef Q_NO_USING_KEYWORD /*! \fn void QGestureEvent::setAccepted(bool accepted) diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index 3516222..6cba5fb 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -849,8 +849,13 @@ public: void ignore(QGesture *); bool isAccepted(QGesture *) const; + // internal + void setWidget(QWidget *widget); + QWidget *widget() const; + private: QList gestures_; + QWidget *widget_; }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qgesture.cpp b/src/gui/kernel/qgesture.cpp index fc8df49..e48fd8e 100644 --- a/src/gui/kernel/qgesture.cpp +++ b/src/gui/kernel/qgesture.cpp @@ -154,16 +154,6 @@ Qt::GestureState QGesture::state() const return d_func()->state; } -QObject *QGesture::targetObject() const -{ - return d_func()->targetObject; -} - -void QGesture::setTargetObject(QObject *value) -{ - d_func()->targetObject = value; -} - QPointF QGesture::hotSpot() const { return d_func()->hotSpot; diff --git a/src/gui/kernel/qgesture.h b/src/gui/kernel/qgesture.h index 02eb526..9d1c11e 100644 --- a/src/gui/kernel/qgesture.h +++ b/src/gui/kernel/qgesture.h @@ -67,7 +67,6 @@ class Q_GUI_EXPORT QGesture : public QObject Q_PROPERTY(Qt::GestureType gestureType READ gestureType) Q_PROPERTY(QPointF hotSpot READ hotSpot WRITE setHotSpot RESET unsetHotSpot) Q_PROPERTY(bool hasHotSpot READ hasHotSpot) - Q_PROPERTY(QObject* targetObject READ targetObject WRITE setTargetObject) public: explicit QGesture(QObject *parent = 0); @@ -77,9 +76,6 @@ public: Qt::GestureState state() const; - QObject *targetObject() const; - void setTargetObject(QObject *value); - QPointF hotSpot() const; void setHotSpot(const QPointF &value); bool hasHotSpot() const; diff --git a/src/gui/kernel/qgesturemanager.cpp b/src/gui/kernel/qgesturemanager.cpp index 0f0aef2..4f8a911 100644 --- a/src/gui/kernel/qgesturemanager.cpp +++ b/src/gui/kernel/qgesturemanager.cpp @@ -88,7 +88,8 @@ Qt::GestureType QGestureManager::registerGestureRecognizer(QGestureRecognizer *r { QGesture *dummy = recognizer->createGesture(0); if (!dummy) { - qWarning("QGestureManager::registerGestureRecognizer: the recognizer doesn't provide gesture object"); + qWarning("QGestureManager::registerGestureRecognizer: " + "the recognizer doesn't provide gesture object"); return Qt::GestureType(0); } Qt::GestureType type = dummy->gestureType(); @@ -107,7 +108,7 @@ void QGestureManager::unregisterGestureRecognizer(Qt::GestureType) } -QGesture* QGestureManager::getState(QObject *object, Qt::GestureType type) +QGesture *QGestureManager::getState(QObject *object, Qt::GestureType type) { // if the widget is being deleted we should be carefull and not to // create a new state, as it will create QWeakPointer which doesnt work @@ -115,9 +116,14 @@ QGesture* QGestureManager::getState(QObject *object, Qt::GestureType type) if (object->isWidgetType()) { if (static_cast(object)->d_func()->data.in_destructor) return 0; + } else if (QGesture *g = qobject_cast(object)) { + return g; + } else { + Q_ASSERT(qobject_cast(object)); } - QWeakPointer state = objectGestures.value(QGestureManager::ObjectGesture(object, type)); + QWeakPointer state = + objectGestures.value(QGestureManager::ObjectGesture(object, type)); if (!state) { QGestureRecognizer *recognizer = recognizers.value(type); if (recognizer) { @@ -136,7 +142,9 @@ QGesture* QGestureManager::getState(QObject *object, Qt::GestureType type) return state.data(); } -bool QGestureManager::filterEvent(QObject *receiver, QEvent *event) +bool QGestureManager::filterEventThroughContexts(const QMap &contexts, + QObject *receiver, QEvent *event) { QSet triggeredGestures; QSet finishedGestures; @@ -144,93 +152,20 @@ bool QGestureManager::filterEvent(QObject *receiver, QEvent *event) QSet canceledGestures; QSet notGestures; - QGraphicsObject *graphicsObject = qobject_cast(receiver); - if (receiver->isWidgetType() || graphicsObject) { - QMap contexts; - if (receiver->isWidgetType()) { - QWidget *w = static_cast(receiver); - if (!w->d_func()->gestureContext.isEmpty()) { - typedef QMap::const_iterator ContextIterator; - for(ContextIterator it = w->d_func()->gestureContext.begin(), - e = w->d_func()->gestureContext.end(); it != e; ++it) { - contexts.insertMulti(w, it.key()); - } - } - // find all gesture contexts for the widget tree - w = w->parentWidget(); - while (w) - { - typedef QMap::const_iterator ContextIterator; - for (ContextIterator it = w->d_func()->gestureContext.begin(), - e = w->d_func()->gestureContext.end(); it != e; ++it) { - if (it.value() == Qt::WidgetWithChildrenGesture) - contexts.insertMulti(w, it.key()); - } - w = w->parentWidget(); - } - } else { - QGraphicsObject *item = graphicsObject; - if (!item->QGraphicsItem::d_func()->gestureContext.isEmpty()) { - typedef QMap::const_iterator ContextIterator; - for(ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.begin(), - e = item->QGraphicsItem::d_func()->gestureContext.end(); it != e; ++it) { - contexts.insertMulti(item, it.key()); - } - } - // find all gesture contexts for the widget tree - item = item->parentObject(); - while (item) - { - typedef QMap::const_iterator ContextIterator; - for (ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.begin(), - e = item->QGraphicsItem::d_func()->gestureContext.end(); it != e; ++it) { - if (it.value() == Qt::WidgetWithChildrenGesture) - contexts.insertMulti(item, it.key()); - } - item = item->parentObject(); - } - } - // filter the event through recognizers - typedef QMap::const_iterator ContextIterator; - for (ContextIterator cit = contexts.begin(), ce = contexts.end(); cit != ce; ++cit) { - Qt::GestureType gestureType = cit.value(); - QMap::const_iterator - rit = recognizers.lowerBound(gestureType), - re = recognizers.upperBound(gestureType); - for (; rit != re; ++rit) { - QGestureRecognizer *recognizer = rit.value(); - QObject *target = cit.key(); - QGesture *state = getState(target, gestureType); - if (!state) - continue; - QGestureRecognizer::Result result = recognizer->filterEvent(state, target, event); - QGestureRecognizer::Result type = result & QGestureRecognizer::ResultState_Mask; - if (type == QGestureRecognizer::GestureTriggered) { - DEBUG() << "QGestureManager: gesture triggered: " << state; - triggeredGestures << state; - } else if (type == QGestureRecognizer::GestureFinished) { - DEBUG() << "QGestureManager: gesture finished: " << state; - finishedGestures << state; - } else if (type == QGestureRecognizer::MaybeGesture) { - DEBUG() << "QGestureManager: maybe gesture: " << state; - newMaybeGestures << state; - } else if (type == QGestureRecognizer::NotGesture) { - DEBUG() << "QGestureManager: not gesture: " << state; - notGestures << state; - } else if (type == QGestureRecognizer::Ignore) { - DEBUG() << "QGestureManager: gesture ignored the event: " << state; - } else { - DEBUG() << "QGestureManager: hm, lets assume the recognizer ignored the event: " << state; - } - if (result & QGestureRecognizer::ConsumeEventHint) { - DEBUG() << "QGestureManager: we were asked to consume the event: " << state; - //TODO: consume events if asked - } - } - } - } else if (QGesture *state = qobject_cast(receiver)) { - if (QGestureRecognizer *recognizer = gestureToRecognizer.value(state)) { - QGestureRecognizer::Result result = recognizer->filterEvent(state, state, event); + // filter the event through recognizers + typedef QMap::const_iterator ContextIterator; + for (ContextIterator cit = contexts.begin(), ce = contexts.end(); cit != ce; ++cit) { + Qt::GestureType gestureType = cit.value(); + QMap::const_iterator + rit = recognizers.lowerBound(gestureType), + re = recognizers.upperBound(gestureType); + for (; rit != re; ++rit) { + QGestureRecognizer *recognizer = rit.value(); + QObject *target = cit.key(); + QGesture *state = getState(target, gestureType); + if (!state) + continue; + QGestureRecognizer::Result result = recognizer->filterEvent(state, target, event); QGestureRecognizer::Result type = result & QGestureRecognizer::ResultState_Mask; if (type == QGestureRecognizer::GestureTriggered) { DEBUG() << "QGestureManager: gesture triggered: " << state; @@ -247,11 +182,15 @@ bool QGestureManager::filterEvent(QObject *receiver, QEvent *event) } else if (type == QGestureRecognizer::Ignore) { DEBUG() << "QGestureManager: gesture ignored the event: " << state; } else { - DEBUG() << "QGestureManager: hm, lets assume the recognizer ignored the event: " << state; + DEBUG() << "QGestureManager: hm, lets assume the recognizer" + << "ignored the event: " << state; + } + if (result & QGestureRecognizer::ConsumeEventHint) { + DEBUG() << "QGestureManager: we were asked to consume the event: " + << state; + //TODO: consume events if asked } } - } else { - return false; } QSet startedGestures = triggeredGestures - activeGestures; @@ -260,7 +199,8 @@ bool QGestureManager::filterEvent(QObject *receiver, QEvent *event) // check if a running gesture switched back to maybe state QSet activeToMaybeGestures = activeGestures & newMaybeGestures; - // check if a running gesture switched back to not gesture state, i.e. were canceled + // check if a running gesture switched back to not gesture state, + // i.e. were canceled QSet activeToCancelGestures = activeGestures & notGestures; canceledGestures += activeToCancelGestures; @@ -271,7 +211,9 @@ bool QGestureManager::filterEvent(QObject *receiver, QEvent *event) timer.start(3000, this); } // kill timers for gestures that were in maybe state - QSet notMaybeGestures = (startedGestures | triggeredGestures | finishedGestures | canceledGestures | notGestures); + QSet notMaybeGestures = (startedGestures | triggeredGestures + | finishedGestures | canceledGestures + | notGestures); foreach(QGesture *gesture, notMaybeGestures) { QMap::iterator it = maybeGestures.find(gesture); @@ -294,7 +236,9 @@ bool QGestureManager::filterEvent(QObject *receiver, QEvent *event) // probably those are "singleshot" gestures so we'll fake the started state. foreach (QGesture *gesture, notStarted) gesture->d_func()->state = Qt::GestureStarted; - deliverEvents(notStarted, receiver); + QSet undeliveredGestures; + deliverEvents(notStarted, receiver, &undeliveredGestures); + finishedGestures -= undeliveredGestures; } activeGestures += startedGestures; @@ -328,10 +272,15 @@ bool QGestureManager::filterEvent(QObject *receiver, QEvent *event) << "\n\tcanceled:" << canceledGestures; } - deliverEvents(startedGestures+triggeredGestures+finishedGestures+canceledGestures, receiver); + QSet undeliveredGestures; + deliverEvents(startedGestures+triggeredGestures+finishedGestures+canceledGestures, + receiver, &undeliveredGestures); + + activeGestures -= undeliveredGestures; // reset gestures that ended - QSet endedGestures = finishedGestures + canceledGestures; + QSet endedGestures = + finishedGestures + canceledGestures + undeliveredGestures; foreach (QGesture *gesture, endedGestures) { if (QGestureRecognizer *recognizer = gestureToRecognizer.value(gesture, 0)) { recognizer->reset(gesture); @@ -341,7 +290,68 @@ bool QGestureManager::filterEvent(QObject *receiver, QEvent *event) return false; } -void QGestureManager::deliverEvents(const QSet &gestures, QObject *lastReceiver) +bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event) +{ + QMap contexts; + QWidget *w = receiver; + if (!w->d_func()->gestureContext.isEmpty()) { + typedef QMap::const_iterator ContextIterator; + for(ContextIterator it = w->d_func()->gestureContext.begin(), + e = w->d_func()->gestureContext.end(); it != e; ++it) { + contexts.insertMulti(w, it.key()); + } + } + // find all gesture contexts for the widget tree + w = w->parentWidget(); + while (w) + { + typedef QMap::const_iterator ContextIterator; + for (ContextIterator it = w->d_func()->gestureContext.begin(), + e = w->d_func()->gestureContext.end(); it != e; ++it) { + if (it.value() == Qt::WidgetWithChildrenGesture) + contexts.insertMulti(w, it.key()); + } + w = w->parentWidget(); + } + return filterEventThroughContexts(contexts , receiver, event); +} + +bool QGestureManager::filterEvent(QGraphicsObject *graphicsObject, QEvent *event) +{ + QMap contexts; + QGraphicsObject *item = graphicsObject; + if (!item->QGraphicsItem::d_func()->gestureContext.isEmpty()) { + typedef QMap::const_iterator ContextIterator; + for(ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.begin(), + e = item->QGraphicsItem::d_func()->gestureContext.end(); it != e; ++it) { + contexts.insertMulti(item, it.key()); + } + } + // find all gesture contexts for the graphics object tree + item = item->parentObject(); + while (item) + { + typedef QMap::const_iterator ContextIterator; + for (ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.begin(), + e = item->QGraphicsItem::d_func()->gestureContext.end(); it != e; ++it) { + if (it.value() == Qt::ItemWithChildrenGesture) + contexts.insertMulti(item, it.key()); + } + item = item->parentObject(); + } + return filterEventThroughContexts(contexts, graphicsObject, event); +} + +bool QGestureManager::filterEvent(QGesture *state, QEvent *event) +{ + QMap contexts; + contexts.insert(state, state->gestureType()); + return filterEventThroughContexts(contexts, 0, event); +} + +void QGestureManager::deliverEvents(const QSet &gestures, + QObject *lastReceiver, + QSet *undeliveredGestures) { if (gestures.isEmpty()) return; @@ -360,16 +370,12 @@ void QGestureManager::deliverEvents(const QSet &gestures, QObject *la if (gesture->hasHotSpot()) { // guess the target using the hotspot of the gesture QPoint pt = gesture->hotSpot().toPoint(); - if (!pt.isNull()) { - if (QWidget *w = qApp->topLevelAt(pt)) - target = w->childAt(w->mapFromGlobal(pt)); + if (QWidget *w = qApp->topLevelAt(pt)) { + target = w->childAt(w->mapFromGlobal(pt)); } } - if (!target) { - target = gesture->targetObject(); - if (!target) - target = lastReceiver; - } + if (!target) + target = lastReceiver; } if (target) { gestureTargets.insert(gesture, target); @@ -379,11 +385,13 @@ void QGestureManager::deliverEvents(const QSet &gestures, QObject *la } else { qWarning() << "QGestureManager::deliverEvent: could not find the target for gesture" << gesture->gestureType(); + undeliveredGestures->insert(gesture); } } typedef QMultiHash::const_iterator ObjectGesturesIterator; - for (ObjectGesturesIterator it = objectGestures.begin(), e = objectGestures.end(); it != e; ++it) { + for (ObjectGesturesIterator it = objectGestures.begin(), + e = objectGestures.end(); it != e; ++it) { QObject *object1 = it.key(); QWidget *widget1 = qobject_cast(object1); QGraphicsObject *item1 = qobject_cast(object1); diff --git a/src/gui/kernel/qgesturemanager_p.h b/src/gui/kernel/qgesturemanager_p.h index c61819f..5fc02ab 100644 --- a/src/gui/kernel/qgesturemanager_p.h +++ b/src/gui/kernel/qgesturemanager_p.h @@ -61,6 +61,7 @@ QT_BEGIN_NAMESPACE class QBasicTimer; +class QGraphicsObject; class QGestureManager : public QObject { Q_OBJECT @@ -71,13 +72,17 @@ public: Qt::GestureType registerGestureRecognizer(QGestureRecognizer *recognizer); void unregisterGestureRecognizer(Qt::GestureType type); - bool filterEvent(QObject *receiver, QEvent *event); + bool filterEvent(QWidget *receiver, QEvent *event); + bool filterEvent(QGesture *receiver, QEvent *event); + bool filterEvent(QGraphicsObject *receiver, QEvent *event); // declared in qapplication.cpp static QGestureManager* instance(); protected: void timerEvent(QTimerEvent *event); + bool filterEventThroughContexts(const QMap &contexts, + QObject *receiver, QEvent *event); private: QMultiMap recognizers; @@ -117,7 +122,8 @@ private: int lastCustomGestureId; QGesture *getState(QObject *widget, Qt::GestureType gesture); - void deliverEvents(const QSet &gestures, QObject *lastReceiver); + void deliverEvents(const QSet &gestures, QObject *lastReceiver, + QSet *undeliveredGestures); }; QT_END_NAMESPACE diff --git a/tests/auto/gestures/tst_gestures.cpp b/tests/auto/gestures/tst_gestures.cpp index baf90fa..3ce5b86 100644 --- a/tests/auto/gestures/tst_gestures.cpp +++ b/tests/auto/gestures/tst_gestures.cpp @@ -56,6 +56,11 @@ //TESTED_CLASS= //TESTED_FILES= +static QPointF mapToGlobal(const QPointF &pt, QGraphicsItem *item, QGraphicsView *view) +{ + return view->mapToGlobal(view->mapFromScene(item->mapToScene(pt))); +} + class CustomGesture : public QGesture { Q_OBJECT @@ -63,11 +68,10 @@ public: static Qt::GestureType GestureType; CustomGesture(QObject *parent = 0) - : QGesture(parent), target(0), serial(0) + : QGesture(parent), serial(0) { } - QObject *target; int serial; static const int SerialMaybeThreshold; @@ -86,13 +90,13 @@ public: CustomEvent(int serial_ = 0) : QEvent(QEvent::Type(CustomEvent::EventType)), - serial(serial_), targetObject(0) + serial(serial_), hasHotSpot(false) { } int serial; - QObject *targetObject; - QPoint hotSpot; + QPointF hotSpot; + bool hasHotSpot; }; int CustomEvent::EventType = 0; @@ -117,8 +121,8 @@ public: CustomGesture *g = static_cast(state); CustomEvent *e = static_cast(event); g->serial = e->serial; - g->setTargetObject(e->targetObject); - g->setHotSpot(e->hotSpot); + if (e->hasHotSpot) + g->setHotSpot(e->hotSpot); ++eventsCounter; if (g->serial >= CustomGesture::SerialFinishedThreshold) result |= QGestureRecognizer::GestureFinished; @@ -231,24 +235,15 @@ protected: } }; -static void sendCustomGesture(QObject *object) +static void sendCustomGesture(CustomEvent *event, QObject *object, QGraphicsScene *scene = 0) { - CustomEvent ev; - ev.targetObject = object; for (int i = CustomGesture::SerialMaybeThreshold; i <= CustomGesture::SerialFinishedThreshold; ++i) { - ev.serial = i; - QApplication::sendEvent(object, &ev); - } -} -static void sendCustomGesture(QObject *object, QObject *target) -{ - CustomEvent ev; - ev.targetObject = target; - for (int i = CustomGesture::SerialMaybeThreshold; - i <= CustomGesture::SerialFinishedThreshold; ++i) { - ev.serial = i; - QApplication::sendEvent(object, &ev); + event->serial = i; + if (scene) + scene->sendEvent(qobject_cast(object), event); + else + QApplication::sendEvent(object, event); } } @@ -276,6 +271,7 @@ private slots: void unknownGesture(); void graphicsItemGesture(); void explicitGraphicsObjectTarget(); + void gestureOverChildGraphicsItem(); }; tst_Gestures::tst_Gestures() @@ -309,7 +305,8 @@ void tst_Gestures::customGesture() { GestureWidget widget; widget.grabGesture(CustomGesture::GestureType, Qt::WidgetGesture); - sendCustomGesture(&widget); + CustomEvent event; + sendCustomGesture(&event, &widget); static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1; static const int TotalCustomEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialMaybeThreshold + 1; @@ -354,7 +351,8 @@ void tst_Gestures::gestureOverChild() widget.grabGesture(CustomGesture::GestureType, Qt::WidgetGesture); - sendCustomGesture(child); + CustomEvent event; + sendCustomGesture(&event, child); static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1; static const int TotalCustomEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialMaybeThreshold + 1; @@ -372,7 +370,7 @@ void tst_Gestures::gestureOverChild() widget.reset(); child->reset(); - sendCustomGesture(child); + sendCustomGesture(&event, child); QCOMPARE(child->customEventsReceived, TotalCustomEventsCount); QCOMPARE(widget.customEventsReceived, 0); @@ -403,7 +401,8 @@ void tst_Gestures::multipleWidgetOnlyGestureInTree() static const int TotalCustomEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialMaybeThreshold + 1; // sending events to the child and making sure there is no conflict - sendCustomGesture(child); + CustomEvent event; + sendCustomGesture(&event, child); QCOMPARE(child->customEventsReceived, TotalCustomEventsCount); QCOMPARE(parent.customEventsReceived, 0); @@ -416,7 +415,7 @@ void tst_Gestures::multipleWidgetOnlyGestureInTree() child->reset(); // same for the parent widget - sendCustomGesture(&parent); + sendCustomGesture(&event, &parent); QCOMPARE(child->customEventsReceived, 0); QCOMPARE(parent.customEventsReceived, TotalCustomEventsCount); @@ -443,7 +442,8 @@ void tst_Gestures::conflictingGestures() child->acceptGestureOverride = true; // sending events to the child and making sure there is no conflict - sendCustomGesture(child); + CustomEvent event; + sendCustomGesture(&event, child); QCOMPARE(child->gestureOverrideEventsReceived, TotalGestureEventsCount); QCOMPARE(child->gestureEventsReceived, 0); @@ -458,7 +458,7 @@ void tst_Gestures::conflictingGestures() child->acceptGestureOverride = false; // sending events to the child and making sure there is no conflict - sendCustomGesture(child); + sendCustomGesture(&event, child); QCOMPARE(child->gestureOverrideEventsReceived, TotalGestureEventsCount); QCOMPARE(child->gestureEventsReceived, 0); @@ -473,7 +473,7 @@ void tst_Gestures::conflictingGestures() child->acceptGestureOverride = false; // sending events to the child and making sure there is no conflict - sendCustomGesture(child); + sendCustomGesture(&event, child); QCOMPARE(child->gestureOverrideEventsReceived, TotalGestureEventsCount); QCOMPARE(child->gestureEventsReceived, TotalGestureEventsCount); @@ -508,7 +508,8 @@ void tst_Gestures::unknownGesture() widget.grabGesture(Qt::CustomGesture, Qt::WidgetGesture); widget.grabGesture(Qt::GestureType(Qt::PanGesture+512), Qt::WidgetGesture); - sendCustomGesture(&widget); + CustomEvent event; + sendCustomGesture(&event, &widget); static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1; @@ -554,6 +555,15 @@ public: QRectF size; + void reset() + { + customEventsReceived = 0; + gestureEventsReceived = 0; + gestureOverrideEventsReceived = 0; + events.clear(); + overrideEvents.clear(); + } + protected: QRectF boundingRect() const { @@ -616,13 +626,37 @@ void tst_Gestures::graphicsItemGesture() scene.addItem(item); item->setPos(100, 100); - item->grabGesture(CustomGesture::GestureType); + view.show(); + QTest::qWaitForWindowShown(&view); + view.ensureVisible(scene.sceneRect()); - sendCustomGesture(item); + view.viewport()->grabGesture(CustomGesture::GestureType, Qt::WidgetGesture); + item->grabGesture(CustomGesture::GestureType); static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1; static const int TotalCustomEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialMaybeThreshold + 1; + CustomEvent event; + 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(); + + // 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); @@ -643,41 +677,112 @@ void tst_Gestures::explicitGraphicsObjectTarget() GestureItem *item1 = new GestureItem; scene.addItem(item1); item1->setPos(100, 100); - item1->grabGesture(CustomGesture::GestureType); GestureItem *item2 = new GestureItem; scene.addItem(item2); item2->setPos(100, 100); - item2->grabGesture(CustomGesture::GestureType); - GestureItem *item3 = new GestureItem; - scene.addItem(item3); - item3->setParentItem(item2); - item3->setPos(0, 0); - item3->grabGesture(CustomGesture::GestureType); + GestureItem *item2_child1 = new GestureItem; + scene.addItem(item2_child1); + item2_child1->setParentItem(item2); + item2_child1->setPos(10, 10); + + view.show(); + QTest::qWaitForWindowShown(&view); + view.ensureVisible(scene.sceneRect()); - // sending events to item1, but the targetObject for the gesture is item2. - sendCustomGesture(item1, item3); + view.viewport()->grabGesture(CustomGesture::GestureType, Qt::WidgetGesture); + item1->grabGesture(CustomGesture::GestureType, Qt::ItemGesture); + item2->grabGesture(CustomGesture::GestureType, Qt::ItemGesture); + item2_child1->grabGesture(CustomGesture::GestureType, Qt::ItemGesture); static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1; - static const int TotalCustomEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialMaybeThreshold + 1; - QCOMPARE(item1->customEventsReceived, TotalCustomEventsCount); + // 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, 0); - QCOMPARE(item3->customEventsReceived, 0); - QCOMPARE(item3->gestureEventsReceived, TotalGestureEventsCount); - QCOMPARE(item3->gestureOverrideEventsReceived, 0); - QCOMPARE(item3->events.all.size(), TotalGestureEventsCount); - for(int i = 0; i < item3->events.all.size(); ++i) - QCOMPARE(item3->events.all.at(i), CustomGesture::GestureType); - QCOMPARE(item3->events.started.size(), 1); - QCOMPARE(item3->events.updated.size(), TotalGestureEventsCount - 2); - QCOMPARE(item3->events.finished.size(), 1); - QCOMPARE(item3->events.canceled.size(), 0); - QCOMPARE(item2->customEventsReceived, 0); + QCOMPARE(item2_child1->gestureEventsReceived, TotalGestureEventsCount); + QCOMPARE(item2_child1->gestureOverrideEventsReceived, 0); + 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, 0); +} + +void tst_Gestures::gestureOverChildGraphicsItem() +{ + QGraphicsScene scene; + QGraphicsView view(&scene); + + GestureItem *item0 = new GestureItem; + scene.addItem(item0); + item0->setPos(0, 0); + + GestureItem *item1 = new GestureItem; + scene.addItem(item1); + item1->setPos(100, 100); + + GestureItem *item2 = new GestureItem; + scene.addItem(item2); + item2->setPos(100, 100); + + GestureItem *item2_child1 = new GestureItem; + scene.addItem(item2_child1); + item2_child1->setParentItem(item2); + item2_child1->setPos(0, 0); + + view.show(); + QTest::qWaitForWindowShown(&view); + view.ensureVisible(scene.sceneRect()); + + view.viewport()->grabGesture(CustomGesture::GestureType, Qt::WidgetGesture); + 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); + QEXPECT_FAIL("", "need to fix gesture event propagation inside graphicsview", Continue); + QCOMPARE(item1->gestureEventsReceived, TotalGestureEventsCount); + QCOMPARE(item1->gestureOverrideEventsReceived, 0); + + item0->reset(); item1->reset(); item2->reset(); item2_child1->reset(); + item2->grabGesture(CustomGesture::GestureType); + + 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); + QEXPECT_FAIL("", "need to fix gesture event propagation inside graphicsview", Continue); + QCOMPARE(item2->gestureEventsReceived, TotalGestureEventsCount); + QEXPECT_FAIL("", "need to fix gesture event propagation inside graphicsview", Continue); + QCOMPARE(item2->gestureOverrideEventsReceived, TotalGestureEventsCount); + QCOMPARE(item1->gestureEventsReceived, 0); + QEXPECT_FAIL("", "need to fix gesture event propagation inside graphicsview", Continue); + QCOMPARE(item1->gestureOverrideEventsReceived, TotalGestureEventsCount); } QTEST_MAIN(tst_Gestures) -- cgit v0.12