aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick
diff options
context:
space:
mode:
authorRichard Moe Gustavsen <richard.gustavsen@qt.io>2018-08-11 16:55:09 +0200
committerRichard Moe Gustavsen <richard.gustavsen@qt.io>2018-08-14 14:58:23 +0000
commitbdeaef727230b6e820b202828e06503dac8096d6 (patch)
tree207b690898395a6924a8c9ff785848ae018430be /src/quick
parentec6b67a0e15ca271032689bfe94619c298a0a9bf (diff)
QQuickTableView: preload one extra row and column at start-up
When a TableView initially loads as many rows and columns it can fit inside the viewport, it will always be one less than the number it will show while flicking. The reason is that, as soon as you flick half a column out on the left, half a column will move in on the right. And this will increase the number of visible columns by 1 (but without reusing any items from the pool, since the first column is not out). Since this is always the case, it makes sense to preload one extra row and column at start-up, so that they're ready when the flicking starts. Note that this doesn't load more items in the background than what we need (like the cache buffer would). The viewport will fit _all_ the loaded items into the viewport once you start flicking. But the extra items loaded at start-up will instead be moved direcly to the pool for reuse, and the application will be informed about it (using the onPooled signal). Change-Id: Icea85c1d44f74ab54f1b96325489e8d6d1c0889e Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
Diffstat (limited to 'src/quick')
-rw-r--r--src/quick/items/qquicktableview.cpp113
-rw-r--r--src/quick/items/qquicktableview_p_p.h20
2 files changed, 101 insertions, 32 deletions
diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp
index fd8af19805..8dce0149f6 100644
--- a/src/quick/items/qquicktableview.cpp
+++ b/src/quick/items/qquicktableview.cpp
@@ -805,7 +805,7 @@ void QQuickTableViewPrivate::cancelLoadRequest()
loadRequest.markAsDone();
model->cancel(modelIndexAtCell(loadRequest.currentCell()));
- if (tableInvalid) {
+ if (rebuildState == RebuildState::NotStarted) {
// No reason to rollback already loaded edge items
// since we anyway are about to reload all items.
return;
@@ -857,13 +857,77 @@ void QQuickTableViewPrivate::processLoadRequest()
qCDebug(lcTableViewDelegateLifecycle()) << "request completed! Table:" << tableLayoutToString();
}
+void QQuickTableViewPrivate::processRebuildTable()
+{
+ moveToNextRebuildState();
+
+ if (rebuildState == RebuildState::LoadInitalTable) {
+ beginRebuildTable();
+ if (!moveToNextRebuildState())
+ return;
+ }
+
+ if (rebuildState == RebuildState::VerifyTable) {
+ if (loadedItems.isEmpty()) {
+ qCDebug(lcTableViewDelegateLifecycle()) << "no items loaded, meaning empty model or no delegate";
+ rebuildState = RebuildState::Done;
+ return;
+ }
+ if (!moveToNextRebuildState())
+ return;
+ }
+
+ if (rebuildState == RebuildState::LayoutTable) {
+ layoutAfterLoadingInitialTable();
+ if (!moveToNextRebuildState())
+ return;
+ }
+
+ if (rebuildState == RebuildState::LoadAndUnloadAfterLayout) {
+ loadAndUnloadVisibleEdges();
+ if (!moveToNextRebuildState())
+ return;
+ }
+
+ if (rebuildState == RebuildState::PreloadColumns) {
+ if (loadedTable.right() < tableSize.width() - 1)
+ loadEdge(Qt::RightEdge, QQmlIncubator::AsynchronousIfNested);
+ if (!moveToNextRebuildState())
+ return;
+ }
+
+ if (rebuildState == RebuildState::PreloadRows) {
+ if (loadedTable.bottom() < tableSize.height() - 1)
+ loadEdge(Qt::BottomEdge, QQmlIncubator::AsynchronousIfNested);
+ if (!moveToNextRebuildState())
+ return;
+ }
+
+ if (rebuildState == RebuildState::MovePreloadedItemsToPool) {
+ while (Qt::Edge edge = nextEdgeToUnload(viewportRect))
+ unloadEdge(edge);
+ if (!moveToNextRebuildState())
+ return;
+ }
+
+ Q_TABLEVIEW_ASSERT(rebuildState == RebuildState::Done, int(rebuildState));
+}
+
+bool QQuickTableViewPrivate::moveToNextRebuildState()
+{
+ if (loadRequest.isActive()) {
+ // Items are still loading async, which means
+ // that the current state is not yet done.
+ return false;
+ }
+ rebuildState = RebuildState(int(rebuildState) + 1);
+ qCDebug(lcTableViewDelegateLifecycle()) << int(rebuildState);
+ return true;
+}
+
void QQuickTableViewPrivate::beginRebuildTable()
{
Q_Q(QQuickTableView);
- qCDebug(lcTableViewDelegateLifecycle());
-
- tableInvalid = false;
- tableRebuilding = true;
releaseLoadedItems();
loadedTable = QRect();
@@ -879,21 +943,16 @@ void QQuickTableViewPrivate::beginRebuildTable()
loadAndUnloadVisibleEdges();
}
-void QQuickTableViewPrivate::endRebuildTable()
+void QQuickTableViewPrivate::layoutAfterLoadingInitialTable()
{
- tableRebuilding = false;
-
- if (rowHeightProvider.isNull() && columnWidthProvider.isNull()) {
- // Since we have no size providers, we need to calculate the size
- // of each row and column based on the size of the delegate items.
+ if (rowHeightProvider.isNull() || columnWidthProvider.isNull()) {
+ // Since we don't have both size providers, we need to calculate the
+ // size of each row and column based on the size of the delegate items.
// This couldn't be done while we were loading the initial rows and
// columns, since during the process, we didn't have all the items
- // available yet for the calculation. So we mark that it needs to be
- // done now, from within updatePolish().
- columnRowPositionsInvalid = true;
+ // available yet for the calculation. So we do it now.
+ relayoutTable();
}
-
- qCDebug(lcTableViewDelegateLifecycle()) << tableLayoutToString();
}
void QQuickTableViewPrivate::loadInitialTopLeftItem()
@@ -1020,7 +1079,7 @@ void QQuickTableViewPrivate::drainReusePoolAfterLoadRequest()
}
void QQuickTableViewPrivate::invalidateTable() {
- tableInvalid = true;
+ rebuildState = RebuildState::NotStarted;
if (loadRequest.isActive())
cancelLoadRequest();
q_func()->polish();
@@ -1056,19 +1115,13 @@ void QQuickTableViewPrivate::updatePolish()
if (!viewportRect.isValid())
return;
- if (tableInvalid) {
- beginRebuildTable();
- if (loadRequest.isActive())
- return;
+ if (rebuildState != RebuildState::Done) {
+ processRebuildTable();
+ return;
}
- if (tableRebuilding)
- endRebuildTable();
-
- if (loadedItems.isEmpty()) {
- qCDebug(lcTableViewDelegateLifecycle()) << "no items loaded, meaning empty model or no delegate";
+ if (loadedItems.isEmpty())
return;
- }
if (columnRowPositionsInvalid)
relayoutTable();
@@ -1499,7 +1552,8 @@ qreal QQuickTableView::explicitContentWidth() const
{
Q_D(const QQuickTableView);
- if (d->tableInvalid && d->explicitContentWidth.isNull) {
+ if (d->rebuildState == QQuickTableViewPrivate::RebuildState::NotStarted
+ && d->explicitContentWidth.isNull) {
// The table is pending to be rebuilt. Since we don't
// know the contentWidth before this is done, we do the
// rebuild now, instead of waiting for the polish event.
@@ -1523,7 +1577,8 @@ qreal QQuickTableView::explicitContentHeight() const
{
Q_D(const QQuickTableView);
- if (d->tableInvalid && d->explicitContentHeight.isNull) {
+ if (d->rebuildState == QQuickTableViewPrivate::RebuildState::NotStarted
+ && d->explicitContentHeight.isNull) {
// The table is pending to be rebuilt. Since we don't
// know the contentHeight before this is done, we do the
// rebuild now, instead of waiting for the polish event.
diff --git a/src/quick/items/qquicktableview_p_p.h b/src/quick/items/qquicktableview_p_p.h
index 936d8b8207..53fd936195 100644
--- a/src/quick/items/qquicktableview_p_p.h
+++ b/src/quick/items/qquicktableview_p_p.h
@@ -163,6 +163,18 @@ public:
}
};
+ enum class RebuildState {
+ NotStarted = 0,
+ LoadInitalTable,
+ VerifyTable,
+ LayoutTable,
+ LoadAndUnloadAfterLayout,
+ PreloadColumns,
+ PreloadRows,
+ MovePreloadedItemsToPool,
+ Done
+ };
+
public:
QQuickTableViewPrivate();
~QQuickTableViewPrivate() override;
@@ -196,6 +208,7 @@ public:
QSize tableSize;
+ RebuildState rebuildState = RebuildState::NotStarted;
TableEdgeLoadRequest loadRequest;
QPoint contentSizeBenchMarkPoint = QPoint(-1, -1);
@@ -205,8 +218,6 @@ public:
QQmlTableInstanceModel::ReusableFlag reusableFlag = QQmlTableInstanceModel::Reusable;
bool blockItemCreatedCallback = false;
- bool tableInvalid = false;
- bool tableRebuilding = false;
bool columnRowPositionsInvalid = false;
bool layoutWarningIssued = false;
bool polishing = false;
@@ -289,8 +300,11 @@ public:
void drainReusePoolAfterLoadRequest();
void cancelLoadRequest();
void processLoadRequest();
+
+ void processRebuildTable();
+ bool moveToNextRebuildState();
void beginRebuildTable();
- void endRebuildTable();
+ void layoutAfterLoadingInitialTable();
void invalidateTable();
void invalidateColumnRowPositions();