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