Fix fetching data when reuseItems is true

QQmlDelegateModelPrivate::requestMoreIfNecessary() is called in various
situations, including at startup, which calls QAIM::fetchMore() on the
model if it supports that. But we need to do it in one more case:
when delegates are being reused from the cache, the model could provide
more rows even though we aren't instantiating new delegates.

Amends 1841a9e41d

Fixes: QTBUG-95107
Change-Id: I5b7ff48345ab78977cb03cfcf58ed96a57c831bd
Reviewed-by: Santhosh Kumar <santhosh.kumar.selvaraj@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
(cherry picked from commit 589d0ee473)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Aleix Pol 2023-07-20 10:54:27 +02:00 committed by Qt Cherry-pick Bot
parent 1757054ff7
commit 0dd96b57b6
3 changed files with 100 additions and 0 deletions

View File

@ -1203,6 +1203,9 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, QQ
addCacheItem(cacheItem, it);
reuseItem(cacheItem, index, flags);
cacheItem->referenceObject();
if (index == m_compositor.count(group) - 1)
requestMoreIfNecessary();
return cacheItem->object;
}

View File

@ -0,0 +1,21 @@
import QtQuick
import org.qtproject.Test
ListView {
id: listView
width: 300
height: 150
flickDeceleration: 10000
model: FetchMoreModel
delegate: Text {
height: 50
text: model.display
}
Text {
anchors.right: parent.right
text: "count " + listView.count
color: listView.moving ? "red" : "blue"
}
}

View File

@ -57,6 +57,8 @@ private slots:
void areaZeroviewDoesNotNeedlesslyPopulateWholeModel();
void delegateContextHandling();
void fetchMore_data();
void fetchMore();
private:
void flickWithTouch(QQuickWindow *window, const QPoint &from, const QPoint &to);
@ -1040,6 +1042,80 @@ void tst_QQuickListView2::delegateContextHandling()
}
class TestFetchMoreModel : public QAbstractListModel
{
Q_OBJECT
public:
QVariant data(const QModelIndex& index, int role) const override
{
if (role == Qt::DisplayRole)
return QString::number(index.row());
return {};
}
int columnCount(const QModelIndex&) const override { return 1; }
int rowCount(const QModelIndex& parent) const override
{
return parent.isValid() ? 0 : m_lines;
}
QModelIndex parent(const QModelIndex&) const override { return {}; }
bool canFetchMore(const QModelIndex &) const override { return true; }
void fetchMore(const QModelIndex & parent) override
{
if (Q_UNLIKELY(parent.isValid()))
return;
beginInsertRows(parent, m_lines, m_lines);
m_lines++;
endInsertRows();
}
int m_lines = 3;
};
void tst_QQuickListView2::fetchMore_data()
{
QTest::addColumn<bool>("reuseItems");
QTest::addColumn<int>("cacheBuffer");
QTest::newRow("no reuseItems, default buffer") << false << -1;
QTest::newRow("reuseItems, default buffer") << true << -1;
QTest::newRow("no reuseItems, no buffer") << false << 0;
QTest::newRow("reuseItems, no buffer") << true << 0;
QTest::newRow("no reuseItems, buffer 100 px") << false << 100;
QTest::newRow("reuseItems, buffer 100 px") << true << 100;
}
void tst_QQuickListView2::fetchMore() // QTBUG-95107
{
QFETCH(bool, reuseItems);
QFETCH(int, cacheBuffer);
TestFetchMoreModel model;
qmlRegisterSingletonInstance("org.qtproject.Test", 1, 0, "FetchMoreModel", &model);
QQuickView window;
QVERIFY(QQuickTest::showView(window, testFileUrl("fetchMore.qml")));
auto *listView = qobject_cast<QQuickListView*>(window.rootObject());
QVERIFY(listView);
listView->setReuseItems(reuseItems);
if (cacheBuffer >= 0)
listView->setCacheBuffer(cacheBuffer);
for (int i = 0; i < 3; ++i) {
const int rowCount = listView->count();
if (lcTests().isDebugEnabled()) QTest::qWait(1000);
listView->flick(0, -5000);
QTRY_VERIFY(!listView->isMoving());
qCDebug(lcTests) << "after flick: contentY" << listView->contentY()
<< "rows" << rowCount << "->" << listView->count();
QCOMPARE_GT(listView->count(), rowCount);
QCOMPARE_GE(model.m_lines, listView->count()); // fetchMore() was called
}
}
QTEST_MAIN(tst_QQuickListView2)
#include "tst_qquicklistview2.moc"