diff options
author | Richard Moe Gustavsen <richard.gustavsen@qt.io> | 2018-07-20 14:05:09 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2018-08-02 09:50:35 +0000 |
commit | 382812cd2917180a160917d24b11825a7eeb2cf1 (patch) | |
tree | dac6fbf8260e90e0347e23b5f863128d9689607c /tests/auto/quick/qquicktableview/tst_qquicktableview.cpp | |
parent | ca1f69757421845f563ebe90a5880509839efb31 (diff) |
QQuickTableView: implement support for reusing delegate items
This patch will make use of the recent changes in QQmlTableInstanceModel
to support reusing delegate items.
The API in TableView to enable this will mainly be a new property
"reuseItems". This property is true by default. By setting it to
false, reusing items will never happen.
When an item is reused, the signal "TableView.reused" is
emitted after the fact, in case the delegate item needs to
execute some extra code during the process. Likewise, a signal
"TableView.pooled" is emitted when the item is pooled.
From an implementation point of view, TableView only need to
do two things to enable reusing of items. First, whenever it releases
items, it provides a second argument to release(), informing
QQmlTableInstanceModel if the item can be reused. Second, it
needs to call drainReusePool() at appropriate times to ensure
that no item will be kept alive in the pool for too long.
Change-Id: I830e2eace776302ac58946733566208aa8954159
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
Diffstat (limited to 'tests/auto/quick/qquicktableview/tst_qquicktableview.cpp')
-rw-r--r-- | tests/auto/quick/qquicktableview/tst_qquicktableview.cpp | 218 |
1 files changed, 208 insertions, 10 deletions
diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp index 1cedde4f79..86839b61dc 100644 --- a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp +++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp @@ -50,6 +50,7 @@ using namespace QQuickVisualTestUtil; static const char* kTableViewPropName = "tableView"; static const char* kDelegateObjectName = "tableViewDelegate"; +static const char *kDelegatesCreatedCountProp = "delegatesCreatedCount"; Q_DECLARE_METATYPE(QMarginsF); @@ -112,6 +113,12 @@ private slots: void flickOvershoot(); void checkRowColumnCount(); void modelSignals(); + void checkIfDelegatesAreReused_data(); + void checkIfDelegatesAreReused(); + void checkContextProperties_data(); + void checkContextProperties(); + void checkContextPropertiesQQmlListProperyModel_data(); + void checkContextPropertiesQQmlListProperyModel(); }; tst_QQuickTableView::tst_QQuickTableView() @@ -757,11 +764,16 @@ void tst_QQuickTableView::flick_data() { QTest::addColumn<QSizeF>("spacing"); QTest::addColumn<QMarginsF>("margins"); - - QTest::newRow("s:0 m:0") << QSizeF(0, 0) << QMarginsF(0, 0, 0, 0); - QTest::newRow("s:5 m:0") << QSizeF(5, 5) << QMarginsF(0, 0, 0, 0); - QTest::newRow("s:0 m:20") << QSizeF(0, 0) << QMarginsF(20, 20, 20, 20); - QTest::newRow("s:5 m:20") << QSizeF(5, 5) << QMarginsF(20, 20, 20, 20); + QTest::addColumn<bool>("reuseItems"); + + QTest::newRow("s:0 m:0 reuse") << QSizeF(0, 0) << QMarginsF(0, 0, 0, 0) << true; + QTest::newRow("s:5 m:0 reuse") << QSizeF(5, 5) << QMarginsF(0, 0, 0, 0) << true; + QTest::newRow("s:0 m:20 reuse") << QSizeF(0, 0) << QMarginsF(20, 20, 20, 20) << true; + QTest::newRow("s:5 m:20 reuse") << QSizeF(5, 5) << QMarginsF(20, 20, 20, 20) << true; + QTest::newRow("s:0 m:0") << QSizeF(0, 0) << QMarginsF(0, 0, 0, 0) << false; + QTest::newRow("s:5 m:0") << QSizeF(5, 5) << QMarginsF(0, 0, 0, 0) << false; + QTest::newRow("s:0 m:20") << QSizeF(0, 0) << QMarginsF(20, 20, 20, 20) << false; + QTest::newRow("s:5 m:20") << QSizeF(5, 5) << QMarginsF(20, 20, 20, 20) << false; } void tst_QQuickTableView::flick() @@ -770,6 +782,7 @@ void tst_QQuickTableView::flick() // with different table configurations. QFETCH(QSizeF, spacing); QFETCH(QMarginsF, margins); + QFETCH(bool, reuseItems); LOAD_TABLEVIEW("plaintableview.qml"); const qreal delegateWidth = 100; @@ -788,6 +801,7 @@ void tst_QQuickTableView::flick() tableView->setRightMargin(margins.right()); tableView->setBottomMargin(margins.bottom()); tableView->setCacheBuffer(0); + tableView->setReuseItems(reuseItems); tableView->setWidth(margins.left() + (visualColumnCount * cellWidth) - spacing.width()); tableView->setHeight(margins.top() + (visualRowCount * cellHeight) - spacing.height()); @@ -821,11 +835,16 @@ void tst_QQuickTableView::flickOvershoot_data() { QTest::addColumn<QSizeF>("spacing"); QTest::addColumn<QMarginsF>("margins"); - - QTest::newRow("s:0 m:0") << QSizeF(0, 0) << QMarginsF(0, 0, 0, 0); - QTest::newRow("s:5 m:0") << QSizeF(5, 5) << QMarginsF(0, 0, 0, 0); - QTest::newRow("s:0 m:20") << QSizeF(0, 0) << QMarginsF(20, 20, 20, 20); - QTest::newRow("s:5 m:20") << QSizeF(5, 5) << QMarginsF(20, 20, 20, 20); + QTest::addColumn<bool>("reuseItems"); + + QTest::newRow("s:0 m:0 reuse") << QSizeF(0, 0) << QMarginsF(0, 0, 0, 0) << true; + QTest::newRow("s:5 m:0 reuse") << QSizeF(5, 5) << QMarginsF(0, 0, 0, 0) << true; + QTest::newRow("s:0 m:20 reuse") << QSizeF(0, 0) << QMarginsF(20, 20, 20, 20) << true; + QTest::newRow("s:5 m:20 reuse") << QSizeF(5, 5) << QMarginsF(20, 20, 20, 20) << true; + QTest::newRow("s:0 m:0") << QSizeF(0, 0) << QMarginsF(0, 0, 0, 0) << false; + QTest::newRow("s:5 m:0") << QSizeF(5, 5) << QMarginsF(0, 0, 0, 0) << false; + QTest::newRow("s:0 m:20") << QSizeF(0, 0) << QMarginsF(20, 20, 20, 20) << false; + QTest::newRow("s:5 m:20") << QSizeF(5, 5) << QMarginsF(20, 20, 20, 20) << false; } void tst_QQuickTableView::flickOvershoot() @@ -836,6 +855,7 @@ void tst_QQuickTableView::flickOvershoot() // when everything is flicked out of view. QFETCH(QSizeF, spacing); QFETCH(QMarginsF, margins); + QFETCH(bool, reuseItems); LOAD_TABLEVIEW("plaintableview.qml"); const int rowCount = 5; @@ -857,6 +877,7 @@ void tst_QQuickTableView::flickOvershoot() tableView->setRightMargin(margins.right()); tableView->setBottomMargin(margins.bottom()); tableView->setCacheBuffer(0); + tableView->setReuseItems(reuseItems); tableView->setWidth(tableWidth - margins.right() - cellWidth / 2); tableView->setHeight(tableHeight - margins.bottom() - cellHeight / 2); @@ -1092,6 +1113,183 @@ void tst_QQuickTableView::modelSignals() QCOMPARE(tableView->columns(), 1); } +void tst_QQuickTableView::checkIfDelegatesAreReused_data() +{ + QTest::addColumn<bool>("reuseItems"); + + QTest::newRow("reuse = true") << true; + QTest::newRow("reuse = false") << false; +} + +void tst_QQuickTableView::checkIfDelegatesAreReused() +{ + // Check that we end up reusing delegate items while flicking if + // TableView has reuseItems set to true, but otherwise not. + QFETCH(bool, reuseItems); + LOAD_TABLEVIEW("countingtableview.qml"); + + const qreal delegateWidth = 100; + const int pageFlickCount = 1; + + auto model = TestModelAsVariant(100, 100); + tableView->setModel(model); + tableView->setReuseItems(reuseItems); + + // Flick half an item to the left, to force one extra column to load before we start. + // This will make things less complicated below, when checking how many times the items + // have been reused (all items will then report the same number). + tableView->setContentX(delegateWidth / 2); + tableView->polish(); + + WAIT_UNTIL_POLISHED; + + const int visibleColumnCount = tableViewPrivate->loadedTable.width(); + const int visibleRowCount = tableViewPrivate->loadedTable.height(); + const int delegateCountAfterInit = view->rootObject()->property(kDelegatesCreatedCountProp).toInt(); + + for (int column = 1; column <= (visibleColumnCount * pageFlickCount); ++column) { + // Flick columns to the left (and add one pixel to ensure the left column is completely out) + tableView->setContentX((delegateWidth * column) + 1); + tableView->polish(); + + WAIT_UNTIL_POLISHED; + + // Check that the number of delegate items created so far is what we expect. + const int delegatesCreatedCount = view->rootObject()->property(kDelegatesCreatedCountProp).toInt(); + int expectedCount = delegateCountAfterInit + (reuseItems ? 0 : visibleRowCount * column); + QCOMPARE(delegatesCreatedCount, expectedCount); + } + + // Check that each delegate item has been reused as many times + // as we have flicked pages (if reuse is enabled). + for (auto fxItem : tableViewPrivate->loadedItems) { + int pooledCount = fxItem->item->property("pooledCount").toInt(); + int reusedCount = fxItem->item->property("reusedCount").toInt(); + if (reuseItems) { + QCOMPARE(pooledCount, pageFlickCount); + QCOMPARE(reusedCount, pageFlickCount); + } else { + QCOMPARE(pooledCount, 0); + QCOMPARE(reusedCount, 0); + } + } +} + +void tst_QQuickTableView::checkContextProperties_data() +{ + QTest::addColumn<QVariant>("model"); + QTest::addColumn<bool>("reuseItems"); + + auto stringList = QStringList(); + for (int i = 0; i < 100; ++i) + stringList.append(QString::number(i)); + + QTest::newRow("QAIM, reuse=false") << TestModelAsVariant(100, 100) << false; + QTest::newRow("QAIM, reuse=true") << TestModelAsVariant(100, 100) << true; + QTest::newRow("Number model, reuse=false") << QVariant::fromValue(100) << false; + QTest::newRow("Number model, reuse=true") << QVariant::fromValue(100) << true; + QTest::newRow("QStringList, reuse=false") << QVariant::fromValue(stringList) << false; + QTest::newRow("QStringList, reuse=true") << QVariant::fromValue(stringList) << true; +} + +void tst_QQuickTableView::checkContextProperties() +{ + // Check that the context properties of the delegate items + // are what we expect while flicking, with or without item recycling. + QFETCH(QVariant, model); + QFETCH(bool, reuseItems); + LOAD_TABLEVIEW("countingtableview.qml"); + + const qreal delegateWidth = 100; + const qreal delegateHeight = 50; + const int rowCount = 100; + const int pageFlickCount = 3; + + tableView->setModel(model); + tableView->setReuseItems(reuseItems); + + WAIT_UNTIL_POLISHED; + + const int visibleRowCount = qMin(tableView->rows(), qCeil(tableView->height() / delegateHeight)); + const int visibleColumnCount = qMin(tableView->columns(), qCeil(tableView->width() / delegateWidth)); + + for (int row = 1; row <= (visibleRowCount * pageFlickCount); ++row) { + // Flick rows up + tableView->setContentY((delegateHeight * row) + (delegateHeight / 2)); + tableView->polish(); + + WAIT_UNTIL_POLISHED; + + for (int col = 0; col < visibleColumnCount; ++col) { + const auto item = tableViewPrivate->loadedTableItem(QPoint(col, row))->item; + const auto context = qmlContext(item.data()); + const int contextIndex = context->contextProperty("index").toInt(); + const int contextRow = context->contextProperty("row").toInt(); + const int contextColumn = context->contextProperty("column").toInt(); + const QString contextModelData = context->contextProperty("modelData").toString(); + + QCOMPARE(contextIndex, row + (col * rowCount)); + QCOMPARE(contextRow, row); + QCOMPARE(contextColumn, col); + QCOMPARE(contextModelData, QStringLiteral("%1").arg(row)); + } + } +} + +void tst_QQuickTableView::checkContextPropertiesQQmlListProperyModel_data() +{ + QTest::addColumn<bool>("reuseItems"); + + QTest::newRow("reuse=false") << false; + QTest::newRow("reuse=true") << true; +} + +void tst_QQuickTableView::checkContextPropertiesQQmlListProperyModel() +{ + // Check that the context properties of the delegate items + // are what we expect while flicking, with or without item recycling. + // This test hard-codes the model to be a QQmlListPropertyModel from + // within the qml file. + QFETCH(bool, reuseItems); + LOAD_TABLEVIEW("qqmllistpropertymodel.qml"); + + const qreal delegateWidth = 100; + const qreal delegateHeight = 50; + const int rowCount = 100; + const int pageFlickCount = 3; + + tableView->setReuseItems(reuseItems); + tableView->polish(); + + WAIT_UNTIL_POLISHED; + + const int visibleRowCount = qMin(tableView->rows(), qCeil(tableView->height() / delegateHeight)); + const int visibleColumnCount = qMin(tableView->columns(), qCeil(tableView->width() / delegateWidth)); + + for (int row = 1; row <= (visibleRowCount * pageFlickCount); ++row) { + // Flick rows up + tableView->setContentY((delegateHeight * row) + (delegateHeight / 2)); + tableView->polish(); + + WAIT_UNTIL_POLISHED; + + for (int col = 0; col < visibleColumnCount; ++col) { + const auto item = tableViewPrivate->loadedTableItem(QPoint(col, row))->item; + const auto context = qmlContext(item.data()); + const int contextIndex = context->contextProperty("index").toInt(); + const int contextRow = context->contextProperty("row").toInt(); + const int contextColumn = context->contextProperty("column").toInt(); + const QObject *contextModelData = qvariant_cast<QObject *>(context->contextProperty("modelData")); + const QString modelDataProperty = contextModelData->property("someCustomProperty").toString(); + + QCOMPARE(contextIndex, row + (col * rowCount)); + QCOMPARE(contextRow, row); + QCOMPARE(contextColumn, col); + QCOMPARE(modelDataProperty, QStringLiteral("%1").arg(row)); + } + } +} + QTEST_MAIN(tst_QQuickTableView) #include "tst_qquicktableview.moc" |