diff options
author | Leander Beernaert <leander.beernaert@qt.io> | 2020-01-16 16:25:06 +0100 |
---|---|---|
committer | Leander Beernaert <leander.beernaert@qt.io> | 2020-01-16 16:25:06 +0100 |
commit | 1d333d3375874efb8d37df37dc5ef561573794ad (patch) | |
tree | 2d8c995f64c05c84c1fcceb2c5cb40fcae69855f /tests/auto/quick/qquicktableview | |
parent | b106d86c433706928b0b0c206a0d9f831681e1bf (diff) | |
parent | e79a2658cde899d6ee11ec3c0d0a3768eb2c864b (diff) |
Merge remote-tracking branch 'origin/dev' into wip/cmake
Change-Id: I0c5b939c70bdb91ccdf7068784308416dcaa5736
Diffstat (limited to 'tests/auto/quick/qquicktableview')
5 files changed, 287 insertions, 5 deletions
diff --git a/tests/auto/quick/qquicktableview/data/checkalwaysemit.qml b/tests/auto/quick/qquicktableview/data/checkalwaysemit.qml new file mode 100644 index 0000000000..33db6f6d02 --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/checkalwaysemit.qml @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 real delegateWidth: 100 + property real delegateHeight: 50 + property Component delegate: tableViewDelegate + property bool delegateParentSetBeforeCompleted: false + + TableView { + id: tableView + width: 600 + height: 400 + anchors.margins: 1 + clip: true + delegate: tableViewDelegate + columnSpacing: 1 + rowSpacing: 1 + } + + Component { + id: tableViewDelegate + Rectangle { + objectName: "tableViewDelegate" + implicitWidth: delegateWidth + implicitHeight: delegateHeight + color: "lightgray" + border.width: 1 + + property string modelDataFromIndex: tableView.model.dataFromSerializedIndex(index) + property string modelDataBinding: modelData + + Text { + anchors.centerIn: parent + text: modelData + } + + Component.onCompleted: { + delegateParentSetBeforeCompleted = parent != null; + } + } + } + +} diff --git a/tests/auto/quick/qquicktableview/data/replaceModelTableView.qml b/tests/auto/quick/qquicktableview/data/replaceModelTableView.qml new file mode 100644 index 0000000000..cc109bb469 --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/replaceModelTableView.qml @@ -0,0 +1,56 @@ +import QtQuick 2.14 +import QtQml.Models 2.14 + +Item { + id: root + visible: true + width: 640 + height: 480 + + property alias tableView: tv + property alias objectModel: om + property alias listModel: lm + property alias delegateModel: dm + + ObjectModel { + id: om + Rectangle { implicitHeight: 30; implicitWidth: 80; color: "red" } + Rectangle { implicitHeight: 30; implicitWidth: 80; color: "green" } + Rectangle { implicitHeight: 30; implicitWidth: 80; color: "blue" } + } + + ListModel { + id: lm + ListElement { name: "1" } + ListElement { name: "44"} + } + + DelegateModel { + id: dm + model: ListModel { + ListElement { name: "Apple" } + ListElement { name: "Orange" } + } + delegate: Rectangle { + implicitHeight: 25 + implicitWidth: 100 + Text { text: "Name: " + name} + } + } + TableView { + id: tv + visible: true + anchors.fill: parent + + delegate: Rectangle { + id: dlg + implicitWidth: 40 + implicitHeight: 20 + color: "red" + Text { + text: qsTr("name: " + name) + } + border.color: "green" + } + } +} diff --git a/tests/auto/quick/qquicktableview/qquicktableview.pro b/tests/auto/quick/qquicktableview/qquicktableview.pro index da0c0b01d0..735c728fc6 100644 --- a/tests/auto/quick/qquicktableview/qquicktableview.pro +++ b/tests/auto/quick/qquicktableview/qquicktableview.pro @@ -13,3 +13,5 @@ TESTDATA = data/* QT += core-private gui-private qml-private quick-private testlib qmlmodels-private +DISTFILES += + diff --git a/tests/auto/quick/qquicktableview/testmodel.h b/tests/auto/quick/qquicktableview/testmodel.h index 50f434019e..2697b1e801 100644 --- a/tests/auto/quick/qquicktableview/testmodel.h +++ b/tests/auto/quick/qquicktableview/testmodel.h @@ -46,6 +46,13 @@ public: , m_columns(columns) {} + TestModel(int rows, int columns, bool dataCanBeFetched, QObject *parent = nullptr) + : QAbstractTableModel(parent) + , m_rows(rows) + , m_columns(columns) + , m_dataCanBeFetched(dataCanBeFetched) + {} + int rowCount(const QModelIndex & = QModelIndex()) const override { return m_rows; } void setRowCount(int count) { beginResetModel(); m_rows = count; emit rowCountChanged(); endResetModel(); } @@ -63,6 +70,13 @@ public: return QStringLiteral("%1").arg(index.row()); } + Q_INVOKABLE QVariant dataFromSerializedIndex(int index) const + { + if (modelData.contains(index)) + return modelData.value(index); + return QString(); + } + QHash<int, QByteArray> roleNames() const override { return { {Qt::DisplayRole, "display"} }; @@ -102,6 +116,12 @@ public: beginRemoveRows(parent, row, row + count - 1); m_rows -= count; + for (int c = 0; c < m_columns; ++c) { + for (int r = 0; r < count; ++r) { + const int serializedIndex = (row + r) + (c * m_rows); + modelData.remove(serializedIndex); + } + } endRemoveRows(); return true; } @@ -128,6 +148,12 @@ public: return true; } + bool canFetchMore(const QModelIndex &parent) const override + { + Q_UNUSED(parent) + return m_dataCanBeFetched; + } + void swapRows(int row1, int row2) { layoutAboutToBeChanged(); @@ -139,6 +165,12 @@ public: layoutChanged(); } + void fetchMore(const QModelIndex &parent) override + { + Q_UNUSED(parent) + addRow(m_rows - 1); + } + void clear() { beginResetModel(); m_rows = 0; @@ -159,6 +191,7 @@ signals: private: int m_rows = 0; int m_columns = 0; + bool m_dataCanBeFetched = false; QHash<int, QString> modelData; }; diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp index 230dcc9446..ef39a91a65 100644 --- a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp +++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp @@ -60,7 +60,7 @@ Q_DECLARE_METATYPE(QMarginsF); auto PROPNAME = view->rootObject()->property(#PROPNAME).value<QQuickTableView *>(); \ QVERIFY(PROPNAME); \ auto PROPNAME ## Private = QQuickTableViewPrivate::get(PROPNAME); \ - Q_UNUSED(PROPNAME ## Private) + Q_UNUSED(PROPNAME ## Private) void() #define LOAD_TABLEVIEW(fileName) \ view->setSource(testFileUrl(fileName)); \ @@ -120,6 +120,7 @@ private slots: void checkRowHeightProviderNotCallable(); void checkForceLayoutFunction(); void checkForceLayoutEndUpDoingALayout(); + void checkForceLayoutDuringModelChange(); void checkContentWidthAndHeight(); void checkPageFlicking(); void checkExplicitContentWidthAndHeight(); @@ -159,6 +160,7 @@ private slots: void checkContextPropertiesQQmlListProperyModel_data(); void checkContextPropertiesQQmlListProperyModel(); void checkRowAndColumnChangedButNotIndex(); + void checkThatWeAlwaysEmitChangedUponItemReused(); void checkChangingModelFromDelegate(); void checkRebuildViewportOnly(); void useDelegateChooserWithoutDefault(); @@ -174,6 +176,8 @@ private slots: void checkSyncView_connect_late_data(); void checkSyncView_connect_late(); void delegateWithRequiredProperties(); + void checkThatFetchMoreIsCalledWhenScrolledToTheEndOfTable(); + void replaceModel(); }; tst_QQuickTableView::tst_QQuickTableView() @@ -390,7 +394,7 @@ void tst_QQuickTableView::checkColumnWidthProviderInvalidReturnValues() tableView->setModel(model); - QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*implicitHeight.*zero")); + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*implicit.*zero")); WAIT_UNTIL_POLISHED; @@ -487,7 +491,7 @@ void tst_QQuickTableView::checkRowHeightProviderInvalidReturnValues() tableView->setModel(model); - QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*implicitHeight.*zero")); + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*implicit.*zero")); WAIT_UNTIL_POLISHED; @@ -588,6 +592,29 @@ void tst_QQuickTableView::checkForceLayoutEndUpDoingALayout() QCOMPARE(fxItem->item->height(), newDelegateSize); } +void tst_QQuickTableView::checkForceLayoutDuringModelChange() +{ + // Check that TableView doesn't assert if we call + // forceLayout() in the middle of a model change. + LOAD_TABLEVIEW("plaintableview.qml"); + + const int initialRowCount = 10; + TestModel model(initialRowCount, 10); + tableView->setModel(QVariant::fromValue(&model)); + + connect(&model, &QAbstractItemModel::rowsInserted, [=](){ + QCOMPARE(tableView->rows(), initialRowCount); + tableView->forceLayout(); + QCOMPARE(tableView->rows(), initialRowCount + 1); + }); + + WAIT_UNTIL_POLISHED; + + QCOMPARE(tableView->rows(), initialRowCount); + model.addRow(0); + QCOMPARE(tableView->rows(), initialRowCount + 1); +} + void tst_QQuickTableView::checkContentWidthAndHeight() { // Check that contentWidth/Height reports the correct size of the @@ -2060,6 +2087,41 @@ void tst_QQuickTableView::checkRowAndColumnChangedButNotIndex() QCOMPARE(contextColumn, 1); } +void tst_QQuickTableView::checkThatWeAlwaysEmitChangedUponItemReused() +{ + // Check that we always emit changes to index when we reuse an item, even + // if it doesn't change. This is needed since the model can have changed + // row or column count while the item was in the pool, which means that + // any data referred to by the index property inside the delegate + // will change too. So we need to refresh any bindings to index. + // QTBUG-79209 + LOAD_TABLEVIEW("checkalwaysemit.qml"); + + TestModel model(1, 1); + tableView->setModel(QVariant::fromValue(&model)); + model.setModelData(QPoint(0, 0), QSize(1, 1), "old value"); + + WAIT_UNTIL_POLISHED; + + const auto reuseItem = tableViewPrivate->loadedTableItem(QPoint(0, 0))->item; + const auto context = qmlContext(reuseItem.data()); + + // Remove the cell/row that has "old value" as model data, and + // add a new one right after. The new cell will have the same + // index, but with no model data assigned. + // This change will not be detected by items in the pool. But since + // we emit indexChanged when the item is reused, it will be updated then. + model.removeRow(0); + model.insertRow(0); + + WAIT_UNTIL_POLISHED; + + QCOMPARE(context->contextProperty("index").toInt(), 0); + QCOMPARE(context->contextProperty("row").toInt(), 0); + QCOMPARE(context->contextProperty("column").toInt(), 0); + QCOMPARE(context->contextProperty("modelDataFromIndex").toString(), ""); +} + void tst_QQuickTableView::checkChangingModelFromDelegate() { // Check that we don't restart a rebuild of the table @@ -2617,7 +2679,27 @@ void tst_QQuickTableView::checkSyncView_connect_late() QCOMPARE(tableViewVPrivate->loadedTableOuterRect.left(), 0); QCOMPARE(tableViewHVPrivate->loadedTableOuterRect, tableViewPrivate->loadedTableOuterRect); +} + +void tst_QQuickTableView::checkThatFetchMoreIsCalledWhenScrolledToTheEndOfTable() +{ + LOAD_TABLEVIEW("plaintableview.qml"); + + auto model = TestModelAsVariant(5, 5, true); + tableView->setModel(model); + WAIT_UNTIL_POLISHED; + + QCOMPARE(tableView->rows(), 5); + QCOMPARE(tableView->columns(), 5); + // Flick table out of view on top + tableView->setContentX(0); + tableView->setContentY(-tableView->height() - 10); + tableView->polish(); + WAIT_UNTIL_POLISHED; + + QCOMPARE(tableView->rows(), 6); + QCOMPARE(tableView->columns(), 5); } void tst_QQuickTableView::delegateWithRequiredProperties() @@ -2648,7 +2730,7 @@ void tst_QQuickTableView::delegateWithRequiredProperties() auto model = QVariant::fromValue(QSharedPointer<MyTable>(new MyTable)); { QTest::ignoreMessage(QtMsgType::QtInfoMsg, "success"); - LOAD_TABLEVIEW("delegateWithRequired.qml") + LOAD_TABLEVIEW("delegateWithRequired.qml"); QVERIFY(tableView); tableView->setModel(model); WAIT_UNTIL_POLISHED; @@ -2656,7 +2738,7 @@ void tst_QQuickTableView::delegateWithRequiredProperties() } { QTest::ignoreMessage(QtMsgType::QtWarningMsg, QRegularExpression(R"|(TableView: failed loading index: \d)|")); - LOAD_TABLEVIEW("delegatewithRequiredUnset.qml") + LOAD_TABLEVIEW("delegatewithRequiredUnset.qml"); QVERIFY(tableView); tableView->setModel(model); WAIT_UNTIL_POLISHED; @@ -2664,6 +2746,28 @@ void tst_QQuickTableView::delegateWithRequiredProperties() } } +void tst_QQuickTableView::replaceModel() +{ + LOAD_TABLEVIEW("replaceModelTableView.qml"); + + const auto objectModel = view->rootObject()->property("objectModel"); + const auto listModel = view->rootObject()->property("listModel"); + const auto delegateModel = view->rootObject()->property("delegateModel"); + + tableView->setModel(listModel); + QTRY_COMPARE(tableView->rows(), 2); + tableView->setModel(objectModel); + QTRY_COMPARE(tableView->rows(), 3); + tableView->setModel(delegateModel); + QTRY_COMPARE(tableView->rows(), 2); + tableView->setModel(listModel); + QTRY_COMPARE(tableView->rows(), 2); + tableView->setModel(QVariant()); + QTRY_COMPARE(tableView->rows(), 0); + QCOMPARE(tableView->contentWidth(), 0); + QCOMPARE(tableView->contentHeight(), 0); +} + QTEST_MAIN(tst_QQuickTableView) #include "tst_qquicktableview.moc" |