diff options
-rw-r--r-- | src/quick/items/qquicktableview.cpp | 37 | ||||
-rw-r--r-- | src/quick/items/qquicktableview_p_p.h | 8 | ||||
-rw-r--r-- | tests/auto/quick/qquicktableview/tst_qquicktableview.cpp | 54 |
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" |