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#ifndef Q_TEST_MODEL_H
30#define Q_TEST_MODEL_H
31
32#include <QtCore/qabstractitemmodel.h>
33
34class TestModel: public QAbstractItemModel
35{
36 Q_OBJECT
37
38public:
39 TestModel(QObject *parent = 0): QAbstractItemModel(parent),
40 fetched(false), rows(10), cols(1), levels(INT_MAX), wrongIndex(false) { init(); }
41
42 TestModel(int _rows, int _cols, QObject *parent = 0): QAbstractItemModel(parent),
43 fetched(false), rows(_rows), cols(_cols), levels(INT_MAX), wrongIndex(false) { init(); }
44
45 void init() {
46 decorationsEnabled = false;
47 alternateChildlessRows = true;
48 tree = new Node(rows);
49 }
50
51 inline qint32 level(const QModelIndex &index) const {
52 Node *n = (Node *)index.internalPointer();
53 if (!n)
54 return -1;
55 int l = -1;
56 while (n != tree) {
57 n = n->parent;
58 ++l;
59 }
60 return l;
61 }
62
63 void resetModel()
64 {
65 beginResetModel();
66 fetched = false;
67 delete tree;
68 tree = new Node(rows);
69 endResetModel();
70 }
71
72 QString displayData(const QModelIndex &idx) const
73 {
74 return QString("[%1,%2,%3,%4]").arg(a: idx.row()).arg(a: idx.column()).arg(a: idx.internalId()).arg(a: hasChildren(parent: idx));
75 }
76
77 bool canFetchMore(const QModelIndex &) const {
78 return !fetched;
79 }
80
81 void fetchMore(const QModelIndex &) {
82 fetched = true;
83 }
84
85 bool hasChildren(const QModelIndex &parent = QModelIndex()) const {
86 bool hasFetched = fetched;
87 fetched = true;
88 bool r = QAbstractItemModel::hasChildren(parent);
89 fetched = hasFetched;
90 return r;
91 }
92
93 int rowCount(const QModelIndex& parent = QModelIndex()) const {
94 if ((parent.column() > 0) || (level(index: parent) > levels)
95 || (alternateChildlessRows && parent.row() > 0 && (parent.row() & 1)))
96 return 0;
97 Node *n = (Node*)parent.internalPointer();
98 if (!n)
99 n = tree;
100 return n->children.count();
101 }
102
103 int columnCount(const QModelIndex& parent = QModelIndex()) const {
104 if ((parent.column() > 0) || (level(index: parent) > levels)
105 || (alternateChildlessRows && parent.row() > 0 && (parent.row() & 1)))
106 return 0;
107 return cols;
108 }
109
110 bool isEditable(const QModelIndex &index) const {
111 if (index.isValid())
112 return true;
113 return false;
114 }
115
116 Q_INVOKABLE QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const
117 {
118 if (row < 0 || column < 0 || (level(index: parent) > levels) || column >= cols)
119 return QModelIndex();
120 Node *pn = (Node*)parent.internalPointer();
121 if (!pn)
122 pn = tree;
123 if (row >= pn->children.count())
124 return QModelIndex();
125
126 Node *n = pn->children.at(i: row);
127 if (!n) {
128 n = new Node(rows, pn);
129 pn->children[row] = n;
130 }
131 return createIndex(arow: row, acolumn: column, adata: n);
132 }
133
134 QModelIndex parent(const QModelIndex &index) const
135 {
136 Node *n = (Node *)index.internalPointer();
137 if (!n || n->parent == tree)
138 return QModelIndex();
139 Q_ASSERT(n->parent->parent);
140 int parentRow = n->parent->parent->children.indexOf(t: n->parent);
141 Q_ASSERT(parentRow != -1);
142 return createIndex(arow: parentRow, acolumn: 0, adata: n->parent);
143 }
144
145 QVariant data(const QModelIndex &idx, int role) const
146 {
147 if (!idx.isValid())
148 return QVariant();
149
150 Node *pn = (Node *)idx.internalPointer();
151 if (!pn)
152 pn = tree;
153 if (pn != tree)
154 pn = pn->parent;
155 if (idx.row() < 0 || idx.column() < 0 || idx.column() >= cols
156 || idx.row() >= pn->children.count()) {
157 wrongIndex = true;
158 qWarning(msg: "Invalid modelIndex [%d,%d,%p]", idx.row(), idx.column(),
159 idx.internalPointer());
160 return QVariant();
161 }
162
163 if (role == Qt::DisplayRole) {
164 return displayData(idx);
165 }
166
167 return QVariant();
168 }
169
170 bool setData(const QModelIndex &index, const QVariant &value, int role)
171 {
172 Q_UNUSED(value);
173 QVector<int> changedRole(1, role);
174 emit dataChanged(topLeft: index, bottomRight: index, roles: changedRole);
175 return true;
176 }
177
178 void groupedSetData(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
179 {
180 emit dataChanged(topLeft, bottomRight, roles);
181 }
182
183 void changeLayout(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>())
184 {
185 emit layoutAboutToBeChanged(parents);
186 emit layoutChanged(parents);
187 }
188
189 bool removeRows(int row, int count, const QModelIndex &parent)
190 {
191 beginRemoveRows(parent, first: row, last: row + count - 1);
192 Node *n = (Node *)parent.internalPointer();
193 if (!n)
194 n = tree;
195 n->removeRows(row, count);
196 endRemoveRows();
197 return true;
198 }
199
200 void removeLastColumn()
201 {
202 beginRemoveColumns(parent: QModelIndex(), first: cols - 1, last: cols - 1);
203 --cols;
204 endRemoveColumns();
205 }
206
207 void removeAllColumns()
208 {
209 beginRemoveColumns(parent: QModelIndex(), first: 0, last: cols - 1);
210 cols = 0;
211 endRemoveColumns();
212 }
213
214 bool insertRows(int row, int count, const QModelIndex &parent)
215 {
216 beginInsertRows(parent, first: row, last: row + count - 1);
217 Node *n = (Node *)parent.internalPointer();
218 if (!n)
219 n = tree;
220 n->addRows(row, count);
221 endInsertRows();
222 return true;
223 }
224
225 bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild)
226 {
227 Q_ASSERT_X(sourceRow >= 0 && sourceRow < rowCount(sourceParent)
228 && count > 0 && sourceRow + count < rowCount(sourceParent)
229 && destinationChild >= 0 && destinationChild <= rowCount(destinationParent),
230 Q_FUNC_INFO, "Rows out of range.");
231 Q_ASSERT_X(!(sourceParent == destinationParent && destinationChild >= sourceRow && destinationChild < sourceRow + count),
232 Q_FUNC_INFO, "Moving rows onto themselves.");
233 if (!beginMoveRows(sourceParent, sourceFirst: sourceRow, sourceLast: sourceRow + count - 1, destinationParent, destinationRow: destinationChild))
234 return false;
235 Node *src = (Node *)sourceParent.internalPointer();
236 if (!src)
237 src = tree;
238 Node *dest = (Node *)destinationParent.internalPointer();
239 if (!dest)
240 dest = tree;
241 QVector<Node *> buffer = src->children.mid(pos: sourceRow, len: count);
242 if (src != dest) {
243 src->removeRows(row: sourceRow, count, keepAlive: true /* keep alive */);
244 dest->addRows(row: destinationChild, count);
245 } else {
246 QVector<Node *> &c = dest->children;
247 if (sourceRow < destinationChild) {
248 memmove(dest: &c[sourceRow], src: &c[sourceRow + count], n: sizeof(Node *) * (destinationChild - sourceRow - count));
249 destinationChild -= count;
250 } else {
251 memmove(dest: &c[destinationChild + count], src: &c[destinationChild], n: sizeof(Node *) * (sourceRow - destinationChild));
252 }
253 }
254 for (int i = 0; i < count; i++) {
255 Node *n = buffer[i];
256 n->parent = dest;
257 dest->children[i + destinationChild] = n;
258 }
259
260 endMoveRows();
261 return true;
262 }
263
264 void setDecorationsEnabled(bool enable)
265 {
266 decorationsEnabled = enable;
267 }
268
269 mutable bool fetched;
270 bool decorationsEnabled;
271 bool alternateChildlessRows;
272 int rows, cols;
273 int levels;
274 mutable bool wrongIndex;
275
276 struct Node {
277 Node *parent;
278 QVector<Node *> children;
279
280 Node(int rows, Node *p = 0) : parent(p)
281 {
282 addRows(row: 0, count: rows);
283 }
284
285 ~Node()
286 {
287 foreach (Node *n, children)
288 delete n;
289 }
290
291 void addRows(int row, int count)
292 {
293 if (count > 0) {
294 children.reserve(asize: children.count() + count);
295 children.insert(i: row, n: count, t: (Node *)0);
296 }
297 }
298
299 void removeRows(int row, int count, bool keepAlive = false)
300 {
301 int newCount = qMax(a: children.count() - count, b: 0);
302 int effectiveCountDiff = children.count() - newCount;
303 if (effectiveCountDiff > 0) {
304 if (!keepAlive)
305 for (int i = 0; i < effectiveCountDiff; i++)
306 delete children[i + row];
307 children.remove(i: row, n: effectiveCountDiff);
308 }
309 }
310 };
311
312 Node *tree;
313};
314
315#endif // Q_TEST_MODEL_H
316

source code of qtdeclarative/tests/auto/qml/qqmlitemmodels/qtestmodel.h