| 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 |  | 
| 36 | class tst_QStandardItemModel : public QObject | 
| 37 | { | 
| 38 |     Q_OBJECT | 
| 39 |  | 
| 40 | public: | 
| 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 |  | 
| 54 | public slots: | 
| 55 |     void init(); | 
| 56 |     void cleanup(); | 
| 57 |  | 
| 58 | protected 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 |  | 
| 82 | private 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 |  | 
| 136 | private: | 
| 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 |  | 
| 150 | static constexpr int defaultSize = 3; | 
| 151 |  | 
| 152 | Q_DECLARE_METATYPE(QStandardItem*) | 
| 153 | Q_DECLARE_METATYPE(Qt::Orientation) | 
| 154 |  | 
| 155 | tst_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 | */ | 
| 173 | void 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 |  | 
| 204 | void tst_QStandardItemModel::cleanup() | 
| 205 | { | 
| 206 |     m_model->disconnect(receiver: this); | 
| 207 |     delete m_model; | 
| 208 |     m_model = nullptr; | 
| 209 | } | 
| 210 |  | 
| 211 | void 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 |  | 
| 223 | void 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 |  | 
| 260 | void tst_QStandardItemModel::insertRows() | 
| 261 | { | 
| 262 |     int rowCount = m_model->rowCount(); | 
| 263 |     QCOMPARE(rowCount, defaultSize); | 
| 264 |  | 
| 265 |     // insert custom header label | 
| 266 |     QString  = "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 |  | 
| 291 | void 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 |  | 
| 311 | void 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 |  | 
| 328 | void 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 |  | 
| 340 | void 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 |  | 
| 376 | void tst_QStandardItemModel::insertColumns() | 
| 377 | { | 
| 378 |     int columnCount = m_model->columnCount(); | 
| 379 |     QCOMPARE(columnCount, defaultSize); | 
| 380 |  | 
| 381 |     // insert custom header label | 
| 382 |     QString  = "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 |  | 
| 406 | void tst_QStandardItemModel::removeRows() | 
| 407 | { | 
| 408 |     int rowCount = m_model->rowCount(); | 
| 409 |     QCOMPARE(rowCount, defaultSize); | 
| 410 |  | 
| 411 |     // insert custom header label | 
| 412 |     QString  = "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 |  | 
| 428 | void tst_QStandardItemModel::removeColumns() | 
| 429 | { | 
| 430 |     int columnCount = m_model->columnCount(); | 
| 431 |     QCOMPARE(columnCount, defaultSize); | 
| 432 |  | 
| 433 |     // insert custom header label | 
| 434 |     QString  = "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 |  | 
| 451 | void 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 ( | 
| 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 |  | 
| 494 | void 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 |  | 
| 566 | void tst_QStandardItemModel::checkAboutToBeRemoved() | 
| 567 | { | 
| 568 |     QVERIFY(persistent.isValid()); | 
| 569 | } | 
| 570 |  | 
| 571 | void tst_QStandardItemModel::checkRemoved() | 
| 572 | { | 
| 573 |     QVERIFY(!persistent.isValid()); | 
| 574 | } | 
| 575 |  | 
| 576 | void 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 |  | 
| 634 | void tst_QStandardItemModel::updateRowAboutToBeRemoved() | 
| 635 | { | 
| 636 |     QModelIndex idx = m_model->index(row: 0, column: 0); | 
| 637 |     QVERIFY(idx.isValid()); | 
| 638 |     persistent = idx; | 
| 639 | } | 
| 640 |  | 
| 641 | void 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 |  | 
| 657 | void 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 |  | 
| 666 | void 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 |  | 
| 719 | void 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 |  | 
| 747 | void 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 |  | 
| 768 | void 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 |  | 
| 793 | void 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 |  | 
| 821 | void 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 |  | 
| 855 | void 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 |  | 
| 880 | void 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 |  | 
| 905 | void 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 |  | 
| 924 | void tst_QStandardItemModel::getSetHeaderItem() | 
| 925 | { | 
| 926 |     QStandardItemModel model; | 
| 927 |  | 
| 928 |     QCOMPARE(model.horizontalHeaderItem(0), nullptr); | 
| 929 |     QStandardItem * = 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 * = 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 |  | 
| 947 | void 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 |  | 
| 980 | void 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 |  | 
| 1002 | class CustomItem : public QStandardItem | 
| 1003 | { | 
| 1004 | public: | 
| 1005 |     using QStandardItem::QStandardItem; | 
| 1006 |  | 
| 1007 |     int type() const override { return UserType; } | 
| 1008 |     QStandardItem *clone() const override { return new CustomItem; } | 
| 1009 | }; | 
| 1010 |  | 
| 1011 | void 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 |  | 
| 1032 | void 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 |  | 
| 1074 | void 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 |  | 
| 1120 | void 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 |  | 
| 1142 | void 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 |  | 
| 1187 | void tst_QStandardItemModel::takeHeaderItem() | 
| 1188 | { | 
| 1189 |     QStandardItemModel model; | 
| 1190 |     // set header items | 
| 1191 |     QScopedPointer<QStandardItem> (new QStandardItem()); | 
| 1192 |     model.setHorizontalHeaderItem(column: 0, item: hheader.get()); | 
| 1193 |     QScopedPointer<QStandardItem> (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 |  | 
| 1204 | void 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 |  | 
| 1227 | static 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 |  | 
| 1257 | void tst_QStandardItemModel::useCase2() | 
| 1258 | { | 
| 1259 |     QStandardItemModel model; | 
| 1260 |     model.setColumnCount(2); | 
| 1261 |     createChildren(model: &model, parent: model.invisibleRootItem(), level: 0); | 
| 1262 | } | 
| 1263 |  | 
| 1264 | void 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 |  | 
| 1303 | void 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 |  | 
| 1315 | void 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 |  | 
| 1327 | void 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 |  | 
| 1345 | bool tst_QStandardItemModel::compareModels(QStandardItemModel *model1, QStandardItemModel *model2) | 
| 1346 | { | 
| 1347 |     return compareItems(item1: model1->invisibleRootItem(), item2: model2->invisibleRootItem()); | 
| 1348 | } | 
| 1349 |  | 
| 1350 | bool 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 |  | 
| 1377 | static 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 | 
| 1404 | static 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 |  | 
| 1412 | struct FriendlyTreeView : public QTreeView | 
| 1413 | { | 
| 1414 |     friend class tst_QStandardItemModel; | 
| 1415 |     Q_DECLARE_PRIVATE(QTreeView) | 
| 1416 | }; | 
| 1417 | #endif | 
| 1418 |  | 
| 1419 | #ifdef QT_BUILD_INTERNAL | 
| 1420 |  | 
| 1421 | static 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 |  | 
| 1452 | void 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 |  | 
| 1555 | void 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 |  | 
| 1601 | void 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 |  | 
| 1619 | void 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 |  | 
| 1627 | void 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 |  | 
| 1634 | void 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 |  | 
| 1694 | void 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 |  | 
| 1715 | QTEST_MAIN(tst_QStandardItemModel) | 
| 1716 | #include "tst_qstandarditemmodel.moc" | 
| 1717 |  |