src/gui/graphicsview/qgraphicsscene.cpp
changeset 33 3e2da88830cd
parent 30 5dc02b23752f
child 37 758a864f9613
--- a/src/gui/graphicsview/qgraphicsscene.cpp	Tue Jul 06 15:10:48 2010 +0300
+++ b/src/gui/graphicsview/qgraphicsscene.cpp	Wed Aug 18 10:37:55 2010 +0300
@@ -699,6 +699,7 @@
     if (!selectionChanging && selectedItems.size() != oldSelectedItemsSize)
         emit q->selectionChanged();
 
+#ifndef QT_NO_GESTURES
     QHash<QGesture *, QGraphicsObject *>::iterator it;
     for (it = gestureTargets.begin(); it != gestureTargets.end();) {
         if (it.value() == item)
@@ -706,6 +707,7 @@
         else
             ++it;
     }
+
     QGraphicsObject *dummy = static_cast<QGraphicsObject *>(item);
     cachedTargetItems.removeOne(dummy);
     cachedItemGestures.remove(dummy);
@@ -713,6 +715,7 @@
 
     foreach (Qt::GestureType gesture, item->d_ptr->gestureContext.keys())
         ungrabGesture(item, gesture);
+#endif // QT_NO_GESTURES
 }
 
 /*!
@@ -882,8 +885,7 @@
             ungrabKeyboard(static_cast<QGraphicsItem *>(widget), itemIsDying);
         }
         if (!itemIsDying && widget->isVisible()) {
-            widget->hide();
-            widget->QGraphicsItem::d_ptr->explicitlyHidden = 0;
+            widget->QGraphicsItem::d_ptr->setVisibleHelper(false, /* explicit = */ false);
         }
     }
 }
@@ -1180,11 +1182,13 @@
 bool QGraphicsScenePrivate::sendEvent(QGraphicsItem *item, QEvent *event)
 {
     if (QGraphicsObject *object = item->toGraphicsObject()) {
+#ifndef QT_NO_GESTURES
         QGestureManager *gestureManager = QApplicationPrivate::instance()->gestureManager;
         if (gestureManager) {
             if (gestureManager->filterEvent(object, event))
                 return true;
         }
+#endif // QT_NO_GESTURES
     }
 
     if (filterEvent(item, event))
@@ -1331,6 +1335,8 @@
                 break;
             }
         }
+        if (item->d_ptr->flags & QGraphicsItem::ItemStopsClickFocusPropagation)
+            break;
         if (item->isPanel())
             break;
     }
@@ -2602,8 +2608,10 @@
         d->enableTouchEventsOnViews();
     }
 
+#ifndef QT_NO_GESTURES
     foreach (Qt::GestureType gesture, item->d_ptr->gestureContext.keys())
         d->grabGesture(item, gesture);
+#endif
 
     // Update selection lists
     if (item->isSelected())
@@ -3525,10 +3533,12 @@
     case QEvent::TouchEnd:
         d->touchEventHandler(static_cast<QTouchEvent *>(event));
         break;
+#ifndef QT_NO_GESTURES
     case QEvent::Gesture:
     case QEvent::GestureOverride:
         d->gestureEventHandler(static_cast<QGestureEvent *>(event));
         break;
+#endif // QT_NO_GESTURES
     default:
         return QObject::event(event);
     }
@@ -4154,6 +4164,25 @@
                                                                 wheelEvent->scenePos(),
                                                                 wheelEvent->widget());
 
+#ifdef Q_WS_MAC
+    // On Mac, ignore the event if the first item under the mouse is not the last opened
+    // popup (or one of its descendant)
+    if (!d->popupWidgets.isEmpty() && !wheelCandidates.isEmpty() && wheelCandidates.first() != d->popupWidgets.back() && !d->popupWidgets.back()->isAncestorOf(wheelCandidates.first())) {
+        wheelEvent->accept();
+        return;
+    }
+#else
+    // Find the first popup under the mouse (including the popup's descendants) starting from the last.
+    // Remove all popups after the one found, or all or them if no popup is under the mouse.
+    // Then continue with the event.
+    QList<QGraphicsWidget *>::const_iterator iter = d->popupWidgets.end();
+    while (--iter >= d->popupWidgets.begin() && !wheelCandidates.isEmpty()) {
+        if (wheelCandidates.first() == *iter || (*iter)->isAncestorOf(wheelCandidates.first()))
+            break;
+        d->removePopup(*iter);
+    }
+#endif
+
     bool hasSetFocus = false;
     foreach (QGraphicsItem *item, wheelCandidates) {
         if (!hasSetFocus && item->isEnabled()
@@ -4889,6 +4918,24 @@
     if (updateAll)
         return;
 
+    if (removingItemFromScene && !ignoreOpacity && !item->d_ptr->ignoreOpacity) {
+        // If any of the item's ancestors ignore opacity, it means that the opacity
+        // was set to 0 (and the update request has not yet been processed). That
+        // also means that we have to ignore the opacity for the item itself; otherwise
+        // things like: parent->setOpacity(0); scene->removeItem(child) won't work.
+        // Note that we only do this when removing items from the scene. In all other
+        // cases the ignoreOpacity bit propagates properly in processDirtyItems, but
+        // since the item is removed immediately it won't be processed there.
+        QGraphicsItem *p = item->d_ptr->parent;
+        while (p) {
+            if (p->d_ptr->ignoreOpacity) {
+                item->d_ptr->ignoreOpacity = true;
+                break;
+            }
+            p = p->d_ptr->parent;
+        }
+    }
+
     if (item->d_ptr->discardUpdateRequest(/*ignoreVisibleBit=*/force,
                                           /*ignoreDirtyBit=*/removingItemFromScene || invalidateChildren,
                                           /*ignoreOpacity=*/ignoreOpacity)) {
@@ -5131,7 +5178,12 @@
     // Process children.
     if (itemHasChildren && item->d_ptr->dirtyChildren) {
         const bool itemClipsChildrenToShape = item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape;
-        if (itemClipsChildrenToShape) {
+        // Items with no content are threated as 'dummy' items which means they are never drawn and
+        // 'processed', so the painted view bounding rect is never up-to-date. This means that whenever
+        // such an item changes geometry, its children have to take care of the update regardless
+        // of whether the item clips children to shape or not.
+        const bool bypassUpdateClip = !itemHasContents && wasDirtyParentViewBoundingRects;
+        if (itemClipsChildrenToShape && !bypassUpdateClip) {
             // Make sure child updates are clipped to the item's bounding rect.
             for (int i = 0; i < views.size(); ++i)
                 views.at(i)->d_func()->setUpdateClip(item);
@@ -5619,8 +5671,10 @@
 void QGraphicsScenePrivate::addView(QGraphicsView *view)
 {
     views << view;
+#ifndef QT_NO_GESTURES
     foreach (Qt::GestureType gesture, grabbedGestures.keys())
         view->viewport()->grabGesture(gesture);
+#endif
 }
 
 void QGraphicsScenePrivate::removeView(QGraphicsView *view)
@@ -5950,6 +6004,7 @@
     dispatchHoverEvent(&hoverEvent);
 }
 
+#ifndef QT_NO_GESTURES
 void QGraphicsScenePrivate::gestureTargetsAtHotSpots(const QSet<QGesture *> &gestures,
                                               Qt::GestureFlag flag,
                                               QHash<QGraphicsObject *, QSet<QGesture *> > *targets,
@@ -6070,8 +6125,15 @@
                     if (ev.isAccepted() || ev.isAccepted(g)) {
                         conflictedGestures.remove(g);
                         // mark the item as a gesture target
-                        if (item)
+                        if (item) {
                             gestureTargets.insert(g, item.data());
+                            QHash<QGraphicsObject *, QSet<QGesture *> >::iterator it, e;
+                            it = cachedItemGestures.begin();
+                            e = cachedItemGestures.end();
+                            for(; it != e; ++it)
+                                it.value().remove(g);
+                            cachedItemGestures[item.data()].insert(g);
+                        }
                         DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
                                 << "override was accepted:"
                                 << g << item.data();
@@ -6240,7 +6302,8 @@
 {
     Q_ASSERT(original);
     QGraphicsItem *originalItem = gestureTargets.value(original);
-    Q_ASSERT(originalItem);
+    if (originalItem == 0) // we only act on accepted gestures, which implies it has a target.
+        return;
 
     // iterate over all active gestures and for each find the owner
     // if the owner is part of our sub-hierarchy, cancel it.
@@ -6338,6 +6401,7 @@
             view->viewport()->ungrabGesture(gesture);
     }
 }
+#endif // QT_NO_GESTURES
 
 QT_END_NAMESPACE