Fix lockup in views due to endless polish loop.
authorMartin Jones <martin.jones@nokia.com>
Wed, 18 Jan 2012 06:21:50 +0000 (16:21 +1000)
committerQt by Nokia <qt-info@nokia.com>
Thu, 19 Jan 2012 23:30:09 +0000 (00:30 +0100)
It was possible to cause an endless polish loop in some rare cases.
Eliminate all calls to polish() within existing polish() code paths.

Cleanup delegate creation and cancelling in the cacheBuffer area.

Adjust first item position correctly when inserting/removing before
visibleItems list.

Change-Id: I508a2e6de8cb09d904466cbf5fb6b5dfd1e89c49
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
src/quick/items/qquickvisualdatamodel.cpp
tests/auto/qtquick2/qquickgridview/tst_qquickgridview.cpp
tests/auto/qtquick2/qquicklistview/tst_qquicklistview.cpp

index ef79a4d..8cc9b42 100644 (file)
@@ -59,6 +59,8 @@ QT_BEGIN_NAMESPACE
 #define QML_FLICK_SNAPONETHRESHOLD 30
 #endif
 
+//#define DEBUG_DELEGATE_LIFECYCLE
+
 //----------------------------------------------------------------------------
 
 class FxGridItemSG : public FxViewItem
@@ -172,7 +174,7 @@ public:
     virtual FxViewItem *newViewItem(int index, QQuickItem *item);
     virtual void repositionPackageItemAt(QQuickItem *item, int index);
     virtual void resetFirstItemPosition(qreal pos = 0.0);
-    virtual void adjustFirstItem(qreal forwards, qreal backwards);
+    virtual void adjustFirstItem(qreal forwards, qreal backwards, int changeBeforeVisible);
 
     virtual void createHighlight();
     virtual void updateHighlight();
@@ -442,7 +444,9 @@ bool QQuickGridViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, bool d
     bool changed = false;
 
     while (modelIndex < model->count() && rowPos <= fillTo + rowSize()*(columns - colNum)/(columns+1)) {
-//        qDebug() << "refill: append item" << modelIndex << colPos << rowPos;
+#ifdef DEBUG_DELEGATE_LIFECYCLE
+        qDebug() << "refill: append item" << modelIndex << colPos << rowPos;
+#endif
         if (!(item = static_cast<FxGridItemSG*>(createItem(modelIndex, doBuffer))))
             break;
         item->setPosition(colPos, rowPos);
@@ -457,6 +461,9 @@ bool QQuickGridViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, bool d
         changed = true;
     }
 
+    if (doBuffer && requestedIndex != -1) // already waiting for an item
+        return changed;
+
     // Find first column
     if (visibleItems.count()) {
         FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
@@ -473,7 +480,9 @@ bool QQuickGridViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, bool d
     // Prepend
     colPos = colNum * colSize();
     while (visibleIndex > 0 && rowPos + rowSize() - 1 >= fillFrom - rowSize()*(colNum+1)/(columns+1)){
-//        qDebug() << "refill: prepend item" << visibleIndex-1 << "top pos" << rowPos << colPos;
+#ifdef DEBUG_DELEGATE_LIFECYCLE
+        qDebug() << "refill: prepend item" << visibleIndex-1 << "top pos" << rowPos << colPos;
+#endif
         if (!(item = static_cast<FxGridItemSG*>(createItem(visibleIndex-1, doBuffer))))
             break;
         --visibleIndex;
@@ -501,7 +510,9 @@ bool QQuickGridViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal buffer
                 && item->rowPos()+rowSize()-1 < bufferFrom - rowSize()*(item->colPos()/colSize()+1)/(columns+1)) {
         if (item->attached->delayRemove())
             break;
-//        qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endRowPos();
+#ifdef DEBUG_DELEGATE_LIFECYCLE
+        qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endRowPos();
+#endif
         if (item->index != -1)
             visibleIndex++;
         visibleItems.removeFirst();
@@ -513,7 +524,9 @@ bool QQuickGridViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal buffer
                 && item->rowPos() > bufferTo + rowSize()*(columns - item->colPos()/colSize())/(columns+1)) {
         if (item->attached->delayRemove())
             break;
-//        qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1;
+#ifdef DEBUG_DELEGATE_LIFECYCLE
+        qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1;
+#endif
         visibleItems.removeLast();
         releaseItem(item);
         changed = true;
@@ -590,12 +603,15 @@ void QQuickGridViewPrivate::resetFirstItemPosition(qreal pos)
     item->setPosition(0, pos);
 }
 
-void QQuickGridViewPrivate::adjustFirstItem(qreal forwards, qreal backwards)
+void QQuickGridViewPrivate::adjustFirstItem(qreal forwards, qreal backwards, int changeBeforeVisible)
 {
     if (!visibleItems.count())
         return;
 
-    int moveCount = (forwards / rowSize()) - (backwards / rowSize());
+    int moveCount = (forwards - backwards) / rowSize();
+
+    if (changeBeforeVisible)
+        moveCount += (changeBeforeVisible%columns) - (columns - 1);
 
     FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(visibleItems.first());
     gridItem->setPosition(gridItem->colPos(), gridItem->rowPos() + ((moveCount / columns) * rowSize()));
@@ -1419,7 +1435,7 @@ void QQuickGridView::setCellWidth(qreal cellWidth)
         d->updateViewport();
         emit cellWidthChanged();
         d->forceLayout = true;
-        d->layout();
+        polish();
     }
 }
 
@@ -1437,7 +1453,7 @@ void QQuickGridView::setCellHeight(qreal cellHeight)
         d->updateViewport();
         emit cellHeightChanged();
         d->forceLayout = true;
-        d->layout();
+        polish();
     }
 }
 /*!
@@ -1521,14 +1537,6 @@ void QQuickGridView::viewportMoved()
         return;
     d->inViewportMoved = true;
 
-    // Set visibility of items to eliminate cost of items outside the visible area.
-    qreal from = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
-    qreal to = d->isContentFlowReversed() ? -d->position() : d->position()+d->size();
-    for (int i = 0; i < d->visibleItems.count(); ++i) {
-        FxGridItemSG *item = static_cast<FxGridItemSG*>(d->visibleItems.at(i));
-        item->item->setVisible(item->rowPos() + d->rowSize() >= from && item->rowPos() <= to);
-    }
-
     if (yflick())
         d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferBefore : QQuickItemViewPrivate::BufferAfter;
     else if (d->isRightToLeftTopToBottom())
@@ -1537,6 +1545,15 @@ void QQuickGridView::viewportMoved()
         d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferBefore : QQuickItemViewPrivate::BufferAfter;
 
     d->refill();
+
+    // Set visibility of items to eliminate cost of items outside the visible area.
+    qreal from = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
+    qreal to = d->isContentFlowReversed() ? -d->position() : d->position()+d->size();
+    for (int i = 0; i < d->visibleItems.count(); ++i) {
+        FxGridItemSG *item = static_cast<FxGridItemSG*>(d->visibleItems.at(i));
+        item->item->setVisible(item->rowPos() + d->rowSize() >= from && item->rowPos() <= to);
+    }
+
     if (d->hData.flicking || d->vData.flicking || d->hData.moving || d->vData.moving)
         d->moveReason = QQuickGridViewPrivate::Mouse;
     if (d->moveReason != QQuickGridViewPrivate::SetIndex) {
@@ -1817,7 +1834,7 @@ bool QQuickGridViewPrivate::applyInsertionChange(const QDeclarativeChangeSet::In
         while (i >= 0) {
             if (rowPos > from && insertionIdx < visibleIndex) {
                 // item won't be visible, just note the size for repositioning
-                insertResult->sizeChangesBeforeVisiblePos += rowSize();
+                insertResult->changeBeforeVisible++;
             } else {
                 // item is before first visible e.g. in cache buffer
                 FxViewItem *item = 0;
index 8ff8b88..3341402 100644 (file)
@@ -775,7 +775,7 @@ void QQuickItemView::destroyRemoved()
     // Correct the positioning of the items
     d->updateSections();
     d->forceLayout = true;
-    d->layout();
+    polish();
 }
 
 void QQuickItemView::modelUpdated(const QDeclarativeChangeSet &changeSet, bool reset)
@@ -1114,7 +1114,7 @@ QQuickItemViewPrivate::QQuickItemViewPrivate()
     , highlightMoveDuration(150)
     , headerComponent(0), header(0), footerComponent(0), footer(0)
     , minExtent(0), maxExtent(0)
-    , ownModel(false), wrap(false), deferredRelease(false)
+    , ownModel(false), wrap(false)
     , inApplyModelChanges(false), inViewportMoved(false), forceLayout(false), currentIndexCleared(false)
     , haveHighlightRange(false), autoHighlight(true), highlightRangeStartValid(false), highlightRangeEndValid(false)
     , fillCacheBuffer(false), inRequest(false), requestedAsync(false)
@@ -1301,7 +1301,7 @@ void QQuickItemViewPrivate::refill()
         refill(position(), position()+s);
 }
 
-void QQuickItemViewPrivate::refill(qreal from, qreal to, bool doBuffer)
+void QQuickItemViewPrivate::refill(qreal from, qreal to)
 {
     Q_Q(QQuickItemView);
     if (!isValid() || !q->isComponentComplete())
@@ -1315,35 +1315,22 @@ void QQuickItemViewPrivate::refill(qreal from, qreal to, bool doBuffer)
     qreal bufferTo = to + buffer;
     qreal fillFrom = from;
     qreal fillTo = to;
-    if (doBuffer && (bufferMode & BufferAfter))
-        fillTo = bufferTo;
-    if (doBuffer && (bufferMode & BufferBefore))
-        fillFrom = bufferFrom;
-
-    // Item creation and release is staggered in order to avoid
-    // creating/releasing multiple items in one frame
-    // while flicking (as much as possible).
 
-    bool changed = addVisibleItems(fillFrom, fillTo, doBuffer);
+    bool added = addVisibleItems(fillFrom, fillTo, false);
+    bool removed = removeNonVisibleItems(bufferFrom, bufferTo);
 
-    if (!changed || deferredRelease) { // avoid destroying items in the same frame that we create
-        if (removeNonVisibleItems(bufferFrom, bufferTo))
-            changed = true;
-        deferredRelease = false;
-    } else {
-        deferredRelease = true;
+    if (buffer && bufferMode != NoBuffer) {
+        if (bufferMode & BufferAfter)
+            fillTo = bufferTo;
+        if (bufferMode & BufferBefore)
+            fillFrom = bufferFrom;
+        added |= addVisibleItems(fillFrom, fillTo, true);
     }
 
-    if (changed) {
+    if (added || removed) {
         markExtentsDirty();
+        updateBeginningEnd();
         visibleItemsChanged();
-    } else if (!doBuffer && buffer && bufferMode != NoBuffer) {
-        refill(from, to, true);
-    }
-
-    if (!q->isMoving() && changed) {
-        fillCacheBuffer = true;
-        q->polish();
     }
 
     if (prevCount != itemCount)
@@ -1393,8 +1380,10 @@ void QQuickItemViewPrivate::layout()
     }
 
     if (!applyModelChanges() && !forceLayout) {
-        if (fillCacheBuffer)
+        if (fillCacheBuffer) {
+            fillCacheBuffer = false;
             refill();
+        }
         return;
     }
     forceLayout = false;
@@ -1459,7 +1448,7 @@ bool QQuickItemViewPrivate::applyModelChanges()
 
         // set positions correctly for the next insertion
         if (!insertions.isEmpty()) {
-            repositionFirstItem(prevVisibleItemsFirst, prevVisibleItemsFirstPos, prevFirstVisible, insertionResult, removalResult);
+            repositionFirstItem(prevVisibleItemsFirst, prevVisibleItemsFirstPos, prevFirstVisible, &insertionResult, &removalResult);
             layoutVisibleItems(removals.first().index);
         }
     }
@@ -1476,7 +1465,7 @@ bool QQuickItemViewPrivate::applyModelChanges()
 
         // set positions correctly for the next insertion
         if (i < insertions.count() - 1) {
-            repositionFirstItem(prevVisibleItemsFirst, prevVisibleItemsFirstPos, prevFirstVisible, insertionResult, removalResult);
+            repositionFirstItem(prevVisibleItemsFirst, prevVisibleItemsFirstPos, prevFirstVisible, &insertionResult, &removalResult);
             layoutVisibleItems(insertions[i].index);
         }
 
@@ -1487,7 +1476,7 @@ bool QQuickItemViewPrivate::applyModelChanges()
 
     // reposition visibleItems.first() correctly so that the content y doesn't jump
     if (removedCount != prevVisibleItemsCount)
-        repositionFirstItem(prevVisibleItemsFirst, prevVisibleItemsFirstPos, prevFirstVisible, insertionResult, removalResult);
+        repositionFirstItem(prevVisibleItemsFirst, prevVisibleItemsFirstPos, prevFirstVisible, &insertionResult, &removalResult);
 
     // Whatever removed/moved items remain are no longer visible items.
     for (QHash<QDeclarativeChangeSet::MoveKey, FxViewItem *>::Iterator it = currentChanges.removedItems.begin();
@@ -1567,27 +1556,31 @@ bool QQuickItemViewPrivate::applyRemovalChange(const QDeclarativeChangeSet::Remo
             }
         }
     }
+
+    if (removal.index + removal.count < visibleIndex)
+        removeResult->changeBeforeVisible -= removal.count;
+
     return visibleAffected;
 }
 
 void QQuickItemViewPrivate::repositionFirstItem(FxViewItem *prevVisibleItemsFirst,
                                                    qreal prevVisibleItemsFirstPos,
                                                    FxViewItem *prevFirstVisible,
-                                                   const ChangeResult &insertionResult,
-                                                   const ChangeResult &removalResult)
+                                                   ChangeResult *insertionResult,
+                                                   ChangeResult *removalResult)
 {
-    const QDeclarativeNullableValue<qreal> prevViewPos = insertionResult.visiblePos;
+    const QDeclarativeNullableValue<qreal> prevViewPos = insertionResult->visiblePos;
 
     // reposition visibleItems.first() correctly so that the content y doesn't jump
     if (visibleItems.count()) {
-        if (prevVisibleItemsFirst && insertionResult.changedFirstItem)
+        if (prevVisibleItemsFirst && insertionResult->changedFirstItem)
             resetFirstItemPosition(prevVisibleItemsFirstPos);
 
         if (prevFirstVisible && prevVisibleItemsFirst == prevFirstVisible
                 && prevFirstVisible != *visibleItems.constBegin()) {
             // the previous visibleItems.first() was also the first visible item, and it has been
             // moved/removed, so move the new visibleItems.first() to the pos of the previous one
-            if (!insertionResult.changedFirstItem)
+            if (!insertionResult->changedFirstItem)
                 resetFirstItemPosition(prevVisibleItemsFirstPos);
 
         } else if (prevViewPos.isValid()) {
@@ -1596,14 +1589,16 @@ void QQuickItemViewPrivate::repositionFirstItem(FxViewItem *prevVisibleItemsFirs
 
             // shift visibleItems.first() relative to the number of added/removed items
             if (visibleItems.first()->position() > prevViewPos) {
-                moveForwardsBy = insertionResult.sizeChangesAfterVisiblePos;
-                moveBackwardsBy = removalResult.sizeChangesAfterVisiblePos;
+                moveForwardsBy = insertionResult->sizeChangesAfterVisiblePos;
+                moveBackwardsBy = removalResult->sizeChangesAfterVisiblePos;
             } else if (visibleItems.first()->position() < prevViewPos) {
-                moveForwardsBy = removalResult.sizeChangesBeforeVisiblePos;
-                moveBackwardsBy = insertionResult.sizeChangesBeforeVisiblePos;
+                moveForwardsBy = removalResult->sizeChangesBeforeVisiblePos;
+                moveBackwardsBy = insertionResult->sizeChangesBeforeVisiblePos;
             }
-            adjustFirstItem(moveForwardsBy, moveBackwardsBy);
+            adjustFirstItem(moveForwardsBy, moveBackwardsBy, insertionResult->changeBeforeVisible + removalResult->changeBeforeVisible);
         }
+        insertionResult->reset();
+        removalResult->reset();
     }
 }
 
@@ -1619,6 +1614,8 @@ FxViewItem *QQuickItemViewPrivate::createItem(int modelIndex, bool asynchronous)
         return 0;
 
     if (requestedIndex != -1 && requestedIndex != modelIndex) {
+        if (requestedItem && requestedItem->item)
+            requestedItem->item->setParentItem(0);
         delete requestedItem;
         requestedItem = 0;
     }
@@ -1631,7 +1628,6 @@ FxViewItem *QQuickItemViewPrivate::createItem(int modelIndex, bool asynchronous)
         item->setParentItem(q->contentItem());
         QDeclarative_setParent_noEvent(item, q->contentItem());
         requestedIndex = -1;
-        fillCacheBuffer = false;
         FxViewItem *viewItem = requestedItem;
         if (!viewItem)
             viewItem = newViewItem(modelIndex, item); // already in cache, so viewItem not initialized in initItem()
@@ -1665,9 +1661,6 @@ void QQuickItemView::createdItem(int index, QQuickItem *item)
             if (index == d->currentIndex)
                 d->updateCurrent(index);
             d->refill();
-        } else {
-            d->fillCacheBuffer = true;
-            polish();
         }
     }
 }
index a2dd963..52463af 100644 (file)
@@ -104,9 +104,18 @@ public:
         qreal sizeChangesBeforeVisiblePos;
         qreal sizeChangesAfterVisiblePos;
         bool changedFirstItem;
+        int changeBeforeVisible;
 
         ChangeResult(const QDeclarativeNullableValue<qreal> &p)
-            : visiblePos(p), sizeChangesBeforeVisiblePos(0), sizeChangesAfterVisiblePos(0), changedFirstItem(false) {}
+            : visiblePos(p), sizeChangesBeforeVisiblePos(0), sizeChangesAfterVisiblePos(0),
+            changedFirstItem(false), changeBeforeVisible(0) {}
+
+        void reset() {
+            sizeChangesBeforeVisiblePos = 0.0;
+            sizeChangesAfterVisiblePos = 0.0;
+            changedFirstItem = false;
+            changeBeforeVisible = 0;
+        }
     };
 
     enum BufferMode { NoBuffer = 0x00, BufferBefore = 0x01, BufferAfter = 0x02 };
@@ -130,7 +139,7 @@ public:
     void regenerate();
     void layout();
     void refill();
-    void refill(qreal from, qreal to, bool doBuffer = false);
+    void refill(qreal from, qreal to);
     void mirrorChange();
 
     FxViewItem *createItem(int modelIndex, bool asynchronous = false);
@@ -149,7 +158,7 @@ public:
     bool applyModelChanges();
     bool applyRemovalChange(const QDeclarativeChangeSet::Remove &removal, ChangeResult *changeResult, int *removedCount);
     void repositionFirstItem(FxViewItem *prevVisibleItemsFirst, qreal prevVisibleItemsFirstPos,
-            FxViewItem *prevFirstVisible, const ChangeResult &insertionResult, const ChangeResult &removalResult);
+            FxViewItem *prevFirstVisible, ChangeResult *insertionResult, ChangeResult *removalResult);
 
     void checkVisible() const;
 
@@ -197,7 +206,6 @@ public:
 
     bool ownModel : 1;
     bool wrap : 1;
-    bool deferredRelease : 1;
     bool inApplyModelChanges : 1;
     bool inViewportMoved : 1;
     bool forceLayout : 1;
@@ -240,7 +248,7 @@ protected:
     virtual FxViewItem *newViewItem(int index, QQuickItem *item) = 0;
     virtual void repositionPackageItemAt(QQuickItem *item, int index) = 0;
     virtual void resetFirstItemPosition(qreal pos = 0.0) = 0;
-    virtual void adjustFirstItem(qreal forwards, qreal backwards) = 0;
+    virtual void adjustFirstItem(qreal forwards, qreal backwards, int changeBeforeVisible) = 0;
 
     virtual void layoutVisibleItems(int fromModelIndex = 0) = 0;
     virtual void changedVisibleIndex(int newIndex) = 0;
index f0ced5f..6215527 100644 (file)
@@ -60,6 +60,8 @@ QT_BEGIN_NAMESPACE
 #define QML_FLICK_SNAPONETHRESHOLD 30
 #endif
 
+//#define DEBUG_DELEGATE_LIFECYCLE
+
 class FxListItemSG;
 
 class QQuickListViewPrivate : public QQuickItemViewPrivate
@@ -94,7 +96,7 @@ public:
     virtual void releaseItem(FxViewItem *item);
     virtual void repositionPackageItemAt(QQuickItem *item, int index);
     virtual void resetFirstItemPosition(qreal pos = 0.0);
-    virtual void adjustFirstItem(qreal forwards, qreal backwards);
+    virtual void adjustFirstItem(qreal forwards, qreal backwards, int);
 
     virtual void createHighlight();
     virtual void updateHighlight();
@@ -601,7 +603,9 @@ bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, bool d
     FxListItemSG *item = 0;
     qreal pos = itemEnd;
     while (modelIndex < model->count() && pos <= fillTo) {
-//        qDebug() << "refill: append item" << modelIndex << "pos" << pos;
+#ifdef DEBUG_DELEGATE_LIFECYCLE
+        qDebug() << "refill: append item" << modelIndex << "pos" << pos;
+#endif
         if (!(item = static_cast<FxListItemSG*>(createItem(modelIndex, doBuffer))))
             break;
         item->setPosition(pos);
@@ -611,8 +615,14 @@ bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, bool d
         ++modelIndex;
         changed = true;
     }
+
+    if (doBuffer && requestedIndex != -1) // already waiting for an item
+        return changed;
+
     while (visibleIndex > 0 && visibleIndex <= model->count() && visiblePos > fillFrom) {
-//        qDebug() << "refill: prepend item" << visibleIndex-1 << "current top pos" << visiblePos;
+#ifdef DEBUG_DELEGATE_LIFECYCLE
+        qDebug() << "refill: prepend item" << visibleIndex-1 << "current top pos" << visiblePos;
+#endif
         if (!(item = static_cast<FxListItemSG*>(createItem(visibleIndex-1, doBuffer))))
             break;
         --visibleIndex;
@@ -641,8 +651,9 @@ bool QQuickListViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal buffer
         if (item->attached->delayRemove())
             break;
         if (item->size() > 0) {
-//            qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endPosition();
-
+#ifdef DEBUG_DELEGATE_LIFECYCLE
+            qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endPosition();
+#endif
             // remove this item and all zero-sized items before it
             while (item) {
                 if (item->index != -1)
@@ -662,7 +673,9 @@ bool QQuickListViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal buffer
     while (visibleItems.count() > 1 && (item = visibleItems.last()) && item->position() > bufferTo) {
         if (item->attached->delayRemove())
             break;
-//        qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1 << item->position();
+#ifdef DEBUG_DELEGATE_LIFECYCLE
+        qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1 << item->position();
+#endif
         visibleItems.removeLast();
         releaseItem(item);
         changed = true;
@@ -741,7 +754,7 @@ void QQuickListViewPrivate::resetFirstItemPosition(qreal pos)
     item->setPosition(pos);
 }
 
-void QQuickListViewPrivate::adjustFirstItem(qreal forwards, qreal backwards)
+void QQuickListViewPrivate::adjustFirstItem(qreal forwards, qreal backwards, int)
 {
     if (!visibleItems.count())
         return;
@@ -1822,7 +1835,7 @@ void QQuickListView::setSpacing(qreal spacing)
     if (spacing != d->spacing) {
         d->spacing = spacing;
         d->forceLayout = true;
-        d->layout();
+        polish();
         emit spacingChanged();
     }
 }
@@ -2188,14 +2201,6 @@ void QQuickListView::viewportMoved()
         return;
     d->inViewportMoved = true;
 
-    // Set visibility of items to eliminate cost of items outside the visible area.
-    qreal from = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
-    qreal to = d->isContentFlowReversed() ? -d->position() : d->position()+d->size();
-    for (int i = 0; i < d->visibleItems.count(); ++i) {
-        FxViewItem *item = static_cast<FxListItemSG*>(d->visibleItems.at(i));
-        item->item->setVisible(item->endPosition() >= from && item->position() <= to);
-    }
-
     if (yflick())
         d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter;
     else if (d->isRightToLeft())
@@ -2204,6 +2209,15 @@ void QQuickListView::viewportMoved()
         d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter;
 
     d->refill();
+
+    // Set visibility of items to eliminate cost of items outside the visible area.
+    qreal from = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
+    qreal to = d->isContentFlowReversed() ? -d->position() : d->position()+d->size();
+    for (int i = 0; i < d->visibleItems.count(); ++i) {
+        FxViewItem *item = static_cast<FxListItemSG*>(d->visibleItems.at(i));
+        item->item->setVisible(item->endPosition() >= from && item->position() <= to);
+    }
+
     if (d->hData.flicking || d->vData.flicking || d->hData.moving || d->vData.moving)
         d->moveReason = QQuickListViewPrivate::Mouse;
     if (d->moveReason != QQuickListViewPrivate::SetIndex) {
@@ -2365,7 +2379,7 @@ void QQuickListView::updateSections()
         d->updateSections();
         if (d->itemCount) {
             d->forceLayout = true;
-            d->layout();
+            polish();
         }
     }
 }
index 3de1e91..d52aec0 100644 (file)
@@ -425,6 +425,10 @@ QQuickVisualDataModel::ReleaseFlags QQuickVisualDataModelPrivate::release(QObjec
             if (QQuickItem *item = qobject_cast<QQuickItem *>(object))
                 emitDestroyingItem(item);
             cacheItem->object = 0;
+            if (cacheItem->incubationTask) {
+                releaseIncubator(cacheItem->incubationTask);
+                cacheItem->incubationTask = 0;
+            }
             stat |= QQuickVisualModel::Destroyed;
         } else {
             stat |= QQuickVisualDataModel::Referenced;
index 132fa5f..15abe32 100644 (file)
@@ -467,7 +467,7 @@ void tst_QQuickGridView::inserted_more()
     // check visibleItems.first() is in correct position
     QQuickItem *item0 = findItem<QQuickItem>(contentItem, "wrapper", 0);
     QVERIFY(item0);
-    QCOMPARE(item0->y(), itemsOffsetAfterMove);
+    QCOMPARE(item0->y(), 0.0);
 
     QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
     int firstVisibleIndex = -1;
@@ -840,6 +840,7 @@ void tst_QQuickGridView::removed_more()
     QFETCH(int, removeIndex);
     QFETCH(int, removeCount);
     QFETCH(qreal, itemsOffsetAfterMove);
+    QFETCH(QString, firstVisible);
 
     QQuickText *name;
     QQuickText *number;
@@ -868,22 +869,20 @@ void tst_QQuickGridView::removed_more()
     model.removeItems(removeIndex, removeCount);
     QTRY_COMPARE(gridview->property("count").toInt(), model.count());
 
-    // check visibleItems.first() is in correct position
-    QQuickItem *item0 = findItem<QQuickItem>(contentItem, "wrapper", 0);
-//    qApp->exec();
-    QVERIFY(item0);
-    QCOMPARE(item0->y(), itemsOffsetAfterMove);
-
+    QString firstName;
     int firstVisibleIndex = -1;
     QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
     for (int i=0; i<items.count(); i++) {
         if (items[i]->y() >= contentY) {
             QDeclarativeExpression e(qmlContext(items[i]), items[i], "index");
             firstVisibleIndex = e.evaluate().toInt();
+            QDeclarativeExpression en(qmlContext(items[i]), items[i], "name");
+            firstName = en.evaluate().toString();
             break;
         }
     }
     QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
+    QCOMPARE(firstName, firstVisible);
 
     // Confirm items positioned correctly and indexes correct
     int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
@@ -911,21 +910,27 @@ void tst_QQuickGridView::removed_more_data()
     QTest::addColumn<int>("removeIndex");
     QTest::addColumn<int>("removeCount");
     QTest::addColumn<qreal>("itemsOffsetAfterMove");
+    QTest::addColumn<QString>("firstVisible");
 
     QTest::newRow("remove 1, before visible items")
             << 120.0     // show 6-23
             << 3 << 1
-            << 0.0;
+            << 0.0 << "Item7";
 
     QTest::newRow("remove multiple, all before visible items")
             << 120.0
             << 1 << 3
-            << 60.0;    // removed top row, slide down by 1 row
+            << 60.0 << "Item6";    // removed top row, slide down by 1 row
 
     QTest::newRow("remove multiple, all before visible items, remove item 0")
             << 120.0
             << 0 << 4
-            << 60.0;    // removed top row, slide down by 1 row
+            << 60.0 << "Item7";    // removed top row, slide down by 1 row
+
+    QTest::newRow("remove multiple rows, all before visible items")
+            << 240.0     // show 12-29
+            << 1 << 7
+            << 120.0 << "Item13";
 
 
     // remove 3,4,5 before the visible pos, first row moves down to just before the visible pos,
@@ -933,80 +938,80 @@ void tst_QQuickGridView::removed_more_data()
     QTest::newRow("remove multiple, mix of items from before and within visible items")
             << 120.0
             << 3 << 5
-            << 60.0;    // adjust for the 1 row removed before the visible
+            << 60.0 << "Item8";    // adjust for the 1 row removed before the visible
 
     QTest::newRow("remove multiple, mix of items from before and within visible items, remove item 0")
             << 120.0
             << 0 << 8
-            << 60.0 * 2;    // adjust for the 2 rows removed before the visible
+            << 60.0 * 2 << "Item8";    // adjust for the 2 rows removed before the visible
 
 
     QTest::newRow("remove 1, from start of visible, content at start")
             << 0.0
             << 0 << 1
-            << 0.0;
+            << 0.0 << "Item1";
 
     QTest::newRow("remove multiple, from start of visible, content at start")
             << 0.0
             << 0 << 3
-            << 0.0;
+            << 0.0 << "Item3";
 
     QTest::newRow("remove 1, from start of visible, content not at start")
             << 120.0     // show 6-23
             << 4 << 1
-            << 0.0;
+            << 0.0 << "Item7";
 
     QTest::newRow("remove multiple, from start of visible, content not at start")
             << 120.0     // show 6-23
             << 4 << 3
-            << 0.0;
+            << 0.0 << "Item9";
 
 
     QTest::newRow("remove 1, from middle of visible, content at start")
             << 0.0
             << 10 << 1
-            << 0.0;
+            << 0.0 << "Item0";
 
     QTest::newRow("remove multiple, from middle of visible, content at start")
             << 0.0
             << 10 << 5
-            << 0.0;
+            << 0.0 << "Item0";
 
     QTest::newRow("remove 1, from middle of visible, content not at start")
             << 120.0     // show 6-23
             << 10 << 1
-            << 0.0;
+            << 0.0 << "Item6";
 
     QTest::newRow("remove multiple, from middle of visible, content not at start")
             << 120.0     // show 6-23
             << 10 << 5
-            << 0.0;
+            << 0.0 << "Item6";
 
 
     QTest::newRow("remove 1, after visible, content at start")
             << 0.0
             << 16 << 1
-            << 0.0;
+            << 0.0 << "Item0";
 
     QTest::newRow("remove multiple, after visible, content at start")
             << 0.0
             << 16 << 5
-            << 0.0;
+            << 0.0 << "Item0";
 
     QTest::newRow("remove 1, after visible, content not at start")
             << 120.0     // show 6-23
             << 16+4 << 1
-            << 0.0;
+            << 0.0 << "Item6";
 
     QTest::newRow("remove multiple, after visible, content not at start")
             << 120.0     // show 6-23
             << 16+4 << 5
-            << 0.0;
+            << 0.0 << "Item6";
 
     QTest::newRow("remove multiple, mix of items from within and after visible items")
             << 120.0     // show 6-23
             << 20 << 5
-            << 0.0;
+            << 0.0 << "Item6";
 }
 
 void tst_QQuickGridView::addOrRemoveBeforeVisible()
@@ -1092,7 +1097,7 @@ void tst_QQuickGridView::addOrRemoveBeforeVisible_data()
     QTest::addColumn<qreal>("newTopContentY");
 
     QTest::newRow("add") << true << -60.0;
-    QTest::newRow("remove") << false << 0.0;
+    QTest::newRow("remove") << false << -60.0;
 }
 
 void tst_QQuickGridView::clear()
@@ -1135,11 +1140,6 @@ void tst_QQuickGridView::clear()
 
 void tst_QQuickGridView::moved()
 {
-    if (QTest::currentDataTag() == QLatin1String("move 1 forwards, from non-visible -> visible")
-            || QTest::currentDataTag() == QLatin1String("move 1 forwards, from non-visible -> visible (move first item)")) {
-        QSKIP("QTBUG-23455");
-    }
-
     QFETCH(qreal, contentY);
     QFETCH(int, from);
     QFETCH(int, to);
@@ -1223,13 +1223,11 @@ void tst_QQuickGridView::moved_data()
             << 1 << 8 << 1
             << 0.0;
 
-    // skipped QTBUG-23455
     QTest::newRow("move 1 forwards, from non-visible -> visible")
             << 120.0     // show 6-23
             << 1 << 23 << 1
             << 0.0;
 
-    // skipped QTBUG-23455
     QTest::newRow("move 1 forwards, from non-visible -> visible (move first item)")
             << 120.0     // // show 6-23
             << 0 << 6 << 1
index 1953cf7..bb168e4 100644 (file)
@@ -1961,8 +1961,8 @@ void tst_QQuickListView::spacing()
     QTRY_VERIFY(listview->spacing() == 10);
 
     // Confirm items positioned correctly
-    itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
-    for (int i = 0; i < model.count() && i < itemCount; ++i) {
+    QTRY_VERIFY(findItems<QQuickItem>(contentItem, "wrapper").count() == 11);
+    for (int i = 0; i < 11; ++i) {
         QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
         if (!item) qWarning() << "Item" << i << "not found";
         QTRY_VERIFY(item);
@@ -1972,8 +1972,8 @@ void tst_QQuickListView::spacing()
     listview->setSpacing(0);
 
     // Confirm items positioned correctly
-    itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
-    for (int i = 0; i < model.count() && i < itemCount; ++i) {
+    QTRY_VERIFY(findItems<QQuickItem>(contentItem, "wrapper").count() >= 16);
+    for (int i = 0; i < 16; ++i) {
         QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
         if (!item) qWarning() << "Item" << i << "not found";
         QTRY_VERIFY(item);
@@ -2264,7 +2264,7 @@ void tst_QQuickListView::sectionsPositioning()
     model.modifyItem(2, "Three", "aaa");
     model.modifyItem(3, "Four", "aaa");
     model.modifyItem(4, "Five", "aaa");
-    QTest::qWait(300);
+    QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false);
 
     QTRY_COMPARE(listview->currentSection(), QString("aaa"));
 
@@ -2275,8 +2275,7 @@ void tst_QQuickListView::sectionsPositioning()
         QTRY_COMPARE(item->y(), qreal(i*20*6));
     }
 
-    topItem = findVisibleChild(contentItem, "sect_aaa"); // section header
-    QVERIFY(topItem);
+    QTRY_VERIFY(topItem = findVisibleChild(contentItem, "sect_aaa")); // section header
     QCOMPARE(topItem->y(), 10.);
 
     // remove section boundary