1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include <qtest.h>
30#include <QQmlEngine>
31#include <QQmlComponent>
32#include <QDebug>
33#include <QStringListModel>
34#include "../../shared/util.h"
35#include "testtypes.h"
36#include "qtestmodel.h"
37
38#define INIT_TEST_OBJECT(fileName, object) \
39 QQmlComponent component_##object(&engine, testFileUrl(fileName)); \
40 QScopedPointer<ItemModelsTest>object(qobject_cast<ItemModelsTest *>(component_##object.create())); \
41
42
43class tst_qqmlitemmodels : public QQmlDataTest
44{
45 Q_OBJECT
46
47public:
48 tst_qqmlitemmodels() {}
49
50private slots:
51 void initTestCase();
52
53 void modelIndex();
54 void persistentModelIndex();
55 void modelIndexConversion();
56 void itemSelectionRange();
57 void itemSelection();
58 void modelIndexList();
59
60private:
61 QQmlEngine engine;
62};
63
64void tst_qqmlitemmodels::initTestCase()
65{
66 QQmlDataTest::initTestCase();
67 qmlRegisterType<ItemModelsTest>(uri: "Test", versionMajor: 1, versionMinor: 0, qmlName: "ItemModelsTest");
68}
69
70void tst_qqmlitemmodels::modelIndex()
71{
72 INIT_TEST_OBJECT("modelindex.qml", object);
73 TestModel model(10, 10);
74
75 QModelIndex index = object->modelIndex();
76 for (int i = 0; i < 5; i++) {
77 QCOMPARE(object->property("isValid").toBool(), index.isValid());
78 QCOMPARE(object->property("row").toInt(), index.row());
79 QCOMPARE(object->property("column").toInt(), index.column());
80 QCOMPARE(object->property("parent").toModelIndex(), index.parent());
81 QCOMPARE(object->property("model").value<QAbstractItemModel *>(), index.model());
82 QCOMPARE(object->property("internalId").toULongLong(), index.internalId());
83
84 if (i < 3) {
85 index = model.index(row: 2 + i, column: 4 - i, parent: index);
86 object->setModelIndex(index);
87 } else if (i < 4) {
88 index = model.index(row: 2 + i, column: 4 - i);
89 object->emitSignalWithModelIndex(index);
90 }
91 }
92}
93
94void tst_qqmlitemmodels::persistentModelIndex()
95{
96 INIT_TEST_OBJECT("persistentmodelindex.qml", object);
97 TestModel model(10, 10);
98
99 QPersistentModelIndex index = object->persistentModelIndex();
100 for (int i = 0; i < 5; i++) {
101 QCOMPARE(object->property("isValid").toBool(), index.isValid());
102 QCOMPARE(object->property("row").toInt(), index.row());
103 QCOMPARE(object->property("column").toInt(), index.column());
104 QCOMPARE(object->property("parent").toModelIndex(), index.parent());
105 QCOMPARE(object->property("model").value<QAbstractItemModel *>(), index.model());
106 QCOMPARE(object->property("internalId").toULongLong(), index.internalId());
107
108 if (i < 2) {
109 index = model.index(row: 2 + i, column: 4 - i, parent: index);
110 object->setPersistentModelIndex(index);
111 } else if (i < 3) {
112 model.removeRow(arow: 2);
113 QVERIFY(!index.isValid()); // QPersistentModelIndex should update
114 object->emitChanged(); // Help QML get the new values as QPMI doesn't emit anything
115 } else if (i < 4) {
116 index = model.index(row: 2 + i, column: 4 - i);
117 object->emitSignalWithPersistentModelIndex(index);
118 }
119 }
120
121 const QVariant &pmiVariant = object->property(name: "pmi");
122 QCOMPARE(pmiVariant.userType(), qMetaTypeId<QPersistentModelIndex>());
123 QCOMPARE(pmiVariant.value<QPersistentModelIndex>(), QPersistentModelIndex(model.index(0, 0)));
124}
125
126void tst_qqmlitemmodels::itemSelectionRange()
127{
128 INIT_TEST_OBJECT("itemselectionrange.qml", object);
129 TestModel model(10, 10);
130
131 for (int i = 0; i < 2; i++) {
132 const QVariant &isrVariant = object->property(name: "itemSelectionRange");
133 QCOMPARE(isrVariant.userType(), qMetaTypeId<QItemSelectionRange>());
134 const QItemSelectionRange &isr = isrVariant.value<QItemSelectionRange>();
135 if (i > 0) {
136 QModelIndex parentIndex = model.index(row: 0, column: 0);
137 QCOMPARE(QModelIndex(isr.topLeft()), model.index(3, 0, parentIndex));
138 QCOMPARE(QModelIndex(isr.bottomRight()), model.index(5, 6, parentIndex));
139 } else {
140 QCOMPARE(QModelIndex(isr.topLeft()), QModelIndex());
141 QCOMPARE(QModelIndex(isr.bottomRight()), QModelIndex());
142 }
143
144 QCOMPARE(object->property("top").toInt(), isr.top());
145 QCOMPARE(object->property("left").toInt(), isr.left());
146 QCOMPARE(object->property("bottom").toInt(), isr.bottom());
147 QCOMPARE(object->property("right").toInt(), isr.right());
148 QCOMPARE(object->property("width").toInt(), isr.width());
149 QCOMPARE(object->property("height").toInt(), isr.height());
150 QCOMPARE(object->property("isValid").toBool(), isr.isValid());
151 QCOMPARE(object->property("isEmpty").toBool(), isr.isEmpty());
152 QCOMPARE(object->property("isrModel").value<QAbstractItemModel *>(), isr.model());
153
154 // Set model for the 2nd iteration and test again
155 object->setModel(&model);
156 }
157
158 // Check API function calls
159 QVERIFY(object->property("contains1").toBool());
160 QVERIFY(object->property("contains2").toBool());
161 QVERIFY(!object->property("intersects").toBool());
162 const QVariant &isrVariant = object->property(name: "intersected");
163 QCOMPARE(isrVariant.userType(), qMetaTypeId<QItemSelectionRange>());
164}
165
166void tst_qqmlitemmodels::modelIndexConversion()
167{
168 INIT_TEST_OBJECT("modelindexconversion.qml", object);
169 TestModel model(10, 10);
170 object->setModel(&model);
171
172 QCOMPARE(object->modelIndex(), model.index(0, 0));
173 QCOMPARE(object->persistentModelIndex(), QPersistentModelIndex(model.index(1, 1)));
174}
175
176void tst_qqmlitemmodels::itemSelection()
177{
178 INIT_TEST_OBJECT("itemselection.qml", object);
179 TestModel model(10, 10);
180
181 object->setModel(&model);
182 QCOMPARE(object->property("count").toInt(), 5);
183 QCOMPARE(object->property("contains").toBool(), true);
184
185 const char *propNames[] = { "itemSelectionRead", "itemSelectionBinding", nullptr };
186 for (const char **name = propNames; *name; name++) {
187 QVariant isVariant = object->property(name: *name);
188 QCOMPARE(isVariant.userType(), qMetaTypeId<QItemSelection>());
189
190 const QItemSelection &sel = isVariant.value<QItemSelection>();
191 QCOMPARE(sel.count(), object->itemSelection().count());
192 QCOMPARE(sel, object->itemSelection());
193 }
194}
195
196void tst_qqmlitemmodels::modelIndexList()
197{
198 INIT_TEST_OBJECT("modelindexlist.qml", object);
199 TestModel model(10, 10);
200 model.fetchMore(QModelIndex());
201
202 object->setModel(&model);
203 QVERIFY(object->property("propIsArray").toBool());
204 QVERIFY(object->property("varPropIsArray").toBool());
205 QVERIFY(object->property("varIsArray").toBool());
206
207 QCOMPARE(object->property("count").toInt(), 10);
208 const QModelIndexList &mil = object->modelIndexList();
209 QCOMPARE(mil.count(), 4);
210 for (int i = 0; i < 3; i++)
211 QCOMPARE(mil.at(i), model.index(2 + i, 2 + i));
212 QCOMPARE(mil.at(3), QModelIndex()); // The string inserted at the end should result in an invalid index
213 QCOMPARE(mil.at(0), object->modelIndex());
214
215 QVariant cppMILVariant = object->property(name: "modelIndexListCopy");
216 QCOMPARE(cppMILVariant.userType(), qMetaTypeId<QModelIndexList>());
217 QModelIndexList someMIL = object->someModelIndexList();
218 QCOMPARE(cppMILVariant.value<QModelIndexList>(), someMIL);
219
220 const char *propNames[] = { "modelIndexListRead", "modelIndexListBinding", nullptr };
221 for (const char **name = propNames; *name; name++) {
222 QVariant milVariant = object->property(name: *name);
223 QCOMPARE(milVariant.userType(), qMetaTypeId<QModelIndexList>());
224
225 const QModelIndexList &milProp = milVariant.value<QModelIndexList>();
226 QCOMPARE(milProp.count(), mil.count());
227 QCOMPARE(milProp, mil);
228 }
229}
230
231#undef INIT_TEST_OBJECT
232
233QTEST_MAIN(tst_qqmlitemmodels)
234
235#include "tst_qqmlitemmodels.moc"
236

source code of qtdeclarative/tests/auto/qml/qqmlitemmodels/tst_qqmlitemmodels.cpp