|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the QtGui module of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "private/qgesturemanager_p.h" |
|
43 #include "private/qstandardgestures_p.h" |
|
44 #include "private/qwidget_p.h" |
|
45 #include "private/qgesture_p.h" |
|
46 #include "private/qgraphicsitem_p.h" |
|
47 #include "private/qevent_p.h" |
|
48 #include "private/qapplication_p.h" |
|
49 #include "qgesture.h" |
|
50 #include "qevent.h" |
|
51 #include "qgraphicsitem.h" |
|
52 |
|
53 #ifdef Q_WS_MAC |
|
54 #include "qmacgesturerecognizer_mac_p.h" |
|
55 #endif |
|
56 #if defined(Q_OS_WIN) && !defined(QT_NO_NATIVE_GESTURES) |
|
57 #include "qwinnativepangesturerecognizer_win_p.h" |
|
58 #endif |
|
59 |
|
60 #include "qdebug.h" |
|
61 |
|
62 // #define GESTURE_DEBUG |
|
63 #ifndef GESTURE_DEBUG |
|
64 # define DEBUG if (0) qDebug |
|
65 #else |
|
66 # define DEBUG qDebug |
|
67 #endif |
|
68 |
|
69 QT_BEGIN_NAMESPACE |
|
70 |
|
71 QGestureManager::QGestureManager(QObject *parent) |
|
72 : QObject(parent), state(NotGesture), m_lastCustomGestureId(0) |
|
73 { |
|
74 qRegisterMetaType<Qt::GestureState>(); |
|
75 |
|
76 #if defined(Q_WS_MAC) |
|
77 registerGestureRecognizer(new QMacSwipeGestureRecognizer); |
|
78 registerGestureRecognizer(new QMacPinchGestureRecognizer); |
|
79 #if defined(QT_MAC_USE_COCOA) |
|
80 registerGestureRecognizer(new QMacPanGestureRecognizer); |
|
81 #endif |
|
82 #else |
|
83 registerGestureRecognizer(new QPanGestureRecognizer); |
|
84 registerGestureRecognizer(new QPinchGestureRecognizer); |
|
85 registerGestureRecognizer(new QSwipeGestureRecognizer); |
|
86 registerGestureRecognizer(new QTapGestureRecognizer); |
|
87 #endif |
|
88 #if defined(Q_OS_WIN) |
|
89 #if !defined(QT_NO_NATIVE_GESTURES) |
|
90 if (QApplicationPrivate::HasTouchSupport) |
|
91 registerGestureRecognizer(new QWinNativePanGestureRecognizer); |
|
92 #endif |
|
93 #else |
|
94 registerGestureRecognizer(new QTapAndHoldGestureRecognizer); |
|
95 #endif |
|
96 } |
|
97 |
|
98 QGestureManager::~QGestureManager() |
|
99 { |
|
100 qDeleteAll(m_recognizers.values()); |
|
101 foreach (QGestureRecognizer *recognizer, m_obsoleteGestures.keys()) { |
|
102 qDeleteAll(m_obsoleteGestures.value(recognizer)); |
|
103 delete recognizer; |
|
104 } |
|
105 m_obsoleteGestures.clear(); |
|
106 } |
|
107 |
|
108 Qt::GestureType QGestureManager::registerGestureRecognizer(QGestureRecognizer *recognizer) |
|
109 { |
|
110 QGesture *dummy = recognizer->create(0); |
|
111 if (!dummy) { |
|
112 qWarning("QGestureManager::registerGestureRecognizer: " |
|
113 "the recognizer fails to create a gesture object, skipping registration."); |
|
114 return Qt::GestureType(0); |
|
115 } |
|
116 Qt::GestureType type = dummy->gestureType(); |
|
117 if (type == Qt::CustomGesture) { |
|
118 // generate a new custom gesture id |
|
119 ++m_lastCustomGestureId; |
|
120 type = Qt::GestureType(Qt::CustomGesture + m_lastCustomGestureId); |
|
121 } |
|
122 m_recognizers.insertMulti(type, recognizer); |
|
123 delete dummy; |
|
124 return type; |
|
125 } |
|
126 |
|
127 void QGestureManager::unregisterGestureRecognizer(Qt::GestureType type) |
|
128 { |
|
129 QList<QGestureRecognizer *> list = m_recognizers.values(type); |
|
130 m_recognizers.remove(type); |
|
131 foreach (QGesture *g, m_gestureToRecognizer.keys()) { |
|
132 QGestureRecognizer *recognizer = m_gestureToRecognizer.value(g); |
|
133 if (list.contains(recognizer)) { |
|
134 m_deletedRecognizers.insert(g, recognizer); |
|
135 m_gestureToRecognizer.remove(g); |
|
136 } |
|
137 } |
|
138 |
|
139 foreach (QGestureRecognizer *recognizer, list) { |
|
140 QList<QGesture *> obsoleteGestures; |
|
141 QMap<ObjectGesture, QList<QGesture *> >::Iterator iter = m_objectGestures.begin(); |
|
142 while (iter != m_objectGestures.end()) { |
|
143 ObjectGesture objectGesture = iter.key(); |
|
144 if (objectGesture.gesture == type) |
|
145 obsoleteGestures << iter.value(); |
|
146 ++iter; |
|
147 } |
|
148 m_obsoleteGestures.insert(recognizer, obsoleteGestures); |
|
149 } |
|
150 } |
|
151 |
|
152 void QGestureManager::cleanupCachedGestures(QObject *target, Qt::GestureType type) |
|
153 { |
|
154 QMap<ObjectGesture, QList<QGesture *> >::Iterator iter = m_objectGestures.begin(); |
|
155 while (iter != m_objectGestures.end()) { |
|
156 ObjectGesture objectGesture = iter.key(); |
|
157 if (objectGesture.gesture == type && target == objectGesture.object.data()) { |
|
158 qDeleteAll(iter.value()); |
|
159 iter = m_objectGestures.erase(iter); |
|
160 } else { |
|
161 ++iter; |
|
162 } |
|
163 } |
|
164 } |
|
165 |
|
166 // get or create a QGesture object that will represent the state for a given object, used by the recognizer |
|
167 QGesture *QGestureManager::getState(QObject *object, QGestureRecognizer *recognizer, Qt::GestureType type) |
|
168 { |
|
169 // if the widget is being deleted we should be carefull and not to |
|
170 // create a new state, as it will create QWeakPointer which doesnt work |
|
171 // from the destructor. |
|
172 if (object->isWidgetType()) { |
|
173 if (static_cast<QWidget *>(object)->d_func()->data.in_destructor) |
|
174 return 0; |
|
175 } else if (QGesture *g = qobject_cast<QGesture *>(object)) { |
|
176 return g; |
|
177 #ifndef QT_NO_GRAPHICSVIEW |
|
178 } else { |
|
179 Q_ASSERT(qobject_cast<QGraphicsObject *>(object)); |
|
180 #endif |
|
181 } |
|
182 |
|
183 // check if the QGesture for this recognizer has already been created |
|
184 foreach (QGesture *state, m_objectGestures.value(QGestureManager::ObjectGesture(object, type))) { |
|
185 if (m_gestureToRecognizer.value(state) == recognizer) |
|
186 return state; |
|
187 } |
|
188 |
|
189 Q_ASSERT(recognizer); |
|
190 QGesture *state = recognizer->create(object); |
|
191 if (!state) |
|
192 return 0; |
|
193 state->setParent(this); |
|
194 if (state->gestureType() == Qt::CustomGesture) { |
|
195 // if the recognizer didn't fill in the gesture type, then this |
|
196 // is a custom gesture with autogenerated id and we fill it. |
|
197 state->d_func()->gestureType = type; |
|
198 #if defined(GESTURE_DEBUG) |
|
199 state->setObjectName(QString::number((int)type)); |
|
200 #endif |
|
201 } |
|
202 m_objectGestures[QGestureManager::ObjectGesture(object, type)].append(state); |
|
203 m_gestureToRecognizer[state] = recognizer; |
|
204 m_gestureOwners[state] = object; |
|
205 |
|
206 return state; |
|
207 } |
|
208 |
|
209 bool QGestureManager::filterEventThroughContexts(const QMultiMap<QObject *, |
|
210 Qt::GestureType> &contexts, |
|
211 QEvent *event) |
|
212 { |
|
213 QSet<QGesture *> triggeredGestures; |
|
214 QSet<QGesture *> finishedGestures; |
|
215 QSet<QGesture *> newMaybeGestures; |
|
216 QSet<QGesture *> notGestures; |
|
217 |
|
218 // TODO: sort contexts by the gesture type and check if one of the contexts |
|
219 // is already active. |
|
220 |
|
221 bool ret = false; |
|
222 |
|
223 // filter the event through recognizers |
|
224 typedef QMultiMap<QObject *, Qt::GestureType>::const_iterator ContextIterator; |
|
225 for (ContextIterator cit = contexts.begin(), ce = contexts.end(); cit != ce; ++cit) { |
|
226 Qt::GestureType gestureType = cit.value(); |
|
227 QMap<Qt::GestureType, QGestureRecognizer *>::const_iterator |
|
228 rit = m_recognizers.lowerBound(gestureType), |
|
229 re = m_recognizers.upperBound(gestureType); |
|
230 for (; rit != re; ++rit) { |
|
231 QGestureRecognizer *recognizer = rit.value(); |
|
232 QObject *target = cit.key(); |
|
233 QGesture *state = getState(target, recognizer, gestureType); |
|
234 if (!state) |
|
235 continue; |
|
236 QGestureRecognizer::Result result = recognizer->recognize(state, target, event); |
|
237 QGestureRecognizer::Result type = result & QGestureRecognizer::ResultState_Mask; |
|
238 result &= QGestureRecognizer::ResultHint_Mask; |
|
239 if (type == QGestureRecognizer::TriggerGesture) { |
|
240 DEBUG() << "QGestureManager:Recognizer: gesture triggered: " << state; |
|
241 triggeredGestures << state; |
|
242 } else if (type == QGestureRecognizer::FinishGesture) { |
|
243 DEBUG() << "QGestureManager:Recognizer: gesture finished: " << state; |
|
244 finishedGestures << state; |
|
245 } else if (type == QGestureRecognizer::MayBeGesture) { |
|
246 DEBUG() << "QGestureManager:Recognizer: maybe gesture: " << state; |
|
247 newMaybeGestures << state; |
|
248 } else if (type == QGestureRecognizer::CancelGesture) { |
|
249 DEBUG() << "QGestureManager:Recognizer: not gesture: " << state; |
|
250 notGestures << state; |
|
251 } else if (type == QGestureRecognizer::Ignore) { |
|
252 DEBUG() << "QGestureManager:Recognizer: ignored the event: " << state; |
|
253 } else { |
|
254 DEBUG() << "QGestureManager:Recognizer: hm, lets assume the recognizer" |
|
255 << "ignored the event: " << state; |
|
256 } |
|
257 if (result & QGestureRecognizer::ConsumeEventHint) { |
|
258 DEBUG() << "QGestureManager: we were asked to consume the event: " |
|
259 << state; |
|
260 ret = true; |
|
261 } |
|
262 } |
|
263 } |
|
264 if (triggeredGestures.isEmpty() && finishedGestures.isEmpty() |
|
265 && newMaybeGestures.isEmpty() && notGestures.isEmpty()) |
|
266 return ret; |
|
267 |
|
268 QSet<QGesture *> startedGestures = triggeredGestures - m_activeGestures; |
|
269 triggeredGestures &= m_activeGestures; |
|
270 |
|
271 // check if a running gesture switched back to maybe state |
|
272 QSet<QGesture *> activeToMaybeGestures = m_activeGestures & newMaybeGestures; |
|
273 |
|
274 // check if a running gesture switched back to not gesture state, |
|
275 // i.e. were canceled |
|
276 QSet<QGesture *> canceledGestures = m_activeGestures & notGestures; |
|
277 |
|
278 // start timers for new gestures in maybe state |
|
279 foreach (QGesture *state, newMaybeGestures) { |
|
280 QBasicTimer &timer = m_maybeGestures[state]; |
|
281 if (!timer.isActive()) |
|
282 timer.start(3000, this); |
|
283 } |
|
284 // kill timers for gestures that were in maybe state |
|
285 QSet<QGesture *> notMaybeGestures = (startedGestures | triggeredGestures |
|
286 | finishedGestures | canceledGestures |
|
287 | notGestures); |
|
288 foreach(QGesture *gesture, notMaybeGestures) { |
|
289 QHash<QGesture *, QBasicTimer>::iterator it = |
|
290 m_maybeGestures.find(gesture); |
|
291 if (it != m_maybeGestures.end()) { |
|
292 it.value().stop(); |
|
293 m_maybeGestures.erase(it); |
|
294 } |
|
295 } |
|
296 |
|
297 Q_ASSERT((startedGestures & finishedGestures).isEmpty()); |
|
298 Q_ASSERT((startedGestures & newMaybeGestures).isEmpty()); |
|
299 Q_ASSERT((startedGestures & canceledGestures).isEmpty()); |
|
300 Q_ASSERT((finishedGestures & newMaybeGestures).isEmpty()); |
|
301 Q_ASSERT((finishedGestures & canceledGestures).isEmpty()); |
|
302 Q_ASSERT((canceledGestures & newMaybeGestures).isEmpty()); |
|
303 |
|
304 QSet<QGesture *> notStarted = finishedGestures - m_activeGestures; |
|
305 if (!notStarted.isEmpty()) { |
|
306 // there are some gestures that claim to be finished, but never started. |
|
307 // probably those are "singleshot" gestures so we'll fake the started state. |
|
308 foreach (QGesture *gesture, notStarted) |
|
309 gesture->d_func()->state = Qt::GestureStarted; |
|
310 QSet<QGesture *> undeliveredGestures; |
|
311 deliverEvents(notStarted, &undeliveredGestures); |
|
312 finishedGestures -= undeliveredGestures; |
|
313 } |
|
314 |
|
315 m_activeGestures += startedGestures; |
|
316 // sanity check: all triggered gestures should already be in active gestures list |
|
317 Q_ASSERT((m_activeGestures & triggeredGestures).size() == triggeredGestures.size()); |
|
318 m_activeGestures -= finishedGestures; |
|
319 m_activeGestures -= activeToMaybeGestures; |
|
320 m_activeGestures -= canceledGestures; |
|
321 |
|
322 // set the proper gesture state on each gesture |
|
323 foreach (QGesture *gesture, startedGestures) |
|
324 gesture->d_func()->state = Qt::GestureStarted; |
|
325 foreach (QGesture *gesture, triggeredGestures) |
|
326 gesture->d_func()->state = Qt::GestureUpdated; |
|
327 foreach (QGesture *gesture, finishedGestures) |
|
328 gesture->d_func()->state = Qt::GestureFinished; |
|
329 foreach (QGesture *gesture, canceledGestures) |
|
330 gesture->d_func()->state = Qt::GestureCanceled; |
|
331 foreach (QGesture *gesture, activeToMaybeGestures) |
|
332 gesture->d_func()->state = Qt::GestureFinished; |
|
333 |
|
334 if (!m_activeGestures.isEmpty() || !m_maybeGestures.isEmpty() || |
|
335 !startedGestures.isEmpty() || !triggeredGestures.isEmpty() || |
|
336 !finishedGestures.isEmpty() || !canceledGestures.isEmpty()) { |
|
337 DEBUG() << "QGestureManager::filterEventThroughContexts:" |
|
338 << "\n\tactiveGestures:" << m_activeGestures |
|
339 << "\n\tmaybeGestures:" << m_maybeGestures.keys() |
|
340 << "\n\tstarted:" << startedGestures |
|
341 << "\n\ttriggered:" << triggeredGestures |
|
342 << "\n\tfinished:" << finishedGestures |
|
343 << "\n\tcanceled:" << canceledGestures; |
|
344 } |
|
345 |
|
346 QSet<QGesture *> undeliveredGestures; |
|
347 deliverEvents(startedGestures+triggeredGestures+finishedGestures+canceledGestures, |
|
348 &undeliveredGestures); |
|
349 |
|
350 foreach (QGesture *g, startedGestures) { |
|
351 if (undeliveredGestures.contains(g)) |
|
352 continue; |
|
353 if (g->gestureCancelPolicy() == QGesture::CancelAllInContext) { |
|
354 DEBUG() << "lets try to cancel some"; |
|
355 // find gestures in context in Qt::GestureStarted or Qt::GestureUpdated state and cancel them |
|
356 cancelGesturesForChildren(g); |
|
357 } |
|
358 } |
|
359 |
|
360 m_activeGestures -= undeliveredGestures; |
|
361 |
|
362 // reset gestures that ended |
|
363 QSet<QGesture *> endedGestures = |
|
364 finishedGestures + canceledGestures + undeliveredGestures; |
|
365 foreach (QGesture *gesture, endedGestures) { |
|
366 recycle(gesture); |
|
367 m_gestureTargets.remove(gesture); |
|
368 } |
|
369 return ret; |
|
370 } |
|
371 |
|
372 // Cancel all gestures of children of the widget that original is associated with |
|
373 void QGestureManager::cancelGesturesForChildren(QGesture *original) |
|
374 { |
|
375 Q_ASSERT(original); |
|
376 QWidget *originatingWidget = m_gestureTargets.value(original); |
|
377 Q_ASSERT(originatingWidget); |
|
378 |
|
379 // iterate over all active gestures and all maybe gestures |
|
380 // for each find the owner |
|
381 // if the owner is part of our sub-hierarchy, cancel it. |
|
382 |
|
383 QSet<QGesture*> cancelledGestures; |
|
384 QSet<QGesture*>::Iterator iter = m_activeGestures.begin(); |
|
385 while (iter != m_activeGestures.end()) { |
|
386 QWidget *widget = m_gestureTargets.value(*iter); |
|
387 // note that we don't touch the gestures for our originatingWidget |
|
388 if (widget != originatingWidget && originatingWidget->isAncestorOf(widget)) { |
|
389 DEBUG() << " found a gesture to cancel" << (*iter); |
|
390 (*iter)->d_func()->state = Qt::GestureCanceled; |
|
391 cancelledGestures << *iter; |
|
392 iter = m_activeGestures.erase(iter); |
|
393 } else { |
|
394 ++iter; |
|
395 } |
|
396 } |
|
397 |
|
398 // TODO handle 'maybe' gestures too |
|
399 |
|
400 // sort them per target widget by cherry picking from almostCanceledGestures and delivering |
|
401 QSet<QGesture *> almostCanceledGestures = cancelledGestures; |
|
402 while (!almostCanceledGestures.isEmpty()) { |
|
403 QWidget *target = 0; |
|
404 QSet<QGesture*> gestures; |
|
405 iter = almostCanceledGestures.begin(); |
|
406 // sort per target widget |
|
407 while (iter != almostCanceledGestures.end()) { |
|
408 QWidget *widget = m_gestureTargets.value(*iter); |
|
409 if (target == 0) |
|
410 target = widget; |
|
411 if (target == widget) { |
|
412 gestures << *iter; |
|
413 iter = almostCanceledGestures.erase(iter); |
|
414 } else { |
|
415 ++iter; |
|
416 } |
|
417 } |
|
418 Q_ASSERT(target); |
|
419 |
|
420 QSet<QGesture*> undeliveredGestures; |
|
421 deliverEvents(gestures, &undeliveredGestures); |
|
422 } |
|
423 |
|
424 for (iter = cancelledGestures.begin(); iter != cancelledGestures.end(); ++iter) |
|
425 recycle(*iter); |
|
426 } |
|
427 |
|
428 void QGestureManager::cleanupGesturesForRemovedRecognizer(QGesture *gesture) |
|
429 { |
|
430 QGestureRecognizer *recognizer = m_deletedRecognizers.value(gesture); |
|
431 Q_ASSERT(recognizer); |
|
432 m_deletedRecognizers.remove(gesture); |
|
433 if (m_deletedRecognizers.keys(recognizer).isEmpty()) { |
|
434 // no more active gestures, cleanup! |
|
435 qDeleteAll(m_obsoleteGestures.value(recognizer)); |
|
436 m_obsoleteGestures.remove(recognizer); |
|
437 delete recognizer; |
|
438 } |
|
439 } |
|
440 |
|
441 // return true if accepted (consumed) |
|
442 bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event) |
|
443 { |
|
444 QMap<Qt::GestureType, int> types; |
|
445 QMultiMap<QObject *, Qt::GestureType> contexts; |
|
446 QWidget *w = receiver; |
|
447 typedef QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator ContextIterator; |
|
448 if (!w->d_func()->gestureContext.isEmpty()) { |
|
449 for(ContextIterator it = w->d_func()->gestureContext.begin(), |
|
450 e = w->d_func()->gestureContext.end(); it != e; ++it) { |
|
451 types.insert(it.key(), 0); |
|
452 contexts.insertMulti(w, it.key()); |
|
453 } |
|
454 } |
|
455 // find all gesture contexts for the widget tree |
|
456 w = w->isWindow() ? 0 : w->parentWidget(); |
|
457 while (w) |
|
458 { |
|
459 for (ContextIterator it = w->d_func()->gestureContext.begin(), |
|
460 e = w->d_func()->gestureContext.end(); it != e; ++it) { |
|
461 if (!(it.value() & Qt::DontStartGestureOnChildren)) { |
|
462 if (!types.contains(it.key())) { |
|
463 types.insert(it.key(), 0); |
|
464 contexts.insertMulti(w, it.key()); |
|
465 } |
|
466 } |
|
467 } |
|
468 if (w->isWindow()) |
|
469 break; |
|
470 w = w->parentWidget(); |
|
471 } |
|
472 return contexts.isEmpty() ? false : filterEventThroughContexts(contexts, event); |
|
473 } |
|
474 |
|
475 #ifndef QT_NO_GRAPHICSVIEW |
|
476 bool QGestureManager::filterEvent(QGraphicsObject *receiver, QEvent *event) |
|
477 { |
|
478 QMap<Qt::GestureType, int> types; |
|
479 QMultiMap<QObject *, Qt::GestureType> contexts; |
|
480 QGraphicsObject *item = receiver; |
|
481 if (!item->QGraphicsItem::d_func()->gestureContext.isEmpty()) { |
|
482 typedef QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator ContextIterator; |
|
483 for(ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.begin(), |
|
484 e = item->QGraphicsItem::d_func()->gestureContext.end(); it != e; ++it) { |
|
485 types.insert(it.key(), 0); |
|
486 contexts.insertMulti(item, it.key()); |
|
487 } |
|
488 } |
|
489 // find all gesture contexts for the graphics object tree |
|
490 item = item->parentObject(); |
|
491 while (item) |
|
492 { |
|
493 typedef QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator ContextIterator; |
|
494 for (ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.begin(), |
|
495 e = item->QGraphicsItem::d_func()->gestureContext.end(); it != e; ++it) { |
|
496 if (!(it.value() & Qt::DontStartGestureOnChildren)) { |
|
497 if (!types.contains(it.key())) { |
|
498 types.insert(it.key(), 0); |
|
499 contexts.insertMulti(item, it.key()); |
|
500 } |
|
501 } |
|
502 } |
|
503 item = item->parentObject(); |
|
504 } |
|
505 return contexts.isEmpty() ? false : filterEventThroughContexts(contexts, event); |
|
506 } |
|
507 #endif |
|
508 |
|
509 bool QGestureManager::filterEvent(QObject *receiver, QEvent *event) |
|
510 { |
|
511 if (!m_gestureToRecognizer.contains(static_cast<QGesture *>(receiver))) |
|
512 return false; |
|
513 QGesture *state = static_cast<QGesture *>(receiver); |
|
514 QMultiMap<QObject *, Qt::GestureType> contexts; |
|
515 contexts.insert(state, state->gestureType()); |
|
516 return filterEventThroughContexts(contexts, event); |
|
517 } |
|
518 |
|
519 void QGestureManager::getGestureTargets(const QSet<QGesture*> &gestures, |
|
520 QMap<QWidget *, QList<QGesture *> > *conflicts, |
|
521 QMap<QWidget *, QList<QGesture *> > *normal) |
|
522 { |
|
523 typedef QHash<Qt::GestureType, QHash<QWidget *, QGesture *> > GestureByTypes; |
|
524 GestureByTypes gestureByTypes; |
|
525 |
|
526 // sort gestures by types |
|
527 foreach (QGesture *gesture, gestures) { |
|
528 QWidget *receiver = m_gestureTargets.value(gesture, 0); |
|
529 Q_ASSERT(receiver); |
|
530 gestureByTypes[gesture->gestureType()].insert(receiver, gesture); |
|
531 } |
|
532 |
|
533 // for each gesture type |
|
534 foreach (Qt::GestureType type, gestureByTypes.keys()) { |
|
535 QHash<QWidget *, QGesture *> gestures = gestureByTypes.value(type); |
|
536 foreach (QWidget *widget, gestures.keys()) { |
|
537 QWidget *w = widget->parentWidget(); |
|
538 while (w) { |
|
539 QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator it |
|
540 = w->d_func()->gestureContext.find(type); |
|
541 if (it != w->d_func()->gestureContext.end()) { |
|
542 // i.e. 'w' listens to gesture 'type' |
|
543 Qt::GestureFlags flags = it.value(); |
|
544 if (!(it.value() & Qt::DontStartGestureOnChildren) && w != widget) { |
|
545 // conflicting gesture! |
|
546 (*conflicts)[widget].append(gestures[widget]); |
|
547 break; |
|
548 } |
|
549 } |
|
550 if (w->isWindow()) { |
|
551 w = 0; |
|
552 break; |
|
553 } |
|
554 w = w->parentWidget(); |
|
555 } |
|
556 if (!w) |
|
557 (*normal)[widget].append(gestures[widget]); |
|
558 } |
|
559 } |
|
560 } |
|
561 |
|
562 void QGestureManager::deliverEvents(const QSet<QGesture *> &gestures, |
|
563 QSet<QGesture *> *undeliveredGestures) |
|
564 { |
|
565 if (gestures.isEmpty()) |
|
566 return; |
|
567 |
|
568 typedef QMap<QWidget *, QList<QGesture *> > GesturesPerWidget; |
|
569 GesturesPerWidget conflictedGestures; |
|
570 GesturesPerWidget normalStartedGestures; |
|
571 |
|
572 QSet<QGesture *> startedGestures; |
|
573 // first figure out the initial receivers of gestures |
|
574 for (QSet<QGesture *>::const_iterator it = gestures.begin(), |
|
575 e = gestures.end(); it != e; ++it) { |
|
576 QGesture *gesture = *it; |
|
577 QWidget *target = m_gestureTargets.value(gesture, 0); |
|
578 if (!target) { |
|
579 // the gesture has just started and doesn't have a target yet. |
|
580 Q_ASSERT(gesture->state() == Qt::GestureStarted); |
|
581 if (gesture->hasHotSpot()) { |
|
582 // guess the target widget using the hotspot of the gesture |
|
583 QPoint pt = gesture->hotSpot().toPoint(); |
|
584 if (QWidget *w = qApp->topLevelAt(pt)) { |
|
585 target = w->childAt(w->mapFromGlobal(pt)); |
|
586 } |
|
587 } else { |
|
588 // or use the context of the gesture |
|
589 QObject *context = m_gestureOwners.value(gesture, 0); |
|
590 if (context->isWidgetType()) |
|
591 target = static_cast<QWidget *>(context); |
|
592 } |
|
593 if (target) |
|
594 m_gestureTargets.insert(gesture, target); |
|
595 } |
|
596 |
|
597 Qt::GestureType gestureType = gesture->gestureType(); |
|
598 Q_ASSERT(gestureType != Qt::CustomGesture); |
|
599 Q_UNUSED(gestureType); |
|
600 |
|
601 if (target) { |
|
602 if (gesture->state() == Qt::GestureStarted) { |
|
603 startedGestures.insert(gesture); |
|
604 } else { |
|
605 normalStartedGestures[target].append(gesture); |
|
606 } |
|
607 } else { |
|
608 DEBUG() << "QGestureManager::deliverEvent: could not find the target for gesture" |
|
609 << gesture->gestureType(); |
|
610 qWarning("QGestureManager::deliverEvent: could not find the target for gesture"); |
|
611 undeliveredGestures->insert(gesture); |
|
612 } |
|
613 } |
|
614 |
|
615 getGestureTargets(startedGestures, &conflictedGestures, &normalStartedGestures); |
|
616 DEBUG() << "QGestureManager::deliverEvents:" |
|
617 << "\nstarted: " << startedGestures |
|
618 << "\nconflicted: " << conflictedGestures |
|
619 << "\nnormal: " << normalStartedGestures |
|
620 << "\n"; |
|
621 |
|
622 // if there are conflicting gestures, send the GestureOverride event |
|
623 for (GesturesPerWidget::const_iterator it = conflictedGestures.begin(), |
|
624 e = conflictedGestures.end(); it != e; ++it) { |
|
625 QWidget *receiver = it.key(); |
|
626 QList<QGesture *> gestures = it.value(); |
|
627 DEBUG() << "QGestureManager::deliverEvents: sending GestureOverride to" |
|
628 << receiver |
|
629 << "gestures:" << gestures; |
|
630 QGestureEvent event(gestures); |
|
631 event.t = QEvent::GestureOverride; |
|
632 // mark event and individual gestures as ignored |
|
633 event.ignore(); |
|
634 foreach(QGesture *g, gestures) |
|
635 event.setAccepted(g, false); |
|
636 |
|
637 QApplication::sendEvent(receiver, &event); |
|
638 bool eventAccepted = event.isAccepted(); |
|
639 foreach(QGesture *gesture, event.gestures()) { |
|
640 if (eventAccepted || event.isAccepted(gesture)) { |
|
641 QWidget *w = event.d_func()->targetWidgets.value(gesture->gestureType(), 0); |
|
642 Q_ASSERT(w); |
|
643 DEBUG() << "override event: gesture was accepted:" << gesture << w; |
|
644 QList<QGesture *> &gestures = normalStartedGestures[w]; |
|
645 gestures.append(gesture); |
|
646 // override the target |
|
647 m_gestureTargets[gesture] = w; |
|
648 } else { |
|
649 DEBUG() << "override event: gesture wasn't accepted. putting back:" << gesture; |
|
650 QList<QGesture *> &gestures = normalStartedGestures[receiver]; |
|
651 gestures.append(gesture); |
|
652 } |
|
653 } |
|
654 } |
|
655 |
|
656 // delivering gestures that are not in conflicted state |
|
657 for (GesturesPerWidget::const_iterator it = normalStartedGestures.begin(), |
|
658 e = normalStartedGestures.end(); it != e; ++it) { |
|
659 if (!it.value().isEmpty()) { |
|
660 DEBUG() << "QGestureManager::deliverEvents: sending to" << it.key() |
|
661 << "gestures:" << it.value(); |
|
662 QGestureEvent event(it.value()); |
|
663 QApplication::sendEvent(it.key(), &event); |
|
664 bool eventAccepted = event.isAccepted(); |
|
665 foreach (QGesture *gesture, event.gestures()) { |
|
666 if (gesture->state() == Qt::GestureStarted && |
|
667 (eventAccepted || event.isAccepted(gesture))) { |
|
668 QWidget *w = event.d_func()->targetWidgets.value(gesture->gestureType(), 0); |
|
669 Q_ASSERT(w); |
|
670 DEBUG() << "started gesture was delivered and accepted by" << w; |
|
671 m_gestureTargets[gesture] = w; |
|
672 } |
|
673 } |
|
674 } |
|
675 } |
|
676 } |
|
677 |
|
678 void QGestureManager::timerEvent(QTimerEvent *event) |
|
679 { |
|
680 QHash<QGesture *, QBasicTimer>::iterator it = m_maybeGestures.begin(), |
|
681 e = m_maybeGestures.end(); |
|
682 for (; it != e; ) { |
|
683 QBasicTimer &timer = it.value(); |
|
684 Q_ASSERT(timer.isActive()); |
|
685 if (timer.timerId() == event->timerId()) { |
|
686 timer.stop(); |
|
687 QGesture *gesture = it.key(); |
|
688 it = m_maybeGestures.erase(it); |
|
689 DEBUG() << "QGestureManager::timerEvent: gesture stopped due to timeout:" |
|
690 << gesture; |
|
691 recycle(gesture); |
|
692 } else { |
|
693 ++it; |
|
694 } |
|
695 } |
|
696 } |
|
697 |
|
698 void QGestureManager::recycle(QGesture *gesture) |
|
699 { |
|
700 QGestureRecognizer *recognizer = m_gestureToRecognizer.value(gesture, 0); |
|
701 if (recognizer) { |
|
702 gesture->setGestureCancelPolicy(QGesture::CancelNone); |
|
703 recognizer->reset(gesture); |
|
704 } else { |
|
705 cleanupGesturesForRemovedRecognizer(gesture); |
|
706 } |
|
707 } |
|
708 |
|
709 QT_END_NAMESPACE |
|
710 |
|
711 #include "moc_qgesturemanager_p.cpp" |