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 <QtTest/QtTest> |
30 | #include <QtCore/QCoreApplication> |
31 | #include <qdebug.h> |
32 | #include "modelstotest.cpp" |
33 | #include <QMetaType> |
34 | |
35 | /*! |
36 | See modelstotest.cpp for instructions on how to have your model tested with these tests. |
37 | |
38 | Each test such as rowCount have a _data() function which populate the QTest data with |
39 | the tests specified by modelstotest.cpp and any extra data needed for that particular test. |
40 | |
41 | setupWithNoTestData() fills the QTest data with just the tests and is used by most tests. |
42 | */ |
43 | class tst_QItemModel : public QObject |
44 | { |
45 | Q_OBJECT |
46 | |
47 | public: |
48 | tst_QItemModel(); |
49 | |
50 | public slots: |
51 | void init(); |
52 | void cleanup(); |
53 | |
54 | private slots: |
55 | void nonDestructiveBasicTest_data(); |
56 | void nonDestructiveBasicTest(); |
57 | |
58 | void rowCount_data(); |
59 | void rowCount(); |
60 | void columnCount_data(); |
61 | void columnCount(); |
62 | |
63 | void hasIndex_data(); |
64 | void hasIndex(); |
65 | void index_data(); |
66 | void index(); |
67 | |
68 | void parent_data(); |
69 | void parent(); |
70 | |
71 | void data_data(); |
72 | void data(); |
73 | |
74 | void setData_data(); |
75 | void setData(); |
76 | |
77 | void setHeaderData_data(); |
78 | void setHeaderData(); |
79 | |
80 | void remove_data(); |
81 | void remove(); |
82 | |
83 | void insert_data(); |
84 | void insert(); |
85 | |
86 | void sort_data(); |
87 | void sort(); |
88 | |
89 | protected slots: |
90 | void slot_rowsAboutToRemove(const QModelIndex &parent); |
91 | void slot_rowsRemoved(const QModelIndex &parent); |
92 | void slot_columnsAboutToRemove(const QModelIndex &parent); |
93 | void slot_columnsRemoved(const QModelIndex &parent); |
94 | |
95 | void slot_rowsAboutToInserted(const QModelIndex &parent); |
96 | void slot_rowsInserted(const QModelIndex &parent); |
97 | void slot_columnsAboutToInserted(const QModelIndex &parent); |
98 | void slot_columnsInserted(const QModelIndex &parent); |
99 | private: |
100 | void setupWithNoTestData(); |
101 | QAbstractItemModel *currentModel; |
102 | ModelsToTest *testModels; |
103 | |
104 | // used by remove() |
105 | QPersistentModelIndex parentOfRemoved; |
106 | int afterAboutToRemoveRowCount; |
107 | int afterRemoveRowCount; |
108 | int afterAboutToRemoveColumnCount; |
109 | int afterRemoveColumnCount; |
110 | |
111 | // remove() recursive |
112 | bool removeRecursively; |
113 | |
114 | // used by insert() |
115 | QPersistentModelIndex parentOfInserted; |
116 | int afterAboutToInsertRowCount; |
117 | int afterInsertRowCount; |
118 | int afterAboutToInsertColumnCount; |
119 | int afterInsertColumnCount; |
120 | |
121 | // insert() recursive |
122 | bool insertRecursively; |
123 | }; |
124 | |
125 | tst_QItemModel::tst_QItemModel() |
126 | { |
127 | qRegisterMetaType<QAbstractItemModel::LayoutChangeHint>(); |
128 | qRegisterMetaType<QList<QPersistentModelIndex>>(); |
129 | } |
130 | |
131 | void tst_QItemModel::init() |
132 | { |
133 | testModels = new ModelsToTest(); |
134 | removeRecursively = false; |
135 | insertRecursively = false; |
136 | } |
137 | |
138 | void tst_QItemModel::cleanup() |
139 | { |
140 | testModels->cleanupTestArea(model: currentModel); |
141 | delete testModels; |
142 | delete currentModel; |
143 | currentModel = 0; |
144 | } |
145 | |
146 | void tst_QItemModel::setupWithNoTestData() |
147 | { |
148 | ModelsToTest modelsToTest; |
149 | QTest::addColumn<QString>(name: "modelType" ); |
150 | QTest::addColumn<bool>(name: "readOnly" ); |
151 | QTest::addColumn<bool>(name: "isEmpty" ); |
152 | for (int i = 0; i < modelsToTest.tests.size(); ++i) { |
153 | ModelsToTest::test t = modelsToTest.tests.at(i); |
154 | bool readOnly = (t.read == ModelsToTest::ReadOnly); |
155 | bool isEmpty = (t.contains == ModelsToTest::Empty); |
156 | QTest::newRow(dataTag: t.modelType.toLatin1().data()) << t.modelType << readOnly << isEmpty; |
157 | } |
158 | } |
159 | |
160 | void tst_QItemModel::nonDestructiveBasicTest_data() |
161 | { |
162 | setupWithNoTestData(); |
163 | } |
164 | |
165 | /*! |
166 | nonDestructiveBasicTest tries to call a number of the basic functions (not all) |
167 | to make sure the model doesn't segfault, testing the functions that makes sense. |
168 | */ |
169 | void tst_QItemModel::nonDestructiveBasicTest() |
170 | { |
171 | QFETCH(QString, modelType); |
172 | currentModel = testModels->createModel(modelType); |
173 | QVERIFY(currentModel); |
174 | |
175 | QCOMPARE(currentModel->buddy(QModelIndex()), QModelIndex()); |
176 | currentModel->canFetchMore(parent: QModelIndex()); |
177 | QVERIFY(currentModel->columnCount(QModelIndex()) >= 0); |
178 | QCOMPARE(currentModel->data(QModelIndex()), QVariant()); |
179 | currentModel->fetchMore(parent: QModelIndex()); |
180 | Qt::ItemFlags flags = currentModel->flags(index: QModelIndex()); |
181 | QVERIFY(flags == Qt::ItemIsDropEnabled || flags == 0); |
182 | currentModel->hasChildren(parent: QModelIndex()); |
183 | currentModel->hasIndex(row: 0, column: 0); |
184 | currentModel->headerData(section: 0, orientation: Qt::Horizontal); |
185 | currentModel->index(row: 0,column: 0); |
186 | currentModel->itemData(index: QModelIndex()); |
187 | QVariant cache; |
188 | currentModel->match(start: QModelIndex(), role: -1, value: cache); |
189 | currentModel->mimeTypes(); |
190 | QCOMPARE(currentModel->parent(QModelIndex()), QModelIndex()); |
191 | QVERIFY(currentModel->rowCount() >= 0); |
192 | QVariant variant; |
193 | currentModel->setData(index: QModelIndex(), value: variant, role: -1); |
194 | currentModel->setHeaderData(section: -1, orientation: Qt::Horizontal, value: QVariant()); |
195 | currentModel->setHeaderData(section: 0, orientation: Qt::Horizontal, value: QVariant()); |
196 | currentModel->setHeaderData(section: currentModel->columnCount() + 100, orientation: Qt::Horizontal, value: QVariant()); |
197 | QMap<int, QVariant> roles; |
198 | currentModel->setItemData(index: QModelIndex(), roles); |
199 | currentModel->sibling(row: 0,column: 0,idx: QModelIndex()); |
200 | currentModel->span(index: QModelIndex()); |
201 | currentModel->supportedDropActions(); |
202 | currentModel->revert(); |
203 | currentModel->submit(); |
204 | } |
205 | |
206 | |
207 | void tst_QItemModel::rowCount_data() |
208 | { |
209 | setupWithNoTestData(); |
210 | } |
211 | |
212 | /*! |
213 | Tests model's implimentation of QAbstractItemModel::rowCount() and hasChildren() |
214 | */ |
215 | void tst_QItemModel::rowCount() |
216 | { |
217 | QFETCH(QString, modelType); |
218 | currentModel = testModels->createModel(modelType); |
219 | QVERIFY(currentModel); |
220 | |
221 | QFETCH(bool, isEmpty); |
222 | if (isEmpty) { |
223 | QCOMPARE(currentModel->rowCount(), 0); |
224 | QCOMPARE(currentModel->hasChildren(), false); |
225 | } |
226 | else { |
227 | QVERIFY(currentModel->rowCount() > 0); |
228 | QCOMPARE(currentModel->hasChildren(), true); |
229 | } |
230 | |
231 | // check top row |
232 | QModelIndex topIndex = currentModel->index(row: 0, column: 0, parent: QModelIndex()); |
233 | int rows = currentModel->rowCount(parent: topIndex); |
234 | QVERIFY(rows >= 0); |
235 | if (rows > 0) |
236 | QCOMPARE(currentModel->hasChildren(topIndex), true); |
237 | else |
238 | QCOMPARE(currentModel->hasChildren(topIndex), false); |
239 | |
240 | QModelIndex secondLevelIndex = currentModel->index(row: 0, column: 0, parent: topIndex); |
241 | if (secondLevelIndex.isValid()) { // not the top level |
242 | // check a row count where parent is valid |
243 | rows = currentModel->rowCount(parent: secondLevelIndex); |
244 | QVERIFY(rows >= 0); |
245 | if (rows > 0) |
246 | QCOMPARE(currentModel->hasChildren(secondLevelIndex), true); |
247 | else |
248 | QCOMPARE(currentModel->hasChildren(secondLevelIndex), false); |
249 | } |
250 | |
251 | // rowCount is tested more extensivly more later in checkChildren(), |
252 | // but this catches the big mistakes |
253 | } |
254 | |
255 | void tst_QItemModel::columnCount_data() |
256 | { |
257 | setupWithNoTestData(); |
258 | } |
259 | |
260 | /*! |
261 | Tests model's implimentation of QAbstractItemModel::columnCount() and hasChildren() |
262 | */ |
263 | void tst_QItemModel::columnCount() |
264 | { |
265 | QFETCH(QString, modelType); |
266 | currentModel = testModels->createModel(modelType); |
267 | QVERIFY(currentModel); |
268 | |
269 | QFETCH(bool, isEmpty); |
270 | if (isEmpty) { |
271 | QCOMPARE(currentModel->hasChildren(), false); |
272 | } |
273 | else { |
274 | QVERIFY(currentModel->columnCount() > 0); |
275 | QCOMPARE(currentModel->hasChildren(), true); |
276 | } |
277 | |
278 | // check top row |
279 | QModelIndex topIndex = currentModel->index(row: 0, column: 0, parent: QModelIndex()); |
280 | int columns = currentModel->columnCount(parent: topIndex); |
281 | |
282 | // check a row count where parent is valid |
283 | columns = currentModel->columnCount(parent: currentModel->index(row: 0, column: 0, parent: topIndex)); |
284 | QVERIFY(columns >= 0); |
285 | |
286 | // columnCount is tested more extensivly more later in checkChildren(), |
287 | // but this catches the big mistakes |
288 | } |
289 | |
290 | void tst_QItemModel::hasIndex_data() |
291 | { |
292 | setupWithNoTestData(); |
293 | } |
294 | |
295 | /*! |
296 | Tests model's implimentation of QAbstractItemModel::hasIndex() |
297 | */ |
298 | void tst_QItemModel::hasIndex() |
299 | { |
300 | QFETCH(QString, modelType); |
301 | currentModel = testModels->createModel(modelType); |
302 | QVERIFY(currentModel); |
303 | |
304 | // Make sure that invalid values returns an invalid index |
305 | QCOMPARE(currentModel->hasIndex(-2, -2), false); |
306 | QCOMPARE(currentModel->hasIndex(-2, 0), false); |
307 | QCOMPARE(currentModel->hasIndex(0, -2), false); |
308 | |
309 | int rows = currentModel->rowCount(); |
310 | int columns = currentModel->columnCount(); |
311 | |
312 | QCOMPARE(currentModel->hasIndex(rows, columns), false); |
313 | QCOMPARE(currentModel->hasIndex(rows+1, columns+1), false); |
314 | |
315 | QFETCH(bool, isEmpty); |
316 | if (isEmpty) |
317 | return; |
318 | |
319 | QCOMPARE(currentModel->hasIndex(0,0), true); |
320 | |
321 | // hasIndex is tested more extensivly more later in checkChildren(), |
322 | // but this catches the big mistakes |
323 | } |
324 | |
325 | void tst_QItemModel::index_data() |
326 | { |
327 | setupWithNoTestData(); |
328 | } |
329 | |
330 | /*! |
331 | Tests model's implimentation of QAbstractItemModel::index() |
332 | */ |
333 | void tst_QItemModel::index() |
334 | { |
335 | QFETCH(QString, modelType); |
336 | currentModel = testModels->createModel(modelType); |
337 | QVERIFY(currentModel); |
338 | |
339 | // Make sure that invalid values returns an invalid index |
340 | QCOMPARE(currentModel->index(-2, -2), QModelIndex()); |
341 | QCOMPARE(currentModel->index(-2, 0), QModelIndex()); |
342 | QCOMPARE(currentModel->index(0, -2), QModelIndex()); |
343 | |
344 | QFETCH(bool, isEmpty); |
345 | if (isEmpty) |
346 | return; |
347 | |
348 | int rows = currentModel->rowCount(); |
349 | int columns = currentModel->columnCount(); |
350 | |
351 | // Catch off by one errors |
352 | QCOMPARE(currentModel->index(rows,columns), QModelIndex()); |
353 | QCOMPARE(currentModel->index(0,0).isValid(), true); |
354 | |
355 | // Make sure that the same index is always returned |
356 | QModelIndex a = currentModel->index(row: 0,column: 0); |
357 | QModelIndex b = currentModel->index(row: 0,column: 0); |
358 | QCOMPARE(a, b); |
359 | |
360 | // index is tested more extensivly more later in checkChildren(), |
361 | // but this catches the big mistakes |
362 | } |
363 | |
364 | |
365 | void tst_QItemModel::parent_data() |
366 | { |
367 | setupWithNoTestData(); |
368 | } |
369 | |
370 | /*! |
371 | A model that returns an index of parent X should also return X when asking |
372 | for the parent of the index. |
373 | |
374 | This recursive function does pretty extensive testing on the whole model in an |
375 | effort to catch edge cases. |
376 | |
377 | This function assumes that rowCount(), columnCount() and index() work. If they have |
378 | a bug it will point it out, but the above tests should have already found the basic bugs |
379 | because it is easier to figure out the problem in those tests then this one. |
380 | */ |
381 | void checkChildren(QAbstractItemModel *currentModel, const QModelIndex &parent, int currentDepth=0) |
382 | { |
383 | QFETCH(bool, readOnly); |
384 | |
385 | if (currentModel->canFetchMore(parent)) |
386 | currentModel->fetchMore(parent); |
387 | |
388 | int rows = currentModel->rowCount(parent); |
389 | int columns = currentModel->columnCount(parent); |
390 | |
391 | const QModelIndex topLeftChild = currentModel->index( row: 0, column: 0, parent ); |
392 | |
393 | QCOMPARE(rows > 0, (currentModel->hasChildren(parent))); |
394 | |
395 | // Some reasuring testing against rows(),columns(), and hasChildren() |
396 | QVERIFY(rows >= 0); |
397 | QVERIFY(columns >= 0); |
398 | if (rows > 0 || columns > 0) |
399 | QCOMPARE(currentModel->hasChildren(parent), true); |
400 | else |
401 | QCOMPARE(currentModel->hasChildren(parent), false); |
402 | |
403 | QCOMPARE(currentModel->hasIndex(rows+1, 0, parent), false); |
404 | for (int r = 0; r < rows; ++r) { |
405 | if (currentModel->canFetchMore(parent)) |
406 | currentModel->fetchMore(parent); |
407 | |
408 | QCOMPARE(currentModel->hasIndex(r, columns+1, parent), false); |
409 | for (int c = 0; c < columns; ++c) { |
410 | QCOMPARE(currentModel->hasIndex(r, c, parent), true); |
411 | QModelIndex index = currentModel->index(row: r, column: c, parent); |
412 | QCOMPARE(index.isValid(), true); |
413 | |
414 | if (!readOnly) |
415 | currentModel->setData(index, value: "I'm a little tea pot short and stout" ); |
416 | QModelIndex modifiedIndex = currentModel->index(row: r, column: c, parent); |
417 | QCOMPARE(index, modifiedIndex); |
418 | |
419 | // Make sure we get the same index if we request it twice in a row |
420 | QModelIndex a = currentModel->index(row: r, column: c, parent); |
421 | QModelIndex b = currentModel->index(row: r, column: c, parent); |
422 | QCOMPARE(a, b); |
423 | |
424 | { |
425 | const QModelIndex sibling = currentModel->sibling( row: r, column: c, idx: topLeftChild ); |
426 | QVERIFY( index == sibling ); |
427 | } |
428 | { |
429 | const QModelIndex sibling = topLeftChild.sibling( arow: r, acolumn: c ); |
430 | QVERIFY( index == sibling ); |
431 | } |
432 | if (r == topLeftChild.row()) { |
433 | const QModelIndex sibling = topLeftChild.siblingAtColumn( acolumn: c ); |
434 | QVERIFY( index == sibling ); |
435 | } |
436 | if (c == topLeftChild.column()) { |
437 | const QModelIndex sibling = topLeftChild.siblingAtRow( arow: r ); |
438 | QVERIFY( index == sibling ); |
439 | } |
440 | |
441 | // Some basic checking on the index that is returned |
442 | QCOMPARE(index.model(), currentModel); |
443 | QCOMPARE(index.row(), r); |
444 | QCOMPARE(index.column(), c); |
445 | QCOMPARE(currentModel->data(index, Qt::DisplayRole).isValid(), true); |
446 | |
447 | // If the next test fails here is some somewhat useful debug you play with. |
448 | /* |
449 | if (currentModel->parent(index) != parent) { |
450 | qDebug() << r << c << currentDepth << currentModel->data(index).toString() |
451 | << currentModel->data(parent).toString(); |
452 | qDebug() << index << parent << currentModel->parent(index); |
453 | QTreeView view; |
454 | view.setModel(currentModel); |
455 | view.show(); |
456 | QTest::qWait(9000); |
457 | }*/ |
458 | QCOMPARE(currentModel->parent(index), parent); |
459 | |
460 | // recursivly go down |
461 | if (currentModel->hasChildren(parent: index) && currentDepth < 5) { |
462 | checkChildren(currentModel, parent: index, currentDepth: ++currentDepth); |
463 | // Because this is recursive we will return at the first failure rather then |
464 | // reporting it over and over |
465 | if (QTest::currentTestFailed()) |
466 | return; |
467 | } |
468 | |
469 | // make sure that after testing the children that the index pointer doesn't change. |
470 | QModelIndex newerIndex = currentModel->index(row: r, column: c, parent); |
471 | QCOMPARE(index, newerIndex); |
472 | } |
473 | } |
474 | } |
475 | |
476 | /*! |
477 | Tests model's implimentation of QAbstractItemModel::parent() |
478 | */ |
479 | void tst_QItemModel::parent() |
480 | { |
481 | QFETCH(QString, modelType); |
482 | currentModel = testModels->createModel(modelType); |
483 | QVERIFY(currentModel); |
484 | |
485 | // Make sure the model won't crash and will return an invalid QModelIndex |
486 | // when asked for the parent of an invalid index. |
487 | QCOMPARE(currentModel->parent(QModelIndex()), QModelIndex()); |
488 | |
489 | QFETCH(bool, isEmpty); |
490 | if (isEmpty) |
491 | return; |
492 | |
493 | // Common error test #1, make sure that a top level index has a parent |
494 | // that is a invalid QModelIndex. You model |
495 | QModelIndex topIndex = currentModel->index(row: 0, column: 0, parent: QModelIndex()); |
496 | QCOMPARE(currentModel->parent(topIndex), QModelIndex()); |
497 | |
498 | // Common error test #2, make sure that a second level index has a parent |
499 | // that is the top level index. |
500 | if (currentModel->rowCount(parent: topIndex) > 0) { |
501 | QModelIndex childIndex = currentModel->index(row: 0, column: 0, parent: topIndex); |
502 | QCOMPARE(currentModel->parent(childIndex), topIndex); |
503 | } |
504 | |
505 | // Common error test #3, the second column has the same children |
506 | // as the first column in a row. |
507 | QModelIndex topIndex1 = currentModel->index(row: 0, column: 1, parent: QModelIndex()); |
508 | if (currentModel->rowCount(parent: topIndex1) > 0) { |
509 | QModelIndex childIndex = currentModel->index(row: 0, column: 0, parent: topIndex); |
510 | QModelIndex childIndex1 = currentModel->index(row: 0, column: 0, parent: topIndex1); |
511 | QVERIFY(childIndex != childIndex1); |
512 | } |
513 | |
514 | // Full test, walk 10 levels deap through the model making sure that all |
515 | // parents's children correctly specify their parent |
516 | QModelIndex top = QModelIndex(); |
517 | checkChildren(currentModel, parent: top); |
518 | } |
519 | |
520 | |
521 | void tst_QItemModel::data_data() |
522 | { |
523 | setupWithNoTestData(); |
524 | } |
525 | |
526 | /*! |
527 | Tests model's implimentation of QAbstractItemModel::data() |
528 | */ |
529 | void tst_QItemModel::data() |
530 | { |
531 | QFETCH(QString, modelType); |
532 | currentModel = testModels->createModel(modelType); |
533 | QVERIFY(currentModel); |
534 | |
535 | // Invalid index should return an invalid qvariant |
536 | QVERIFY(!currentModel->data(QModelIndex()).isValid()); |
537 | |
538 | QFETCH(bool, isEmpty); |
539 | if (isEmpty) |
540 | return; |
541 | |
542 | // A valid index should have a valid qvariant data |
543 | QVERIFY(currentModel->index(0,0).isValid()); |
544 | |
545 | // General Purpose roles |
546 | QVariant variant = currentModel->data(index: currentModel->index(row: 0,column: 0), role: Qt::ToolTipRole); |
547 | if (variant.isValid()) { |
548 | QVERIFY(variant.canConvert<QString>()); |
549 | } |
550 | variant = currentModel->data(index: currentModel->index(row: 0,column: 0), role: Qt::StatusTipRole); |
551 | if (variant.isValid()) { |
552 | QVERIFY(variant.canConvert<QString>()); |
553 | } |
554 | variant = currentModel->data(index: currentModel->index(row: 0,column: 0), role: Qt::WhatsThisRole); |
555 | if (variant.isValid()) { |
556 | QVERIFY(variant.canConvert<QString>()); |
557 | } |
558 | |
559 | variant = currentModel->data(index: currentModel->index(row: 0,column: 0), role: Qt::SizeHintRole); |
560 | if (variant.isValid()) { |
561 | QVERIFY(variant.canConvert<QSize>()); |
562 | } |
563 | |
564 | |
565 | // Appearance roles |
566 | QVariant fontVariant = currentModel->data(index: currentModel->index(row: 0,column: 0), role: Qt::FontRole); |
567 | if (fontVariant.isValid()) { |
568 | QVERIFY(fontVariant.canConvert<QFont>()); |
569 | } |
570 | |
571 | QVariant textAlignmentVariant = currentModel->data(index: currentModel->index(row: 0,column: 0), role: Qt::TextAlignmentRole); |
572 | if (textAlignmentVariant.isValid()) { |
573 | int alignment = textAlignmentVariant.toInt(); |
574 | QVERIFY(alignment == Qt::AlignLeft || |
575 | alignment == Qt::AlignRight || |
576 | alignment == Qt::AlignHCenter || |
577 | alignment == Qt::AlignJustify); |
578 | } |
579 | |
580 | QVariant colorVariant = currentModel->data(index: currentModel->index(row: 0,column: 0), role: Qt::BackgroundRole); |
581 | if (colorVariant.isValid()) { |
582 | QVERIFY(colorVariant.canConvert<QColor>()); |
583 | } |
584 | |
585 | colorVariant = currentModel->data(index: currentModel->index(row: 0,column: 0), role: Qt::ForegroundRole); |
586 | if (colorVariant.isValid()) { |
587 | QVERIFY(colorVariant.canConvert<QColor>()); |
588 | } |
589 | |
590 | QVariant checkStateVariant = currentModel->data(index: currentModel->index(row: 0,column: 0), role: Qt::CheckStateRole); |
591 | if (checkStateVariant.isValid()) { |
592 | int state = checkStateVariant.toInt(); |
593 | QVERIFY(state == Qt::Unchecked || |
594 | state == Qt::PartiallyChecked || |
595 | state == Qt::Checked); |
596 | } |
597 | } |
598 | |
599 | void tst_QItemModel::setData_data() |
600 | { |
601 | setupWithNoTestData(); |
602 | } |
603 | |
604 | /*! |
605 | Tests model's implimentation of QAbstractItemModel::setData() |
606 | */ |
607 | void tst_QItemModel::setData() |
608 | { |
609 | QFETCH(QString, modelType); |
610 | currentModel = testModels->createModel(modelType); |
611 | QVERIFY(currentModel); |
612 | QSignalSpy spy(currentModel, &QAbstractItemModel::dataChanged); |
613 | QVERIFY(spy.isValid()); |
614 | QCOMPARE(spy.count(), 0); |
615 | |
616 | QFETCH(bool, isEmpty); |
617 | if (isEmpty) |
618 | return; |
619 | |
620 | QFETCH(bool, readOnly); |
621 | if (readOnly) |
622 | return; |
623 | |
624 | // Populate the test area so we can chage stuff. See: cleanup() |
625 | QModelIndex topIndex = testModels->populateTestArea(model: currentModel); |
626 | QVERIFY(currentModel->hasChildren(topIndex)); |
627 | QModelIndex index = currentModel->index(row: 0, column: 0, parent: topIndex); |
628 | QVERIFY(index.isValid()); |
629 | |
630 | spy.clear(); |
631 | QString text = "Index private pointers should always be the same" ; |
632 | QCOMPARE(currentModel->setData(index, text, Qt::EditRole), true); |
633 | QCOMPARE(index.data(Qt::EditRole).toString(), text); |
634 | |
635 | // Changing the text shouldn't change the layout, parent, pointer etc. |
636 | QModelIndex changedIndex = currentModel->index(row: 0, column: 0, parent: topIndex); |
637 | QCOMPARE(changedIndex, index); |
638 | QCOMPARE(spy.count(), 1); |
639 | } |
640 | |
641 | void tst_QItemModel::() |
642 | { |
643 | setupWithNoTestData(); |
644 | } |
645 | |
646 | /*! |
647 | Tests model's implimentation of QAbstractItemModel::setHeaderData() |
648 | */ |
649 | void tst_QItemModel::() |
650 | { |
651 | QFETCH(QString, modelType); |
652 | currentModel = testModels->createModel(modelType); |
653 | QVERIFY(currentModel); |
654 | |
655 | QCOMPARE(currentModel->setHeaderData(-1, Qt::Horizontal, QVariant()), false); |
656 | QCOMPARE(currentModel->setHeaderData(-1, Qt::Vertical, QVariant()), false); |
657 | |
658 | QFETCH(bool, isEmpty); |
659 | if (isEmpty) |
660 | return; |
661 | |
662 | QFETCH(bool, readOnly); |
663 | if (readOnly) |
664 | return; |
665 | |
666 | // Populate the test area so we can change stuff. See: cleanup() |
667 | QModelIndex topIndex = testModels->populateTestArea(model: currentModel); |
668 | QVERIFY(currentModel->hasChildren(topIndex)); |
669 | QModelIndex index = currentModel->index(row: 0, column: 0, parent: topIndex); |
670 | QVERIFY(index.isValid()); |
671 | |
672 | qRegisterMetaType<Qt::Orientation>(typeName: "Qt::Orientation" ); |
673 | QSignalSpy spy(currentModel, &QAbstractItemModel::headerDataChanged); |
674 | QVERIFY(spy.isValid()); |
675 | |
676 | QString text = "Index private pointers should always be the same" ; |
677 | int signalCount = 0; |
678 | for (int i = 0; i < 4; ++i){ |
679 | if(currentModel->setHeaderData(section: i, orientation: Qt::Horizontal, value: text)) { |
680 | QCOMPARE(currentModel->headerData(i, Qt::Horizontal).toString(), text); |
681 | ++signalCount; |
682 | } |
683 | if(currentModel->setHeaderData(section: i, orientation: Qt::Vertical, value: text)) { |
684 | QCOMPARE(currentModel->headerData(i, Qt::Vertical).toString(), text); |
685 | ++signalCount; |
686 | } |
687 | } |
688 | QCOMPARE(spy.count(), signalCount); |
689 | } |
690 | |
691 | void tst_QItemModel::sort_data() |
692 | { |
693 | setupWithNoTestData(); |
694 | } |
695 | |
696 | /*! |
697 | Tests model's implimentation of QAbstractItemModel::sort() |
698 | */ |
699 | void tst_QItemModel::sort() |
700 | { |
701 | QFETCH(QString, modelType); |
702 | currentModel = testModels->createModel(modelType); |
703 | QVERIFY(currentModel); |
704 | |
705 | QFETCH(bool, isEmpty); |
706 | if (isEmpty) |
707 | return; |
708 | |
709 | // Populate the test area so we can chage stuff. See: cleanup() |
710 | QPersistentModelIndex topIndex = testModels->populateTestArea(model: currentModel); |
711 | QVERIFY(currentModel->hasChildren(topIndex)); |
712 | QModelIndex index = currentModel->index(row: 0, column: 0, parent: topIndex); |
713 | QVERIFY(index.isValid()); |
714 | QSignalSpy spy(currentModel, &QAbstractItemModel::layoutChanged); |
715 | QVERIFY(spy.isValid()); |
716 | for (int i=-1; i < 10; ++i){ |
717 | currentModel->sort(column: i); |
718 | if (index != currentModel->index(row: 0, column: 0, parent: topIndex)){ |
719 | QVERIFY(spy.count() > 0); |
720 | index = currentModel->index(row: 0, column: 0, parent: topIndex); |
721 | spy.clear(); |
722 | } |
723 | } |
724 | currentModel->sort(column: 99999); |
725 | } |
726 | |
727 | /*! |
728 | Tests model's implimentation of QAbstractItemModel::removeRow() and QAbstractItemModel::removeColumn() |
729 | */ |
730 | #define START 0 |
731 | #define MIDDLE 6 |
732 | #define END -1 |
733 | #define MANY 9 |
734 | #define ALL -1 |
735 | #define NOSIGNALS 0 |
736 | #define DEFAULTCOUNT 1 |
737 | #define DNS 1 // DefaultNumberOfSignals |
738 | #define RECURSIVE true |
739 | #define SUCCESS true |
740 | #define FAIL false |
741 | void tst_QItemModel::remove_data() |
742 | { |
743 | ModelsToTest modelsToTest; |
744 | QTest::addColumn<QString>(name: "modelType" ); |
745 | QTest::addColumn<bool>(name: "readOnly" ); |
746 | QTest::addColumn<bool>(name: "isEmpty" ); |
747 | |
748 | QTest::addColumn<int>(name: "start" ); |
749 | QTest::addColumn<int>(name: "count" ); |
750 | |
751 | QTest::addColumn<int>(name: "numberOfRowsAboutToBeRemovedSignals" ); |
752 | QTest::addColumn<int>(name: "numberOfColumnsAboutToBeRemovedSignals" ); |
753 | QTest::addColumn<int>(name: "numberOfRowsRemovedSignals" ); |
754 | QTest::addColumn<int>(name: "numberOfColumnsRemovedSignals" ); |
755 | |
756 | QTest::addColumn<bool>(name: "recursive" ); |
757 | QTest::addColumn<int>(name: "recursiveRow" ); |
758 | QTest::addColumn<int>(name: "recursiveCount" ); |
759 | |
760 | QTest::addColumn<bool>(name: "shouldSucceed" ); |
761 | |
762 | #define makeTestRow(testName, start, count, sar, srr, sac, src, r, rr, rc, s) \ |
763 | QTest::newRow((t.modelType + testName).toLatin1().data()) << t.modelType << readOnly << isEmpty << \ |
764 | start << count << \ |
765 | sar << srr << sac << src << \ |
766 | r << rr << rc << \ |
767 | s; |
768 | |
769 | for (int i = 0; i < modelsToTest.tests.size(); ++i) { |
770 | ModelsToTest::test t = modelsToTest.tests.at(i); |
771 | QString name = t.modelType; |
772 | bool readOnly = (t.read == ModelsToTest::ReadOnly); |
773 | bool isEmpty = (t.contains == ModelsToTest::Empty); |
774 | |
775 | // half these |
776 | makeTestRow(":one at the start" , START, DEFAULTCOUNT, DNS, DNS, DNS, DNS, !RECURSIVE, 0, 0, SUCCESS); |
777 | makeTestRow(":one at the middle" , MIDDLE, DEFAULTCOUNT, DNS, DNS, DNS, DNS, !RECURSIVE, 0, 0, SUCCESS); |
778 | makeTestRow(":one at the end" , END, DEFAULTCOUNT, DNS, DNS, DNS, DNS, !RECURSIVE, 0, 0, SUCCESS); |
779 | |
780 | makeTestRow(":many at the start" , START, MANY, DNS, DNS, DNS, DNS, !RECURSIVE, 0, 0, SUCCESS); |
781 | makeTestRow(":many at the middle" , MIDDLE, MANY, DNS, DNS, DNS, DNS, !RECURSIVE, 0, 0, SUCCESS); |
782 | makeTestRow(":many at the end" , END, MANY, DNS, DNS, DNS, DNS, !RECURSIVE, 0, 0, SUCCESS); |
783 | |
784 | makeTestRow(":remove all" , START, ALL, DNS, DNS, DNS, DNS, !RECURSIVE, 0, 0, SUCCESS); |
785 | |
786 | makeTestRow(":none at the start" , START, 0, NOSIGNALS, NOSIGNALS, NOSIGNALS, NOSIGNALS, !RECURSIVE, 0, 0, FAIL); |
787 | makeTestRow(":none at the middle" , MIDDLE, 0, NOSIGNALS, NOSIGNALS, NOSIGNALS, NOSIGNALS, !RECURSIVE, 0, 0, FAIL); |
788 | makeTestRow(":none at the end" , END, 0, NOSIGNALS, NOSIGNALS, NOSIGNALS, NOSIGNALS, !RECURSIVE, 0, 0, FAIL); |
789 | |
790 | makeTestRow(":invalid start, valid count 1" , -99, 0, NOSIGNALS, NOSIGNALS, NOSIGNALS, NOSIGNALS, !RECURSIVE, 0, 0, FAIL); |
791 | makeTestRow(":invalid start, valid count 2" , 9999, 0, NOSIGNALS, NOSIGNALS, NOSIGNALS, NOSIGNALS, !RECURSIVE, 0, 0, FAIL); |
792 | makeTestRow(":invalid start, valid count 3" , -99, 1, NOSIGNALS, NOSIGNALS, NOSIGNALS, NOSIGNALS, !RECURSIVE, 0, 0, FAIL); |
793 | makeTestRow(":invalid start, valid count 4" , 9999, 1, NOSIGNALS, NOSIGNALS, NOSIGNALS, NOSIGNALS, !RECURSIVE, 0, 0, FAIL); |
794 | makeTestRow(":invalid start, valid count 5" , -99, MANY, NOSIGNALS, NOSIGNALS, NOSIGNALS, NOSIGNALS, !RECURSIVE, 0, 0, FAIL); |
795 | makeTestRow(":invalid start, valid count 6" , 9999, MANY, NOSIGNALS, NOSIGNALS, NOSIGNALS, NOSIGNALS, !RECURSIVE, 0, 0, FAIL); |
796 | |
797 | makeTestRow(":valid start, invalid count 1" , START, -2, NOSIGNALS, NOSIGNALS, NOSIGNALS, NOSIGNALS, !RECURSIVE, 0, 0, FAIL); |
798 | makeTestRow(":valid start, invalid count 2" , MIDDLE, -2, NOSIGNALS, NOSIGNALS, NOSIGNALS, NOSIGNALS, !RECURSIVE, 0, 0, FAIL); |
799 | makeTestRow(":valid start, invalid count 3" , END, -2, NOSIGNALS, NOSIGNALS, NOSIGNALS, NOSIGNALS, !RECURSIVE, 0, 0, FAIL); |
800 | makeTestRow(":valid start, invalid count 4" , START, 9999, NOSIGNALS, NOSIGNALS, NOSIGNALS, NOSIGNALS, !RECURSIVE, 0, 0, FAIL); |
801 | makeTestRow(":valid start, invalid count 5" , MIDDLE, 9999, NOSIGNALS, NOSIGNALS, NOSIGNALS, NOSIGNALS, !RECURSIVE, 0, 0, FAIL); |
802 | makeTestRow(":valid start, invalid count 6" , END, 9999, NOSIGNALS, NOSIGNALS, NOSIGNALS, NOSIGNALS, !RECURSIVE, 0, 0, FAIL); |
803 | |
804 | // Recursive remove's might assert, haven't decided yet... |
805 | //makeTestRow(":one at the start recursivly", START, DEFAULTCOUNT, 2, DNS, 2, DNS, RECURSIVE, START, DEFAULTCOUNT, FAIL); |
806 | //makeTestRow(":one at the middle recursivly", MIDDLE, DEFAULTCOUNT, 2, DNS, 2, DNS, RECURSIVE, START, DEFAULTCOUNT, SUCCESS); |
807 | //makeTestRow(":one at the end recursivly", END, DEFAULTCOUNT, 2, DNS, 2, DNS, RECURSIVE, START, DEFAULTCOUNT, SUCCESS); |
808 | } |
809 | } |
810 | |
811 | void tst_QItemModel::remove() |
812 | { |
813 | QFETCH(QString, modelType); |
814 | |
815 | currentModel = testModels->createModel(modelType); |
816 | QVERIFY(currentModel); |
817 | |
818 | QFETCH(bool, readOnly); |
819 | if (readOnly) |
820 | return; |
821 | |
822 | QFETCH(int, start); |
823 | QFETCH(int, count); |
824 | |
825 | QFETCH(bool, recursive); |
826 | removeRecursively = recursive; |
827 | |
828 | /*! |
829 | Removes count number of rows starting at start |
830 | if count is -1 it removes all rows |
831 | if start is -1 then it starts at the last row - count |
832 | */ |
833 | QFETCH(bool, shouldSucceed); |
834 | |
835 | // Populate the test area so we can remove something. See: cleanup() |
836 | // parentOfRemoved is stored so that the slots can make sure parentOfRemoved is the index that is emitted. |
837 | parentOfRemoved = testModels->populateTestArea(model: currentModel); |
838 | |
839 | if (count == -1) |
840 | count = currentModel->rowCount(parent: parentOfRemoved); |
841 | if (start == -1) |
842 | start = currentModel->rowCount(parent: parentOfRemoved)-count; |
843 | |
844 | if (currentModel->rowCount(parent: parentOfRemoved) == 0 || |
845 | currentModel->columnCount(parent: parentOfRemoved) == 0) { |
846 | qWarning() << "model test area doesn't have any rows or columns, can't fully test remove(). Skipping" ; |
847 | return; |
848 | } |
849 | |
850 | // When a row or column is removed there should be two signals. |
851 | // Watch to make sure they are emitted and get the row/column count when they do get emitted by connecting them to a slot |
852 | QSignalSpy columnsAboutToBeRemovedSpy(currentModel, &QAbstractItemModel::columnsAboutToBeRemoved); |
853 | QSignalSpy rowsAboutToBeRemovedSpy(currentModel, &QAbstractItemModel::rowsAboutToBeRemoved); |
854 | QSignalSpy columnsRemovedSpy(currentModel, &QAbstractItemModel::columnsRemoved); |
855 | QSignalSpy rowsRemovedSpy(currentModel, &QAbstractItemModel::rowsRemoved); |
856 | QSignalSpy modelResetSpy(currentModel, &QAbstractItemModel::modelReset); |
857 | QSignalSpy modelLayoutChangedSpy(currentModel, &QAbstractItemModel::layoutChanged); |
858 | |
859 | QVERIFY(columnsAboutToBeRemovedSpy.isValid()); |
860 | QVERIFY(rowsAboutToBeRemovedSpy.isValid()); |
861 | QVERIFY(columnsRemovedSpy.isValid()); |
862 | QVERIFY(rowsRemovedSpy.isValid()); |
863 | QVERIFY(modelResetSpy.isValid()); |
864 | QVERIFY(modelLayoutChangedSpy.isValid()); |
865 | |
866 | QFETCH(int, numberOfRowsAboutToBeRemovedSignals); |
867 | QFETCH(int, numberOfColumnsAboutToBeRemovedSignals); |
868 | QFETCH(int, numberOfRowsRemovedSignals); |
869 | QFETCH(int, numberOfColumnsRemovedSignals); |
870 | |
871 | // |
872 | // test removeRow() |
873 | // |
874 | connect(sender: currentModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), |
875 | receiver: this, SLOT(slot_rowsAboutToRemove(QModelIndex))); |
876 | connect(sender: currentModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), |
877 | receiver: this, SLOT(slot_rowsRemoved(QModelIndex))); |
878 | int beforeRemoveRowCount = currentModel->rowCount(parent: parentOfRemoved); |
879 | QPersistentModelIndex dyingIndex = currentModel->index(row: start + count + 1, column: 0, parent: parentOfRemoved); |
880 | QCOMPARE(currentModel->removeRows(start, count, parentOfRemoved), shouldSucceed); |
881 | currentModel->submit(); |
882 | if (shouldSucceed && dyingIndex.isValid()) |
883 | QCOMPARE(dyingIndex.row(), start + 1); |
884 | |
885 | if (rowsAboutToBeRemovedSpy.count() > 0){ |
886 | QList<QVariant> arguments = rowsAboutToBeRemovedSpy.at(i: 0); |
887 | QModelIndex parent = (qvariant_cast<QModelIndex>(v: arguments.at(i: 0))); |
888 | int first = arguments.at(i: 1).toInt(); |
889 | int last = arguments.at(i: 2).toInt(); |
890 | QCOMPARE(first, start); |
891 | QCOMPARE(last, start + count - 1); |
892 | QVERIFY(parentOfRemoved == parent); |
893 | } |
894 | |
895 | if (rowsRemovedSpy.count() > 0){ |
896 | QList<QVariant> arguments = rowsRemovedSpy.at(i: 0); |
897 | QModelIndex parent = (qvariant_cast<QModelIndex>(v: arguments.at(i: 0))); |
898 | int first = arguments.at(i: 1).toInt(); |
899 | int last = arguments.at(i: 2).toInt(); |
900 | QCOMPARE(first, start); |
901 | QCOMPARE(last, start + count - 1); |
902 | QVERIFY(parentOfRemoved == parent); |
903 | } |
904 | |
905 | // Only the row signals should have been emitted |
906 | if (modelResetSpy.count() >= 1 || modelLayoutChangedSpy.count() >=1 ){ |
907 | QCOMPARE(columnsAboutToBeRemovedSpy.count(), 0); |
908 | QCOMPARE(rowsAboutToBeRemovedSpy.count(), 0); |
909 | QCOMPARE(columnsRemovedSpy.count(), 0); |
910 | QCOMPARE(rowsRemovedSpy.count(), 0); |
911 | } |
912 | else { |
913 | QCOMPARE(columnsAboutToBeRemovedSpy.count(), 0); |
914 | QCOMPARE(rowsAboutToBeRemovedSpy.count(), numberOfRowsAboutToBeRemovedSignals); |
915 | QCOMPARE(columnsRemovedSpy.count(), 0); |
916 | QCOMPARE(rowsRemovedSpy.count(), numberOfRowsRemovedSignals); |
917 | } |
918 | |
919 | // The row count should only change *after* rowsAboutToBeRemoved has been emitted |
920 | if (shouldSucceed) { |
921 | if (modelResetSpy.count() == 0 && modelLayoutChangedSpy.count() == 0){ |
922 | QCOMPARE(afterAboutToRemoveRowCount, beforeRemoveRowCount); |
923 | QCOMPARE(afterRemoveRowCount, beforeRemoveRowCount-count-(numberOfRowsRemovedSignals-1)); |
924 | } |
925 | if (modelResetSpy.count() == 0 ) |
926 | QCOMPARE(currentModel->rowCount(parentOfRemoved), beforeRemoveRowCount-count-(numberOfRowsRemovedSignals-1)); |
927 | } |
928 | else { |
929 | if (recursive) |
930 | QCOMPARE(currentModel->rowCount(parentOfRemoved), beforeRemoveRowCount-1); |
931 | else |
932 | QCOMPARE(currentModel->rowCount(parentOfRemoved), beforeRemoveRowCount); |
933 | |
934 | } |
935 | disconnect(sender: currentModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), |
936 | receiver: this, SLOT(slot_rowsAboutToRemove(QModelIndex))); |
937 | disconnect(sender: currentModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), |
938 | receiver: this, SLOT(slot_rowsRemoved(QModelIndex))); |
939 | modelResetSpy.clear(); |
940 | QCOMPARE(modelResetSpy.count(), 0); |
941 | |
942 | // |
943 | // Test remove column |
944 | // |
945 | connect(sender: currentModel, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)), |
946 | receiver: this, SLOT(slot_columnsAboutToRemove(QModelIndex))); |
947 | connect(sender: currentModel, SIGNAL(columnsRemoved(QModelIndex,int,int)), |
948 | receiver: this, SLOT(slot_columnsRemoved(QModelIndex))); |
949 | int beforeRemoveColumnCount = currentModel->columnCount(parent: parentOfRemoved); |
950 | |
951 | // Some models don't let you remove the column, only row |
952 | if (currentModel->removeColumns(column: start, count, parent: parentOfRemoved)) { |
953 | currentModel->submit(); |
954 | // Didn't reset the rows, so they should still be at the same value |
955 | if (modelResetSpy.count() >= 1 || modelLayoutChangedSpy.count() >= 1){ |
956 | QCOMPARE(columnsAboutToBeRemovedSpy.count(), 0); |
957 | //QCOMPARE(rowsAboutToBeRemovedSpy.count(), numberOfRowsAboutToBeRemovedSignals); |
958 | QCOMPARE(columnsRemovedSpy.count(), 0); |
959 | //QCOMPARE(rowsRemovedSpy.count(), numberOfRowsRemovedSignals); |
960 | } |
961 | else { |
962 | QCOMPARE(columnsAboutToBeRemovedSpy.count(), numberOfColumnsAboutToBeRemovedSignals); |
963 | QCOMPARE(rowsAboutToBeRemovedSpy.count(), numberOfRowsAboutToBeRemovedSignals); |
964 | QCOMPARE(columnsRemovedSpy.count(), numberOfColumnsRemovedSignals); |
965 | QCOMPARE(rowsRemovedSpy.count(), numberOfRowsRemovedSignals); |
966 | } |
967 | |
968 | // The column count should only change *after* rowsAboutToBeRemoved has been emitted |
969 | if (shouldSucceed) { |
970 | if (modelResetSpy.count() == 0 && modelLayoutChangedSpy.count() == 0){ |
971 | QCOMPARE(afterAboutToRemoveColumnCount, beforeRemoveColumnCount); |
972 | QCOMPARE(afterRemoveColumnCount, beforeRemoveColumnCount-count-(numberOfColumnsRemovedSignals-1)); |
973 | } |
974 | if (modelResetSpy.count() == 0) |
975 | QCOMPARE(currentModel->columnCount(parentOfRemoved), beforeRemoveColumnCount-count-(numberOfColumnsRemovedSignals-1)); |
976 | } |
977 | else |
978 | QCOMPARE(currentModel->rowCount(parentOfRemoved), beforeRemoveRowCount); |
979 | } |
980 | disconnect(sender: currentModel, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)), |
981 | receiver: this, SLOT(slot_columnsAboutToRemove(QModelIndex))); |
982 | disconnect(sender: currentModel, SIGNAL(columnsRemoved(QModelIndex,int,int)), |
983 | receiver: this, SLOT(slot_columnsRemoved(QModelIndex))); |
984 | |
985 | if (columnsAboutToBeRemovedSpy.count() > 0){ |
986 | QList<QVariant> arguments = columnsAboutToBeRemovedSpy.at(i: 0); |
987 | QModelIndex parent = (qvariant_cast<QModelIndex>(v: arguments.at(i: 0))); |
988 | int first = arguments.at(i: 1).toInt(); |
989 | int last = arguments.at(i: 2).toInt(); |
990 | QCOMPARE(first, start); |
991 | QCOMPARE(last, start + count - 1); |
992 | QVERIFY(parentOfRemoved == parent); |
993 | } |
994 | |
995 | if (columnsRemovedSpy.count() > 0){ |
996 | QList<QVariant> arguments = columnsRemovedSpy.at(i: 0); |
997 | QModelIndex parent = (qvariant_cast<QModelIndex>(v: arguments.at(i: 0))); |
998 | int first = arguments.at(i: 1).toInt(); |
999 | int last = arguments.at(i: 2).toInt(); |
1000 | QCOMPARE(first, start); |
1001 | QCOMPARE(last, start + count - 1); |
1002 | QVERIFY(parentOfRemoved == parent); |
1003 | } |
1004 | |
1005 | // Cleanup the test area because remove::() is called multiple times in a test |
1006 | testModels->cleanupTestArea(model: currentModel); |
1007 | } |
1008 | |
1009 | /*! |
1010 | Developers like to use the slots to then *do* something on the model so it needs to be |
1011 | in a working state. |
1012 | */ |
1013 | void verifyState(QAbstractItemModel *currentModel) { |
1014 | // Make sure the model isn't confused right now and still knows what is root |
1015 | if (currentModel->hasChildren()) { |
1016 | QCOMPARE(currentModel->hasIndex(0, 0), true); |
1017 | QModelIndex index = currentModel->index(row: 0,column: 0); |
1018 | QCOMPARE(index.isValid(), true); |
1019 | QCOMPARE(currentModel->parent(index).isValid(), false); |
1020 | } else { |
1021 | QModelIndex index = currentModel->index(row: 0,column: 0); |
1022 | QCOMPARE(index.isValid(), false); |
1023 | } |
1024 | } |
1025 | |
1026 | void tst_QItemModel::slot_rowsAboutToRemove(const QModelIndex &parent) |
1027 | { |
1028 | QVERIFY(parentOfRemoved == parent); |
1029 | afterAboutToRemoveRowCount = currentModel->rowCount(parent); |
1030 | // hasChildren() should still work |
1031 | if (afterAboutToRemoveRowCount > 0) |
1032 | QCOMPARE(currentModel->hasChildren(parent), true); |
1033 | else |
1034 | QCOMPARE(currentModel->hasChildren(parent), false); |
1035 | |
1036 | verifyState(currentModel); |
1037 | |
1038 | // This does happen |
1039 | if (removeRecursively) { |
1040 | QFETCH(int, recursiveRow); |
1041 | QFETCH(int, recursiveCount); |
1042 | removeRecursively = false; |
1043 | QCOMPARE(currentModel->removeRows(recursiveRow, recursiveCount, parent), true); |
1044 | } |
1045 | } |
1046 | |
1047 | void tst_QItemModel::slot_rowsRemoved(const QModelIndex &parent) |
1048 | { |
1049 | QVERIFY(parentOfRemoved == parent); |
1050 | afterRemoveRowCount = currentModel->rowCount(parent); |
1051 | if (afterRemoveRowCount > 0) |
1052 | QCOMPARE(currentModel->hasChildren(parent), true); |
1053 | else |
1054 | QCOMPARE(currentModel->hasChildren(parent), false); |
1055 | |
1056 | verifyState(currentModel); |
1057 | } |
1058 | |
1059 | void tst_QItemModel::slot_columnsAboutToRemove(const QModelIndex &parent) |
1060 | { |
1061 | QVERIFY(parentOfRemoved == parent); |
1062 | afterAboutToRemoveColumnCount = currentModel->columnCount(parent); |
1063 | // hasChildren() should still work |
1064 | if (afterAboutToRemoveColumnCount > 0 && currentModel->rowCount(parent) > 0) |
1065 | QCOMPARE(currentModel->hasChildren(parent), true); |
1066 | else |
1067 | QCOMPARE(currentModel->hasChildren(parent), false); |
1068 | |
1069 | verifyState(currentModel); |
1070 | } |
1071 | |
1072 | void tst_QItemModel::slot_columnsRemoved(const QModelIndex &parent) |
1073 | { |
1074 | QVERIFY(parentOfRemoved == parent); |
1075 | afterRemoveColumnCount = currentModel->columnCount(parent); |
1076 | if (afterRemoveColumnCount > 0) |
1077 | QCOMPARE(currentModel->hasChildren(parent), true); |
1078 | else |
1079 | QCOMPARE(currentModel->hasChildren(parent), false); |
1080 | |
1081 | verifyState(currentModel); |
1082 | } |
1083 | |
1084 | /*! |
1085 | Tests the model's insertRow/Column() |
1086 | */ |
1087 | void tst_QItemModel::insert_data() |
1088 | { |
1089 | ModelsToTest modelsToTest; |
1090 | QTest::addColumn<QString>(name: "modelType" ); |
1091 | QTest::addColumn<bool>(name: "readOnly" ); |
1092 | QTest::addColumn<bool>(name: "isEmpty" ); |
1093 | |
1094 | QTest::addColumn<int>(name: "start" ); |
1095 | QTest::addColumn<int>(name: "count" ); |
1096 | |
1097 | QTest::addColumn<int>(name: "numberOfRowsAboutToBeInsertedSignals" ); |
1098 | QTest::addColumn<int>(name: "numberOfColumnsAboutToBeInsertedSignals" ); |
1099 | QTest::addColumn<int>(name: "numberOfRowsInsertedSignals" ); |
1100 | QTest::addColumn<int>(name: "numberOfColumnsInsertedSignals" ); |
1101 | |
1102 | QTest::addColumn<bool>(name: "recursive" ); |
1103 | QTest::addColumn<int>(name: "recursiveRow" ); |
1104 | QTest::addColumn<int>(name: "recursiveCount" ); |
1105 | |
1106 | QTest::addColumn<bool>(name: "shouldSucceed" ); |
1107 | |
1108 | #define makeTestRow(testName, start, count, sar, srr, sac, src, r, rr, rc, s) \ |
1109 | QTest::newRow((t.modelType + testName).toLatin1().data()) << t.modelType << readOnly << isEmpty << \ |
1110 | start << count << \ |
1111 | sar << srr << sac << src << \ |
1112 | r << rr << rc << \ |
1113 | s; |
1114 | |
1115 | for (int i = 0; i < modelsToTest.tests.size(); ++i) { |
1116 | ModelsToTest::test t = modelsToTest.tests.at(i); |
1117 | QString name = t.modelType; |
1118 | bool readOnly = (t.read == ModelsToTest::ReadOnly); |
1119 | bool isEmpty = (t.contains == ModelsToTest::Empty); |
1120 | |
1121 | // half these |
1122 | makeTestRow(":one at the start" , START, DEFAULTCOUNT, DNS, DNS, DNS, DNS, !RECURSIVE, 0, 0, SUCCESS); |
1123 | makeTestRow(":one at the middle" , MIDDLE, DEFAULTCOUNT, DNS, DNS, DNS, DNS, !RECURSIVE, 0, 0, SUCCESS); |
1124 | makeTestRow(":one at the end" , END, DEFAULTCOUNT, DNS, DNS, DNS, DNS, !RECURSIVE, 0, 0, SUCCESS); |
1125 | |
1126 | makeTestRow(":many at the start" , START, MANY, DNS, DNS, DNS, DNS, !RECURSIVE, 0, 0, SUCCESS); |
1127 | makeTestRow(":many at the middle" , MIDDLE, MANY, DNS, DNS, DNS, DNS, !RECURSIVE, 0, 0, SUCCESS); |
1128 | makeTestRow(":many at the end" , END, MANY, DNS, DNS, DNS, DNS, !RECURSIVE, 0, 0, SUCCESS); |
1129 | |
1130 | makeTestRow(":add row count" , START, ALL, DNS, DNS, DNS, DNS, !RECURSIVE, 0, 0, SUCCESS); |
1131 | |
1132 | makeTestRow(":none at the start" , START, 0, NOSIGNALS, NOSIGNALS, NOSIGNALS, NOSIGNALS, !RECURSIVE, 0, 0, FAIL); |
1133 | makeTestRow(":none at the middle" , MIDDLE, 0, NOSIGNALS, NOSIGNALS, NOSIGNALS, NOSIGNALS, !RECURSIVE, 0, 0, FAIL); |
1134 | makeTestRow(":none at the end" , END, 0, NOSIGNALS, NOSIGNALS, NOSIGNALS, NOSIGNALS, !RECURSIVE, 0, 0, FAIL); |
1135 | |
1136 | makeTestRow(":invalid start, valid count 1" , -99, 0, NOSIGNALS, NOSIGNALS, NOSIGNALS, NOSIGNALS, !RECURSIVE, 0, 0, FAIL); |
1137 | makeTestRow(":invalid start, valid count 2" , 9999, 0, NOSIGNALS, NOSIGNALS, NOSIGNALS, NOSIGNALS, !RECURSIVE, 0, 0, FAIL); |
1138 | makeTestRow(":invalid start, valid count 3" , -99, 1, NOSIGNALS, NOSIGNALS, NOSIGNALS, NOSIGNALS, !RECURSIVE, 0, 0, FAIL); |
1139 | makeTestRow(":invalid start, valid count 4" , 9999, 1, NOSIGNALS, NOSIGNALS, NOSIGNALS, NOSIGNALS, !RECURSIVE, 0, 0, FAIL); |
1140 | makeTestRow(":invalid start, valid count 5" , -99, MANY, NOSIGNALS, NOSIGNALS, NOSIGNALS, NOSIGNALS, !RECURSIVE, 0, 0, FAIL); |
1141 | makeTestRow(":invalid start, valid count 6" , 9999, MANY, NOSIGNALS, NOSIGNALS, NOSIGNALS, NOSIGNALS, !RECURSIVE, 0, 0, FAIL); |
1142 | |
1143 | makeTestRow(":valid start, invalid count 1" , START, -2, NOSIGNALS, NOSIGNALS, NOSIGNALS, NOSIGNALS, !RECURSIVE, 0, 0, FAIL); |
1144 | makeTestRow(":valid start, invalid count 2" , MIDDLE, -2, NOSIGNALS, NOSIGNALS, NOSIGNALS, NOSIGNALS, !RECURSIVE, 0, 0, FAIL); |
1145 | makeTestRow(":valid start, invalid count 3" , END, -2, NOSIGNALS, NOSIGNALS, NOSIGNALS, NOSIGNALS, !RECURSIVE, 0, 0, FAIL); |
1146 | |
1147 | // Recursive insert's might assert, haven't decided yet... |
1148 | //makeTestRow(":one at the start recursivly", START, DEFAULTCOUNT, 2, DNS, 2, DNS, RECURSIVE, START, DEFAULTCOUNT, FAIL); |
1149 | //makeTestRow(":one at the middle recursivly", MIDDLE, DEFAULTCOUNT, 2, DNS, 2, DNS, RECURSIVE, START, DEFAULTCOUNT, SUCCESS); |
1150 | //makeTestRow(":one at the end recursivly", END, DEFAULTCOUNT, 2, DNS, 2, DNS, RECURSIVE, START, DEFAULTCOUNT, SUCCESS); |
1151 | } |
1152 | } |
1153 | |
1154 | void tst_QItemModel::insert() |
1155 | { |
1156 | QFETCH(QString, modelType); |
1157 | currentModel = testModels->createModel(modelType); |
1158 | QVERIFY(currentModel); |
1159 | |
1160 | QFETCH(bool, readOnly); |
1161 | if (readOnly) |
1162 | return; |
1163 | |
1164 | QFETCH(int, start); |
1165 | QFETCH(int, count); |
1166 | |
1167 | QFETCH(bool, recursive); |
1168 | insertRecursively = recursive; |
1169 | |
1170 | /*! |
1171 | Inserts count number of rows starting at start |
1172 | if count is -1 it inserts all rows |
1173 | if start is -1 then it starts at the last row - count |
1174 | */ |
1175 | QFETCH(bool, shouldSucceed); |
1176 | |
1177 | // Populate the test area so we can insert something. See: cleanup() |
1178 | // parentOfInserted is stored so that the slots can make sure parentOfInserted is the index that is emitted. |
1179 | parentOfInserted = testModels->populateTestArea(model: currentModel); |
1180 | |
1181 | if (count == -1) |
1182 | count = currentModel->rowCount(parent: parentOfInserted); |
1183 | if (start == -1) |
1184 | start = currentModel->rowCount(parent: parentOfInserted)-count; |
1185 | |
1186 | if (currentModel->rowCount(parent: parentOfInserted) == 0 || |
1187 | currentModel->columnCount(parent: parentOfInserted) == 0) { |
1188 | qWarning() << "model test area doesn't have any rows, can't fully test insert(). Skipping" ; |
1189 | return; |
1190 | } |
1191 | |
1192 | // When a row or column is inserted there should be two signals. |
1193 | // Watch to make sure they are emitted and get the row/column count when they do get emitted by connecting them to a slot |
1194 | QSignalSpy columnsAboutToBeInsertedSpy(currentModel, &QAbstractItemModel::columnsAboutToBeInserted); |
1195 | QSignalSpy rowsAboutToBeInsertedSpy(currentModel, &QAbstractItemModel::rowsAboutToBeInserted); |
1196 | QSignalSpy columnsInsertedSpy(currentModel, &QAbstractItemModel::columnsInserted); |
1197 | QSignalSpy rowsInsertedSpy(currentModel, &QAbstractItemModel::rowsInserted); |
1198 | QSignalSpy modelResetSpy(currentModel, &QAbstractItemModel::modelReset); |
1199 | QSignalSpy modelLayoutChangedSpy(currentModel, &QAbstractItemModel::layoutChanged); |
1200 | |
1201 | QVERIFY(columnsAboutToBeInsertedSpy.isValid()); |
1202 | QVERIFY(rowsAboutToBeInsertedSpy.isValid()); |
1203 | QVERIFY(columnsInsertedSpy.isValid()); |
1204 | QVERIFY(rowsInsertedSpy.isValid()); |
1205 | QVERIFY(modelResetSpy.isValid()); |
1206 | QVERIFY(modelLayoutChangedSpy.isValid()); |
1207 | |
1208 | QFETCH(int, numberOfRowsAboutToBeInsertedSignals); |
1209 | QFETCH(int, numberOfColumnsAboutToBeInsertedSignals); |
1210 | QFETCH(int, numberOfRowsInsertedSignals); |
1211 | QFETCH(int, numberOfColumnsInsertedSignals); |
1212 | |
1213 | // |
1214 | // test insertRow() |
1215 | // |
1216 | connect(sender: currentModel, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), |
1217 | receiver: this, SLOT(slot_rowsAboutToInserted(QModelIndex))); |
1218 | connect(sender: currentModel, SIGNAL(rowsInserted(QModelIndex,int,int)), |
1219 | receiver: this, SLOT(slot_rowsInserted(QModelIndex))); |
1220 | int beforeInsertRowCount = currentModel->rowCount(parent: parentOfInserted); |
1221 | QCOMPARE(currentModel->insertRows(start, count, parentOfInserted), shouldSucceed); |
1222 | currentModel->submit(); |
1223 | |
1224 | if (rowsAboutToBeInsertedSpy.count() > 0){ |
1225 | QList<QVariant> arguments = rowsAboutToBeInsertedSpy.at(i: 0); |
1226 | QModelIndex parent = (qvariant_cast<QModelIndex>(v: arguments.at(i: 0))); |
1227 | int first = arguments.at(i: 1).toInt(); |
1228 | int last = arguments.at(i: 2).toInt(); |
1229 | QCOMPARE(first, start); |
1230 | QCOMPARE(last, start + count - 1); |
1231 | QVERIFY(parentOfInserted == parent); |
1232 | } |
1233 | |
1234 | if (rowsInsertedSpy.count() > 0){ |
1235 | QList<QVariant> arguments = rowsInsertedSpy.at(i: 0); |
1236 | QModelIndex parent = (qvariant_cast<QModelIndex>(v: arguments.at(i: 0))); |
1237 | int first = arguments.at(i: 1).toInt(); |
1238 | int last = arguments.at(i: 2).toInt(); |
1239 | QCOMPARE(first, start); |
1240 | QCOMPARE(last, start + count - 1); |
1241 | QVERIFY(parentOfInserted == parent); |
1242 | } |
1243 | |
1244 | // Only the row signals should have been emitted |
1245 | if (modelResetSpy.count() >= 1 || modelLayoutChangedSpy.count() >= 1) { |
1246 | QCOMPARE(columnsAboutToBeInsertedSpy.count(), 0); |
1247 | QCOMPARE(rowsAboutToBeInsertedSpy.count(), 0); |
1248 | QCOMPARE(columnsInsertedSpy.count(), 0); |
1249 | QCOMPARE(rowsInsertedSpy.count(), 0); |
1250 | } |
1251 | else { |
1252 | QCOMPARE(columnsAboutToBeInsertedSpy.count(), 0); |
1253 | QCOMPARE(rowsAboutToBeInsertedSpy.count(), numberOfRowsAboutToBeInsertedSignals); |
1254 | QCOMPARE(columnsInsertedSpy.count(), 0); |
1255 | QCOMPARE(rowsInsertedSpy.count(), numberOfRowsInsertedSignals); |
1256 | } |
1257 | // The row count should only change *after* rowsAboutToBeInserted has been emitted |
1258 | if (shouldSucceed) { |
1259 | if (modelResetSpy.count() == 0 && modelLayoutChangedSpy.count() == 0) { |
1260 | QCOMPARE(afterAboutToInsertRowCount, beforeInsertRowCount); |
1261 | QCOMPARE(afterInsertRowCount, beforeInsertRowCount+count+(numberOfRowsInsertedSignals-1)); |
1262 | } |
1263 | if (modelResetSpy.count() == 0) |
1264 | QCOMPARE(currentModel->rowCount(parentOfInserted), beforeInsertRowCount+count+(numberOfRowsInsertedSignals-1)); |
1265 | } |
1266 | else { |
1267 | if (recursive) |
1268 | QCOMPARE(currentModel->rowCount(parentOfInserted), beforeInsertRowCount+1); |
1269 | else |
1270 | QCOMPARE(currentModel->rowCount(parentOfInserted), beforeInsertRowCount); |
1271 | |
1272 | } |
1273 | disconnect(sender: currentModel, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), |
1274 | receiver: this, SLOT(slot_rowsAboutToInserted(QModelIndex))); |
1275 | disconnect(sender: currentModel, SIGNAL(rowsInserted(QModelIndex,int,int)), |
1276 | receiver: this, SLOT(slot_rowsInserted(QModelIndex))); |
1277 | modelResetSpy.clear(); |
1278 | |
1279 | // |
1280 | // Test insertColumn() |
1281 | // |
1282 | connect(sender: currentModel, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)), |
1283 | receiver: this, SLOT(slot_columnsAboutToInserted(QModelIndex))); |
1284 | connect(sender: currentModel, SIGNAL(columnsInserted(QModelIndex,int,int)), |
1285 | receiver: this, SLOT(slot_columnsInserted(QModelIndex))); |
1286 | int beforeInsertColumnCount = currentModel->columnCount(parent: parentOfInserted); |
1287 | |
1288 | // Some models don't let you insert the column, only row |
1289 | if (currentModel->insertColumns(column: start, count, parent: parentOfInserted)) { |
1290 | currentModel->submit(); |
1291 | if (modelResetSpy.count() >= 1 || modelLayoutChangedSpy.count() >= 1) { |
1292 | // Didn't reset the rows, so they should still be at the same value |
1293 | QCOMPARE(columnsAboutToBeInsertedSpy.count(), 0); |
1294 | //QCOMPARE(rowsAboutToBeInsertedSpy.count(), numberOfRowsAboutToBeInsertedSignals); |
1295 | QCOMPARE(columnsInsertedSpy.count(), 0); |
1296 | //QCOMPARE(rowsInsertedSpy.count(), numberOfRowsInsertedSignals); |
1297 | } |
1298 | else { |
1299 | // Didn't reset the rows, so they should still be at the same value |
1300 | QCOMPARE(columnsAboutToBeInsertedSpy.count(), numberOfColumnsAboutToBeInsertedSignals); |
1301 | QCOMPARE(rowsAboutToBeInsertedSpy.count(), numberOfRowsAboutToBeInsertedSignals); |
1302 | QCOMPARE(columnsInsertedSpy.count(), numberOfColumnsInsertedSignals); |
1303 | QCOMPARE(rowsInsertedSpy.count(), numberOfRowsInsertedSignals); |
1304 | } |
1305 | // The column count should only change *after* rowsAboutToBeInserted has been emitted |
1306 | if (shouldSucceed) { |
1307 | if (modelResetSpy.count() == 0 && modelLayoutChangedSpy.count() == 0) { |
1308 | QCOMPARE(afterAboutToInsertColumnCount, beforeInsertColumnCount); |
1309 | QCOMPARE(afterInsertColumnCount, beforeInsertColumnCount+count+(numberOfColumnsInsertedSignals-1)); |
1310 | } |
1311 | if (modelResetSpy.count() == 0) |
1312 | QCOMPARE(currentModel->columnCount(parentOfInserted), beforeInsertColumnCount+count+(numberOfColumnsInsertedSignals-1)); |
1313 | } |
1314 | else |
1315 | QCOMPARE(currentModel->rowCount(parentOfInserted), beforeInsertRowCount); |
1316 | } |
1317 | disconnect(sender: currentModel, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)), |
1318 | receiver: this, SLOT(slot_columnsAboutToInserted(QModelIndex))); |
1319 | disconnect(sender: currentModel, SIGNAL(columnsInserted(QModelIndex,int,int)), |
1320 | receiver: this, SLOT(slot_columnsInserted(QModelIndex))); |
1321 | |
1322 | if (columnsAboutToBeInsertedSpy.count() > 0){ |
1323 | QList<QVariant> arguments = columnsAboutToBeInsertedSpy.at(i: 0); |
1324 | QModelIndex parent = (qvariant_cast<QModelIndex>(v: arguments.at(i: 0))); |
1325 | int first = arguments.at(i: 1).toInt(); |
1326 | int last = arguments.at(i: 2).toInt(); |
1327 | QCOMPARE(first, start); |
1328 | QCOMPARE(last, start + count - 1); |
1329 | QVERIFY(parentOfInserted == parent); |
1330 | } |
1331 | |
1332 | if (columnsInsertedSpy.count() > 0){ |
1333 | QList<QVariant> arguments = columnsInsertedSpy.at(i: 0); |
1334 | QModelIndex parent = (qvariant_cast<QModelIndex>(v: arguments.at(i: 0))); |
1335 | int first = arguments.at(i: 1).toInt(); |
1336 | int last = arguments.at(i: 2).toInt(); |
1337 | QCOMPARE(first, start); |
1338 | QCOMPARE(last, start + count - 1); |
1339 | QVERIFY(parentOfInserted == parent); |
1340 | } |
1341 | |
1342 | // Cleanup the test area because insert::() is called multiple times in a test |
1343 | testModels->cleanupTestArea(model: currentModel); |
1344 | } |
1345 | |
1346 | void tst_QItemModel::slot_rowsAboutToInserted(const QModelIndex &parent) |
1347 | { |
1348 | QVERIFY(parentOfInserted == parent); |
1349 | afterAboutToInsertRowCount = currentModel->rowCount(parent); |
1350 | bool hasChildren = currentModel->hasChildren(parent); |
1351 | bool hasDimensions = currentModel->columnCount(parent) > 0 && currentModel->rowCount(parent) > 0; |
1352 | QCOMPARE(hasChildren, hasDimensions); |
1353 | verifyState(currentModel); |
1354 | |
1355 | // This does happen |
1356 | if (insertRecursively) { |
1357 | QFETCH(int, recursiveRow); |
1358 | QFETCH(int, recursiveCount); |
1359 | insertRecursively = false; |
1360 | QCOMPARE(currentModel->insertRows(recursiveRow, recursiveCount, parent), true); |
1361 | } |
1362 | } |
1363 | |
1364 | void tst_QItemModel::slot_rowsInserted(const QModelIndex &parent) |
1365 | { |
1366 | QVERIFY(parentOfInserted == parent); |
1367 | afterInsertRowCount = currentModel->rowCount(parent); |
1368 | bool hasChildren = currentModel->hasChildren(parent); |
1369 | bool hasDimensions = currentModel->columnCount(parent) > 0 && currentModel->rowCount(parent) > 0; |
1370 | QCOMPARE(hasChildren, hasDimensions); |
1371 | verifyState(currentModel); |
1372 | } |
1373 | |
1374 | void tst_QItemModel::slot_columnsAboutToInserted(const QModelIndex &parent) |
1375 | { |
1376 | QVERIFY(parentOfInserted == parent); |
1377 | afterAboutToInsertColumnCount = currentModel->columnCount(parent); |
1378 | bool hasChildren = currentModel->hasChildren(parent); |
1379 | bool hasDimensions = currentModel->columnCount(parent) > 0 && currentModel->rowCount(parent) > 0; |
1380 | QCOMPARE(hasChildren, hasDimensions); |
1381 | verifyState(currentModel); |
1382 | } |
1383 | |
1384 | void tst_QItemModel::slot_columnsInserted(const QModelIndex &parent) |
1385 | { |
1386 | QVERIFY(parentOfInserted == parent); |
1387 | afterInsertColumnCount = currentModel->columnCount(parent); |
1388 | bool hasChildren = currentModel->hasChildren(parent); |
1389 | bool hasDimensions = currentModel->columnCount(parent) > 0 && currentModel->rowCount(parent) > 0; |
1390 | QCOMPARE(hasChildren, hasDimensions); |
1391 | verifyState(currentModel); |
1392 | } |
1393 | |
1394 | QTEST_MAIN(tst_QItemModel) |
1395 | #include "tst_qitemmodel.moc" |
1396 | |