| 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 |  | 
| 32 | #include <QtCore/QSortFilterProxyModel> | 
| 33 | #include <QtCore/QStringListModel> | 
| 34 | #include <QtGui/QStandardItemModel> | 
| 35 |  | 
| 36 | #include "dynamictreemodel.h" | 
| 37 |  | 
| 38 | /*! | 
| 39 |     Note that this doesn't test models, but any functionality that QAbstractItemModel should provide | 
| 40 |  */ | 
| 41 | class tst_QAbstractItemModel : public QObject | 
| 42 | { | 
| 43 |     Q_OBJECT | 
| 44 |  | 
| 45 | public slots: | 
| 46 |     void init(); | 
| 47 |     void cleanup(); | 
| 48 |  | 
| 49 | private slots: | 
| 50 |     void index(); | 
| 51 |     void parent(); | 
| 52 |     void hasChildren(); | 
| 53 |     void data(); | 
| 54 |     void headerData(); | 
| 55 |     void itemData(); | 
| 56 |     void itemFlags(); | 
| 57 |     void match(); | 
| 58 |     void dropMimeData_data(); | 
| 59 |     void dropMimeData(); | 
| 60 |     void canDropMimeData(); | 
| 61 |     void changePersistentIndex(); | 
| 62 |     void movePersistentIndex(); | 
| 63 |  | 
| 64 |     void insertRows(); | 
| 65 |     void insertColumns(); | 
| 66 |     void removeRows(); | 
| 67 |     void removeColumns(); | 
| 68 |     void moveRows(); | 
| 69 |     void moveColumns(); | 
| 70 |  | 
| 71 |     void reset(); | 
| 72 |  | 
| 73 |     void complexChangesWithPersistent(); | 
| 74 |  | 
| 75 |     void testMoveSameParentUp_data(); | 
| 76 |     void testMoveSameParentUp(); | 
| 77 |  | 
| 78 |     void testMoveSameParentDown_data(); | 
| 79 |     void testMoveSameParentDown(); | 
| 80 |  | 
| 81 |     void testMoveToGrandParent_data(); | 
| 82 |     void testMoveToGrandParent(); | 
| 83 |  | 
| 84 |     void testMoveToSibling_data(); | 
| 85 |     void testMoveToSibling(); | 
| 86 |  | 
| 87 |     void testMoveToUncle_data(); | 
| 88 |     void testMoveToUncle(); | 
| 89 |  | 
| 90 |     void testMoveToDescendants(); | 
| 91 |  | 
| 92 |     void testMoveWithinOwnRange_data(); | 
| 93 |     void testMoveWithinOwnRange(); | 
| 94 |  | 
| 95 |     void testMoveThroughProxy(); | 
| 96 |  | 
| 97 |     void testReset(); | 
| 98 |  | 
| 99 |     void testDataChanged(); | 
| 100 |  | 
| 101 |     void testChildrenLayoutsChanged(); | 
| 102 |  | 
| 103 |     void testRoleNames(); | 
| 104 |     void testDragActions(); | 
| 105 |     void dragActionsFallsBackToDropActions(); | 
| 106 |  | 
| 107 |     void testFunctionPointerSignalConnection(); | 
| 108 |  | 
| 109 |     void checkIndex(); | 
| 110 |  | 
| 111 | private: | 
| 112 |     DynamicTreeModel *m_model; | 
| 113 | }; | 
| 114 |  | 
| 115 | /*! | 
| 116 |     Test model that impliments the pure vitual functions and anything else that is | 
| 117 |     needed. | 
| 118 |  | 
| 119 |     It is a table implemented as a vector of vectors of strings. | 
| 120 |  */ | 
| 121 | class QtTestModel: public QAbstractItemModel | 
| 122 | { | 
| 123 | public: | 
| 124 |     QtTestModel(int rows, int columns, QObject *parent = 0); | 
| 125 |     QtTestModel(const QVector<QVector<QString> > tbl, QObject *parent = 0); | 
| 126 |     QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; | 
| 127 |     QModelIndex parent(const QModelIndex &) const; | 
| 128 |     int rowCount(const QModelIndex &parent) const; | 
| 129 |     int columnCount(const QModelIndex &parent) const; | 
| 130 |     bool hasChildren(const QModelIndex &) const; | 
| 131 |     QVariant data(const QModelIndex &idx, int) const; | 
| 132 |     bool setData(const QModelIndex &idx, const QVariant &value, int); | 
| 133 |     bool insertRows(int row, int count, const QModelIndex &parent= QModelIndex()); | 
| 134 |     bool insertColumns(int column, int count, const QModelIndex &parent= QModelIndex()); | 
| 135 |     void setPersistent(const QModelIndex &from, const QModelIndex &to); | 
| 136 |     bool removeRows ( int row, int count, const QModelIndex & parent = QModelIndex() ); | 
| 137 |     bool removeColumns( int column, int count, const QModelIndex & parent = QModelIndex()); | 
| 138 |     bool moveRows (const QModelIndex &sourceParent, int sourceRow, int count, | 
| 139 |                    const QModelIndex &destinationParent, int destinationChild); | 
| 140 |     bool moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count, | 
| 141 |                      const QModelIndex &destinationParent, int destinationChild); | 
| 142 |     void reset(); | 
| 143 |  | 
| 144 |     bool canDropMimeData(const QMimeData *data, Qt::DropAction action, | 
| 145 |                                  int row, int column, const QModelIndex &parent) const; | 
| 146 |  | 
| 147 |     int cCount, rCount; | 
| 148 |     mutable bool wrongIndex; | 
| 149 |     QVector<QVector<QString> > table; | 
| 150 | }; | 
| 151 |  | 
| 152 | Q_DECLARE_METATYPE(QAbstractItemModel::LayoutChangeHint); | 
| 153 |  | 
| 154 | QtTestModel::QtTestModel(int rows, int columns, QObject *parent) | 
| 155 |     : QAbstractItemModel(parent), cCount(columns), rCount(rows), wrongIndex(false) | 
| 156 | { | 
| 157 |     table.resize(asize: rows); | 
| 158 |     for (int r = 0; r < rows; ++r) { | 
| 159 |         const QString prefix = QString::number(r) + QLatin1Char('/'); | 
| 160 |         table[r].resize(asize: columns); | 
| 161 |         for (int c = 0; c < columns; ++c) | 
| 162 |             table[r][c] = prefix + QString::number(c); | 
| 163 |     } | 
| 164 | } | 
| 165 |  | 
| 166 | QtTestModel::QtTestModel(const QVector<QVector<QString> > tbl, QObject *parent) | 
| 167 |     : QAbstractItemModel(parent), wrongIndex(false) | 
| 168 | { | 
| 169 |     table = tbl; | 
| 170 |     rCount = tbl.count(); | 
| 171 |     cCount = tbl.at(i: 0).count(); | 
| 172 | } | 
| 173 |  | 
| 174 | QModelIndex QtTestModel::index(int row, int column, const QModelIndex &parent) const | 
| 175 | { | 
| 176 |     return hasIndex(row, column, parent) ? createIndex(arow: row, acolumn: column) : QModelIndex(); | 
| 177 | } | 
| 178 |  | 
| 179 | QModelIndex QtTestModel::parent(const QModelIndex &) const { return QModelIndex(); } | 
| 180 | int QtTestModel::rowCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : rCount; } | 
| 181 | int QtTestModel::columnCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : cCount; } | 
| 182 | bool QtTestModel::hasChildren(const QModelIndex &) const { return false; } | 
| 183 |  | 
| 184 | QVariant QtTestModel::data(const QModelIndex &idx, int) const | 
| 185 | { | 
| 186 |     if (idx.row() < 0 || idx.column() < 0 || idx.column() > cCount || idx.row() > rCount) { | 
| 187 |         wrongIndex = true; | 
| 188 |         qWarning(msg: "got invalid modelIndex %d/%d" , idx.row(), idx.column()); | 
| 189 |         return QVariant(); | 
| 190 |     } | 
| 191 |     return table.at(i: idx.row()).at(i: idx.column()); | 
| 192 | } | 
| 193 |  | 
| 194 | bool QtTestModel::setData(const QModelIndex &idx, const QVariant &value, int) | 
| 195 | { | 
| 196 |     table[idx.row()][idx.column()] = value.toString(); | 
| 197 |     return true; | 
| 198 | } | 
| 199 |  | 
| 200 | bool QtTestModel::insertRows(int row, int count, const QModelIndex &parent) | 
| 201 | { | 
| 202 |     QAbstractItemModel::beginInsertRows(parent, first: row, last: row + count - 1); | 
| 203 |     int cc = columnCount(parent); | 
| 204 |     table.insert(i: row, n: count, t: QVector<QString>(cc)); | 
| 205 |     rCount = table.count(); | 
| 206 |     QAbstractItemModel::endInsertRows(); | 
| 207 |     return true; | 
| 208 | } | 
| 209 |  | 
| 210 | bool QtTestModel::insertColumns(int column, int count, const QModelIndex &parent) | 
| 211 | { | 
| 212 |     QAbstractItemModel::beginInsertColumns(parent, first: column, last: column + count - 1); | 
| 213 |     int rc = rowCount(parent); | 
| 214 |     for (int i = 0; i < rc; ++i) | 
| 215 |         table[i].insert(i: column, n: 1, t: "" ); | 
| 216 |     cCount = table.at(i: 0).count(); | 
| 217 |     QAbstractItemModel::endInsertColumns(); | 
| 218 |     return true; | 
| 219 | } | 
| 220 |  | 
| 221 | void QtTestModel::setPersistent(const QModelIndex &from, const QModelIndex &to) | 
| 222 | { | 
| 223 |     changePersistentIndex(from, to); | 
| 224 | } | 
| 225 |  | 
| 226 | bool QtTestModel::removeRows( int row, int count, const QModelIndex & parent) | 
| 227 | { | 
| 228 |     QAbstractItemModel::beginRemoveRows(parent, first: row, last: row + count - 1); | 
| 229 |  | 
| 230 |     for (int r = row+count-1; r >= row; --r) | 
| 231 |         table.remove(i: r); | 
| 232 |     rCount = table.count(); | 
| 233 |  | 
| 234 |     QAbstractItemModel::endRemoveRows(); | 
| 235 |     return true; | 
| 236 | } | 
| 237 |  | 
| 238 | bool QtTestModel::removeColumns(int column, int count, const QModelIndex & parent) | 
| 239 | { | 
| 240 |     QAbstractItemModel::beginRemoveColumns(parent, first: column, last: column + count - 1); | 
| 241 |  | 
| 242 |     for (int c = column+count-1; c > column; --c) | 
| 243 |         for (int r = 0; r < rCount; ++r) | 
| 244 |             table[r].remove(i: c); | 
| 245 |  | 
| 246 |     cCount = table.at(i: 0).count(); | 
| 247 |  | 
| 248 |     QAbstractItemModel::endRemoveColumns(); | 
| 249 |     return true; | 
| 250 | } | 
| 251 |  | 
| 252 | bool QtTestModel::moveRows(const QModelIndex &sourceParent, int src, int cnt, | 
| 253 |                            const QModelIndex &destinationParent, int dst) | 
| 254 | { | 
| 255 |     if (!QAbstractItemModel::beginMoveRows(sourceParent, sourceFirst: src, sourceLast: src + cnt - 1, | 
| 256 |                                            destinationParent, destinationRow: dst)) | 
| 257 |         return false; | 
| 258 |  | 
| 259 |     QVector<QString> buf; | 
| 260 |     if (dst < src) { | 
| 261 |         for (int i  = 0; i < cnt; ++i) { | 
| 262 |             buf.swap(other&: table[src + i]); | 
| 263 |             table.remove(i: src + 1); | 
| 264 |             table.insert(i: dst, t: buf); | 
| 265 |         } | 
| 266 |     } else if (src < dst) { | 
| 267 |         for (int i  = 0; i < cnt; ++i) { | 
| 268 |             buf.swap(other&: table[src]); | 
| 269 |             table.remove(i: src); | 
| 270 |             table.insert(i: dst + i, t: buf); | 
| 271 |         } | 
| 272 |     } | 
| 273 |  | 
| 274 |     rCount = table.count(); | 
| 275 |  | 
| 276 |     QAbstractItemModel::endMoveRows(); | 
| 277 |     return true; | 
| 278 | } | 
| 279 |  | 
| 280 | bool QtTestModel::moveColumns(const QModelIndex &sourceParent, int src, int cnt, | 
| 281 |                               const QModelIndex &destinationParent, int dst) | 
| 282 | { | 
| 283 |     if (!QAbstractItemModel::beginMoveColumns(sourceParent, sourceFirst: src, sourceLast: src + cnt - 1, | 
| 284 |                                               destinationParent, destinationColumn: dst)) | 
| 285 |         return false; | 
| 286 |  | 
| 287 |     for (int r = 0; r < rCount; ++r) { | 
| 288 |         QString buf; | 
| 289 |         if (dst < src) { | 
| 290 |             for (int i  = 0; i < cnt; ++i) { | 
| 291 |                 buf = table[r][src + i]; | 
| 292 |                 table[r].remove(i: src + 1); | 
| 293 |                 table[r].insert(i: dst, t: buf); | 
| 294 |             } | 
| 295 |         } else if (src < dst) { | 
| 296 |             for (int i  = 0; i < cnt; ++i) { | 
| 297 |                 buf = table[r][src]; | 
| 298 |                 table[r].remove(i: src); | 
| 299 |                 table[r].insert(i: dst + i, t: buf); | 
| 300 |             } | 
| 301 |         } | 
| 302 |     } | 
| 303 |  | 
| 304 |     cCount = table.at(i: 0).count(); | 
| 305 |  | 
| 306 |     QAbstractItemModel::endMoveColumns(); | 
| 307 |     return true; | 
| 308 | } | 
| 309 |  | 
| 310 | void QtTestModel::reset() | 
| 311 | { | 
| 312 |     QAbstractItemModel::beginResetModel(); | 
| 313 |     QAbstractItemModel::endResetModel(); | 
| 314 | } | 
| 315 |  | 
| 316 | bool QtTestModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, | 
| 317 |                                  int row, int column, const QModelIndex &parent) const | 
| 318 | { | 
| 319 |     Q_UNUSED(data); | 
| 320 |     Q_UNUSED(action); | 
| 321 |  | 
| 322 |     // For testing purposes, we impose some arbitrary rules on what may be dropped. | 
| 323 |     if (!parent.isValid() && row < 0 && column < 0) { | 
| 324 |         // a drop in emtpy space in the view is allowed. | 
| 325 |         // For example, in a filesystem view, a file may be dropped into empty space | 
| 326 |         // if it represents a writable directory. | 
| 327 |         return true; | 
| 328 |     } | 
| 329 |  | 
| 330 |     // We then arbitrarily decide to only allow drops on odd rows. | 
| 331 |     // A filesystem view/model might be able to drop onto (writable) directories. | 
| 332 |     return row % 2 == 0; | 
| 333 | } | 
| 334 |  | 
| 335 | void tst_QAbstractItemModel::init() | 
| 336 | { | 
| 337 |     m_model = new DynamicTreeModel(this); | 
| 338 |  | 
| 339 |     ModelInsertCommand *insertCommand = new ModelInsertCommand(m_model, this); | 
| 340 |     insertCommand->setNumCols(4); | 
| 341 |     insertCommand->setStartRow(0); | 
| 342 |     insertCommand->setEndRow(9); | 
| 343 |     insertCommand->doCommand(); | 
| 344 |  | 
| 345 |     insertCommand = new ModelInsertCommand(m_model, this); | 
| 346 |     insertCommand->setAncestorRowNumbers(QList<int>() << 5); | 
| 347 |     insertCommand->setNumCols(4); | 
| 348 |     insertCommand->setStartRow(0); | 
| 349 |     insertCommand->setEndRow(9); | 
| 350 |     insertCommand->doCommand(); | 
| 351 |  | 
| 352 |     qRegisterMetaType<QAbstractItemModel::LayoutChangeHint>(); | 
| 353 | } | 
| 354 |  | 
| 355 | void tst_QAbstractItemModel::cleanup() | 
| 356 | { | 
| 357 |     delete m_model; | 
| 358 | } | 
| 359 |  | 
| 360 | /* | 
| 361 |   tests | 
| 362 | */ | 
| 363 |  | 
| 364 | void tst_QAbstractItemModel::index() | 
| 365 | { | 
| 366 |     QtTestModel model(1, 1); | 
| 367 |     QModelIndex idx = model.index(row: 0, column: 0, parent: QModelIndex()); | 
| 368 |     QVERIFY(idx.isValid()); | 
| 369 | } | 
| 370 |  | 
| 371 | void tst_QAbstractItemModel::parent() | 
| 372 | { | 
| 373 |     QtTestModel model(1, 1); | 
| 374 |     QModelIndex idx = model.index(row: 0, column: 0, parent: QModelIndex()); | 
| 375 |     QModelIndex par = model.parent(idx); | 
| 376 |     QVERIFY(!par.isValid()); | 
| 377 | } | 
| 378 |  | 
| 379 | void tst_QAbstractItemModel::hasChildren() | 
| 380 | { | 
| 381 |     QtTestModel model(1, 1); | 
| 382 |     QModelIndex idx = model.index(row: 0, column: 0, parent: QModelIndex()); | 
| 383 |     QVERIFY(!model.hasChildren(idx)); | 
| 384 | } | 
| 385 |  | 
| 386 | void tst_QAbstractItemModel::data() | 
| 387 | { | 
| 388 |     QtTestModel model(1, 1); | 
| 389 |     QModelIndex idx = model.index(row: 0, column: 0, parent: QModelIndex()); | 
| 390 |     QVERIFY(idx.isValid()); | 
| 391 |     QCOMPARE(model.data(idx, Qt::DisplayRole).toString(), QString("0/0" )); | 
| 392 |  | 
| 393 |     // Default does nothing | 
| 394 |     QCOMPARE(model.setHeaderData(0, Qt::Horizontal, QVariant(0), 0), false); | 
| 395 | } | 
| 396 |  | 
| 397 | void tst_QAbstractItemModel::() | 
| 398 | { | 
| 399 |     QtTestModel model(1, 1); | 
| 400 |     QCOMPARE(model.headerData(0, Qt::Horizontal, Qt::DisplayRole).toString(), | 
| 401 |             QString("1" )); | 
| 402 |  | 
| 403 |     // Default text alignment for header must be invalid | 
| 404 |     QVERIFY( !model.headerData(0, Qt::Horizontal, Qt::TextAlignmentRole).isValid() ); | 
| 405 | } | 
| 406 |  | 
| 407 | void tst_QAbstractItemModel::itemData() | 
| 408 | { | 
| 409 |     QtTestModel model(1, 1); | 
| 410 |     QModelIndex idx = model.index(row: 0, column: 0, parent: QModelIndex()); | 
| 411 |     QVERIFY(idx.isValid()); | 
| 412 |     QMap<int, QVariant> dat = model.itemData(index: idx); | 
| 413 |     QCOMPARE(dat.count(Qt::DisplayRole), 1); | 
| 414 |     QCOMPARE(dat.value(Qt::DisplayRole).toString(), QString("0/0" )); | 
| 415 | } | 
| 416 |  | 
| 417 | void tst_QAbstractItemModel::itemFlags() | 
| 418 | { | 
| 419 |     QtTestModel model(1, 1); | 
| 420 |     QModelIndex idx = model.index(row: 0, column: 0, parent: QModelIndex()); | 
| 421 |     QVERIFY(idx.isValid()); | 
| 422 |     Qt::ItemFlags flags = model.flags(index: idx); | 
| 423 |     QCOMPARE(Qt::ItemIsSelectable|Qt::ItemIsEnabled, flags); | 
| 424 | } | 
| 425 |  | 
| 426 | void tst_QAbstractItemModel::match() | 
| 427 | { | 
| 428 |     QtTestModel model(4, 1); | 
| 429 |     QModelIndex start = model.index(row: 0, column: 0, parent: QModelIndex()); | 
| 430 |     QVERIFY(start.isValid()); | 
| 431 |     QModelIndexList res = model.match(start, role: Qt::DisplayRole, value: QVariant("1" ), hits: 3); | 
| 432 |     QCOMPARE(res.count(), 1); | 
| 433 |     QModelIndex idx = model.index(row: 1, column: 0, parent: QModelIndex()); | 
| 434 |     bool areEqual = (idx == res.first()); | 
| 435 |     QVERIFY(areEqual); | 
| 436 |  | 
| 437 |     model.setData(idx: model.index(row: 0, column: 0, parent: QModelIndex()), value: "bat" , Qt::DisplayRole); | 
| 438 |     model.setData(idx: model.index(row: 1, column: 0, parent: QModelIndex()), value: "cat" , Qt::DisplayRole); | 
| 439 |     model.setData(idx: model.index(row: 2, column: 0, parent: QModelIndex()), value: "dog" , Qt::DisplayRole); | 
| 440 |     model.setData(idx: model.index(row: 3, column: 0, parent: QModelIndex()), value: "boar" , Qt::DisplayRole); | 
| 441 |  | 
| 442 |     res = model.match(start, role: Qt::DisplayRole, value: QVariant("dog" ), hits: -1, flags: Qt::MatchExactly); | 
| 443 |     QCOMPARE(res.count(), 1); | 
| 444 |     res = model.match(start, role: Qt::DisplayRole, value: QVariant("a" ), hits: -1, flags: Qt::MatchContains); | 
| 445 |     QCOMPARE(res.count(), 3); | 
| 446 |     res = model.match(start, role: Qt::DisplayRole, value: QVariant("b" ), hits: -1, flags: Qt::MatchStartsWith); | 
| 447 |     QCOMPARE(res.count(), 2); | 
| 448 |     res = model.match(start, role: Qt::DisplayRole, value: QVariant("t" ), hits: -1, flags: Qt::MatchEndsWith); | 
| 449 |     QCOMPARE(res.count(), 2); | 
| 450 |     res = model.match(start, role: Qt::DisplayRole, value: QVariant("*a*" ), hits: -1, flags: Qt::MatchWildcard); | 
| 451 |     QCOMPARE(res.count(), 3); | 
| 452 |     res = model.match(start, role: Qt::DisplayRole, value: QVariant(".*O.*" ), hits: -1, flags: Qt::MatchRegExp); | 
| 453 |     QCOMPARE(res.count(), 2); | 
| 454 |     res = model.match(start, role: Qt::DisplayRole, value: QVariant(".*O.*" ), hits: -1, flags: Qt::MatchRegExp | Qt::MatchCaseSensitive); | 
| 455 |     QCOMPARE(res.count(), 0); | 
| 456 |     res = model.match(start, role: Qt::DisplayRole, value: QVariant("BOAR" ), hits: -1, flags: Qt::MatchFixedString); | 
| 457 |     QCOMPARE(res.count(), 1); | 
| 458 |     res = model.match(start, role: Qt::DisplayRole, value: QVariant("bat" ), hits: -1, | 
| 459 |                       flags: Qt::MatchFixedString | Qt::MatchCaseSensitive); | 
| 460 |     QCOMPARE(res.count(), 1); | 
| 461 |  | 
| 462 |     res = model.match(start, role: Qt::DisplayRole, value: QVariant(".*O.*" ), hits: -1, | 
| 463 |                       flags: Qt::MatchRegularExpression); | 
| 464 |     QCOMPARE(res.count(), 2); | 
| 465 |     res = model.match(start, role: Qt::DisplayRole, value: QVariant(".*O.*" ), hits: -1, | 
| 466 |                       flags: Qt::MatchRegularExpression | Qt::MatchCaseSensitive); | 
| 467 |     QCOMPARE(res.count(), 0); | 
| 468 |  | 
| 469 |     res = model.match(start, role: Qt::DisplayRole, value: QVariant(QRegularExpression(".*O.*" )), | 
| 470 |                       hits: -1, flags: Qt::MatchRegularExpression); | 
| 471 |     QCOMPARE(res.count(), 0); | 
| 472 |     res = model.match(start, | 
| 473 |                       role: Qt::DisplayRole, | 
| 474 |                       value: QVariant(QRegularExpression(".*O.*" , | 
| 475 |                                                   QRegularExpression::CaseInsensitiveOption)), | 
| 476 |                       hits: -1, | 
| 477 |                       flags: Qt::MatchRegularExpression); | 
| 478 |     QCOMPARE(res.count(), 2); | 
| 479 |  | 
| 480 |     // Ensure that the case sensitivity is properly ignored when passing a | 
| 481 |     // QRegularExpression object. | 
| 482 |     res = model.match(start, | 
| 483 |                       role: Qt::DisplayRole, | 
| 484 |                       value: QVariant(QRegularExpression(".*O.*" , | 
| 485 |                                                   QRegularExpression::CaseInsensitiveOption)), | 
| 486 |                       hits: -1, | 
| 487 |                       flags: Qt::MatchRegularExpression | Qt::MatchCaseSensitive); | 
| 488 |     QCOMPARE(res.count(), 2); | 
| 489 | } | 
| 490 |  | 
| 491 | typedef QPair<int, int> Position; | 
| 492 | typedef QVector<QPair<int, int> > Selection; | 
| 493 | typedef QVector<QVector<QString> > StringTable; | 
| 494 | typedef QVector<QString> StringTableRow; | 
| 495 |  | 
| 496 | static StringTableRow qStringTableRow(const QString &s1, const QString &s2, const QString &s3) | 
| 497 | { | 
| 498 |     StringTableRow row; | 
| 499 |     row << s1 << s2 << s3; | 
| 500 |     return row; | 
| 501 | } | 
| 502 |  | 
| 503 | #ifdef Q_CC_MSVC | 
| 504 | # define STRINGTABLE (StringTable()) | 
| 505 | #else | 
| 506 | # define STRINGTABLE StringTable() | 
| 507 | #endif | 
| 508 |  | 
| 509 | void tst_QAbstractItemModel::dropMimeData_data() | 
| 510 | { | 
| 511 |     QTest::addColumn<StringTable>(name: "src_table" ); // drag source | 
| 512 |     QTest::addColumn<StringTable>(name: "dst_table" ); // drop target | 
| 513 |     QTest::addColumn<Selection>(name: "selection" ); // dragged items | 
| 514 |     QTest::addColumn<Position>(name: "dst_position" ); // drop position | 
| 515 |     QTest::addColumn<StringTable>(name: "res_table" ); // expected result | 
| 516 |  | 
| 517 |     { | 
| 518 |         QTest::newRow(dataTag: "2x2 dropped at [0, 0]" ) | 
| 519 |             << (STRINGTABLE // source table | 
| 520 |                 << (qStringTableRow(s1: "A" , s2: "B" , s3: "C" )) | 
| 521 |                 << (qStringTableRow(s1: "D" , s2: "E" , s3: "F" ))) | 
| 522 |             << (STRINGTABLE // destination table | 
| 523 |                 << (qStringTableRow(s1: "0" , s2: "1" , s3: "2" )) | 
| 524 |                 << (qStringTableRow(s1: "3" , s2: "4" , s3: "5" ))) | 
| 525 |             << (Selection() // selection | 
| 526 |                 << Position(0, 0) << Position(0, 1) | 
| 527 |                 << Position(1, 0) << Position(1, 1)) | 
| 528 |             << Position(0, 0) // drop position | 
| 529 |             << (STRINGTABLE // resulting table | 
| 530 |                 << (qStringTableRow(s1: "A" , s2: "B" , s3: ""  )) | 
| 531 |                 << (qStringTableRow(s1: "D" , s2: "E" , s3: ""  )) | 
| 532 |                 << (qStringTableRow(s1: "0" , s2: "1" , s3: "2" )) | 
| 533 |                 << (qStringTableRow(s1: "3" , s2: "4" , s3: "5" ))); | 
| 534 |     } | 
| 535 |  | 
| 536 |     { | 
| 537 |         QTest::newRow(dataTag: "2x2 dropped at [1, 0]" ) | 
| 538 |             << (STRINGTABLE // source table | 
| 539 |                 << (qStringTableRow(s1: "A" , s2: "B" , s3: "C" )) | 
| 540 |                 << (qStringTableRow(s1: "D" , s2: "E" , s3: "F" ))) | 
| 541 |             << (STRINGTABLE // destination table | 
| 542 |                 << (qStringTableRow(s1: "0" , s2: "1" , s3: "2" )) | 
| 543 |                 << (qStringTableRow(s1: "3" , s2: "4" , s3: "5" ))) | 
| 544 |             << (Selection() // selection | 
| 545 |                 << Position(0, 0) << Position(0, 1) | 
| 546 |                 << Position(1, 0) << Position(1, 1)) | 
| 547 |             << Position(1, 0) // drop position | 
| 548 |             << (STRINGTABLE // resulting table | 
| 549 |                 << (qStringTableRow(s1: "0" , s2: "1" , s3: "2" )) | 
| 550 |                 << (qStringTableRow(s1: "A" , s2: "B" , s3: ""  )) | 
| 551 |                 << (qStringTableRow(s1: "D" , s2: "E" , s3: ""  )) | 
| 552 |                 << (qStringTableRow(s1: "3" , s2: "4" , s3: "5" ))); | 
| 553 |     } | 
| 554 |  | 
| 555 |     { | 
| 556 |         QTest::newRow(dataTag: "2x2 dropped at [3, 0]" ) | 
| 557 |             << (STRINGTABLE // source table | 
| 558 |                 << (qStringTableRow(s1: "A" , s2: "B" , s3: "C" )) | 
| 559 |                 << (qStringTableRow(s1: "D" , s2: "E" , s3: "F" ))) | 
| 560 |             << (STRINGTABLE // destination table | 
| 561 |                 << (qStringTableRow(s1: "0" , s2: "1" , s3: "2" )) | 
| 562 |                 << (qStringTableRow(s1: "3" , s2: "4" , s3: "5" ))) | 
| 563 |             << (Selection() // selection | 
| 564 |                 << Position(0, 0) << Position(0, 1) | 
| 565 |                 << Position(1, 0) << Position(1, 1)) | 
| 566 |             << Position(3, 0) // drop position | 
| 567 |             << (STRINGTABLE // resulting table | 
| 568 |                 << (qStringTableRow(s1: "0" , s2: "1" , s3: "2" )) | 
| 569 |                 << (qStringTableRow(s1: "3" , s2: "4" , s3: "5" )) | 
| 570 |                 << (qStringTableRow(s1: "A" , s2: "B" , s3: ""  )) | 
| 571 |                 << (qStringTableRow(s1: "D" , s2: "E" , s3: ""  ))); | 
| 572 |     } | 
| 573 |  | 
| 574 |     { | 
| 575 |         QTest::newRow(dataTag: "2x2 dropped at [0, 1]" ) | 
| 576 |             << (STRINGTABLE // source table | 
| 577 |                 << (qStringTableRow(s1: "A" , s2: "B" , s3: "C" )) | 
| 578 |                 << (qStringTableRow(s1: "D" , s2: "E" , s3: "F" ))) | 
| 579 |             << (STRINGTABLE // destination table | 
| 580 |                 << (qStringTableRow(s1: "0" , s2: "1" , s3: "2" )) | 
| 581 |                 << (qStringTableRow(s1: "3" , s2: "4" , s3: "5" ))) | 
| 582 |             << (Selection() // selection | 
| 583 |                 << Position(0, 0) << Position(0, 1) | 
| 584 |                 << Position(1, 0) << Position(1, 1)) | 
| 585 |             << Position(0, 1) // drop position | 
| 586 |             << (STRINGTABLE // resulting table | 
| 587 |                 << (qStringTableRow(s1: ""  , s2: "A" , s3: "B" )) | 
| 588 |                 << (qStringTableRow(s1: ""  , s2: "D" , s3: "E" )) | 
| 589 |                 << (qStringTableRow(s1: "0" , s2: "1" , s3: "2" )) | 
| 590 |                 << (qStringTableRow(s1: "3" , s2: "4" , s3: "5" ))); | 
| 591 |     } | 
| 592 |  | 
| 593 |     { | 
| 594 |         QTest::newRow(dataTag: "2x2 dropped at [0, 2] (line break)" ) | 
| 595 |             << (STRINGTABLE // source table | 
| 596 |                 << (qStringTableRow(s1: "A" , s2: "B" , s3: "C" )) | 
| 597 |                 << (qStringTableRow(s1: "D" , s2: "E" , s3: "F" ))) | 
| 598 |             << (STRINGTABLE // destination table | 
| 599 |                 << (qStringTableRow(s1: "0" , s2: "1" , s3: "2" )) | 
| 600 |                 << (qStringTableRow(s1: "3" , s2: "4" , s3: "5" ))) | 
| 601 |             << (Selection() // selection | 
| 602 |                 << Position(0, 0) << Position(0, 1) | 
| 603 |                 << Position(1, 0) << Position(1, 1)) | 
| 604 |             << Position(0, 2) // drop position | 
| 605 |             << (STRINGTABLE // resulting table | 
| 606 |                 << (qStringTableRow(s1: ""  , s2: ""  , s3: "A" )) | 
| 607 |                 << (qStringTableRow(s1: ""  , s2: ""  , s3: "D" )) | 
| 608 |                 << (qStringTableRow(s1: ""  , s2: ""  , s3: "B" )) | 
| 609 |                 << (qStringTableRow(s1: ""  , s2: ""  , s3: "E" )) | 
| 610 |                 << (qStringTableRow(s1: "0" , s2: "1" , s3: "2" )) | 
| 611 |                 << (qStringTableRow(s1: "3" , s2: "4" , s3: "5" ))); | 
| 612 |     } | 
| 613 |  | 
| 614 |     { | 
| 615 |         QTest::newRow(dataTag: "2x2 dropped at [3, 2] (line break)" ) | 
| 616 |             << (STRINGTABLE // source table | 
| 617 |                 << (qStringTableRow(s1: "A" , s2: "B" , s3: "C" )) | 
| 618 |                 << (qStringTableRow(s1: "D" , s2: "E" , s3: "F" ))) | 
| 619 |             << (STRINGTABLE // destination table | 
| 620 |                 << (qStringTableRow(s1: "0" , s2: "1" , s3: "2" )) | 
| 621 |                 << (qStringTableRow(s1: "3" , s2: "4" , s3: "5" ))) | 
| 622 |             << (Selection() // selection | 
| 623 |                 << Position(0, 0) << Position(0, 1) | 
| 624 |                 << Position(1, 0) << Position(1, 1)) | 
| 625 |             << Position(3, 2) // drop position | 
| 626 |             << (STRINGTABLE // resulting table | 
| 627 |                 << (qStringTableRow(s1: "0" , s2: "1" , s3: "2" )) | 
| 628 |                 << (qStringTableRow(s1: "3" , s2: "4" , s3: "5" )) | 
| 629 |                 << (qStringTableRow(s1: ""  , s2: ""  , s3: "A" )) | 
| 630 |                 << (qStringTableRow(s1: ""  , s2: ""  , s3: "D" )) | 
| 631 |                 << (qStringTableRow(s1: ""  , s2: ""  , s3: "B" )) | 
| 632 |                 << (qStringTableRow(s1: ""  , s2: ""  , s3: "E" ))); | 
| 633 |     } | 
| 634 |  | 
| 635 |     { | 
| 636 |         QTest::newRow(dataTag: "non-square dropped at [0, 0]" ) | 
| 637 |             << (STRINGTABLE // source table | 
| 638 |                 << (qStringTableRow(s1: "A" , s2: "B" , s3: "C" )) | 
| 639 |                 << (qStringTableRow(s1: "D" , s2: "E" , s3: "F" ))) | 
| 640 |             << (STRINGTABLE // destination table | 
| 641 |                 << (qStringTableRow(s1: "0" , s2: "1" , s3: "2" )) | 
| 642 |                 << (qStringTableRow(s1: "3" , s2: "4" , s3: "5" ))) | 
| 643 |             << (Selection() // selection | 
| 644 |                 << Position(0, 0) << Position(0, 1) | 
| 645 |                 << Position(1, 0)) | 
| 646 |             << Position(0, 0) // drop position | 
| 647 |             << (STRINGTABLE // resulting table | 
| 648 |                 << (qStringTableRow(s1: "A" , s2: "B" , s3: ""  )) | 
| 649 |                 << (qStringTableRow(s1: "D" , s2: ""  , s3: ""  )) | 
| 650 |                 << (qStringTableRow(s1: "0" , s2: "1" , s3: "2" )) | 
| 651 |                 << (qStringTableRow(s1: "3" , s2: "4" , s3: "5" ))); | 
| 652 |     } | 
| 653 |  | 
| 654 |     { | 
| 655 |         QTest::newRow(dataTag: "non-square dropped at [0, 2]" ) | 
| 656 |             << (STRINGTABLE // source table | 
| 657 |                 << (qStringTableRow(s1: "A" , s2: "B" , s3: "C" )) | 
| 658 |                 << (qStringTableRow(s1: "D" , s2: "E" , s3: "F" ))) | 
| 659 |             << (STRINGTABLE // destination table | 
| 660 |                 << (qStringTableRow(s1: "0" , s2: "1" , s3: "2" )) | 
| 661 |                 << (qStringTableRow(s1: "3" , s2: "4" , s3: "5" ))) | 
| 662 |             << (Selection() // selection | 
| 663 |                 << Position(0, 0) << Position(0, 1) | 
| 664 |                 << Position(1, 0)) | 
| 665 |             << Position(0, 2) // drop position | 
| 666 |             << (STRINGTABLE // resulting table | 
| 667 |                 << (qStringTableRow(s1: ""  , s2: ""  , s3: "A" )) | 
| 668 |                 << (qStringTableRow(s1: ""  , s2: ""  , s3: "D" )) | 
| 669 |                 << (qStringTableRow(s1: ""  , s2: ""  , s3: "B" )) | 
| 670 |                 << (qStringTableRow(s1: "0" , s2: "1" , s3: "2" )) | 
| 671 |                 << (qStringTableRow(s1: "3" , s2: "4" , s3: "5" ))); | 
| 672 |     } | 
| 673 |  | 
| 674 |     { | 
| 675 |         QTest::newRow(dataTag: "2x 1x2 dropped at [0, 0] (duplicates)" ) | 
| 676 |             << (STRINGTABLE // source table | 
| 677 |                 << (qStringTableRow(s1: "A" , s2: "B" , s3: "C" )) | 
| 678 |                 << (qStringTableRow(s1: "D" , s2: "E" , s3: "F" ))) | 
| 679 |             << (STRINGTABLE // destination table | 
| 680 |                 << (qStringTableRow(s1: "0" , s2: "1" , s3: "2" )) | 
| 681 |                 << (qStringTableRow(s1: "3" , s2: "4" , s3: "5" ))) | 
| 682 |             << (Selection() // selection; 2x the same row (to simulate selections in hierarchy) | 
| 683 |                 << Position(0, 0) << Position(0, 1) | 
| 684 |                 << Position(0, 0) << Position(0, 1)) | 
| 685 |             << Position(0, 0) // drop position | 
| 686 |             << (STRINGTABLE // resulting table | 
| 687 |                 << (qStringTableRow(s1: "A" , s2: "B" , s3: ""  )) | 
| 688 |                 << (qStringTableRow(s1: "A" , s2: ""  , s3: ""  )) | 
| 689 |                 << (qStringTableRow(s1: ""  , s2: "B" , s3: ""  )) // ### FIXME: strange behavior, but rare case | 
| 690 |                 << (qStringTableRow(s1: "0" , s2: "1" , s3: "2" )) | 
| 691 |                 << (qStringTableRow(s1: "3" , s2: "4" , s3: "5" ))); | 
| 692 |     } | 
| 693 |  | 
| 694 |     { | 
| 695 |         QTest::newRow(dataTag: "2x 1x2 dropped at [3, 2] (duplicates)" ) | 
| 696 |             << (STRINGTABLE // source table | 
| 697 |                 << (qStringTableRow(s1: "A" , s2: "B" , s3: "C" )) | 
| 698 |                 << (qStringTableRow(s1: "D" , s2: "E" , s3: "F" ))) | 
| 699 |             << (STRINGTABLE // destination table | 
| 700 |                 << (qStringTableRow(s1: "0" , s2: "1" , s3: "2" )) | 
| 701 |                 << (qStringTableRow(s1: "3" , s2: "4" , s3: "5" ))) | 
| 702 |             << (Selection() // selection; 2x the same row (to simulate selections in hierarchy) | 
| 703 |                 << Position(0, 0) << Position(0, 1) | 
| 704 |                 << Position(0, 0) << Position(0, 1)) | 
| 705 |             << Position(3, 2) // drop position | 
| 706 |             << (STRINGTABLE // resulting table | 
| 707 |                 << (qStringTableRow(s1: "0" , s2: "1" , s3: "2" )) | 
| 708 |                 << (qStringTableRow(s1: "3" , s2: "4" , s3: "5" )) | 
| 709 |                 << (qStringTableRow(s1: ""  , s2: ""  , s3: "A" )) | 
| 710 |                 << (qStringTableRow(s1: ""  , s2: ""  , s3: "B" )) | 
| 711 |                 << (qStringTableRow(s1: ""  , s2: ""  , s3: "A" )) | 
| 712 |                 << (qStringTableRow(s1: ""  , s2: ""  , s3: "B" ))); | 
| 713 |     } | 
| 714 |     { | 
| 715 |         QTest::newRow(dataTag: "2x 1x2 dropped at [3, 2] (different rows)" ) | 
| 716 |             << (STRINGTABLE // source table | 
| 717 |                 << (qStringTableRow(s1: "A" , s2: "B" , s3: "C" )) | 
| 718 |                 << (qStringTableRow(s1: "D" , s2: "E" , s3: "F" )) | 
| 719 |                 << (qStringTableRow(s1: "G" , s2: "H" , s3: "I" ))) | 
| 720 |             << (STRINGTABLE // destination table | 
| 721 |                 << (qStringTableRow(s1: "0" , s2: "1" , s3: "2" )) | 
| 722 |                 << (qStringTableRow(s1: "3" , s2: "4" , s3: "5" ))) | 
| 723 |             << (Selection() // selection; 2x the same row (to simulate selections in hierarchy) | 
| 724 |                 << Position(0, 0) << Position(0, 1) | 
| 725 |                 << Position(2, 0) << Position(2, 1)) | 
| 726 |             << Position(2, 1) // drop position | 
| 727 |             << (STRINGTABLE // resulting table | 
| 728 |                 << (qStringTableRow(s1: "0" , s2: "1" , s3: "2" )) | 
| 729 |                 << (qStringTableRow(s1: "3" , s2: "4" , s3: "5" )) | 
| 730 |                 << (qStringTableRow(s1: ""  , s2: "A"  , s3: "B" )) | 
| 731 |                 << (qStringTableRow(s1: ""  , s2: "G"  , s3: "H" ))); | 
| 732 |     } | 
| 733 |  | 
| 734 |     { | 
| 735 |         QTest::newRow(dataTag: "2x 1x2 dropped at [3, 2] (different rows, over the edge)" ) | 
| 736 |             << (STRINGTABLE // source table | 
| 737 |                 << (qStringTableRow(s1: "A" , s2: "B" , s3: "C" )) | 
| 738 |                 << (qStringTableRow(s1: "D" , s2: "E" , s3: "F" )) | 
| 739 |                 << (qStringTableRow(s1: "G" , s2: "H" , s3: "I" ))) | 
| 740 |             << (STRINGTABLE // destination table | 
| 741 |                 << (qStringTableRow(s1: "0" , s2: "1" , s3: "2" )) | 
| 742 |                 << (qStringTableRow(s1: "3" , s2: "4" , s3: "5" ))) | 
| 743 |             << (Selection() // selection; 2x the same row (to simulate selections in hierarchy) | 
| 744 |                 << Position(0, 0) << Position(0, 1) | 
| 745 |                 << Position(2, 0) << Position(2, 1)) | 
| 746 |             << Position(3, 2) // drop position | 
| 747 |             << (STRINGTABLE // resulting table | 
| 748 |                 << (qStringTableRow(s1: "0" , s2: "1" , s3: "2" )) | 
| 749 |                 << (qStringTableRow(s1: "3" , s2: "4" , s3: "5" )) | 
| 750 |                 << (qStringTableRow(s1: ""  , s2: ""  , s3: "A" )) | 
| 751 |                 << (qStringTableRow(s1: ""  , s2: ""  , s3: "G" )) | 
| 752 |                 << (qStringTableRow(s1: ""  , s2: ""  , s3: "B" )) | 
| 753 |                 << (qStringTableRow(s1: ""  , s2: ""  , s3: "H" ))); | 
| 754 |     } | 
| 755 | } | 
| 756 |  | 
| 757 | void tst_QAbstractItemModel::dropMimeData() | 
| 758 | { | 
| 759 |     QFETCH(StringTable, src_table); | 
| 760 |     QFETCH(StringTable, dst_table); | 
| 761 |     QFETCH(Selection, selection); | 
| 762 |     QFETCH(Position, dst_position); | 
| 763 |     QFETCH(StringTable, res_table); | 
| 764 |  | 
| 765 |     QtTestModel src(src_table); | 
| 766 |     QtTestModel dst(dst_table); | 
| 767 |     QtTestModel res(res_table); | 
| 768 |  | 
| 769 |     // get the mimeData from the "selected" indexes | 
| 770 |     QModelIndexList selectedIndexes; | 
| 771 |     for (int i = 0; i < selection.count(); ++i) | 
| 772 |         selectedIndexes << src.index(row: selection.at(i).first, column: selection.at(i).second, parent: QModelIndex()); | 
| 773 |     QMimeData *md = src.mimeData(indexes: selectedIndexes); | 
| 774 |     // do the drop | 
| 775 |     dst.dropMimeData(data: md, action: Qt::CopyAction, row: dst_position.first, column: dst_position.second, parent: QModelIndex()); | 
| 776 |     delete md; | 
| 777 |  | 
| 778 |     // compare to the expected results | 
| 779 |     QCOMPARE(dst.rowCount(QModelIndex()), res.rowCount(QModelIndex())); | 
| 780 |     QCOMPARE(dst.columnCount(QModelIndex()), res.columnCount(QModelIndex())); | 
| 781 |     for (int r = 0; r < dst.rowCount(parent: QModelIndex()); ++r) { | 
| 782 |         for (int c = 0; c < dst.columnCount(parent: QModelIndex()); ++c) { | 
| 783 |             QModelIndex dst_idx = dst.index(row: r, column: c, parent: QModelIndex()); | 
| 784 |             QModelIndex res_idx = res.index(row: r, column: c, parent: QModelIndex()); | 
| 785 |             QMap<int, QVariant> dst_data = dst.itemData(index: dst_idx); | 
| 786 |             QMap<int, QVariant> res_data = res.itemData(index: res_idx); | 
| 787 |             QCOMPARE(dst_data , res_data); | 
| 788 |         } | 
| 789 |     } | 
| 790 | } | 
| 791 |  | 
| 792 | void tst_QAbstractItemModel::canDropMimeData() | 
| 793 | { | 
| 794 |     QtTestModel model(3, 3); | 
| 795 |  | 
| 796 |     QVERIFY(model.canDropMimeData(0, Qt::CopyAction, -1, -1, QModelIndex())); | 
| 797 |     QVERIFY(model.canDropMimeData(0, Qt::CopyAction, 0, 0, QModelIndex())); | 
| 798 |     QVERIFY(!model.canDropMimeData(0, Qt::CopyAction, 1, 0, QModelIndex())); | 
| 799 | } | 
| 800 |  | 
| 801 | void tst_QAbstractItemModel::changePersistentIndex() | 
| 802 | { | 
| 803 |     QtTestModel model(3, 3); | 
| 804 |     QModelIndex a = model.index(row: 1, column: 2, parent: QModelIndex()); | 
| 805 |     QModelIndex b = model.index(row: 2, column: 1, parent: QModelIndex()); | 
| 806 |     QPersistentModelIndex p(a); | 
| 807 |     QVERIFY(p == a); | 
| 808 |     model.setPersistent(from: a, to: b); | 
| 809 |     QVERIFY(p == b); | 
| 810 | } | 
| 811 |  | 
| 812 | void tst_QAbstractItemModel::movePersistentIndex() | 
| 813 | { | 
| 814 |     QtTestModel model(3, 3); | 
| 815 |  | 
| 816 |     QPersistentModelIndex a = model.index(row: 1, column: 1); | 
| 817 |     QVERIFY(a.isValid()); | 
| 818 |     QCOMPARE(a.row(), 1); | 
| 819 |     QCOMPARE(a.column(), 1); | 
| 820 |  | 
| 821 |     model.insertRow(arow: 0); | 
| 822 |     QCOMPARE(a.row(), 2); | 
| 823 |  | 
| 824 |     model.insertRow(arow: 1); | 
| 825 |     QCOMPARE(a.row(), 3); | 
| 826 |  | 
| 827 |     model.insertColumn(acolumn: 0); | 
| 828 |     QCOMPARE(a.column(), 2); | 
| 829 | } | 
| 830 |  | 
| 831 | void tst_QAbstractItemModel::removeRows() | 
| 832 | { | 
| 833 |     QtTestModel model(10, 10); | 
| 834 |  | 
| 835 |     QSignalSpy rowsAboutToBeRemovedSpy(&model, &QtTestModel::rowsAboutToBeRemoved); | 
| 836 |     QSignalSpy rowsRemovedSpy(&model, &QtTestModel::rowsRemoved); | 
| 837 |  | 
| 838 |     QVERIFY(rowsAboutToBeRemovedSpy.isValid()); | 
| 839 |     QVERIFY(rowsRemovedSpy.isValid()); | 
| 840 |  | 
| 841 |     QCOMPARE(model.removeRows(6, 4), true); | 
| 842 |     QCOMPARE(rowsAboutToBeRemovedSpy.count(), 1); | 
| 843 |     QCOMPARE(rowsRemovedSpy.count(), 1); | 
| 844 | } | 
| 845 |  | 
| 846 | void tst_QAbstractItemModel::removeColumns() | 
| 847 | { | 
| 848 |     QtTestModel model(10, 10); | 
| 849 |  | 
| 850 |     QSignalSpy columnsAboutToBeRemovedSpy(&model, &QtTestModel::columnsAboutToBeRemoved); | 
| 851 |     QSignalSpy columnsRemovedSpy(&model, &QtTestModel::columnsRemoved); | 
| 852 |  | 
| 853 |     QVERIFY(columnsAboutToBeRemovedSpy.isValid()); | 
| 854 |     QVERIFY(columnsRemovedSpy.isValid()); | 
| 855 |  | 
| 856 |     QCOMPARE(model.removeColumns(6, 4), true); | 
| 857 |     QCOMPARE(columnsAboutToBeRemovedSpy.count(), 1); | 
| 858 |     QCOMPARE(columnsRemovedSpy.count(), 1); | 
| 859 | } | 
| 860 |  | 
| 861 | void tst_QAbstractItemModel::insertRows() | 
| 862 | { | 
| 863 |     QtTestModel model(10, 10); | 
| 864 |  | 
| 865 |     QSignalSpy rowsAboutToBeInsertedSpy(&model, &QtTestModel::rowsAboutToBeInserted); | 
| 866 |     QSignalSpy rowsInsertedSpy(&model, &QtTestModel::rowsInserted); | 
| 867 |  | 
| 868 |     QVERIFY(rowsAboutToBeInsertedSpy.isValid()); | 
| 869 |     QVERIFY(rowsInsertedSpy.isValid()); | 
| 870 |  | 
| 871 |     QCOMPARE(model.insertRows(6, 4), true); | 
| 872 |     QCOMPARE(rowsAboutToBeInsertedSpy.count(), 1); | 
| 873 |     QCOMPARE(rowsInsertedSpy.count(), 1); | 
| 874 | } | 
| 875 |  | 
| 876 | void tst_QAbstractItemModel::insertColumns() | 
| 877 | { | 
| 878 |     QtTestModel model(10, 10); | 
| 879 |  | 
| 880 |     QSignalSpy columnsAboutToBeInsertedSpy(&model, &QtTestModel::columnsAboutToBeInserted); | 
| 881 |     QSignalSpy columnsInsertedSpy(&model, &QtTestModel::columnsInserted); | 
| 882 |  | 
| 883 |     QVERIFY(columnsAboutToBeInsertedSpy.isValid()); | 
| 884 |     QVERIFY(columnsInsertedSpy.isValid()); | 
| 885 |  | 
| 886 |     QCOMPARE(model.insertColumns(6, 4), true); | 
| 887 |     QCOMPARE(columnsAboutToBeInsertedSpy.count(), 1); | 
| 888 |     QCOMPARE(columnsInsertedSpy.count(), 1); | 
| 889 | } | 
| 890 |  | 
| 891 | void tst_QAbstractItemModel::moveRows() | 
| 892 | { | 
| 893 |     QtTestModel model(10, 10); | 
| 894 |  | 
| 895 |     QSignalSpy rowsAboutToBeMovedSpy(&model, &QtTestModel::rowsAboutToBeMoved); | 
| 896 |     QSignalSpy rowsMovedSpy(&model, &QtTestModel::rowsMoved); | 
| 897 |  | 
| 898 |     QVERIFY(rowsAboutToBeMovedSpy.isValid()); | 
| 899 |     QVERIFY(rowsMovedSpy.isValid()); | 
| 900 |  | 
| 901 |     QCOMPARE(model.moveRows(QModelIndex(), 6, 4, QModelIndex(), 1), true); | 
| 902 |     QCOMPARE(rowsAboutToBeMovedSpy.count(), 1); | 
| 903 |     QCOMPARE(rowsMovedSpy.count(), 1); | 
| 904 | } | 
| 905 |  | 
| 906 | void tst_QAbstractItemModel::moveColumns() | 
| 907 | { | 
| 908 |     QtTestModel model(10, 10); | 
| 909 |  | 
| 910 |     QSignalSpy columnsAboutToBeMovedSpy(&model, &QtTestModel::columnsAboutToBeMoved); | 
| 911 |     QSignalSpy columnsMovedSpy(&model, &QtTestModel::columnsMoved); | 
| 912 |  | 
| 913 |     QVERIFY(columnsAboutToBeMovedSpy.isValid()); | 
| 914 |     QVERIFY(columnsMovedSpy.isValid()); | 
| 915 |  | 
| 916 |     QCOMPARE(model.moveColumns(QModelIndex(), 6, 4, QModelIndex(), 1), true); | 
| 917 |     QCOMPARE(columnsAboutToBeMovedSpy.count(), 1); | 
| 918 |     QCOMPARE(columnsMovedSpy.count(), 1); | 
| 919 |  | 
| 920 |     QCOMPARE(model.moveColumn(QModelIndex(), 4, QModelIndex(), 1), true); | 
| 921 |     QCOMPARE(columnsAboutToBeMovedSpy.count(), 2); | 
| 922 |     QCOMPARE(columnsMovedSpy.count(), 2); | 
| 923 | } | 
| 924 |  | 
| 925 | void tst_QAbstractItemModel::reset() | 
| 926 | { | 
| 927 |     QtTestModel model(10, 10); | 
| 928 |  | 
| 929 |     QSignalSpy resetSpy(&model, &QtTestModel::modelReset); | 
| 930 |     QVERIFY(resetSpy.isValid()); | 
| 931 |     model.reset(); | 
| 932 |     QCOMPARE(resetSpy.count(), 1); | 
| 933 | } | 
| 934 |  | 
| 935 | void tst_QAbstractItemModel::complexChangesWithPersistent() | 
| 936 | { | 
| 937 |     QtTestModel model(10, 10); | 
| 938 |     QPersistentModelIndex a = model.index(row: 1, column: 1, parent: QModelIndex()); | 
| 939 |     QPersistentModelIndex b = model.index(row: 9, column: 7, parent: QModelIndex()); | 
| 940 |     QPersistentModelIndex c = model.index(row: 5, column: 6, parent: QModelIndex()); | 
| 941 |     QPersistentModelIndex d = model.index(row: 3, column: 9, parent: QModelIndex()); | 
| 942 |     QPersistentModelIndex e[10]; | 
| 943 |     for (int i=0; i <10 ; i++) { | 
| 944 |         e[i] = model.index(row: 2, column: i , parent: QModelIndex()); | 
| 945 |     } | 
| 946 |  | 
| 947 |     QVERIFY(a == model.index(1, 1, QModelIndex())); | 
| 948 |     QVERIFY(b == model.index(9, 7, QModelIndex())); | 
| 949 |     QVERIFY(c == model.index(5, 6, QModelIndex())); | 
| 950 |     QVERIFY(d == model.index(3, 9, QModelIndex())); | 
| 951 |     for (int i=0; i <8 ; i++) | 
| 952 |         QVERIFY(e[i] == model.index(2, i , QModelIndex())); | 
| 953 |  | 
| 954 |     //remove a bunch of columns | 
| 955 |     model.removeColumns(column: 2, count: 4); | 
| 956 |  | 
| 957 |     QVERIFY(a == model.index(1, 1, QModelIndex())); | 
| 958 |     QVERIFY(b == model.index(9, 3, QModelIndex())); | 
| 959 |     QVERIFY(c == model.index(5, 2, QModelIndex())); | 
| 960 |     QVERIFY(d == model.index(3, 5, QModelIndex())); | 
| 961 |     for (int i=0; i <2 ; i++) | 
| 962 |         QVERIFY(e[i] == model.index(2, i , QModelIndex())); | 
| 963 |     for (int i=2; i <6 ; i++) | 
| 964 |         QVERIFY(!e[i].isValid()); | 
| 965 |     for (int i=6; i <10 ; i++) | 
| 966 |         QVERIFY(e[i] == model.index(2, i-4 , QModelIndex())); | 
| 967 |  | 
| 968 |     //move some indexes around | 
| 969 |     model.setPersistent(from: model.index(row: 1, column: 1 , parent: QModelIndex()), to: model.index(row: 9, column: 3 , parent: QModelIndex())); | 
| 970 |     model.setPersistent(from: model.index(row: 9, column: 3 , parent: QModelIndex()), to: model.index(row: 8, column: 4 , parent: QModelIndex())); | 
| 971 |  | 
| 972 |     QVERIFY(a == model.index(9, 3, QModelIndex())); | 
| 973 |     QVERIFY(b == model.index(8, 4, QModelIndex())); | 
| 974 |     QVERIFY(c == model.index(5, 2, QModelIndex())); | 
| 975 |     QVERIFY(d == model.index(3, 5, QModelIndex())); | 
| 976 |     for (int i=0; i <2 ; i++) | 
| 977 |         QVERIFY(e[i] == model.index(2, i , QModelIndex())); | 
| 978 |     for (int i=2; i <6 ; i++) | 
| 979 |         QVERIFY(!e[i].isValid()); | 
| 980 |     for (int i=6; i <10 ; i++) | 
| 981 |         QVERIFY(e[i] == model.index(2, i-4 , QModelIndex())); | 
| 982 |  | 
| 983 |     //inserting a bunch of columns | 
| 984 |     model.insertColumns(column: 2, count: 2); | 
| 985 |     QVERIFY(a == model.index(9, 5, QModelIndex())); | 
| 986 |     QVERIFY(b == model.index(8, 6, QModelIndex())); | 
| 987 |     QVERIFY(c == model.index(5, 4, QModelIndex())); | 
| 988 |     QVERIFY(d == model.index(3, 7, QModelIndex())); | 
| 989 |     for (int i=0; i <2 ; i++) | 
| 990 |         QVERIFY(e[i] == model.index(2, i , QModelIndex())); | 
| 991 |     for (int i=2; i <6 ; i++) | 
| 992 |         QVERIFY(!e[i].isValid()); | 
| 993 |     for (int i=6; i <10 ; i++) | 
| 994 |         QVERIFY(e[i] == model.index(2, i-2 , QModelIndex())); | 
| 995 | } | 
| 996 |  | 
| 997 | void tst_QAbstractItemModel::testMoveSameParentDown_data() | 
| 998 | { | 
| 999 |     QTest::addColumn<int>(name: "startRow" ); | 
| 1000 |     QTest::addColumn<int>(name: "endRow" ); | 
| 1001 |     QTest::addColumn<int>(name: "destRow" ); | 
| 1002 |     // We can't put the actual parent index for the move in here because m_model is not defined until init() is run. | 
| 1003 |     QTest::addColumn<bool>(name: "topLevel" ); | 
| 1004 |  | 
| 1005 |     // Move from the start to the middle | 
| 1006 |     QTest::newRow(dataTag: "move01" ) << 0 << 2 << 8 << true; | 
| 1007 |     // Move from the start to the end | 
| 1008 |     QTest::newRow(dataTag: "move02" ) << 0 << 2 << 10 << true; | 
| 1009 |     // Move from the middle to the middle | 
| 1010 |     QTest::newRow(dataTag: "move03" ) << 3 << 5 << 8 << true; | 
| 1011 |     // Move from the middle to the end | 
| 1012 |     QTest::newRow(dataTag: "move04" ) << 3 << 5 << 10 << true; | 
| 1013 |  | 
| 1014 |     QTest::newRow(dataTag: "move05" ) << 0 << 2 << 8 << false; | 
| 1015 |     QTest::newRow(dataTag: "move06" ) << 0 << 2 << 10 << false; | 
| 1016 |     QTest::newRow(dataTag: "move07" ) << 3 << 5 << 8 << false; | 
| 1017 |     QTest::newRow(dataTag: "move08" ) << 3 << 5 << 10 << false; | 
| 1018 | } | 
| 1019 |  | 
| 1020 | void tst_QAbstractItemModel::testMoveSameParentDown() | 
| 1021 | { | 
| 1022 |     QFETCH(int, startRow); | 
| 1023 |     QFETCH(int, endRow); | 
| 1024 |     QFETCH(int, destRow); | 
| 1025 |     QFETCH(bool, topLevel); | 
| 1026 |  | 
| 1027 |     QModelIndex moveParent = topLevel ? QModelIndex() : m_model->index(row: 5, column: 0); | 
| 1028 |  | 
| 1029 |     QList<QPersistentModelIndex> persistentList; | 
| 1030 |     QModelIndexList indexList; | 
| 1031 |  | 
| 1032 |     for (int column = 0; column < m_model->columnCount(); ++column) { | 
| 1033 |         for (int row = 0; row < m_model->rowCount(); ++row) { | 
| 1034 |             QModelIndex idx = m_model->index(row, column); | 
| 1035 |             QVERIFY(idx.isValid()); | 
| 1036 |             indexList << idx; | 
| 1037 |             persistentList << QPersistentModelIndex(idx); | 
| 1038 |         } | 
| 1039 |     } | 
| 1040 |  | 
| 1041 |     QModelIndex parent = m_model->index(row: 5, column: 0); | 
| 1042 |     for (int column = 0; column < m_model->columnCount(); ++column) { | 
| 1043 |         for (int row = 0; row < m_model->rowCount(index: parent); ++row) { | 
| 1044 |             QModelIndex idx = m_model->index(row, column, parent); | 
| 1045 |             QVERIFY(idx.isValid()); | 
| 1046 |             indexList << idx; | 
| 1047 |             persistentList << QPersistentModelIndex(idx); | 
| 1048 |         } | 
| 1049 |     } | 
| 1050 |  | 
| 1051 |     QSignalSpy beforeSpy(m_model, &DynamicTreeModel::rowsAboutToBeMoved); | 
| 1052 |     QSignalSpy afterSpy(m_model, &DynamicTreeModel::rowsMoved); | 
| 1053 |  | 
| 1054 |     QVERIFY(beforeSpy.isValid()); | 
| 1055 |     QVERIFY(afterSpy.isValid()); | 
| 1056 |  | 
| 1057 |     ModelMoveCommand *moveCommand = new ModelMoveCommand(m_model, this); | 
| 1058 |     moveCommand->setNumCols(4); | 
| 1059 |     if (!topLevel) | 
| 1060 |         moveCommand->setAncestorRowNumbers(QList<int>() << 5); | 
| 1061 |     moveCommand->setStartRow(startRow); | 
| 1062 |     moveCommand->setEndRow(endRow); | 
| 1063 |     moveCommand->setDestRow(destRow); | 
| 1064 |     if (!topLevel) | 
| 1065 |         moveCommand->setDestAncestors(QList<int>() << 5); | 
| 1066 |     moveCommand->doCommand(); | 
| 1067 |  | 
| 1068 |     QVariantList beforeSignal = beforeSpy.takeAt(i: 0); | 
| 1069 |     QVariantList afterSignal = afterSpy.takeAt(i: 0); | 
| 1070 |  | 
| 1071 |     QCOMPARE(beforeSignal.size(), 5); | 
| 1072 |     QCOMPARE(beforeSignal.at(0).value<QModelIndex>(), moveParent); | 
| 1073 |     QCOMPARE(beforeSignal.at(1).toInt(), startRow); | 
| 1074 |     QCOMPARE(beforeSignal.at(2).toInt(), endRow); | 
| 1075 |     QCOMPARE(beforeSignal.at(3).value<QModelIndex>(), moveParent); | 
| 1076 |     QCOMPARE(beforeSignal.at(4).toInt(), destRow); | 
| 1077 |  | 
| 1078 |     QCOMPARE(afterSignal.size(), 5); | 
| 1079 |     QCOMPARE(afterSignal.at(0).value<QModelIndex>(), moveParent); | 
| 1080 |     QCOMPARE(afterSignal.at(1).toInt(), startRow); | 
| 1081 |     QCOMPARE(afterSignal.at(2).toInt(), endRow); | 
| 1082 |     QCOMPARE(afterSignal.at(3).value<QModelIndex>(), moveParent); | 
| 1083 |     QCOMPARE(afterSignal.at(4).toInt(), destRow); | 
| 1084 |  | 
| 1085 |     for (int i = 0; i < indexList.size(); i++) { | 
| 1086 |         QModelIndex idx = indexList.at(i); | 
| 1087 |         QModelIndex persistentIndex = persistentList.at(i); | 
| 1088 |         if (idx.parent() == moveParent) { | 
| 1089 |             int row = idx.row(); | 
| 1090 |             if ( row >= startRow) { | 
| 1091 |                 if (row <= endRow) { | 
| 1092 |                     QCOMPARE(row + destRow - endRow - 1, persistentIndex.row()); | 
| 1093 |                     QCOMPARE(idx.column(), persistentIndex.column()); | 
| 1094 |                     QCOMPARE(idx.parent(), persistentIndex.parent()); | 
| 1095 |                     QCOMPARE(idx.model(), persistentIndex.model()); | 
| 1096 |                 } else if (row < destRow) { | 
| 1097 |                     QCOMPARE(row - (endRow - startRow + 1), persistentIndex.row()); | 
| 1098 |                     QCOMPARE(idx.column(), persistentIndex.column()); | 
| 1099 |                     QCOMPARE(idx.parent(), persistentIndex.parent()); | 
| 1100 |                     QCOMPARE(idx.model(), persistentIndex.model()); | 
| 1101 |                 } else { | 
| 1102 |                     QCOMPARE(idx, persistentIndex); | 
| 1103 |                 } | 
| 1104 |             } else { | 
| 1105 |                 QCOMPARE(idx, persistentIndex); | 
| 1106 |             } | 
| 1107 |         } else { | 
| 1108 |             QCOMPARE(idx, persistentIndex); | 
| 1109 |         } | 
| 1110 |     } | 
| 1111 | } | 
| 1112 |  | 
| 1113 | void tst_QAbstractItemModel::testMoveSameParentUp_data() | 
| 1114 | { | 
| 1115 |     QTest::addColumn<int>(name: "startRow" ); | 
| 1116 |     QTest::addColumn<int>(name: "endRow" ); | 
| 1117 |     QTest::addColumn<int>(name: "destRow" ); | 
| 1118 |     QTest::addColumn<bool>(name: "topLevel" ); | 
| 1119 |  | 
| 1120 |     // Move from the middle to the start | 
| 1121 |     QTest::newRow(dataTag: "move01" ) << 5 << 7 << 0 << true; | 
| 1122 |     // Move from the end to the start | 
| 1123 |     QTest::newRow(dataTag: "move02" ) << 8 << 9 << 0 << true; | 
| 1124 |     // Move from the middle to the middle | 
| 1125 |     QTest::newRow(dataTag: "move03" ) << 5 << 7 << 2 << true; | 
| 1126 |     // Move from the end to the middle | 
| 1127 |     QTest::newRow(dataTag: "move04" ) << 8 << 9 << 5 << true; | 
| 1128 |  | 
| 1129 |     QTest::newRow(dataTag: "move05" ) << 5 << 7 << 0 << false; | 
| 1130 |     QTest::newRow(dataTag: "move06" ) << 8 << 9 << 0 << false; | 
| 1131 |     QTest::newRow(dataTag: "move07" ) << 5 << 7 << 2 << false; | 
| 1132 |     QTest::newRow(dataTag: "move08" ) << 8 << 9 << 5 << false; | 
| 1133 | } | 
| 1134 |  | 
| 1135 | void tst_QAbstractItemModel::testMoveSameParentUp() | 
| 1136 | { | 
| 1137 |     QFETCH(int, startRow); | 
| 1138 |     QFETCH(int, endRow); | 
| 1139 |     QFETCH(int, destRow); | 
| 1140 |     QFETCH(bool, topLevel); | 
| 1141 |  | 
| 1142 |     QModelIndex moveParent = topLevel ? QModelIndex() : m_model->index(row: 5, column: 0); | 
| 1143 |  | 
| 1144 |     QList<QPersistentModelIndex> persistentList; | 
| 1145 |     QModelIndexList indexList; | 
| 1146 |  | 
| 1147 |     for (int column = 0; column < m_model->columnCount(); ++column) { | 
| 1148 |         for (int row = 0; row < m_model->rowCount(); ++row) { | 
| 1149 |             QModelIndex idx = m_model->index(row, column); | 
| 1150 |             QVERIFY(idx.isValid()); | 
| 1151 |             indexList << idx; | 
| 1152 |             persistentList << QPersistentModelIndex(idx); | 
| 1153 |         } | 
| 1154 |     } | 
| 1155 |  | 
| 1156 |     QModelIndex parent = m_model->index(row: 2, column: 0); | 
| 1157 |     for (int column = 0; column < m_model->columnCount(); ++column) { | 
| 1158 |         for (int row = 0; row < m_model->rowCount(index: parent); ++row) { | 
| 1159 |             QModelIndex idx = m_model->index(row, column, parent); | 
| 1160 |             QVERIFY(idx.isValid()); | 
| 1161 |             indexList << idx; | 
| 1162 |             persistentList << QPersistentModelIndex(idx); | 
| 1163 |         } | 
| 1164 |     } | 
| 1165 |  | 
| 1166 |     QSignalSpy beforeSpy(m_model, &DynamicTreeModel::rowsAboutToBeMoved); | 
| 1167 |     QSignalSpy afterSpy(m_model, &DynamicTreeModel::rowsMoved); | 
| 1168 |  | 
| 1169 |     QVERIFY(beforeSpy.isValid()); | 
| 1170 |     QVERIFY(afterSpy.isValid()); | 
| 1171 |  | 
| 1172 |     ModelMoveCommand *moveCommand = new ModelMoveCommand(m_model, this); | 
| 1173 |     moveCommand->setNumCols(4); | 
| 1174 |     if (!topLevel) | 
| 1175 |         moveCommand->setAncestorRowNumbers(QList<int>() << 5); | 
| 1176 |     moveCommand->setStartRow(startRow); | 
| 1177 |     moveCommand->setEndRow(endRow); | 
| 1178 |     moveCommand->setDestRow(destRow); | 
| 1179 |     if (!topLevel) | 
| 1180 |         moveCommand->setDestAncestors(QList<int>() << 5); | 
| 1181 |     moveCommand->doCommand(); | 
| 1182 |  | 
| 1183 |     QVariantList beforeSignal = beforeSpy.takeAt(i: 0); | 
| 1184 |     QVariantList afterSignal = afterSpy.takeAt(i: 0); | 
| 1185 |  | 
| 1186 |     QCOMPARE(beforeSignal.size(), 5); | 
| 1187 |     QCOMPARE(beforeSignal.at(0).value<QModelIndex>(), moveParent); | 
| 1188 |     QCOMPARE(beforeSignal.at(1).toInt(), startRow); | 
| 1189 |     QCOMPARE(beforeSignal.at(2).toInt(), endRow); | 
| 1190 |     QCOMPARE(beforeSignal.at(3).value<QModelIndex>(), moveParent); | 
| 1191 |     QCOMPARE(beforeSignal.at(4).toInt(), destRow); | 
| 1192 |  | 
| 1193 |     QCOMPARE(afterSignal.size(), 5); | 
| 1194 |     QCOMPARE(afterSignal.at(0).value<QModelIndex>(), moveParent); | 
| 1195 |     QCOMPARE(afterSignal.at(1).toInt(), startRow); | 
| 1196 |     QCOMPARE(afterSignal.at(2).toInt(), endRow); | 
| 1197 |     QCOMPARE(afterSignal.at(3).value<QModelIndex>(), moveParent); | 
| 1198 |     QCOMPARE(afterSignal.at(4).toInt(), destRow); | 
| 1199 |  | 
| 1200 |     for (int i = 0; i < indexList.size(); i++) { | 
| 1201 |         QModelIndex idx = indexList.at(i); | 
| 1202 |         QModelIndex persistentIndex = persistentList.at(i); | 
| 1203 |         if (idx.parent() == moveParent) { | 
| 1204 |             int row = idx.row(); | 
| 1205 |             if ( row >= destRow) { | 
| 1206 |                 if (row < startRow) { | 
| 1207 |                     QCOMPARE(row + endRow - startRow + 1, persistentIndex.row()); | 
| 1208 |                     QCOMPARE(idx.column(), persistentIndex.column()); | 
| 1209 |                     QCOMPARE(idx.parent(), persistentIndex.parent()); | 
| 1210 |                     QCOMPARE(idx.model(), persistentIndex.model()); | 
| 1211 |                 } else if (row <= endRow) { | 
| 1212 |                     QCOMPARE(row + destRow - startRow, persistentIndex.row()); | 
| 1213 |                     QCOMPARE(idx.column(), persistentIndex.column()); | 
| 1214 |                     QCOMPARE(idx.parent(), persistentIndex.parent()); | 
| 1215 |                     QCOMPARE(idx.model(), persistentIndex.model()); | 
| 1216 |                 } else { | 
| 1217 |                     QCOMPARE(idx, persistentIndex); | 
| 1218 |                 } | 
| 1219 |             } else { | 
| 1220 |                 QCOMPARE(idx, persistentIndex); | 
| 1221 |             } | 
| 1222 |         } else { | 
| 1223 |             QCOMPARE(idx, persistentIndex); | 
| 1224 |         } | 
| 1225 |     } | 
| 1226 | } | 
| 1227 |  | 
| 1228 | void tst_QAbstractItemModel::testMoveThroughProxy() | 
| 1229 | { | 
| 1230 |     QSortFilterProxyModel *proxy = new QSortFilterProxyModel(this); | 
| 1231 |     proxy->setSourceModel(m_model); | 
| 1232 |  | 
| 1233 |     QList<QPersistentModelIndex> persistentList; | 
| 1234 |  | 
| 1235 |     persistentList.append(t: proxy->index(row: 0, column: 0)); | 
| 1236 |     persistentList.append(t: proxy->index(row: 0, column: 0, parent: proxy->mapFromSource(sourceIndex: m_model->index(row: 5, column: 0)))); | 
| 1237 |  | 
| 1238 |     ModelMoveCommand *moveCommand = new ModelMoveCommand(m_model, this); | 
| 1239 |     moveCommand->setNumCols(4); | 
| 1240 |     moveCommand->setAncestorRowNumbers(QList<int>() << 5); | 
| 1241 |     moveCommand->setStartRow(0); | 
| 1242 |     moveCommand->setEndRow(0); | 
| 1243 |     moveCommand->setDestRow(0); | 
| 1244 |     moveCommand->doCommand(); | 
| 1245 | } | 
| 1246 |  | 
| 1247 | void tst_QAbstractItemModel::testMoveToGrandParent_data() | 
| 1248 | { | 
| 1249 |     QTest::addColumn<int>(name: "startRow" ); | 
| 1250 |     QTest::addColumn<int>(name: "endRow" ); | 
| 1251 |     QTest::addColumn<int>(name: "destRow" ); | 
| 1252 |  | 
| 1253 |     // Move from the start to the middle | 
| 1254 |     QTest::newRow(dataTag: "move01" ) << 0 << 2 << 8; | 
| 1255 |     // Move from the start to the end | 
| 1256 |     QTest::newRow(dataTag: "move02" ) << 0 << 2 << 10; | 
| 1257 |     // Move from the middle to the middle | 
| 1258 |     QTest::newRow(dataTag: "move03" ) << 3 << 5 << 8; | 
| 1259 |     // Move from the middle to the end | 
| 1260 |     QTest::newRow(dataTag: "move04" ) << 3 << 5 << 10; | 
| 1261 |  | 
| 1262 |     // Move from the middle to the start | 
| 1263 |     QTest::newRow(dataTag: "move05" ) << 5 << 7 << 0; | 
| 1264 |     // Move from the end to the start | 
| 1265 |     QTest::newRow(dataTag: "move06" ) << 8 << 9 << 0; | 
| 1266 |     // Move from the middle to the middle | 
| 1267 |     QTest::newRow(dataTag: "move07" ) << 5 << 7 << 2; | 
| 1268 |     // Move from the end to the middle | 
| 1269 |     QTest::newRow(dataTag: "move08" ) << 8 << 9 << 5; | 
| 1270 |  | 
| 1271 |     // Moving to the same row in a different parent doesn't confuse things. | 
| 1272 |     QTest::newRow(dataTag: "move09" ) << 8 << 8 << 8; | 
| 1273 |  | 
| 1274 |     // Moving to the row of my parent and its neighbours doesn't confuse things | 
| 1275 |     QTest::newRow(dataTag: "move10" ) << 8 << 8 << 4; | 
| 1276 |     QTest::newRow(dataTag: "move11" ) << 8 << 8 << 5; | 
| 1277 |     QTest::newRow(dataTag: "move12" ) << 8 << 8 << 6; | 
| 1278 |  | 
| 1279 |     // Moving everything from one parent to another | 
| 1280 |     QTest::newRow(dataTag: "move13" ) << 0 << 9 << 10; | 
| 1281 |     QTest::newRow(dataTag: "move14" ) << 0 << 9 << 0; | 
| 1282 | } | 
| 1283 |  | 
| 1284 | void tst_QAbstractItemModel::testMoveToGrandParent() | 
| 1285 | { | 
| 1286 |     QFETCH(int, startRow); | 
| 1287 |     QFETCH(int, endRow); | 
| 1288 |     QFETCH(int, destRow); | 
| 1289 |  | 
| 1290 |     QList<QPersistentModelIndex> persistentList; | 
| 1291 |     QModelIndexList indexList; | 
| 1292 |     QModelIndexList parentsList; | 
| 1293 |  | 
| 1294 |     for (int column = 0; column < m_model->columnCount(); ++column) { | 
| 1295 |         for (int row = 0; row < m_model->rowCount(); ++row) { | 
| 1296 |             QModelIndex idx = m_model->index(row, column); | 
| 1297 |             QVERIFY(idx.isValid()); | 
| 1298 |             indexList << idx; | 
| 1299 |             parentsList << idx.parent(); | 
| 1300 |             persistentList << QPersistentModelIndex(idx); | 
| 1301 |         } | 
| 1302 |     } | 
| 1303 |  | 
| 1304 |     QModelIndex sourceIndex = m_model->index(row: 5, column: 0); | 
| 1305 |     for (int column = 0; column < m_model->columnCount(); ++column) { | 
| 1306 |         for (int row = 0; row < m_model->rowCount(index: sourceIndex); ++row) { | 
| 1307 |             QModelIndex idx = m_model->index(row, column, parent: sourceIndex); | 
| 1308 |             QVERIFY(idx.isValid()); | 
| 1309 |             indexList << idx; | 
| 1310 |             parentsList << idx.parent(); | 
| 1311 |             persistentList << QPersistentModelIndex(idx); | 
| 1312 |         } | 
| 1313 |     } | 
| 1314 |  | 
| 1315 |     QSignalSpy beforeSpy(m_model, &DynamicTreeModel::rowsAboutToBeMoved); | 
| 1316 |     QSignalSpy afterSpy(m_model, &DynamicTreeModel::rowsMoved); | 
| 1317 |  | 
| 1318 |     QVERIFY(beforeSpy.isValid()); | 
| 1319 |     QVERIFY(afterSpy.isValid()); | 
| 1320 |  | 
| 1321 |     QPersistentModelIndex persistentSource = sourceIndex; | 
| 1322 |  | 
| 1323 |     ModelMoveCommand *moveCommand = new ModelMoveCommand(m_model, this); | 
| 1324 |     moveCommand->setAncestorRowNumbers(QList<int>() << 5); | 
| 1325 |     moveCommand->setNumCols(4); | 
| 1326 |     moveCommand->setStartRow(startRow); | 
| 1327 |     moveCommand->setEndRow(endRow); | 
| 1328 |     moveCommand->setDestRow(destRow); | 
| 1329 |     moveCommand->doCommand(); | 
| 1330 |  | 
| 1331 |     QVariantList beforeSignal = beforeSpy.takeAt(i: 0); | 
| 1332 |     QVariantList afterSignal = afterSpy.takeAt(i: 0); | 
| 1333 |  | 
| 1334 |     QCOMPARE(beforeSignal.size(), 5); | 
| 1335 |     QCOMPARE(beforeSignal.at(0).value<QModelIndex>(), sourceIndex); | 
| 1336 |     QCOMPARE(beforeSignal.at(1).toInt(), startRow); | 
| 1337 |     QCOMPARE(beforeSignal.at(2).toInt(), endRow); | 
| 1338 |     QCOMPARE(beforeSignal.at(3).value<QModelIndex>(), QModelIndex()); | 
| 1339 |     QCOMPARE(beforeSignal.at(4).toInt(), destRow); | 
| 1340 |  | 
| 1341 |     QCOMPARE(afterSignal.size(), 5); | 
| 1342 |     QCOMPARE(afterSignal.at(0).value<QModelIndex>(), static_cast<QModelIndex>(persistentSource)); | 
| 1343 |     QCOMPARE(afterSignal.at(1).toInt(), startRow); | 
| 1344 |     QCOMPARE(afterSignal.at(2).toInt(), endRow); | 
| 1345 |     QCOMPARE(afterSignal.at(3).value<QModelIndex>(), QModelIndex()); | 
| 1346 |     QCOMPARE(afterSignal.at(4).toInt(), destRow); | 
| 1347 |  | 
| 1348 |     for (int i = 0; i < indexList.size(); i++) { | 
| 1349 |         QModelIndex idx = indexList.at(i); | 
| 1350 |         QModelIndex idxParent = parentsList.at(i); | 
| 1351 |         QModelIndex persistentIndex = persistentList.at(i); | 
| 1352 |         int row = idx.row(); | 
| 1353 |         if (idxParent == QModelIndex()) { | 
| 1354 |             if (row >= destRow) { | 
| 1355 |                 QCOMPARE(row + endRow - startRow + 1, persistentIndex.row()); | 
| 1356 |                 QCOMPARE(idx.column(), persistentIndex.column()); | 
| 1357 |                 QCOMPARE(idxParent, persistentIndex.parent()); | 
| 1358 |                 QCOMPARE(idx.model(), persistentIndex.model()); | 
| 1359 |             } else { | 
| 1360 |                 QCOMPARE(idx, persistentIndex); | 
| 1361 |             } | 
| 1362 |         } else { | 
| 1363 |             if (row < startRow) { | 
| 1364 |                 QCOMPARE(idx, persistentIndex); | 
| 1365 |             } else if (row <= endRow) { | 
| 1366 |                 QCOMPARE(row + destRow - startRow, persistentIndex.row()); | 
| 1367 |                 QCOMPARE(idx.column(), persistentIndex.column()); | 
| 1368 |                 QCOMPARE(QModelIndex(), persistentIndex.parent()); | 
| 1369 |                 QCOMPARE(idx.model(), persistentIndex.model()); | 
| 1370 |             } else { | 
| 1371 |                 QCOMPARE(row - (endRow - startRow + 1), persistentIndex.row()); | 
| 1372 |                 QCOMPARE(idx.column(), persistentIndex.column()); | 
| 1373 |  | 
| 1374 |                 if (idxParent.row() >= destRow) { | 
| 1375 |                     QModelIndex adjustedParent; | 
| 1376 |                     adjustedParent = idxParent.sibling(arow: idxParent.row() + endRow - startRow + 1, acolumn: idxParent.column()); | 
| 1377 |                     QCOMPARE(adjustedParent, persistentIndex.parent()); | 
| 1378 |                 } else { | 
| 1379 |                     QCOMPARE(idxParent, persistentIndex.parent()); | 
| 1380 |                 } | 
| 1381 |                 QCOMPARE(idx.model(), persistentIndex.model()); | 
| 1382 |             } | 
| 1383 |         } | 
| 1384 |     } | 
| 1385 | } | 
| 1386 |  | 
| 1387 | void tst_QAbstractItemModel::testMoveToSibling_data() | 
| 1388 | { | 
| 1389 |     QTest::addColumn<int>(name: "startRow" ); | 
| 1390 |     QTest::addColumn<int>(name: "endRow" ); | 
| 1391 |     QTest::addColumn<int>(name: "destRow" ); | 
| 1392 |  | 
| 1393 |     // Move from the start to the middle | 
| 1394 |     QTest::newRow(dataTag: "move01" ) << 0 << 2 << 8; | 
| 1395 |     // Move from the start to the end | 
| 1396 |     QTest::newRow(dataTag: "move02" ) << 0 << 2 << 10; | 
| 1397 |     // Move from the middle to the middle | 
| 1398 |     QTest::newRow(dataTag: "move03" ) << 2 << 4 << 8; | 
| 1399 |     // Move from the middle to the end | 
| 1400 |     QTest::newRow(dataTag: "move04" ) << 2 << 4 << 10; | 
| 1401 |  | 
| 1402 |     // Move from the middle to the start | 
| 1403 |     QTest::newRow(dataTag: "move05" ) << 8 << 8 << 0; | 
| 1404 |     // Move from the end to the start | 
| 1405 |     QTest::newRow(dataTag: "move06" ) << 8 << 9 << 0; | 
| 1406 |     // Move from the middle to the middle | 
| 1407 |     QTest::newRow(dataTag: "move07" ) << 6 << 8 << 2; | 
| 1408 |     // Move from the end to the middle | 
| 1409 |     QTest::newRow(dataTag: "move08" ) << 8 << 9 << 5; | 
| 1410 |  | 
| 1411 |     // Moving to the same row in a different parent doesn't confuse things. | 
| 1412 |     QTest::newRow(dataTag: "move09" ) << 8 << 8 << 8; | 
| 1413 |  | 
| 1414 |     // Moving to the row of my target and its neighbours doesn't confuse things | 
| 1415 |     QTest::newRow(dataTag: "move10" ) << 8 << 8 << 4; | 
| 1416 |     QTest::newRow(dataTag: "move11" ) << 8 << 8 << 5; | 
| 1417 |     QTest::newRow(dataTag: "move12" ) << 8 << 8 << 6; | 
| 1418 |  | 
| 1419 |     // Move such that the destination parent no longer valid after the move. | 
| 1420 |     // The destination parent is always QMI(5, 0), but after this move the | 
| 1421 |     // row count is 5, so (5, 0) (used internally in QAIM) no longer refers to a valid index. | 
| 1422 |     QTest::newRow(dataTag: "move13" ) << 0 << 4 << 0; | 
| 1423 | } | 
| 1424 |  | 
| 1425 | void tst_QAbstractItemModel::testMoveToSibling() | 
| 1426 | { | 
| 1427 |     QFETCH(int, startRow); | 
| 1428 |     QFETCH(int, endRow); | 
| 1429 |     QFETCH(int, destRow); | 
| 1430 |  | 
| 1431 |     QList<QPersistentModelIndex> persistentList; | 
| 1432 |     QModelIndexList indexList; | 
| 1433 |     QModelIndexList parentsList; | 
| 1434 |  | 
| 1435 |     const int column = 0; | 
| 1436 |  | 
| 1437 |     for (int i = 0; i < m_model->rowCount(); ++i) { | 
| 1438 |         QModelIndex idx = m_model->index(row: i, column); | 
| 1439 |         QVERIFY(idx.isValid()); | 
| 1440 |         indexList << idx; | 
| 1441 |         parentsList << idx.parent(); | 
| 1442 |         persistentList << QPersistentModelIndex(idx); | 
| 1443 |     } | 
| 1444 |  | 
| 1445 |     QModelIndex destIndex = m_model->index(row: 5, column: 0); | 
| 1446 |     QModelIndex sourceIndex; | 
| 1447 |     for (int i = 0; i < m_model->rowCount(index: destIndex); ++i) { | 
| 1448 |         QModelIndex idx = m_model->index(row: i, column, parent: destIndex); | 
| 1449 |         QVERIFY(idx.isValid()); | 
| 1450 |         indexList << idx; | 
| 1451 |         parentsList << idx.parent(); | 
| 1452 |         persistentList << QPersistentModelIndex(idx); | 
| 1453 |     } | 
| 1454 |  | 
| 1455 |     QSignalSpy beforeSpy(m_model, &DynamicTreeModel::rowsAboutToBeMoved); | 
| 1456 |     QSignalSpy afterSpy(m_model, &DynamicTreeModel::rowsMoved); | 
| 1457 |  | 
| 1458 |     QVERIFY(beforeSpy.isValid()); | 
| 1459 |     QVERIFY(afterSpy.isValid()); | 
| 1460 |  | 
| 1461 |     QPersistentModelIndex persistentDest = destIndex; | 
| 1462 |  | 
| 1463 |     ModelMoveCommand *moveCommand = new ModelMoveCommand(m_model, this); | 
| 1464 |     moveCommand->setNumCols(4); | 
| 1465 |     moveCommand->setStartRow(startRow); | 
| 1466 |     moveCommand->setEndRow(endRow); | 
| 1467 |     moveCommand->setDestAncestors(QList<int>() << 5); | 
| 1468 |     moveCommand->setDestRow(destRow); | 
| 1469 |     moveCommand->doCommand(); | 
| 1470 |  | 
| 1471 |     QVariantList beforeSignal = beforeSpy.takeAt(i: 0); | 
| 1472 |     QVariantList afterSignal = afterSpy.takeAt(i: 0); | 
| 1473 |  | 
| 1474 |     QCOMPARE(beforeSignal.size(), 5); | 
| 1475 |     QCOMPARE(beforeSignal.at(0).value<QModelIndex>(), sourceIndex); | 
| 1476 |     QCOMPARE(beforeSignal.at(1).toInt(), startRow); | 
| 1477 |     QCOMPARE(beforeSignal.at(2).toInt(), endRow); | 
| 1478 |     QCOMPARE(beforeSignal.at(3).value<QModelIndex>(), destIndex); | 
| 1479 |     QCOMPARE(beforeSignal.at(4).toInt(), destRow); | 
| 1480 |  | 
| 1481 |     QCOMPARE(afterSignal.size(), 5); | 
| 1482 |     QCOMPARE(afterSignal.at(0).value<QModelIndex>(), sourceIndex); | 
| 1483 |     QCOMPARE(afterSignal.at(1).toInt(), startRow); | 
| 1484 |     QCOMPARE(afterSignal.at(2).toInt(), endRow); | 
| 1485 |     QCOMPARE(afterSignal.at(3).value<QModelIndex>(), static_cast<QModelIndex>(persistentDest)); | 
| 1486 |     QCOMPARE(afterSignal.at(4).toInt(), destRow); | 
| 1487 |  | 
| 1488 |     for (int i = 0; i < indexList.size(); i++) { | 
| 1489 |         QModelIndex idx = indexList.at(i); | 
| 1490 |         QModelIndex idxParent = parentsList.at(i); | 
| 1491 |         QModelIndex persistentIndex = persistentList.at(i); | 
| 1492 |  | 
| 1493 |         QModelIndex adjustedDestination = destIndex.sibling(arow: destIndex.row() - (endRow - startRow + 1), acolumn: destIndex.column()); | 
| 1494 |         int row = idx.row(); | 
| 1495 |         if (idxParent == destIndex) { | 
| 1496 |             if (row >= destRow) { | 
| 1497 |                 QCOMPARE(row + endRow - startRow + 1, persistentIndex.row()); | 
| 1498 |                 QCOMPARE(idx.column(), persistentIndex.column()); | 
| 1499 |                 if (idxParent.row() > startRow) { | 
| 1500 |                     QCOMPARE(adjustedDestination, persistentIndex.parent()); | 
| 1501 |                 } else { | 
| 1502 |                     QCOMPARE(destIndex, persistentIndex.parent()); | 
| 1503 |                 } | 
| 1504 |                 QCOMPARE(idx.model(), persistentIndex.model()); | 
| 1505 |             } else { | 
| 1506 |                 QCOMPARE(idx, persistentIndex); | 
| 1507 |             } | 
| 1508 |         } else { | 
| 1509 |             if (row < startRow) { | 
| 1510 |                 QCOMPARE(idx, persistentIndex); | 
| 1511 |             } else if (row <= endRow) { | 
| 1512 |                 QCOMPARE(row + destRow - startRow, persistentIndex.row()); | 
| 1513 |                 QCOMPARE(idx.column(), persistentIndex.column()); | 
| 1514 |                 if (destIndex.row() > startRow) { | 
| 1515 |                     QCOMPARE(adjustedDestination, persistentIndex.parent()); | 
| 1516 |                 } else { | 
| 1517 |                     QCOMPARE(destIndex, persistentIndex.parent()); | 
| 1518 |                 } | 
| 1519 |  | 
| 1520 |                 QCOMPARE(idx.model(), persistentIndex.model()); | 
| 1521 |             } else { | 
| 1522 |                 QCOMPARE(row - (endRow - startRow + 1), persistentIndex.row()); | 
| 1523 |                 QCOMPARE(idx.column(), persistentIndex.column()); | 
| 1524 |                 QCOMPARE(idxParent, persistentIndex.parent()); | 
| 1525 |                 QCOMPARE(idx.model(), persistentIndex.model()); | 
| 1526 |             } | 
| 1527 |         } | 
| 1528 |     } | 
| 1529 | } | 
| 1530 |  | 
| 1531 | void tst_QAbstractItemModel::testMoveToUncle_data() | 
| 1532 | { | 
| 1533 |     QTest::addColumn<int>(name: "startRow" ); | 
| 1534 |     QTest::addColumn<int>(name: "endRow" ); | 
| 1535 |     QTest::addColumn<int>(name: "destRow" ); | 
| 1536 |  | 
| 1537 |     // Move from the start to the middle | 
| 1538 |     QTest::newRow(dataTag: "move01" ) << 0 << 2 << 8; | 
| 1539 |     // Move from the start to the end | 
| 1540 |     QTest::newRow(dataTag: "move02" ) << 0 << 2 << 10; | 
| 1541 |     // Move from the middle to the middle | 
| 1542 |     QTest::newRow(dataTag: "move03" ) << 3 << 5 << 8; | 
| 1543 |     // Move from the middle to the end | 
| 1544 |     QTest::newRow(dataTag: "move04" ) << 3 << 5 << 10; | 
| 1545 |  | 
| 1546 |     // Move from the middle to the start | 
| 1547 |     QTest::newRow(dataTag: "move05" ) << 5 << 7 << 0; | 
| 1548 |     // Move from the end to the start | 
| 1549 |     QTest::newRow(dataTag: "move06" ) << 8 << 9 << 0; | 
| 1550 |     // Move from the middle to the middle | 
| 1551 |     QTest::newRow(dataTag: "move07" ) << 5 << 7 << 2; | 
| 1552 |     // Move from the end to the middle | 
| 1553 |     QTest::newRow(dataTag: "move08" ) << 8 << 9 << 5; | 
| 1554 |  | 
| 1555 |     // Moving to the same row in a different parent doesn't confuse things. | 
| 1556 |     QTest::newRow(dataTag: "move09" ) << 8 << 8 << 8; | 
| 1557 |  | 
| 1558 |     // Moving to the row of my parent and its neighbours doesn't confuse things | 
| 1559 |     QTest::newRow(dataTag: "move10" ) << 8 << 8 << 4; | 
| 1560 |     QTest::newRow(dataTag: "move11" ) << 8 << 8 << 5; | 
| 1561 |     QTest::newRow(dataTag: "move12" ) << 8 << 8 << 6; | 
| 1562 |  | 
| 1563 |     // Moving everything from one parent to another | 
| 1564 |     QTest::newRow(dataTag: "move13" ) << 0 << 9 << 10; | 
| 1565 | } | 
| 1566 |  | 
| 1567 | void tst_QAbstractItemModel::testMoveToUncle() | 
| 1568 | { | 
| 1569 |     // Need to have some extra rows available. | 
| 1570 |     ModelInsertCommand *insertCommand = new ModelInsertCommand(m_model, this); | 
| 1571 |     insertCommand->setAncestorRowNumbers(QList<int>() << 9); | 
| 1572 |     insertCommand->setNumCols(4); | 
| 1573 |     insertCommand->setStartRow(0); | 
| 1574 |     insertCommand->setEndRow(9); | 
| 1575 |     insertCommand->doCommand(); | 
| 1576 |  | 
| 1577 |     QFETCH(int, startRow); | 
| 1578 |     QFETCH(int, endRow); | 
| 1579 |     QFETCH(int, destRow); | 
| 1580 |  | 
| 1581 |     QList<QPersistentModelIndex> persistentList; | 
| 1582 |     QModelIndexList indexList; | 
| 1583 |     QModelIndexList parentsList; | 
| 1584 |  | 
| 1585 |     const int column = 0; | 
| 1586 |  | 
| 1587 |     QModelIndex sourceIndex = m_model->index(row: 9, column: 0); | 
| 1588 |     for (int i = 0; i < m_model->rowCount(index: sourceIndex); ++i) { | 
| 1589 |         QModelIndex idx = m_model->index(row: i, column, parent: sourceIndex); | 
| 1590 |         QVERIFY(idx.isValid()); | 
| 1591 |         indexList << idx; | 
| 1592 |         parentsList << idx.parent(); | 
| 1593 |         persistentList << QPersistentModelIndex(idx); | 
| 1594 |     } | 
| 1595 |  | 
| 1596 |     QModelIndex destIndex = m_model->index(row: 5, column: 0); | 
| 1597 |     for (int i = 0; i < m_model->rowCount(index: destIndex); ++i) { | 
| 1598 |         QModelIndex idx = m_model->index(row: i, column, parent: destIndex); | 
| 1599 |         QVERIFY(idx.isValid()); | 
| 1600 |         indexList << idx; | 
| 1601 |         parentsList << idx.parent(); | 
| 1602 |         persistentList << QPersistentModelIndex(idx); | 
| 1603 |     } | 
| 1604 |  | 
| 1605 |     QSignalSpy beforeSpy(m_model, &DynamicTreeModel::rowsAboutToBeMoved); | 
| 1606 |     QSignalSpy afterSpy(m_model, &DynamicTreeModel::rowsMoved); | 
| 1607 |  | 
| 1608 |     QVERIFY(beforeSpy.isValid()); | 
| 1609 |     QVERIFY(afterSpy.isValid()); | 
| 1610 |  | 
| 1611 |     ModelMoveCommand *moveCommand = new ModelMoveCommand(m_model, this); | 
| 1612 |     moveCommand->setAncestorRowNumbers(QList<int>() << 9); | 
| 1613 |     moveCommand->setNumCols(4); | 
| 1614 |     moveCommand->setStartRow(startRow); | 
| 1615 |     moveCommand->setEndRow(endRow); | 
| 1616 |     moveCommand->setDestAncestors(QList<int>() << 5); | 
| 1617 |     moveCommand->setDestRow(destRow); | 
| 1618 |     moveCommand->doCommand(); | 
| 1619 |  | 
| 1620 |     QVariantList beforeSignal = beforeSpy.takeAt(i: 0); | 
| 1621 |     QVariantList afterSignal = afterSpy.takeAt(i: 0); | 
| 1622 |  | 
| 1623 |     QCOMPARE(beforeSignal.size(), 5); | 
| 1624 |     QCOMPARE(beforeSignal.at(0).value<QModelIndex>(), sourceIndex); | 
| 1625 |     QCOMPARE(beforeSignal.at(1).toInt(), startRow); | 
| 1626 |     QCOMPARE(beforeSignal.at(2).toInt(), endRow); | 
| 1627 |     QCOMPARE(beforeSignal.at(3).value<QModelIndex>(), destIndex); | 
| 1628 |     QCOMPARE(beforeSignal.at(4).toInt(), destRow); | 
| 1629 |  | 
| 1630 |     QCOMPARE(afterSignal.size(), 5); | 
| 1631 |     QCOMPARE(afterSignal.at(0).value<QModelIndex>(), sourceIndex); | 
| 1632 |     QCOMPARE(afterSignal.at(1).toInt(), startRow); | 
| 1633 |     QCOMPARE(afterSignal.at(2).toInt(), endRow); | 
| 1634 |     QCOMPARE(afterSignal.at(3).value<QModelIndex>(), destIndex); | 
| 1635 |     QCOMPARE(afterSignal.at(4).toInt(), destRow); | 
| 1636 |  | 
| 1637 |     for (int i = 0; i < indexList.size(); i++) { | 
| 1638 |         QModelIndex idx = indexList.at(i); | 
| 1639 |         QModelIndex idxParent = parentsList.at(i); | 
| 1640 |         QModelIndex persistentIndex = persistentList.at(i); | 
| 1641 |  | 
| 1642 |         int row = idx.row(); | 
| 1643 |         if (idxParent == destIndex) { | 
| 1644 |             if (row >= destRow) { | 
| 1645 |                 QCOMPARE(row + endRow - startRow + 1, persistentIndex.row()); | 
| 1646 |                 QCOMPARE(idx.column(), persistentIndex.column()); | 
| 1647 |                 QCOMPARE(destIndex, persistentIndex.parent()); | 
| 1648 |                 QCOMPARE(idx.model(), persistentIndex.model()); | 
| 1649 |             } else { | 
| 1650 |                 QCOMPARE(idx, persistentIndex); | 
| 1651 |             } | 
| 1652 |         } else { | 
| 1653 |             if (row < startRow) { | 
| 1654 |                 QCOMPARE(idx, persistentIndex); | 
| 1655 |             } else if (row <= endRow) { | 
| 1656 |                 QCOMPARE(row + destRow - startRow, persistentIndex.row()); | 
| 1657 |                 QCOMPARE(idx.column(), persistentIndex.column()); | 
| 1658 |                 QCOMPARE(destIndex, persistentIndex.parent()); | 
| 1659 |                 QCOMPARE(idx.model(), persistentIndex.model()); | 
| 1660 |             } else { | 
| 1661 |                 QCOMPARE(row - (endRow - startRow + 1), persistentIndex.row()); | 
| 1662 |                 QCOMPARE(idx.column(), persistentIndex.column()); | 
| 1663 |                 QCOMPARE(idxParent, persistentIndex.parent()); | 
| 1664 |                 QCOMPARE(idx.model(), persistentIndex.model()); | 
| 1665 |             } | 
| 1666 |         } | 
| 1667 |     } | 
| 1668 | } | 
| 1669 |  | 
| 1670 | void tst_QAbstractItemModel::testMoveToDescendants() | 
| 1671 | { | 
| 1672 |     // Attempt to move a row to its ancestors depth rows deep. | 
| 1673 |     const int depth = 6; | 
| 1674 |  | 
| 1675 |     // Need to have some extra rows available in a tree. | 
| 1676 |     QList<int> rows; | 
| 1677 |     ModelInsertCommand *insertCommand; | 
| 1678 |     for (int i = 0; i < depth; i++) { | 
| 1679 |         insertCommand = new ModelInsertCommand(m_model, this); | 
| 1680 |         insertCommand->setAncestorRowNumbers(rows); | 
| 1681 |         insertCommand->setNumCols(4); | 
| 1682 |         insertCommand->setStartRow(0); | 
| 1683 |         insertCommand->setEndRow(9); | 
| 1684 |         insertCommand->doCommand(); | 
| 1685 |         rows << 9; | 
| 1686 |     } | 
| 1687 |  | 
| 1688 |     QList<QPersistentModelIndex> persistentList; | 
| 1689 |     QModelIndexList indexList; | 
| 1690 |     QModelIndexList parentsList; | 
| 1691 |  | 
| 1692 |     const int column = 0; | 
| 1693 |  | 
| 1694 |     QModelIndex sourceIndex = m_model->index(row: 9, column: 0); | 
| 1695 |     for (int i = 0; i < m_model->rowCount(index: sourceIndex); ++i) { | 
| 1696 |         QModelIndex idx = m_model->index(row: i, column, parent: sourceIndex); | 
| 1697 |         QVERIFY(idx.isValid()); | 
| 1698 |         indexList << idx; | 
| 1699 |         parentsList << idx.parent(); | 
| 1700 |         persistentList << QPersistentModelIndex(idx); | 
| 1701 |     } | 
| 1702 |  | 
| 1703 |     QModelIndex destIndex = m_model->index(row: 5, column: 0); | 
| 1704 |     for (int i = 0; i < m_model->rowCount(index: destIndex); ++i) { | 
| 1705 |         QModelIndex idx = m_model->index(row: i, column, parent: destIndex); | 
| 1706 |         QVERIFY(idx.isValid()); | 
| 1707 |         indexList << idx; | 
| 1708 |         parentsList << idx.parent(); | 
| 1709 |         persistentList << QPersistentModelIndex(idx); | 
| 1710 |     } | 
| 1711 |  | 
| 1712 |     QSignalSpy beforeSpy(m_model, &DynamicTreeModel::rowsAboutToBeMoved); | 
| 1713 |     QSignalSpy afterSpy(m_model, &DynamicTreeModel::rowsMoved); | 
| 1714 |  | 
| 1715 |     QVERIFY(beforeSpy.isValid()); | 
| 1716 |     QVERIFY(afterSpy.isValid()); | 
| 1717 |  | 
| 1718 |     ModelMoveCommand *moveCommand; | 
| 1719 |     QList<int> ancestors; | 
| 1720 |     while (ancestors.size() < depth) { | 
| 1721 |         ancestors << 9; | 
| 1722 |         for (int row = 0; row <= 9; row++) { | 
| 1723 |             moveCommand = new ModelMoveCommand(m_model, this); | 
| 1724 |             moveCommand->setNumCols(4); | 
| 1725 |             moveCommand->setStartRow(9); | 
| 1726 |             moveCommand->setEndRow(9); | 
| 1727 |             moveCommand->setDestAncestors(ancestors); | 
| 1728 |             moveCommand->setDestRow(row); | 
| 1729 |             moveCommand->doCommand(); | 
| 1730 |  | 
| 1731 |             QCOMPARE(beforeSpy.size(), 0); | 
| 1732 |             QCOMPARE(afterSpy.size(), 0); | 
| 1733 |         } | 
| 1734 |     } | 
| 1735 | } | 
| 1736 |  | 
| 1737 | void tst_QAbstractItemModel::testMoveWithinOwnRange_data() | 
| 1738 | { | 
| 1739 |     QTest::addColumn<int>(name: "startRow" ); | 
| 1740 |     QTest::addColumn<int>(name: "endRow" ); | 
| 1741 |     QTest::addColumn<int>(name: "destRow" ); | 
| 1742 |  | 
| 1743 |     QTest::newRow(dataTag: "move01" ) << 0 << 0 << 0; | 
| 1744 |     QTest::newRow(dataTag: "move02" ) << 0 << 0 << 1; | 
| 1745 |     QTest::newRow(dataTag: "move03" ) << 0 << 5 << 0; | 
| 1746 |     QTest::newRow(dataTag: "move04" ) << 0 << 5 << 1; | 
| 1747 |     QTest::newRow(dataTag: "move05" ) << 0 << 5 << 2; | 
| 1748 |     QTest::newRow(dataTag: "move06" ) << 0 << 5 << 3; | 
| 1749 |     QTest::newRow(dataTag: "move07" ) << 0 << 5 << 4; | 
| 1750 |     QTest::newRow(dataTag: "move08" ) << 0 << 5 << 5; | 
| 1751 |     QTest::newRow(dataTag: "move09" ) << 0 << 5 << 6; | 
| 1752 |     QTest::newRow(dataTag: "move10" ) << 3 << 5 << 5; | 
| 1753 |     QTest::newRow(dataTag: "move11" ) << 3 << 5 << 6; | 
| 1754 |     QTest::newRow(dataTag: "move12" ) << 4 << 5 << 5; | 
| 1755 |     QTest::newRow(dataTag: "move13" ) << 4 << 5 << 6; | 
| 1756 |     QTest::newRow(dataTag: "move14" ) << 5 << 5 << 5; | 
| 1757 |     QTest::newRow(dataTag: "move15" ) << 5 << 5 << 6; | 
| 1758 |     QTest::newRow(dataTag: "move16" ) << 5 << 9 << 9; | 
| 1759 |     QTest::newRow(dataTag: "move17" ) << 5 << 9 << 10; | 
| 1760 |     QTest::newRow(dataTag: "move18" ) << 6 << 9 << 9; | 
| 1761 |     QTest::newRow(dataTag: "move19" ) << 6 << 9 << 10; | 
| 1762 |     QTest::newRow(dataTag: "move20" ) << 7 << 9 << 9; | 
| 1763 |     QTest::newRow(dataTag: "move21" ) << 7 << 9 << 10; | 
| 1764 |     QTest::newRow(dataTag: "move22" ) << 8 << 9 << 9; | 
| 1765 |     QTest::newRow(dataTag: "move23" ) << 8 << 9 << 10; | 
| 1766 |     QTest::newRow(dataTag: "move24" ) << 9 << 9 << 9; | 
| 1767 |     QTest::newRow(dataTag: "move25" ) << 0 << 9 << 10; | 
| 1768 | } | 
| 1769 |  | 
| 1770 | void tst_QAbstractItemModel::testMoveWithinOwnRange() | 
| 1771 | { | 
| 1772 |     QFETCH(int, startRow); | 
| 1773 |     QFETCH(int, endRow); | 
| 1774 |     QFETCH(int, destRow); | 
| 1775 |  | 
| 1776 |     QSignalSpy beforeSpy(m_model, &DynamicTreeModel::rowsAboutToBeMoved); | 
| 1777 |     QSignalSpy afterSpy(m_model, &DynamicTreeModel::rowsMoved); | 
| 1778 |  | 
| 1779 |     QVERIFY(beforeSpy.isValid()); | 
| 1780 |     QVERIFY(afterSpy.isValid()); | 
| 1781 |  | 
| 1782 |     ModelMoveCommand *moveCommand = new ModelMoveCommand(m_model, this); | 
| 1783 |     moveCommand->setNumCols(4); | 
| 1784 |     moveCommand->setStartRow(startRow); | 
| 1785 |     moveCommand->setEndRow(endRow); | 
| 1786 |     moveCommand->setDestRow(destRow); | 
| 1787 |     moveCommand->doCommand(); | 
| 1788 |  | 
| 1789 |     QCOMPARE(beforeSpy.size(), 0); | 
| 1790 |     QCOMPARE(afterSpy.size(), 0); | 
| 1791 | } | 
| 1792 |  | 
| 1793 | class ListenerObject : public QObject | 
| 1794 | { | 
| 1795 |     Q_OBJECT | 
| 1796 | public: | 
| 1797 |     ListenerObject(QAbstractProxyModel *parent); | 
| 1798 |  | 
| 1799 | protected: | 
| 1800 |     void fillIndexStores(const QModelIndex &parent); | 
| 1801 |  | 
| 1802 | public slots: | 
| 1803 |     void slotAboutToBeReset(); | 
| 1804 |     void slotReset(); | 
| 1805 |  | 
| 1806 | private: | 
| 1807 |     QAbstractProxyModel *m_model; | 
| 1808 |     QList<QPersistentModelIndex> m_persistentIndexes; | 
| 1809 |     QModelIndexList m_nonPersistentIndexes; | 
| 1810 | }; | 
| 1811 |  | 
| 1812 |  | 
| 1813 | class ModelWithCustomRole : public QStringListModel | 
| 1814 | { | 
| 1815 |   Q_OBJECT | 
| 1816 | public: | 
| 1817 |     using QStringListModel::QStringListModel; | 
| 1818 |  | 
| 1819 |     QHash<int, QByteArray> roleNames() const override | 
| 1820 |     { | 
| 1821 |         return {{Qt::UserRole + 1, QByteArrayLiteral("custom" )}}; | 
| 1822 |     } | 
| 1823 | }; | 
| 1824 |  | 
| 1825 | ListenerObject::ListenerObject(QAbstractProxyModel *parent) | 
| 1826 |     : QObject(parent), m_model(parent) | 
| 1827 | { | 
| 1828 |     connect(asender: m_model, SIGNAL(modelAboutToBeReset()), SLOT(slotAboutToBeReset())); | 
| 1829 |     connect(asender: m_model, SIGNAL(modelReset()), SLOT(slotReset())); | 
| 1830 |  | 
| 1831 |     fillIndexStores(parent: QModelIndex()); | 
| 1832 | } | 
| 1833 |  | 
| 1834 | void ListenerObject::fillIndexStores(const QModelIndex &parent) | 
| 1835 | { | 
| 1836 |     const int column = 0; | 
| 1837 |     int row = 0; | 
| 1838 |     QModelIndex idx = m_model->index(row, column, parent); | 
| 1839 |     while (idx.isValid()) { | 
| 1840 |         m_persistentIndexes << QPersistentModelIndex(idx); | 
| 1841 |         m_nonPersistentIndexes << idx; | 
| 1842 |         if (m_model->hasChildren(parent: idx)) | 
| 1843 |             fillIndexStores(parent: idx); | 
| 1844 |         ++row; | 
| 1845 |         idx = m_model->index(row, column, parent); | 
| 1846 |     } | 
| 1847 | } | 
| 1848 |  | 
| 1849 | void ListenerObject::slotAboutToBeReset() | 
| 1850 | { | 
| 1851 |     // Nothing has been changed yet. All indexes should be the same. | 
| 1852 |     for (int i = 0; i < m_persistentIndexes.size(); ++i) { | 
| 1853 |         QModelIndex idx = m_persistentIndexes.at(i); | 
| 1854 |         QCOMPARE(idx, m_nonPersistentIndexes.at(i)); | 
| 1855 |         QVERIFY(m_model->mapToSource(idx).isValid()); | 
| 1856 |     } | 
| 1857 | } | 
| 1858 |  | 
| 1859 | void ListenerObject::slotReset() | 
| 1860 | { | 
| 1861 |     for (const auto &idx : qAsConst(t&: m_persistentIndexes)) { | 
| 1862 |         QVERIFY(!idx.isValid()); | 
| 1863 |     } | 
| 1864 | } | 
| 1865 |  | 
| 1866 | void tst_QAbstractItemModel::testReset() | 
| 1867 | { | 
| 1868 |     QSignalSpy beforeResetSpy(m_model, &DynamicTreeModel::modelAboutToBeReset); | 
| 1869 |     QSignalSpy afterResetSpy(m_model, &DynamicTreeModel::modelReset); | 
| 1870 |  | 
| 1871 |     QVERIFY(beforeResetSpy.isValid()); | 
| 1872 |     QVERIFY(afterResetSpy.isValid()); | 
| 1873 |  | 
| 1874 |     QSortFilterProxyModel *nullProxy = new QSortFilterProxyModel(this); | 
| 1875 |     nullProxy->setSourceModel(m_model); | 
| 1876 |  | 
| 1877 |     // Makes sure the model and proxy are in a consistent state. before and after reset. | 
| 1878 |     ListenerObject *listener = new ListenerObject(nullProxy); | 
| 1879 |  | 
| 1880 |     ModelResetCommandFixed *resetCommand = new ModelResetCommandFixed(m_model, this); | 
| 1881 |  | 
| 1882 |     resetCommand->setNumCols(4); | 
| 1883 |     resetCommand->setStartRow(0); | 
| 1884 |     resetCommand->setEndRow(0); | 
| 1885 |     resetCommand->setDestRow(0); | 
| 1886 |     resetCommand->setDestAncestors(QList<int>() << 5); | 
| 1887 |     resetCommand->doCommand(); | 
| 1888 |  | 
| 1889 |     // Verify that the correct signals were emitted | 
| 1890 |     QCOMPARE(beforeResetSpy.size(), 1); | 
| 1891 |     QCOMPARE(afterResetSpy.size(), 1); | 
| 1892 |  | 
| 1893 |     // Verify that the move actually happened. | 
| 1894 |     QCOMPARE(m_model->rowCount(), 9); | 
| 1895 |     QModelIndex destIndex = m_model->index(row: 4, column: 0); | 
| 1896 |     QCOMPARE(m_model->rowCount(destIndex), 11); | 
| 1897 |  | 
| 1898 |     // Delete it because its slots test things which are not true after this point. | 
| 1899 |     delete listener; | 
| 1900 |  | 
| 1901 |     QSignalSpy proxyBeforeResetSpy(nullProxy, &QSortFilterProxyModel::modelAboutToBeReset); | 
| 1902 |     QSignalSpy proxyAfterResetSpy(nullProxy, &QSortFilterProxyModel::modelReset); | 
| 1903 |  | 
| 1904 |     // Before setting it, it does not have custom roles. | 
| 1905 |     QCOMPARE(nullProxy->roleNames().value(Qt::UserRole + 1), QByteArray()); | 
| 1906 |  | 
| 1907 |     nullProxy->setSourceModel(new ModelWithCustomRole(this)); | 
| 1908 |     QCOMPARE(proxyBeforeResetSpy.size(), 1); | 
| 1909 |     QCOMPARE(proxyAfterResetSpy.size(), 1); | 
| 1910 |  | 
| 1911 |     QCOMPARE(nullProxy->roleNames().value(Qt::UserRole + 1), QByteArray("custom" )); | 
| 1912 |  | 
| 1913 |     nullProxy->setSourceModel(m_model); | 
| 1914 |     QCOMPARE(proxyBeforeResetSpy.size(), 2); | 
| 1915 |     QCOMPARE(proxyAfterResetSpy.size(), 2); | 
| 1916 |  | 
| 1917 |     // After being reset the proxy must be queried again. | 
| 1918 |     QCOMPARE(nullProxy->roleNames().value(Qt::UserRole + 1), QByteArray()); | 
| 1919 | } | 
| 1920 |  | 
| 1921 | class CustomRoleModel : public QStringListModel | 
| 1922 | { | 
| 1923 |     Q_OBJECT | 
| 1924 |     Q_ENUMS(Roles) | 
| 1925 | public: | 
| 1926 |     enum Roles { | 
| 1927 |         Custom1 = Qt::UserRole + 1, | 
| 1928 |         Custom2, | 
| 1929 |         UserRole | 
| 1930 |     }; | 
| 1931 |  | 
| 1932 |     CustomRoleModel(QObject *parent = 0) | 
| 1933 |       : QStringListModel(QStringList() << "a"  << "b"  << "c" , parent) | 
| 1934 |     { | 
| 1935 |     } | 
| 1936 |  | 
| 1937 |     void emitSignals() | 
| 1938 |     { | 
| 1939 |         const QModelIndex top = index(row: 0, column: 0); | 
| 1940 |         const QModelIndex bottom = index(row: 2, column: 0); | 
| 1941 |  | 
| 1942 |         emit dataChanged(topLeft: top, bottomRight: bottom); | 
| 1943 |         emit dataChanged(topLeft: top, bottomRight: bottom, roles: QVector<int>() << Qt::ToolTipRole); | 
| 1944 |         emit dataChanged(topLeft: top, bottomRight: bottom, roles: QVector<int>() << Qt::ToolTipRole << Custom1); | 
| 1945 |     } | 
| 1946 | }; | 
| 1947 |  | 
| 1948 | void tst_QAbstractItemModel::testDataChanged() | 
| 1949 | { | 
| 1950 |     CustomRoleModel model; | 
| 1951 |  | 
| 1952 |     QSignalSpy withRoles(&model, &CustomRoleModel::dataChanged); | 
| 1953 |     QSignalSpy withoutRoles(&model, &CustomRoleModel::dataChanged); | 
| 1954 |  | 
| 1955 |     QVERIFY(withRoles.isValid()); | 
| 1956 |     QVERIFY(withoutRoles.isValid()); | 
| 1957 |  | 
| 1958 |     model.emitSignals(); | 
| 1959 |  | 
| 1960 |     QCOMPARE(withRoles.size(), withoutRoles.size()); | 
| 1961 |     QCOMPARE(withRoles.size(), 3); | 
| 1962 |  | 
| 1963 |     const QVariantList secondEmission = withRoles.at(i: 1); | 
| 1964 |     const QVariantList thirdEmission = withRoles.at(i: 2); | 
| 1965 |  | 
| 1966 |     const QVector<int> secondRoles = secondEmission.at(i: 2).value<QVector<int> >(); | 
| 1967 |     const QVector<int> thirdRoles = thirdEmission.at(i: 2).value<QVector<int> >(); | 
| 1968 |  | 
| 1969 |     QCOMPARE(secondRoles.size(), 1); | 
| 1970 |     QVERIFY(secondRoles.contains(Qt::ToolTipRole)); | 
| 1971 |  | 
| 1972 |     QCOMPARE(thirdRoles.size(), 2); | 
| 1973 |     QVERIFY(thirdRoles.contains(Qt::ToolTipRole)); | 
| 1974 |     QVERIFY(thirdRoles.contains(CustomRoleModel::Custom1)); | 
| 1975 | } | 
| 1976 |  | 
| 1977 | Q_DECLARE_METATYPE(QList<QPersistentModelIndex>) | 
| 1978 |  | 
| 1979 | class SignalArgumentChecker : public QObject | 
| 1980 | { | 
| 1981 |     Q_OBJECT | 
| 1982 | public: | 
| 1983 |     SignalArgumentChecker(const QModelIndex &p1, const QModelIndex &p2, QObject *parent = 0) | 
| 1984 |       : QObject(parent), m_p1(p1), m_p2(p2), m_p1Persistent(p1), m_p2Persistent(p2) | 
| 1985 |     { | 
| 1986 |       connect(asender: p1.model(), SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>)), SLOT(layoutAboutToBeChanged(QList<QPersistentModelIndex>))); | 
| 1987 |       connect(asender: p1.model(), SIGNAL(layoutChanged(QList<QPersistentModelIndex>)), SLOT(layoutChanged(QList<QPersistentModelIndex>))); | 
| 1988 |     } | 
| 1989 |  | 
| 1990 | private slots: | 
| 1991 |     void layoutAboutToBeChanged(const QList<QPersistentModelIndex> &parents) | 
| 1992 |     { | 
| 1993 |         QCOMPARE(parents.size(), 2); | 
| 1994 |         QVERIFY(parents.first() != parents.at(1)); | 
| 1995 |         QVERIFY(parents.contains(m_p1)); | 
| 1996 |         QVERIFY(parents.contains(m_p2)); | 
| 1997 |     } | 
| 1998 |  | 
| 1999 |     void layoutChanged(const QList<QPersistentModelIndex> &parents) | 
| 2000 |     { | 
| 2001 |         QCOMPARE(parents.size(), 2); | 
| 2002 |         QVERIFY(parents.first() != parents.at(1)); | 
| 2003 |         QVERIFY(parents.contains(m_p1Persistent)); | 
| 2004 |         QVERIFY(parents.contains(m_p2Persistent)); | 
| 2005 |         QVERIFY(!parents.contains(m_p2)); // Has changed | 
| 2006 |     } | 
| 2007 |  | 
| 2008 | private: | 
| 2009 |     QModelIndex m_p1; | 
| 2010 |     QModelIndex m_p2; | 
| 2011 |     QPersistentModelIndex m_p1Persistent; | 
| 2012 |     QPersistentModelIndex m_p2Persistent; | 
| 2013 | }; | 
| 2014 |  | 
| 2015 | void tst_QAbstractItemModel::testChildrenLayoutsChanged() | 
| 2016 | { | 
| 2017 |     DynamicTreeModel model; | 
| 2018 |  | 
| 2019 |     ModelInsertCommand *insertCommand = new ModelInsertCommand(&model, this); | 
| 2020 |     insertCommand->setStartRow(0); | 
| 2021 |     insertCommand->setEndRow(9); | 
| 2022 |     insertCommand->doCommand(); | 
| 2023 |  | 
| 2024 |     insertCommand = new ModelInsertCommand(&model, this); | 
| 2025 |     insertCommand->setAncestorRowNumbers(QList<int>() << 2); | 
| 2026 |     insertCommand->setStartRow(0); | 
| 2027 |     insertCommand->setEndRow(9); | 
| 2028 |     insertCommand->doCommand(); | 
| 2029 |  | 
| 2030 |     insertCommand = new ModelInsertCommand(&model, this); | 
| 2031 |     insertCommand->setAncestorRowNumbers(QList<int>() << 5); | 
| 2032 |     insertCommand->setStartRow(0); | 
| 2033 |     insertCommand->setEndRow(9); | 
| 2034 |     insertCommand->doCommand(); | 
| 2035 |  | 
| 2036 |     qRegisterMetaType<QList<QPersistentModelIndex> >(); | 
| 2037 |  | 
| 2038 |     { | 
| 2039 |         const QModelIndex p1 = model.index(row: 2, column: 0); | 
| 2040 |         const QModelIndex p2 = model.index(row: 5, column: 0); | 
| 2041 |  | 
| 2042 |         const QPersistentModelIndex p1FirstPersistent = model.index(row: 0, column: 0, parent: p1); | 
| 2043 |         const QPersistentModelIndex p1LastPersistent = model.index(row: 9, column: 0, parent: p1); | 
| 2044 |         const QPersistentModelIndex p2FirstPersistent = model.index(row: 0, column: 0, parent: p2); | 
| 2045 |         const QPersistentModelIndex p2LastPersistent = model.index(row: 9, column: 0, parent: p2); | 
| 2046 |  | 
| 2047 |         QVERIFY(p1.isValid()); | 
| 2048 |         QVERIFY(p2.isValid()); | 
| 2049 |  | 
| 2050 |         QCOMPARE(model.rowCount(), 10); | 
| 2051 |         QCOMPARE(model.rowCount(p1), 10); | 
| 2052 |         QCOMPARE(model.rowCount(p2), 10); | 
| 2053 |  | 
| 2054 |         QSignalSpy beforeSpy(&model, &DynamicTreeModel::layoutAboutToBeChanged); | 
| 2055 |         QSignalSpy afterSpy(&model, &DynamicTreeModel::layoutChanged); | 
| 2056 |  | 
| 2057 |         QVERIFY(beforeSpy.isValid()); | 
| 2058 |         QVERIFY(afterSpy.isValid()); | 
| 2059 |  | 
| 2060 |         ModelChangeChildrenLayoutsCommand *changeCommand = new ModelChangeChildrenLayoutsCommand(&model, this); | 
| 2061 |         changeCommand->setAncestorRowNumbers(QList<int>() << 2); | 
| 2062 |         changeCommand->setSecondAncestorRowNumbers(QList<int>() << 5); | 
| 2063 |         changeCommand->doCommand(); | 
| 2064 |  | 
| 2065 |         QCOMPARE(beforeSpy.size(), 1); | 
| 2066 |         QCOMPARE(afterSpy.size(), 1); | 
| 2067 |  | 
| 2068 |         const QVariantList beforeSignal = beforeSpy.first(); | 
| 2069 |         const QVariantList afterSignal = afterSpy.first(); | 
| 2070 |         QCOMPARE(beforeSignal.size(), 2); | 
| 2071 |         QCOMPARE(afterSignal.size(), 2); | 
| 2072 |  | 
| 2073 |         const QList<QPersistentModelIndex> beforeParents = beforeSignal.first().value<QList<QPersistentModelIndex> >(); | 
| 2074 |         QCOMPARE(beforeParents.size(), 2); | 
| 2075 |         QVERIFY(beforeParents.first() != beforeParents.at(1)); | 
| 2076 |         QVERIFY(beforeParents.contains(p1)); | 
| 2077 |         QVERIFY(beforeParents.contains(p2)); | 
| 2078 |  | 
| 2079 |         const QList<QPersistentModelIndex> afterParents = afterSignal.first().value<QList<QPersistentModelIndex> >(); | 
| 2080 |         QCOMPARE(afterParents.size(), 2); | 
| 2081 |         QVERIFY(afterParents.first() != afterParents.at(1)); | 
| 2082 |         QVERIFY(afterParents.contains(p1)); | 
| 2083 |         QVERIFY(afterParents.contains(p2)); | 
| 2084 |  | 
| 2085 |         // The first will be the last, and the lest will be the first. | 
| 2086 |         QCOMPARE(p1FirstPersistent.row(), 1); | 
| 2087 |         QCOMPARE(p1LastPersistent.row(), 0); | 
| 2088 |         QCOMPARE(p2FirstPersistent.row(), 9); | 
| 2089 |         QCOMPARE(p2LastPersistent.row(), 8); | 
| 2090 |     } | 
| 2091 |  | 
| 2092 |     insertCommand = new ModelInsertCommand(&model, this); | 
| 2093 |     insertCommand->setAncestorRowNumbers(QList<int>() << 5 << 4); | 
| 2094 |     insertCommand->setStartRow(0); | 
| 2095 |     insertCommand->setEndRow(9); | 
| 2096 |     insertCommand->doCommand(); | 
| 2097 |  | 
| 2098 |     delete insertCommand; | 
| 2099 |  | 
| 2100 |     // Even when p2 itself is moved around, signal emission remains correct for its children. | 
| 2101 |     { | 
| 2102 |         const QModelIndex p1 = model.index(row: 5, column: 0); | 
| 2103 |         const QModelIndex p2 = model.index(row: 4, column: 0, parent: p1); | 
| 2104 |  | 
| 2105 |         QVERIFY(p1.isValid()); | 
| 2106 |         QVERIFY(p2.isValid()); | 
| 2107 |  | 
| 2108 |         QCOMPARE(model.rowCount(), 10); | 
| 2109 |         QCOMPARE(model.rowCount(p1), 10); | 
| 2110 |         QCOMPARE(model.rowCount(p2), 10); | 
| 2111 |  | 
| 2112 |         const QPersistentModelIndex p1Persistent = p1; | 
| 2113 |         const QPersistentModelIndex p2Persistent = p2; | 
| 2114 |  | 
| 2115 |         const QPersistentModelIndex p1FirstPersistent = model.index(row: 0, column: 0, parent: p1); | 
| 2116 |         const QPersistentModelIndex p1LastPersistent = model.index(row: 9, column: 0, parent: p1); | 
| 2117 |         const QPersistentModelIndex p2FirstPersistent = model.index(row: 0, column: 0, parent: p2); | 
| 2118 |         const QPersistentModelIndex p2LastPersistent = model.index(row: 9, column: 0, parent: p2); | 
| 2119 |  | 
| 2120 |         QSignalSpy beforeSpy(&model, &DynamicTreeModel::layoutAboutToBeChanged); | 
| 2121 |         QSignalSpy afterSpy(&model, &DynamicTreeModel::layoutChanged); | 
| 2122 |  | 
| 2123 |         QVERIFY(beforeSpy.isValid()); | 
| 2124 |         QVERIFY(afterSpy.isValid()); | 
| 2125 |  | 
| 2126 |         // Because the arguments in the signal are persistent, we need to check them for the aboutToBe | 
| 2127 |         // case at emission time - before they get updated. | 
| 2128 |         SignalArgumentChecker checker(p1, p2); | 
| 2129 |  | 
| 2130 |         ModelChangeChildrenLayoutsCommand *changeCommand = new ModelChangeChildrenLayoutsCommand(&model, this); | 
| 2131 |         changeCommand->setAncestorRowNumbers(QList<int>() << 5); | 
| 2132 |         changeCommand->setSecondAncestorRowNumbers(QList<int>() << 5 << 4); | 
| 2133 |         changeCommand->doCommand(); | 
| 2134 |  | 
| 2135 |         // p2 has been moved. | 
| 2136 |         QCOMPARE(p2Persistent.row(), p2.row() + 1); | 
| 2137 |  | 
| 2138 |         QCOMPARE(beforeSpy.size(), 1); | 
| 2139 |         QCOMPARE(afterSpy.size(), 1); | 
| 2140 |  | 
| 2141 |         const QVariantList beforeSignal = beforeSpy.first(); | 
| 2142 |         const QVariantList afterSignal = afterSpy.first(); | 
| 2143 |         QCOMPARE(beforeSignal.size(), 2); | 
| 2144 |         QCOMPARE(afterSignal.size(), 2); | 
| 2145 |  | 
| 2146 |         QCOMPARE(p1FirstPersistent.row(), 1); | 
| 2147 |         QCOMPARE(p1LastPersistent.row(), 0); | 
| 2148 |         QCOMPARE(p2FirstPersistent.row(), 9); | 
| 2149 |         QCOMPARE(p2LastPersistent.row(), 8); | 
| 2150 |     } | 
| 2151 | } | 
| 2152 |  | 
| 2153 | class OverrideRoleNamesAndDragActions : public QStringListModel | 
| 2154 | { | 
| 2155 |     Q_OBJECT | 
| 2156 | public: | 
| 2157 |     OverrideRoleNamesAndDragActions(QObject *parent = 0) | 
| 2158 |       : QStringListModel(parent) | 
| 2159 |     { | 
| 2160 |  | 
| 2161 |     } | 
| 2162 |  | 
| 2163 |     QHash<int, QByteArray> roleNames() const | 
| 2164 |     { | 
| 2165 |         QHash<int, QByteArray> roles = QStringListModel::roleNames(); | 
| 2166 |         roles.insert(akey: Qt::UserRole + 2, avalue: "custom" ); | 
| 2167 |         return roles; | 
| 2168 |     } | 
| 2169 |  | 
| 2170 |     Qt::DropActions supportedDragActions() const | 
| 2171 |     { | 
| 2172 |         return QStringListModel::supportedDragActions() | Qt::MoveAction; | 
| 2173 |     } | 
| 2174 | }; | 
| 2175 |  | 
| 2176 | void tst_QAbstractItemModel::testRoleNames() | 
| 2177 | { | 
| 2178 |     QAbstractItemModel *model = new OverrideRoleNamesAndDragActions(this); | 
| 2179 |     QHash<int, QByteArray> roles = model->roleNames(); | 
| 2180 |     QVERIFY(roles.contains(Qt::UserRole + 2)); | 
| 2181 |     QVERIFY(roles.value(Qt::UserRole + 2) == "custom" ); | 
| 2182 | } | 
| 2183 |  | 
| 2184 | void tst_QAbstractItemModel::testDragActions() | 
| 2185 | { | 
| 2186 |     QAbstractItemModel *model = new OverrideRoleNamesAndDragActions(this); | 
| 2187 |     const Qt::DropActions actions = model->supportedDragActions(); | 
| 2188 |     QVERIFY(actions & Qt::CopyAction); // Present by default | 
| 2189 |     QVERIFY(actions & Qt::MoveAction); | 
| 2190 | } | 
| 2191 |  | 
| 2192 | class OverrideDropActions : public QStringListModel | 
| 2193 | { | 
| 2194 |     Q_OBJECT | 
| 2195 | public: | 
| 2196 |     OverrideDropActions(QObject *parent = 0) | 
| 2197 |       : QStringListModel(parent) | 
| 2198 |     { | 
| 2199 |     } | 
| 2200 |     Qt::DropActions supportedDropActions() const override | 
| 2201 |     { | 
| 2202 |         return Qt::MoveAction; | 
| 2203 |     } | 
| 2204 | }; | 
| 2205 |  | 
| 2206 | void tst_QAbstractItemModel::dragActionsFallsBackToDropActions() | 
| 2207 | { | 
| 2208 |     QAbstractItemModel *model = new OverrideDropActions(this); | 
| 2209 |     QCOMPARE(model->supportedDragActions(), Qt::MoveAction); | 
| 2210 |     QCOMPARE(model->supportedDropActions(), Qt::MoveAction); | 
| 2211 | } | 
| 2212 |  | 
| 2213 | class SignalConnectionTester : public QObject | 
| 2214 | { | 
| 2215 |     Q_OBJECT | 
| 2216 | public: | 
| 2217 |     SignalConnectionTester(QObject *parent = 0) | 
| 2218 |       : QObject(parent), testPassed(false) | 
| 2219 |     { | 
| 2220 |  | 
| 2221 |     } | 
| 2222 |  | 
| 2223 | public Q_SLOTS: | 
| 2224 |     void testSlot() | 
| 2225 |     { | 
| 2226 |       testPassed = true; | 
| 2227 |     } | 
| 2228 |     void testSlotWithParam_1(const QModelIndex &idx) | 
| 2229 |     { | 
| 2230 |       testPassed = !idx.isValid(); | 
| 2231 |     } | 
| 2232 |     void testSlotWithParam_2(const QModelIndex &idx, int start) | 
| 2233 |     { | 
| 2234 |       testPassed = !idx.isValid() && start == 0; | 
| 2235 |     } | 
| 2236 |     void testSlotWithParam_3(const QModelIndex &idx, int start, int end) | 
| 2237 |     { | 
| 2238 |       testPassed = !idx.isValid() && start == 0 && end == 1; | 
| 2239 |     } | 
| 2240 |  | 
| 2241 | public: | 
| 2242 |     bool testPassed; | 
| 2243 | }; | 
| 2244 |  | 
| 2245 | void tst_QAbstractItemModel::testFunctionPointerSignalConnection() | 
| 2246 | { | 
| 2247 |     QStringListModel model; | 
| 2248 |     { | 
| 2249 |         SignalConnectionTester tester; | 
| 2250 |         QObject::connect(sender: &model, signal: &QAbstractItemModel::rowsInserted, receiver: &tester, slot: &SignalConnectionTester::testSlot); | 
| 2251 |  | 
| 2252 |         QVERIFY(!tester.testPassed); | 
| 2253 |  | 
| 2254 |         model.insertRows(row: 0, count: 2); | 
| 2255 |  | 
| 2256 |         QVERIFY(tester.testPassed); | 
| 2257 |         tester.testPassed = false; | 
| 2258 |         QMetaObject::invokeMethod(obj: &model, member: "rowsInserted" , Q_ARG(QModelIndex, QModelIndex()), Q_ARG(int, 0), Q_ARG(int, 1)); | 
| 2259 |         QVERIFY(tester.testPassed); | 
| 2260 |     } | 
| 2261 |     { | 
| 2262 |         SignalConnectionTester tester; | 
| 2263 |         QObject::connect(sender: &model, signal: &QAbstractItemModel::rowsInserted, receiver: &tester, slot: &SignalConnectionTester::testSlotWithParam_1); | 
| 2264 |  | 
| 2265 |         QVERIFY(!tester.testPassed); | 
| 2266 |  | 
| 2267 |         model.insertRows(row: 0, count: 2); | 
| 2268 |  | 
| 2269 |         QVERIFY(tester.testPassed); | 
| 2270 |         tester.testPassed = false; | 
| 2271 |         QMetaObject::invokeMethod(obj: &model, member: "rowsInserted" , Q_ARG(QModelIndex, QModelIndex()), Q_ARG(int, 0), Q_ARG(int, 1)); | 
| 2272 |         QVERIFY(tester.testPassed); | 
| 2273 |     } | 
| 2274 |     { | 
| 2275 |         SignalConnectionTester tester; | 
| 2276 |         QObject::connect(sender: &model, signal: &QAbstractItemModel::rowsInserted, receiver: &tester, slot: &SignalConnectionTester::testSlotWithParam_2); | 
| 2277 |  | 
| 2278 |         QVERIFY(!tester.testPassed); | 
| 2279 |  | 
| 2280 |         model.insertRows(row: 0, count: 2); | 
| 2281 |  | 
| 2282 |         QVERIFY(tester.testPassed); | 
| 2283 |         tester.testPassed = false; | 
| 2284 |         QMetaObject::invokeMethod(obj: &model, member: "rowsInserted" , Q_ARG(QModelIndex, QModelIndex()), Q_ARG(int, 0), Q_ARG(int, 1)); | 
| 2285 |         QVERIFY(tester.testPassed); | 
| 2286 |     } | 
| 2287 |     { | 
| 2288 |         SignalConnectionTester tester; | 
| 2289 |         QObject::connect(sender: &model, signal: &QAbstractItemModel::rowsInserted, receiver: &tester, slot: &SignalConnectionTester::testSlotWithParam_3); | 
| 2290 |  | 
| 2291 |         QVERIFY(!tester.testPassed); | 
| 2292 |  | 
| 2293 |         model.insertRows(row: 0, count: 2); | 
| 2294 |  | 
| 2295 |         QVERIFY(tester.testPassed); | 
| 2296 |         tester.testPassed = false; | 
| 2297 |         QMetaObject::invokeMethod(obj: &model, member: "rowsInserted" , Q_ARG(QModelIndex, QModelIndex()), Q_ARG(int, 0), Q_ARG(int, 1)); | 
| 2298 |         QVERIFY(tester.testPassed); | 
| 2299 |     } | 
| 2300 |     { | 
| 2301 |         SignalConnectionTester tester; | 
| 2302 |         QObject::connect(sender: &model, SIGNAL(rowsInserted(QModelIndex,int,int)), receiver: &tester, SLOT(testSlot())); | 
| 2303 |  | 
| 2304 |         QVERIFY(!tester.testPassed); | 
| 2305 |  | 
| 2306 |         model.insertRows(row: 0, count: 2); | 
| 2307 |  | 
| 2308 |         QVERIFY(tester.testPassed); | 
| 2309 |         tester.testPassed = false; | 
| 2310 |         QMetaObject::invokeMethod(obj: &model, member: "rowsInserted" , Q_ARG(QModelIndex, QModelIndex()), Q_ARG(int, 0), Q_ARG(int, 1)); | 
| 2311 |         QVERIFY(tester.testPassed); | 
| 2312 |     } | 
| 2313 |     // Intentionally does not compile. | 
| 2314 | //     model.rowsInserted(QModelIndex(), 0, 0); | 
| 2315 | } | 
| 2316 |  | 
| 2317 | void tst_QAbstractItemModel::checkIndex() | 
| 2318 | { | 
| 2319 |     const QRegularExpression ignorePattern("^Index QModelIndex" ); | 
| 2320 |  | 
| 2321 |     // checkIndex is QAbstractItemModel API; using QStandardItem as an easy | 
| 2322 |     // way to build a tree model | 
| 2323 |     QStandardItemModel model; | 
| 2324 |     QStandardItem *topLevel = new QStandardItem("topLevel" ); | 
| 2325 |     model.appendRow(aitem: topLevel); | 
| 2326 |  | 
| 2327 |     topLevel->appendRow(aitem: new QStandardItem("child1" )); | 
| 2328 |     topLevel->appendRow(aitem: new QStandardItem("child2" )); | 
| 2329 |  | 
| 2330 |     QVERIFY(model.checkIndex(QModelIndex())); | 
| 2331 |     QVERIFY(model.checkIndex(QModelIndex(), QAbstractItemModel::CheckIndexOption::DoNotUseParent)); | 
| 2332 |     QVERIFY(model.checkIndex(QModelIndex(), QAbstractItemModel::CheckIndexOption::ParentIsInvalid)); | 
| 2333 |     QTest::ignoreMessage(type: QtWarningMsg, messagePattern: ignorePattern); | 
| 2334 |     QVERIFY(!model.checkIndex(QModelIndex(), QAbstractItemModel::CheckIndexOption::IndexIsValid)); | 
| 2335 |  | 
| 2336 |     QModelIndex topLevelIndex = model.index(row: 0, column: 0); | 
| 2337 |     QVERIFY(topLevelIndex.isValid()); | 
| 2338 |     QVERIFY(model.checkIndex(topLevelIndex)); | 
| 2339 |     QVERIFY(model.checkIndex(topLevelIndex, QAbstractItemModel::CheckIndexOption::DoNotUseParent)); | 
| 2340 |     QVERIFY(model.checkIndex(topLevelIndex, QAbstractItemModel::CheckIndexOption::ParentIsInvalid)); | 
| 2341 |     QVERIFY(model.checkIndex(topLevelIndex, QAbstractItemModel::CheckIndexOption::IndexIsValid)); | 
| 2342 |  | 
| 2343 |     QModelIndex childIndex = model.index(row: 0, column: 0, parent: topLevelIndex); | 
| 2344 |     QVERIFY(childIndex.isValid()); | 
| 2345 |     QVERIFY(model.checkIndex(childIndex)); | 
| 2346 |     QVERIFY(model.checkIndex(childIndex, QAbstractItemModel::CheckIndexOption::DoNotUseParent)); | 
| 2347 |     QTest::ignoreMessage(type: QtWarningMsg, messagePattern: ignorePattern); | 
| 2348 |     QVERIFY(!model.checkIndex(childIndex, QAbstractItemModel::CheckIndexOption::ParentIsInvalid)); | 
| 2349 |     QVERIFY(model.checkIndex(childIndex, QAbstractItemModel::CheckIndexOption::IndexIsValid)); | 
| 2350 |  | 
| 2351 |     childIndex = model.index(row: 1, column: 0, parent: topLevelIndex); | 
| 2352 |     QVERIFY(childIndex.isValid()); | 
| 2353 |     QVERIFY(model.checkIndex(childIndex)); | 
| 2354 |     QVERIFY(model.checkIndex(childIndex, QAbstractItemModel::CheckIndexOption::DoNotUseParent)); | 
| 2355 |     QTest::ignoreMessage(type: QtWarningMsg, messagePattern: ignorePattern); | 
| 2356 |     QVERIFY(!model.checkIndex(childIndex, QAbstractItemModel::CheckIndexOption::ParentIsInvalid)); | 
| 2357 |     QVERIFY(model.checkIndex(childIndex, QAbstractItemModel::CheckIndexOption::IndexIsValid)); | 
| 2358 |  | 
| 2359 |     topLevel->removeRow(row: 1); | 
| 2360 |     QTest::ignoreMessage(type: QtWarningMsg, messagePattern: ignorePattern); | 
| 2361 |     QVERIFY(!model.checkIndex(childIndex)); | 
| 2362 |     QVERIFY(model.checkIndex(childIndex, QAbstractItemModel::CheckIndexOption::DoNotUseParent)); | 
| 2363 |     QTest::ignoreMessage(type: QtWarningMsg, messagePattern: ignorePattern); | 
| 2364 |     QVERIFY(!model.checkIndex(childIndex, QAbstractItemModel::CheckIndexOption::ParentIsInvalid)); | 
| 2365 |     QTest::ignoreMessage(type: QtWarningMsg, messagePattern: ignorePattern); | 
| 2366 |     QVERIFY(!model.checkIndex(childIndex, QAbstractItemModel::CheckIndexOption::IndexIsValid)); | 
| 2367 |  | 
| 2368 |     QStandardItemModel model2; | 
| 2369 |     model2.appendRow(aitem: new QStandardItem("otherTopLevel" )); | 
| 2370 |     topLevelIndex = model2.index(row: 0, column: 0); | 
| 2371 |     QVERIFY(topLevelIndex.isValid()); | 
| 2372 |     QVERIFY(model2.checkIndex(topLevelIndex)); | 
| 2373 |     QVERIFY(model2.checkIndex(topLevelIndex, QAbstractItemModel::CheckIndexOption::DoNotUseParent)); | 
| 2374 |     QVERIFY(model2.checkIndex(topLevelIndex, QAbstractItemModel::CheckIndexOption::ParentIsInvalid)); | 
| 2375 |     QVERIFY(model2.checkIndex(topLevelIndex, QAbstractItemModel::CheckIndexOption::IndexIsValid)); | 
| 2376 |  | 
| 2377 |     QTest::ignoreMessage(type: QtWarningMsg, messagePattern: ignorePattern); | 
| 2378 |     QVERIFY(!model.checkIndex(topLevelIndex)); | 
| 2379 |     QTest::ignoreMessage(type: QtWarningMsg, messagePattern: ignorePattern); | 
| 2380 |     QVERIFY(!model.checkIndex(topLevelIndex, QAbstractItemModel::CheckIndexOption::DoNotUseParent)); | 
| 2381 |     QTest::ignoreMessage(type: QtWarningMsg, messagePattern: ignorePattern); | 
| 2382 |     QVERIFY(!model.checkIndex(topLevelIndex, QAbstractItemModel::CheckIndexOption::ParentIsInvalid)); | 
| 2383 |     QTest::ignoreMessage(type: QtWarningMsg, messagePattern: ignorePattern); | 
| 2384 |     QVERIFY(!model.checkIndex(topLevelIndex, QAbstractItemModel::CheckIndexOption::IndexIsValid)); | 
| 2385 | } | 
| 2386 |  | 
| 2387 | QTEST_MAIN(tst_QAbstractItemModel) | 
| 2388 | #include "tst_qabstractitemmodel.moc" | 
| 2389 |  |