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
30#include <QtTest/QtTest>
31
32#include <QStandardItemModel>
33#include <QTreeView>
34#include <private/qtreeview_p.h>
35
36class tst_QStandardItemModel : public QObject
37{
38 Q_OBJECT
39
40public:
41 tst_QStandardItemModel();
42
43 enum ModelChanged {
44 RowsAboutToBeInserted,
45 RowsInserted,
46 RowsAboutToBeRemoved,
47 RowsRemoved,
48 ColumnsAboutToBeInserted,
49 ColumnsInserted,
50 ColumnsAboutToBeRemoved,
51 ColumnsRemoved
52 };
53
54public slots:
55 void init();
56 void cleanup();
57
58protected slots:
59 void checkAboutToBeRemoved();
60 void checkRemoved();
61 void updateRowAboutToBeRemoved();
62
63 void rowsAboutToBeInserted(const QModelIndex &parent, int first, int last)
64 { modelChanged(change: RowsAboutToBeInserted, parent, first, last); }
65 void rowsInserted(const QModelIndex &parent, int first, int last)
66 { modelChanged(change: RowsInserted, parent, first, last); }
67 void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last)
68 { modelChanged(change: RowsAboutToBeRemoved, parent, first, last); }
69 void rowsRemoved(const QModelIndex &parent, int first, int last)
70 { modelChanged(change: RowsRemoved, parent, first, last); }
71 void columnsAboutToBeInserted(const QModelIndex &parent, int first, int last)
72 { modelChanged(change: ColumnsAboutToBeInserted, parent, first, last); }
73 void columnsInserted(const QModelIndex &parent, int first, int last)
74 { modelChanged(change: ColumnsInserted, parent, first, last); }
75 void columnsAboutToBeRemoved(const QModelIndex &parent, int first, int last)
76 { modelChanged(change: ColumnsAboutToBeRemoved, parent, first, last); }
77 void columnsRemoved(const QModelIndex &parent, int first, int last)
78 { modelChanged(change: ColumnsRemoved, parent, first, last); }
79
80 void modelChanged(ModelChanged change, const QModelIndex &parent, int first, int last);
81
82private slots:
83 void insertRow_data();
84 void insertRow();
85 void insertRows();
86 void insertRowsItems();
87 void insertRowInHierarcy();
88 void insertColumn_data();
89 void insertColumn();
90 void insertColumns();
91 void removeRows();
92 void removeColumns();
93 void setHeaderData();
94 void persistentIndexes();
95 void removingPersistentIndexes();
96 void updatingPersistentIndexes();
97
98 void checkChildren();
99 void data();
100 void clear();
101 void clearItemData();
102 void sort_data();
103 void sort();
104 void sortRole_data();
105 void sortRole();
106 void findItems();
107 void getSetHeaderItem();
108 void indexFromItem();
109 void itemFromIndex();
110 void getSetItemPrototype();
111 void getSetItemData();
112 void setHeaderLabels_data();
113 void setHeaderLabels();
114 void itemDataChanged();
115 void takeHeaderItem();
116 void useCase1();
117 void useCase2();
118 void useCase3();
119
120 void setNullChild();
121 void deleteChild();
122
123 void rootItemFlags();
124#ifdef QT_BUILD_INTERNAL
125 void treeDragAndDrop();
126#endif
127 void removeRowsAndColumns();
128
129 void itemRoleNames();
130 void getMimeDataWithInvalidModelIndex();
131 void supportedDragDropActions();
132
133 void taskQTBUG_45114_setItemData();
134 void setItemPersistentIndex();
135
136private:
137 QStandardItemModel *m_model = nullptr;
138 QPersistentModelIndex persistent;
139 QVector<QModelIndex> rcParent = QVector<QModelIndex>(8);
140 QVector<int> rcFirst = QVector<int>(8, 0);
141 QVector<int> rcLast = QVector<int>(8, 0);
142 QVector<int> currentRoles;
143
144 //return true if models have the same structure, and all child have the same text
145 static bool compareModels(QStandardItemModel *model1, QStandardItemModel *model2);
146 //return true if models have the same structure, and all child have the same text
147 static bool compareItems(QStandardItem *item1, QStandardItem *item2);
148};
149
150static constexpr int defaultSize = 3;
151
152Q_DECLARE_METATYPE(QStandardItem*)
153Q_DECLARE_METATYPE(Qt::Orientation)
154
155tst_QStandardItemModel::tst_QStandardItemModel()
156{
157 qRegisterMetaType<QStandardItem*>(typeName: "QStandardItem*");
158 qRegisterMetaType<Qt::Orientation>(typeName: "Qt::Orientation");
159 qRegisterMetaType<QAbstractItemModel::LayoutChangeHint>(typeName: "QAbstractItemModel::LayoutChangeHint");
160 qRegisterMetaType<QList<QPersistentModelIndex>>(typeName: "QList<QPersistentModelIndex>");
161}
162
163/*
164 This test usually uses a model with a 3x3 table
165 ---------------------------
166 | 0,0 | 0,1 | 0,2 |
167 ---------------------------
168 | 1,0 | 1,1 | 1,2 |
169 ---------------------------
170 | 2,0 | 2,1 | 2,2 |
171 ---------------------------
172*/
173void tst_QStandardItemModel::init()
174{
175 m_model = new QStandardItemModel(defaultSize, defaultSize);
176 connect(sender: m_model, signal: &QStandardItemModel::rowsAboutToBeInserted,
177 receiver: this, slot: &tst_QStandardItemModel::rowsAboutToBeInserted);
178 connect(sender: m_model, signal: &QStandardItemModel::rowsInserted,
179 receiver: this, slot: &tst_QStandardItemModel::rowsInserted);
180 connect(sender: m_model, signal: &QStandardItemModel::rowsAboutToBeRemoved,
181 receiver: this, slot: &tst_QStandardItemModel::rowsAboutToBeRemoved);
182 connect(sender: m_model, signal: &QStandardItemModel::rowsRemoved,
183 receiver: this, slot: &tst_QStandardItemModel::rowsRemoved);
184
185 connect(sender: m_model, signal: &QStandardItemModel::columnsAboutToBeInserted,
186 receiver: this, slot: &tst_QStandardItemModel::columnsAboutToBeInserted);
187 connect(sender: m_model, signal: &QStandardItemModel::columnsInserted,
188 receiver: this, slot: &tst_QStandardItemModel::columnsInserted);
189 connect(sender: m_model, signal: &QStandardItemModel::columnsAboutToBeRemoved,
190 receiver: this, slot: &tst_QStandardItemModel::columnsAboutToBeRemoved);
191 connect(sender: m_model, signal: &QStandardItemModel::columnsRemoved,
192 receiver: this, slot: &tst_QStandardItemModel::columnsRemoved);
193
194 connect(sender: m_model, signal: &QAbstractItemModel::dataChanged,
195 context: this, slot: [this](const QModelIndex &, const QModelIndex &, const QVector<int> &roles)
196 {
197 currentRoles = roles;
198 });
199
200 rcFirst.fill(from: -1);
201 rcLast.fill(from: -1);
202}
203
204void tst_QStandardItemModel::cleanup()
205{
206 m_model->disconnect(receiver: this);
207 delete m_model;
208 m_model = nullptr;
209}
210
211void tst_QStandardItemModel::insertRow_data()
212{
213 QTest::addColumn<int>(name: "insertRow");
214 QTest::addColumn<int>(name: "expectedRow");
215
216 QTest::newRow(dataTag: "Insert less then 0") << -1 << 0;
217 QTest::newRow(dataTag: "Insert at 0") << 0 << 0;
218 QTest::newRow(dataTag: "Insert beyond count") << defaultSize+1 << defaultSize;
219 QTest::newRow(dataTag: "Insert at count") << defaultSize << defaultSize;
220 QTest::newRow(dataTag: "Insert in the middle") << 1 << 1;
221}
222
223void tst_QStandardItemModel::insertRow()
224{
225 QFETCH(int, insertRow);
226 QFETCH(int, expectedRow);
227
228 QIcon icon;
229 // default all initial items to DisplayRole: "initalitem"
230 for (int r = 0; r < m_model->rowCount(); ++r) {
231 for (int c = 0; c < m_model->columnCount(); ++c) {
232 m_model->setData(index: m_model->index(row: r, column: c), value: "initialitem", role: Qt::DisplayRole);
233 }
234 }
235
236 // check that inserts changes rowCount
237 QCOMPARE(m_model->rowCount(), defaultSize);
238 m_model->insertRow(arow: insertRow);
239 if (insertRow >= 0 && insertRow <= defaultSize) {
240 QCOMPARE(m_model->rowCount(), defaultSize + 1);
241
242 // check that signals were emitted with correct info
243 QCOMPARE(rcFirst[RowsAboutToBeInserted], expectedRow);
244 QCOMPARE(rcLast[RowsAboutToBeInserted], expectedRow);
245 QCOMPARE(rcFirst[RowsInserted], expectedRow);
246 QCOMPARE(rcLast[RowsInserted], expectedRow);
247
248 //check that the inserted item has different DisplayRole than initial items
249 QVERIFY(m_model->data(m_model->index(expectedRow, 0), Qt::DisplayRole).toString() != QLatin1String("initialitem"));
250 } else {
251 // We inserted something outside the bounds, do nothing
252 QCOMPARE(m_model->rowCount(), defaultSize);
253 QCOMPARE(rcFirst[RowsAboutToBeInserted], -1);
254 QCOMPARE(rcLast[RowsAboutToBeInserted], -1);
255 QCOMPARE(rcFirst[RowsInserted], -1);
256 QCOMPARE(rcLast[RowsInserted], -1);
257 }
258}
259
260void tst_QStandardItemModel::insertRows()
261{
262 int rowCount = m_model->rowCount();
263 QCOMPARE(rowCount, defaultSize);
264
265 // insert custom header label
266 QString headerLabel = "custom";
267 m_model->setHeaderData(section: 0, orientation: Qt::Vertical, value: headerLabel);
268
269 // insert one row
270 m_model->insertRows(row: 0, count: 1);
271 QCOMPARE(m_model->rowCount(), rowCount + 1);
272 rowCount = m_model->rowCount();
273
274 // check header data has moved
275 QCOMPARE(m_model->headerData(1, Qt::Vertical).toString(), headerLabel);
276
277 // insert two rows
278 m_model->insertRows(row: 0, count: 2);
279 QCOMPARE(m_model->rowCount(), rowCount + 2);
280
281 // check header data has moved
282 QCOMPARE(m_model->headerData(3, Qt::Vertical).toString(), headerLabel);
283
284 // do not assert on empty list
285 QStandardItem *si = m_model->invisibleRootItem();
286 si->insertRow(row: 0, items: QList<QStandardItem*>());
287 si->insertRows(row: 0, count: 0);
288 si->insertRows(row: 0, items: QList<QStandardItem*>());
289}
290
291void tst_QStandardItemModel::insertRowsItems()
292{
293 int rowCount = m_model->rowCount();
294
295 QList<QStandardItem *> items;
296 QStandardItemModel *m = m_model;
297 QStandardItem *hiddenRoot = m->invisibleRootItem();
298 for (int i = 0; i < 3; ++i)
299 items.append(t: new QStandardItem(QString::number(i + 10)));
300 hiddenRoot->appendRows(aitems: items);
301 QCOMPARE(m_model->rowCount(), rowCount + 3);
302 QCOMPARE(m_model->index(rowCount + 0, 0).data().toInt(), 10);
303 QCOMPARE(m_model->index(rowCount + 1, 0).data().toInt(), 11);
304 QCOMPARE(m_model->index(rowCount + 2, 0).data().toInt(), 12);
305 for (int i = rowCount; i < rowCount + 3; ++i) {
306 QVERIFY(m->item(i));
307 QCOMPARE(m->item(i)->model(), m_model);
308 }
309}
310
311void tst_QStandardItemModel::insertRowInHierarcy()
312{
313 QVERIFY(m_model->insertRows(0, 1, QModelIndex()));
314 QVERIFY(m_model->insertColumns(0, 1, QModelIndex()));
315 QVERIFY(m_model->hasIndex(0, 0, QModelIndex()));
316
317 QModelIndex parent = m_model->index(row: 0, column: 0, parent: QModelIndex());
318 QVERIFY(parent.isValid());
319
320 QVERIFY(m_model->insertRows(0, 1, parent));
321 QVERIFY(m_model->insertColumns(0, 1, parent));
322 QVERIFY(m_model->hasIndex(0, 0, parent));
323
324 QModelIndex child = m_model->index(row: 0, column: 0, parent);
325 QVERIFY(child.isValid());
326}
327
328void tst_QStandardItemModel::insertColumn_data()
329{
330 QTest::addColumn<int>(name: "insertColumn");
331 QTest::addColumn<int>(name: "expectedColumn");
332
333 QTest::newRow(dataTag: "Insert less then 0") << -1 << 0;
334 QTest::newRow(dataTag: "Insert at 0") << 0 << 0;
335 QTest::newRow(dataTag: "Insert beyond count") << defaultSize+1 << defaultSize;
336 QTest::newRow(dataTag: "Insert at count") << defaultSize << defaultSize;
337 QTest::newRow(dataTag: "Insert in the middle") << 1 << 1;
338}
339
340void tst_QStandardItemModel::insertColumn()
341{
342 QFETCH(int, insertColumn);
343 QFETCH(int, expectedColumn);
344
345 // default all initial items to DisplayRole: "initalitem"
346 for (int r = 0; r < m_model->rowCount(); ++r) {
347 for (int c = 0; c < m_model->columnCount(); ++c) {
348 m_model->setData(index: m_model->index(row: r, column: c), value: "initialitem", role: Qt::DisplayRole);
349 }
350 }
351
352 // check that inserts changes columnCount
353 QCOMPARE(m_model->columnCount(), defaultSize);
354 m_model->insertColumn(acolumn: insertColumn);
355 if (insertColumn >= 0 && insertColumn <= defaultSize) {
356 QCOMPARE(m_model->columnCount(), defaultSize + 1);
357 // check that signals were emitted with correct info
358 QCOMPARE(rcFirst[ColumnsAboutToBeInserted], expectedColumn);
359 QCOMPARE(rcLast[ColumnsAboutToBeInserted], expectedColumn);
360 QCOMPARE(rcFirst[ColumnsInserted], expectedColumn);
361 QCOMPARE(rcLast[ColumnsInserted], expectedColumn);
362
363 //check that the inserted item has different DisplayRole than initial items
364 QVERIFY(m_model->data(m_model->index(0, expectedColumn), Qt::DisplayRole).toString() != QLatin1String("initialitem"));
365 } else {
366 // We inserted something outside the bounds, do nothing
367 QCOMPARE(m_model->columnCount(), defaultSize);
368 QCOMPARE(rcFirst[ColumnsAboutToBeInserted], -1);
369 QCOMPARE(rcLast[ColumnsAboutToBeInserted], -1);
370 QCOMPARE(rcFirst[ColumnsInserted], -1);
371 QCOMPARE(rcLast[ColumnsInserted], -1);
372 }
373
374}
375
376void tst_QStandardItemModel::insertColumns()
377{
378 int columnCount = m_model->columnCount();
379 QCOMPARE(columnCount, defaultSize);
380
381 // insert custom header label
382 QString headerLabel = "custom";
383 m_model->setHeaderData(section: 0, orientation: Qt::Horizontal, value: headerLabel);
384
385 // insert one column
386 m_model->insertColumns(column: 0, count: 1);
387 QCOMPARE(m_model->columnCount(), columnCount + 1);
388 columnCount = m_model->columnCount();
389
390 // check header data has moved
391 QCOMPARE(m_model->headerData(1, Qt::Horizontal).toString(), headerLabel);
392
393 // insert two columns
394 m_model->insertColumns(column: 0, count: 2);
395 QCOMPARE(m_model->columnCount(), columnCount + 2);
396
397 // check header data has moved
398 QCOMPARE(m_model->headerData(3, Qt::Horizontal).toString(), headerLabel);
399
400 // do not assert on empty list
401 QStandardItem *si = m_model->invisibleRootItem();
402 si->insertColumn(column: 0, items: QList<QStandardItem*>());
403 si->insertColumns(column: 0, count: 0);
404}
405
406void tst_QStandardItemModel::removeRows()
407{
408 int rowCount = m_model->rowCount();
409 QCOMPARE(rowCount, defaultSize);
410
411 // insert custom header label
412 QString headerLabel = "custom";
413 m_model->setHeaderData(section: rowCount - 1, orientation: Qt::Vertical, value: headerLabel);
414
415 // remove one row
416 m_model->removeRows(row: 0, count: 1);
417 QCOMPARE(m_model->rowCount(), rowCount - 1);
418 rowCount = m_model->rowCount();
419
420 // check header data has moved
421 QCOMPARE(m_model->headerData(rowCount - 1, Qt::Vertical).toString(), headerLabel);
422
423 // remove two rows
424 m_model->removeRows(row: 0, count: 2);
425 QCOMPARE(m_model->rowCount(), rowCount - 2);
426}
427
428void tst_QStandardItemModel::removeColumns()
429{
430 int columnCount = m_model->columnCount();
431 QCOMPARE(columnCount, defaultSize);
432
433 // insert custom header label
434 QString headerLabel = "custom";
435 m_model->setHeaderData(section: columnCount - 1, orientation: Qt::Horizontal, value: headerLabel);
436
437 // remove one column
438 m_model->removeColumns(column: 0, count: 1);
439 QCOMPARE(m_model->columnCount(), columnCount - 1);
440 columnCount = m_model->columnCount();
441
442 // check header data has moved
443 QCOMPARE(m_model->headerData(columnCount - 1, Qt::Horizontal).toString(), headerLabel);
444
445 // remove two columns
446 m_model->removeColumns(column: 0, count: 2);
447 QCOMPARE(m_model->columnCount(), columnCount - 2);
448}
449
450
451void tst_QStandardItemModel::setHeaderData()
452{
453 for (int x = 0; x < 2; ++x) {
454 bool vertical = (x == 0);
455 int count = vertical ? m_model->rowCount() : m_model->columnCount();
456 QCOMPARE(count, defaultSize);
457 Qt::Orientation orient = vertical ? Qt::Vertical : Qt::Horizontal;
458
459 // check default values are ok
460 for (int i = 0; i < count; ++i)
461 QCOMPARE(m_model->headerData(i, orient).toString(), QString::number(i + 1));
462
463 QSignalSpy headerDataChangedSpy(
464 m_model, &QAbstractItemModel::headerDataChanged);
465 QSignalSpy dataChangedSpy(
466 m_model, &QAbstractItemModel::dataChanged);
467 // insert custom values and check
468 for (int i = 0; i < count; ++i) {
469 QString customString = QString("custom") + QString::number(i);
470 QCOMPARE(m_model->setHeaderData(i, orient, customString), true);
471 QCOMPARE(headerDataChangedSpy.count(), 1);
472 QCOMPARE(dataChangedSpy.count(), 0);
473 QVariantList args = headerDataChangedSpy.takeFirst();
474 QCOMPARE(qvariant_cast<Qt::Orientation>(args.at(0)), orient);
475 QCOMPARE(args.at(1).toInt(), i);
476 QCOMPARE(args.at(2).toInt(), i);
477 QCOMPARE(m_model->headerData(i, orient).toString(), customString);
478 QCOMPARE(m_model->setHeaderData(i, orient, customString), true);
479 QCOMPARE(headerDataChangedSpy.count(), 0);
480 QCOMPARE(dataChangedSpy.count(), 0);
481 }
482
483 //check read from invalid sections
484 QVERIFY(!m_model->headerData(count, orient).isValid());
485 QVERIFY(!m_model->headerData(-1, orient).isValid());
486 //check write to invalid section
487 QCOMPARE(m_model->setHeaderData(count, orient, "foo"), false);
488 QCOMPARE(m_model->setHeaderData(-1, orient, "foo"), false);
489 QVERIFY(!m_model->headerData(count, orient).isValid());
490 QVERIFY(!m_model->headerData(-1, orient).isValid());
491 }
492}
493
494void tst_QStandardItemModel::persistentIndexes()
495{
496 QCOMPARE(m_model->rowCount(), defaultSize);
497 QCOMPARE(m_model->columnCount(), defaultSize);
498
499 // create a persisten index at 0,0
500 QPersistentModelIndex persistentIndex(m_model->index(row: 0, column: 0));
501
502 // verify it is ok and at the correct spot
503 QVERIFY(persistentIndex.isValid());
504 QCOMPARE(persistentIndex.row(), 0);
505 QCOMPARE(persistentIndex.column(), 0);
506
507 // insert row and check that the persisten index has moved
508 QVERIFY(m_model->insertRow(0));
509 QVERIFY(persistentIndex.isValid());
510 QCOMPARE(persistentIndex.row(), 1);
511 QCOMPARE(persistentIndex.column(), 0);
512
513 // insert row after the persisten index and see that it stays the same
514 QVERIFY(m_model->insertRow(m_model->rowCount()));
515 QVERIFY(persistentIndex.isValid());
516 QCOMPARE(persistentIndex.row(), 1);
517 QCOMPARE(persistentIndex.column(), 0);
518
519 // insert column and check that the persisten index has moved
520 QVERIFY(m_model->insertColumn(0));
521 QVERIFY(persistentIndex.isValid());
522 QCOMPARE(persistentIndex.row(), 1);
523 QCOMPARE(persistentIndex.column(), 1);
524
525 // insert column after the persisten index and see that it stays the same
526 QVERIFY(m_model->insertColumn(m_model->columnCount()));
527 QVERIFY(persistentIndex.isValid());
528 QCOMPARE(persistentIndex.row(), 1);
529 QCOMPARE(persistentIndex.column(), 1);
530
531 // removes a row beyond the persistent index and see it stays the same
532 QVERIFY(m_model->removeRow(m_model->rowCount() - 1));
533 QVERIFY(persistentIndex.isValid());
534 QCOMPARE(persistentIndex.row(), 1);
535 QCOMPARE(persistentIndex.column(), 1);
536
537 // removes a column beyond the persistent index and see it stays the same
538 QVERIFY(m_model->removeColumn(m_model->columnCount() - 1));
539 QVERIFY(persistentIndex.isValid());
540 QCOMPARE(persistentIndex.row(), 1);
541 QCOMPARE(persistentIndex.column(), 1);
542
543 // removes a row before the persistent index and see it moves the same
544 QVERIFY(m_model->removeRow(0));
545 QVERIFY(persistentIndex.isValid());
546 QCOMPARE(persistentIndex.row(), 0);
547 QCOMPARE(persistentIndex.column(), 1);
548
549 // removes a column before the persistent index and see it moves the same
550 QVERIFY(m_model->removeColumn(0));
551 QVERIFY(persistentIndex.isValid());
552 QCOMPARE(persistentIndex.row(), 0);
553 QCOMPARE(persistentIndex.column(), 0);
554
555 // remove the row where the persistent index is, and see that it becomes invalid
556 QVERIFY(m_model->removeRow(0));
557 QVERIFY(!persistentIndex.isValid());
558
559 // remove the row where the persistent index is, and see that it becomes invalid
560 persistentIndex = m_model->index(row: 0, column: 0);
561 QVERIFY(persistentIndex.isValid());
562 QVERIFY(m_model->removeColumn(0));
563 QVERIFY(!persistentIndex.isValid());
564}
565
566void tst_QStandardItemModel::checkAboutToBeRemoved()
567{
568 QVERIFY(persistent.isValid());
569}
570
571void tst_QStandardItemModel::checkRemoved()
572{
573 QVERIFY(!persistent.isValid());
574}
575
576void tst_QStandardItemModel::removingPersistentIndexes()
577{
578 // add 10 rows and columns to model to make it big enough
579 QVERIFY(m_model->insertRows(0, 10));
580 QVERIFY(m_model->insertColumns(0, 10));
581
582 connect(sender: m_model, signal: &QAbstractItemModel::rowsAboutToBeRemoved,
583 receiver: this, slot: &tst_QStandardItemModel::checkAboutToBeRemoved);
584 connect(sender: m_model, signal: &QAbstractItemModel::rowsRemoved,
585 receiver: this, slot: &tst_QStandardItemModel::checkRemoved);
586 connect(sender: m_model, signal: &QAbstractItemModel::columnsAboutToBeRemoved,
587 receiver: this, slot: &tst_QStandardItemModel::checkAboutToBeRemoved);
588 connect(sender: m_model, signal: &QAbstractItemModel::columnsRemoved,
589 receiver: this, slot: &tst_QStandardItemModel::checkRemoved);
590
591
592 // test removeRow
593 // add child table 3x3 to parent index(0, 0)
594 QVERIFY(m_model->insertRows(0, 3, m_model->index(0, 0)));
595 QVERIFY(m_model->insertColumns(0, 3, m_model->index(0, 0)));
596
597 // set child to persistent and delete parent row
598 persistent = m_model->index(row: 0, column: 0, parent: m_model->index(row: 0, column: 0));
599 QVERIFY(persistent.isValid());
600 QVERIFY(m_model->removeRow(0));
601
602 // set persistent to index(0, 0) and remove that row
603 persistent = m_model->index(row: 0, column: 0);
604 QVERIFY(persistent.isValid());
605 QVERIFY(m_model->removeRow(0));
606
607
608 // test removeColumn
609 // add child table 3x3 to parent index (0, 0)
610 QVERIFY(m_model->insertRows(0, 3, m_model->index(0, 0)));
611 QVERIFY(m_model->insertColumns(0, 3, m_model->index(0, 0)));
612
613 // set child to persistent and delete parent column
614 persistent = m_model->index(row: 0, column: 0, parent: m_model->index(row: 0, column: 0));
615 QVERIFY(persistent.isValid());
616 QVERIFY(m_model->removeColumn(0));
617
618 // set persistent to index(0, 0) and remove that column
619 persistent = m_model->index(row: 0, column: 0);
620 QVERIFY(persistent.isValid());
621 QVERIFY(m_model->removeColumn(0));
622
623
624 disconnect(sender: m_model, signal: &QAbstractItemModel::rowsAboutToBeRemoved,
625 receiver: this, slot: &tst_QStandardItemModel::checkAboutToBeRemoved);
626 disconnect(sender: m_model, signal: &QAbstractItemModel::rowsRemoved,
627 receiver: this, slot: &tst_QStandardItemModel::checkRemoved);
628 disconnect(sender: m_model, signal: &QAbstractItemModel::columnsAboutToBeRemoved,
629 receiver: this, slot: &tst_QStandardItemModel::checkAboutToBeRemoved);
630 disconnect(sender: m_model, signal: &QAbstractItemModel::columnsRemoved,
631 receiver: this, slot: &tst_QStandardItemModel::checkRemoved);
632}
633
634void tst_QStandardItemModel::updateRowAboutToBeRemoved()
635{
636 QModelIndex idx = m_model->index(row: 0, column: 0);
637 QVERIFY(idx.isValid());
638 persistent = idx;
639}
640
641void tst_QStandardItemModel::updatingPersistentIndexes()
642{
643 connect(sender: m_model, signal: &QAbstractItemModel::rowsAboutToBeRemoved,
644 receiver: this, slot: &tst_QStandardItemModel::updateRowAboutToBeRemoved);
645
646 persistent = m_model->index(row: 1, column: 0);
647 QVERIFY(persistent.isValid());
648 QVERIFY(m_model->removeRow(1));
649 QVERIFY(persistent.isValid());
650 QPersistentModelIndex tmp = m_model->index(row: 0, column: 0);
651 QCOMPARE(persistent, tmp);
652
653 disconnect(sender: m_model, signal: &QAbstractItemModel::rowsAboutToBeRemoved,
654 receiver: this, slot: &tst_QStandardItemModel::updateRowAboutToBeRemoved);
655}
656
657void tst_QStandardItemModel::modelChanged(ModelChanged change, const QModelIndex &parent,
658 int first, int last)
659{
660 rcParent[change] = parent;
661 rcFirst[change] = first;
662 rcLast[change] = last;
663}
664
665
666void tst_QStandardItemModel::checkChildren()
667{
668 QStandardItemModel model(0, 0);
669 QCOMPARE(model.rowCount(), 0);
670 QCOMPARE(model.columnCount(), 0);
671 QVERIFY(!model.hasChildren());
672
673 QVERIFY(model.insertRows(0, 1));
674 QVERIFY(!model.hasChildren());
675 QCOMPARE(model.rowCount(), 1);
676 QCOMPARE(model.columnCount(), 0);
677
678 QVERIFY(model.insertColumns(0, 1));
679 QVERIFY(model.hasChildren());
680 QCOMPARE(model.rowCount(), 1);
681 QCOMPARE(model.columnCount(), 1);
682
683 QModelIndex idx = model.index(row: 0, column: 0);
684 QVERIFY(!model.hasChildren(idx));
685 QCOMPARE(model.rowCount(idx), 0);
686 QCOMPARE(model.columnCount(idx), 0);
687
688 QVERIFY(model.insertRows(0, 1, idx));
689 QVERIFY(!model.hasChildren(idx));
690 QCOMPARE(model.rowCount(idx), 1);
691 QCOMPARE(model.columnCount(idx), 0);
692
693 QVERIFY(model.insertColumns(0, 1, idx));
694 QVERIFY(model.hasChildren(idx));
695 QCOMPARE(model.rowCount(idx), 1);
696 QCOMPARE(model.columnCount(idx), 1);
697
698 QModelIndex idx2 = model.index(row: 0, column: 0, parent: idx);
699 QVERIFY(!model.hasChildren(idx2));
700 QCOMPARE(model.rowCount(idx2), 0);
701 QCOMPARE(model.columnCount(idx2), 0);
702
703 QVERIFY(model.removeRows(0, 1, idx));
704 QVERIFY(model.hasChildren());
705 QCOMPARE(model.rowCount(), 1);
706 QCOMPARE(model.columnCount(), 1);
707 QVERIFY(!model.hasChildren(idx));
708 QCOMPARE(model.rowCount(idx), 0);
709 QCOMPARE(model.columnCount(idx), 1);
710
711 QVERIFY(model.removeRows(0, 1));
712 QVERIFY(!model.hasChildren());
713 QCOMPARE(model.rowCount(), 0);
714 QCOMPARE(model.columnCount(), 1);
715
716 QVERIFY(!model.index(0,0).sibling(100,100).isValid());
717}
718
719void tst_QStandardItemModel::data()
720{
721 currentRoles.clear();
722 // bad args
723 m_model->setData(index: QModelIndex(), value: "bla", role: Qt::DisplayRole);
724 QVERIFY(currentRoles.isEmpty());
725
726 QIcon icon;
727 for (int r = 0; r < m_model->rowCount(); ++r) {
728 for (int c = 0; c < m_model->columnCount(); ++c) {
729 m_model->setData(index: m_model->index(row: r,column: c), value: "initialitem", role: Qt::DisplayRole);
730 QCOMPARE(currentRoles, QVector<int>({Qt::DisplayRole, Qt::EditRole}));
731 m_model->setData(index: m_model->index(row: r,column: c), value: "tooltip", role: Qt::ToolTipRole);
732 QCOMPARE(currentRoles, QVector<int>{Qt::ToolTipRole});
733 m_model->setData(index: m_model->index(row: r,column: c), value: icon, role: Qt::DecorationRole);
734 QCOMPARE(currentRoles, QVector<int>{Qt::DecorationRole});
735 }
736 }
737
738 QCOMPARE(m_model->data(m_model->index(0, 0), Qt::DisplayRole).toString(), QLatin1String("initialitem"));
739 QCOMPARE(m_model->data(m_model->index(0, 0), Qt::ToolTipRole).toString(), QLatin1String("tooltip"));
740 const QMap<int, QVariant> itmData = m_model->itemData(index: m_model->index(row: 0, column: 0));
741 QCOMPARE(itmData.value(Qt::DisplayRole), QLatin1String("initialitem"));
742 QCOMPARE(itmData.value(Qt::ToolTipRole), QLatin1String("tooltip"));
743 QVERIFY(!itmData.contains(Qt::UserRole - 1));
744 QVERIFY(m_model->itemData(QModelIndex()).isEmpty());
745}
746
747void tst_QStandardItemModel::clearItemData()
748{
749 currentRoles.clear();
750 QVERIFY(!m_model->clearItemData(QModelIndex()));
751 QVERIFY(currentRoles.isEmpty());
752 const QModelIndex idx = m_model->index(row: 0, column: 0);
753 const QMap<int, QVariant> oldData = m_model->itemData(index: idx);
754 m_model->setData(index: idx, value: QLatin1String("initialitem"), role: Qt::DisplayRole);
755 m_model->setData(index: idx, value: QLatin1String("tooltip"), role: Qt::ToolTipRole);
756 m_model->setData(index: idx, value: 5, role: Qt::UserRole);
757 currentRoles.clear();
758 QVERIFY(m_model->clearItemData(idx));
759 QCOMPARE(idx.data(Qt::UserRole), QVariant());
760 QCOMPARE(idx.data(Qt::ToolTipRole), QVariant());
761 QCOMPARE(idx.data(Qt::DisplayRole), QVariant());
762 QCOMPARE(idx.data(Qt::EditRole), QVariant());
763 QVERIFY(currentRoles.isEmpty());
764 m_model->setItemData(index: idx, roles: oldData);
765 currentRoles.clear();
766}
767
768void tst_QStandardItemModel::clear()
769{
770 QStandardItemModel model;
771 model.insertColumns(column: 0, count: 10);
772 model.insertRows(row: 0, count: 10);
773 QCOMPARE(model.columnCount(), 10);
774 QCOMPARE(model.rowCount(), 10);
775
776 QSignalSpy modelResetSpy(&model, &QStandardItemModel::modelReset);
777 QSignalSpy layoutChangedSpy(&model, &QStandardItemModel::layoutChanged);
778 QSignalSpy rowsRemovedSpy(&model, &QStandardItemModel::rowsRemoved);
779
780 QAbstractItemModelTester mt(&model);
781
782 model.clear();
783
784 QCOMPARE(modelResetSpy.count(), 1);
785 QCOMPARE(layoutChangedSpy.count(), 0);
786 QCOMPARE(rowsRemovedSpy.count(), 0);
787 QCOMPARE(model.index(0, 0), QModelIndex());
788 QCOMPARE(model.columnCount(), 0);
789 QCOMPARE(model.rowCount(), 0);
790 QCOMPARE(model.hasChildren(), false);
791}
792
793void tst_QStandardItemModel::sort_data()
794{
795 QTest::addColumn<Qt::SortOrder>(name: "sortOrder");
796 QTest::addColumn<QStringList>(name: "initial");
797 QTest::addColumn<QStringList>(name: "expected");
798
799 const QStringList unsorted(
800 {"delta", "yankee", "bravo", "lima", "charlie", "juliet",
801 "tango", "hotel", "uniform", "alpha", "echo", "golf",
802 "quebec", "foxtrot", "india", "romeo", "november",
803 "oskar", "zulu", "kilo", "whiskey", "mike", "papa",
804 "sierra", "xray" , "viktor"});
805 QStringList sorted = unsorted;
806
807 std::sort(first: sorted.begin(), last: sorted.end());
808 QTest::newRow(dataTag: "flat ascending") << Qt::AscendingOrder
809 << unsorted
810 << sorted;
811 std::reverse(first: sorted.begin(), last: sorted.end());
812 QTest::newRow(dataTag: "flat descending") << Qt::DescendingOrder
813 << unsorted
814 << sorted;
815 QStringList list;
816 for (int i = 1000; i < 2000; ++i)
817 list.append(QStringLiteral("Number: ") + QString::number(i));
818 QTest::newRow(dataTag: "large set ascending") << Qt::AscendingOrder << list << list;
819}
820
821void tst_QStandardItemModel::sort()
822{
823 QFETCH(Qt::SortOrder, sortOrder);
824 QFETCH(QStringList, initial);
825 QFETCH(QStringList, expected);
826 // prepare model
827 QStandardItemModel model;
828 QVERIFY(model.insertRows(0, initial.count(), QModelIndex()));
829 QCOMPARE(model.rowCount(QModelIndex()), initial.count());
830 model.insertColumns(column: 0, count: 1, parent: QModelIndex());
831 QCOMPARE(model.columnCount(QModelIndex()), 1);
832 for (int row = 0; row < model.rowCount(parent: QModelIndex()); ++row) {
833 QModelIndex index = model.index(row, column: 0, parent: QModelIndex());
834 model.setData(index, value: initial.at(i: row), role: Qt::DisplayRole);
835 }
836
837 QSignalSpy layoutAboutToBeChangedSpy(
838 &model, &QStandardItemModel::layoutAboutToBeChanged);
839 QSignalSpy layoutChangedSpy(
840 &model, &QStandardItemModel::layoutChanged);
841
842 // sort
843 model.sort(column: 0, order: sortOrder);
844
845 QCOMPARE(layoutAboutToBeChangedSpy.count(), 1);
846 QCOMPARE(layoutChangedSpy.count(), 1);
847
848 // make sure the model is sorted
849 for (int row = 0; row < model.rowCount(parent: QModelIndex()); ++row) {
850 QModelIndex index = model.index(row, column: 0, parent: QModelIndex());
851 QCOMPARE(model.data(index, Qt::DisplayRole).toString(), expected.at(row));
852 }
853}
854
855void tst_QStandardItemModel::sortRole_data()
856{
857 QTest::addColumn<QStringList>(name: "initialText");
858 QTest::addColumn<QVariantList>(name: "initialData");
859 QTest::addColumn<Qt::ItemDataRole>(name: "sortRole");
860 QTest::addColumn<Qt::SortOrder>(name: "sortOrder");
861 QTest::addColumn<QStringList>(name: "expectedText");
862 QTest::addColumn<QVariantList>(name: "expectedData");
863
864 QTest::newRow(dataTag: "sort ascending with Qt::DisplayRole")
865 << (QStringList() << "b" << "a" << "c")
866 << (QVariantList() << 2 << 3 << 1)
867 << Qt::DisplayRole
868 << Qt::AscendingOrder
869 << (QStringList() << "a" << "b" << "c")
870 << (QVariantList() << 3 << 2 << 1);
871 QTest::newRow(dataTag: "sort ascending with Qt::UserRole")
872 << (QStringList() << "a" << "b" << "c")
873 << (QVariantList() << 3 << 2 << 1)
874 << Qt::UserRole
875 << Qt::AscendingOrder
876 << (QStringList() << "c" << "b" << "a")
877 << (QVariantList() << 1 << 2 << 3);
878}
879
880void tst_QStandardItemModel::sortRole()
881{
882 QFETCH(QStringList, initialText);
883 QFETCH(QVariantList, initialData);
884 QFETCH(Qt::ItemDataRole, sortRole);
885 QFETCH(Qt::SortOrder, sortOrder);
886 QFETCH(QStringList, expectedText);
887 QFETCH(QVariantList, expectedData);
888
889 QStandardItemModel model;
890 for (int i = 0; i < initialText.count(); ++i) {
891 QStandardItem *item = new QStandardItem;
892 item->setText(initialText.at(i));
893 item->setData(value: initialData.at(i), role: Qt::UserRole);
894 model.appendRow(aitem: item);
895 }
896 model.setSortRole(sortRole);
897 model.sort(column: 0, order: sortOrder);
898 for (int i = 0; i < expectedText.count(); ++i) {
899 QStandardItem *item = model.item(row: i);
900 QCOMPARE(item->text(), expectedText.at(i));
901 QCOMPARE(item->data(Qt::UserRole), expectedData.at(i));
902 }
903}
904
905void tst_QStandardItemModel::findItems()
906{
907 QStandardItemModel model;
908 model.appendRow(aitem: new QStandardItem(QLatin1String("foo")));
909 model.appendRow(aitem: new QStandardItem(QLatin1String("bar")));
910 model.item(row: 1)->appendRow(aitem: new QStandardItem(QLatin1String("foo")));
911 QList<QStandardItem*> matches;
912 matches = model.findItems(text: QLatin1String("foo"), flags: Qt::MatchExactly|Qt::MatchRecursive, column: 0);
913 QCOMPARE(matches.count(), 2);
914 matches = model.findItems(text: QLatin1String("foo"), flags: Qt::MatchExactly, column: 0);
915 QCOMPARE(matches.count(), 1);
916 matches = model.findItems(text: QLatin1String("food"), flags: Qt::MatchExactly|Qt::MatchRecursive, column: 0);
917 QCOMPARE(matches.count(), 0);
918 matches = model.findItems(text: QLatin1String("foo"), flags: Qt::MatchExactly|Qt::MatchRecursive, column: -1);
919 QCOMPARE(matches.count(), 0);
920 matches = model.findItems(text: QLatin1String("foo"), flags: Qt::MatchExactly|Qt::MatchRecursive, column: 1);
921 QCOMPARE(matches.count(), 0);
922}
923
924void tst_QStandardItemModel::getSetHeaderItem()
925{
926 QStandardItemModel model;
927
928 QCOMPARE(model.horizontalHeaderItem(0), nullptr);
929 QStandardItem *hheader = new QStandardItem();
930 model.setHorizontalHeaderItem(column: 0, item: hheader);
931 QCOMPARE(model.columnCount(), 1);
932 QCOMPARE(model.horizontalHeaderItem(0), hheader);
933 QCOMPARE(hheader->model(), &model);
934 model.setHorizontalHeaderItem(column: 0, item: nullptr);
935 QCOMPARE(model.horizontalHeaderItem(0), nullptr);
936
937 QCOMPARE(model.verticalHeaderItem(0), nullptr);
938 QStandardItem *vheader = new QStandardItem();
939 model.setVerticalHeaderItem(row: 0, item: vheader);
940 QCOMPARE(model.rowCount(), 1);
941 QCOMPARE(model.verticalHeaderItem(0), vheader);
942 QCOMPARE(vheader->model(), &model);
943 model.setVerticalHeaderItem(row: 0, item: nullptr);
944 QCOMPARE(model.verticalHeaderItem(0), nullptr);
945}
946
947void tst_QStandardItemModel::indexFromItem()
948{
949 QStandardItemModel model;
950
951 QCOMPARE(model.indexFromItem(model.invisibleRootItem()), QModelIndex());
952
953 QStandardItem *item = new QStandardItem;
954 model.setItem(row: 10, column: 20, item);
955 QCOMPARE(item->model(), &model);
956 QModelIndex itemIndex = model.indexFromItem(item);
957 QVERIFY(itemIndex.isValid());
958 QCOMPARE(itemIndex.row(), 10);
959 QCOMPARE(itemIndex.column(), 20);
960 QCOMPARE(itemIndex.parent(), QModelIndex());
961 QCOMPARE(itemIndex.model(), &model);
962
963 QStandardItem *child = new QStandardItem;
964 item->setChild(row: 4, column: 2, item: child);
965 QModelIndex childIndex = model.indexFromItem(item: child);
966 QVERIFY(childIndex.isValid());
967 QCOMPARE(childIndex.row(), 4);
968 QCOMPARE(childIndex.column(), 2);
969 QCOMPARE(childIndex.parent(), itemIndex);
970
971 QStandardItem *dummy = new QStandardItem;
972 QModelIndex noSuchIndex = model.indexFromItem(item: dummy);
973 QVERIFY(!noSuchIndex.isValid());
974 delete dummy;
975
976 noSuchIndex = model.indexFromItem(item: nullptr);
977 QVERIFY(!noSuchIndex.isValid());
978}
979
980void tst_QStandardItemModel::itemFromIndex()
981{
982 QStandardItemModel model;
983
984 QCOMPARE(model.itemFromIndex(QModelIndex()), nullptr);
985
986 QStandardItem *item = new QStandardItem;
987 model.setItem(row: 10, column: 20, item);
988 QModelIndex itemIndex = model.index(row: 10, column: 20, parent: QModelIndex());
989 QVERIFY(itemIndex.isValid());
990 QCOMPARE(model.itemFromIndex(itemIndex), item);
991
992 QStandardItem *child = new QStandardItem;
993 item->setChild(row: 4, column: 2, item: child);
994 QModelIndex childIndex = model.index(row: 4, column: 2, parent: itemIndex);
995 QVERIFY(childIndex.isValid());
996 QCOMPARE(model.itemFromIndex(childIndex), child);
997
998 QModelIndex noSuchIndex = model.index(row: 99, column: 99, parent: itemIndex);
999 QVERIFY(!noSuchIndex.isValid());
1000}
1001
1002class CustomItem : public QStandardItem
1003{
1004public:
1005 using QStandardItem::QStandardItem;
1006
1007 int type() const override { return UserType; }
1008 QStandardItem *clone() const override { return new CustomItem; }
1009};
1010
1011void tst_QStandardItemModel::getSetItemPrototype()
1012{
1013 QStandardItemModel model;
1014 QCOMPARE(model.itemPrototype(), nullptr);
1015
1016 const CustomItem *proto = new CustomItem;
1017 model.setItemPrototype(proto);
1018 QCOMPARE(model.itemPrototype(), proto);
1019
1020 model.setRowCount(1);
1021 model.setColumnCount(1);
1022 QModelIndex index = model.index(row: 0, column: 0, parent: QModelIndex());
1023 model.setData(index, value: "foo");
1024 QStandardItem *item = model.itemFromIndex(index);
1025 QVERIFY(item != nullptr);
1026 QCOMPARE(item->type(), static_cast<int>(QStandardItem::UserType));
1027
1028 model.setItemPrototype(nullptr);
1029 QCOMPARE(model.itemPrototype(), nullptr);
1030}
1031
1032void tst_QStandardItemModel::getSetItemData()
1033{
1034 QMap<int, QVariant> roles;
1035 QLatin1String text("text");
1036 roles.insert(key: Qt::DisplayRole, value: text);
1037 QLatin1String statusTip("statusTip");
1038 roles.insert(key: Qt::StatusTipRole, value: statusTip);
1039 QLatin1String toolTip("toolTip");
1040 roles.insert(key: Qt::ToolTipRole, value: toolTip);
1041 QLatin1String whatsThis("whatsThis");
1042 roles.insert(key: Qt::WhatsThisRole, value: whatsThis);
1043 QSize sizeHint(64, 48);
1044 roles.insert(key: Qt::SizeHintRole, value: sizeHint);
1045 QFont font;
1046 roles.insert(key: Qt::FontRole, value: font);
1047 Qt::Alignment textAlignment(Qt::AlignLeft|Qt::AlignVCenter);
1048 roles.insert(key: Qt::TextAlignmentRole, value: int(textAlignment));
1049 QColor backgroundColor(Qt::blue);
1050 roles.insert(key: Qt::BackgroundRole, value: backgroundColor);
1051 QColor textColor(Qt::green);
1052 roles.insert(key: Qt::ForegroundRole, value: textColor);
1053 Qt::CheckState checkState(Qt::PartiallyChecked);
1054 roles.insert(key: Qt::CheckStateRole, value: int(checkState));
1055 QLatin1String accessibleText("accessibleText");
1056 roles.insert(key: Qt::AccessibleTextRole, value: accessibleText);
1057 QLatin1String accessibleDescription("accessibleDescription");
1058 roles.insert(key: Qt::AccessibleDescriptionRole, value: accessibleDescription);
1059
1060 QStandardItemModel model;
1061 model.insertRows(row: 0, count: 1);
1062 model.insertColumns(column: 0, count: 1);
1063 QModelIndex idx = model.index(row: 0, column: 0, parent: QModelIndex());
1064
1065 QSignalSpy modelDataChangedSpy(
1066 &model, &QStandardItemModel::dataChanged);
1067 QVERIFY(model.setItemData(idx, roles));
1068 QCOMPARE(modelDataChangedSpy.count(), 1);
1069 QVERIFY(model.setItemData(idx, roles));
1070 QCOMPARE(modelDataChangedSpy.count(), 1); //it was already changed once
1071 QCOMPARE(model.itemData(idx), roles);
1072}
1073
1074void tst_QStandardItemModel::setHeaderLabels_data()
1075{
1076 QTest::addColumn<int>(name: "rows");
1077 QTest::addColumn<int>(name: "columns");
1078 QTest::addColumn<Qt::Orientation>(name: "orientation");
1079 QTest::addColumn<QStringList>(name: "labels");
1080 QTest::addColumn<QStringList>(name: "expectedLabels");
1081
1082 QTest::newRow(dataTag: "horizontal labels")
1083 << 1
1084 << 4
1085 << Qt::Horizontal
1086 << (QStringList() << "a" << "b" << "c" << "d")
1087 << (QStringList() << "a" << "b" << "c" << "d");
1088 QTest::newRow(dataTag: "vertical labels")
1089 << 4
1090 << 1
1091 << Qt::Vertical
1092 << (QStringList() << "a" << "b" << "c" << "d")
1093 << (QStringList() << "a" << "b" << "c" << "d");
1094 QTest::newRow(dataTag: "too few (horizontal)")
1095 << 1
1096 << 4
1097 << Qt::Horizontal
1098 << (QStringList() << "a" << "b")
1099 << (QStringList() << "a" << "b" << "3" << "4");
1100 QTest::newRow(dataTag: "too few (vertical)")
1101 << 4
1102 << 1
1103 << Qt::Vertical
1104 << (QStringList() << "a" << "b")
1105 << (QStringList() << "a" << "b" << "3" << "4");
1106 QTest::newRow(dataTag: "too many (horizontal)")
1107 << 1
1108 << 2
1109 << Qt::Horizontal
1110 << (QStringList() << "a" << "b" << "c" << "d")
1111 << (QStringList() << "a" << "b" << "c" << "d");
1112 QTest::newRow(dataTag: "too many (vertical)")
1113 << 2
1114 << 1
1115 << Qt::Vertical
1116 << (QStringList() << "a" << "b" << "c" << "d")
1117 << (QStringList() << "a" << "b" << "c" << "d");
1118}
1119
1120void tst_QStandardItemModel::setHeaderLabels()
1121{
1122 QFETCH(int, rows);
1123 QFETCH(int, columns);
1124 QFETCH(Qt::Orientation, orientation);
1125 QFETCH(QStringList, labels);
1126 QFETCH(QStringList, expectedLabels);
1127 QStandardItemModel model(rows, columns);
1128 QSignalSpy columnsInsertedSpy(&model, &QAbstractItemModel::columnsInserted);
1129 QSignalSpy rowsInsertedSpy(&model, &QAbstractItemModel::rowsInserted);
1130 if (orientation == Qt::Horizontal)
1131 model.setHorizontalHeaderLabels(labels);
1132 else
1133 model.setVerticalHeaderLabels(labels);
1134 for (int i = 0; i < expectedLabels.count(); ++i)
1135 QCOMPARE(model.headerData(i, orientation).toString(), expectedLabels.at(i));
1136 QCOMPARE(columnsInsertedSpy.count(),
1137 (orientation == Qt::Vertical) ? 0 : labels.count() > columns);
1138 QCOMPARE(rowsInsertedSpy.count(),
1139 (orientation == Qt::Horizontal) ? 0 : labels.count() > rows);
1140}
1141
1142void tst_QStandardItemModel::itemDataChanged()
1143{
1144 QStandardItemModel model(6, 4);
1145 QStandardItem item;
1146 QSignalSpy dataChangedSpy(&model, &QStandardItemModel::dataChanged);
1147 QSignalSpy itemChangedSpy(&model, &QStandardItemModel::itemChanged);
1148
1149 model.setItem(arow: 0, aitem: &item);
1150 QCOMPARE(dataChangedSpy.count(), 1);
1151 QCOMPARE(itemChangedSpy.count(), 1);
1152 QModelIndex index = model.indexFromItem(item: &item);
1153 QList<QVariant> args;
1154 args = dataChangedSpy.takeFirst();
1155 QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), index);
1156 QCOMPARE(qvariant_cast<QModelIndex>(args.at(1)), index);
1157 args = itemChangedSpy.takeFirst();
1158 QCOMPARE(qvariant_cast<QStandardItem*>(args.at(0)), &item);
1159
1160 item.setData(value: QLatin1String("foo"), role: Qt::DisplayRole);
1161 QCOMPARE(dataChangedSpy.count(), 1);
1162 QCOMPARE(itemChangedSpy.count(), 1);
1163 args = dataChangedSpy.takeFirst();
1164 QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), index);
1165 QCOMPARE(qvariant_cast<QModelIndex>(args.at(1)), index);
1166 args = itemChangedSpy.takeFirst();
1167 QCOMPARE(qvariant_cast<QStandardItem*>(args.at(0)), &item);
1168
1169 item.setData(value: item.data(role: Qt::DisplayRole), role: Qt::DisplayRole);
1170 QCOMPARE(dataChangedSpy.count(), 0);
1171 QCOMPARE(itemChangedSpy.count(), 0);
1172
1173 item.setFlags(Qt::ItemIsEnabled);
1174 QCOMPARE(dataChangedSpy.count(), 1);
1175 QCOMPARE(itemChangedSpy.count(), 1);
1176 args = dataChangedSpy.takeFirst();
1177 QCOMPARE(qvariant_cast<QModelIndex>(args.at(0)), index);
1178 QCOMPARE(qvariant_cast<QModelIndex>(args.at(1)), index);
1179 args = itemChangedSpy.takeFirst();
1180 QCOMPARE(qvariant_cast<QStandardItem*>(args.at(0)), &item);
1181
1182 item.setFlags(item.flags());
1183 QCOMPARE(dataChangedSpy.count(), 0);
1184 QCOMPARE(itemChangedSpy.count(), 0);
1185}
1186
1187void tst_QStandardItemModel::takeHeaderItem()
1188{
1189 QStandardItemModel model;
1190 // set header items
1191 QScopedPointer<QStandardItem> hheader(new QStandardItem());
1192 model.setHorizontalHeaderItem(column: 0, item: hheader.get());
1193 QScopedPointer<QStandardItem> vheader(new QStandardItem());
1194 model.setVerticalHeaderItem(row: 0, item: vheader.get());
1195 // take header items
1196 QCOMPARE(model.takeHorizontalHeaderItem(0), hheader.get());
1197 QCOMPARE(model.takeVerticalHeaderItem(0), vheader.get());
1198 QCOMPARE(hheader->model(), nullptr);
1199 QCOMPARE(vheader->model(), nullptr);
1200 QCOMPARE(model.takeHorizontalHeaderItem(0), nullptr);
1201 QCOMPARE(model.takeVerticalHeaderItem(0), nullptr);
1202}
1203
1204void tst_QStandardItemModel::useCase1()
1205{
1206 const int rows = 5;
1207 const int columns = 8;
1208 QStandardItemModel model(rows, columns);
1209 for (int i = 0; i < model.rowCount(); ++i) {
1210 for (int j = 0; j < model.columnCount(); ++j) {
1211 QCOMPARE(model.item(i, j), nullptr);
1212
1213 QStandardItem *item = new QStandardItem();
1214 model.setItem(row: i, column: j, item);
1215 QCOMPARE(item->row(), i);
1216 QCOMPARE(item->column(), j);
1217 QCOMPARE(item->model(), &model);
1218
1219 QModelIndex index = model.indexFromItem(item);
1220 QCOMPARE(index, model.index(i, j, QModelIndex()));
1221 QStandardItem *sameItem = model.itemFromIndex(index);
1222 QCOMPARE(sameItem, item);
1223 }
1224 }
1225}
1226
1227static void createChildren(QStandardItemModel *model, QStandardItem *parent, int level)
1228{
1229 if (level > 4)
1230 return;
1231 for (int i = 0; i < 4; ++i) {
1232 QCOMPARE(parent->rowCount(), i);
1233 parent->appendRow(aitems: QList<QStandardItem*>());
1234 for (int j = 0; j < parent->columnCount(); ++j) {
1235 QStandardItem *item = new QStandardItem();
1236 parent->setChild(row: i, column: j, item);
1237 QCOMPARE(item->row(), i);
1238 QCOMPARE(item->column(), j);
1239
1240 QModelIndex parentIndex = model->indexFromItem(item: parent);
1241 QModelIndex index = model->indexFromItem(item);
1242 QCOMPARE(index, model->index(i, j, parentIndex));
1243 QStandardItem *theItem = model->itemFromIndex(index);
1244 QCOMPARE(theItem, item);
1245 QStandardItem *theParent = model->itemFromIndex(index: parentIndex);
1246 QCOMPARE(theParent, (level == 0) ? static_cast<QStandardItem *>(nullptr) : parent);
1247 }
1248
1249 {
1250 QStandardItem *item = parent->child(row: i);
1251 item->setColumnCount(parent->columnCount());
1252 createChildren(model, parent: item, level: level + 1);
1253 }
1254 }
1255}
1256
1257void tst_QStandardItemModel::useCase2()
1258{
1259 QStandardItemModel model;
1260 model.setColumnCount(2);
1261 createChildren(model: &model, parent: model.invisibleRootItem(), level: 0);
1262}
1263
1264void tst_QStandardItemModel::useCase3()
1265{
1266 // create the tree structure first
1267 QStandardItem *childItem = nullptr;
1268 for (int i = 0; i < 100; ++i) {
1269 QStandardItem *item = new QStandardItem(QStringLiteral("item ") + QString::number(i));
1270 if (childItem)
1271 item->appendRow(aitem: childItem);
1272 childItem = item;
1273 }
1274
1275 // add to model as last step
1276 QStandardItemModel model;
1277 model.appendRow(aitem: childItem);
1278
1279 // make sure each item has the correct model and parent
1280 QStandardItem *parentItem = nullptr;
1281 while (childItem) {
1282 QCOMPARE(childItem->model(), &model);
1283 QCOMPARE(childItem->parent(), parentItem);
1284 parentItem = childItem;
1285 childItem = childItem->child(row: 0);
1286 }
1287
1288 // take the item, make sure model is set to 0, but that parents are the same
1289 childItem = model.takeItem(row: 0);
1290 {
1291 parentItem = nullptr;
1292 QStandardItem *item = childItem;
1293 while (item) {
1294 QCOMPARE(item->model(), nullptr);
1295 QCOMPARE(item->parent(), parentItem);
1296 parentItem = item;
1297 item = item->child(row: 0);
1298 }
1299 }
1300 delete childItem;
1301}
1302
1303void tst_QStandardItemModel::setNullChild()
1304{
1305 QStandardItemModel model;
1306 model.setColumnCount(2);
1307 createChildren(model: &model, parent: model.invisibleRootItem(), level: 0);
1308 QStandardItem *item = model.item(row: 0);
1309 QSignalSpy spy(&model, &QAbstractItemModel::dataChanged);
1310 item->setChild(arow: 0, aitem: nullptr);
1311 QCOMPARE(item->child(0), nullptr);
1312 QCOMPARE(spy.count(), 1);
1313}
1314
1315void tst_QStandardItemModel::deleteChild()
1316{
1317 QStandardItemModel model;
1318 model.setColumnCount(2);
1319 createChildren(model: &model, parent: model.invisibleRootItem(), level: 0);
1320 QStandardItem *item = model.item(row: 0);
1321 QSignalSpy spy(&model, &QAbstractItemModel::dataChanged);
1322 delete item->child(row: 0);
1323 QCOMPARE(item->child(0), nullptr);
1324 QCOMPARE(spy.count(), 1);
1325}
1326
1327void tst_QStandardItemModel::rootItemFlags()
1328{
1329 QStandardItemModel model(6, 4);
1330 QCOMPARE(model.invisibleRootItem()->flags() , model.flags(QModelIndex()));
1331 QCOMPARE(model.invisibleRootItem()->flags() , Qt::ItemIsDropEnabled);
1332
1333 Qt::ItemFlags f = Qt::ItemIsDropEnabled | Qt::ItemIsEnabled;
1334 model.invisibleRootItem()->setFlags(f);
1335 QCOMPARE(model.invisibleRootItem()->flags() , f);
1336 QCOMPARE(model.invisibleRootItem()->flags() , model.flags(QModelIndex()));
1337
1338#if QT_CONFIG(draganddrop)
1339 model.invisibleRootItem()->setDropEnabled(false);
1340#endif
1341 QCOMPARE(model.invisibleRootItem()->flags() , Qt::ItemIsEnabled);
1342 QCOMPARE(model.invisibleRootItem()->flags() , model.flags(QModelIndex()));
1343}
1344
1345bool tst_QStandardItemModel::compareModels(QStandardItemModel *model1, QStandardItemModel *model2)
1346{
1347 return compareItems(item1: model1->invisibleRootItem(), item2: model2->invisibleRootItem());
1348}
1349
1350bool tst_QStandardItemModel::compareItems(QStandardItem *item1, QStandardItem *item2)
1351{
1352 if (!item1 && !item2)
1353 return true;
1354 if (!item1 || !item2)
1355 return false;
1356 if (item1->text() != item2->text()) {
1357 qDebug() << item1->text() << item2->text();
1358 return false;
1359 }
1360 if (item1->rowCount() != item2->rowCount()) {
1361 // qDebug() << "RowCount" << item1->text() << item1->rowCount() << item2->rowCount();
1362 return false;
1363 }
1364 if (item1->columnCount() != item2->columnCount()) {
1365 // qDebug() << "ColumnCount" << item1->text() << item1->columnCount() << item2->columnCount();
1366 return false;
1367 }
1368 for (int row = 0; row < item1->columnCount(); row++) {
1369 for (int col = 0; col < item1->columnCount(); col++) {
1370 if (!compareItems(item1: item1->child(row, column: col), item2: item2->child(row, column: col)))
1371 return false;
1372 }
1373 }
1374 return true;
1375}
1376
1377static QStandardItem *itemFromText(QStandardItem *parent, const QString &text)
1378{
1379 QStandardItem *item = nullptr;
1380 for (int i = 0; i < parent->columnCount(); i++) {
1381 for (int j = 0; j < parent->rowCount(); j++) {
1382 QStandardItem *child = parent->child(row: j, column: i);
1383 if (!child)
1384 continue;
1385
1386 if (child->text() == text) {
1387 if (item)
1388 return nullptr;
1389 item = child;
1390 }
1391
1392 QStandardItem *candidate = itemFromText(parent: child, text);
1393 if (candidate) {
1394 if (item)
1395 return nullptr;
1396 item = candidate;
1397 }
1398 }
1399 }
1400 return item;
1401}
1402
1403#ifdef QT_BUILD_INTERNAL
1404static QModelIndex indexFromText(QStandardItemModel *model, const QString &text)
1405{
1406 QStandardItem *item = itemFromText(parent: model->invisibleRootItem(), text);
1407 /*QVERIFY(item);*/
1408 return model->indexFromItem(item);
1409}
1410
1411
1412struct FriendlyTreeView : public QTreeView
1413{
1414 friend class tst_QStandardItemModel;
1415 Q_DECLARE_PRIVATE(QTreeView)
1416};
1417#endif
1418
1419#ifdef QT_BUILD_INTERNAL
1420
1421static void populateDragAndDropModel(QStandardItemModel &model, int nRow, int nCol)
1422{
1423 const QString item = QStringLiteral("item ");
1424 const QString dash = QStringLiteral(" - ");
1425 for (int i = 0; i < nRow; ++i) {
1426 const QString iS = QString::number(i);
1427 QList<QStandardItem *> colItems1;
1428 for (int c = 0 ; c < nCol; c ++)
1429 colItems1 << new QStandardItem(item + iS + dash + QString::number(c));
1430 model.appendRow(items: colItems1);
1431
1432 for (int j = 0; j < nRow; ++j) {
1433 const QString jS = QString::number(j);
1434 QList<QStandardItem *> colItems2;
1435 for (int c = 0 ; c < nCol; c ++)
1436 colItems2 << new QStandardItem(item + iS + QLatin1Char('/') + jS + dash + QString::number(c));
1437 colItems1.at(i: 0)->appendRow(aitems: colItems2);
1438
1439 for (int k = 0; k < nRow; ++k) {
1440 QList<QStandardItem *> colItems3;
1441 const QString kS = QString::number(k);
1442 for (int c = 0 ; c < nCol; c ++)
1443 colItems3 << new QStandardItem(item + iS + QLatin1Char('/') + jS
1444 + QLatin1Char('/') + kS
1445 + dash + QString::number(c));
1446 colItems2.at(i: 0)->appendRow(aitems: colItems3);
1447 }
1448 }
1449 }
1450}
1451
1452void tst_QStandardItemModel::treeDragAndDrop()
1453{
1454 const int nRow = 5;
1455 const int nCol = 3;
1456
1457 QStandardItemModel model;
1458 QStandardItemModel checkModel;
1459
1460 populateDragAndDropModel(model, nRow, nCol);
1461 populateDragAndDropModel(model&: checkModel, nRow, nCol);
1462
1463 QVERIFY(compareModels(&model, &checkModel));
1464
1465 FriendlyTreeView view;
1466 view.setModel(&model);
1467 view.expandAll();
1468 view.show();
1469#if QT_CONFIG(draganddrop)
1470 view.setDragDropMode(QAbstractItemView::InternalMove);
1471#endif
1472 view.setSelectionMode(QAbstractItemView::ExtendedSelection);
1473
1474 QItemSelectionModel *selection = view.selectionModel();
1475
1476 //
1477 // step1 drag "item 1" and "item 2" into "item 4"
1478 //
1479 {
1480 selection->clear();
1481 selection->select(selection: QItemSelection(indexFromText(model: &model, text: QString("item 1 - 0")),
1482 indexFromText(model: &model, text: QString("item 1 - %0").arg(a: nCol-1))), command: QItemSelectionModel::Select);
1483
1484 selection->select(selection: QItemSelection(indexFromText(model: &model, text: QString("item 2 - 0")),
1485 indexFromText(model: &model, text: QString("item 2 - %0").arg(a: nCol-1))), command: QItemSelectionModel::Select);
1486
1487 //code based from QAbstractItemView::startDrag and QAbstractItemView::dropEvent
1488 QModelIndexList indexes = view.selectedIndexes();
1489 QMimeData *data = model.mimeData(indexes);
1490 if(model.dropMimeData(data, action: Qt::MoveAction, row: 0, column: 0, parent: indexFromText(model: &model, text: "item 4 - 0")))
1491 view.d_func()->clearOrRemove();
1492 delete data;
1493
1494 QVERIFY(!compareModels(&model, &checkModel)); //the model must be different at this point
1495 QStandardItem *item4 = itemFromText(parent: checkModel.invisibleRootItem(), text: "item 4 - 0");
1496 item4->insertRow(row: 0, items: checkModel.takeRow(row: 1));
1497 item4->insertRow(row: 1, items: checkModel.takeRow(row: 1));
1498 QVERIFY(compareModels(&model, &checkModel));
1499 }
1500
1501 //
1502 // step2 drag "item 3" and "item 3/0" into "item 4"
1503 //
1504 {
1505 selection->clear();
1506 selection->select(selection: QItemSelection(indexFromText(model: &model, text: QString("item 3 - 0")),
1507 indexFromText(model: &model, text: QString("item 3 - %0").arg(a: nCol-1))), command: QItemSelectionModel::Select);
1508
1509 selection->select(selection: QItemSelection(indexFromText(model: &model, text: QString("item 3/0 - 0")),
1510 indexFromText(model: &model, text: QString("item 3/0 - %0").arg(a: nCol-1))), command: QItemSelectionModel::Select);
1511
1512 //code based from QAbstractItemView::startDrag and QAbstractItemView::dropEvent
1513 QModelIndexList indexes = view.selectedIndexes();
1514 QMimeData *data = model.mimeData(indexes);
1515 if(model.dropMimeData(data, action: Qt::MoveAction, row: 0, column: 0, parent: indexFromText(model: &model, text: "item 4 - 0")))
1516 view.d_func()->clearOrRemove();
1517 delete data;
1518
1519 QVERIFY(!compareModels(&model, &checkModel)); //the model must be different at this point
1520 QStandardItem *item4 = itemFromText(parent: checkModel.invisibleRootItem(), text: "item 4 - 0");
1521 item4->insertRow(row: 0, items: checkModel.takeRow(row: 1));
1522
1523 QVERIFY(compareModels(&model, &checkModel));
1524 }
1525
1526 //
1527 // step2 drag "item 3" and "item 3/0/2" into "item 0/2"
1528 // ( remember "item 3" is now the first child of "item 4")
1529 //
1530 {
1531 selection->clear();
1532 selection->select(selection: QItemSelection(indexFromText(model: &model, text: QString("item 3 - 0")),
1533 indexFromText(model: &model, text: QString("item 3 - %0").arg(a: nCol-1))), command: QItemSelectionModel::Select);
1534
1535 selection->select(selection: QItemSelection(indexFromText(model: &model, text: QString("item 3/0/2 - 0")),
1536 indexFromText(model: &model, text: QString("item 3/0/2 - %0").arg(a: nCol-1))), command: QItemSelectionModel::Select);
1537
1538 //code based from QAbstractItemView::startDrag and QAbstractItemView::dropEvent
1539 QModelIndexList indexes = view.selectedIndexes();
1540 QMimeData *data = model.mimeData(indexes);
1541 if(model.dropMimeData(data, action: Qt::MoveAction, row: 0, column: 0, parent: indexFromText(model: &model, text: "item 0/2 - 0")))
1542 view.d_func()->clearOrRemove();
1543 delete data;
1544
1545 QVERIFY(!compareModels(&model, &checkModel)); //the model must be different at this point
1546 QStandardItem *item02 = itemFromText(parent: checkModel.invisibleRootItem(), text: "item 0/2 - 0");
1547 QStandardItem *item4 = itemFromText(parent: checkModel.invisibleRootItem(), text: "item 4 - 0");
1548 item02->insertRow(row: 0, items: item4->takeRow(row: 0));
1549
1550 QVERIFY(compareModels(&model, &checkModel));
1551 }
1552}
1553#endif
1554
1555void tst_QStandardItemModel::removeRowsAndColumns()
1556{
1557#define VERIFY_MODEL \
1558 for (int c = 0; c < col_list.count(); c++) \
1559 for (int r = 0; r < row_list.count(); r++) \
1560 QCOMPARE(model.item(r,c)->text() , row_list[r] + QLatin1Char('x') + col_list[c]);
1561
1562 QVector<QString> row_list = QString("1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20").split(sep: ',').toVector();
1563 QVector<QString> col_list = row_list;
1564 QStandardItemModel model;
1565 for (int c = 0; c < col_list.count(); c++)
1566 for (int r = 0; r < row_list.count(); r++)
1567 model.setItem(row: r, column: c, item: new QStandardItem(row_list[r] + QLatin1Char('x') + col_list[c]));
1568 VERIFY_MODEL
1569
1570 row_list.remove(i: 3);
1571 model.removeRow(arow: 3);
1572 VERIFY_MODEL
1573
1574 col_list.remove(i: 5);
1575 model.removeColumn(acolumn: 5);
1576 VERIFY_MODEL
1577
1578 row_list.remove(i: 2, n: 5);
1579 model.removeRows(row: 2, count: 5);
1580 VERIFY_MODEL
1581
1582 col_list.remove(i: 1, n: 6);
1583 model.removeColumns(column: 1, count: 6);
1584 VERIFY_MODEL
1585
1586 QList<QStandardItem *> row_taken = model.takeRow(row: 6);
1587 QCOMPARE(row_taken.count(), col_list.count());
1588 for (int c = 0; c < col_list.count(); c++)
1589 QCOMPARE(row_taken[c]->text() , row_list[6] + QLatin1Char('x') + col_list[c]);
1590 row_list.remove(i: 6);
1591 VERIFY_MODEL
1592
1593 QList<QStandardItem *> col_taken = model.takeColumn(column: 10);
1594 QCOMPARE(col_taken.count(), row_list.count());
1595 for (int r = 0; r < row_list.count(); r++)
1596 QCOMPARE(col_taken[r]->text() , row_list[r] + QLatin1Char('x') + col_list[10]);
1597 col_list.remove(i: 10);
1598 VERIFY_MODEL
1599}
1600
1601void tst_QStandardItemModel::itemRoleNames()
1602{
1603 QVector<QString> row_list = QString("1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20").split(sep: ',').toVector();
1604 QVector<QString> col_list = row_list;
1605 QStandardItemModel model;
1606 for (int c = 0; c < col_list.count(); c++)
1607 for (int r = 0; r < row_list.count(); r++)
1608 model.setItem(row: r, column: c, item: new QStandardItem(row_list[r] + QLatin1Char('x') + col_list[c]));
1609 VERIFY_MODEL
1610
1611 QHash<int, QByteArray> newRoleNames;
1612 newRoleNames.insert(key: Qt::DisplayRole, value: "Name");
1613 newRoleNames.insert(key: Qt::DecorationRole, value: "Avatar");
1614 model.setItemRoleNames(newRoleNames);
1615 QCOMPARE(model.roleNames(), newRoleNames);
1616 VERIFY_MODEL
1617}
1618
1619void tst_QStandardItemModel::getMimeDataWithInvalidModelIndex()
1620{
1621 QStandardItemModel model;
1622 QTest::ignoreMessage(type: QtWarningMsg, message: "QStandardItemModel::mimeData: No item associated with invalid index");
1623 QMimeData *data = model.mimeData(indexes: QModelIndexList() << QModelIndex());
1624 QVERIFY(!data);
1625}
1626
1627void tst_QStandardItemModel::supportedDragDropActions()
1628{
1629 QStandardItemModel model;
1630 QCOMPARE(model.supportedDragActions(), Qt::CopyAction | Qt::MoveAction);
1631 QCOMPARE(model.supportedDropActions(), Qt::CopyAction | Qt::MoveAction);
1632}
1633
1634void tst_QStandardItemModel::taskQTBUG_45114_setItemData()
1635{
1636 QStandardItemModel model;
1637 QSignalSpy spy(&model, &QStandardItemModel::itemChanged);
1638
1639 QStandardItem *item = new QStandardItem("item");
1640 item->setData(value: 1, role: Qt::UserRole + 1);
1641 item->setData(value: 2, role: Qt::UserRole + 2);
1642 model.appendRow(aitem: item);
1643
1644 QModelIndex index = item->index();
1645 QCOMPARE(model.itemData(index).size(), 3);
1646
1647 QCOMPARE(spy.count(), 0);
1648
1649 QMap<int, QVariant> roles;
1650
1651 roles.insert(key: Qt::UserRole + 1, value: 1);
1652 roles.insert(key: Qt::UserRole + 2, value: 2);
1653 model.setItemData(index, roles);
1654
1655 QCOMPARE(spy.count(), 0);
1656
1657 roles.insert(key: Qt::UserRole + 1, value: 1);
1658 roles.insert(key: Qt::UserRole + 2, value: 2);
1659 roles.insert(key: Qt::UserRole + 3, value: QVariant());
1660 model.setItemData(index, roles);
1661
1662 QCOMPARE(spy.count(), 0);
1663
1664 roles.clear();
1665 roles.insert(key: Qt::UserRole + 1, value: 10);
1666 roles.insert(key: Qt::UserRole + 3, value: 12);
1667 model.setItemData(index, roles);
1668
1669 QCOMPARE(spy.count(), 1);
1670 QMap<int, QVariant> itemRoles = model.itemData(index);
1671
1672 QCOMPARE(itemRoles.size(), 4);
1673 QCOMPARE(itemRoles[Qt::UserRole + 1].toInt(), 10);
1674 QCOMPARE(itemRoles[Qt::UserRole + 2].toInt(), 2);
1675 QCOMPARE(itemRoles[Qt::UserRole + 3].toInt(), 12);
1676
1677 roles.clear();
1678 roles.insert(key: Qt::UserRole + 3, value: 1);
1679 model.setItemData(index, roles);
1680
1681 QCOMPARE(spy.count(), 2);
1682
1683 roles.clear();
1684 roles.insert(key: Qt::UserRole + 3, value: QVariant());
1685 model.setItemData(index, roles);
1686
1687 QCOMPARE(spy.count(), 3);
1688
1689 itemRoles = model.itemData(index);
1690 QCOMPARE(itemRoles.size(), 3);
1691 QVERIFY(!itemRoles.keys().contains(Qt::UserRole + 3));
1692}
1693
1694void tst_QStandardItemModel::setItemPersistentIndex()
1695{
1696 QPersistentModelIndex persistentIndex;
1697 // setItem on an already existing item should not destroy the persistent index
1698 QStandardItemModel m;
1699 persistentIndex = m.index(row: 0, column: 0);
1700 QVERIFY(!persistentIndex.isValid());
1701
1702 m.setItem(row: 0, column: 0, item: new QStandardItem);
1703 persistentIndex = m.index(row: 0, column: 0);
1704 QVERIFY(persistentIndex.isValid());
1705 QCOMPARE(persistentIndex.row(), 0);
1706 QCOMPARE(persistentIndex.column(), 0);
1707
1708 m.setItem(row: 0, column: 0, item: new QStandardItem);
1709 QVERIFY(persistentIndex.isValid());
1710
1711 m.setItem(row: 0, column: 0, item: nullptr);
1712 QVERIFY(!persistentIndex.isValid());
1713}
1714
1715QTEST_MAIN(tst_QStandardItemModel)
1716#include "tst_qstandarditemmodel.moc"
1717

source code of qtbase/tests/auto/gui/itemmodels/qstandarditemmodel/tst_qstandarditemmodel.cpp