src/gui/graphicsview/qgraphicsitem.cpp
branchRCL_3
changeset 5 d3bac044e0f0
parent 4 3b1da2848fc7
child 7 3f74d0d4af4c
--- a/src/gui/graphicsview/qgraphicsitem.cpp	Fri Feb 19 23:40:16 2010 +0200
+++ b/src/gui/graphicsview/qgraphicsitem.cpp	Fri Mar 12 15:46:37 2010 +0200
@@ -268,6 +268,17 @@
 */
 
 /*!
+    \variable QGraphicsItem::Type
+
+    The type value returned by the virtual type() function in standard
+    graphics item classes in Qt. All such standard graphics item
+    classes in Qt are associated with a unique value for Type,
+    e.g. the value returned by QGraphicsPathItem::type() is 2.
+
+    \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 18
+*/
+
+/*!
     \variable QGraphicsItem::UserType
 
     The lowest permitted type value for custom items (subclasses
@@ -276,6 +287,8 @@
     and declaring a Type enum value. Example:
 
     \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 1
+
+    \note UserType = 65536
 */
 
 /*!
@@ -798,8 +811,36 @@
             return;
     }
 
-    foreach (QGraphicsItem *child, children)
-        child->d_ptr->updateAncestorFlag(childFlag, flag, enabled, false);
+    for (int i = 0; i < children.size(); ++i)
+        children.at(i)->d_ptr->updateAncestorFlag(childFlag, flag, enabled, false);
+}
+
+void QGraphicsItemPrivate::updateAncestorFlags()
+{
+    int flags = 0;
+    if (parent) {
+        // Inherit the parent's ancestor flags.
+        QGraphicsItemPrivate *pd = parent->d_ptr.data();
+        flags = pd->ancestorFlags;
+
+        // Add in flags from the parent.
+        if (pd->filtersDescendantEvents)
+            flags |= AncestorFiltersChildEvents;
+        if (pd->handlesChildEvents)
+            flags |= AncestorHandlesChildEvents;
+        if (pd->flags & QGraphicsItem::ItemClipsChildrenToShape)
+            flags |= AncestorClipsChildren;
+        if (pd->flags & QGraphicsItem::ItemIgnoresTransformations)
+            flags |= AncestorIgnoresTransformations;
+    }
+
+    if (ancestorFlags == flags)
+        return; // No change; stop propagation.
+    ancestorFlags = flags;
+
+    // Propagate to children recursively.
+    for (int i = 0; i < children.size(); ++i)
+        children.at(i)->d_ptr->updateAncestorFlags();
 }
 
 /*!
@@ -984,25 +1025,17 @@
     prepareGeometryChange) if the item is in its destructor, i.e.
     inDestructor is 1.
 */
-void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent)
+void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent, const QVariant *newParentVariant,
+                                               const QVariant *thisPointerVariant)
 {
     Q_Q(QGraphicsItem);
-    if (newParent == q) {
-        qWarning("QGraphicsItem::setParentItem: cannot assign %p as a parent of itself", this);
-        return;
-    }
-    if (newParent == parent)
-        return;
-
-    const QVariant newParentVariant(q->itemChange(QGraphicsItem::ItemParentChange,
-                                                  qVariantFromValue<QGraphicsItem *>(newParent)));
-    newParent = qVariantValue<QGraphicsItem *>(newParentVariant);
     if (newParent == parent)
         return;
 
     if (scene) {
         // Deliver the change to the index
-        scene->d_func()->index->itemChange(q, QGraphicsItem::ItemParentChange, newParentVariant);
+        if (scene->d_func()->indexMethod != QGraphicsScene::NoIndex)
+            scene->d_func()->index->itemChange(q, QGraphicsItem::ItemParentChange, newParent);
 
         // Disable scene pos notifications for old ancestors
         if (scenePosDescendants || (flags & QGraphicsItem::ItemSendsScenePositionChanges))
@@ -1020,11 +1053,11 @@
     if (!inDestructor)
         q_ptr->prepareGeometryChange();
 
-    const QVariant thisPointerVariant(qVariantFromValue<QGraphicsItem *>(q));
     if (parent) {
         // Remove from current parent
         parent->d_ptr->removeChild(q);
-        parent->itemChange(QGraphicsItem::ItemChildRemovedChange, thisPointerVariant);
+        if (thisPointerVariant)
+            parent->itemChange(QGraphicsItem::ItemChildRemovedChange, *thisPointerVariant);
     }
 
     // Update toplevelitem list. If this item is being deleted, its parent
@@ -1042,7 +1075,7 @@
     QGraphicsItem *p = parent;
     QGraphicsItem *parentFocusScopeItem = 0;
     while (p) {
-        if (p->flags() & QGraphicsItem::ItemIsFocusScope) {
+        if (p->d_ptr->flags & QGraphicsItem::ItemIsFocusScope) {
             // If this item's focus scope's focus scope item points
             // to this item or a descendent, then clear it.
             QGraphicsItem *fsi = p->d_ptr->focusScopeItem;
@@ -1055,6 +1088,10 @@
         p = p->d_ptr->parent;
     }
 
+    // Update graphics effect optimization flag
+    if (newParent && (graphicsEffect || mayHaveChildWithGraphicsEffect))
+        newParent->d_ptr->updateChildWithGraphicsEffectFlagRecursively();
+
     // Update focus scope item ptr in new scope.
     QGraphicsItem *newFocusScopeItem = subFocusItem ? subFocusItem : parentFocusScopeItem;
     if (newFocusScopeItem && newParent) {
@@ -1063,11 +1100,11 @@
             QGraphicsItem *ancestorScope = 0;
             QGraphicsItem *p = subFocusItem->d_ptr->parent;
             while (p) {
-                if (p->flags() & QGraphicsItem::ItemIsFocusScope)
+                if (p->d_ptr->flags & QGraphicsItem::ItemIsFocusScope)
                     ancestorScope = p;
-                if (p->isPanel())
+                if (p->d_ptr->flags & QGraphicsItem::ItemIsPanel)
                     break;
-                p = p->parentItem();
+                p = p->d_ptr->parent;
             }
             if (ancestorScope)
                 newFocusScopeItem = ancestorScope;
@@ -1075,7 +1112,7 @@
 
         QGraphicsItem *p = newParent;
         while (p) {
-            if (p->flags() & QGraphicsItem::ItemIsFocusScope) {
+            if (p->d_ptr->flags & QGraphicsItem::ItemIsFocusScope) {
                 p->d_ptr->focusScopeItem = newFocusScopeItem;
                 // Ensure the new item is no longer the subFocusItem. The
                 // only way to set focus on a child of a focus scope is
@@ -1089,52 +1126,45 @@
     }
 
     if ((parent = newParent)) {
-        bool implicitUpdate = false;
         if (parent->d_func()->scene && parent->d_func()->scene != scene) {
             // Move this item to its new parent's scene
             parent->d_func()->scene->addItem(q);
-            implicitUpdate = true;
         } else if (!parent->d_func()->scene && scene) {
             // Remove this item from its former scene
             scene->removeItem(q);
         }
 
         parent->d_ptr->addChild(q);
-        parent->itemChange(QGraphicsItem::ItemChildAddedChange, thisPointerVariant);
+        if (thisPointerVariant)
+            parent->itemChange(QGraphicsItem::ItemChildAddedChange, *thisPointerVariant);
         if (scene) {
-            if (!implicitUpdate)
-                scene->d_func()->markDirty(q_ptr);
-
             // Re-enable scene pos notifications for new ancestors
             if (scenePosDescendants || (flags & QGraphicsItem::ItemSendsScenePositionChanges))
                 scene->d_func()->setScenePosItemEnabled(q, true);
         }
 
+        // Propagate dirty flags to the new parent
+        markParentDirty(/*updateBoundingRect=*/true);
+
         // Inherit ancestor flags from the new parent.
-        updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-2));
-        updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-1));
-        updateAncestorFlag(QGraphicsItem::ItemClipsChildrenToShape);
-        updateAncestorFlag(QGraphicsItem::ItemIgnoresTransformations);
+        updateAncestorFlags();
 
         // Update item visible / enabled.
-        if (parent->isVisible() != visible) {
-            if (!parent->isVisible() || !explicitlyHidden)
-                setVisibleHelper(parent->isVisible(), /* explicit = */ false, /* update = */ !implicitUpdate);
+        if (parent->d_ptr->visible != visible) {
+            if (!parent->d_ptr->visible || !explicitlyHidden)
+                setVisibleHelper(parent->d_ptr->visible, /* explicit = */ false, /* update = */ false);
         }
         if (parent->isEnabled() != enabled) {
-            if (!parent->isEnabled() || !explicitlyDisabled)
-                setEnabledHelper(parent->isEnabled(), /* explicit = */ false, /* update = */ !implicitUpdate);
+            if (!parent->d_ptr->enabled || !explicitlyDisabled)
+                setEnabledHelper(parent->d_ptr->enabled, /* explicit = */ false, /* update = */ false);
         }
 
         // Auto-activate if visible and the parent is active.
-        if (q->isVisible() && parent->isActive())
+        if (visible && parent->isActive())
             q->setActive(true);
     } else {
         // Inherit ancestor flags from the new parent.
-        updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-2));
-        updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-1));
-        updateAncestorFlag(QGraphicsItem::ItemClipsChildrenToShape);
-        updateAncestorFlag(QGraphicsItem::ItemIgnoresTransformations);
+        updateAncestorFlags();
 
         if (!inDestructor) {
             // Update item visible / enabled.
@@ -1142,10 +1172,6 @@
                 setVisibleHelper(true, /* explicit = */ false);
             if (!enabled && !explicitlyDisabled)
                 setEnabledHelper(true, /* explicit = */ false);
-
-            // If the item is being deleted, the whole scene will be updated.
-            if (scene)
-                scene->d_func()->markDirty(q_ptr);
         }
     }
 
@@ -1161,7 +1187,8 @@
     }
 
     // Deliver post-change notification
-    q->itemChange(QGraphicsItem::ItemParentHasChanged, newParentVariant);
+    if (newParentVariant)
+        q->itemChange(QGraphicsItem::ItemParentHasChanged, *newParentVariant);
 
     if (isObject)
         emit static_cast<QGraphicsObject *>(q)->parentChanged();
@@ -1350,7 +1377,7 @@
         d_ptr->scene->d_func()->removeItemHelper(this);
     } else {
         d_ptr->resetFocusProxy();
-        d_ptr->setParentItemHelper(0);
+        setParentItem(0);
     }
 
 #ifndef QT_NO_GRAPHICSEFFECT
@@ -1543,21 +1570,36 @@
 }
 
 /*!
-    Sets this item's parent item to \a parent. If this item already has a
-    parent, it is first removed from the previous parent. If \a parent is 0,
-    this item will become a top-level item.
-
-    Note that this implicitly adds this graphics item to the scene of
-    the parent. You should not \l{QGraphicsScene::addItem()}{add} the
-    item to the scene yourself.
-
-    Calling this function on an item that is an ancestor of \a parent have undefined behaviour.
-
-    \sa parentItem(), childItems()
-*/
-void QGraphicsItem::setParentItem(QGraphicsItem *parent)
-{
-    d_ptr->setParentItemHelper(parent);
+  Sets this item's parent item to \a newParent. If this item already
+  has a parent, it is first removed from the previous parent. If \a
+  newParent is 0, this item will become a top-level item.
+
+  Note that this implicitly adds this graphics item to the scene of
+  the parent. You should not \l{QGraphicsScene::addItem()}{add} the
+  item to the scene yourself.
+
+  Calling this function on an item that is an ancestor of \a newParent
+  have undefined behaviour.
+
+  \sa parentItem(), childItems()
+*/
+void QGraphicsItem::setParentItem(QGraphicsItem *newParent)
+{
+    if (newParent == this) {
+        qWarning("QGraphicsItem::setParentItem: cannot assign %p as a parent of itself", this);
+        return;
+    }
+    if (newParent == d_ptr->parent)
+        return;
+
+    const QVariant newParentVariant(itemChange(QGraphicsItem::ItemParentChange,
+                                               qVariantFromValue<QGraphicsItem *>(newParent)));
+    newParent = qVariantValue<QGraphicsItem *>(newParentVariant);
+    if (newParent == d_ptr->parent)
+        return;
+
+    const QVariant thisPointerVariant(qVariantFromValue<QGraphicsItem *>(this));
+    d_ptr->setParentItemHelper(newParent, &newParentVariant, &thisPointerVariant);
 }
 
 /*!
@@ -1607,7 +1649,7 @@
 */
 bool QGraphicsItem::isWindow() const
 {
-    return isWidget() && (static_cast<const QGraphicsWidget *>(this)->windowType() & Qt::Window);
+    return d_ptr->isWidget && (static_cast<const QGraphicsWidget *>(this)->windowType() & Qt::Window);
 }
 
 /*!
@@ -1644,9 +1686,9 @@
 void QGraphicsItem::setFlag(GraphicsItemFlag flag, bool enabled)
 {
     if (enabled)
-        setFlags(flags() | flag);
+        setFlags(GraphicsItemFlags(d_ptr->flags) | flag);
     else
-        setFlags(flags() & ~flag);
+        setFlags(GraphicsItemFlags(d_ptr->flags) & ~flag);
 }
 
 /*!
@@ -1693,8 +1735,8 @@
     flags = GraphicsItemFlags(itemChange(ItemFlagsChange, quint32(flags)).toUInt());
     if (quint32(d_ptr->flags) == quint32(flags))
         return;
-    if (d_ptr->scene)
-        d_ptr->scene->d_func()->index->itemChange(this, ItemFlagsChange, quint32(flags));
+    if (d_ptr->scene && d_ptr->scene->d_func()->indexMethod != QGraphicsScene::NoIndex)
+        d_ptr->scene->d_func()->index->itemChange(this, ItemFlagsChange, &flags);
 
     // Flags that alter the geometry of the item (or its children).
     const quint32 geomChangeFlagsMask = (ItemClipsChildrenToShape | ItemClipsToShape | ItemIgnoresTransformations | ItemIsSelectable);
@@ -1703,7 +1745,7 @@
         d_ptr->paintedViewBoundingRectsNeedRepaint = 1;
 
     // Keep the old flags to compare the diff.
-    GraphicsItemFlags oldFlags = this->flags();
+    GraphicsItemFlags oldFlags = GraphicsItemFlags(d_ptr->flags);
 
     // Update flags.
     d_ptr->flags = flags;
@@ -1732,7 +1774,23 @@
         d_ptr->updateAncestorFlag(ItemIgnoresTransformations);
     }
 
+    if ((flags & ItemNegativeZStacksBehindParent) != (oldFlags & ItemNegativeZStacksBehindParent)) {
+        // NB! We change the flags directly here, so we must also update d_ptr->flags.
+        // Note that this has do be done before the ItemStacksBehindParent check
+        // below; otherwise we will loose the change.
+
+        // Update stack-behind.
+        if (d_ptr->z < qreal(0.0))
+            flags |= ItemStacksBehindParent;
+        else
+            flags &= ~ItemStacksBehindParent;
+        d_ptr->flags = flags;
+    }
+
     if ((flags & ItemStacksBehindParent) != (oldFlags & ItemStacksBehindParent)) {
+        // NB! This check has to come after the ItemNegativeZStacksBehindParent
+        // check above. Be careful.
+
         // Ensure child item sorting is up to date when toggling this flag.
         if (d_ptr->parent)
             d_ptr->parent->d_ptr->needSortChildren = 1;
@@ -1746,10 +1804,6 @@
             d_ptr->scene->d_func()->updateInputMethodSensitivityInViews();
     }
 
-    if ((flags & ItemNegativeZStacksBehindParent) != (oldFlags & ItemNegativeZStacksBehindParent)) {
-        // Update stack-behind.
-        setFlag(ItemStacksBehindParent, d_ptr->z < qreal(0.0));
-    }
 
     if ((d_ptr->panelModality != NonModal)
         && d_ptr->scene
@@ -2523,7 +2577,9 @@
     // Update.
     if (d_ptr->scene) {
 #ifndef QT_NO_GRAPHICSEFFECT
-        d_ptr->invalidateGraphicsEffectsRecursively();
+        d_ptr->invalidateParentGraphicsEffectsRecursively();
+        if (!(d_ptr->flags & ItemDoesntPropagateOpacityToChildren))
+            d_ptr->invalidateChildGraphicsEffectsRecursively(QGraphicsItemPrivate::OpacityChanged);
 #endif //QT_NO_GRAPHICSEFFECT
         d_ptr->scene->d_func()->markDirty(this, QRectF(),
                                           /*invalidateChildren=*/true,
@@ -2568,6 +2624,8 @@
     if (d_ptr->graphicsEffect) {
         delete d_ptr->graphicsEffect;
         d_ptr->graphicsEffect = 0;
+    } else if (d_ptr->parent) {
+        d_ptr->parent->d_ptr->updateChildWithGraphicsEffectFlagRecursively();
     }
 
     if (effect) {
@@ -2581,6 +2639,19 @@
 }
 #endif //QT_NO_GRAPHICSEFFECT
 
+void QGraphicsItemPrivate::updateChildWithGraphicsEffectFlagRecursively()
+{
+#ifndef QT_NO_GRAPHICSEFFECT
+    QGraphicsItemPrivate *itemPrivate = this;
+    do {
+        // parent chain already notified?
+        if (itemPrivate->mayHaveChildWithGraphicsEffect)
+            return;
+        itemPrivate->mayHaveChildWithGraphicsEffect = 1;
+    } while ((itemPrivate = itemPrivate->parent ? itemPrivate->parent->d_ptr.data() : 0));
+#endif
+}
+
 /*!
     \internal
     \since 4.6
@@ -4264,9 +4335,9 @@
     if (newZ == d_ptr->z)
         return;
 
-    if (d_ptr->scene) {
+    if (d_ptr->scene && d_ptr->scene->d_func()->indexMethod != QGraphicsScene::NoIndex) {
         // Z Value has changed, we have to notify the index.
-        d_ptr->scene->d_func()->index->itemChange(this, ItemZValueChange, newZVariant);
+        d_ptr->scene->d_func()->index->itemChange(this, ItemZValueChange, &newZ);
     }
 
     d_ptr->z = newZ;
@@ -5033,7 +5104,7 @@
     \internal
 */
 #ifndef QT_NO_GRAPHICSEFFECT
-void QGraphicsItemPrivate::invalidateGraphicsEffectsRecursively()
+void QGraphicsItemPrivate::invalidateParentGraphicsEffectsRecursively()
 {
     QGraphicsItemPrivate *itemPrivate = this;
     do {
@@ -5045,6 +5116,24 @@
         }
     } while ((itemPrivate = itemPrivate->parent ? itemPrivate->parent->d_ptr.data() : 0));
 }
+
+void QGraphicsItemPrivate::invalidateChildGraphicsEffectsRecursively(QGraphicsItemPrivate::InvalidateReason reason)
+{
+    if (!mayHaveChildWithGraphicsEffect)
+        return;
+
+    for (int i = 0; i < children.size(); ++i) {
+        QGraphicsItemPrivate *childPrivate = children.at(i)->d_ptr.data();
+        if (reason == OpacityChanged && (childPrivate->flags & QGraphicsItem::ItemIgnoresParentOpacity))
+            continue;
+        if (childPrivate->graphicsEffect) {
+            childPrivate->notifyInvalidated = 1;
+            static_cast<QGraphicsItemEffectSourcePrivate *>(childPrivate->graphicsEffect->d_func()->source->d_func())->invalidateCache();
+        }
+
+        childPrivate->invalidateChildGraphicsEffectsRecursively(reason);
+    }
+}
 #endif //QT_NO_GRAPHICSEFFECT
 
 /*!
@@ -5289,7 +5378,7 @@
 
     // Make sure we notify effects about invalidated source.
 #ifndef QT_NO_GRAPHICSEFFECT
-    d_ptr->invalidateGraphicsEffectsRecursively();
+    d_ptr->invalidateParentGraphicsEffectsRecursively();
 #endif //QT_NO_GRAPHICSEFFECT
 
     if (CacheMode(d_ptr->cacheMode) != NoCache) {
@@ -7165,7 +7254,9 @@
 
         QGraphicsScenePrivate *scenePrivate = d_ptr->scene->d_func();
         scenePrivate->index->prepareBoundingRectChange(this);
-        scenePrivate->markDirty(this, QRectF(), /*invalidateChildren=*/true);
+        scenePrivate->markDirty(this, QRectF(), /*invalidateChildren=*/true, /*force=*/false,
+                                /*ignoreOpacity=*/ false, /*removingItemFromScene=*/ false,
+                                /*updateBoundingRect=*/true);
 
         // For compatibility reasons, we have to update the item's old geometry
         // if someone is connected to the changed signal or the scene has no views.
@@ -7182,19 +7273,7 @@
         }
     }
 
-    QGraphicsItem *parent = this;
-    while ((parent = parent->d_ptr->parent)) {
-        QGraphicsItemPrivate *parentp = parent->d_ptr.data();
-        parentp->dirtyChildrenBoundingRect = 1;
-        // ### Only do this if the parent's effect applies to the entire subtree.
-        parentp->notifyBoundingRectChanged = 1;
-#ifndef QT_NO_GRAPHICSEFFECT
-        if (parentp->scene && parentp->graphicsEffect) {
-            parentp->notifyInvalidated = 1;
-            static_cast<QGraphicsItemEffectSourcePrivate *>(parentp->graphicsEffect->d_func()->source->d_func())->invalidateCache();
-        }
-#endif
-    }
+    d_ptr->markParentDirty(/*updateBoundingRect=*/true);
 }
 
 /*!