katie/src/gui/kernel/qgesturemanager.cpp
Ivailo Monev 48a45d0cd4 build fixes for the QT_STRICT_ITERATORS conditional
the only thing left to fix is the dbus component which requires the
pointer operator backported from 9c5a77f0ef
but it messes up the erase and insert templates and causes source
incompatibilities so it has to investigated further.

upstream commits:
fad1fa65ed
7c1e0fef8e
c4fbe872be
0412ad3513

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
2016-06-04 14:15:26 +00:00

721 lines
29 KiB
C++

/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company 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.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qgesturemanager_p.h"
#include "qstandardgestures_p.h"
#include "qwidget_p.h"
#include "qgesture_p.h"
#include "qgraphicsitem_p.h"
#include "qevent_p.h"
#include "qapplication_p.h"
#include "qgesture.h"
#include "qevent.h"
#include "qgraphicsitem.h"
#ifdef Q_WS_MAC
#include "qmacgesturerecognizer_mac_p.h"
#endif
#if defined(Q_OS_WIN) && !defined(QT_NO_NATIVE_GESTURES)
#include "qwinnativepangesturerecognizer_win_p.h"
#endif
#include "qdebug.h"
// #define GESTURE_DEBUG
#ifndef GESTURE_DEBUG
# define DEBUG if (0) qDebug
#else
# define DEBUG qDebug
#endif
#ifndef QT_NO_GESTURES
QT_BEGIN_NAMESPACE
QGestureManager::QGestureManager(QObject *parent)
: QObject(parent), state(NotGesture), m_lastCustomGestureId(Qt::CustomGesture)
{
qRegisterMetaType<Qt::GestureState>();
#if defined(Q_WS_MAC)
registerGestureRecognizer(new QMacSwipeGestureRecognizer);
registerGestureRecognizer(new QMacPinchGestureRecognizer);
#if defined(QT_MAC_USE_COCOA)
registerGestureRecognizer(new QMacPanGestureRecognizer);
#endif
#else
registerGestureRecognizer(new QPanGestureRecognizer);
registerGestureRecognizer(new QPinchGestureRecognizer);
registerGestureRecognizer(new QSwipeGestureRecognizer);
registerGestureRecognizer(new QTapGestureRecognizer);
#endif
#if defined(Q_OS_WIN)
#if !defined(QT_NO_NATIVE_GESTURES)
if (QApplicationPrivate::HasTouchSupport)
registerGestureRecognizer(new QWinNativePanGestureRecognizer);
#endif
#else
registerGestureRecognizer(new QTapAndHoldGestureRecognizer);
#endif
}
QGestureManager::~QGestureManager()
{
qDeleteAll(m_recognizers.values());
foreach (QGestureRecognizer *recognizer, m_obsoleteGestures.keys()) {
qDeleteAll(m_obsoleteGestures.value(recognizer));
delete recognizer;
}
m_obsoleteGestures.clear();
}
Qt::GestureType QGestureManager::registerGestureRecognizer(QGestureRecognizer *recognizer)
{
QGesture *dummy = recognizer->create(0);
if (!dummy) {
qWarning("QGestureManager::registerGestureRecognizer: "
"the recognizer fails to create a gesture object, skipping registration.");
return Qt::GestureType(0);
}
Qt::GestureType type = dummy->gestureType();
if (type == Qt::CustomGesture) {
// generate a new custom gesture id
++m_lastCustomGestureId;
type = Qt::GestureType(m_lastCustomGestureId);
}
m_recognizers.insertMulti(type, recognizer);
delete dummy;
return type;
}
void QGestureManager::unregisterGestureRecognizer(Qt::GestureType type)
{
QList<QGestureRecognizer *> list = m_recognizers.values(type);
while (QGestureRecognizer *recognizer = m_recognizers.take(type)) {
if (!m_obsoleteGestures.contains(recognizer)) {
// inserting even an empty QSet will cause the recognizer to be deleted on destruction of the manager
m_obsoleteGestures.insert(recognizer, QSet<QGesture *>());
}
}
foreach (QGesture *g, m_gestureToRecognizer.keys()) {
QGestureRecognizer *recognizer = m_gestureToRecognizer.value(g);
if (list.contains(recognizer)) {
m_deletedRecognizers.insert(g, recognizer);
}
}
QMap<ObjectGesture, QList<QGesture *> >::const_iterator iter = m_objectGestures.constBegin();
while (iter != m_objectGestures.constEnd()) {
ObjectGesture objectGesture = iter.key();
if (objectGesture.gesture == type) {
foreach (QGesture *g, iter.value()) {
if (QGestureRecognizer *recognizer = m_gestureToRecognizer.value(g)) {
m_gestureToRecognizer.remove(g);
m_obsoleteGestures[recognizer].insert(g);
}
}
}
++iter;
}
}
void QGestureManager::cleanupCachedGestures(QObject *target, Qt::GestureType type)
{
QMap<ObjectGesture, QList<QGesture *> >::Iterator iter = m_objectGestures.begin();
while (iter != m_objectGestures.end()) {
ObjectGesture objectGesture = iter.key();
if (objectGesture.gesture == type && target == objectGesture.object) {
QSet<QGesture *> gestures = iter.value().toSet();
for (QHash<QGestureRecognizer *, QSet<QGesture *> >::iterator
it = m_obsoleteGestures.begin(), e = m_obsoleteGestures.end(); it != e; ++it) {
it.value() -= gestures;
}
foreach (QGesture *g, gestures) {
m_deletedRecognizers.remove(g);
m_gestureToRecognizer.remove(g);
m_maybeGestures.remove(g);
m_activeGestures.remove(g);
m_gestureOwners.remove(g);
m_gestureTargets.remove(g);
m_gesturesToDelete.insert(g);
}
iter = m_objectGestures.erase(iter);
} else {
++iter;
}
}
}
// get or create a QGesture object that will represent the state for a given object, used by the recognizer
QGesture *QGestureManager::getState(QObject *object, QGestureRecognizer *recognizer, Qt::GestureType type)
{
// if the widget is being deleted we should be careful not to
// create a new state, as it will create QWeakPointer which doesn't work
// from the destructor.
if (object->isWidgetType()) {
if (static_cast<QWidget *>(object)->d_func()->data.in_destructor)
return 0;
} else if (QGesture *g = qobject_cast<QGesture *>(object)) {
return g;
#ifndef QT_NO_GRAPHICSVIEW
} else {
Q_ASSERT(qobject_cast<QGraphicsObject *>(object));
QGraphicsObject *graphicsObject = static_cast<QGraphicsObject *>(object);
if (graphicsObject->QGraphicsItem::d_func()->inDestructor)
return 0;
#endif
}
// check if the QGesture for this recognizer has already been created
foreach (QGesture *state, m_objectGestures.value(QGestureManager::ObjectGesture(object, type))) {
if (m_gestureToRecognizer.value(state) == recognizer)
return state;
}
Q_ASSERT(recognizer);
QGesture *state = recognizer->create(object);
if (!state)
return 0;
state->setParent(this);
if (state->gestureType() == Qt::CustomGesture) {
// if the recognizer didn't fill in the gesture type, then this
// is a custom gesture with autogenerated id and we fill it.
state->d_func()->gestureType = type;
#if defined(GESTURE_DEBUG)
state->setObjectName(QString::number((int)type));
#endif
}
m_objectGestures[QGestureManager::ObjectGesture(object, type)].append(state);
m_gestureToRecognizer[state] = recognizer;
m_gestureOwners[state] = object;
return state;
}
bool QGestureManager::filterEventThroughContexts(const QMultiMap<QObject *,
Qt::GestureType> &contexts,
QEvent *event)
{
QSet<QGesture *> triggeredGestures;
QSet<QGesture *> finishedGestures;
QSet<QGesture *> newMaybeGestures;
QSet<QGesture *> notGestures;
// TODO: sort contexts by the gesture type and check if one of the contexts
// is already active.
bool consumeEventHint = false;
// filter the event through recognizers
typedef QMultiMap<QObject *, Qt::GestureType>::const_iterator ContextIterator;
ContextIterator contextEnd = contexts.end();
for (ContextIterator context = contexts.begin(); context != contextEnd; ++context) {
Qt::GestureType gestureType = context.value();
const QMap<Qt::GestureType, QGestureRecognizer *> &const_recognizers = m_recognizers;
QMap<Qt::GestureType, QGestureRecognizer *>::const_iterator
typeToRecognizerIterator = const_recognizers.lowerBound(gestureType),
typeToRecognizerEnd = const_recognizers.upperBound(gestureType);
for (; typeToRecognizerIterator != typeToRecognizerEnd; ++typeToRecognizerIterator) {
QGestureRecognizer *recognizer = typeToRecognizerIterator.value();
QObject *target = context.key();
QGesture *state = getState(target, recognizer, gestureType);
if (!state)
continue;
QGestureRecognizer::Result recognizerResult = recognizer->recognize(state, target, event);
QGestureRecognizer::Result recognizerState = recognizerResult & QGestureRecognizer::ResultState_Mask;
QGestureRecognizer::Result resultHint = recognizerResult & QGestureRecognizer::ResultHint_Mask;
if (recognizerState == QGestureRecognizer::TriggerGesture) {
DEBUG() << "QGestureManager:Recognizer: gesture triggered: " << state;
triggeredGestures << state;
} else if (recognizerState == QGestureRecognizer::FinishGesture) {
DEBUG() << "QGestureManager:Recognizer: gesture finished: " << state;
finishedGestures << state;
} else if (recognizerState == QGestureRecognizer::MayBeGesture) {
DEBUG() << "QGestureManager:Recognizer: maybe gesture: " << state;
newMaybeGestures << state;
} else if (recognizerState == QGestureRecognizer::CancelGesture) {
DEBUG() << "QGestureManager:Recognizer: not gesture: " << state;
notGestures << state;
} else if (recognizerState == QGestureRecognizer::Ignore) {
DEBUG() << "QGestureManager:Recognizer: ignored the event: " << state;
} else {
DEBUG() << "QGestureManager:Recognizer: hm, lets assume the recognizer"
<< "ignored the event: " << state;
}
if (resultHint & QGestureRecognizer::ConsumeEventHint) {
DEBUG() << "QGestureManager: we were asked to consume the event: "
<< state;
consumeEventHint = true;
}
}
}
if (!triggeredGestures.isEmpty() || !finishedGestures.isEmpty()
|| !newMaybeGestures.isEmpty() || !notGestures.isEmpty()) {
QSet<QGesture *> startedGestures = triggeredGestures - m_activeGestures;
triggeredGestures &= m_activeGestures;
// check if a running gesture switched back to maybe state
QSet<QGesture *> activeToMaybeGestures = m_activeGestures & newMaybeGestures;
// check if a maybe gesture switched to canceled - reset it but don't send an event
QSet<QGesture *> maybeToCanceledGestures = m_maybeGestures & notGestures;
// check if a running gesture switched back to not gesture state,
// i.e. were canceled
QSet<QGesture *> canceledGestures = m_activeGestures & notGestures;
// new gestures in maybe state
m_maybeGestures += newMaybeGestures;
// gestures that were in maybe state
QSet<QGesture *> notMaybeGestures = (startedGestures | triggeredGestures
| finishedGestures | canceledGestures
| notGestures);
m_maybeGestures -= notMaybeGestures;
Q_ASSERT((startedGestures & finishedGestures).isEmpty());
Q_ASSERT((startedGestures & newMaybeGestures).isEmpty());
Q_ASSERT((startedGestures & canceledGestures).isEmpty());
Q_ASSERT((finishedGestures & newMaybeGestures).isEmpty());
Q_ASSERT((finishedGestures & canceledGestures).isEmpty());
Q_ASSERT((canceledGestures & newMaybeGestures).isEmpty());
QSet<QGesture *> notStarted = finishedGestures - m_activeGestures;
if (!notStarted.isEmpty()) {
// there are some gestures that claim to be finished, but never started.
// probably those are "singleshot" gestures so we'll fake the started state.
foreach (QGesture *gesture, notStarted)
gesture->d_func()->state = Qt::GestureStarted;
QSet<QGesture *> undeliveredGestures;
deliverEvents(notStarted, &undeliveredGestures);
finishedGestures -= undeliveredGestures;
}
m_activeGestures += startedGestures;
// sanity check: all triggered gestures should already be in active gestures list
Q_ASSERT((m_activeGestures & triggeredGestures).size() == triggeredGestures.size());
m_activeGestures -= finishedGestures;
m_activeGestures -= activeToMaybeGestures;
m_activeGestures -= canceledGestures;
// set the proper gesture state on each gesture
foreach (QGesture *gesture, startedGestures)
gesture->d_func()->state = Qt::GestureStarted;
foreach (QGesture *gesture, triggeredGestures)
gesture->d_func()->state = Qt::GestureUpdated;
foreach (QGesture *gesture, finishedGestures)
gesture->d_func()->state = Qt::GestureFinished;
foreach (QGesture *gesture, canceledGestures)
gesture->d_func()->state = Qt::GestureCanceled;
foreach (QGesture *gesture, activeToMaybeGestures)
gesture->d_func()->state = Qt::GestureFinished;
if (!m_activeGestures.isEmpty() || !m_maybeGestures.isEmpty() ||
!startedGestures.isEmpty() || !triggeredGestures.isEmpty() ||
!finishedGestures.isEmpty() || !canceledGestures.isEmpty()) {
DEBUG() << "QGestureManager::filterEventThroughContexts:"
<< "\n\tactiveGestures:" << m_activeGestures
<< "\n\tmaybeGestures:" << m_maybeGestures
<< "\n\tstarted:" << startedGestures
<< "\n\ttriggered:" << triggeredGestures
<< "\n\tfinished:" << finishedGestures
<< "\n\tcanceled:" << canceledGestures
<< "\n\tmaybe-canceled:" << maybeToCanceledGestures;
}
QSet<QGesture *> undeliveredGestures;
deliverEvents(startedGestures+triggeredGestures+finishedGestures+canceledGestures,
&undeliveredGestures);
foreach (QGesture *g, startedGestures) {
if (undeliveredGestures.contains(g))
continue;
if (g->gestureCancelPolicy() == QGesture::CancelAllInContext) {
DEBUG() << "lets try to cancel some";
// find gestures in context in Qt::GestureStarted or Qt::GestureUpdated state and cancel them
cancelGesturesForChildren(g);
}
}
m_activeGestures -= undeliveredGestures;
// reset gestures that ended
QSet<QGesture *> endedGestures =
finishedGestures + canceledGestures + undeliveredGestures + maybeToCanceledGestures;
foreach (QGesture *gesture, endedGestures) {
recycle(gesture);
m_gestureTargets.remove(gesture);
}
}
//Clean up the Gestures
qDeleteAll(m_gesturesToDelete);
m_gesturesToDelete.clear();
return consumeEventHint;
}
// Cancel all gestures of children of the widget that original is associated with
void QGestureManager::cancelGesturesForChildren(QGesture *original)
{
Q_ASSERT(original);
QWidget *originatingWidget = m_gestureTargets.value(original);
Q_ASSERT(originatingWidget);
// iterate over all active gestures and all maybe gestures
// for each find the owner
// if the owner is part of our sub-hierarchy, cancel it.
QSet<QGesture*> cancelledGestures;
QSet<QGesture*>::Iterator iter = m_activeGestures.begin();
while (iter != m_activeGestures.end()) {
QWidget *widget = m_gestureTargets.value(*iter);
// note that we don't touch the gestures for our originatingWidget
if (widget != originatingWidget && originatingWidget->isAncestorOf(widget)) {
DEBUG() << " found a gesture to cancel" << (*iter);
(*iter)->d_func()->state = Qt::GestureCanceled;
cancelledGestures << *iter;
iter = m_activeGestures.erase(iter);
} else {
++iter;
}
}
// TODO handle 'maybe' gestures too
// sort them per target widget by cherry picking from almostCanceledGestures and delivering
QSet<QGesture *> almostCanceledGestures = cancelledGestures;
while (!almostCanceledGestures.isEmpty()) {
QWidget *target = 0;
QSet<QGesture*> gestures;
iter = almostCanceledGestures.begin();
// sort per target widget
while (iter != almostCanceledGestures.end()) {
QWidget *widget = m_gestureTargets.value(*iter);
if (target == 0)
target = widget;
if (target == widget) {
gestures << *iter;
iter = almostCanceledGestures.erase(iter);
} else {
++iter;
}
}
Q_ASSERT(target);
QSet<QGesture*> undeliveredGestures;
deliverEvents(gestures, &undeliveredGestures);
}
for (iter = cancelledGestures.begin(); iter != cancelledGestures.end(); ++iter)
recycle(*iter);
}
void QGestureManager::cleanupGesturesForRemovedRecognizer(QGesture *gesture)
{
QGestureRecognizer *recognizer = m_deletedRecognizers.value(gesture);
if(!recognizer) //The Gesture is removed while in the even loop, so the recognizers for this gestures was removed
return;
m_deletedRecognizers.remove(gesture);
if (m_deletedRecognizers.keys(recognizer).isEmpty()) {
// no more active gestures, cleanup!
qDeleteAll(m_obsoleteGestures.value(recognizer));
m_obsoleteGestures.remove(recognizer);
delete recognizer;
}
}
// return true if accepted (consumed)
bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event)
{
QMap<Qt::GestureType, int> types;
QMultiMap<QObject *, Qt::GestureType> contexts;
QWidget *w = receiver;
typedef QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator ContextIterator;
if (!w->d_func()->gestureContext.isEmpty()) {
for(ContextIterator it = w->d_func()->gestureContext.constBegin(),
e = w->d_func()->gestureContext.constEnd(); it != e; ++it) {
types.insert(it.key(), 0);
contexts.insertMulti(w, it.key());
}
}
// find all gesture contexts for the widget tree
w = w->isWindow() ? 0 : w->parentWidget();
while (w)
{
for (ContextIterator it = w->d_func()->gestureContext.constBegin(),
e = w->d_func()->gestureContext.constEnd(); it != e; ++it) {
if (!(it.value() & Qt::DontStartGestureOnChildren)) {
if (!types.contains(it.key())) {
types.insert(it.key(), 0);
contexts.insertMulti(w, it.key());
}
}
}
if (w->isWindow())
break;
w = w->parentWidget();
}
return contexts.isEmpty() ? false : filterEventThroughContexts(contexts, event);
}
#ifndef QT_NO_GRAPHICSVIEW
bool QGestureManager::filterEvent(QGraphicsObject *receiver, QEvent *event)
{
QMap<Qt::GestureType, int> types;
QMultiMap<QObject *, Qt::GestureType> contexts;
QGraphicsObject *item = receiver;
if (!item->QGraphicsItem::d_func()->gestureContext.isEmpty()) {
typedef QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator ContextIterator;
for(ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.constBegin(),
e = item->QGraphicsItem::d_func()->gestureContext.constEnd(); it != e; ++it) {
types.insert(it.key(), 0);
contexts.insertMulti(item, it.key());
}
}
// find all gesture contexts for the graphics object tree
item = item->parentObject();
while (item)
{
typedef QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator ContextIterator;
for (ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.constBegin(),
e = item->QGraphicsItem::d_func()->gestureContext.constEnd(); it != e; ++it) {
if (!(it.value() & Qt::DontStartGestureOnChildren)) {
if (!types.contains(it.key())) {
types.insert(it.key(), 0);
contexts.insertMulti(item, it.key());
}
}
}
item = item->parentObject();
}
return contexts.isEmpty() ? false : filterEventThroughContexts(contexts, event);
}
#endif
bool QGestureManager::filterEvent(QObject *receiver, QEvent *event)
{
if (!m_gestureToRecognizer.contains(static_cast<QGesture *>(receiver)))
return false;
QGesture *state = static_cast<QGesture *>(receiver);
QMultiMap<QObject *, Qt::GestureType> contexts;
contexts.insert(state, state->gestureType());
return filterEventThroughContexts(contexts, event);
}
void QGestureManager::getGestureTargets(const QSet<QGesture*> &gestures,
QMap<QWidget *, QList<QGesture *> > *conflicts,
QMap<QWidget *, QList<QGesture *> > *normal)
{
typedef QHash<Qt::GestureType, QHash<QWidget *, QGesture *> > GestureByTypes;
GestureByTypes gestureByTypes;
// sort gestures by types
foreach (QGesture *gesture, gestures) {
QWidget *receiver = m_gestureTargets.value(gesture, 0);
Q_ASSERT(receiver);
gestureByTypes[gesture->gestureType()].insert(receiver, gesture);
}
// for each gesture type
foreach (Qt::GestureType type, gestureByTypes.keys()) {
QHash<QWidget *, QGesture *> gestures = gestureByTypes.value(type);
foreach (QWidget *widget, gestures.keys()) {
QWidget *w = widget->parentWidget();
while (w) {
QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator it
= w->d_func()->gestureContext.constFind(type);
if (it != w->d_func()->gestureContext.constEnd()) {
// i.e. 'w' listens to gesture 'type'
if (!(it.value() & Qt::DontStartGestureOnChildren) && w != widget) {
// conflicting gesture!
(*conflicts)[widget].append(gestures[widget]);
break;
}
}
if (w->isWindow()) {
w = 0;
break;
}
w = w->parentWidget();
}
if (!w)
(*normal)[widget].append(gestures[widget]);
}
}
}
void QGestureManager::deliverEvents(const QSet<QGesture *> &gestures,
QSet<QGesture *> *undeliveredGestures)
{
if (gestures.isEmpty())
return;
typedef QMap<QWidget *, QList<QGesture *> > GesturesPerWidget;
GesturesPerWidget conflictedGestures;
GesturesPerWidget normalStartedGestures;
QSet<QGesture *> startedGestures;
// first figure out the initial receivers of gestures
for (QSet<QGesture *>::const_iterator it = gestures.begin(),
e = gestures.end(); it != e; ++it) {
QGesture *gesture = *it;
QWidget *target = m_gestureTargets.value(gesture, 0);
if (!target) {
// the gesture has just started and doesn't have a target yet.
Q_ASSERT(gesture->state() == Qt::GestureStarted);
if (gesture->hasHotSpot()) {
// guess the target widget using the hotspot of the gesture
QPoint pt = gesture->hotSpot().toPoint();
if (QWidget *topLevel = qApp->topLevelAt(pt)) {
QWidget *child = topLevel->childAt(topLevel->mapFromGlobal(pt));
target = child ? child : topLevel;
}
} else {
// or use the context of the gesture
QObject *context = m_gestureOwners.value(gesture, 0);
if (context->isWidgetType())
target = static_cast<QWidget *>(context);
}
if (target)
m_gestureTargets.insert(gesture, target);
}
Qt::GestureType gestureType = gesture->gestureType();
Q_ASSERT(gestureType != Qt::CustomGesture);
Q_UNUSED(gestureType);
if (target) {
if (gesture->state() == Qt::GestureStarted) {
startedGestures.insert(gesture);
} else {
normalStartedGestures[target].append(gesture);
}
} else {
DEBUG() << "QGestureManager::deliverEvent: could not find the target for gesture"
<< gesture->gestureType();
qWarning("QGestureManager::deliverEvent: could not find the target for gesture");
undeliveredGestures->insert(gesture);
}
}
getGestureTargets(startedGestures, &conflictedGestures, &normalStartedGestures);
DEBUG() << "QGestureManager::deliverEvents:"
<< "\nstarted: " << startedGestures
<< "\nconflicted: " << conflictedGestures
<< "\nnormal: " << normalStartedGestures
<< "\n";
// if there are conflicting gestures, send the GestureOverride event
for (GesturesPerWidget::const_iterator it = conflictedGestures.constBegin(),
e = conflictedGestures.constEnd(); it != e; ++it) {
QWidget *receiver = it.key();
QList<QGesture *> gestures = it.value();
DEBUG() << "QGestureManager::deliverEvents: sending GestureOverride to"
<< receiver
<< "gestures:" << gestures;
QGestureEvent event(gestures);
event.t = QEvent::GestureOverride;
// mark event and individual gestures as ignored
event.ignore();
foreach(QGesture *g, gestures)
event.setAccepted(g, false);
QApplication::sendEvent(receiver, &event);
bool eventAccepted = event.isAccepted();
foreach(QGesture *gesture, event.gestures()) {
if (eventAccepted || event.isAccepted(gesture)) {
QWidget *w = event.d_func()->targetWidgets.value(gesture->gestureType(), 0);
Q_ASSERT(w);
DEBUG() << "override event: gesture was accepted:" << gesture << w;
QList<QGesture *> &gestures = normalStartedGestures[w];
gestures.append(gesture);
// override the target
m_gestureTargets[gesture] = w;
} else {
DEBUG() << "override event: gesture wasn't accepted. putting back:" << gesture;
QList<QGesture *> &gestures = normalStartedGestures[receiver];
gestures.append(gesture);
}
}
}
// delivering gestures that are not in conflicted state
for (GesturesPerWidget::const_iterator it = normalStartedGestures.constBegin(),
e = normalStartedGestures.constEnd(); it != e; ++it) {
if (!it.value().isEmpty()) {
DEBUG() << "QGestureManager::deliverEvents: sending to" << it.key()
<< "gestures:" << it.value();
QGestureEvent event(it.value());
QApplication::sendEvent(it.key(), &event);
bool eventAccepted = event.isAccepted();
foreach (QGesture *gesture, event.gestures()) {
if (gesture->state() == Qt::GestureStarted &&
(eventAccepted || event.isAccepted(gesture))) {
QWidget *w = event.d_func()->targetWidgets.value(gesture->gestureType(), 0);
Q_ASSERT(w);
DEBUG() << "started gesture was delivered and accepted by" << w;
m_gestureTargets[gesture] = w;
}
}
}
}
}
void QGestureManager::recycle(QGesture *gesture)
{
QGestureRecognizer *recognizer = m_gestureToRecognizer.value(gesture, 0);
if (recognizer) {
gesture->setGestureCancelPolicy(QGesture::CancelNone);
recognizer->reset(gesture);
m_activeGestures.remove(gesture);
} else {
cleanupGesturesForRemovedRecognizer(gesture);
}
}
QT_END_NAMESPACE
#endif // QT_NO_GESTURES
#include "moc_qgesturemanager_p.h"