diff options
author | Martin Jones <martin.jones@nokia.com> | 2012-01-18 16:21:50 +1000 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-01-20 00:30:09 +0100 |
commit | d9fd9ff55d4d8717cb35b7af39f9f5f39f9a3448 (patch) | |
tree | ff2f7725482a36506c1b5a34a7a69ff79ec10c67 /src/quick/items/qquickitemview.cpp | |
parent | b1da5cb07922e786bd3223317651284b73159e82 (diff) |
Fix lockup in views due to endless polish loop.
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>
Diffstat (limited to 'src/quick/items/qquickitemview.cpp')
-rw-r--r-- | src/quick/items/qquickitemview.cpp | 81 |
1 files changed, 37 insertions, 44 deletions
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index 8ff8b8860c..3341402acd 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -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(); } } } |