QQuickTableView: add support for hiding rows and columns
This patch will add support for hiding rows and columns to TableView. You can now hide a column by returning 0 width for it from the columnWidthProvider. The same can be done to hide a row (by using the rowHeightProvider). If you return NaN or negative number, TableView will fall back to calculate the size of the column/row by looking at the delegate items, like before. This to make it possible to hide some rows/columns, without having to calculate and return the heights and widths of the other rows and columns. [ChangeLog][QtQuick][TableView] Added support for hiding rows and columns by setting their size to 0 from the columnsWidthProvider/rowHeightProvider. Change-Id: If9e1a8db91e257d36cb2787bab4856e6201456ac Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
This commit is contained in:
parent
e04e5db13d
commit
0068575602
File diff suppressed because it is too large
Load Diff
|
@ -88,54 +88,52 @@ public:
|
|||
public:
|
||||
void begin(const QPoint &cell, const QPointF &pos, QQmlIncubator::IncubationMode incubationMode)
|
||||
{
|
||||
Q_ASSERT(!active);
|
||||
active = true;
|
||||
tableEdge = Qt::Edge(0);
|
||||
tableCells = QLine(cell, cell);
|
||||
mode = incubationMode;
|
||||
cellCount = 1;
|
||||
currentIndex = 0;
|
||||
startPos = pos;
|
||||
Q_ASSERT(!m_active);
|
||||
m_active = true;
|
||||
m_edge = Qt::Edge(0);
|
||||
m_mode = incubationMode;
|
||||
m_edgeIndex = cell.x();
|
||||
m_visibleCellsInEdge.clear();
|
||||
m_visibleCellsInEdge.append(cell.y());
|
||||
m_currentIndex = 0;
|
||||
m_startPos = pos;
|
||||
qCDebug(lcTableViewDelegateLifecycle()) << "begin top-left:" << toString();
|
||||
}
|
||||
|
||||
void begin(const QLine cellsToLoad, Qt::Edge edgeToLoad, QQmlIncubator::IncubationMode incubationMode)
|
||||
void begin(Qt::Edge edgeToLoad, int edgeIndex, const QList<int> visibleCellsInEdge, QQmlIncubator::IncubationMode incubationMode)
|
||||
{
|
||||
Q_ASSERT(!active);
|
||||
active = true;
|
||||
tableEdge = edgeToLoad;
|
||||
tableCells = cellsToLoad;
|
||||
mode = incubationMode;
|
||||
cellCount = tableCells.x2() - tableCells.x1() + tableCells.y2() - tableCells.y1() + 1;
|
||||
currentIndex = 0;
|
||||
Q_ASSERT(!m_active);
|
||||
m_active = true;
|
||||
m_edge = edgeToLoad;
|
||||
m_edgeIndex = edgeIndex;
|
||||
m_visibleCellsInEdge = visibleCellsInEdge;
|
||||
m_mode = incubationMode;
|
||||
m_currentIndex = 0;
|
||||
qCDebug(lcTableViewDelegateLifecycle()) << "begin:" << toString();
|
||||
}
|
||||
|
||||
inline void markAsDone() { active = false; }
|
||||
inline bool isActive() { return active; }
|
||||
inline void markAsDone() { m_active = false; }
|
||||
inline bool isActive() { return m_active; }
|
||||
|
||||
inline QPoint firstCell() { return tableCells.p1(); }
|
||||
inline QPoint lastCell() { return tableCells.p2(); }
|
||||
inline QPoint currentCell() { return cellAt(currentIndex); }
|
||||
inline QPoint previousCell() { return cellAt(currentIndex - 1); }
|
||||
inline QPoint currentCell() { return cellAt(m_currentIndex); }
|
||||
inline bool hasCurrentCell() { return m_currentIndex < m_visibleCellsInEdge.count(); }
|
||||
inline void moveToNextCell() { ++m_currentIndex; }
|
||||
|
||||
inline bool atBeginning() { return currentIndex == 0; }
|
||||
inline bool hasCurrentCell() { return currentIndex < cellCount; }
|
||||
inline void moveToNextCell() { ++currentIndex; }
|
||||
inline Qt::Edge edge() { return m_edge; }
|
||||
inline int row() { return cellAt(0).y(); }
|
||||
inline int column() { return cellAt(0).x(); }
|
||||
inline QQmlIncubator::IncubationMode incubationMode() { return m_mode; }
|
||||
|
||||
inline Qt::Edge edge() { return tableEdge; }
|
||||
inline QQmlIncubator::IncubationMode incubationMode() { return mode; }
|
||||
|
||||
inline QPointF startPosition() { return startPos; }
|
||||
inline QPointF startPosition() { return m_startPos; }
|
||||
|
||||
QString toString()
|
||||
{
|
||||
QString str;
|
||||
QDebug dbg(&str);
|
||||
dbg.nospace() << "TableSectionLoadRequest(" << "edge:"
|
||||
<< tableEdge << " cells:" << tableCells << " incubation:";
|
||||
<< m_edge << ", edgeIndex:" << m_edgeIndex << ", incubation:";
|
||||
|
||||
switch (mode) {
|
||||
switch (m_mode) {
|
||||
case QQmlIncubator::Asynchronous:
|
||||
dbg << "Asynchronous";
|
||||
break;
|
||||
|
@ -151,22 +149,31 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
Qt::Edge tableEdge = Qt::Edge(0);
|
||||
QLine tableCells;
|
||||
int currentIndex = 0;
|
||||
int cellCount = 0;
|
||||
bool active = false;
|
||||
QQmlIncubator::IncubationMode mode = QQmlIncubator::AsynchronousIfNested;
|
||||
QPointF startPos;
|
||||
Qt::Edge m_edge = Qt::Edge(0);
|
||||
QList<int> m_visibleCellsInEdge;
|
||||
int m_edgeIndex = 0;
|
||||
int m_currentIndex = 0;
|
||||
bool m_active = false;
|
||||
QQmlIncubator::IncubationMode m_mode = QQmlIncubator::AsynchronousIfNested;
|
||||
QPointF m_startPos;
|
||||
|
||||
QPoint cellAt(int index)
|
||||
{
|
||||
int x = tableCells.p1().x() + (tableCells.dx() ? index : 0);
|
||||
int y = tableCells.p1().y() + (tableCells.dy() ? index : 0);
|
||||
return QPoint(x, y);
|
||||
inline QPoint cellAt(int index) {
|
||||
return !m_edge || (m_edge & (Qt::LeftEdge | Qt::RightEdge))
|
||||
? QPoint(m_edgeIndex, m_visibleCellsInEdge[index])
|
||||
: QPoint(m_visibleCellsInEdge[index], m_edgeIndex);
|
||||
}
|
||||
};
|
||||
|
||||
class EdgeRange {
|
||||
public:
|
||||
EdgeRange();
|
||||
bool containsIndex(Qt::Edge edge, int index);
|
||||
|
||||
int startIndex;
|
||||
int endIndex;
|
||||
qreal size;
|
||||
};
|
||||
|
||||
enum class RebuildState {
|
||||
Begin = 0,
|
||||
LoadInitalTable,
|
||||
|
@ -234,7 +241,6 @@ public:
|
|||
|
||||
TableEdgeLoadRequest loadRequest;
|
||||
|
||||
QPoint contentSizeBenchMarkPoint = QPoint(-1, -1);
|
||||
QSizeF cellSpacing = QSizeF(0, 0);
|
||||
|
||||
QQmlTableInstanceModel::ReusableFlag reusableFlag = QQmlTableInstanceModel::Reusable;
|
||||
|
@ -248,6 +254,10 @@ public:
|
|||
QJSValue rowHeightProvider;
|
||||
QJSValue columnWidthProvider;
|
||||
|
||||
EdgeRange cachedNextVisibleEdgeIndex[4];
|
||||
EdgeRange cachedColumnWidth;
|
||||
EdgeRange cachedRowHeight;
|
||||
|
||||
// TableView uses contentWidth/height to report the size of the table (this
|
||||
// will e.g make scrollbars written for Flickable work out of the box). This
|
||||
// value is continuously calculated, and will change/improve as more columns
|
||||
|
@ -281,8 +291,13 @@ public:
|
|||
qreal sizeHintForRow(int row);
|
||||
void calculateTableSize();
|
||||
|
||||
qreal resolveColumnWidth(int column);
|
||||
qreal resolveRowHeight(int row);
|
||||
inline bool isColumnHidden(int column);
|
||||
inline bool isRowHidden(int row);
|
||||
|
||||
qreal getColumnLayoutWidth(int column);
|
||||
qreal getRowLayoutHeight(int row);
|
||||
qreal getColumnWidth(int column);
|
||||
qreal getRowHeight(int row);
|
||||
|
||||
inline int topRow() const { return loadedRows.firstKey(); }
|
||||
inline int bottomRow() const { return loadedRows.lastKey(); }
|
||||
|
@ -300,12 +315,16 @@ public:
|
|||
void updateContentWidth();
|
||||
void updateContentHeight();
|
||||
void updateAverageEdgeSize();
|
||||
void forceLayout();
|
||||
|
||||
void enforceTableAtOrigin();
|
||||
void syncLoadedTableRectFromLoadedTable();
|
||||
void syncLoadedTableFromLoadRequest();
|
||||
|
||||
int nextVisibleEdgeIndex(Qt::Edge edge, int startIndex);
|
||||
int nextVisibleEdgeIndexAroundLoadedTable(Qt::Edge edge);
|
||||
inline int edgeToArrayIndex(Qt::Edge edge);
|
||||
void clearEdgeSizeCache();
|
||||
|
||||
bool canLoadTableEdge(Qt::Edge tableEdge, const QRectF fillRect) const;
|
||||
bool canUnloadTableEdge(Qt::Edge tableEdge, const QRectF fillRect) const;
|
||||
|
@ -316,7 +335,6 @@ public:
|
|||
qreal cellHeight(const QPoint &cell);
|
||||
|
||||
FxTableItem *loadedTableItem(const QPoint &cell) const;
|
||||
FxTableItem *itemNextTo(const FxTableItem *fxTableItem, const QPoint &direction) const;
|
||||
FxTableItem *createFxTableItem(const QPoint &cell, QQmlIncubator::IncubationMode incubationMode);
|
||||
FxTableItem *loadFxTableItem(const QPoint &cell, QQmlIncubator::IncubationMode incubationMode);
|
||||
|
||||
|
@ -324,18 +342,17 @@ public:
|
|||
void releaseLoadedItems(QQmlTableInstanceModel::ReusableFlag reusableFlag);
|
||||
|
||||
void unloadItem(const QPoint &cell);
|
||||
void unloadItems(const QLine &items);
|
||||
|
||||
void loadInitialTopLeftItem(const QPoint &cell, const QPointF &pos);
|
||||
void loadEdge(Qt::Edge edge, QQmlIncubator::IncubationMode incubationMode);
|
||||
void unloadEdge(Qt::Edge edge);
|
||||
void loadAndUnloadVisibleEdges();
|
||||
void drainReusePoolAfterLoadRequest();
|
||||
void cancelLoadRequest();
|
||||
void processLoadRequest();
|
||||
|
||||
void processRebuildTable();
|
||||
bool moveToNextRebuildState();
|
||||
QPoint calculateNewTopLeft();
|
||||
void calculateTopLeft(QPoint &topLeft, QPointF &topLeftPos);
|
||||
void beginRebuildTable();
|
||||
void layoutAfterLoadingInitialTable();
|
||||
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtQuick module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Window 2.3
|
||||
|
||||
Item {
|
||||
width: 640
|
||||
height: 450
|
||||
|
||||
property alias tableView: tableView
|
||||
property var rowsToHide
|
||||
property var columnsToHide
|
||||
|
||||
TableView {
|
||||
id: tableView
|
||||
width: 600
|
||||
height: 400
|
||||
anchors.margins: 1
|
||||
clip: true
|
||||
delegate: tableViewDelegate
|
||||
columnSpacing: 1
|
||||
rowSpacing: 1
|
||||
columnWidthProvider: function(column) {
|
||||
if (columnsToHide.includes(column))
|
||||
return 0;
|
||||
}
|
||||
rowHeightProvider: function(row) {
|
||||
if (rowsToHide.includes(row))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: tableViewDelegate
|
||||
Rectangle {
|
||||
objectName: "tableViewDelegate"
|
||||
color: "lightgray"
|
||||
border.width: 1
|
||||
implicitWidth: 50
|
||||
implicitHeight: 50
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: column + "," + row
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -56,16 +56,14 @@ Item {
|
|||
delegate: tableViewDelegate
|
||||
columnSpacing: 1
|
||||
rowSpacing: 1
|
||||
columnWidthProvider: function(column) { }
|
||||
rowHeightProvider: function(row) { return 0 }
|
||||
columnWidthProvider: function(column) { return "notAValidValue" }
|
||||
rowHeightProvider: function(row) { return "notAValidValue" }
|
||||
}
|
||||
|
||||
Component {
|
||||
id: tableViewDelegate
|
||||
Rectangle {
|
||||
objectName: "tableViewDelegate"
|
||||
implicitWidth: 20
|
||||
implicitHeight: 20
|
||||
color: "lightgray"
|
||||
border.width: 1
|
||||
Text {
|
||||
|
|
|
@ -46,6 +46,8 @@ Item {
|
|||
|
||||
property alias tableView: tableView
|
||||
property Component delegate: tableViewDelegate
|
||||
property bool returnNegativeColumnWidth: false
|
||||
property bool returnNegativeRowHeight: false
|
||||
|
||||
TableView {
|
||||
id: tableView
|
||||
|
@ -56,8 +58,16 @@ Item {
|
|||
delegate: tableViewDelegate
|
||||
columnSpacing: 1
|
||||
rowSpacing: 1
|
||||
columnWidthProvider: function(column) { return column + 10 }
|
||||
rowHeightProvider: function(row) { return row + 10 }
|
||||
columnWidthProvider: function(column) {
|
||||
if (returnNegativeColumnWidth)
|
||||
return -1
|
||||
return column + 10
|
||||
}
|
||||
rowHeightProvider: function(row) {
|
||||
if (returnNegativeRowHeight)
|
||||
return -1
|
||||
return row + 10
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
|
|
|
@ -111,10 +111,12 @@ private slots:
|
|||
void checkDelegateWithAnchors();
|
||||
void checkColumnWidthProvider();
|
||||
void checkColumnWidthProviderInvalidReturnValues();
|
||||
void checkColumnWidthProviderNegativeReturnValue();
|
||||
void checkColumnWidthProviderNotCallable();
|
||||
void checkRowHeightWithoutProvider();
|
||||
void checkRowHeightProvider();
|
||||
void checkRowHeightProviderInvalidReturnValues();
|
||||
void checkRowHeightProviderNegativeReturnValue();
|
||||
void checkRowHeightProviderNotCallable();
|
||||
void checkForceLayoutFunction();
|
||||
void checkContentWidthAndHeight();
|
||||
|
@ -157,6 +159,8 @@ private slots:
|
|||
void checkRebuildViewportOnly();
|
||||
void useDelegateChooserWithoutDefault();
|
||||
void checkTableviewInsideAsyncLoader();
|
||||
void hideRowsAndColumns_data();
|
||||
void hideRowsAndColumns();
|
||||
};
|
||||
|
||||
tst_QQuickTableView::tst_QQuickTableView()
|
||||
|
@ -373,7 +377,7 @@ void tst_QQuickTableView::checkColumnWidthProviderInvalidReturnValues()
|
|||
|
||||
tableView->setModel(model);
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*Provider.*valid"));
|
||||
QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*implicitHeight.*zero"));
|
||||
|
||||
WAIT_UNTIL_POLISHED;
|
||||
|
||||
|
@ -381,6 +385,23 @@ void tst_QQuickTableView::checkColumnWidthProviderInvalidReturnValues()
|
|||
QCOMPARE(fxItem->item->width(), kDefaultColumnWidth);
|
||||
}
|
||||
|
||||
void tst_QQuickTableView::checkColumnWidthProviderNegativeReturnValue()
|
||||
{
|
||||
// Check that we fall back to use the implicit width of the delegate
|
||||
// items if the columnWidthProvider return a negative number.
|
||||
LOAD_TABLEVIEW("userowcolumnprovider.qml");
|
||||
|
||||
auto model = TestModelAsVariant(10, 10);
|
||||
view->rootObject()->setProperty("returnNegativeColumnWidth", true);
|
||||
|
||||
tableView->setModel(model);
|
||||
|
||||
WAIT_UNTIL_POLISHED;
|
||||
|
||||
for (auto fxItem : tableViewPrivate->loadedItems)
|
||||
QCOMPARE(fxItem->item->width(), 20);
|
||||
}
|
||||
|
||||
void tst_QQuickTableView::checkColumnWidthProviderNotCallable()
|
||||
{
|
||||
// Check that we fall back to use default columns widths, if you
|
||||
|
@ -453,7 +474,7 @@ void tst_QQuickTableView::checkRowHeightProviderInvalidReturnValues()
|
|||
|
||||
tableView->setModel(model);
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*Provider.*valid"));
|
||||
QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*implicitHeight.*zero"));
|
||||
|
||||
WAIT_UNTIL_POLISHED;
|
||||
|
||||
|
@ -461,6 +482,23 @@ void tst_QQuickTableView::checkRowHeightProviderInvalidReturnValues()
|
|||
QCOMPARE(fxItem->item->height(), kDefaultRowHeight);
|
||||
}
|
||||
|
||||
void tst_QQuickTableView::checkRowHeightProviderNegativeReturnValue()
|
||||
{
|
||||
// Check that we fall back to use the implicit height of the delegate
|
||||
// items if the rowHeightProvider return a negative number.
|
||||
LOAD_TABLEVIEW("userowcolumnprovider.qml");
|
||||
|
||||
auto model = TestModelAsVariant(10, 10);
|
||||
view->rootObject()->setProperty("returnNegativeRowHeight", true);
|
||||
|
||||
tableView->setModel(model);
|
||||
|
||||
WAIT_UNTIL_POLISHED;
|
||||
|
||||
for (auto fxItem : tableViewPrivate->loadedItems)
|
||||
QCOMPARE(fxItem->item->height(), 20);
|
||||
}
|
||||
|
||||
void tst_QQuickTableView::checkRowHeightProviderNotCallable()
|
||||
{
|
||||
// Check that we fall back to use default row heights, if you
|
||||
|
@ -538,6 +576,8 @@ void tst_QQuickTableView::checkContentWidthAndHeight()
|
|||
const qreal expectedSizeInit = (tableSize * cellSizeSmall) + ((tableSize - 1) * spacing);
|
||||
QCOMPARE(tableView->contentWidth(), expectedSizeInit);
|
||||
QCOMPARE(tableView->contentHeight(), expectedSizeInit);
|
||||
QCOMPARE(tableViewPrivate->averageEdgeSize.width(), cellSizeSmall);
|
||||
QCOMPARE(tableViewPrivate->averageEdgeSize.height(), cellSizeSmall);
|
||||
|
||||
// Flick in 5 more rows and columns, but not so far that we start loading in
|
||||
// the ones that are bigger. Loading in more rows and columns of the same
|
||||
|
@ -548,6 +588,8 @@ void tst_QQuickTableView::checkContentWidthAndHeight()
|
|||
|
||||
QCOMPARE(tableView->contentWidth(), expectedSizeInit);
|
||||
QCOMPARE(tableView->contentHeight(), expectedSizeInit);
|
||||
QCOMPARE(tableViewPrivate->averageEdgeSize.width(), cellSizeSmall);
|
||||
QCOMPARE(tableViewPrivate->averageEdgeSize.height(), cellSizeSmall);
|
||||
|
||||
// Flick to row and column 20 (smallCellCount), since there the row and
|
||||
// column sizes increases with 100. Check that TableView then adjusts
|
||||
|
@ -562,6 +604,11 @@ void tst_QQuickTableView::checkContentWidthAndHeight()
|
|||
QVERIFY(tableViewPrivate->rebuildScheduled);
|
||||
WAIT_UNTIL_POLISHED;
|
||||
|
||||
// Check that the average cell size is now matching the
|
||||
// large cells since they fill up the whole view.
|
||||
QCOMPARE(tableViewPrivate->averageEdgeSize.width(), cellSizeLarge);
|
||||
QCOMPARE(tableViewPrivate->averageEdgeSize.height(), cellSizeLarge);
|
||||
|
||||
const int largeSizeCellCountInView = qCeil(tableView->width() / cellSizeLarge);
|
||||
const int columnCount = smallCellCount + largeSizeCellCountInView;
|
||||
QCOMPARE(tableViewPrivate->leftColumn(), smallCellCount);
|
||||
|
@ -571,41 +618,47 @@ void tst_QQuickTableView::checkContentWidthAndHeight()
|
|||
const qreal secondHalfOneScreenLength = largeSizeCellCountInView * cellSizeLarge;
|
||||
const qreal lengthAfterFlick = firstHalfLength + secondHalfOneScreenLength;
|
||||
|
||||
const qreal averageCellSize = lengthAfterFlick / columnCount;
|
||||
const qreal expectedSizeHalf = (tableSize * averageCellSize) + accumulatedSpacing;
|
||||
// Check that loadedTableOuterRect has been calculated correct thus far
|
||||
const qreal spacingAfterFlick = (smallCellCount + largeSizeCellCountInView - 1) * spacing;
|
||||
QCOMPARE(tableViewPrivate->loadedTableOuterRect.left(), flickTo + spacing);
|
||||
QCOMPARE(tableViewPrivate->loadedTableOuterRect.right(), lengthAfterFlick + spacingAfterFlick);
|
||||
QCOMPARE(tableViewPrivate->loadedTableOuterRect.top(), flickTo + spacing);
|
||||
QCOMPARE(tableViewPrivate->loadedTableOuterRect.bottom(), lengthAfterFlick + spacingAfterFlick);
|
||||
|
||||
QCOMPARE(tableView->contentWidth(), expectedSizeHalf);
|
||||
QCOMPARE(tableView->contentHeight(), expectedSizeHalf);
|
||||
// At this point, we should have the exact content width/height set, because
|
||||
// TableView knows where the large cells start in the viewport, and how many
|
||||
// columns that remain in the model. It will assume that the rest of the the
|
||||
// columns have the same average size as the ones currently inside the viewport.
|
||||
const qreal expectedContentSize = (smallCellCount * cellSizeSmall) + (largeCellCount * cellSizeLarge) + accumulatedSpacing;
|
||||
QCOMPARE(tableView->contentWidth(), expectedContentSize);
|
||||
QCOMPARE(tableView->contentHeight(), expectedContentSize);
|
||||
|
||||
// Flick to the end (row/column 100, and overshoot a bit), and
|
||||
// check that we then end up with the exact content width/height.
|
||||
const qreal secondHalfLength = largeCellCount * cellSizeLarge;
|
||||
const qreal expectedFullSize = (firstHalfLength + secondHalfLength) + accumulatedSpacing;
|
||||
|
||||
// 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);
|
||||
}
|
||||
const qreal overshoot = 100;
|
||||
const qreal endPosX = expectedFullSize - tableView->width() + overshoot;
|
||||
const qreal endPosY = expectedFullSize - tableView->height() + overshoot;
|
||||
tableView->setContentX(endPosX);
|
||||
tableView->setContentY(endPosY);
|
||||
|
||||
QCOMPARE(tableView->contentWidth(), expectedFullSize);
|
||||
QCOMPARE(tableView->contentHeight(), expectedFullSize);
|
||||
|
||||
// Flick back to start. Since we know the actual table
|
||||
// size, contentWidth/Height shouldn't change.
|
||||
// Flick back to start
|
||||
tableView->setContentX(0);
|
||||
tableView->setContentY(0);
|
||||
|
||||
QCOMPARE(tableView->contentWidth(), expectedFullSize);
|
||||
QCOMPARE(tableView->contentHeight(), expectedFullSize);
|
||||
// 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;
|
||||
|
||||
// We should now have the same content width/height as when we started
|
||||
QCOMPARE(tableView->contentWidth(), expectedSizeInit);
|
||||
QCOMPARE(tableView->contentHeight(), expectedSizeInit);
|
||||
}
|
||||
|
||||
void tst_QQuickTableView::checkPageFlicking()
|
||||
|
@ -2001,6 +2054,92 @@ void tst_QQuickTableView::checkTableviewInsideAsyncLoader()
|
|||
QVERIFY(height > 0);
|
||||
};
|
||||
|
||||
#define INT_LIST(indices) QVariant::fromValue(QList<int>() << indices)
|
||||
|
||||
void tst_QQuickTableView::hideRowsAndColumns_data()
|
||||
{
|
||||
QTest::addColumn<QVariant>("rowsToHide");
|
||||
QTest::addColumn<QVariant>("columnsToHide");
|
||||
|
||||
const auto emptyList = QVariant::fromValue(QList<int>());
|
||||
|
||||
// Hide rows
|
||||
QTest::newRow("first") << INT_LIST(0) << emptyList;
|
||||
QTest::newRow("middle 1") << INT_LIST(1) << emptyList;
|
||||
QTest::newRow("middle 3") << INT_LIST(3) << emptyList;
|
||||
QTest::newRow("last") << INT_LIST(4) << emptyList;
|
||||
|
||||
QTest::newRow("subsequent 0,1") << INT_LIST(0 << 1) << emptyList;
|
||||
QTest::newRow("subsequent 1,2") << INT_LIST(1 << 2) << emptyList;
|
||||
QTest::newRow("subsequent 3,4") << INT_LIST(3 << 4) << emptyList;
|
||||
|
||||
QTest::newRow("all but first") << INT_LIST(1 << 2 << 3 << 4) << emptyList;
|
||||
QTest::newRow("all but last") << INT_LIST(0 << 1 << 2 << 3) << emptyList;
|
||||
QTest::newRow("all but middle") << INT_LIST(0 << 1 << 3 << 4) << emptyList;
|
||||
|
||||
// Hide columns
|
||||
QTest::newRow("first") << emptyList << INT_LIST(0);
|
||||
QTest::newRow("middle 1") << emptyList << INT_LIST(1);
|
||||
QTest::newRow("middle 3") << emptyList << INT_LIST(3);
|
||||
QTest::newRow("last") << emptyList << INT_LIST(4);
|
||||
|
||||
QTest::newRow("subsequent 0,1") << emptyList << INT_LIST(0 << 1);
|
||||
QTest::newRow("subsequent 1,2") << emptyList << INT_LIST(1 << 2);
|
||||
QTest::newRow("subsequent 3,4") << emptyList << INT_LIST(3 << 4);
|
||||
|
||||
QTest::newRow("all but first") << emptyList << INT_LIST(1 << 2 << 3 << 4);
|
||||
QTest::newRow("all but last") << emptyList << INT_LIST(0 << 1 << 2 << 3);
|
||||
QTest::newRow("all but middle") << emptyList << INT_LIST(0 << 1 << 3 << 4);
|
||||
|
||||
// Hide both rows and columns at the same time
|
||||
QTest::newRow("first") << INT_LIST(0) << INT_LIST(0);
|
||||
QTest::newRow("middle 1") << INT_LIST(1) << INT_LIST(1);
|
||||
QTest::newRow("middle 3") << INT_LIST(3) << INT_LIST(3);
|
||||
QTest::newRow("last") << INT_LIST(4) << INT_LIST(4);
|
||||
|
||||
QTest::newRow("subsequent 0,1") << INT_LIST(0 << 1) << INT_LIST(0 << 1);
|
||||
QTest::newRow("subsequent 1,2") << INT_LIST(1 << 2) << INT_LIST(1 << 2);
|
||||
QTest::newRow("subsequent 3,4") << INT_LIST(3 << 4) << INT_LIST(3 << 4);
|
||||
|
||||
QTest::newRow("all but first") << INT_LIST(1 << 2 << 3 << 4) << INT_LIST(1 << 2 << 3 << 4);
|
||||
QTest::newRow("all but last") << INT_LIST(0 << 1 << 2 << 3) << INT_LIST(0 << 1 << 2 << 3);
|
||||
QTest::newRow("all but middle") << INT_LIST(0 << 1 << 3 << 4) << INT_LIST(0 << 1 << 3 << 4);
|
||||
|
||||
// Hide all rows and columns
|
||||
QTest::newRow("all") << INT_LIST(0 << 1 << 2 << 3 << 4) << INT_LIST(0 << 1 << 2 << 3 << 4);
|
||||
}
|
||||
|
||||
void tst_QQuickTableView::hideRowsAndColumns()
|
||||
{
|
||||
// Check that you can hide the first row (corner case)
|
||||
// and that we load the other columns as expected.
|
||||
QFETCH(QVariant, rowsToHide);
|
||||
QFETCH(QVariant, columnsToHide);
|
||||
LOAD_TABLEVIEW("hiderowsandcolumns.qml");
|
||||
|
||||
const QList<int> rowsToHideList = qvariant_cast<QList<int>>(rowsToHide);
|
||||
const QList<int> columnsToHideList = qvariant_cast<QList<int>>(columnsToHide);
|
||||
const int modelSize = 5;
|
||||
auto model = TestModelAsVariant(modelSize, modelSize);
|
||||
view->rootObject()->setProperty("rowsToHide", rowsToHide);
|
||||
view->rootObject()->setProperty("columnsToHide", columnsToHide);
|
||||
|
||||
tableView->setModel(model);
|
||||
|
||||
WAIT_UNTIL_POLISHED;
|
||||
|
||||
const int expectedRowCount = modelSize - rowsToHideList.count();
|
||||
const int expectedColumnCount = modelSize - columnsToHideList.count();
|
||||
QCOMPARE(tableViewPrivate->loadedRows.count(), expectedRowCount);
|
||||
QCOMPARE(tableViewPrivate->loadedColumns.count(), expectedColumnCount);
|
||||
|
||||
for (const int row : tableViewPrivate->loadedRows.keys())
|
||||
QVERIFY(!rowsToHideList.contains(row));
|
||||
|
||||
for (const int column : tableViewPrivate->loadedColumns.keys())
|
||||
QVERIFY(!columnsToHideList.contains(column));
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QQuickTableView)
|
||||
|
||||
#include "tst_qquicktableview.moc"
|
||||
|
|
Loading…
Reference in New Issue