diff options
Diffstat (limited to 'tests/auto/quickcontrols2/qquickheaderview')
4 files changed, 672 insertions, 0 deletions
diff --git a/tests/auto/quickcontrols2/qquickheaderview/CMakeLists.txt b/tests/auto/quickcontrols2/qquickheaderview/CMakeLists.txt new file mode 100644 index 0000000000..6a8f0fae5c --- /dev/null +++ b/tests/auto/quickcontrols2/qquickheaderview/CMakeLists.txt @@ -0,0 +1,50 @@ +# Generated from qquickheaderview.pro. + +##################################################################### +## tst_qquickheaderview Test: +##################################################################### + +# Collect test data +file(GLOB_RECURSE test_data_glob + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + data/*) +list(APPEND test_data ${test_data_glob}) + +qt_internal_add_test(tst_qquickheaderview + SOURCES + ../shared/qtest_quickcontrols.h + ../shared/util.cpp ../shared/util.h + ../shared/visualtestutil.cpp ../shared/visualtestutil.h + tst_qquickheaderview.cpp + DEFINES + QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../../src\\\" + PUBLIC_LIBRARIES + Qt::CorePrivate + Qt::Gui + Qt::GuiPrivate + Qt::QmlPrivate + Qt::QuickControls2 + Qt::QuickControls2Private + Qt::QuickPrivate + Qt::QuickTemplates2 + Qt::QuickTemplates2Private + Qt::QuickTest + Qt::TestPrivate + TESTDATA ${test_data} +) + +#### Keys ignored in scope 1:.:.:qquickheaderview.pro:<TRUE>: +# OTHER_FILES = "data/*.qml" + +## Scopes: +##################################################################### + +qt_internal_extend_target(tst_qquickheaderview CONDITION ANDROID OR IOS + DEFINES + QT_QMLTEST_DATADIR=\\\":/data\\\" +) + +qt_internal_extend_target(tst_qquickheaderview CONDITION NOT ANDROID AND NOT IOS + DEFINES + QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\" +) diff --git a/tests/auto/quickcontrols2/qquickheaderview/data/ListModel.qml b/tests/auto/quickcontrols2/qquickheaderview/data/ListModel.qml new file mode 100644 index 0000000000..b8160a46dd --- /dev/null +++ b/tests/auto/quickcontrols2/qquickheaderview/data/ListModel.qml @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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: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$ +** +****************************************************************************/ + +import QtQuick +import QtQuick.Window +import QtQuick.Controls +import TestTableModel + +Window { + objectName: "window" + width: 400 + height: 400 + visible: true + + Component { + id: cellDelegate + Rectangle { + implicitHeight: 25 + implicitWidth: 50 + color: "red" + Text { + text: row + "," + column + } + } + } + + HorizontalHeaderView { + id: hhv + objectName: "horizontalHeader" + model: ["AAA", "BBB", "CCC", "DDD", "EEE"] + syncView: tv + anchors.top: parent.top + x: vhv.width + } + + VerticalHeaderView { + id: vhv + objectName: "verticalHeader" + model: ["111", "222", "333", "444", "555"] + syncView: tv + anchors.left: parent.left + y: hhv.height + } + + TableView { + id: tv + objectName: "tableView" + model: TestTableModel { + id: tm + objectName: "tableModel" + rowCount: 5 + columnCount: 5 + } + delegate: cellDelegate + anchors.top: hhv.bottom + anchors.left: vhv.right + anchors.right: parent.right + anchors.bottom: parent.bottom + } +} diff --git a/tests/auto/quickcontrols2/qquickheaderview/data/Window.qml b/tests/auto/quickcontrols2/qquickheaderview/data/Window.qml new file mode 100644 index 0000000000..9bf9963c69 --- /dev/null +++ b/tests/auto/quickcontrols2/qquickheaderview/data/Window.qml @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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: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$ +** +****************************************************************************/ + +import QtQuick +import QtQuick.Window +import QtQuick.Controls +import TestTableModel +import TestTableModelWithHeader +import HeaderDataProxyModel + +Window { + objectName: "window" + width: 400 + height: 400 + visible: true + + Component { + id: cellDelegate + Rectangle { + implicitHeight: 25 + implicitWidth: 50 + color: "red" + Text { + text: row + "," + column + } + } + } + + HeaderDataProxyModel { + id: pm + objectName: "proxyModel" + } + + TestTableModel { + id: tm + objectName: "tableModel" + rowCount: 5 + columnCount: 10 + } + + TestTableModelWithHeader { + id: thm + objectName: "tableHeaderModel" + rowCount: 5 + columnCount: 10 + } + + HorizontalHeaderView { + id: hhv + objectName: "horizontalHeader" + width: 200 + height: 200 + model: thm + delegate: cellDelegate + } + + VerticalHeaderView { + id: vhv + objectName: "verticalHeader" + width: 200 + height: 200 + model: thm + delegate: cellDelegate + } + + TableView { + id: tv + objectName: "tableView" + width: 400 + height: 400 + model: thm + delegate:cellDelegate + } +} diff --git a/tests/auto/quickcontrols2/qquickheaderview/tst_qquickheaderview.cpp b/tests/auto/quickcontrols2/qquickheaderview/tst_qquickheaderview.cpp new file mode 100644 index 0000000000..db2529cb0b --- /dev/null +++ b/tests/auto/quickcontrols2/qquickheaderview/tst_qquickheaderview.cpp @@ -0,0 +1,394 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "../shared/util.h" +#include <QtTest/qsignalspy.h> +#include <QtTest/qtest.h> + +#include <QAbstractItemModelTester> +#include <QtQml/QQmlEngine> +#include <QtQuick/private/qquickwindow_p.h> +#include <QtQuick/private/qquicktext_p.h> +#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h> +#include <QtQuickTemplates2/private/qquickheaderview_p.h> +#include <private/qquickheaderview_p_p.h> + +class TestTableModel : public QAbstractTableModel { + Q_OBJECT + Q_PROPERTY(int rowCount READ rowCount WRITE setRowCount NOTIFY rowCountChanged) + Q_PROPERTY(int columnCount READ columnCount WRITE setColumnCount NOTIFY columnCountChanged) + +public: + TestTableModel(QObject *parent = nullptr) + : QAbstractTableModel(parent) + { + } + + int rowCount(const QModelIndex &index = QModelIndex()) const override + { + if (index.isValid()) + return 0; + return m_rows; + } + virtual void setRowCount(int count) + { + beginResetModel(); + m_rows = count; + emit rowCountChanged(); + endResetModel(); + } + + int columnCount(const QModelIndex &index = QModelIndex()) const override + { + if (index.isValid()) + return 0; + return m_cols; + } + virtual void setColumnCount(int count) + { + beginResetModel(); + m_cols = count; + emit columnCountChanged(); + endResetModel(); + } + + int indexValue(const QModelIndex &index) const + { + return index.row() + (index.column() * rowCount()); + } + + Q_INVOKABLE QModelIndex toQModelIndex(int serialIndex) + { + return createIndex(serialIndex % rowCount(), serialIndex / rowCount()); + } + + Q_INVOKABLE QVariant data(int row, int col) + { + return data(createIndex(row, col), Qt::DisplayRole); + } + QVariant data(const QModelIndex &index, int role) const override + { + if (!index.isValid()) + return QVariant(); + + switch (role) { + case Qt::DisplayRole: + return QString("%1, %2, checked: %3 ") + .arg(index.row()) + .arg(index.column()) + .arg(m_checkedCells.contains(indexValue(index))); + case Qt::EditRole: + return m_checkedCells.contains(indexValue(index)); + default: + return QVariant(); + } + } + + bool setData(const QModelIndex &index, const QVariant &value, + int role = Qt::EditRole) override + { + + if (role != Qt::EditRole) + return false; + + int i = indexValue(index); + bool checked = value.toBool(); + if (checked == m_checkedCells.contains(i)) + return false; + + if (checked) + m_checkedCells.insert(i); + else + m_checkedCells.remove(i); + + emit dataChanged(index, index, { role }); + return true; + } + + Q_INVOKABLE QHash<int, QByteArray> roleNames() const override + { + return { + { Qt::DisplayRole, "display" }, + { Qt::EditRole, "edit" } + }; + } + +signals: + void rowCountChanged(); + void columnCountChanged(); + +private: + int m_rows = 0; + int m_cols = 0; + + QSet<int> m_checkedCells; +}; + +class TestTableModelWithHeader : public TestTableModel { + + Q_OBJECT +public: + void setRowCount(int count) override + { + vData.resize(count); + TestTableModel::setRowCount(count); + } + + void setColumnCount(int count) override + { + hData.resize(count); + TestTableModel::setColumnCount(count); + } + Q_INVOKABLE QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const override + { + auto sectionCount = orientation == Qt::Horizontal ? columnCount() : rowCount(); + if (section < 0 || section >= sectionCount) + return QVariant(); + switch (role) { + case Qt::DisplayRole: + case Qt::EditRole: { + auto &data = orientation == Qt::Horizontal ? hData : vData; + return data[section].toString(); + } + default: + return QVariant(); + } + } + Q_INVOKABLE bool setHeaderData(int section, Qt::Orientation orientation, + const QVariant &value, int role = Qt::EditRole) override + { + qDebug() << Q_FUNC_INFO + << "section:" << section + << "orient:" << orientation + << "value:" << value + << "role:" << QAbstractItemModel::roleNames()[role]; + auto sectionCount = orientation == Qt::Horizontal ? columnCount() : rowCount(); + if (section < 0 || section >= sectionCount) + return false; + auto &data = orientation == Qt::Horizontal ? hData : vData; + data[section] = value; + emit headerDataChanged(orientation, section, section); + return true; + } + +private: + QList<QVariant> hData, vData; +}; + +class tst_QQuickHeaderView : public QQmlDataTest { + Q_OBJECT + +private slots: + void initTestCase() override; + void cleanupTestCase(); + void init(); + void cleanup(); + + void defaults(); + void testHeaderDataProxyModel(); + void testOrientation(); + void testModel(); + void listModel(); + +private: + QQmlEngine *engine; + QString errorString; + + std::unique_ptr<QObject> rootObjectFromQml(const char *file) + { + auto component = new QQmlComponent(engine); + component->loadUrl(testFileUrl(file)); + auto root = component->create(); + if (!root) + errorString = component->errorString(); + return std::unique_ptr<QObject>(new QObject(root)); + } +}; + +void tst_QQuickHeaderView::initTestCase() +{ + QQmlDataTest::initTestCase(); + qmlRegisterType<TestTableModel>("TestTableModel", 0, 1, "TestTableModel"); + qmlRegisterType<TestTableModelWithHeader>("TestTableModelWithHeader", 0, 1, "TestTableModelWithHeader"); + qmlRegisterType<QHeaderDataProxyModel>("HeaderDataProxyModel", 0, 1, "HeaderDataProxyModel"); +} + +void tst_QQuickHeaderView::cleanupTestCase() +{ +} + +void tst_QQuickHeaderView::init() +{ + engine = new QQmlEngine(this); +} + +void tst_QQuickHeaderView::cleanup() +{ + if (engine) { + delete engine; + engine = nullptr; + } +} + +void tst_QQuickHeaderView::defaults() +{ + QQmlComponent component(engine); + component.loadUrl(testFileUrl("Window.qml")); + + QScopedPointer<QObject> root(component.create()); + QVERIFY2(root, qPrintable(component.errorString())); + + auto hhv = root->findChild<QQuickHorizontalHeaderView *>("horizontalHeader"); + QVERIFY(hhv); + auto vhv = root->findChild<QQuickVerticalHeaderView *>("verticalHeader"); + QVERIFY(vhv); + auto tm = root->findChild<TestTableModel *>("tableModel"); + QVERIFY(tm); + auto pm = root->findChild<QHeaderDataProxyModel *>("proxyModel"); + QVERIFY(pm); + auto tv = root->findChild<QQuickTableView *>("tableView"); + QVERIFY(tv); +} + +void tst_QQuickHeaderView::testHeaderDataProxyModel() +{ + TestTableModel model; + model.setColumnCount(10); + model.setRowCount(7); + QHeaderDataProxyModel model2; + model2.setSourceModel(&model); + QAbstractItemModelTester tester(&model2, QAbstractItemModelTester::FailureReportingMode::QtTest); +} + +void tst_QQuickHeaderView::testOrientation() +{ + QQmlComponent component(engine); + component.loadUrl(testFileUrl("Window.qml")); + + QScopedPointer<QObject> root(component.create()); + QVERIFY2(root, qPrintable(component.errorString())); + + auto hhv = root->findChild<QQuickHorizontalHeaderView *>("horizontalHeader"); + QVERIFY(hhv); + QCOMPARE(hhv->columns(), 10); + QCOMPARE(hhv->rows(), 1); + auto vhv = root->findChild<QQuickVerticalHeaderView *>("verticalHeader"); + QVERIFY(vhv); + + hhv->setSyncDirection(Qt::Vertical); + hhv->flick(10, 20); + + vhv->setSyncDirection(Qt::Horizontal); + vhv->flick(20, 10); + + QVERIFY(QTest::qWaitForWindowActive(qobject_cast<QWindow *>(root.data()))); + // Explicitly setting a different synDirection is ignored + QCOMPARE(hhv->syncDirection(), Qt::Horizontal); + QCOMPARE(hhv->flickableDirection(), QQuickFlickable::HorizontalFlick); + QCOMPARE(vhv->syncDirection(), Qt::Vertical); + QCOMPARE(vhv->flickableDirection(), QQuickFlickable::VerticalFlick); +} + +void tst_QQuickHeaderView::testModel() +{ + QQmlComponent component(engine); + component.loadUrl(testFileUrl("Window.qml")); + + QScopedPointer<QObject> root(component.create()); + QVERIFY2(root, qPrintable(component.errorString())); + + auto hhv = root->findChild<QQuickHorizontalHeaderView *>("horizontalHeader"); + QVERIFY(hhv); + auto thm = root->findChild<TestTableModel *>("tableHeaderModel"); + QVERIFY(thm); + auto pm = root->findChild<QHeaderDataProxyModel *>("proxyModel"); + QVERIFY(pm); + + QSignalSpy modelChangedSpy(hhv, SIGNAL(modelChanged())); + QVERIFY(modelChangedSpy.isValid()); + + hhv->setModel(QVariant::fromValue(thm)); + QCOMPARE(modelChangedSpy.count(), 0); + + hhv->setModel(QVariant::fromValue(pm)); + QCOMPARE(modelChangedSpy.count(), 1); + + TestTableModel ttm2; + ttm2.setRowCount(100); + ttm2.setColumnCount(30); + hhv->setModel(QVariant::fromValue(&ttm2)); + QCOMPARE(modelChangedSpy.count(), 2); +} + +void tst_QQuickHeaderView::listModel() +{ + QQmlComponent component(engine); + component.loadUrl(testFileUrl("ListModel.qml")); + + QScopedPointer<QObject> root(component.create()); + QVERIFY2(root, qPrintable(component.errorString())); + + if (!QTest::qWaitForWindowActive(qobject_cast<QWindow *>(root.data()))) + QSKIP("Window failed to become active!"); + + auto hhv = root->findChild<QQuickHorizontalHeaderView *>("horizontalHeader"); + QVERIFY(hhv); + auto vhv = root->findChild<QQuickVerticalHeaderView *>("verticalHeader"); + QVERIFY(vhv); + + auto hhvCell1 = hhv->childAt(0, 0)->childAt(0, 0)->findChild<QQuickText *>(); + QVERIFY(hhvCell1); + QCOMPARE(hhvCell1->property("text"), "AAA"); + + auto hhvCell2 = hhv->childAt(hhvCell1->width() + 5, 0)-> + childAt(hhvCell1->width() + 5, 0)->findChild<QQuickText *>(); + QVERIFY(hhvCell2); + QCOMPARE(hhvCell2->property("text"), "BBB"); + + auto vhvCell1 = vhv->childAt(0, 0)->childAt(0, 0)->findChild<QQuickText *>(); + QVERIFY(vhvCell1); + QCOMPARE(vhvCell1->property("text"), "111"); + + auto vhvCell2 = vhv->childAt(0, vhvCell1->height() + 5)-> + childAt(0, vhvCell1->height() + 5)->findChild<QQuickText *>(); + QVERIFY(vhvCell2); + QCOMPARE(vhvCell2->property("text"), "222"); +} + +QTEST_MAIN(tst_QQuickHeaderView) + +#include "tst_qquickheaderview.moc" |