diff options
-rw-r--r-- | src/qml/doc/snippets/qml/tablemodel/roleDataProvider.qml | 83 | ||||
-rw-r--r-- | src/qml/types/qqmltablemodel.cpp | 40 | ||||
-rw-r--r-- | src/qml/types/qqmltablemodel_p.h | 6 | ||||
-rw-r--r-- | tests/auto/qml/qqmltablemodel/data/roleDataProvider.qml | 65 | ||||
-rw-r--r-- | tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp | 19 |
5 files changed, 213 insertions, 0 deletions
diff --git a/src/qml/doc/snippets/qml/tablemodel/roleDataProvider.qml b/src/qml/doc/snippets/qml/tablemodel/roleDataProvider.qml new file mode 100644 index 0000000000..6c8ae3f1fc --- /dev/null +++ b/src/qml/doc/snippets/qml/tablemodel/roleDataProvider.qml @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +//![0] +import QtQuick 2.12 +import Qt.labs.qmlmodels 1.0 + +TableView { + columnSpacing: 1; rowSpacing: 1 + model: TableModel { + property real taxPercent: 10 + rows: [ + [{ fruitType: "Apple" }, { fruitPrice: 1.50 }], + [{ fruitType: "Orange" }, { fruitPrice: 2.50 }] + ] + roleDataProvider: function(row, column, role, cellData) { + if (role === "display") { + if (cellData.hasOwnProperty("fruitPrice")) { + console.log("taxing your fruit " + JSON.stringify(cellData)) + return (cellData.fruitPrice * (1 + taxPercent / 100)).toFixed(2); + } + else if (cellData.hasOwnProperty("fruitType")) + return cellData.fruitType; + } + return cellData; + } + } + delegate: Rectangle { + implicitWidth: 150; implicitHeight: 30 + color: "lightsteelblue" + Text { + x: 6; anchors.verticalCenter: parent.verticalCenter + text: display + } + } +} +//![0] diff --git a/src/qml/types/qqmltablemodel.cpp b/src/qml/types/qqmltablemodel.cpp index cf3fc0298a..9bf8c7f562 100644 --- a/src/qml/types/qqmltablemodel.cpp +++ b/src/qml/types/qqmltablemodel.cpp @@ -548,6 +548,38 @@ void QQmlTableModel::setRow(int rowIndex, const QVariant &row) } } +/*! + \qmlproperty var TableModel::roleDataProvider + + This property can hold a function that will map roles to values. + + When assigned, it will be called each time data() is called, to enable + extracting arbitrary values, converting the data in arbitrary ways, or even + doing calculations. It takes 4 arguments: \c row, \c column, \c role (as a + string), and \c cellData, which is the complete data that is stored in the + given cell. (If the cell contains a JS object with multiple named values, + the entire object will be given in cellData.) The function that you define + must return the value to be used; for example a typical delegate will + display the value returned for the \c display role, so you can check + whether that is the role and return data in a form that is suitable for the + delegate to show: + + \snippet qml/tablemodel/roleDataProvider.qml 0 +*/ +QJSValue QQmlTableModel::roleDataProvider() const +{ + return mRoleDataProvider; +} + +void QQmlTableModel::setRoleDataProvider(QJSValue roleDataProvider) +{ + if (roleDataProvider.strictlyEquals(mRoleDataProvider)) + return; + + mRoleDataProvider = roleDataProvider; + emit roleDataProviderChanged(); +} + QModelIndex QQmlTableModel::index(int row, int column, const QModelIndex &parent) const { return row >= 0 && row < rowCount() && column >= 0 && column < columnCount() && !parent.isValid() @@ -603,6 +635,14 @@ QVariant QQmlTableModel::data(const QModelIndex &index, int role) const return QVariant(); const QVariantList rowData = mRows.at(row).toList(); + + if (mRoleDataProvider.isCallable()) { + const auto args = QJSValueList() << row << column << + QString::fromUtf8(mRoleNames.value(role)) << + qmlEngine(this)->toScriptValue(rowData.at(column)); + return const_cast<QQmlTableModel*>(this)->mRoleDataProvider.call(args).toVariant(); + } + const QVariantMap columnData = rowData.at(column).toMap(); int effectiveRole = role; diff --git a/src/qml/types/qqmltablemodel_p.h b/src/qml/types/qqmltablemodel_p.h index 8da930872d..863c592678 100644 --- a/src/qml/types/qqmltablemodel_p.h +++ b/src/qml/types/qqmltablemodel_p.h @@ -65,6 +65,7 @@ class Q_QML_PRIVATE_EXPORT QQmlTableModel : public QAbstractTableModel Q_PROPERTY(int columnCount READ columnCount NOTIFY columnCountChanged FINAL) Q_PROPERTY(int rowCount READ rowCount NOTIFY rowCountChanged FINAL) Q_PROPERTY(QVariant rows READ rows WRITE setRows NOTIFY rowsChanged FINAL) + Q_PROPERTY(QJSValue roleDataProvider READ roleDataProvider WRITE setRoleDataProvider NOTIFY roleDataProviderChanged) public: QQmlTableModel(QObject *parent = nullptr); @@ -81,6 +82,9 @@ public: Q_INVOKABLE void removeRow(int rowIndex, int rows = 1); Q_INVOKABLE void setRow(int rowIndex, const QVariant &row); + QJSValue roleDataProvider() const; + void setRoleDataProvider(QJSValue roleDataProvider); + QModelIndex index(int row, int column, const QModelIndex &parent) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; @@ -92,6 +96,7 @@ Q_SIGNALS: void columnCountChanged(); void rowCountChanged(); void rowsChanged(); + void roleDataProviderChanged(); private: class ColumnPropertyInfo @@ -136,6 +141,7 @@ private: // key = column index // value = index (key) into mRoleNames QHash<int, int> mDefaultDisplayRoles; + QJSValue mRoleDataProvider; }; QT_END_NAMESPACE diff --git a/tests/auto/qml/qqmltablemodel/data/roleDataProvider.qml b/tests/auto/qml/qqmltablemodel/data/roleDataProvider.qml new file mode 100644 index 0000000000..825a1ad071 --- /dev/null +++ b/tests/auto/qml/qqmltablemodel/data/roleDataProvider.qml @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** 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 QtQuick 2.12 +import Qt.labs.qmlmodels 1.0 + +Item { + id: root + width: 200 + height: 200 + + property alias testModel: testModel + + TableModel { + id: testModel + objectName: "testModel" + rows: [ + [ { name: "Rex" }, { age: 3 } ], + [ { name: "Buster" }, { age: 5 } ] + ] + roleDataProvider: function(row, column, role, cellData) { + if (role === "display") { + // Age will now be in dog years + if (cellData.hasOwnProperty("age")) + return (cellData.age * 7); + else if (column === 0) + return (cellData.name); + } + return cellData; + } + } + TableView { + anchors.fill: parent + model: testModel + delegate: Text { + id: textItem + text: model.display + } + } +} diff --git a/tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp b/tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp index 825017e811..276f4e2b9f 100644 --- a/tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp +++ b/tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp @@ -56,6 +56,7 @@ private slots: void setRowsImperatively(); void setRowsMultipleTimes(); void defaultDisplayRoles(); + void roleDataProvider(); }; void tst_QQmlTableModel::appendRemoveRow() @@ -859,6 +860,24 @@ void tst_QQmlTableModel::defaultDisplayRoles() QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 33); } +void tst_QQmlTableModel::roleDataProvider() +{ + QQuickView view(testFileUrl("roleDataProvider.qml")); + QCOMPARE(view.status(), QQuickView::Ready); + view.show(); + QVERIFY(QTest::qWaitForWindowActive(&view)); + + QQmlTableModel *model = view.rootObject()->property("testModel").value<QQmlTableModel*>(); + QVERIFY(model); + + const QHash<int, QByteArray> roleNames = model->roleNames(); + QVERIFY(roleNames.values().contains("display")); + QCOMPARE(model->data(model->index(0, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Rex")); + QCOMPARE(model->data(model->index(0, 1, QModelIndex()), roleNames.key("display")).toInt(), 3 * 7); + QCOMPARE(model->data(model->index(1, 0, QModelIndex()), roleNames.key("display")).toString(), QLatin1String("Buster")); + QCOMPARE(model->data(model->index(1, 1, QModelIndex()), roleNames.key("display")).toInt(), 5 * 7); +} + QTEST_MAIN(tst_QQmlTableModel) #include "tst_qqmltablemodel.moc" |