summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp435
-rw-r--r--src/gui/graphicsview/qgraphicsscene_p.h13
-rw-r--r--tests/auto/gestures/tst_gestures.cpp139
3 files changed, 343 insertions, 244 deletions
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index 34543e3..40e1d2c 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -693,6 +693,18 @@ void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item)
--selectionChanging;
if (!selectionChanging && selectedItems.size() != oldSelectedItemsSize)
emit q->selectionChanged();
+
+ QHash<QGesture *, QGraphicsObject *>::iterator it;
+ for (it = gestureTargets.begin(); it != gestureTargets.end();) {
+ if (it.value() == item)
+ it = gestureTargets.erase(it);
+ else
+ ++it;
+ }
+ QGraphicsObject *dummy = static_cast<QGraphicsObject *>(item);
+ cachedTargetItems.removeOne(dummy);
+ cachedItemGestures.remove(dummy);
+ cachedAlreadyDeliveredGestures.remove(dummy);
}
/*!
@@ -5900,43 +5912,51 @@ void QGraphicsScenePrivate::leaveModal(QGraphicsItem *panel)
dispatchHoverEvent(&hoverEvent);
}
-void QGraphicsScenePrivate::getGestureTargets(const QSet<QGesture *> &gestures,
- QMap<Qt::GestureType, QGesture *> *conflictedGestures,
- QList<QList<QGraphicsObject *> > *conflictedItems,
- QHash<QGesture *, QGraphicsObject *> *normalGestures)
+void QGraphicsScenePrivate::gestureTargetsAtHotSpots(const QSet<QGesture *> &gestures,
+ Qt::GestureFlag flag,
+ QHash<QGraphicsObject *, QSet<QGesture *> > *targets,
+ QSet<QGraphicsObject *> *itemsSet,
+ QSet<QGesture *> *normal,
+ QSet<QGesture *> *conflicts)
{
+ QSet<QGesture *> normalGestures; // that are not in conflicted state.
foreach (QGesture *gesture, gestures) {
- Qt::GestureType gestureType = gesture->gestureType();
- if (gesture->hasHotSpot()) {
- QList<QGraphicsItem *> items = itemsAtPosition(QPoint(), gesture->d_func()->sceneHotSpot, 0);
- QList<QGraphicsObject *> result;
- for (int j = 0; j < items.size(); ++j) {
- QGraphicsItem *item = items.at(j);
+ if (!gesture->hasHotSpot())
+ continue;
+ const Qt::GestureType gestureType = gesture->gestureType();
+ QList<QGraphicsItem *> items = itemsAtPosition(QPoint(), gesture->d_func()->sceneHotSpot, 0);
+ for (int j = 0; j < items.size(); ++j) {
+ QGraphicsItem *item = items.at(j);
- // Check if the item is blocked by a modal panel and use it as
- // a target instead of this item.
- (void) item->isBlockedByModalPanel(&item);
+ // Check if the item is blocked by a modal panel and use it as
+ // a target instead of this item.
+ (void) item->isBlockedByModalPanel(&item);
- if (QGraphicsObject *itemobj = item->toGraphicsObject()) {
- QGraphicsItemPrivate *d = item->d_func();
- if (d->gestureContext.contains(gestureType)) {
- result.append(itemobj);
+ if (QGraphicsObject *itemobj = item->toGraphicsObject()) {
+ QGraphicsItemPrivate *d = item->QGraphicsItem::d_func();
+ QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator it =
+ d->gestureContext.find(gestureType);
+ if (it != d->gestureContext.end() && (!flag || (it.value() & flag))) {
+ if (normalGestures.contains(gesture)) {
+ normalGestures.remove(gesture);
+ if (conflicts)
+ conflicts->insert(gesture);
+ } else {
+ normalGestures.insert(gesture);
}
+ if (targets)
+ (*targets)[itemobj].insert(gesture);
+ if (itemsSet)
+ (*itemsSet).insert(itemobj);
}
- // Don't propagate through panels.
- if (item->isPanel())
- break;
- }
- DEBUG() << "QGraphicsScenePrivate::getGestureTargets:"
- << gesture << result;
- if (result.size() == 1) {
- normalGestures->insert(gesture, result.first());
- } else if (!result.isEmpty()) {
- conflictedGestures->insert(gestureType, gesture);
- conflictedItems->append(result);
}
+ // Don't propagate through panels.
+ if (item->isPanel())
+ break;
}
}
+ if (normal)
+ *normal = normalGestures;
}
void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event)
@@ -5952,18 +5972,14 @@ void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event)
DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
<< "Delivering gestures:" << allGestures;
- typedef QHash<QGraphicsObject *, QList<QGesture *> > GesturesPerItem;
- GesturesPerItem gesturesPerItem;
-
- // gestures that are only supposed to propagate to parent items.
- QSet<QGesture *> parentPropagatedGestures;
-
QSet<QGesture *> startedGestures;
+ QPoint delta = graphicsView->mapFromGlobal(QPoint());
+ QTransform toScene = QTransform::fromTranslate(delta.x(), delta.y())
+ * graphicsView->viewportTransform().inverted();
foreach (QGesture *gesture, allGestures) {
// cache scene coordinates of the hot spot
if (gesture->hasHotSpot()) {
- gesture->d_func()->sceneHotSpot = graphicsView->mapToScene(
- graphicsView->mapFromGlobal(gesture->hotSpot().toPoint()));
+ gesture->d_func()->sceneHotSpot = toScene.map(gesture->hotSpot());
} else {
gesture->d_func()->sceneHotSpot = QPointF();
}
@@ -5974,243 +5990,184 @@ void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event)
// then the only one interested in gesture is the view/scene
if (gesture->state() == Qt::GestureStarted)
startedGestures.insert(gesture);
- } else {
- gesturesPerItem[target].append(gesture);
- Qt::GestureFlags flags =
- target->QGraphicsItem::d_func()->gestureContext.value(gesture->gestureType());
- if (flags & Qt::IgnoredGesturesPropagateToParent)
- parentPropagatedGestures.insert(gesture);
}
}
- QMap<Qt::GestureType, QGesture *> conflictedGestures;
- QList<QList<QGraphicsObject *> > conflictedItems;
- QHash<QGesture *, QGraphicsObject *> normalGestures;
- getGestureTargets(startedGestures, &conflictedGestures, &conflictedItems,
- &normalGestures);
- DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
- << "Conflicting gestures:" << conflictedGestures.values() << conflictedItems;
- Q_ASSERT((conflictedGestures.isEmpty() && conflictedItems.isEmpty()) ||
- (!conflictedGestures.isEmpty() && !conflictedItems.isEmpty()));
-
- // gestures that were sent as override events, but no one accepted them
- QHash<QGesture *, QGraphicsObject *> ignoredConflictedGestures;
-
- // deliver conflicted gestures as override events first
- while (!conflictedGestures.isEmpty() && !conflictedItems.isEmpty()) {
- // get the topmost item to deliver the override event
- Q_ASSERT(!conflictedItems.isEmpty());
- Q_ASSERT(!conflictedItems.first().isEmpty());
- QGraphicsObject *topmost = conflictedItems.first().first();
- for (int i = 1; i < conflictedItems.size(); ++i) {
- QGraphicsObject *item = conflictedItems.at(i).first();
- if (qt_closestItemFirst(item, topmost)) {
- topmost = item;
- }
- }
- // get a list of gestures to send to the item
- QList<Qt::GestureType> grabbedGestures =
- topmost->QGraphicsItem::d_func()->gestureContext.keys();
- QList<QGesture *> gestures;
- for (int i = 0; i < grabbedGestures.size(); ++i) {
- if (QGesture *g = conflictedGestures.value(grabbedGestures.at(i), 0)) {
- gestures.append(g);
- if (!ignoredConflictedGestures.contains(g))
- ignoredConflictedGestures.insert(g, topmost);
- }
- }
-
- // send gesture override to the topmost item
- QGestureEvent ev(gestures);
- ev.t = QEvent::GestureOverride;
- ev.setWidget(event->widget());
- // mark event and individual gestures as ignored
- ev.ignore();
- foreach(QGesture *g, gestures)
- ev.setAccepted(g, false);
+ if (!startedGestures.isEmpty()) {
+ QSet<QGesture *> normalGestures; // that have just one target
+ QSet<QGesture *> conflictedGestures; // that have multiple possible targets
+ gestureTargetsAtHotSpots(startedGestures, Qt::GestureFlag(0), &cachedItemGestures, 0,
+ &normalGestures, &conflictedGestures);
+ cachedTargetItems = cachedItemGestures.keys();
+ qSort(cachedTargetItems.begin(), cachedTargetItems.end(), qt_closestItemFirst);
DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
- << "delivering override to"
- << topmost << gestures;
- sendEvent(topmost, &ev);
- // mark all accepted gestures to deliver them as normal gesture events
- foreach (QGesture *g, gestures) {
- if (ev.isAccepted() || ev.isAccepted(g)) {
- conflictedGestures.remove(g->gestureType());
- gestureTargets.remove(g);
- // add the gesture to the list of normal delivered gestures
- normalGestures.insert(g, topmost);
+ << "Conflicting gestures:" << conflictedGestures;
+
+ // deliver conflicted gestures as override events AND remember
+ // initial gesture targets
+ if (!conflictedGestures.isEmpty()) {
+ for (int i = 0; i < cachedTargetItems.size(); ++i) {
+ QWeakPointer<QGraphicsObject> item = cachedTargetItems.at(i);
+
+ // get gestures to deliver to the current item
+ QSet<QGesture *> gestures = conflictedGestures & cachedItemGestures.value(item.data());
+ if (gestures.isEmpty())
+ continue;
+
DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
- << "override was accepted:"
- << g << topmost;
- ignoredConflictedGestures.remove(g);
+ << "delivering override to"
+ << item.data() << gestures;
+ // send gesture override
+ QGestureEvent ev(gestures.toList());
+ ev.t = QEvent::GestureOverride;
+ ev.setWidget(event->widget());
+ // mark event and individual gestures as ignored
+ ev.ignore();
+ foreach(QGesture *g, gestures)
+ ev.setAccepted(g, false);
+ sendEvent(item.data(), &ev);
+ // mark all accepted gestures to deliver them as normal gesture events
+ foreach (QGesture *g, gestures) {
+ if (ev.isAccepted() || ev.isAccepted(g)) {
+ conflictedGestures.remove(g);
+ // mark the item as a gesture target
+ if (item)
+ gestureTargets.insert(g, item.data());
+ DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
+ << "override was accepted:"
+ << g << item.data();
+ }
+ // remember the first item that received the override event
+ // as it most likely become a target if noone else accepts
+ // the override event
+ if (!gestureTargets.contains(g) && item)
+ gestureTargets.insert(g, item.data());
+
+ }
+ if (conflictedGestures.isEmpty())
+ break;
}
}
- // remove the item that we've already delivered from the list
- for (int i = 0; i < conflictedItems.size(); ) {
- QList<QGraphicsObject *> &items = conflictedItems[i];
- if (items.first() == topmost) {
- items.removeFirst();
- if (items.isEmpty()) {
- conflictedItems.removeAt(i);
- continue;
+ // remember the initial target item for each gesture that was not in
+ // the conflicted state.
+ if (!normalGestures.isEmpty()) {
+ for (int i = 0; i < cachedTargetItems.size() && !normalGestures.isEmpty(); ++i) {
+ QGraphicsObject *item = cachedTargetItems.at(i);
+
+ // get gestures to deliver to the current item
+ foreach (QGesture *g, cachedItemGestures.value(item)) {
+ if (!gestureTargets.contains(g)) {
+ gestureTargets.insert(g, item);
+ normalGestures.remove(g);
+ }
}
}
- ++i;
}
}
- // put back those started gestures that are not in the conflicted state
- // and remember their targets
- QHash<QGesture *, QGraphicsObject *>::const_iterator it = normalGestures.begin(),
- e = normalGestures.end();
- for (; it != e; ++it) {
- QGesture *g = it.key();
- QGraphicsObject *receiver = it.value();
- Q_ASSERT(!gestureTargets.contains(g));
- gestureTargets.insert(g, receiver);
- gesturesPerItem[receiver].append(g);
- Qt::GestureFlags flags =
- receiver->QGraphicsItem::d_func()->gestureContext.value(g->gestureType());
- if (flags & Qt::IgnoredGesturesPropagateToParent)
- parentPropagatedGestures.insert(g);
- }
- it = ignoredConflictedGestures.begin();
- e = ignoredConflictedGestures.end();
- for (; it != e; ++it) {
- QGesture *g = it.key();
- QGraphicsObject *receiver = it.value();
- Q_ASSERT(!gestureTargets.contains(g));
- gestureTargets.insert(g, receiver);
- gesturesPerItem[receiver].append(g);
- Qt::GestureFlags flags =
- receiver->QGraphicsItem::d_func()->gestureContext.value(g->gestureType());
- if (flags & Qt::IgnoredGesturesPropagateToParent)
- parentPropagatedGestures.insert(g);
- }
-
- DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
- << "Started gestures:" << normalGestures.keys()
- << "All gestures:" << gesturesPerItem.values();
// deliver all gesture events
- QList<QGesture *> alreadyIgnoredGestures;
- QHash<QGraphicsObject *, QSet<QGesture *> > itemIgnoredGestures;
- QList<QGraphicsObject *> targetItems = gesturesPerItem.keys();
- qSort(targetItems.begin(), targetItems.end(), qt_closestItemFirst);
- for (int i = 0; i < targetItems.size(); ++i) {
- QGraphicsObject *item = targetItems.at(i);
- QList<QGesture *> gestures = gesturesPerItem.value(item);
- // remove gestures that were already delivered once and were ignored
- DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
- << "already ignored gestures for item"
- << item << ":" << itemIgnoredGestures.value(item);
-
- if (itemIgnoredGestures.contains(item)) // don't deliver twice to the same item
- continue;
-
- QGraphicsItemPrivate *gid = item->QGraphicsItem::d_func();
- foreach(QGesture *g, alreadyIgnoredGestures) {
- QMap<Qt::GestureType, Qt::GestureFlags>::iterator contextit =
- gid->gestureContext.find(g->gestureType());
- bool deliver = false;
- if (contextit != gid->gestureContext.end()) {
- if (g->state() == Qt::GestureStarted) {
- deliver = true;
- } else {
- const Qt::GestureFlags flags = contextit.value();
- if (flags & Qt::ReceivePartialGestures) {
- QGraphicsObject *originalTarget = gestureTargets.value(g);
- Q_ASSERT(originalTarget);
- QGraphicsItemPrivate *otd = originalTarget->QGraphicsItem::d_func();
- const Qt::GestureFlags originalTargetFlags = otd->gestureContext.value(g->gestureType());
- if (originalTargetFlags & Qt::IgnoredGesturesPropagateToParent) {
- // only deliver to parents of the original target item
- deliver = item->isAncestorOf(originalTarget);
- } else {
- deliver = true;
- }
- }
- }
- }
- if (deliver)
- gestures += g;
+ QSet<QGesture *> undeliveredGestures;
+ QSet<QGesture *> parentPropagatedGestures;
+ foreach (QGesture *gesture, allGestures) {
+ if (QGraphicsObject *target = gestureTargets.value(gesture, 0)) {
+ cachedItemGestures[target].insert(gesture);
+ cachedTargetItems.append(target);
+ undeliveredGestures.insert(gesture);
+ QGraphicsItemPrivate *d = target->QGraphicsItem::d_func();
+ const Qt::GestureFlags flags = d->gestureContext.value(gesture->gestureType());
+ if (flags & Qt::IgnoredGesturesPropagateToParent)
+ parentPropagatedGestures.insert(gesture);
}
+ }
+ qSort(cachedTargetItems.begin(), cachedTargetItems.end(), qt_closestItemFirst);
+ for (int i = 0; i < cachedTargetItems.size(); ++i) {
+ QWeakPointer<QGraphicsObject> receiver = cachedTargetItems.at(i);
+ QSet<QGesture *> gestures =
+ undeliveredGestures & cachedItemGestures.value(receiver.data());
+ gestures -= cachedAlreadyDeliveredGestures.value(receiver.data());
+
if (gestures.isEmpty())
continue;
+
+ cachedAlreadyDeliveredGestures[receiver.data()] += gestures;
+ const bool isPanel = receiver.data()->isPanel();
+
DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
<< "delivering to"
- << item << gestures;
- QGestureEvent ev(gestures);
+ << receiver.data() << gestures;
+ QGestureEvent ev(gestures.toList());
ev.setWidget(event->widget());
- sendEvent(item, &ev);
+ sendEvent(receiver.data(), &ev);
QSet<QGesture *> ignoredGestures;
foreach (QGesture *g, gestures) {
if (!ev.isAccepted() && !ev.isAccepted(g)) {
- ignoredGestures.insert(g);
+ // if the gesture was ignored by its target, we will update the
+ // targetItems list with a possible target items (items that
+ // want to receive partial gestures).
+ // ### wont' work if the target was destroyed in the event
+ // we will just stop delivering it.
+ if (receiver && receiver.data() == gestureTargets.value(g, 0))
+ ignoredGestures.insert(g);
} else {
- if (g->state() == Qt::GestureStarted)
- gestureTargets[g] = item;
- }
- }
- if (!ignoredGestures.isEmpty()) {
- // get a list of items under the (current) hotspot of each ignored
- // gesture and start delivery again from the beginning
- DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
- << "item has ignored the event, will propagate."
- << item << ignoredGestures;
- itemIgnoredGestures[item] += ignoredGestures;
- alreadyIgnoredGestures = ignoredGestures.toList();
-
- // remove gestures that are supposed to be propagated to
- // parent items only.
- QSet<QGesture *> parentGestures;
- for (QSet<QGesture *>::iterator it = ignoredGestures.begin();
- it != ignoredGestures.end();) {
- if (parentPropagatedGestures.contains(*it)) {
- parentGestures.insert(*it);
- it = ignoredGestures.erase(it);
- } else {
- ++it;
+ if (receiver && g->state() == Qt::GestureStarted) {
+ // someone accepted the propagated initial GestureStarted
+ // event, let it be the new target for all following events.
+ gestureTargets[g] = receiver.data();
}
+ undeliveredGestures.remove(g);
}
+ }
+ if (undeliveredGestures.isEmpty())
+ break;
+
+ // ignoredGestures list is only filled when delivering to the gesture
+ // target item, so it is safe to assume item == target.
+ if (!ignoredGestures.isEmpty() && !isPanel) {
+ // look for new potential targets for gestures that were ignored
+ // and should be propagated.
+
+ QSet<QGraphicsObject *> targetsSet = cachedTargetItems.toSet();
+
+ if (receiver) {
+ // first if the gesture should be propagated to parents only
+ for (QSet<QGesture *>::iterator it = ignoredGestures.begin();
+ it != ignoredGestures.end();) {
+ if (parentPropagatedGestures.contains(*it)) {
+ QGesture *gesture = *it;
+ const Qt::GestureType gestureType = gesture->gestureType();
+ QGraphicsItem *item = receiver.data();
+ while (item) {
+ if (QGraphicsObject *obj = item->toGraphicsObject()) {
+ if (item->d_func()->gestureContext.contains(gestureType)) {
+ targetsSet.insert(obj);
+ cachedItemGestures[obj].insert(gesture);
+ }
+ }
+ if (item->isPanel())
+ break;
+ item = item->parentItem();
+ }
- QSet<QGraphicsObject *> itemsSet = targetItems.toSet();
-
- foreach(QGesture *g, parentGestures) {
- // get the original target for the gesture
- QGraphicsItem *item = gestureTargets.value(g, 0);
- Q_ASSERT(item);
- const Qt::GestureType gestureType = g->gestureType();
- // iterate through parent items of the original gesture
- // target item and collect potential receivers
- do {
- if (QGraphicsObject *obj = item->toGraphicsObject()) {
- if (item->d_func()->gestureContext.contains(gestureType))
- itemsSet.insert(obj);
+ it = ignoredGestures.erase(it);
+ continue;
}
- if (item->isPanel())
- break;
- } while ((item = item->parentItem()));
+ ++it;
+ }
}
- QMap<Qt::GestureType, QGesture *> conflictedGestures;
- QList<QList<QGraphicsObject *> > itemsForConflictedGestures;
- QHash<QGesture *, QGraphicsObject *> normalGestures;
- getGestureTargets(ignoredGestures,
- &conflictedGestures, &itemsForConflictedGestures,
- &normalGestures);
- for (int k = 0; k < itemsForConflictedGestures.size(); ++k)
- itemsSet += itemsForConflictedGestures.at(k).toSet();
-
- targetItems = itemsSet.toList();
+ gestureTargetsAtHotSpots(ignoredGestures, Qt::ReceivePartialGestures,
+ &cachedItemGestures, &targetsSet, 0, 0);
- qSort(targetItems.begin(), targetItems.end(), qt_closestItemFirst);
+ cachedTargetItems = targetsSet.toList();
+ qSort(cachedTargetItems.begin(), cachedTargetItems.end(), qt_closestItemFirst);
DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
- << "new targets:" << targetItems;
+ << "new targets:" << cachedTargetItems;
i = -1; // start delivery again
continue;
}
}
+
foreach (QGesture *g, startedGestures) {
if (g->gestureCancelPolicy() == QGesture::CancelAllInContext) {
DEBUG() << "lets try to cancel some";
@@ -6230,6 +6187,10 @@ void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event)
break;
}
}
+
+ cachedTargetItems.clear();
+ cachedItemGestures.clear();
+ cachedAlreadyDeliveredGestures.clear();
}
void QGraphicsScenePrivate::cancelGesturesForChildren(QGesture *original)
diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h
index 2e19a89..ca8b829 100644
--- a/src/gui/graphicsview/qgraphicsscene_p.h
+++ b/src/gui/graphicsview/qgraphicsscene_p.h
@@ -294,12 +294,17 @@ public:
bool allItemsIgnoreTouchEvents;
void enableTouchEventsOnViews();
+ QList<QGraphicsObject *> cachedTargetItems;
+ QHash<QGraphicsObject *, QSet<QGesture *> > cachedItemGestures;
+ QHash<QGraphicsObject *, QSet<QGesture *> > cachedAlreadyDeliveredGestures;
QHash<QGesture *, QGraphicsObject *> gestureTargets;
void gestureEventHandler(QGestureEvent *event);
- void getGestureTargets(const QSet<QGesture *> &gestures,
- QMap<Qt::GestureType, QGesture *> *conflictedGestures,
- QList<QList<QGraphicsObject *> > *conflictedItems,
- QHash<QGesture *, QGraphicsObject *> *normalGestures);
+ void gestureTargetsAtHotSpots(const QSet<QGesture *> &gestures,
+ Qt::GestureFlag flag,
+ QHash<QGraphicsObject *, QSet<QGesture *> > *targets,
+ QSet<QGraphicsObject *> *itemsSet = 0,
+ QSet<QGesture *> *normal = 0,
+ QSet<QGesture *> *conflicts = 0);
void cancelGesturesForChildren(QGesture *original);
void updateInputMethodSensitivityInViews();
diff --git a/tests/auto/gestures/tst_gestures.cpp b/tests/auto/gestures/tst_gestures.cpp
index 1765a30..a2058cd 100644
--- a/tests/auto/gestures/tst_gestures.cpp
+++ b/tests/auto/gestures/tst_gestures.cpp
@@ -261,15 +261,19 @@ protected:
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:
@@ -283,13 +287,23 @@ protected:
}
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; ++i) {
+ i <= CustomGesture::SerialFinishedThreshold && receiver; ++i) {
event->serial = i;
if (scene)
scene->sendEvent(qobject_cast<QGraphicsObject *>(object), event);
@@ -336,6 +350,9 @@ private slots:
void graphicsViewParentPropagation();
void panelPropagation();
void panelStacksBehindParent();
+ void deleteGestureTargetWidget();
+ void deleteGestureTargetItem_data();
+ void deleteGestureTargetItem();
};
tst_Gestures::tst_Gestures()
@@ -657,14 +674,16 @@ static const QColor InstanceColors[] = {
class GestureItem : public QGraphicsObject
{
+ Q_OBJECT
static int InstanceCount;
-
public:
GestureItem(const char *name = 0)
{
instanceNumber = InstanceCount++;
- if (name)
+ if (name) {
setObjectName(QLatin1String(name));
+ setToolTip(name);
+ }
size = QRectF(0, 0, 100, 100);
customEventsReceived = 0;
gestureEventsReceived = 0;
@@ -672,6 +691,8 @@ public:
events.clear();
overrideEvents.clear();
acceptGestureOverride = false;
+
+ scene = 0;
}
~GestureItem()
{
@@ -773,15 +794,19 @@ protected:
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:
Q_ASSERT(false);
@@ -794,6 +819,26 @@ protected:
}
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;
@@ -1724,5 +1769,93 @@ void tst_Gestures::panelStacksBehindParent()
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());
+
+ view.viewport()->grabGesture(CustomGesture::GestureType, Qt::DontStartGestureOnChildren);
+
+ 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);
+}
+
QTEST_MAIN(tst_Gestures)
#include "tst_gestures.moc"