From d32360bb33e830f8c17a6db1a31f529436c2915e Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Wed, 24 Nov 2010 11:25:07 +1000 Subject: Avoid lockup in ListView when animating delegates. Animating delegates results in the content height changing, which may result in fixup being called if at the ends of the view, which may in turn cause refill to be called, which will change the content height, which repeats. Prevent this recusion from happening. Task-number: QTBUG-14821 Reviewed-by: Bea Lam --- .../graphicsitems/qdeclarativelistview.cpp | 8 ++++++ .../qdeclarativelistview/data/qtbug14821.qml | 31 ++++++++++++++++++++++ .../tst_qdeclarativelistview.cpp | 21 +++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 tests/auto/declarative/qdeclarativelistview/data/qtbug14821.qml diff --git a/src/declarative/graphicsitems/qdeclarativelistview.cpp b/src/declarative/graphicsitems/qdeclarativelistview.cpp index 6be49ba..450b6af 100644 --- a/src/declarative/graphicsitems/qdeclarativelistview.cpp +++ b/src/declarative/graphicsitems/qdeclarativelistview.cpp @@ -183,6 +183,7 @@ public: , ownModel(false), wrap(false), autoHighlight(true), haveHighlightRange(false) , correctFlick(false), inFlickCorrection(false), lazyRelease(false) , deferredRelease(false), layoutScheduled(false), currentIndexCleared(false) + , inViewportMoved(false) , minExtentDirty(true), maxExtentDirty(true) {} @@ -503,6 +504,7 @@ public: bool deferredRelease : 1; bool layoutScheduled : 1; bool currentIndexCleared : 1; + bool inViewportMoved : 1; mutable bool minExtentDirty : 1; mutable bool maxExtentDirty : 1; }; @@ -2281,6 +2283,10 @@ void QDeclarativeListView::viewportMoved() QDeclarativeFlickable::viewportMoved(); if (!d->itemCount) return; + // Recursion can occur due to refill changing the content size. + if (d->inViewportMoved) + return; + d->inViewportMoved = true; d->lazyRelease = true; refill(); if (d->flickingHorizontally || d->flickingVertically || d->movingHorizontally || d->movingVertically) @@ -2294,6 +2300,7 @@ void QDeclarativeListView::viewportMoved() pos = viewPos + d->highlightRangeEnd - d->highlight->size(); if (pos < viewPos + d->highlightRangeStart) pos = viewPos + d->highlightRangeStart; + d->highlightPosAnimator->stop(); d->highlight->setPosition(qRound(pos)); // update current index @@ -2341,6 +2348,7 @@ void QDeclarativeListView::viewportMoved() } d->inFlickCorrection = false; } + d->inViewportMoved = false; } qreal QDeclarativeListView::minYExtent() const diff --git a/tests/auto/declarative/qdeclarativelistview/data/qtbug14821.qml b/tests/auto/declarative/qdeclarativelistview/data/qtbug14821.qml new file mode 100644 index 0000000..e0303ec --- /dev/null +++ b/tests/auto/declarative/qdeclarativelistview/data/qtbug14821.qml @@ -0,0 +1,31 @@ +import QtQuick 1.0 + +ListView { + id: view + width: 300; height: 200 + focus: true + keyNavigationWraps: true + + model: 100 + + preferredHighlightBegin: 90 + preferredHighlightEnd: 110 + + highlightRangeMode: ListView.StrictlyEnforceRange + highlight: Component { + Rectangle { + border.color: "blue" + border.width: 3 + color: "transparent" + width: 300; height: 15 + } + } + + delegate: Component { + Item { + height: 15 + (view.currentIndex == index ? 20 : 0) + width: 200 + Text { text: 'Index: ' + index; anchors.verticalCenter: parent.verticalCenter } + } + } +} diff --git a/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp b/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp index a4b4f21..37d836d 100644 --- a/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp +++ b/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp @@ -101,6 +101,7 @@ private slots: void footer(); void resizeView(); void sizeLessThan1(); + void QTBUG_14821(); private: template void items(); @@ -1768,6 +1769,26 @@ void tst_QDeclarativeListView::sizeLessThan1() delete canvas; } +void tst_QDeclarativeListView::QTBUG_14821() +{ + QDeclarativeView *canvas = createView(); + + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/qtbug14821.qml")); + qApp->processEvents(); + + QDeclarativeListView *listview = qobject_cast(canvas->rootObject()); + QVERIFY(listview != 0); + + QDeclarativeItem *contentItem = listview->contentItem(); + QVERIFY(contentItem != 0); + + listview->decrementCurrentIndex(); + QCOMPARE(listview->currentIndex(), 99); + + listview->incrementCurrentIndex(); + QCOMPARE(listview->currentIndex(), 0); +} + void tst_QDeclarativeListView::qListModelInterface_items() { items(); -- cgit v0.12