From d67b7829e7d5d8fbd57b701f4268dc1c6d77f1b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Arve=20S=C3=A6ther?= Date: Wed, 12 Aug 2009 09:33:37 +0200 Subject: Fix a bug in removeAnchors and reorder how anchors are removed. The problem was that if an item had a center anchor and we removed the left-center anchor before we called removeCenterAnchors(). Suppose the center vertex had 3 edges, (refcount was 3) removeAnchor would then *first* remove the left-center edge, causing the internalVertex refcount to go to 2. That would cause removeInternalVertex() to try to "merge" the two center anchors by calling removeCenterAnchors(). Of course, calling removeCenterAnchors at that point did not work since removeCenterAnchors() assumed that the only two edges connected to the center vertex was its internal left-center and center-right anchors. This was not the case, and the assertion Q_ASSERT(first && center && last); was triggered, since first (or last) was removed at that point. Of course it was not enough to simply call removeCenterAnchors first, because that function assumed that the only two anchors connected to the center vertex was "internal center anchors". removeAnchors is a bit special since we are not really interested in first converting the "internal center anchors" to a single internal anchor because the ultimate goal of that function is to remove *all* anchors. The solution was the additional argument "substitute" to indicate that we really just want to substitute with a simpler anchor (normal behaviour). If not, we really just want to delete the center anchors (don't even try to merge them into a simple internal anchor). --- src/gui/graphicsview/qgraphicsanchorlayout_p.cpp | 97 +++++++++++++++--------- src/gui/graphicsview/qgraphicsanchorlayout_p.h | 4 +- 2 files changed, 66 insertions(+), 35 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp index e44b59a..6b7a12c 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp @@ -592,7 +592,8 @@ void QGraphicsAnchorLayoutPrivate::createCenterAnchors( } void QGraphicsAnchorLayoutPrivate::removeCenterAnchors( - QGraphicsLayoutItem *item, QGraphicsAnchorLayout::Edge centerEdge) + QGraphicsLayoutItem *item, QGraphicsAnchorLayout::Edge centerEdge, + bool substitute) { Orientation orientation; switch (centerEdge) { @@ -619,22 +620,20 @@ void QGraphicsAnchorLayoutPrivate::removeCenterAnchors( lastEdge = QGraphicsAnchorLayout::Bottom; } - AnchorVertex *first = internalVertex(item, firstEdge); AnchorVertex *center = internalVertex(item, centerEdge); + if (!center) + return; + AnchorVertex *first = internalVertex(item, firstEdge); AnchorVertex *last = internalVertex(item, lastEdge); - Q_ASSERT(first && center && last); - Q_ASSERT(graph[orientation].adjacentVertices(center).count() == 2); - // Create new anchor - AnchorData *oldData = graph[orientation].edgeData(first, center); + Q_ASSERT(first); + Q_ASSERT(center); + Q_ASSERT(last); - int minimumSize = oldData->minSize * 2; - int preferredSize = oldData->prefSize * 2; - int maximumSize = oldData->maxSize * 2; + Graph &g = graph[orientation]; - AnchorData *data = new AnchorData(minimumSize, preferredSize, maximumSize); - addAnchor(item, firstEdge, item, lastEdge, data); + AnchorData *oldData = g.edgeData(first, center); // Remove center constraint for (int i = itemCenterConstraints[orientation].count() - 1; i >= 0; --i) { if (itemCenterConstraints[orientation][i]->variables.contains(oldData)) { @@ -643,9 +642,36 @@ void QGraphicsAnchorLayoutPrivate::removeCenterAnchors( } } - // Remove old anchors - removeAnchor(item, firstEdge, item, centerEdge); - removeAnchor(item, centerEdge, item, lastEdge); + if (substitute) { + // Create the new anchor that should substitute the left-center-right anchors. + AnchorData *oldData = g.edgeData(first, center); + + int minimumSize = oldData->minSize * 2; + int preferredSize = oldData->prefSize * 2; + int maximumSize = oldData->maxSize * 2; + + AnchorData *data = new AnchorData(minimumSize, preferredSize, maximumSize); + addAnchor(item, firstEdge, item, lastEdge, data); + + // Remove old anchors + removeAnchor(item, firstEdge, item, centerEdge); + removeAnchor(item, centerEdge, item, lastEdge); + + } else { + // this is only called from removeAnchors() + // first, remove all non-internal anchors + QList adjacents = g.adjacentVertices(center); + for (int i = 0; i < adjacents.count(); ++i) { + AnchorVertex *v = adjacents.at(i); + if (v->m_item != item) { + removeAnchor(item, centerEdge, v->m_item, v->m_edge); + } + } + // when all non-internal anchors is removed it will automatically merge the + // center anchor into a left-right (or top-bottom) anchor. We must also delete that. + // by this time, the center vertex is deleted and merged into a non-centered internal anchor + removeAnchor(item, firstEdge, item, lastEdge); + } } @@ -832,7 +858,7 @@ void QGraphicsAnchorLayoutPrivate::removeInternalVertex(QGraphicsLayoutItem *ite if ((v.second == 2) && ((edge == QGraphicsAnchorLayout::HCenter) || (edge == QGraphicsAnchorLayout::VCenter))) { - removeCenterAnchors(item, edge); + removeCenterAnchors(item, edge, true); } } } @@ -856,30 +882,33 @@ void QGraphicsAnchorLayoutPrivate::removeAnchor(QGraphicsLayoutItem *firstItem, removeInternalVertex(secondItem, secondEdge); } -void QGraphicsAnchorLayoutPrivate::removeAnchors(QGraphicsLayoutItem *item) +void QGraphicsAnchorLayoutPrivate::removeVertex(QGraphicsLayoutItem *item, QGraphicsAnchorLayout::Edge edge) { - AnchorVertex *v1 = 0; - AnchorVertex *v2 = 0; - QList allVertex; - int edge; - - for (edge = QGraphicsAnchorLayout::Left; edge <= QGraphicsAnchorLayout::Bottom; ++edge) { - // Remove all vertex for all edges - QGraphicsAnchorLayout::Edge e = static_cast(edge); - - if ((v1 = internalVertex(item, e))) { - // Remove all edges - allVertex = graph[edgeOrientation(e)].adjacentVertices(v1); - - foreach (v2, allVertex) { - graph[edgeOrientation(e)].removeEdge(v1, v2); - removeInternalVertex(item, e); - removeInternalVertex(v2->m_item, v2->m_edge); - } + if (AnchorVertex *v = internalVertex(item, edge)) { + Graph &g = graph[edgeOrientation(edge)]; + const QList allVertices = graph[edgeOrientation(edge)].adjacentVertices(v); + AnchorVertex *v2; + foreach (v2, allVertices) { + g.removeEdge(v, v2); + removeInternalVertex(item, edge); + removeInternalVertex(v2->m_item, v2->m_edge); } } } +void QGraphicsAnchorLayoutPrivate::removeAnchors(QGraphicsLayoutItem *item) +{ + // remove the center anchor first!! + removeCenterAnchors(item, QGraphicsAnchorLayout::HCenter, false); + removeVertex(item, QGraphicsAnchorLayout::Left); + removeVertex(item, QGraphicsAnchorLayout::Right); + + removeCenterAnchors(item, QGraphicsAnchorLayout::VCenter, false); + removeVertex(item, QGraphicsAnchorLayout::Top); + removeVertex(item, QGraphicsAnchorLayout::Bottom); + +} + /*! \internal diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.h b/src/gui/graphicsview/qgraphicsanchorlayout_p.h index 1c0f737..131d7c3 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.h +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.h @@ -300,7 +300,7 @@ public: void deleteLayoutEdges(); void createItemEdges(QGraphicsLayoutItem *item); void createCenterAnchors(QGraphicsLayoutItem *item, QGraphicsAnchorLayout::Edge centerEdge); - void removeCenterAnchors(QGraphicsLayoutItem *item, QGraphicsAnchorLayout::Edge centerEdge); + void removeCenterAnchors(QGraphicsLayoutItem *item, QGraphicsAnchorLayout::Edge centerEdge, bool substitute = true); void removeCenterConstraints(QGraphicsLayoutItem *item, Orientation orientation); // helper function used by the 4 API functions @@ -324,6 +324,8 @@ public: void removeAnchors(QGraphicsLayoutItem *item); + void removeVertex(QGraphicsLayoutItem *item, QGraphicsAnchorLayout::Edge edge); + void correctEdgeDirection(QGraphicsLayoutItem *&firstItem, QGraphicsAnchorLayout::Edge &firstEdge, QGraphicsLayoutItem *&secondItem, -- cgit v0.12