libqt5-qtdeclarative/sanitize-visibleItems-list-after-model-insertions.patch

142 lines
6.8 KiB
Diff

From be1ef858f44e1523ba264520a0361981cf9b37c6 Mon Sep 17 00:00:00 2001
From: Gabriel de Dietrich <gabriel.dedietrich@theqtcompany.com>
Date: Wed, 25 Nov 2015 12:14:52 -0800
Subject: [PATCH] ListView: Sanitize visibleItems list after model insertions
In QQuickListViewPrivate::applyInsertionChange(), we update the
visibleItems list by first shifting the currently visible items
and then we add as many items as the model was added and at the
right position. We do this in such a way that we won't create
items that will not be visible right away (and may be deleted
right after by removeNonVisibleItems()). However, this may leave
gaps in the item index sequence, and QQuickListView doesn't always
recover gracefully from it.
The purpose of this patch is to make sure those gaps are cleared
right after inserting the new items. Since the insertions can happen
in two different places (either before or after the first visible
item) we need to update the visibleItems list accordingly. The way
we sanitize visibleItems is by removing those items that lie beyond
a possible index gap. If insertion happens before the first visible
item, we'll remove all those items before the insertion point. If
the insertion happens after the first visible item, we'll remove the
items after the insertion point.
Besides that, the logic for inserting before the visible position was
wrong. As items are inserted bottom-up in that case, the insertion
would start by just accounting for the item's size until the condition
pos > from && insertionIdx < visibleIndex
would become false only because 'pos' would be small enough. After
that, the next loop run would start adding items before the 'from'
position, which is wrong. Our fix is to move the condition outside
the loop if the insertion index will be before the visible index
and just account for the items' size in that case. Otherwise, the
insertion happens as usual until pos < from.
Change-Id: I35767cf6e9737bea1fe7677e580245fc7172710c
Task-number: QTBUG-48870
---
src/quick/items/qquicklistview.cpp | 59 ++++++++++++++++++----
1 files changed, 59 insertions(+), 4 deletions(-)
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index c7df855..9f53586 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -3097,12 +3097,13 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &ch
int i = 0;
qreal from = tempPos - displayMarginBeginning - buffer;
- for (i = count-1; i >= 0; --i) {
- if (pos > from && insertionIdx < visibleIndex) {
- // item won't be visible, just note the size for repositioning
- insertResult->sizeChangesBeforeVisiblePos += averageSize + spacing;
- pos -= averageSize + spacing;
- } else {
+ if (insertionIdx < visibleIndex) {
+ if (pos >= from) {
+ // items won't be visible, just note the size for repositioning
+ insertResult->sizeChangesBeforeVisiblePos += count * (averageSize + spacing);
+ }
+ } else {
+ for (i = count-1; i >= 0 && pos >= from; --i) {
// item is before first visible e.g. in cache buffer
FxViewItem *item = 0;
if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
@@ -3117,17 +3118,33 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &ch
insertResult->changedFirstItem = true;
if (!change.isMove()) {
addedItems->append(item);
- item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true);
+ if (transitioner)
+ item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true);
+ else
+ static_cast<FxListItemSG *>(item)->setPosition(pos, true);
}
insertResult->sizeChangesBeforeVisiblePos += item->size() + spacing;
pos -= item->size() + spacing;
+ index++;
+ }
+ }
+
+ int firstOkIdx = -1;
+ for (int i = 0; i <= insertionIdx && i < visibleItems.count() - 1; i++) {
+ if (visibleItems.at(i)->index + 1 != visibleItems.at(i + 1)->index) {
+ firstOkIdx = i + 1;
+ break;
}
- index++;
}
+ for (int i = 0; i < firstOkIdx; i++) {
+ FxViewItem *nvItem = visibleItems.takeFirst();
+ addedItems->removeOne(nvItem);
+ removeItem(nvItem);
+ }
+
} else {
- int i = 0;
qreal to = buffer + displayMarginEnd + tempPos + size();
- for (i = 0; i < count && pos <= to; ++i) {
+ for (int i = 0; i < count && pos <= to; ++i) {
FxViewItem *item = 0;
if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
item->index = modelIndex + i;
@@ -3147,12 +3164,32 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &ch
movingIntoView->append(MovedItem(item, change.moveKey(item->index)));
} else {
addedItems->append(item);
- item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true);
+ if (transitioner)
+ item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true);
+ else
+ static_cast<FxListItemSG *>(item)->setPosition(pos, true);
}
insertResult->sizeChangesAfterVisiblePos += item->size() + spacing;
pos += item->size() + spacing;
++index;
}
+
+ if (0 < index && index < visibleItems.count()) {
+ FxViewItem *prevItem = visibleItems.at(index - 1);
+ FxViewItem *item = visibleItems.at(index);
+ if (prevItem->index != item->index - 1) {
+ int i = index;
+ qreal prevPos = prevItem->position();
+ while (i < visibleItems.count()) {
+ FxListItemSG *nvItem = static_cast<FxListItemSG *>(visibleItems.takeLast());
+ insertResult->sizeChangesAfterVisiblePos -= nvItem->size() + spacing;
+ addedItems->removeOne(nvItem);
+ if (nvItem->transitionScheduledOrRunning())
+ nvItem->setPosition(prevPos + (nvItem->index - prevItem->index) * averageSize);
+ removeItem(nvItem);
+ }
+ }
+ }
}
updateVisibleIndex();
--
2.6.2.2.g1b5ffa3