Fix refill where zero-size items are involved
authorBea Lam <bea.lam@nokia.com>
Thu, 10 Nov 2011 04:30:08 +0000 (14:30 +1000)
committerQt by Nokia <qt-info@nokia.com>
Wed, 16 Nov 2011 03:39:26 +0000 (04:39 +0100)
881091b5c0f1d2ead2b70e54f7ac2e4c17680b4e was incorrect since it meant
that any items following zero-sized delegates would not be deleted as
they scrolled up past the top of the view.

refill() should be deleting these items as well as any zero-sized items
before them.

Task-number: QTBUG-22014
Change-Id: I10cd30bb85a8ec1ddaa2a1cbaa924192536ef6fc
Reviewed-by: Martin Jones <martin.jones@nokia.com>
src/declarative/items/qquicklistview.cpp
tests/auto/declarative/qquicklistview/tst_qquicklistview.cpp

index 9dc9130..4fd4e97 100644 (file)
@@ -634,18 +634,34 @@ bool QQuickListViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal buffer
     FxViewItem *item = 0;
     bool changed = false;
 
-    while (visibleItems.count() > 1 && (item = visibleItems.first()) && item->endPosition() <= bufferFrom) {
+    // Remove items from the start of the view.
+    // Zero-sized items shouldn't be removed unless a non-zero-sized item is also being
+    // removed, otherwise a zero-sized item is infinitely added and removed over and
+    // over by refill().
+    int index = 0;
+    while (visibleItems.count() > 1 && index < visibleItems.count()
+           && (item = visibleItems.at(index)) && item->endPosition() <= bufferFrom) {
         if (item->attached->delayRemove())
             break;
-        if (item->size() == 0)
-            break;
+        if (item->size() > 0) {
 //            qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endPosition();
-        if (item->index != -1)
-            visibleIndex++;
-        visibleItems.removeFirst();
-        releaseItem(item);
-        changed = true;
+
+            // remove this item and all zero-sized items before it
+            while (item) {
+                if (item->index != -1)
+                    visibleIndex++;
+                visibleItems.removeAt(index);
+                releaseItem(item);
+                if (index == 0)
+                    break;
+                item = visibleItems.at(--index);
+            }
+            changed = true;
+        } else {
+            index++;
+        }
     }
+
     while (visibleItems.count() > 1 && (item = visibleItems.last()) && item->position() > bufferTo) {
         if (item->attached->delayRemove())
             break;
index ae37724..36824f8 100644 (file)
@@ -3468,7 +3468,7 @@ void tst_QQuickListView::resizeFirstDelegate()
     // check the content y has not jumped up and down
     QCOMPARE(listview->contentY(), 0.0);
     QSignalSpy spy(listview, SIGNAL(contentYChanged()));
-    QTest::qWait(300);
+    QTest::qWait(100);
     QCOMPARE(spy.count(), 0);
 
     for (int i = 1; i < model.count(); ++i) {
@@ -3477,6 +3477,24 @@ void tst_QQuickListView::resizeFirstDelegate()
         QTRY_COMPARE(item->y(), (i-1)*20.0);
     }
 
+
+    // QTBUG-22014: refill doesn't clear items scrolling off the top of the
+    // list if they follow a zero-sized delegate
+
+    for (int i = 0; i < 10; i++)
+        model.addItem("Item" + QString::number(i), "");
+
+    item = findItem<QQuickItem>(contentItem, "wrapper", 1);
+    QVERIFY(item);
+    item->setHeight(0);
+
+    listview->setCurrentIndex(19);
+    qApp->processEvents();
+
+    // items 0-3 should have been deleted
+    for (int i=0; i<4; i++)
+        QTRY_VERIFY(!findItem<QQuickItem>(contentItem, "wrapper", i));
+
     delete testObject;
     delete canvas;
 }