aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/quick/items/qquicktableview.cpp321
-rw-r--r--src/quick/items/qquicktableview_p.h4
-rw-r--r--src/quick/items/qquicktableview_p_p.h34
-rw-r--r--tests/auto/quick/qquicktableview/tst_qquicktableview.cpp186
4 files changed, 524 insertions, 21 deletions
diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp
index cb600c7b47..28a5dee681 100644
--- a/src/quick/items/qquicktableview.cpp
+++ b/src/quick/items/qquicktableview.cpp
@@ -350,6 +350,81 @@
*/
/*!
+ \qmlmethod QtQuick::TableView::positionViewAtCell(point cell, Qt.Alignment alignment, point offset)
+
+ Positions \l contentX and \l contentY such that \a cell is at the position specified by
+ \a alignment. \a alignment can be an or-ed combination of the following:
+
+ \list
+ \li Qt.AlignLeft - position the cell at the left of the view.
+ \li Qt.AlignHCenter - position the cell at the horizontal center of the view.
+ \li Qt.AlignRight - position the cell at the right of the view.
+ \li Qt.AlignTop - position the cell at the top of the view.
+ \li Qt.AlignVCenter - position the cell at the vertical center of the view.
+ \li Qt.AlignBottom - position the cell at the bottom of the view.
+ \li Qt.AlignCenter - the same as (Qt.AlignHCenter | Qt.AlignVCenter)
+ \endlist
+
+ Optionally, you can specify \a offset to move \l contentX and \l contentY an extra number of
+ pixels beyond the target alignment. E.g if you want to position the view so
+ that cell [10, 10] ends up at the top-left corner with a 5px margin, you could do:
+
+ \code
+ positionViewAtCell(Qt.point(10, 10), Qt.AlignLeft | Qt.AlignTop, Qt.point(-5, -5))
+ \endcode
+*/
+
+/*!
+ \qmlmethod QtQuick::TableView::positionViewAtCell(int column, int row, Qt.Alignment alignment, point offset)
+
+ Convenience for calling \code positionViewAtCell(Qt.point(column, row), alignment, offset)
+*/
+
+/*!
+ \qmlmethod QtQuick::TableView::positionViewAtRow(int row, Qt.Alignment alignment, real offset)
+
+ Positions \l contentY such that \a row is at the position specified by
+ \a alignment. \a alignment can be one of the following:
+
+ \list
+ \li Qt.AlignTop - position the row at the top of the view.
+ \li Qt.AlignVCenter - position the cell at the vertical center of the view.
+ \li Qt.AlignCenter - the same as Qt.AlignVCenter.
+ \li Qt.AlignBottom - position the cell at the bottom of the view.
+ \endlist
+
+ Optionally, you can specify \a offset to move \l contentY an extra number of
+ pixels beyond the target alignment. E.g if you want to position the view so
+ that row 10 ends up at the bottom with a 5px margin, you could do:
+
+ \code
+ positionViewAtRow(10, Qt.AlignBottom, 5)
+ \endcode
+*/
+
+/*!
+ \qmlmethod QtQuick::TableView::positionViewAtColumn(int column, Qt.Alignment alignment, real offset)
+
+ Positions \l contentX such that \a column is at the position specified by
+ \a alignment. \a alignment can be one of the following:
+
+ \list
+ \li Qt.AlignLeft - position the column at the left of the view.
+ \li Qt.AlignHCenter - position the column at the horizontal center of the view.
+ \li Qt.AlignCenter - the same as Qt.AlignVCenter.
+ \li Qt.AlignRight - position the column at the right of the view.
+ \endlist
+
+ Optionally, you can specify \a offset to move \l contentX an extra number of
+ pixels to the side of the target alignment. E.g if you want to position the view so
+ that column 10 ends up at the left side with a 5px margin, you could do:
+
+ \code
+ positionViewAtColumn(10, Qt.AlignLeft, -5)
+ \endcode
+*/
+
+/*!
\qmlattachedproperty TableView QtQuick::TableView::view
This attached property holds the view that manages the delegate instance.
@@ -906,6 +981,18 @@ void QQuickTableViewPrivate::syncLoadedTableRectFromLoadedTable()
loadedTableInnerRect = QRectF(topLeftRect.bottomRight(), bottomRightRect.topLeft());
}
+void QQuickTableViewPrivate::shiftLoadedTableRect(const QPointF newPosition)
+{
+ // Move the tracked table rects to the new position. For this to
+ // take visual effect (move the delegate items to be inside the table
+ // rect), it needs to be followed by a relayoutTableItems().
+ // Also note that the position of the viewport needs to be adjusted
+ // separately for it to overlap the loaded table.
+ const QPointF innerDiff = loadedTableOuterRect.topLeft() - loadedTableInnerRect.topLeft();
+ loadedTableOuterRect.moveTopLeft(newPosition);
+ loadedTableInnerRect.moveTopLeft(newPosition + innerDiff);
+}
+
QQuickTableViewPrivate::RebuildOptions QQuickTableViewPrivate::checkForVisibilityChanges()
{
// Go through all columns from first to last, find the columns that used
@@ -1291,6 +1378,20 @@ qreal QQuickTableViewPrivate::getColumnLayoutWidth(int column)
return columnWidth;
}
+qreal QQuickTableViewPrivate::getEffectiveRowHeight(int row) const
+{
+ // Return row height after layout
+ Q_TABLEVIEW_ASSERT(loadedRows.contains(row), row);
+ return loadedTableItem(QPoint(leftColumn(), row))->geometry().height();
+}
+
+qreal QQuickTableViewPrivate::getEffectiveColumnWidth(int column) const
+{
+ // Return column width after layout
+ Q_TABLEVIEW_ASSERT(loadedColumns.contains(column), column);
+ return loadedTableItem(QPoint(column, topRow()))->geometry().width();
+}
+
qreal QQuickTableViewPrivate::getRowLayoutHeight(int row)
{
// Return the row height specified by the application, or go
@@ -1611,7 +1712,9 @@ void QQuickTableViewPrivate::processLoadRequest()
loadRequest.markAsDone();
- qCDebug(lcTableViewDelegateLifecycle()) << "request completed! Table:" << tableLayoutToString();
+ qCDebug(lcTableViewDelegateLifecycle()) << "current table:" << tableLayoutToString();
+ qCDebug(lcTableViewDelegateLifecycle()) << "Load request completed!";
+ qCDebug(lcTableViewDelegateLifecycle()) << "****************************************";
}
void QQuickTableViewPrivate::processRebuildTable()
@@ -1635,7 +1738,7 @@ void QQuickTableViewPrivate::processRebuildTable()
moveToNextRebuildState();
if (rebuildState == RebuildState::LoadInitalTable) {
- beginRebuildTable();
+ loadInitialTable();
if (!moveToNextRebuildState())
return;
}
@@ -1688,7 +1791,10 @@ void QQuickTableViewPrivate::processRebuildTable()
}
Q_TABLEVIEW_ASSERT(rebuildState == RebuildState::Done, int(rebuildState));
- qCDebug(lcTableViewDelegateLifecycle()) << "rebuild complete:" << q;
+ qCDebug(lcTableViewDelegateLifecycle()) << "current table:" << tableLayoutToString();
+ qCDebug(lcTableViewDelegateLifecycle()) << "rebuild completed!";
+ qCDebug(lcTableViewDelegateLifecycle()) << "################################################";
+ qCDebug(lcTableViewDelegateLifecycle());
}
bool QQuickTableViewPrivate::moveToNextRebuildState()
@@ -1781,10 +1887,16 @@ void QQuickTableViewPrivate::calculateTopLeft(QPoint &topLeftCell, QPointF &topL
const int newColumn = int(viewportRect.x() / (averageEdgeSize.width() + cellSpacing.width()));
topLeftCell.rx() = qBound(0, newColumn, tableSize.width() - 1);
topLeftPos.rx() = topLeftCell.x() * (averageEdgeSize.width() + cellSpacing.width());
+ } else if (rebuildOptions & RebuildOption::PositionViewAtColumn) {
+ topLeftCell.rx() = qBound(0, positionViewAtColumn, tableSize.width() - 1);
+ topLeftPos.rx() = qFloor(topLeftCell.x()) * (averageEdgeSize.width() + cellSpacing.width());
} else {
// Keep the current top left, unless it's outside model
topLeftCell.rx() = qBound(0, leftColumn(), tableSize.width() - 1);
- topLeftPos.rx() = loadedTableOuterRect.topLeft().x();
+ // We begin by loading the columns where the viewport is at
+ // now. But will move the whole table and the viewport
+ // later, when we do a layoutAfterLoadingInitialTable().
+ topLeftPos.rx() = loadedTableOuterRect.x();
}
}
@@ -1801,21 +1913,25 @@ void QQuickTableViewPrivate::calculateTopLeft(QPoint &topLeftCell, QPointF &topL
const int newRow = int(viewportRect.y() / (averageEdgeSize.height() + cellSpacing.height()));
topLeftCell.ry() = qBound(0, newRow, tableSize.height() - 1);
topLeftPos.ry() = topLeftCell.y() * (averageEdgeSize.height() + cellSpacing.height());
+ } else if (rebuildOptions & RebuildOption::PositionViewAtRow) {
+ topLeftCell.ry() = qBound(0, positionViewAtRow, tableSize.height() - 1);
+ topLeftPos.ry() = qFloor(topLeftCell.y()) * (averageEdgeSize.height() + cellSpacing.height());
} else {
- // Keep the current top left, unless it's outside model
topLeftCell.ry() = qBound(0, topRow(), tableSize.height() - 1);
- topLeftPos.ry() = loadedTableOuterRect.topLeft().y();
+ topLeftPos.ry() = loadedTableOuterRect.y();
}
}
}
-void QQuickTableViewPrivate::beginRebuildTable()
+void QQuickTableViewPrivate::loadInitialTable()
{
updateTableSize();
QPoint topLeft;
QPointF topLeftPos;
calculateTopLeft(topLeft, topLeftPos);
+ qCDebug(lcTableViewDelegateLifecycle()) << "initial viewport rect:" << viewportRect;
+ qCDebug(lcTableViewDelegateLifecycle()) << "initial top left cell:" << topLeft << ", pos:" << topLeftPos;
if (!loadedItems.isEmpty()) {
if (rebuildOptions & RebuildOption::All)
@@ -1838,15 +1954,17 @@ void QQuickTableViewPrivate::beginRebuildTable()
loadedTableInnerRect = QRect();
clearEdgeSizeCache();
- if (syncHorizontally) {
+ if (syncHorizontally)
setLocalViewportX(syncView->contentX());
- viewportRect.moveLeft(syncView->d_func()->viewportRect.left());
- }
- if (syncVertically) {
+ if (syncVertically)
setLocalViewportY(syncView->contentY());
- viewportRect.moveTop(syncView->d_func()->viewportRect.top());
- }
+
+ if (!syncHorizontally && rebuildOptions & RebuildOption::PositionViewAtColumn)
+ setLocalViewportX(topLeftPos.x());
+
+ if (!syncVertically && rebuildOptions & RebuildOption::PositionViewAtRow)
+ setLocalViewportY(topLeftPos.y());
if (!model) {
qCDebug(lcTableViewDelegateLifecycle()) << "no model found, leaving table empty";
@@ -1904,6 +2022,74 @@ void QQuickTableViewPrivate::layoutAfterLoadingInitialTable()
}
updateExtents();
+ adjustViewportXAccordingToAlignment();
+ adjustViewportYAccordingToAlignment();
+}
+
+void QQuickTableViewPrivate::adjustViewportXAccordingToAlignment()
+{
+ // Check if we are supposed to position the viewport at a certain column
+ if (!rebuildOptions.testFlag(RebuildOption::PositionViewAtColumn))
+ return;
+ // The requested column might have been hidden or is outside model bounds
+ if (positionViewAtColumn != leftColumn())
+ return;
+
+ const float columnWidth = getEffectiveColumnWidth(positionViewAtColumn);
+
+ switch (positionViewAtColumnAlignment) {
+ case Qt::AlignLeft:
+ setLocalViewportX(loadedTableOuterRect.left() + positionViewAtColumnOffset);
+ break;
+ case Qt::AlignHCenter:
+ setLocalViewportX(loadedTableOuterRect.left()
+ - (viewportRect.width() / 2)
+ + (columnWidth / 2)
+ + positionViewAtColumnOffset);
+ break;
+ case Qt::AlignRight:
+ setLocalViewportX(loadedTableOuterRect.left()
+ - viewportRect.width()
+ + columnWidth
+ + positionViewAtColumnOffset);
+ break;
+ default:
+ Q_TABLEVIEW_UNREACHABLE("options are checked in setter");
+ break;
+ }
+}
+
+void QQuickTableViewPrivate::adjustViewportYAccordingToAlignment()
+{
+ // Check if we are supposed to position the viewport at a certain row
+ if (!rebuildOptions.testFlag(RebuildOption::PositionViewAtRow))
+ return;
+ // The requested row might have been hidden or is outside model bounds
+ if (positionViewAtRow != topRow())
+ return;
+
+ const float rowHeight = getEffectiveRowHeight(positionViewAtRow);
+
+ switch (positionViewAtRowAlignment) {
+ case Qt::AlignTop:
+ setLocalViewportY(loadedTableOuterRect.top() + positionViewAtRowOffset);
+ break;
+ case Qt::AlignVCenter:
+ setLocalViewportY(loadedTableOuterRect.top()
+ - (viewportRect.height() / 2)
+ + (rowHeight / 2)
+ + positionViewAtRowOffset);
+ break;
+ case Qt::AlignBottom:
+ setLocalViewportY(loadedTableOuterRect.top()
+ - viewportRect.height()
+ + rowHeight
+ + positionViewAtRowOffset);
+ break;
+ default:
+ Q_TABLEVIEW_UNREACHABLE("options are checked in setter");
+ break;
+ }
}
void QQuickTableViewPrivate::unloadEdge(Qt::Edge edge)
@@ -2077,7 +2263,12 @@ bool QQuickTableViewPrivate::updateTableRecursive()
const auto children = syncChildren;
for (auto syncChild : children) {
auto syncChild_d = syncChild->d_func();
- syncChild_d->scheduledRebuildOptions |= rebuildOptions;
+ const int mask =
+ RebuildOption::PositionViewAtRow |
+ RebuildOption::PositionViewAtColumn |
+ RebuildOption::CalculateNewTopLeftRow |
+ RebuildOption::CalculateNewTopLeftColumn;
+ syncChild_d->scheduledRebuildOptions |= rebuildOptions & ~mask;
const bool descendantUpdateComplete = syncChild_d->updateTableRecursive();
if (!descendantUpdateComplete)
@@ -2230,6 +2421,7 @@ void QQuickTableViewPrivate::syncWithPendingChanges()
syncModel();
syncDelegate();
syncSyncView();
+ syncPositionView();
syncRebuildOptions();
}
@@ -2253,6 +2445,12 @@ void QQuickTableViewPrivate::syncRebuildOptions()
} else if (rebuildOptions.testFlag(RebuildOption::ViewportOnly)) {
rebuildOptions.setFlag(RebuildOption::LayoutOnly, false);
}
+
+ if (rebuildOptions.testFlag(RebuildOption::PositionViewAtRow))
+ rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftRow, false);
+
+ if (rebuildOptions.testFlag(RebuildOption::PositionViewAtColumn))
+ rebuildOptions.setFlag(RebuildOption::CalculateNewTopLeftColumn, false);
}
void QQuickTableViewPrivate::syncDelegate()
@@ -2369,6 +2567,16 @@ void QQuickTableViewPrivate::syncSyncView()
}
}
+void QQuickTableViewPrivate::syncPositionView()
+{
+ // Only positionViewAtRow/positionViewAtColumn are critical
+ // to sync before a rebuild to avoid them being overwritten
+ // by the setters while building. The other position properties
+ // can change without it causing trouble.
+ positionViewAtRow = assignedPositionViewAtRow;
+ positionViewAtColumn = assignedPositionViewAtColumn;
+}
+
void QQuickTableViewPrivate::connectToModel()
{
Q_Q(QQuickTableView);
@@ -2538,6 +2746,10 @@ void QQuickTableViewPrivate::setLocalViewportX(qreal contentX)
return;
q->setContentX(contentX);
+
+ // Keep our own viewportRect in sync
+ viewportRect.moveLeft(contentX);
+ qCDebug(lcTableViewDelegateLifecycle) << "viewportRect adjusted to:" << viewportRect;
}
void QQuickTableViewPrivate::setLocalViewportY(qreal contentY)
@@ -2552,6 +2764,10 @@ void QQuickTableViewPrivate::setLocalViewportY(qreal contentY)
return;
q->setContentY(contentY);
+
+ // Keep our own viewportRect in sync
+ viewportRect.moveTop(contentY);
+ qCDebug(lcTableViewDelegateLifecycle) << "viewportRect adjusted to:" << viewportRect;
}
void QQuickTableViewPrivate::syncViewportPosRecursive()
@@ -2829,6 +3045,83 @@ void QQuickTableView::setSyncDirection(Qt::Orientations direction)
emit syncDirectionChanged();
}
+void QQuickTableView::positionViewAtCell(const QPoint &cell, Qt::Alignment alignment, const QPointF &offset)
+{
+ positionViewAtRow(cell.y(), alignment & Qt::AlignVertical_Mask, offset.y());
+ positionViewAtColumn(cell.x(), alignment & Qt::AlignHorizontal_Mask, offset.x());
+}
+
+void QQuickTableView::positionViewAtCell(int column, int row, Qt::Alignment alignment, const QPointF &offset)
+{
+ positionViewAtCell(QPoint(column, row), alignment, offset);
+}
+
+void QQuickTableView::positionViewAtRow(int row, Qt::Alignment alignment, qreal offset)
+{
+ Q_D(QQuickTableView);
+
+ if (d->syncVertically) {
+ d->syncView->positionViewAtRow(row, alignment, offset);
+ return;
+ }
+
+ // Clean up flags, in case it has
+ // Qt::AlignCenter set (which we allow)
+ Qt::Alignment adjustedAlignment = alignment;
+ adjustedAlignment.setFlag(Qt::AlignHCenter, false);
+ if (!int(adjustedAlignment))
+ adjustedAlignment.setFlag(Qt::AlignTop);
+
+ switch (adjustedAlignment) {
+ case Qt::AlignTop:
+ case Qt::AlignVCenter:
+ case Qt::AlignBottom:
+ break;
+ default:
+ qmlWarning(this) << "Unsupported alignment. Use AlignTop, AlignVCenter, or AlignBottom";
+ return;
+ }
+
+ d->assignedPositionViewAtRow = row;
+ d->positionViewAtRowAlignment = adjustedAlignment;
+ d->positionViewAtRowOffset = offset;
+ d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly |
+ QQuickTableViewPrivate::RebuildOption::PositionViewAtRow);
+}
+
+void QQuickTableView::positionViewAtColumn(int column, Qt::Alignment alignment, qreal offset)
+{
+ Q_D(QQuickTableView);
+
+ if (d->syncHorizontally) {
+ d->syncView->positionViewAtColumn(column, alignment, offset);
+ return;
+ }
+
+ // Clean up flags, in case it has
+ // Qt::AlignCenter set (which we allow)
+ Qt::Alignment adjustedAlignment = alignment;
+ adjustedAlignment.setFlag(Qt::AlignVCenter, false);
+ if (!int(adjustedAlignment))
+ adjustedAlignment.setFlag(Qt::AlignLeft);
+
+ switch (adjustedAlignment) {
+ case Qt::AlignLeft:
+ case Qt::AlignHCenter:
+ case Qt::AlignRight:
+ break;
+ default:
+ qmlWarning(this) << "Unsupported alignment. Use AlignLeft, AlignHCenter, or AlignRight";
+ return;
+ }
+
+ d->assignedPositionViewAtColumn = column;
+ d->positionViewAtColumnAlignment = adjustedAlignment;
+ d->positionViewAtColumnOffset = offset;
+ d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly |
+ QQuickTableViewPrivate::RebuildOption::PositionViewAtColumn);
+}
+
void QQuickTableView::forceLayout()
{
d_func()->forceLayout();
diff --git a/src/quick/items/qquicktableview_p.h b/src/quick/items/qquicktableview_p.h
index c71e74bfdc..387cc5d51d 100644
--- a/src/quick/items/qquicktableview_p.h
+++ b/src/quick/items/qquicktableview_p.h
@@ -123,6 +123,10 @@ public:
void setSyncDirection(Qt::Orientations direction);
Q_INVOKABLE void forceLayout();
+ Q_INVOKABLE void positionViewAtCell(const QPoint &cell, Qt::Alignment alignment, const QPointF &offset = QPointF());
+ Q_INVOKABLE void positionViewAtCell(int column, int row, Qt::Alignment alignment, const QPointF &offset = QPointF());
+ Q_INVOKABLE void positionViewAtRow(int row, Qt::Alignment alignment, qreal offset = 0);
+ Q_INVOKABLE void positionViewAtColumn(int column, Qt::Alignment alignment, qreal offset = 0);
static QQuickTableViewAttached *qmlAttachedProperties(QObject *);
diff --git a/src/quick/items/qquicktableview_p_p.h b/src/quick/items/qquicktableview_p_p.h
index 93a8d839e0..ab53a07dd0 100644
--- a/src/quick/items/qquicktableview_p_p.h
+++ b/src/quick/items/qquicktableview_p_p.h
@@ -208,11 +208,13 @@ public:
enum class RebuildOption {
None = 0,
- LayoutOnly = 0x1,
- ViewportOnly = 0x2,
- CalculateNewTopLeftRow = 0x4,
- CalculateNewTopLeftColumn = 0x8,
- All = 0x10,
+ All = 0x1,
+ LayoutOnly = 0x2,
+ ViewportOnly = 0x4,
+ CalculateNewTopLeftRow = 0x8,
+ CalculateNewTopLeftColumn = 0x10,
+ PositionViewAtRow = 0x20,
+ PositionViewAtColumn = 0x40,
};
Q_DECLARE_FLAGS(RebuildOptions, RebuildOption)
@@ -310,6 +312,15 @@ public:
QList<QPointer<QQuickTableView> > syncChildren;
Qt::Orientations assignedSyncDirection = Qt::Horizontal | Qt::Vertical;
+ int assignedPositionViewAtRow = 0;
+ int assignedPositionViewAtColumn = 0;
+ int positionViewAtRow = 0;
+ int positionViewAtColumn = 0;
+ qreal positionViewAtRowOffset = 0;
+ qreal positionViewAtColumnOffset = 0;
+ Qt::Alignment positionViewAtRowAlignment = Qt::AlignTop;
+ Qt::Alignment positionViewAtColumnAlignment = Qt::AlignLeft;
+
const static QPoint kLeft;
const static QPoint kRight;
const static QPoint kUp;
@@ -337,6 +348,8 @@ public:
qreal getRowLayoutHeight(int row);
qreal getColumnWidth(int column);
qreal getRowHeight(int row);
+ qreal getEffectiveRowHeight(int row) const;
+ qreal getEffectiveColumnWidth(int column) const;
inline int topRow() const { return loadedRows.cbegin().key(); }
inline int bottomRow() const { return (--loadedRows.cend()).key(); }
@@ -363,6 +376,7 @@ public:
void updateExtents();
void syncLoadedTableRectFromLoadedTable();
void syncLoadedTableFromLoadRequest();
+ void shiftLoadedTableRect(const QPointF newPosition);
int nextVisibleEdgeIndex(Qt::Edge edge, int startIndex);
int nextVisibleEdgeIndexAroundLoadedTable(Qt::Edge edge);
@@ -394,8 +408,11 @@ public:
void processRebuildTable();
bool moveToNextRebuildState();
void calculateTopLeft(QPoint &topLeft, QPointF &topLeftPos);
- void beginRebuildTable();
+ void loadInitialTable();
+
void layoutAfterLoadingInitialTable();
+ void adjustViewportXAccordingToAlignment();
+ void adjustViewportYAccordingToAlignment();
void scheduleRebuildTable(QQuickTableViewPrivate::RebuildOptions options);
@@ -413,8 +430,9 @@ public:
virtual QVariant modelImpl() const;
virtual void setModelImpl(const QVariant &newModel);
virtual void syncModel();
- inline void syncRebuildOptions();
virtual void syncSyncView();
+ virtual void syncPositionView();
+ inline void syncRebuildOptions();
void connectToModel();
void disconnectFromModel();
@@ -459,6 +477,8 @@ public:
QPoint cell;
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickTableViewPrivate::RebuildOptions)
+
QT_END_NAMESPACE
#endif
diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
index ef39a91a65..e0917cbea9 100644
--- a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
+++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
@@ -178,6 +178,10 @@ private slots:
void delegateWithRequiredProperties();
void checkThatFetchMoreIsCalledWhenScrolledToTheEndOfTable();
void replaceModel();
+ void positionViewAtRow_data();
+ void positionViewAtRow();
+ void positionViewAtColumn_data();
+ void positionViewAtColumn();
};
tst_QQuickTableView::tst_QQuickTableView()
@@ -2768,6 +2772,188 @@ void tst_QQuickTableView::replaceModel()
QCOMPARE(tableView->contentHeight(), 0);
}
+void tst_QQuickTableView::positionViewAtRow_data()
+{
+ QTest::addColumn<int>("row");
+ QTest::addColumn<Qt::AlignmentFlag>("alignment");
+ QTest::addColumn<qreal>("offset");
+ QTest::addColumn<qreal>("contentYStartPos");
+
+ QTest::newRow("AlignTop 0") << 0 << Qt::AlignTop << 0. << 0.;
+ QTest::newRow("AlignTop 1") << 1 << Qt::AlignTop << 0. << 0.;
+ QTest::newRow("AlignTop 1") << 1 << Qt::AlignTop << 0. << 50.;
+ QTest::newRow("AlignTop 50") << 50 << Qt::AlignTop << 0. << -1.;
+ QTest::newRow("AlignTop 0") << 0 << Qt::AlignTop << 0. << -1.;
+ QTest::newRow("AlignTop 99") << 99 << Qt::AlignTop << 0. << -1.;
+
+ QTest::newRow("AlignTop 0") << 0 << Qt::AlignTop << -10. << 0.;
+ QTest::newRow("AlignTop 1") << 1 << Qt::AlignTop << -10. << 0.;
+ QTest::newRow("AlignTop 1") << 1 << Qt::AlignTop << -10. << 50.;
+ QTest::newRow("AlignTop 50") << 50 << Qt::AlignTop << -10. << -1.;
+ QTest::newRow("AlignTop 0") << 0 << Qt::AlignTop << -10. << -1.;
+ QTest::newRow("AlignTop 99") << 99 << Qt::AlignTop << -10. << -1.;
+
+ QTest::newRow("AlignBottom 0") << 0 << Qt::AlignBottom << 0. << 0.;
+ QTest::newRow("AlignBottom 1") << 1 << Qt::AlignBottom << 0. << 0.;
+ QTest::newRow("AlignBottom 1") << 1 << Qt::AlignBottom << 0. << 50.;
+ QTest::newRow("AlignBottom 50") << 50 << Qt::AlignBottom << 0. << -1.;
+ QTest::newRow("AlignBottom 0") << 0 << Qt::AlignBottom << 0. << -1.;
+ QTest::newRow("AlignBottom 99") << 99 << Qt::AlignBottom << 0. << -1.;
+
+ QTest::newRow("AlignBottom 0") << 0 << Qt::AlignBottom << 10. << 0.;
+ QTest::newRow("AlignBottom 1") << 1 << Qt::AlignBottom << 10. << 0.;
+ QTest::newRow("AlignBottom 1") << 1 << Qt::AlignBottom << 10. << 50.;
+ QTest::newRow("AlignBottom 50") << 50 << Qt::AlignBottom << 10. << -1.;
+ QTest::newRow("AlignBottom 0") << 0 << Qt::AlignBottom << 10. << -1.;
+ QTest::newRow("AlignBottom 99") << 99 << Qt::AlignBottom << 10. << -1.;
+
+ QTest::newRow("AlignCenter 0") << 0 << Qt::AlignCenter << 0. << 0.;
+ QTest::newRow("AlignCenter 1") << 1 << Qt::AlignCenter << 0. << 0.;
+ QTest::newRow("AlignCenter 1") << 1 << Qt::AlignCenter << 0. << 50.;
+ QTest::newRow("AlignCenter 50") << 50 << Qt::AlignCenter << 0. << -1.;
+ QTest::newRow("AlignCenter 0") << 0 << Qt::AlignCenter << 0. << -1.;
+ QTest::newRow("AlignCenter 99") << 99 << Qt::AlignCenter << 0. << -1.;
+
+ QTest::newRow("AlignCenter 0") << 0 << Qt::AlignCenter << -10. << 0.;
+ QTest::newRow("AlignCenter 1") << 1 << Qt::AlignCenter << -10. << 0.;
+ QTest::newRow("AlignCenter 1") << 1 << Qt::AlignCenter << -10. << 50.;
+ QTest::newRow("AlignCenter 50") << 50 << Qt::AlignCenter << -10. << -1.;
+ QTest::newRow("AlignCenter 0") << 0 << Qt::AlignCenter << -10. << -1.;
+ QTest::newRow("AlignCenter 99") << 99 << Qt::AlignCenter << -10. << -1.;
+}
+
+void tst_QQuickTableView::positionViewAtRow()
+{
+ // Check that positionViewAtRow actually flicks the view
+ // to the right position so that the row becomes visible
+ QFETCH(int, row);
+ QFETCH(Qt::AlignmentFlag, alignment);
+ QFETCH(qreal, offset);
+ QFETCH(qreal, contentYStartPos);
+
+ LOAD_TABLEVIEW("plaintableview.qml");
+ auto model = TestModelAsVariant(100, 100);
+ tableView->setModel(model);
+ if (contentYStartPos >= 0)
+ tableView->setContentY(contentYStartPos);
+
+ WAIT_UNTIL_POLISHED;
+
+ tableView->positionViewAtRow(row, alignment, offset);
+
+ WAIT_UNTIL_POLISHED;
+
+ const QPoint cell(0, row);
+ const int modelIndex = tableViewPrivate->modelIndexAtCell(cell);
+ QVERIFY(tableViewPrivate->loadedItems.contains(modelIndex));
+ const auto geometry = tableViewPrivate->loadedTableItem(cell)->geometry();
+
+ switch (alignment) {
+ case Qt::AlignTop:
+ QCOMPARE(geometry.y(), tableView->contentY() - offset);
+ break;
+ case Qt::AlignBottom:
+ QCOMPARE(geometry.bottom(), tableView->contentY() + tableView->height() - offset);
+ break;
+ case Qt::AlignCenter:
+ QCOMPARE(geometry.y(), tableView->contentY() + (tableView->height() / 2) - (geometry.height() / 2) - offset);
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+}
+
+void tst_QQuickTableView::positionViewAtColumn_data()
+{
+ QTest::addColumn<int>("column");
+ QTest::addColumn<Qt::AlignmentFlag>("alignment");
+ QTest::addColumn<qreal>("offset");
+ QTest::addColumn<qreal>("contentXStartPos");
+
+ QTest::newRow("AlignLeft 0") << 0 << Qt::AlignLeft << 0. << 0.;
+ QTest::newRow("AlignLeft 1") << 1 << Qt::AlignLeft << 0. << 0.;
+ QTest::newRow("AlignLeft 1") << 1 << Qt::AlignLeft << 0. << 50.;
+ QTest::newRow("AlignLeft 50") << 50 << Qt::AlignLeft << 0. << -1.;
+ QTest::newRow("AlignLeft 0") << 0 << Qt::AlignLeft << 0. << -1.;
+ QTest::newRow("AlignLeft 99") << 99 << Qt::AlignLeft << 0. << -1.;
+
+ QTest::newRow("AlignLeft 0") << 0 << Qt::AlignLeft << -10. << 0.;
+ QTest::newRow("AlignLeft 1") << 1 << Qt::AlignLeft << -10. << 0.;
+ QTest::newRow("AlignLeft 1") << 1 << Qt::AlignLeft << -10. << 50.;
+ QTest::newRow("AlignLeft 50") << 50 << Qt::AlignLeft << -10. << -1.;
+ QTest::newRow("AlignLeft 0") << 0 << Qt::AlignLeft << -10. << -1.;
+ QTest::newRow("AlignLeft 99") << 99 << Qt::AlignLeft << -10. << -1.;
+
+ QTest::newRow("AlignRight 0") << 0 << Qt::AlignRight << 0. << 0.;
+ QTest::newRow("AlignRight 1") << 1 << Qt::AlignRight << 0. << 0.;
+ QTest::newRow("AlignRight 1") << 1 << Qt::AlignRight << 0. << 50.;
+ QTest::newRow("AlignRight 50") << 50 << Qt::AlignRight << 0. << -1.;
+ QTest::newRow("AlignRight 0") << 0 << Qt::AlignRight << 0. << -1.;
+ QTest::newRow("AlignRight 99") << 99 << Qt::AlignRight << 0. << -1.;
+
+ QTest::newRow("AlignRight 0") << 0 << Qt::AlignRight << 10. << 0.;
+ QTest::newRow("AlignRight 1") << 1 << Qt::AlignRight << 10. << 0.;
+ QTest::newRow("AlignRight 1") << 1 << Qt::AlignRight << 10. << 50.;
+ QTest::newRow("AlignRight 50") << 50 << Qt::AlignRight << 10. << -1.;
+ QTest::newRow("AlignRight 0") << 0 << Qt::AlignRight << 10. << -1.;
+ QTest::newRow("AlignRight 99") << 99 << Qt::AlignRight << 10. << -1.;
+
+ QTest::newRow("AlignCenter 0") << 0 << Qt::AlignCenter << 0. << 0.;
+ QTest::newRow("AlignCenter 1") << 1 << Qt::AlignCenter << 0. << 0.;
+ QTest::newRow("AlignCenter 1") << 1 << Qt::AlignCenter << 0. << 50.;
+ QTest::newRow("AlignCenter 50") << 50 << Qt::AlignCenter << 0. << -1.;
+ QTest::newRow("AlignCenter 0") << 0 << Qt::AlignCenter << 0. << -1.;
+ QTest::newRow("AlignCenter 99") << 99 << Qt::AlignCenter << 0. << -1.;
+
+ QTest::newRow("AlignCenter 0") << 0 << Qt::AlignCenter << -10. << 0.;
+ QTest::newRow("AlignCenter 1") << 1 << Qt::AlignCenter << -10. << 0.;
+ QTest::newRow("AlignCenter 1") << 1 << Qt::AlignCenter << -10. << 50.;
+ QTest::newRow("AlignCenter 50") << 50 << Qt::AlignCenter << -10. << -1.;
+ QTest::newRow("AlignCenter 0") << 0 << Qt::AlignCenter << -10. << -1.;
+ QTest::newRow("AlignCenter 99") << 99 << Qt::AlignCenter << -10. << -1.;
+}
+
+void tst_QQuickTableView::positionViewAtColumn()
+{
+ // Check that positionViewAtColumn actually flicks the view
+ // to the right position so that the row becomes visible
+ QFETCH(int, column);
+ QFETCH(Qt::AlignmentFlag, alignment);
+ QFETCH(qreal, offset);
+ QFETCH(qreal, contentXStartPos);
+
+ LOAD_TABLEVIEW("plaintableview.qml");
+ auto model = TestModelAsVariant(100, 100);
+ tableView->setModel(model);
+ if (contentXStartPos >= 0)
+ tableView->setContentX(contentXStartPos);
+
+ WAIT_UNTIL_POLISHED;
+
+ tableView->positionViewAtColumn(column, alignment, offset);
+
+ WAIT_UNTIL_POLISHED;
+
+ const QPoint cell(column, 0);
+ const int modelIndex = tableViewPrivate->modelIndexAtCell(cell);
+ QVERIFY(tableViewPrivate->loadedItems.contains(modelIndex));
+ const auto geometry = tableViewPrivate->loadedTableItem(cell)->geometry();
+
+ switch (alignment) {
+ case Qt::AlignLeft:
+ QCOMPARE(geometry.x(), tableView->contentX() - offset);
+ break;
+ case Qt::AlignRight:
+ QCOMPARE(geometry.right(), tableView->contentX() + tableView->width() - offset);
+ break;
+ case Qt::AlignCenter:
+ QCOMPARE(geometry.x(), tableView->contentX() + (tableView->width() / 2) - (geometry.width() / 2) - offset);
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+}
+
QTEST_MAIN(tst_QQuickTableView)
#include "tst_qquicktableview.moc"