diff options
-rw-r--r-- | src/qml/doc/snippets/qml/tablemodel/fruit-example-simpledelegate.qml | 1 | ||||
-rw-r--r-- | src/qml/types/qqmltablemodel.cpp | 149 | ||||
-rw-r--r-- | src/qml/types/qqmltablemodel_p.h | 19 | ||||
-rw-r--r-- | tests/auto/qml/qqmltablemodel/data/TestModel.qml (renamed from tests/auto/qml/qqmltablemodel/data/defaultDisplayRoles.qml) | 42 | ||||
-rw-r--r-- | tests/auto/qml/qqmltablemodel/data/TestUtils.js | 45 | ||||
-rw-r--r-- | tests/auto/qml/qqmltablemodel/data/builtInRoles.qml | 47 | ||||
-rw-r--r-- | tests/auto/qml/qqmltablemodel/data/common.qml | 18 | ||||
-rw-r--r-- | tests/auto/qml/qqmltablemodel/data/empty.qml | 3 | ||||
-rw-r--r-- | tests/auto/qml/qqmltablemodel/data/explicitDisplayRole.qml | 41 | ||||
-rw-r--r-- | tests/auto/qml/qqmltablemodel/data/setDataThroughDelegate.qml | 32 | ||||
-rw-r--r-- | tests/auto/qml/qqmltablemodel/data/setRowsMultipleTimes.qml | 18 | ||||
-rw-r--r-- | tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp | 88 |
12 files changed, 317 insertions, 186 deletions
diff --git a/src/qml/doc/snippets/qml/tablemodel/fruit-example-simpledelegate.qml b/src/qml/doc/snippets/qml/tablemodel/fruit-example-simpledelegate.qml index ae1f8d0b71..5f00eb484b 100644 --- a/src/qml/doc/snippets/qml/tablemodel/fruit-example-simpledelegate.qml +++ b/src/qml/doc/snippets/qml/tablemodel/fruit-example-simpledelegate.qml @@ -100,6 +100,7 @@ Window { padding: 12 selectByMouse: true + // TODO: the property used here is undefined onAccepted: model.display = text Rectangle { diff --git a/src/qml/types/qqmltablemodel.cpp b/src/qml/types/qqmltablemodel.cpp index 0b1273a54b..c59a7584f7 100644 --- a/src/qml/types/qqmltablemodel.cpp +++ b/src/qml/types/qqmltablemodel.cpp @@ -119,6 +119,7 @@ static const QString displayRoleName = QStringLiteral("display"); QQmlTableModel::QQmlTableModel(QObject *parent) : QAbstractTableModel(parent) { + mRoleNames = QAbstractTableModel::roleNames(); } QQmlTableModel::~QQmlTableModel() @@ -167,6 +168,9 @@ void QQmlTableModel::setRows(const QVariant &rows) } if (mColumnCount > 0) { + qCDebug(lcTableModel) << "validating" << rowsAsVariantList.size() + << "rows against existing metadata"; + // This is not the first time the rows have been set; validate the new columns. for (int i = 0; i < rowsAsVariantList.size(); ++i) { // validateNewRow() expects a QVariant wrapping a QJSValue, so to @@ -178,95 +182,72 @@ void QQmlTableModel::setRows(const QVariant &rows) } } - const bool resettingModel = mRowCount != rowsAsVariantList.size(); const int oldRowCount = mRowCount; const int oldColumnCount = mColumnCount; - if (resettingModel) - beginResetModel(); + + beginResetModel(); // We don't clear the column or role data, because a TableModel should not be reused in that way. // Once it has valid data, its columns and roles are fixed. mRows = rowsAsVariantList; mRowCount = mRows.size(); - if (mRowCount == 0) { - // No elements. - if (resettingModel) - endResetModel(); - - emit rowsChanged(); - - if (mRowCount != oldRowCount) - emit rowCountChanged(); - if (mColumnCount != oldColumnCount) - emit columnCountChanged(); - return; - } - - if (mColumnCount == 0) { - // This is the first time the rows have been set, so establish the column count. + const bool isFirstTimeSet = mColumnCount == 0; + if (isFirstTimeSet && mRowCount > 0) { + // This is the first time the rows have been set, so establish + // the column count and gather column metadata. mColumnCount = firstRow.size(); - } + qCDebug(lcTableModel) << "gathering metadata for" << mColumnCount << "columns from first row:"; - bool explicitDisplayRoleIndex = false; - - if (mRowCount > 0) { // Go through each property of each cell in the first row // and make a role name from it. - int roleKey = Qt::UserRole; + int userRoleKey = Qt::UserRole; for (int columnIndex = 0; columnIndex < mColumnCount; ++columnIndex) { // We need it as a QVariantMap because we need to get // the name of the property, which we can't do with QJSValue's API. const QVariantMap column = firstRow.at(columnIndex).toMap(); const QStringList columnPropertyNames = column.keys(); + ColumnProperties properties; + int propertyInfoIndex = 0; + + qCDebug(lcTableModel).nospace() << "- column " << columnIndex << ":"; - const int firstRoleForColumn = roleKey; - QVector<ColumnPropertyInfo> properties; for (const QString &roleName : columnPropertyNames) { // QML/JS supports utf8. - mRoleNames[roleKey] = roleName.toUtf8().constData(); - - if (!explicitDisplayRoleIndex && roleName == displayRoleName) { - explicitDisplayRoleIndex = true; - // The user explicitly declared a "display" role, so now they're on their own. - mDefaultDisplayRoles.clear(); - - qCDebug(lcTableModel).nospace() << "explicit \"display\" role found; " - << "clearing default display roles"; + const QByteArray roleNameUtf8 = roleName.toUtf8(); + if (!mRoleNames.values().contains(roleNameUtf8)) { + // We don't already have this role name, so it's a user role. + mRoleNames[userRoleKey] = roleName.toUtf8().constData(); + qCDebug(lcTableModel) << " - added new user role" << roleName << "with key" << userRoleKey; + ++userRoleKey; + } else { + qCDebug(lcTableModel) << " - found existing role" << roleName; } - qCDebug(lcTableModel).nospace() << "added role " - << roleName << " with key " << roleKey << " found in column " << columnIndex; + if (properties.explicitDisplayRoleIndex == -1 && roleName == displayRoleName) { + // The user explicitly declared a "display" role, + // so now we don't need to make it the first role in the column for them. + properties.explicitDisplayRoleIndex = propertyInfoIndex; + } + // Keep track of the type of property so we can use it to validate new rows later on. const QVariant roleValue = column.value(roleName); - properties.append(ColumnPropertyInfo(roleName, roleValue.type(), QString::fromLatin1(roleValue.typeName()))); - - ++roleKey; - } + const auto propertyInfo = ColumnPropertyInfo(roleName, roleValue.type(), + QString::fromLatin1(roleValue.typeName())); + properties.infoForProperties.append(propertyInfo); - mColumnProperties.append(properties); + qCDebug(lcTableModel) << " - column property" << propertyInfo.name + << "has type" << propertyInfo.typeName; - if (!explicitDisplayRoleIndex) { - // The "display" role wasn't specified for this column, - // so we use the first role that was declared for that column. - // TODO: make it possible to specify the display role? - // e.g. { myRoleName: 123, displayRole: "myRoleName" } - mDefaultDisplayRoles[columnIndex] = firstRoleForColumn; - - qCDebug(lcTableModel).nospace() << "added implicit \"display\" role with key " - << int(Qt::DisplayRole) << " for column " << columnIndex - << " which will display values from the " << mRoleNames.value(firstRoleForColumn) << " role"; + ++propertyInfoIndex; } - } - if (!explicitDisplayRoleIndex) { - // There was no "display" role declared by the user, so we can provide one for them. - mRoleNames[Qt::DisplayRole] = displayRoleName.toUtf8().constData(); + mColumnProperties.append(properties); } - - endResetModel(); } + endResetModel(); + emit rowsChanged(); if (mRowCount != oldRowCount) @@ -504,8 +485,8 @@ void QQmlTableModel::removeRow(int rowIndex, int rows) endRemoveRows(); emit rowCountChanged(); - qCDebug(lcTableModel).nospace() << "removed" << rows - << "items from the model, starting at index" << rowIndex; + qCDebug(lcTableModel).nospace() << "removed " << rows + << " items from the model, starting at index " << rowIndex; } /*! @@ -678,7 +659,7 @@ QVariant QQmlTableModel::data(const QModelIndex &index, int role) const if (column < 0 || column >= columnCount()) return QVariant(); - if ((role < Qt::UserRole || role >= Qt::UserRole + mRoleNames.size()) && role != Qt::DisplayRole) + if (!mRoleNames.contains(role)) return QVariant(); const QVariantList rowData = mRows.at(row).toList(); @@ -692,18 +673,11 @@ QVariant QQmlTableModel::data(const QModelIndex &index, int role) const return const_cast<QQmlTableModel*>(this)->mRoleDataProvider.call(args).toVariant(); } + // TODO: should we also allow this code to be executed if roleDataProvider doesn't + // handle the role/column, so that it only has to handle the case where there is + // more than one role in a column? const QVariantMap columnData = rowData.at(column).toMap(); - - int effectiveRole = role; - if (role == Qt::DisplayRole) { - // If the execution got to this point, then the user is requesting data for the display role, - // but didn't specify any role with the name "display". - // So, we give them the data of the implicit display role. - Q_ASSERT(mDefaultDisplayRoles.contains(column)); - effectiveRole = mDefaultDisplayRoles.value(column); - } - - const QString propertyName = QString::fromUtf8(roleNames().value(effectiveRole)); + const QString propertyName = columnPropertyNameFromRole(column, role); const QVariant value = columnData.value(propertyName); return value; } @@ -734,17 +708,11 @@ bool QQmlTableModel::setData(const QModelIndex &index, const QVariant &value, in if (column < 0 || column >= columnCount()) return false; - if ((role < Qt::UserRole || role >= Qt::UserRole + mRoleNames.size()) && role != Qt::DisplayRole) + if (!mRoleNames.contains(role)) return false; - int effectiveRole = role; - if (role == Qt::DisplayRole) { - Q_ASSERT(mDefaultDisplayRoles.contains(column)); - effectiveRole = mDefaultDisplayRoles.value(column); - } - const QVariantList rowData = mRows.at(row).toList(); - const QString propertyName = QString::fromUtf8(roleNames().value(effectiveRole)); + const QString propertyName = columnPropertyNameFromRole(column, role); qCDebug(lcTableModel).nospace() << "setData() called with index " << index << ", value " << value << " and role " << propertyName; @@ -757,7 +725,7 @@ bool QQmlTableModel::setData(const QModelIndex &index, const QVariant &value, in stream.nospace() << "setData(): no role named " << propertyName << " at column index " << column << ". The available roles for that column are:\n"; - const QVector<ColumnPropertyInfo> availableProperties = mColumnProperties.at(column); + const QVector<ColumnPropertyInfo> availableProperties = mColumnProperties.at(column).infoForProperties; for (auto propertyInfo : availableProperties) stream << " - " << propertyInfo.name << " (" << qPrintable(propertyInfo.typeName) << ")"; @@ -909,7 +877,7 @@ bool QQmlTableModel::validateColumnPropertyTypes(const char *functionName, const QVariantList columnProperties = column.values(); const QStringList propertyNames = column.keys(); // Expected - const QVector<ColumnPropertyInfo> properties = mColumnProperties.at(columnIndex); + const QVector<ColumnPropertyInfo> properties = mColumnProperties.at(columnIndex).infoForProperties; // This iterates across the properties in the column. For example: // 0 1 2 @@ -955,7 +923,7 @@ QQmlTableModel::ColumnPropertyInfo QQmlTableModel::findColumnPropertyInfo( { // TODO: check if a hash with its string-based lookup is faster, // keeping in mind that we may be doing index-based lookups too. - const QVector<ColumnPropertyInfo> properties = mColumnProperties.at(columnIndex); + const QVector<ColumnPropertyInfo> properties = mColumnProperties.at(columnIndex).infoForProperties; for (int i = 0; i < properties.size(); ++i) { const ColumnPropertyInfo &info = properties.at(i); if (info.name == columnPropertyName) @@ -965,4 +933,19 @@ QQmlTableModel::ColumnPropertyInfo QQmlTableModel::findColumnPropertyInfo( return ColumnPropertyInfo(); } +QString QQmlTableModel::columnPropertyNameFromRole(int columnIndex, int role) const +{ + QString propertyName; + if (role == Qt::DisplayRole && mColumnProperties.at(columnIndex).explicitDisplayRoleIndex == -1) { + // The user is getting or setting data for the display role, + // but didn't specify any role with the name "display" in this column. + // So, we give them the implicit display role, aka the first property we find. + propertyName = mColumnProperties.at(columnIndex).infoForProperties.first().name; + } else { + // QML/JS supports utf8. + propertyName = QString::fromUtf8(mRoleNames.value(role)); + } + return propertyName; +} + QT_END_NAMESPACE diff --git a/src/qml/types/qqmltablemodel_p.h b/src/qml/types/qqmltablemodel_p.h index 3bbaff4183..33b2189fcd 100644 --- a/src/qml/types/qqmltablemodel_p.h +++ b/src/qml/types/qqmltablemodel_p.h @@ -114,6 +114,14 @@ private: QString typeName; }; + struct ColumnProperties + { + QVector<ColumnPropertyInfo> infoForProperties; + // If there was a display role found in this column, it'll be stored here. + // The index is into infoForProperties. + int explicitDisplayRoleIndex = -1; + }; + enum NewRowOperationFlag { OtherOperation, // insert(), set(), etc. AppendOperation @@ -127,22 +135,19 @@ private: bool validateColumnPropertyType(const char *functionName, const QString &propertyName, const QVariant &propertyValue, const ColumnPropertyInfo &expectedPropertyFormat, int columnIndex) const; - ColumnPropertyInfo findColumnPropertyInfo(int columnIndex, const QString &columnPropertyName) const; + ColumnPropertyInfo findColumnPropertyInfo(int columnIndex, const QString &columnPropertyNameFromRole) const; + QString columnPropertyNameFromRole(int columnIndex, int role) const; void doInsert(int rowIndex, const QVariant &row); QVariantList mRows; int mRowCount = 0; int mColumnCount = 0; - QVector<QVector<ColumnPropertyInfo>> mColumnProperties; + // Each entry contains information about the properties of the column at that index. + QVector<ColumnProperties> mColumnProperties; // key = property index (0 to number of properties across all columns) // value = role name QHash<int, QByteArray> mRoleNames; - // Contains the role key to be used as the display role for each column - // when "display" isn't explicitly specified. - // key = column index - // value = index (key) into mRoleNames - QHash<int, int> mDefaultDisplayRoles; QJSValue mRoleDataProvider; }; diff --git a/tests/auto/qml/qqmltablemodel/data/defaultDisplayRoles.qml b/tests/auto/qml/qqmltablemodel/data/TestModel.qml index 32daea61f9..7aeb5d03f4 100644 --- a/tests/auto/qml/qqmltablemodel/data/defaultDisplayRoles.qml +++ b/tests/auto/qml/qqmltablemodel/data/TestModel.qml @@ -26,36 +26,22 @@ ** ****************************************************************************/ -import QtQuick 2.12 import Qt.labs.qmlmodels 1.0 -Item { - id: root - width: 200 - height: 200 +import "TestUtils.js" as TestUtils - property alias testModel: testModel - - TableModel { - id: testModel - objectName: "testModel" - rows: [ - [ - { name: "John", someOtherRole1: "foo" }, // column 0 - { age: 22, someOtherRole2: "foo" } // column 1 - ], - [ - { name: "Oliver", someOtherRole1: "foo" }, // column 0 - { age: 33, someOtherRole2: "foo" } // column 1 - ] +TableModel { + id: testModel + objectName: "testModel" + roleDataProvider: TestUtils.testModelRoleDataProvider + rows: [ + [ + { name: "John" }, + { age: 22 } + ], + [ + { name: "Oliver" }, + { age: 33 } ] - } - TableView { - anchors.fill: parent - model: testModel - delegate: Text { - id: textItem - text: model.display - } - } + ] } diff --git a/tests/auto/qml/qqmltablemodel/data/TestUtils.js b/tests/auto/qml/qqmltablemodel/data/TestUtils.js new file mode 100644 index 0000000000..0b92a377bb --- /dev/null +++ b/tests/auto/qml/qqmltablemodel/data/TestUtils.js @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** 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-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +function testModelRoleDataProvider(index, role, cellData) { + switch (role) { + case "display": + switch (index.column) { + case 0: + return cellData.name + case 1: + return cellData.age + } + break + case "name": + return cellData.name + case "age": + return cellData.age + } + return cellData +} diff --git a/tests/auto/qml/qqmltablemodel/data/builtInRoles.qml b/tests/auto/qml/qqmltablemodel/data/builtInRoles.qml new file mode 100644 index 0000000000..d9882e4dea --- /dev/null +++ b/tests/auto/qml/qqmltablemodel/data/builtInRoles.qml @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** 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-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt.labs.qmlmodels 1.0 + +import "TestUtils.js" as TestUtils + +TableModel { + id: testModel + objectName: "testModel" + roleDataProvider: TestUtils.testModelRoleDataProvider + rows: [ + [ + { name: "John", someOtherRole1: "foo" }, // column 0 + { age: 22, someOtherRole2: "foo" } // column 1 + ], + [ + { name: "Oliver", someOtherRole1: "foo" }, // column 0 + { age: 33, someOtherRole2: "foo" } // column 1 + ] + ] +} diff --git a/tests/auto/qml/qqmltablemodel/data/common.qml b/tests/auto/qml/qqmltablemodel/data/common.qml index 2ae9c50a1b..aec796bd4f 100644 --- a/tests/auto/qml/qqmltablemodel/data/common.qml +++ b/tests/auto/qml/qqmltablemodel/data/common.qml @@ -115,24 +115,12 @@ Item { ]) } - TableModel { - id: testModel - objectName: "testModel" - rows: [ - [ - { name: "John" }, - { age: 22 } - ], - [ - { name: "Oliver" }, - { age: 33 } - ] - ] - } TableView { id: tableView anchors.fill: parent - model: testModel + model: TestModel { + id: testModel + } delegate: Text { text: model.display } diff --git a/tests/auto/qml/qqmltablemodel/data/empty.qml b/tests/auto/qml/qqmltablemodel/data/empty.qml index 57f2f992d9..6e66b99145 100644 --- a/tests/auto/qml/qqmltablemodel/data/empty.qml +++ b/tests/auto/qml/qqmltablemodel/data/empty.qml @@ -29,6 +29,8 @@ import QtQuick 2.12 import Qt.labs.qmlmodels 1.0 +import "TestUtils.js" as TestUtils + Item { id: root width: 200 @@ -53,6 +55,7 @@ Item { TableModel { id: testModel objectName: "testModel" + roleDataProvider: TestUtils.testModelRoleDataProvider } TableView { id: tableView diff --git a/tests/auto/qml/qqmltablemodel/data/explicitDisplayRole.qml b/tests/auto/qml/qqmltablemodel/data/explicitDisplayRole.qml new file mode 100644 index 0000000000..510a62e74b --- /dev/null +++ b/tests/auto/qml/qqmltablemodel/data/explicitDisplayRole.qml @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** 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-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt.labs.qmlmodels 1.0 + +import "TestUtils.js" as TestUtils + +TableModel { + id: testModel + rows: [ + [ + { name: "John", display: "foo" }, + { age: 22, display: "bar" } + ] + ] +} diff --git a/tests/auto/qml/qqmltablemodel/data/setDataThroughDelegate.qml b/tests/auto/qml/qqmltablemodel/data/setDataThroughDelegate.qml index 7a419d81c6..5f849c3350 100644 --- a/tests/auto/qml/qqmltablemodel/data/setDataThroughDelegate.qml +++ b/tests/auto/qml/qqmltablemodel/data/setDataThroughDelegate.qml @@ -52,25 +52,27 @@ Item { shouldModifyInvalidType() } - TableModel { - id: testModel - objectName: "testModel" - rows: [ - [ - { name: "John" }, - { age: 22 } - ], - [ - { name: "Oliver" }, - { age: 33 } - ] - ] - } TableView { anchors.fill: parent - model: testModel + model: TableModel { + id: testModel + objectName: "testModel" + rows: [ + [ + { name: "John" }, + { age: 22 } + ], + [ + { name: "Oliver" }, + { age: 33 } + ] + ] + } + delegate: Text { id: textItem + // TODO: this is currently random when no roleDataProvider handles it + // we should allow roleDataProvider to be used to handle specific roles only text: model.display Connections { diff --git a/tests/auto/qml/qqmltablemodel/data/setRowsMultipleTimes.qml b/tests/auto/qml/qqmltablemodel/data/setRowsMultipleTimes.qml index 15d52f93a6..6aaf79f2d4 100644 --- a/tests/auto/qml/qqmltablemodel/data/setRowsMultipleTimes.qml +++ b/tests/auto/qml/qqmltablemodel/data/setRowsMultipleTimes.qml @@ -71,24 +71,12 @@ Item { ] } - TableModel { - id: testModel - objectName: "testModel" - rows: [ - [ - { name: "John" }, - { age: 22 } - ], - [ - { name: "Oliver" }, - { age: 33 } - ] - ] - } TableView { id: tableView anchors.fill: parent - model: testModel + model: TestModel { + id: testModel + } delegate: Text { text: model.display } diff --git a/tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp b/tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp index eb1fbda45a..059ce082d9 100644 --- a/tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp +++ b/tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp @@ -55,11 +55,15 @@ private slots: void setDataThroughDelegate(); void setRowsImperatively(); void setRowsMultipleTimes(); - void defaultDisplayRoles(); + void builtInRoles_data(); + void builtInRoles(); + void explicitDisplayRole(); void roleDataProvider(); void dataAndEditing(); }; +static const int builtInRoleCount = 6; + void tst_QQmlTableModel::appendRemoveRow() { QQuickView view(testFileUrl("common.qml")); @@ -80,11 +84,15 @@ void tst_QQmlTableModel::appendRemoveRow() int heightSignalEmissions = 0; const QHash<int, QByteArray> roleNames = model->roleNames(); - QCOMPARE(roleNames.size(), 3); + QCOMPARE(roleNames.size(), 2 + builtInRoleCount); QVERIFY(roleNames.values().contains("name")); QVERIFY(roleNames.values().contains("age")); QVERIFY(roleNames.values().contains("display")); - + QVERIFY(roleNames.values().contains("decoration")); + QVERIFY(roleNames.values().contains("edit")); + QVERIFY(roleNames.values().contains("toolTip")); + QVERIFY(roleNames.values().contains("statusTip")); + QVERIFY(roleNames.values().contains("whatsThis")); QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John")); QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22); QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); @@ -208,10 +216,9 @@ void tst_QQmlTableModel::clear() QVERIFY(rowCountSpy.isValid()); const QHash<int, QByteArray> roleNames = model->roleNames(); - QCOMPARE(roleNames.size(), 3); QVERIFY(roleNames.values().contains("name")); QVERIFY(roleNames.values().contains("age")); - QVERIFY(roleNames.values().contains("display")); + QCOMPARE(roleNames.size(), 2 + builtInRoleCount); QQuickTableView *tableView = view.rootObject()->property("tableView").value<QQuickTableView*>(); QVERIFY(tableView); @@ -221,8 +228,8 @@ void tst_QQmlTableModel::clear() QVERIFY(QMetaObject::invokeMethod(model, "clear")); QCOMPARE(model->rowCount(), 0); QCOMPARE(model->columnCount(), 2); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")), QVariant()); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")), QVariant()); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")), QVariant()); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")), QVariant()); QCOMPARE(columnCountSpy.count(), 0); QCOMPARE(rowCountSpy.count(), 1); // Wait until updatePolish() gets called, which is where the size is recalculated. @@ -690,10 +697,9 @@ void tst_QQmlTableModel::setDataThroughDelegate() QVERIFY(rowCountSpy.isValid()); const QHash<int, QByteArray> roleNames = model->roleNames(); - QCOMPARE(roleNames.size(), 3); + QCOMPARE(roleNames.size(), 2 + builtInRoleCount); QVERIFY(roleNames.values().contains("name")); QVERIFY(roleNames.values().contains("age")); - QVERIFY(roleNames.values().contains("display")); QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("John")); QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("age")).toInt(), 22); QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("name")).toString(), QLatin1String("Oliver")); @@ -836,29 +842,65 @@ void tst_QQmlTableModel::setRowsMultipleTimes() QCOMPARE(tableView->columns(), 2); } -void tst_QQmlTableModel::defaultDisplayRoles() +void tst_QQmlTableModel::builtInRoles_data() { - QQuickView view(testFileUrl("defaultDisplayRoles.qml")); - QCOMPARE(view.status(), QQuickView::Ready); - view.show(); - QVERIFY(QTest::qWaitForWindowActive(&view)); + QTest::addColumn<int>("row"); + QTest::addColumn<int>("column"); + QTest::addColumn<QByteArray>("roleName"); + QTest::addColumn<QVariant>("expectedValue"); - QQmlTableModel *model = view.rootObject()->property("testModel").value<QQmlTableModel*>(); + const QByteArray displayRole = "display"; + + QTest::addRow("display(0,0)") << 0 << 0 << displayRole << QVariant(QLatin1String("John")); + QTest::addRow("display(0,1)") << 0 << 1 << displayRole << QVariant(QLatin1String("22")); + QTest::addRow("display(1,0)") << 1 << 0 << displayRole << QVariant(QLatin1String("Oliver")); + QTest::addRow("display(1,1)") << 1 << 1 << displayRole << QVariant(QLatin1String("33")); +} + +void tst_QQmlTableModel::builtInRoles() +{ + QFETCH(int, row); + QFETCH(int, column); + QFETCH(QByteArray, roleName); + QFETCH(QVariant, expectedValue); + + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("builtInRoles.qml")); + QCOMPARE(component.status(), QQmlComponent::Ready); + + QScopedPointer<QQmlTableModel> model(qobject_cast<QQmlTableModel*>(component.create())); QVERIFY(model); QCOMPARE(model->rowCount(), 2); QCOMPARE(model->columnCount(), 2); - QSignalSpy columnCountSpy(model, SIGNAL(columnCountChanged())); - QVERIFY(columnCountSpy.isValid()); + const QHash<int, QByteArray> roleNames = model->roleNames(); + QCOMPARE(roleNames.size(), 4 + builtInRoleCount); + QVERIFY(roleNames.values().contains("display")); + QVERIFY(roleNames.values().contains("decoration")); + QVERIFY(roleNames.values().contains("edit")); + QVERIFY(roleNames.values().contains("toolTip")); + QVERIFY(roleNames.values().contains("statusTip")); + QVERIFY(roleNames.values().contains("whatsThis")); + QVERIFY(roleNames.values().contains("name")); + QVERIFY(roleNames.values().contains("age")); + QVERIFY(roleNames.values().contains("someOtherRole1")); + QVERIFY(roleNames.values().contains("someOtherRole2")); + QCOMPARE(model->data(model->index(row, column, QModelIndex()), roleNames.key(roleName)), expectedValue); +} - QSignalSpy rowCountSpy(model, SIGNAL(rowCountChanged())); - QVERIFY(rowCountSpy.isValid()); +void tst_QQmlTableModel::explicitDisplayRole() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("explicitDisplayRole.qml")); + QCOMPARE(component.status(), QQmlComponent::Ready); + QScopedPointer<QQmlTableModel> model(qobject_cast<QQmlTableModel*>(component.create())); + QVERIFY(model); + QCOMPARE(model->rowCount(), 1); + QCOMPARE(model->columnCount(), 2); const QHash<int, QByteArray> roleNames = model->roleNames(); - QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("John")); - QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 22); - QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Oliver")); - QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("foo")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("bar")); } void tst_QQmlTableModel::roleDataProvider() |