aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Moe Gustavsen <richard.gustavsen@qt.io>2018-08-09 09:15:08 +0200
committerRichard Moe Gustavsen <richard.gustavsen@qt.io>2018-08-09 16:20:56 +0000
commit1d6dcee6cc75b65092715acc59d4481a2dfeb5ec (patch)
tree85702162a38b943ef390555a73e63d4e5ebf7e0c
parent82da798499aa8b656e771191332864a703069739 (diff)
QQuickTableView: override contentWidth/Height properties
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 are loaded into view. At the same time, we want to open up for the possibility that the application can set the content width explicitly, in case it knows what the exact width should be from the start. We therefore override the contentWidth/height properties from QQuickFlickable, to be able to implement this combined behavior. This also lets us lazy build the table if the application needs to know the content size early on. The latter will also fix problems related to querying the content size from Component.onCompleted. Change-Id: Ife7ef551dc46cf15d6940e3c6dff78545a3e4330 Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
-rw-r--r--src/quick/items/qquicktableview.cpp81
-rw-r--r--src/quick/items/qquicktableview_p.h9
-rw-r--r--src/quick/items/qquicktableview_p_p.h14
-rw-r--r--tests/auto/quick/qquicktableview/tst_qquicktableview.cpp19
4 files changed, 117 insertions, 6 deletions
diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp
index 23f6e79049..74db76c198 100644
--- a/src/quick/items/qquicktableview.cpp
+++ b/src/quick/items/qquicktableview.cpp
@@ -168,6 +168,12 @@ void QQuickTableViewPrivate::updateContentWidth()
{
Q_Q(QQuickTableView);
+ if (explicitContentWidth.isValid()) {
+ // Don't calculate contentWidth when it
+ // was set explicitly by the application.
+ return;
+ }
+
const qreal thresholdBeforeAdjust = 0.1;
int currentRightColumn = loadedTable.right();
@@ -203,6 +209,12 @@ void QQuickTableViewPrivate::updateContentHeight()
{
Q_Q(QQuickTableView);
+ if (explicitContentHeight.isValid()) {
+ // Don't calculate contentHeight when it
+ // was set explicitly by the application.
+ return;
+ }
+
const qreal thresholdBeforeAdjust = 0.1;
int currentBottomRow = loadedTable.bottom();
@@ -860,8 +872,6 @@ void QQuickTableViewPrivate::beginRebuildTable()
loadedTableInnerRect = QRect();
contentSizeBenchMarkPoint = QPoint(-1, -1);
- q->setContentWidth(0);
- q->setContentHeight(0);
q->setContentX(0);
q->setContentY(0);
@@ -1291,9 +1301,23 @@ void QQuickTableViewPrivate::modelResetCallback()
invalidateTable();
}
+bool QQuickTableViewPrivate::updatePolishIfPossible() const
+{
+ if (polishing || !q_func()->isComponentComplete()) {
+ // We shouldn't recurse into updatePolish(). And we shouldn't
+ // build the table before the component is complete.
+ return false;
+ }
+
+ const_cast<QQuickTableViewPrivate *>(this)->updatePolish();
+ return true;
+}
+
QQuickTableView::QQuickTableView(QQuickItem *parent)
: QQuickFlickable(*(new QQuickTableViewPrivate), parent)
{
+ connect(this, &QQuickFlickable::contentWidthChanged, this, &QQuickTableView::contentWidthOverrideChanged);
+ connect(this, &QQuickFlickable::contentHeightChanged, this, &QQuickTableView::contentHeightOverrideChanged);
}
int QQuickTableView::rows() const
@@ -1542,6 +1566,54 @@ void QQuickTableView::setReuseItems(bool reuse)
emit reuseItemsChanged();
}
+qreal QQuickTableView::explicitContentWidth() const
+{
+ Q_D(const QQuickTableView);
+
+ if (d->tableInvalid && 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.
+ d->updatePolishIfPossible();
+ }
+
+ return contentWidth();
+}
+
+void QQuickTableView::setExplicitContentWidth(qreal width)
+{
+ Q_D(QQuickTableView);
+ d->explicitContentWidth = width;
+ if (width == contentWidth())
+ return;
+
+ setContentWidth(width);
+}
+
+qreal QQuickTableView::explicitContentHeight() const
+{
+ Q_D(const QQuickTableView);
+
+ if (d->tableInvalid && 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.
+ d->updatePolishIfPossible();
+ }
+
+ return contentHeight();
+}
+
+void QQuickTableView::setExplicitContentHeight(qreal height)
+{
+ Q_D(QQuickTableView);
+ d->explicitContentHeight = height;
+ if (height == contentHeight())
+ return;
+
+ setContentHeight(height);
+}
+
QQuickTableViewAttached *QQuickTableView::qmlAttachedProperties(QObject *obj)
{
return new QQuickTableViewAttached(obj);
@@ -1563,7 +1635,6 @@ void QQuickTableView::geometryChanged(const QRectF &newGeometry, const QRectF &o
void QQuickTableView::viewportMoved(Qt::Orientations orientation)
{
- Q_D(QQuickTableView);
QQuickFlickable::viewportMoved(orientation);
// Calling polish() will schedule a polish event. But while the user is flicking, several
@@ -1573,9 +1644,7 @@ void QQuickTableView::viewportMoved(Qt::Orientations orientation)
// has the pitfall that we open up for recursive callbacks. E.g while inside updatePolish(), we
// load/unload items, and emit signals. The application can listen to those signals and set a
// new contentX/Y on the flickable. So we need to guard for this, to avoid unexpected behavior.
- if (!d->polishing)
- d->updatePolish();
- else
+ if (!d_func()->updatePolishIfPossible())
polish();
}
diff --git a/src/quick/items/qquicktableview_p.h b/src/quick/items/qquicktableview_p.h
index fa7561554e..513e644e43 100644
--- a/src/quick/items/qquicktableview_p.h
+++ b/src/quick/items/qquicktableview_p.h
@@ -79,6 +79,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTableView : public QQuickFlickable
Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged)
Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
Q_PROPERTY(bool reuseItems READ reuseItems WRITE setReuseItems NOTIFY reuseItemsChanged)
+ Q_PROPERTY(qreal contentWidth READ explicitContentWidth WRITE setExplicitContentWidth NOTIFY contentWidthOverrideChanged)
+ Q_PROPERTY(qreal contentHeight READ explicitContentHeight WRITE setExplicitContentWidth NOTIFY contentHeightOverrideChanged)
public:
QQuickTableView(QQuickItem *parent = nullptr);
@@ -122,6 +124,11 @@ public:
bool reuseItems() const;
void setReuseItems(bool reuseItems);
+ qreal explicitContentWidth() const;
+ void setExplicitContentWidth(qreal width);
+ qreal explicitContentHeight() const;
+ void setExplicitContentHeight(qreal height);
+
static QQuickTableViewAttached *qmlAttachedProperties(QObject *);
Q_SIGNALS:
@@ -139,6 +146,8 @@ Q_SIGNALS:
void modelChanged();
void delegateChanged();
void reuseItemsChanged();
+ void contentWidthOverrideChanged();
+ void contentHeightOverrideChanged();
protected:
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
diff --git a/src/quick/items/qquicktableview_p_p.h b/src/quick/items/qquicktableview_p_p.h
index e6e40e1bae..26b391818c 100644
--- a/src/quick/items/qquicktableview_p_p.h
+++ b/src/quick/items/qquicktableview_p_p.h
@@ -219,6 +219,18 @@ public:
QJSValue rowHeightProvider;
QJSValue columnWidthProvider;
+ // 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
+ // are loaded into view. At the same time, we want to open up for the
+ // possibility that the application can set the content width explicitly, in
+ // case it knows what the exact width should be from the start. We therefore
+ // override the contentWidth/height properties from QQuickFlickable, to be able
+ // to implement this combined behavior. This also lets us lazy build the table
+ // if the application needs to know the content size early on.
+ QQmlNullableValue<qreal> explicitContentWidth;
+ QQmlNullableValue<qreal> explicitContentHeight;
+
const static QPoint kLeft;
const static QPoint kRight;
const static QPoint kUp;
@@ -311,6 +323,8 @@ public:
void columnsRemovedCallback(const QModelIndex &parent, int begin, int end);
void modelResetCallback();
+ bool updatePolishIfPossible() const;
+
inline QString tableLayoutToString() const;
void dumpTable() const;
};
diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
index 94d3a356fe..b2f4e412f1 100644
--- a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
+++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
@@ -96,6 +96,7 @@ private slots:
void checkRowHeightProviderInvalidReturnValues();
void checkRowHeightProviderNotCallable();
void checkContentWidthAndHeight();
+ void checkExplicitContentWidthAndHeight();
void noDelegate();
void countDelegateItems_data();
void countDelegateItems();
@@ -481,6 +482,24 @@ void tst_QQuickTableView::checkContentWidthAndHeight()
QCOMPARE(tableView->contentHeight(), expectedFullSize);
}
+void tst_QQuickTableView::checkExplicitContentWidthAndHeight()
+{
+ // Check that you can set a custom contentWidth/Height, and that
+ // TableView doesn't override it while loading more rows and columns.
+ LOAD_TABLEVIEW("contentwidthheight.qml");
+
+ tableView->setContentWidth(1000);
+ tableView->setContentHeight(1000);
+ QCOMPARE(tableView->contentWidth(), 1000);
+ QCOMPARE(tableView->contentHeight(), 1000);
+
+ // Flick somewhere. It should not affect the contentWidth/Height
+ tableView->setContentX(500);
+ tableView->setContentY(500);
+ QCOMPARE(tableView->contentWidth(), 1000);
+ QCOMPARE(tableView->contentHeight(), 1000);
+}
+
void tst_QQuickTableView::noDelegate()
{
// Check that you can skip setting a delegate without