aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/quick/qquicktableview
diff options
context:
space:
mode:
authorRichard Moe Gustavsen <richard.gustavsen@qt.io>2018-09-27 11:37:46 +0200
committerShawn Rutledge <shawn.rutledge@qt.io>2018-09-29 06:26:17 +0000
commit863bc570ca9d8f08b9fbedee903faf63622fac3c (patch)
tree1a5bee89e20d1f2c04da832619762f7f2d476045 /tests/auto/quick/qquicktableview
parent731fa2fa82fbb150d9a977e189302f4fe74cda50 (diff)
QQuickTableView: improve performance when scrolling with scrollbars
When flicking, the current implementation would load and unload edges around the table until the new viewport was covered. The downside of that strategy is that you if you move the viewport a long distance in one go, you will need to load and unload edges hidden outside the viewport until it catches up with the new viewport. It gets even worse if you flick with a scrollbar, since then you can end up flicking thousands of rows in one go. And this will keep tableview busy loading and unloading edges for a "long" time. This patch will fix this issue by checking how much the viewport changes during a flick, and select a strategy based on that. So if the viewport moves more than a page (which is the size of the viewport), it will schedule a rebuild of the table from the viewports new location, rather than trying to load and unload edges until it catches up. Fixes: QTBUG-70704 Change-Id: I88909e118ec0759a7b7a305c19ccc6670af6263b Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
Diffstat (limited to 'tests/auto/quick/qquicktableview')
-rw-r--r--tests/auto/quick/qquicktableview/tst_qquicktableview.cpp97
1 files changed, 95 insertions, 2 deletions
diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
index 039fb91da0..60b938d127 100644
--- a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
+++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
@@ -117,6 +117,7 @@ private slots:
void checkRowHeightProviderNotCallable();
void checkForceLayoutFunction();
void checkContentWidthAndHeight();
+ void checkPageFlicking();
void checkExplicitContentWidthAndHeight();
void checkContentXY();
void noDelegate();
@@ -554,8 +555,15 @@ void tst_QQuickTableView::checkContentWidthAndHeight()
tableView->setContentX(flickTo);
tableView->setContentY(flickTo);
+ // Since we move the viewport more than a page, tableview
+ // will jump to the new position and do a rebuild.
+ QVERIFY(tableViewPrivate->polishScheduled);
+ QVERIFY(tableViewPrivate->rebuildScheduled);
+ WAIT_UNTIL_POLISHED;
+
const int largeSizeCellCountInView = qCeil(tableView->width() / cellSizeLarge);
const int columnCount = smallCellCount + largeSizeCellCountInView;
+ QCOMPARE(tableViewPrivate->loadedTable.left(), smallCellCount);
QCOMPARE(tableViewPrivate->loadedTable.right(), columnCount - 1);
const qreal firstHalfLength = smallCellCount * cellSizeSmall;
@@ -572,8 +580,20 @@ void tst_QQuickTableView::checkContentWidthAndHeight()
// check that we then end up with the exact content width/height.
const qreal secondHalfLength = largeCellCount * cellSizeLarge;
const qreal expectedFullSize = (firstHalfLength + secondHalfLength) + accumulatedSpacing;
- tableView->setContentX(expectedFullSize);
- tableView->setContentY(expectedFullSize);
+
+ // If we flick more than one page at a time, tableview will jump to the new
+ // position and rebuild the table without loading the edges in-between. Which
+ // row and column that ends up as new top-left is then based on a prediction, and
+ // therefore unreliable. To avoid this to happen (which will also affect the
+ // reported size of the table), we flick to the end position in smaller chuncks.
+ QVERIFY(!tableViewPrivate->polishScheduled);
+ QVERIFY(!tableViewPrivate->rebuildScheduled);
+ int pages = qCeil((expectedFullSize - tableView->contentX()) / tableView->width());
+ for (int i = 0; i < pages; i++) {
+ tableView->setContentX(tableView->contentX() + tableView->width() - 1);
+ tableView->setContentY(tableView->contentY() + tableView->height() - 1);
+ QVERIFY(!tableViewPrivate->rebuildScheduled);
+ }
QCOMPARE(tableView->contentWidth(), expectedFullSize);
QCOMPARE(tableView->contentHeight(), expectedFullSize);
@@ -587,6 +607,79 @@ void tst_QQuickTableView::checkContentWidthAndHeight()
QCOMPARE(tableView->contentHeight(), expectedFullSize);
}
+void tst_QQuickTableView::checkPageFlicking()
+{
+ // Check that we rebuild the table instead of refilling edges, if the viewport moves
+ // more than a page (the size of TableView).
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ const int cellWidth = 100;
+ const int cellHeight = 50;
+ auto model = TestModelAsVariant(10000, 10000);
+
+ tableView->setModel(model);
+
+ WAIT_UNTIL_POLISHED;
+
+ // Sanity check startup table
+ QRect tableRect = tableViewPrivate->loadedTable;
+ QCOMPARE(tableRect.x(), 0);
+ QCOMPARE(tableRect.y(), 0);
+ QCOMPARE(tableRect.width(), tableView->width() / cellWidth);
+ QCOMPARE(tableRect.height(), tableView->height() / cellHeight);
+
+ // Since all cells have the same size, the average row/column
+ // size found by TableView should be exactly equal to this.
+ QCOMPARE(tableViewPrivate->averageEdgeSize.width(), cellWidth);
+ QCOMPARE(tableViewPrivate->averageEdgeSize.height(), cellHeight);
+
+ QVERIFY(!tableViewPrivate->rebuildScheduled);
+ QCOMPARE(tableViewPrivate->scheduledRebuildOptions, QQuickTableViewPrivate::RebuildOption::None);
+
+ // Flick 5000 columns to the right, and check that this triggers a
+ // rebuild, and that we end up at the expected top-left.
+ const int flickToColumn = 5000;
+ const qreal columnSpacing = tableView->columnSpacing();
+ const qreal flickToColumnInPixels = ((cellWidth + columnSpacing) * flickToColumn) - columnSpacing;
+ tableView->setContentX(flickToColumnInPixels);
+
+ QVERIFY(tableViewPrivate->rebuildScheduled);
+ QVERIFY(tableViewPrivate->scheduledRebuildOptions & QQuickTableViewPrivate::RebuildOption::ViewportOnly);
+ QVERIFY(tableViewPrivate->scheduledRebuildOptions & QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftColumn);
+ QVERIFY(!(tableViewPrivate->scheduledRebuildOptions & QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftRow));
+
+ WAIT_UNTIL_POLISHED;
+
+ tableRect = tableViewPrivate->loadedTable;
+ QCOMPARE(tableRect.x(), flickToColumn);
+ QCOMPARE(tableRect.y(), 0);
+ QCOMPARE(tableRect.width(), tableView->width() / cellWidth);
+ QCOMPARE(tableRect.height(), tableView->height() / cellHeight);
+
+ // Flick 5000 rows down as well. Since flicking down should only calculate a new row (but
+ // keep the current column), we deliberatly change the average width to check that it's
+ // actually ignored by the rebuild, and that the column stays the same.
+ tableViewPrivate->averageEdgeSize.rwidth() /= 2;
+
+ const int flickToRow = 5000;
+ const qreal rowSpacing = tableView->rowSpacing();
+ const qreal flickToRowInPixels = ((cellHeight + rowSpacing) * flickToRow) - rowSpacing;
+ tableView->setContentY(flickToRowInPixels);
+
+ QVERIFY(tableViewPrivate->rebuildScheduled);
+ QVERIFY(tableViewPrivate->scheduledRebuildOptions & QQuickTableViewPrivate::RebuildOption::ViewportOnly);
+ QVERIFY(!(tableViewPrivate->scheduledRebuildOptions & QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftColumn));
+ QVERIFY(tableViewPrivate->scheduledRebuildOptions & QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftRow);
+
+ WAIT_UNTIL_POLISHED;
+
+ tableRect = tableViewPrivate->loadedTable;
+ QCOMPARE(tableRect.x(), flickToRow);
+ QCOMPARE(tableRect.y(), flickToColumn);
+ QCOMPARE(tableRect.width(), tableView->width() / cellWidth);
+ QCOMPARE(tableRect.height(), tableView->height() / cellHeight);
+}
+
void tst_QQuickTableView::checkExplicitContentWidthAndHeight()
{
// Check that you can set a custom contentWidth/Height, and that