aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Moe Gustavsen <richard.gustavsen@qt.io>2018-08-21 13:08:59 +0200
committerRichard Moe Gustavsen <richard.gustavsen@qt.io>2018-08-27 11:48:29 +0000
commit267eb009ee77dd52a3764a87594f4a7385f26b4f (patch)
tree2263e893ef60331e4afc026f02f246b3fe497383
parent4dc3582a1ee332bf8b577bb974f29e7692df85e9 (diff)
QQuickTableView: handle RebuildOption::ViewportOnly
When rebuildOptions have ViewportOnly set, we now let the top-left item be the same as before (and at the same position as before), and start rebuilding from there. This will greatly increase performance if e.g the table has been flicked far down to row 1000 when the rebuild needs to happen (e.g because the model got a new row). Change-Id: I30beb34a7beccedff8dc406f9a524119a2893eb3 Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
-rw-r--r--src/quick/items/qquicktableview.cpp37
-rw-r--r--src/quick/items/qquicktableview_p_p.h8
-rw-r--r--tests/auto/quick/qquicktableview/tst_qquicktableview.cpp54
3 files changed, 86 insertions, 13 deletions
diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp
index e1ec5aff75..a1a5520239 100644
--- a/src/quick/items/qquicktableview.cpp
+++ b/src/quick/items/qquicktableview.cpp
@@ -771,13 +771,11 @@ void QQuickTableViewPrivate::layoutHorizontalEdge(Qt::Edge tableEdge)
void QQuickTableViewPrivate::layoutTopLeftItem()
{
- // ###todo: support starting with other top-left items than 0,0
const QPoint cell = loadRequest.firstCell();
- Q_TABLEVIEW_ASSERT(cell == QPoint(0, 0), loadRequest.toString());
auto topLeftItem = loadedTableItem(cell);
auto item = topLeftItem->item;
- item->setPosition(QPoint(tableMargins.left(), tableMargins.top()));
+ item->setPosition(loadRequest.startPosition());
item->setSize(QSizeF(resolveColumnWidth(cell.x()), resolveRowHeight(cell.y())));
topLeftItem->setVisible(true);
qCDebug(lcTableViewDelegateLifecycle) << "geometry:" << topLeftItem->geometry();
@@ -938,18 +936,35 @@ void QQuickTableViewPrivate::beginRebuildTable()
if (loadRequest.isActive())
cancelLoadRequest();
- releaseLoadedItems(QQmlTableInstanceModel::NotReusable);
+ QPoint topLeft;
+ QPointF topLeftPos;
+ calculateTableSize();
+
+ if (rebuildOptions & RebuildOption::All) {
+ releaseLoadedItems(QQmlTableInstanceModel::NotReusable);
+ topLeft = QPoint(0, 0);
+ topLeftPos = QPointF(tableMargins.left(), tableMargins.top());
+ q->setContentX(0);
+ q->setContentY(0);
+ } else if (rebuildOptions & RebuildOption::ViewportOnly) {
+ // Rebuild the table without flicking the content view back to origin, and
+ // start building from the same top left item that is currently showing
+ // (unless it has been removed from the model).
+ releaseLoadedItems(reusableFlag);
+ topLeft = loadedTable.topLeft();
+ topLeftPos = loadedTableOuterRect.topLeft();
+ topLeft.setX(qMin(topLeft.x(), tableSize.width() - 1));
+ topLeft.setY(qMin(topLeft.y(), tableSize.height() - 1));
+ } else {
+ Q_TABLEVIEW_UNREACHABLE(rebuildOptions);
+ }
loadedTable = QRect();
loadedTableOuterRect = QRect();
loadedTableInnerRect = QRect();
contentSizeBenchMarkPoint = QPoint(-1, -1);
- q->setContentX(0);
- q->setContentY(0);
-
- calculateTableSize();
- loadInitialTopLeftItem();
+ loadInitialTopLeftItem(topLeft, topLeftPos);
loadAndUnloadVisibleEdges();
}
@@ -965,7 +980,7 @@ void QQuickTableViewPrivate::layoutAfterLoadingInitialTable()
}
}
-void QQuickTableViewPrivate::loadInitialTopLeftItem()
+void QQuickTableViewPrivate::loadInitialTopLeftItem(const QPoint &cell, const QPointF &pos)
{
Q_TABLEVIEW_ASSERT(loadedItems.isEmpty(), "");
@@ -980,7 +995,7 @@ void QQuickTableViewPrivate::loadInitialTopLeftItem()
// Load top-left item. After loaded, loadItemsInsideRect() will take
// care of filling out the rest of the table.
- loadRequest.begin(QPoint(0, 0), QQmlIncubator::AsynchronousIfNested);
+ loadRequest.begin(cell, pos, QQmlIncubator::AsynchronousIfNested);
processLoadRequest();
}
diff --git a/src/quick/items/qquicktableview_p_p.h b/src/quick/items/qquicktableview_p_p.h
index 81127adae4..1e8c10c285 100644
--- a/src/quick/items/qquicktableview_p_p.h
+++ b/src/quick/items/qquicktableview_p_p.h
@@ -86,7 +86,7 @@ public:
// done by QQuickTableView.
public:
- void begin(const QPoint &cell, QQmlIncubator::IncubationMode incubationMode)
+ void begin(const QPoint &cell, const QPointF &pos, QQmlIncubator::IncubationMode incubationMode)
{
Q_ASSERT(!active);
active = true;
@@ -95,6 +95,7 @@ public:
mode = incubationMode;
cellCount = 1;
currentIndex = 0;
+ startPos = pos;
qCDebug(lcTableViewDelegateLifecycle()) << "begin top-left:" << toString();
}
@@ -125,6 +126,8 @@ public:
inline Qt::Edge edge() { return tableEdge; }
inline QQmlIncubator::IncubationMode incubationMode() { return mode; }
+ inline QPointF startPosition() { return startPos; }
+
QString toString()
{
QString str;
@@ -154,6 +157,7 @@ public:
int cellCount = 0;
bool active = false;
QQmlIncubator::IncubationMode mode = QQmlIncubator::AsynchronousIfNested;
+ QPointF startPos;
QPoint cellAt(int index)
{
@@ -304,7 +308,7 @@ public:
void unloadItem(const QPoint &cell);
void unloadItems(const QLine &items);
- void loadInitialTopLeftItem();
+ void loadInitialTopLeftItem(const QPoint &cell, const QPointF &pos);
void loadEdge(Qt::Edge edge, QQmlIncubator::IncubationMode incubationMode);
void unloadEdge(Qt::Edge edge);
void loadAndUnloadVisibleEdges();
diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
index 99534ddb50..e5b06051a5 100644
--- a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
+++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
@@ -130,6 +130,7 @@ private slots:
void checkContextPropertiesQQmlListProperyModel();
void checkRowAndColumnChangedButNotIndex();
void checkChangingModelFromDelegate();
+ void checkRebuildViewportOnly();
};
tst_QQuickTableView::tst_QQuickTableView()
@@ -1666,6 +1667,59 @@ void tst_QQuickTableView::checkChangingModelFromDelegate()
QCOMPARE(tableViewPrivate->loadedTable.height(), 3);
}
+void tst_QQuickTableView::checkRebuildViewportOnly()
+{
+ // Check that we only rebuild from the current top-left cell
+ // when you add or remove rows and columns. There should be
+ // no need to do a rebuild from scratch in such cases.
+ LOAD_TABLEVIEW("countingtableview.qml");
+
+ const char *propName = "delegatesCreatedCount";
+ const qreal delegateWidth = 100;
+ const qreal delegateHeight = 50;
+
+ TestModel model(100, 100);
+ tableView->setModel(QVariant::fromValue(&model));
+
+ WAIT_UNTIL_POLISHED;
+
+ // Flick to row/column 50, 50
+ tableView->setContentX(delegateWidth * 50);
+ tableView->setContentY(delegateHeight * 50);
+
+ // Set reuse items to false, just to make it easier to
+ // check the number of items created during a rebuild.
+ tableView->setReuseItems(false);
+ const int itemCountBeforeRebuild = tableViewPrivate->loadedItems.count();
+
+ // Since all cells have the same size, we expect that we end up creating
+ // the same amount of items that were already showing before, even after
+ // adding or removing rows and columns.
+ view->rootObject()->setProperty(propName, 0);
+ model.insertRow(51);
+ WAIT_UNTIL_POLISHED;
+ int countAfterRebuild = view->rootObject()->property(propName).toInt();
+ QCOMPARE(countAfterRebuild, itemCountBeforeRebuild);
+
+ view->rootObject()->setProperty(propName, 0);
+ model.removeRow(51);
+ WAIT_UNTIL_POLISHED;
+ countAfterRebuild = view->rootObject()->property(propName).toInt();
+ QCOMPARE(countAfterRebuild, itemCountBeforeRebuild);
+
+ view->rootObject()->setProperty(propName, 0);
+ model.insertColumn(51);
+ WAIT_UNTIL_POLISHED;
+ countAfterRebuild = view->rootObject()->property(propName).toInt();
+ QCOMPARE(countAfterRebuild, itemCountBeforeRebuild);
+
+ view->rootObject()->setProperty(propName, 0);
+ model.removeColumn(51);
+ WAIT_UNTIL_POLISHED;
+ countAfterRebuild = view->rootObject()->property(propName).toInt();
+ QCOMPARE(countAfterRebuild, itemCountBeforeRebuild);
+}
+
QTEST_MAIN(tst_QQuickTableView)
#include "tst_qquicktableview.moc"