aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Moe Gustavsen <richard.gustavsen@qt.io>2018-05-04 14:40:49 +0200
committerRichard Moe Gustavsen <richard.gustavsen@qt.io>2018-05-14 10:27:56 +0000
commitb7b49e32080572f8f669651adba88c66a00a2218 (patch)
tree21bcbd96037e4dbea54dddca750e199528861677
parentc487599cf21d95cef34b1c83550e09cead893d18 (diff)
TableView: add support for table margins
Instead of always drawing the table at 0,0 in the content view of the flickable, add support for setting margins. The margins will let the developer add some extra space around the table to e.g make space for custom headers etc. Change-Id: I4a69b2cf3594bd72255d21372b5bf0d3220676dc Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
-rw-r--r--src/quick/items/qquicktableview.cpp108
-rw-r--r--src/quick/items/qquicktableview_p.h20
-rw-r--r--src/quick/items/qquicktableview_p_p.h2
-rw-r--r--tests/auto/quick/qquicktableview/tst_qquicktableview.cpp96
4 files changed, 208 insertions, 18 deletions
diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp
index 860db13561..291a1a6497 100644
--- a/src/quick/items/qquicktableview.cpp
+++ b/src/quick/items/qquicktableview.cpp
@@ -173,6 +173,10 @@ void QQuickTableViewPrivate::updateContentWidth()
qreal averageSize = averageCellSize + cellSpacing.width();
qreal estimatedWith = (tableSize.width() * averageSize) - cellSpacing.width();
+ // loadedTableOuterRect has already been adjusted for left margin
+ currentWidth += tableMargins.right();
+ estimatedWith += tableMargins.right();
+
if (currentRightColumn >= tableSize.width() - 1) {
// We are at the last column, and can set the exact width
if (currentWidth != q->implicitWidth())
@@ -204,6 +208,10 @@ void QQuickTableViewPrivate::updateContentHeight()
qreal averageSize = averageCellSize + cellSpacing.height();
qreal estimatedHeight = (tableSize.height() * averageSize) - cellSpacing.height();
+ // loadedTableOuterRect has already been adjusted for top margin
+ currentHeight += tableMargins.bottom();
+ estimatedHeight += tableMargins.bottom();
+
if (currentBottomRow >= tableSize.height() - 1) {
// We are at the last row, and can set the exact height
if (currentHeight != q->implicitHeight())
@@ -229,23 +237,23 @@ void QQuickTableViewPrivate::enforceFirstRowColumnAtOrigo()
bool layoutNeeded = false;
const qreal flickMargin = 50;
- if (loadedTable.x() == 0 && loadedTableOuterRect.x() != 0) {
+ if (loadedTable.x() == 0 && loadedTableOuterRect.x() != tableMargins.left()) {
// The table is at the beginning, but not at the edge of the
// content view. So move the table to origo.
- loadedTableOuterRect.moveLeft(0);
+ loadedTableOuterRect.moveLeft(tableMargins.left());
layoutNeeded = true;
} else if (loadedTableOuterRect.x() < 0) {
// The table is outside the beginning of the content view. Move
// the whole table inside, and make some room for flicking.
- loadedTableOuterRect.moveLeft(loadedTable.x() == 0 ? 0 : flickMargin);
+ loadedTableOuterRect.moveLeft(tableMargins.left() + loadedTable.x() == 0 ? 0 : flickMargin);
layoutNeeded = true;
}
- if (loadedTable.y() == 0 && loadedTableOuterRect.y() != 0) {
- loadedTableOuterRect.moveTop(0);
+ if (loadedTable.y() == 0 && loadedTableOuterRect.y() != tableMargins.top()) {
+ loadedTableOuterRect.moveTop(tableMargins.top());
layoutNeeded = true;
} else if (loadedTableOuterRect.y() < 0) {
- loadedTableOuterRect.moveTop(loadedTable.y() == 0 ? 0 : flickMargin);
+ loadedTableOuterRect.moveTop(tableMargins.top() + loadedTable.y() == 0 ? 0 : flickMargin);
layoutNeeded = true;
}
@@ -815,6 +823,16 @@ void QQuickTableViewPrivate::layoutHorizontalEdge(Qt::Edge tableEdge, bool adjus
}
}
+void QQuickTableViewPrivate::layoutTopLeftItem()
+{
+ // ###todo: support starting with other top-left items than 0,0
+ Q_TABLEVIEW_ASSERT(loadRequest.firstCell() == QPoint(0, 0), loadRequest.toString());
+ auto topLeftItem = loadedTableItem(QPoint(0, 0));
+ topLeftItem->item->setPosition(QPoint(tableMargins.left(), tableMargins.top()));
+ topLeftItem->setVisible(true);
+ qCDebug(lcTableViewDelegateLifecycle) << "geometry:" << topLeftItem->geometry();
+}
+
void QQuickTableViewPrivate::layoutTableEdgeFromLoadRequest()
{
// If tableRebuilding is true, we avoid adjusting cell sizes until all items
@@ -837,11 +855,7 @@ void QQuickTableViewPrivate::layoutTableEdgeFromLoadRequest()
layoutHorizontalEdge(loadRequest.edge(), adjustSize);
break;
default:
- // Request loaded top-left item rather than an edge.
- // ###todo: support starting with other top-left items than 0,0
- Q_TABLEVIEW_ASSERT(loadRequest.firstCell() == QPoint(0, 0), loadRequest.toString());
- loadedTableItem(QPoint(0, 0))->setVisible(true);
- qCDebug(lcTableViewDelegateLifecycle) << "top-left item geometry:" << loadedTableItem(QPoint(0, 0))->geometry();
+ layoutTopLeftItem();
break;
}
}
@@ -1201,6 +1215,78 @@ void QQuickTableView::setColumnSpacing(qreal spacing)
emit columnSpacingChanged();
}
+qreal QQuickTableView::topMargin() const
+{
+ return d_func()->tableMargins.top();
+}
+
+void QQuickTableView::setTopMargin(qreal margin)
+{
+ Q_D(QQuickTableView);
+ if (qt_is_nan(margin))
+ return;
+ if (qFuzzyCompare(d->tableMargins.top(), margin))
+ return;
+
+ d->tableMargins.setTop(margin);
+ d->invalidateColumnRowPositions();
+ emit topMarginChanged();
+}
+
+qreal QQuickTableView::bottomMargin() const
+{
+ return d_func()->tableMargins.bottom();
+}
+
+void QQuickTableView::setBottomMargin(qreal margin)
+{
+ Q_D(QQuickTableView);
+ if (qt_is_nan(margin))
+ return;
+ if (qFuzzyCompare(d->tableMargins.bottom(), margin))
+ return;
+
+ d->tableMargins.setBottom(margin);
+ d->invalidateColumnRowPositions();
+ emit bottomMarginChanged();
+}
+
+qreal QQuickTableView::leftMargin() const
+{
+ return d_func()->tableMargins.left();
+}
+
+void QQuickTableView::setLeftMargin(qreal margin)
+{
+ Q_D(QQuickTableView);
+ if (qt_is_nan(margin))
+ return;
+ if (qFuzzyCompare(d->tableMargins.left(), margin))
+ return;
+
+ d->tableMargins.setLeft(margin);
+ d->invalidateColumnRowPositions();
+ emit leftMarginChanged();
+}
+
+qreal QQuickTableView::rightMargin() const
+{
+ return d_func()->tableMargins.right();
+}
+
+void QQuickTableView::setRightMargin(qreal margin)
+{
+ Q_D(QQuickTableView);
+ if (qt_is_nan(margin))
+ return;
+ if (qFuzzyCompare(d->tableMargins.right(), margin))
+ return;
+
+ d->tableMargins.setRight(margin);
+ d->invalidateColumnRowPositions();
+ emit rightMarginChanged();
+}
+
int QQuickTableView::cacheBuffer() const
{
return d_func()->cacheBuffer;
diff --git a/src/quick/items/qquicktableview_p.h b/src/quick/items/qquicktableview_p.h
index 13c164bd11..8cc5800d7e 100644
--- a/src/quick/items/qquicktableview_p.h
+++ b/src/quick/items/qquicktableview_p.h
@@ -69,6 +69,10 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTableView : public QQuickFlickable
Q_PROPERTY(int columns READ columns NOTIFY columnsChanged)
Q_PROPERTY(qreal rowSpacing READ rowSpacing WRITE setRowSpacing NOTIFY rowSpacingChanged)
Q_PROPERTY(qreal columnSpacing READ columnSpacing WRITE setColumnSpacing NOTIFY columnSpacingChanged)
+ Q_PROPERTY(qreal topMargin READ topMargin WRITE setTopMargin NOTIFY topMarginChanged)
+ Q_PROPERTY(qreal bottomMargin READ bottomMargin WRITE setBottomMargin NOTIFY bottomMarginChanged)
+ Q_PROPERTY(qreal leftMargin READ leftMargin WRITE setLeftMargin NOTIFY leftMarginChanged)
+ Q_PROPERTY(qreal rightMargin READ rightMargin WRITE setRightMargin NOTIFY rightMarginChanged)
Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged)
Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged)
@@ -86,6 +90,18 @@ public:
qreal columnSpacing() const;
void setColumnSpacing(qreal spacing);
+ qreal topMargin() const;
+ void setTopMargin(qreal margin);
+
+ qreal bottomMargin() const;
+ void setBottomMargin(qreal margin);
+
+ qreal leftMargin() const;
+ void setLeftMargin(qreal margin);
+
+ qreal rightMargin() const;
+ void setRightMargin(qreal margin);
+
int cacheBuffer() const;
void setCacheBuffer(int newBuffer);
@@ -102,6 +118,10 @@ Q_SIGNALS:
void columnsChanged();
void rowSpacingChanged();
void columnSpacingChanged();
+ void topMarginChanged();
+ void bottomMarginChanged();
+ void leftMarginChanged();
+ void rightMarginChanged();
void cacheBufferChanged();
void modelChanged();
void delegateChanged();
diff --git a/src/quick/items/qquicktableview_p_p.h b/src/quick/items/qquicktableview_p_p.h
index 906c705850..61daaec385 100644
--- a/src/quick/items/qquicktableview_p_p.h
+++ b/src/quick/items/qquicktableview_p_p.h
@@ -202,6 +202,7 @@ public:
QPoint contentSizeBenchMarkPoint = QPoint(-1, -1);
QSizeF cellSpacing;
+ QMarginsF tableMargins;
int cacheBuffer = kDefaultCacheBuffer;
QTimer cacheBufferDelayTimer;
@@ -246,6 +247,7 @@ public:
void layoutVerticalEdge(Qt::Edge tableEdge, bool adjustSize);
void layoutHorizontalEdge(Qt::Edge tableEdge, bool adjustSize);
+ void layoutTopLeftItem();
void layoutTableEdgeFromLoadRequest();
void updateContentWidth();
diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
index 35efd6a40b..ad48283e1d 100644
--- a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
+++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
@@ -52,6 +52,8 @@ using namespace QQuickVisualTestUtil;
static const char* kTableViewPropName = "tableView";
static const char* kDelegateObjectName = "tableViewDelegate";
+Q_DECLARE_METATYPE(QMarginsF);
+
#define LOAD_TABLEVIEW(fileName) \
QScopedPointer<QQuickView> view(createView()); \
view->setSource(testFileUrl(fileName)); \
@@ -73,6 +75,7 @@ public:
tst_QQuickTableView();
QQuickTableViewAttached *getAttachedObject(const QObject *object) const;
+ FxTableItem *findFxTableItem(int row, int column, const QList<FxTableItem *> items) const;
private slots:
void initTestCase() override;
@@ -85,6 +88,8 @@ private slots:
void countDelegateItems();
void checkLayoutOfEqualSizedDelegateItems_data();
void checkLayoutOfEqualSizedDelegateItems();
+ void checkTableMargins_data();
+ void checkTableMargins();
};
tst_QQuickTableView::tst_QQuickTableView()
@@ -103,6 +108,17 @@ QQuickTableViewAttached *tst_QQuickTableView::getAttachedObject(const QObject *o
return static_cast<QQuickTableViewAttached *>(attachedObject);
}
+FxTableItem *tst_QQuickTableView::findFxTableItem(int row, int column, const QList<FxTableItem *> items) const
+{
+ for (int i = 0; i < items.count(); ++i) {
+ FxTableItem *fxitem = items[i];
+ auto attached = getAttachedObject(fxitem->item);
+ if (row == attached->row() && column == attached->column())
+ return fxitem;
+ }
+ return nullptr;
+}
+
void tst_QQuickTableView::setAndGetModel_data()
{
QTest::addColumn<QVariant>("model");
@@ -187,11 +203,18 @@ void tst_QQuickTableView::checkLayoutOfEqualSizedDelegateItems_data()
QTest::addColumn<QVariant>("model");
QTest::addColumn<QSize>("tableSize");
QTest::addColumn<QSizeF>("spacing");
-
- QTest::newRow("QAIM 1x1 1,1") << TestModelAsVariant(1, 1) << QSize(1, 1) << QSizeF(1, 1);
- QTest::newRow("QAIM 5x5 0,0") << TestModelAsVariant(5, 5) << QSize(5, 5) << QSizeF(0, 0);
- QTest::newRow("QAIM 5x5 1,0") << TestModelAsVariant(5, 5) << QSize(5, 5) << QSizeF(1, 0);
- QTest::newRow("QAIM 5x5 0,1") << TestModelAsVariant(5, 5) << QSize(5, 5) << QSizeF(0, 1);
+ QTest::addColumn<QMarginsF>("margins");
+
+ // Check spacing together with different table setups
+ QTest::newRow("QAIM 1x1 1,1") << TestModelAsVariant(1, 1) << QSize(1, 1) << QSizeF(1, 1) << QMarginsF(0, 0, 0, 0);
+ QTest::newRow("QAIM 5x5 0,0") << TestModelAsVariant(5, 5) << QSize(5, 5) << QSizeF(0, 0) << QMarginsF(0, 0, 0, 0);
+ QTest::newRow("QAIM 5x5 1,0") << TestModelAsVariant(5, 5) << QSize(5, 5) << QSizeF(1, 0) << QMarginsF(0, 0, 0, 0);
+ QTest::newRow("QAIM 5x5 0,1") << TestModelAsVariant(5, 5) << QSize(5, 5) << QSizeF(0, 1) << QMarginsF(0, 0, 0, 0);
+
+ // Check spacing together with margins
+ QTest::newRow("QAIM 1x1 1,1 5555") << TestModelAsVariant(1, 1) << QSize(1, 1) << QSizeF(1, 1) << QMarginsF(5, 5, 5, 5);
+ QTest::newRow("QAIM 4x4 0,0 3333") << TestModelAsVariant(4, 4) << QSize(4, 4) << QSizeF(0, 0) << QMarginsF(3, 3, 3, 3);
+ QTest::newRow("QAIM 4x4 2,2 1234") << TestModelAsVariant(4, 4) << QSize(4, 4) << QSizeF(2, 2) << QMarginsF(1, 2, 3, 4);
}
void tst_QQuickTableView::checkLayoutOfEqualSizedDelegateItems()
@@ -200,11 +223,16 @@ void tst_QQuickTableView::checkLayoutOfEqualSizedDelegateItems()
QFETCH(QVariant, model);
QFETCH(QSize, tableSize);
QFETCH(QSizeF, spacing);
+ QFETCH(QMarginsF, margins);
LOAD_TABLEVIEW("plaintableview.qml");
tableView->setModel(model);
tableView->setRowSpacing(spacing.height());
tableView->setColumnSpacing(spacing.width());
+ tableView->setLeftMargin(margins.left());
+ tableView->setTopMargin(margins.top());
+ tableView->setRightMargin(margins.right());
+ tableView->setBottomMargin(margins.bottom());
WAIT_UNTIL_POLISHED;
@@ -224,8 +252,8 @@ void tst_QQuickTableView::checkLayoutOfEqualSizedDelegateItems()
auto attached = getAttachedObject(item);
int row = attached->row();
int column = attached->column();
- qreal expectedX = column * (expectedWidth + spacing.width());
- qreal expectedY = row * (expectedHeight + spacing.height());
+ qreal expectedX = margins.left() + (column * (expectedWidth + spacing.width()));
+ qreal expectedY = margins.top() + (row * (expectedHeight + spacing.height()));
QCOMPARE(item->x(), expectedX);
QCOMPARE(item->y(), expectedY);
QCOMPARE(item->width(), expectedWidth);
@@ -233,6 +261,60 @@ void tst_QQuickTableView::checkLayoutOfEqualSizedDelegateItems()
}
}
+void tst_QQuickTableView::checkTableMargins_data()
+{
+ QTest::addColumn<QVariant>("model");
+ QTest::addColumn<QSize>("tableSize");
+ QTest::addColumn<QSizeF>("spacing");
+ QTest::addColumn<QMarginsF>("margins");
+
+ QTest::newRow("QAIM 1x1 1,1 0000") << TestModelAsVariant(1, 1) << QSize(1, 1) << QSizeF(1, 1) << QMarginsF(0, 0, 0, 0);
+ QTest::newRow("QAIM 4x4 1,1 0000") << TestModelAsVariant(4, 4) << QSize(4, 4) << QSizeF(1, 1) << QMarginsF(0, 0, 0, 0);
+ QTest::newRow("QAIM 1x1 1,1 5555") << TestModelAsVariant(1, 1) << QSize(1, 1) << QSizeF(1, 1) << QMarginsF(5, 5, 5, 5);
+ QTest::newRow("QAIM 4x4 0,0 3333") << TestModelAsVariant(4, 4) << QSize(4, 4) << QSizeF(0, 0) << QMarginsF(3, 3, 3, 3);
+ QTest::newRow("QAIM 4x4 2,2 1234") << TestModelAsVariant(4, 4) << QSize(4, 4) << QSizeF(2, 2) << QMarginsF(1, 2, 3, 4);
+ QTest::newRow("QAIM 1x1 0,0 3210") << TestModelAsVariant(1, 1) << QSize(1, 1) << QSizeF(0, 0) << QMarginsF(3, 2, 1, 0);
+}
+
+void tst_QQuickTableView::checkTableMargins()
+{
+ // Check that the space between the content view and
+ // the items matches the margins we set on the tableview.
+ QFETCH(QVariant, model);
+ QFETCH(QSize, tableSize);
+ QFETCH(QSizeF, spacing);
+ QFETCH(QMarginsF, margins);
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ tableView->setModel(model);
+ tableView->setRowSpacing(spacing.height());
+ tableView->setColumnSpacing(spacing.width());
+ tableView->setLeftMargin(margins.left());
+ tableView->setTopMargin(margins.top());
+ tableView->setRightMargin(margins.right());
+ tableView->setBottomMargin(margins.bottom());
+
+ WAIT_UNTIL_POLISHED;
+
+ auto const items = tableViewPrivate->loadedItems;
+
+ auto const topLeftFxItem = findFxTableItem(0, 0, items);
+ auto const bottomRightFxItem = findFxTableItem(tableSize.height() - 1, tableSize.width() - 1, items);
+ QVERIFY(topLeftFxItem);
+ QVERIFY(bottomRightFxItem);
+
+ auto const topLeftItem = topLeftFxItem->item;
+ auto const bottomRightItem = bottomRightFxItem->item;
+ qreal leftSpace = topLeftItem->x();
+ qreal topSpace = topLeftItem->y();
+ qreal rightSpace = tableView->contentWidth() - (bottomRightItem->x() + bottomRightItem->width());
+ qreal bottomSpace = tableView->contentHeight() - (bottomRightItem->y() + bottomRightItem->height());
+ QCOMPARE(leftSpace, margins.left());
+ QCOMPARE(topSpace, margins.top());
+ QCOMPARE(rightSpace, margins.right());
+ QCOMPARE(bottomSpace, margins.bottom());
+}
+
QTEST_MAIN(tst_QQuickTableView)
#include "tst_qquicktableview.moc"