TableView: use fetchMore() when scrolling to the end of the table

QQmlTableInstanceModel implements canFetchMore and fetchMore functions,
but these are not called at any point in QQuickTableView. This change
checks if additional data can be fetched when atYEndChanged signal is
emitted.

Fixes: QTBUG-78273
Change-Id: I49b41b09d9a218826b34f32cd9fe4724a6097b52
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
This commit is contained in:
Kari Hormi 2019-11-06 15:53:40 +02:00
parent af090d8073
commit acb6ed0815
6 changed files with 61 additions and 0 deletions

View File

@ -103,6 +103,9 @@ public:
bool isValid() const override { return true; }
bool canFetchMore() const { return m_adaptorModel.canFetchMore(); }
void fetchMore() { m_adaptorModel.fetchMore(); }
QVariant model() const;
void setModel(const QVariant &model);

View File

@ -2314,6 +2314,7 @@ void QQuickTableViewPrivate::syncSyncView()
void QQuickTableViewPrivate::connectToModel()
{
Q_Q(QQuickTableView);
Q_TABLEVIEW_ASSERT(model, "");
QObjectPrivate::connect(model, &QQmlInstanceModel::createdItem, this, &QQuickTableViewPrivate::itemCreatedCallback);
@ -2323,6 +2324,8 @@ void QQuickTableViewPrivate::connectToModel()
const auto tm = tableModel.data();
QObjectPrivate::connect(tm, &QQmlTableInstanceModel::itemPooled, this, &QQuickTableViewPrivate::itemPooledCallback);
QObjectPrivate::connect(tm, &QQmlTableInstanceModel::itemReused, this, &QQuickTableViewPrivate::itemReusedCallback);
// Connect atYEndChanged to a function that fetches data if more is available
QObjectPrivate::connect(q, &QQuickTableView::atYEndChanged, this, &QQuickTableViewPrivate::fetchMoreData);
}
if (auto const aim = model->abstractItemModel()) {
@ -2346,6 +2349,7 @@ void QQuickTableViewPrivate::connectToModel()
void QQuickTableViewPrivate::disconnectFromModel()
{
Q_Q(QQuickTableView);
Q_TABLEVIEW_ASSERT(model, "");
QObjectPrivate::disconnect(model, &QQmlInstanceModel::createdItem, this, &QQuickTableViewPrivate::itemCreatedCallback);
@ -2355,6 +2359,7 @@ void QQuickTableViewPrivate::disconnectFromModel()
const auto tm = tableModel.data();
QObjectPrivate::disconnect(tm, &QQmlTableInstanceModel::itemPooled, this, &QQuickTableViewPrivate::itemPooledCallback);
QObjectPrivate::disconnect(tm, &QQmlTableInstanceModel::itemReused, this, &QQuickTableViewPrivate::itemReusedCallback);
QObjectPrivate::disconnect(q, &QQuickTableView::atYEndChanged, this, &QQuickTableViewPrivate::fetchMoreData);
}
if (auto const aim = model->abstractItemModel()) {
@ -2436,6 +2441,14 @@ void QQuickTableViewPrivate::layoutChangedCallback(const QList<QPersistentModelI
scheduleRebuildTable(RebuildOption::ViewportOnly);
}
void QQuickTableViewPrivate::fetchMoreData()
{
if (tableModel && tableModel->canFetchMore()) {
tableModel->fetchMore();
scheduleRebuildTable(RebuildOption::ViewportOnly);
}
}
void QQuickTableViewPrivate::modelResetCallback()
{
scheduleRebuildTable(RebuildOption::All);

View File

@ -426,6 +426,8 @@ public:
void setLocalViewportY(qreal contentY);
void syncViewportPosRecursive();
void fetchMoreData();
void _q_componentFinalized();
void registerCallbackWhenBindingsAreEvaluated();

View File

@ -13,3 +13,5 @@ TESTDATA = data/*
QT += core-private gui-private qml-private quick-private testlib qmlmodels-private
DISTFILES +=

View File

@ -46,6 +46,13 @@ public:
, m_columns(columns)
{}
TestModel(int rows, int columns, bool dataCanBeFetched, QObject *parent = nullptr)
: QAbstractTableModel(parent)
, m_rows(rows)
, m_columns(columns)
, m_dataCanBeFetched(dataCanBeFetched)
{}
int rowCount(const QModelIndex & = QModelIndex()) const override { return m_rows; }
void setRowCount(int count) { beginResetModel(); m_rows = count; emit rowCountChanged(); endResetModel(); }
@ -141,6 +148,12 @@ public:
return true;
}
bool canFetchMore(const QModelIndex &parent) const override
{
Q_UNUSED(parent)
return m_dataCanBeFetched;
}
void swapRows(int row1, int row2)
{
layoutAboutToBeChanged();
@ -152,6 +165,12 @@ public:
layoutChanged();
}
void fetchMore(const QModelIndex &parent) override
{
Q_UNUSED(parent)
addRow(m_rows - 1);
}
void clear() {
beginResetModel();
m_rows = 0;
@ -172,6 +191,7 @@ signals:
private:
int m_rows = 0;
int m_columns = 0;
bool m_dataCanBeFetched = false;
QHash<int, QString> modelData;
};

View File

@ -175,6 +175,7 @@ private slots:
void checkSyncView_differentSizedModels();
void checkSyncView_connect_late_data();
void checkSyncView_connect_late();
void checkThatFetchMoreIsCalledWhenScrolledToTheEndOfTable();
};
tst_QQuickTableView::tst_QQuickTableView()
@ -2676,7 +2677,27 @@ void tst_QQuickTableView::checkSyncView_connect_late()
QCOMPARE(tableViewVPrivate->loadedTableOuterRect.left(), 0);
QCOMPARE(tableViewHVPrivate->loadedTableOuterRect, tableViewPrivate->loadedTableOuterRect);
}
void tst_QQuickTableView::checkThatFetchMoreIsCalledWhenScrolledToTheEndOfTable()
{
LOAD_TABLEVIEW("plaintableview.qml");
auto model = TestModelAsVariant(5, 5, true);
tableView->setModel(model);
WAIT_UNTIL_POLISHED;
QCOMPARE(tableView->rows(), 5);
QCOMPARE(tableView->columns(), 5);
// Flick table out of view on top
tableView->setContentX(0);
tableView->setContentY(-tableView->height() - 10);
tableView->polish();
WAIT_UNTIL_POLISHED;
QCOMPARE(tableView->rows(), 6);
QCOMPARE(tableView->columns(), 5);
}
QTEST_MAIN(tst_QQuickTableView)