diff options
author | Andreas Aardal Hanssen <andreas.aardal.hanssen@nokia.com> | 2009-06-09 15:45:04 (GMT) |
---|---|---|
committer | Andreas Aardal Hanssen <andreas.aardal.hanssen@nokia.com> | 2009-06-09 16:50:42 (GMT) |
commit | 2af18f51f216d5c624ce28b3fa966a17050d882b (patch) | |
tree | 41a68e7f7a24c7e9e7488676c66ee98521f3c26b | |
parent | 6185ff436816738e933e3c88d44c45faa7f401f7 (diff) | |
download | Qt-2af18f51f216d5c624ce28b3fa966a17050d882b.zip Qt-2af18f51f216d5c624ce28b3fa966a17050d882b.tar.gz Qt-2af18f51f216d5c624ce28b3fa966a17050d882b.tar.bz2 |
Fix sorting bug when using BSP tree index + add autotest.
We use stable sorting to keep insertion order. This works fine as long
as we sort a complete list of siblings in one go, and this list already
has items in insertion order. But if we shuffle such a list, the only
way to get proper sort order again (with insertion order intact), is
if each item has a sibling index. We used to have this, but we don't
have it anymore (as it's not needed for NoIndex mode).
So until we separate the BSP index into a separate class and add this
index there, we add this workaround which uses the toplevelitems list
to ensure the items have the correct order.
Reviewed-by: bnilsen
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem.cpp | 8 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene.cpp | 46 | ||||
-rw-r--r-- | tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp | 56 |
3 files changed, 92 insertions, 18 deletions
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index db16213..f50d210 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -6190,10 +6190,8 @@ void QGraphicsItem::addToIndex() // ### add to child index only if applicable return; } - if (d_ptr->scene) { + if (d_ptr->scene) d_ptr->scene->d_func()->addToIndex(this); - d_ptr->scene->d_func()->markDirty(this); - } } /*! @@ -6209,10 +6207,8 @@ void QGraphicsItem::removeFromIndex() // ### remove from child index only if applicable return; } - if (d_ptr->scene) { - d_ptr->scene->d_func()->markDirty(this); + if (d_ptr->scene) d_ptr->scene->d_func()->removeFromIndex(this); - } } /*! diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index b63efd6..e6c3503 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -5112,18 +5112,42 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * } else if (indexMethod == QGraphicsScene::NoIndex || !exposedRegion) { children = &this->topLevelItems; } else { - tmp = estimateItemsInRect(viewTransform.inverted().mapRect(exposedRegion->boundingRect())); + QRectF sceneRect = viewTransform.inverted().mapRect(QRectF(exposedRegion->boundingRect().adjusted(-1, -1, 1, 1))); + if (!largestUntransformableItem.isEmpty()) { + // ### Nuke this when we move the indexing code into a separate + // class. All the largestUntransformableItem code should then go + // away, and the estimate function should return untransformable + // items as well. + QRectF untr = largestUntransformableItem; + QRectF ltri = viewTransform.inverted().mapRect(untr); + ltri.adjust(-untr.width(), -untr.height(), untr.width(), untr.height()); + sceneRect.adjust(-ltri.width(), -ltri.height(), ltri.width(), ltri.height()); + } + tmp = estimateItemsInRect(sceneRect); QList<QGraphicsItem *> tli; - for (int i = 0; i < tmp.size(); ++i) { - QGraphicsItem *it = tmp.at(i)->topLevelItem(); - if (!it->d_ptr->itemDiscovered) { - tli << it; - it->d_ptr->itemDiscovered = 1; + for (int i = 0; i < tmp.size(); ++i) + tmp.at(i)->topLevelItem()->d_ptr->itemDiscovered = 1; + + // Sort if the toplevel list is unsorted. + if (needSortTopLevelItems) { + needSortTopLevelItems = false; + qStableSort(this->topLevelItems.begin(), + this->topLevelItems.end(), qt_notclosestLeaf); + } + + for (int i = 0; i < this->topLevelItems.size(); ++i) { + // ### Investigate smarter ways. Looping through all top level + // items is not optimal. If the BSP tree is to have maximum + // effect, it should be possible to sort the subset of items + // quickly. We must use this approach for now, as it's the only + // current way to keep the stable sorting order (insertion order). + QGraphicsItem *item = this->topLevelItems.at(i); + if (item->d_ptr->itemDiscovered) { + item->d_ptr->itemDiscovered = 0; + tli << item; } } - for (int i = 0; i < tli.size(); ++i) - tli.at(i)->d_ptr->itemDiscovered = 0; tmp = tli; children = &tmp; @@ -5147,9 +5171,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * if (item && item->d_ptr->needSortChildren) { item->d_ptr->needSortChildren = 0; qStableSort(children->begin(), children->end(), qt_notclosestLeaf); - } else if (!item && children == &tmp) { - qStableSort(children->begin(), children->end(), qt_notclosestLeaf); - } else if (!item && needSortTopLevelItems) { + } else if (!item && needSortTopLevelItems && children != &tmp) { needSortTopLevelItems = false; qStableSort(children->begin(), children->end(), qt_notclosestLeaf); } @@ -5220,7 +5242,7 @@ void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, b if (item->d_ptr->discardUpdateRequest(/*ignoreClipping=*/maybeDirtyClipPath, /*ignoreVisibleBit=*/force, - /*ignoreDirtyBit=*/removingItemFromScene, + /*ignoreDirtyBit=*/removingItemFromScene || invalidateChildren, /*ignoreOpacity=*/ignoreOpacity)) { return; } diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp index af34fe5..481dc6b 100644 --- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp @@ -226,6 +226,8 @@ private slots: void itemUsesExtendedStyleOption(); void itemSendsGeometryChanges(); void moveItem(); + void sorting_data(); + void sorting(); // task specific tests below me void task141694_textItemEnsureVisible(); @@ -6926,5 +6928,59 @@ void tst_QGraphicsItem::moveItem() QCOMPARE(view.paintedRegion, expectedParentRegion); } +void tst_QGraphicsItem::sorting_data() +{ + QTest::addColumn<int>("index"); + + QTest::newRow("NoIndex") << int(QGraphicsScene::NoIndex); + QTest::newRow("BspTreeIndex") << int(QGraphicsScene::BspTreeIndex); +} + +void tst_QGraphicsItem::sorting() +{ + _paintedItems.clear(); + + QGraphicsScene scene; + QGraphicsItem *grid[100][100]; + for (int x = 0; x < 100; ++x) { + for (int y = 0; y < 100; ++y) { + PainterItem *item = new PainterItem; + item->setPos(x * 25, y * 25); + item->setData(0, QString("%1x%2").arg(x).arg(y)); + grid[x][y] = item; + scene.addItem(item); + } + } + + PainterItem *item1 = new PainterItem; + PainterItem *item2 = new PainterItem; + item1->setData(0, "item1"); + item2->setData(0, "item2"); + scene.addItem(item1); + scene.addItem(item2); + + QGraphicsView view(&scene); + view.setResizeAnchor(QGraphicsView::NoAnchor); + view.setTransformationAnchor(QGraphicsView::NoAnchor); + view.resize(100, 100); + view.setFrameStyle(0); + view.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&view); +#endif + QTest::qWait(100); + + _paintedItems.clear(); + + view.viewport()->repaint(); + + QCOMPARE(_paintedItems, QList<QGraphicsItem *>() + << grid[0][0] << grid[0][1] << grid[0][2] << grid[0][3] + << grid[1][0] << grid[1][1] << grid[1][2] << grid[1][3] + << grid[2][0] << grid[2][1] << grid[2][2] << grid[2][3] + << grid[3][0] << grid[3][1] << grid[3][2] << grid[3][3] + << item1 << item2); +} + QTEST_MAIN(tst_QGraphicsItem) #include "tst_qgraphicsitem.moc" |