Don't ignore model changes when the ListView scroll position changes.
authorAndrew den Exter <andrew.den-exter@nokia.com>
Wed, 11 Apr 2012 06:22:52 +0000 (16:22 +1000)
committerQt by Nokia <qt-info@nokia.com>
Fri, 13 Apr 2012 06:07:16 +0000 (08:07 +0200)
If there are pending changes when the ListView viewport changes then
do a full layout instead of a refill.  Likewise for GridView and when
animations finish or the cacheBuffer size changes.

Change-Id: I57a2b01fee5729381558af366dad24ba26c223ef
Reviewed-by: Bea Lam <bea.lam@nokia.com>
src/quick/items/qquickgridview.cpp
src/quick/items/qquickitemview.cpp
src/quick/items/qquickitemview_p_p.h
src/quick/items/qquicklistview.cpp
tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
tests/auto/quick/qquicklistview/tst_qquicklistview.cpp

index 1fab4a8..0caf93c 100644 (file)
@@ -1884,7 +1884,7 @@ void QQuickGridView::viewportMoved()
     else
         d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferBefore : QQuickItemViewPrivate::BufferAfter;
 
-    d->refill();
+    d->refillOrLayout();
 
     // Set visibility of items to eliminate cost of items outside the visible area.
     qreal from = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
index 209d30a..64c05aa 100644 (file)
@@ -442,7 +442,7 @@ void QQuickItemView::setCacheBuffer(int b)
         d->buffer = b;
         if (isComponentComplete()) {
             d->bufferMode = QQuickItemViewPrivate::BufferBefore | QQuickItemViewPrivate::BufferAfter;
-            d->refill();
+            d->refillOrLayout();
         }
         emit cacheBufferChanged();
     }
@@ -1075,7 +1075,7 @@ void QQuickItemView::animStopped()
 {
     Q_D(QQuickItemView);
     d->bufferMode = QQuickItemViewPrivate::BufferBefore | QQuickItemViewPrivate::BufferAfter;
-    d->refill();
+    d->refillOrLayout();
     if (d->haveHighlightRange && d->highlightRange == QQuickItemView::StrictlyEnforceRange)
         d->updateHighlight();
 }
@@ -1777,7 +1777,7 @@ void QQuickItemViewPrivate::layout()
 bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult, ChangeResult *totalRemovalResult)
 {
     Q_Q(QQuickItemView);
-    if (!q->isComponentComplete() || (!currentChanges.hasPendingChanges() && !bufferedChanges.hasPendingChanges() && !runDelayedRemoveTransition) || disableLayout)
+    if (!q->isComponentComplete() || !hasPendingChanges() || disableLayout)
         return false;
 
     disableLayout = true;
index e352c46..1e29faf 100644 (file)
@@ -229,6 +229,19 @@ public:
             hData.markExtentsDirty();
     }
 
+    bool hasPendingChanges() const {
+        return currentChanges.hasPendingChanges()
+                || bufferedChanges.hasPendingChanges()
+                ||runDelayedRemoveTransition;
+    }
+
+    void refillOrLayout() {
+        if (hasPendingChanges())
+            layout();
+        else
+            refill();
+    }
+
     QQmlGuard<QQuickVisualModel> model;
     QVariant modelVariant;
     int itemCount;
index 1cc2637..b65cb85 100644 (file)
@@ -2557,7 +2557,7 @@ void QQuickListView::viewportMoved()
     else
         d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter;
 
-    d->refill();
+    d->refillOrLayout();
 
     // Set visibility of items to eliminate cost of items outside the visible area.
     qreal from = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
index f154e6e..5399a04 100644 (file)
@@ -89,8 +89,10 @@ private slots:
     void clear();
     void moved();
     void moved_data();
-    void multipleChanges();
-    void multipleChanges_data();
+    void multipleChanges_condensed() { multipleChanges(true); }
+    void multipleChanges_condensed_data() { multipleChanges_data(); }
+    void multipleChanges_uncondensed() { multipleChanges(false); }
+    void multipleChanges_uncondensed_data() { multipleChanges_data(); }
     void swapWithFirstItem();
     void changeFlow();
     void currentIndex();
@@ -154,6 +156,9 @@ private:
     void matchItemsAndIndexes(const QVariantMap &items, const QaimModel &model, const QList<int> &expectedIndexes);
     void matchItemLists(const QVariantList &itemLists, const QList<QQuickItem *> &expectedItems);
 
+    void multipleChanges(bool condensed);
+    void multipleChanges_data();
+
 #ifdef SHARE_VIEWS
     QQuickView *getView() {
         if (m_view) {
@@ -1323,7 +1328,7 @@ void tst_QQuickGridView::moved_data()
             << -1.0;   // 16,17,18 move to above item 0, all items move up by 1 row
 }
 
-void tst_QQuickGridView::multipleChanges()
+void tst_QQuickGridView::multipleChanges(bool condensed)
 {
     QFETCH(int, startCount);
     QFETCH(QList<ListChange>, changes);
@@ -1361,26 +1366,26 @@ void tst_QQuickGridView::multipleChanges()
             }
             case ListChange::Removed:
                 model.removeItems(changes[i].index, changes[i].count);
-                QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
                 break;
             case ListChange::Moved:
                 model.moveItems(changes[i].index, changes[i].to, changes[i].count);
-                QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
                 break;
             case ListChange::SetCurrent:
                 gridview->setCurrentIndex(changes[i].index);
-                QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
                 break;
             case ListChange::SetContentY:
                 gridview->setContentY(changes[i].pos);
-                QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
                 break;
         }
+        if (condensed) {
+            QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
+        }
     }
+    QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false);
 
-    QTRY_COMPARE(gridview->count(), newCount);
+    QCOMPARE(gridview->count(), newCount);
     QCOMPARE(gridview->count(), model.count());
-    QTRY_COMPARE(gridview->currentIndex(), newCurrentIndex);
+    QCOMPARE(gridview->currentIndex(), newCurrentIndex);
 
     QQuickText *name;
     QQuickText *number;
@@ -1549,6 +1554,28 @@ void tst_QQuickGridView::multipleChanges_data()
             << ListChange::remove(0, 5)
             << ListChange::insert(0, 5)
             ) << 5 << -1;
+
+    QTest::newRow("remove, scroll") << 30 << (QList<ListChange>()
+            << ListChange::remove(20, 5)
+            << ListChange::setContentY(20)
+            ) << 25 << 0;
+
+    QTest::newRow("insert, scroll") << 10 << (QList<ListChange>()
+            << ListChange::insert(9, 5)
+            << ListChange::setContentY(20)
+            ) << 15 << 0;
+
+    QTest::newRow("move, scroll") << 20 << (QList<ListChange>()
+            << ListChange::move(15, 8, 3)
+            << ListChange::setContentY(0)
+            ) << 20 << 0;
+
+    QTest::newRow("clear, insert, scroll") << 30 << (QList<ListChange>()
+            << ListChange::setContentY(20)
+            << ListChange::remove(0, 30)
+            << ListChange::insert(0, 2)
+            << ListChange::setContentY(0)
+            ) << 2 << 0;
 }
 
 
index 1ef895d..a3f9e93 100644 (file)
@@ -105,8 +105,10 @@ private slots:
     void qAbstractItemModel_moved();
     void qAbstractItemModel_moved_data();
 
-    void multipleChanges();
-    void multipleChanges_data();
+    void multipleChanges_condensed() { multipleChanges(true); }
+    void multipleChanges_condensed_data() { multipleChanges_data(); }
+    void multipleChanges_uncondensed() { multipleChanges(false); }
+    void multipleChanges_uncondensed_data() { multipleChanges_data(); }
 
     void qListModelInterface_clear();
     void qListModelInterface_package_clear();
@@ -202,6 +204,9 @@ private:
     template <class T> void clear(const QUrl &source);
     template <class T> void sections(const QUrl &source);
 
+    void multipleChanges(bool condensed);
+    void multipleChanges_data();
+
     QList<int> toIntList(const QVariantList &list);
     void matchIndexLists(const QVariantList &indexLists, const QList<int> &expectedIndexes);
     void matchItemsAndIndexes(const QVariantMap &items, const QaimModel &model, const QList<int> &expectedIndexes);
@@ -1403,7 +1408,7 @@ void tst_QQuickListView::moved_data()
             << -20.0 * 3;   // to minimize movement, 16,17,18 move to above item 0, and other items do not move
 }
 
-void tst_QQuickListView::multipleChanges()
+void tst_QQuickListView::multipleChanges(bool condensed)
 {
     QFETCH(int, startCount);
     QFETCH(QList<ListChange>, changes);
@@ -1439,31 +1444,32 @@ void tst_QQuickListView::multipleChanges()
                 for (int j=changes[i].index; j<changes[i].index + changes[i].count; ++j)
                     items << qMakePair(QString("new item %1").arg(j), QString::number(j));
                 model.insertItems(changes[i].index, items);
-                QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false);
                 break;
             }
             case ListChange::Removed:
                 model.removeItems(changes[i].index, changes[i].count);
-                QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false);
                 break;
             case ListChange::Moved:
                 model.moveItems(changes[i].index, changes[i].to, changes[i].count);
-                QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false);
                 break;
             case ListChange::SetCurrent:
                 listview->setCurrentIndex(changes[i].index);
-                QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false);
                 break;
             case ListChange::SetContentY:
                 listview->setContentY(changes[i].pos);
-                QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false);
                 break;
+            default:
+                continue;
+        }
+        if (!condensed) {
+            QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false);
         }
     }
+    QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false);
 
-    QTRY_COMPARE(listview->count(), newCount);
+    QCOMPARE(listview->count(), newCount);
     QCOMPARE(listview->count(), model.count());
-    QTRY_COMPARE(listview->currentIndex(), newCurrentIndex);
+    QCOMPARE(listview->currentIndex(), newCurrentIndex);
 
     QQuickText *name;
     QQuickText *number;
@@ -1626,13 +1632,34 @@ void tst_QQuickListView::multipleChanges_data()
             << ListChange::insert(3, 5)
             ) << 15 << 8;
 
-
     QTest::newRow("clear current") << 0 << (QList<ListChange>()
             << ListChange::insert(0, 5)
             << ListChange::setCurrent(-1)
             << ListChange::remove(0, 5)
             << ListChange::insert(0, 5)
             ) << 5 << -1;
+
+    QTest::newRow("remove, scroll") << 30 << (QList<ListChange>()
+            << ListChange::remove(20, 5)
+            << ListChange::setContentY(20)
+            ) << 25 << 0;
+
+    QTest::newRow("insert, scroll") << 10 << (QList<ListChange>()
+            << ListChange::insert(9, 5)
+            << ListChange::setContentY(20)
+            ) << 15 << 0;
+
+    QTest::newRow("move, scroll") << 20 << (QList<ListChange>()
+            << ListChange::move(15, 8, 3)
+            << ListChange::setContentY(0)
+            ) << 20 << 0;
+
+    QTest::newRow("clear, insert, scroll") << 30 << (QList<ListChange>()
+            << ListChange::setContentY(20)
+            << ListChange::remove(0, 30)
+            << ListChange::insert(0, 2)
+            << ListChange::setContentY(0)
+            ) << 2 << 0;
 }
 
 void tst_QQuickListView::swapWithFirstItem()