File indexing completed on 2024-05-12 16:45:18

0001 /***************************************************************************
0002  * SPDX-FileCopyrightText: 2022 S. MANKOWSKI stephane@mankowski.fr
0003  * SPDX-FileCopyrightText: 2022 G. DE BURE support@mankowski.fr
0004  * SPDX-License-Identifier: GPL-3.0-or-later
0005  ***************************************************************************/
0006 
0007 /****************************************************************************
0008 **
0009 ** Copy right ( C ) 2012 Digia Plc and/or its subsidiary(-ies).
0010 ** Contact: http://www.qt-project.org/legal
0011 **
0012 ** This file is part of the test suite of the Qt Toolkit.
0013 **
0014 ** $QT_BEGIN_LICENSE:LGPL$
0015 ** Commercial License Usage
0016 ** Licensees holding valid commercial Qt licenses may use this file in
0017 ** accordance with the commercial license agreement provided with the
0018 ** Software or, alternatively, in accordance with the terms contained in
0019 ** a written agreement between you and Digia.  For licensing terms and
0020 ** conditions see http://qt.digia.com/licensing.  For further information
0021 ** use the contact form at http://qt.digia.com/contact-us.
0022 **
0023 ** GNU Lesser General Public License Usage
0024 ** Alternatively, this file may be used under the terms of the GNU Lesser
0025 ** General Public License version 2.1 as published by the Free Software
0026 ** Foundation and appearing in the file LICENSE.LGPL included in the
0027 ** packaging of this file.  Please review the following information to
0028 ** ensure the GNU Lesser General Public License version 2.1 requirements
0029 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
0030 **
0031 ** In addition, as a special exception, Digia gives you certain additional
0032 ** rights.  These rights are described in the Digia Qt LGPL Exception
0033 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
0034 **
0035 ** GNU General Public License Usage
0036 ** Alternatively, this file may be used under the terms of the GNU
0037 ** General Public License version 3.0 as published by the Free Software
0038 ** Foundation and appearing in the file LICENSE.GPL included in the
0039 ** packaging of this file.  Please review the following information to
0040 ** ensure the GNU General Public License version 3.0 requirements will be
0041 ** met: http://www.gnu.org/copyleft/gpl.html.
0042 **
0043 **
0044 ** $QT_END_LICENSE$
0045 **
0046 ****************************************************************************/
0047 #include "modeltest.h"
0048 
0049 #include <QtTest>
0050 
0051 #undef Q_ASSERT
0052 #define Q_ASSERT  QVERIFY
0053 
0054 Q_DECLARE_METATYPE(QModelIndex)
0055 
0056 /*!
0057     Connect to all of the models signals.  Whenever anything happens recheck everything.
0058 */
0059 ModelTest::ModelTest(QAbstractItemModel* model, QObject* iParent) : QObject(iParent), model(model), fetchingMore(false)
0060 {
0061     Q_ASSERT(model);
0062 
0063     connect(model, &QAbstractItemModel::columnsAboutToBeInserted, this, &ModelTest::runAllTests);
0064     connect(model, &QAbstractItemModel::columnsAboutToBeRemoved, this, &ModelTest::runAllTests);
0065     connect(model, &QAbstractItemModel::columnsInserted, this, &ModelTest::runAllTests);
0066     connect(model, &QAbstractItemModel::columnsRemoved, this, &ModelTest::runAllTests);
0067     connect(model, &QAbstractItemModel::dataChanged, this, &ModelTest::runAllTests);
0068     connect(model, &QAbstractItemModel::headerDataChanged, this, &ModelTest::runAllTests);
0069     connect(model, &QAbstractItemModel::layoutAboutToBeChanged, this, &ModelTest::runAllTests);
0070     connect(model, &QAbstractItemModel::layoutChanged, this, &ModelTest::runAllTests);
0071     connect(model, &QAbstractItemModel::modelReset, this, &ModelTest::runAllTests);
0072     connect(model, &QAbstractItemModel::rowsAboutToBeInserted, this, &ModelTest::runAllTests);
0073     connect(model, &QAbstractItemModel::rowsAboutToBeRemoved, this, &ModelTest::runAllTests);
0074     connect(model, &QAbstractItemModel::rowsInserted, this, &ModelTest::runAllTests);
0075     connect(model, &QAbstractItemModel::rowsRemoved, this, &ModelTest::runAllTests);
0076 
0077     // Special checks for inserting/removing
0078     connect(model, &QAbstractItemModel::layoutAboutToBeChanged, this, &ModelTest::layoutAboutToBeChanged);
0079     connect(model, &QAbstractItemModel::layoutChanged, this, &ModelTest::layoutChanged);
0080 
0081     connect(model, &QAbstractItemModel::rowsAboutToBeInserted, this, &ModelTest::rowsAboutToBeInserted);
0082     connect(model, &QAbstractItemModel::rowsAboutToBeRemoved, this, &ModelTest::rowsAboutToBeRemoved);
0083     connect(model, &QAbstractItemModel::rowsInserted, this, &ModelTest::rowsInserted);
0084     connect(model, &QAbstractItemModel::rowsRemoved, this, &ModelTest::rowsRemoved);
0085 
0086     runAllTests();
0087 }
0088 
0089 void ModelTest::runAllTests()
0090 {
0091     if (fetchingMore) {
0092         return;
0093     }
0094     nonDestructiveBasicTest();
0095     rowCount();
0096     columnCount();
0097     hasIndex();
0098     index();
0099     parent();
0100     data();
0101 }
0102 
0103 /*!
0104     nonDestructiveBasicTest tries to call a number of the basic functions (not all)
0105     to make sure the model doesn't outright segfault, testing the functions that makes sense.
0106 */
0107 void ModelTest::nonDestructiveBasicTest()
0108 {
0109     Q_ASSERT(model->buddy(QModelIndex()) == QModelIndex());
0110     model->canFetchMore(QModelIndex());
0111     Q_ASSERT(model->columnCount(QModelIndex()) >= 0);
0112     Q_ASSERT(model->data(QModelIndex()) == QVariant());
0113     fetchingMore = true;
0114     model->fetchMore(QModelIndex());
0115     fetchingMore = false;
0116     Qt::ItemFlags flags = model->flags(QModelIndex());
0117     Q_ASSERT(flags == Qt::ItemIsDropEnabled || flags == 0);
0118     model->hasChildren(QModelIndex());
0119     model->hasIndex(0, 0);
0120     model->headerData(0, Qt::Horizontal);
0121     model->index(0, 0);
0122     model->itemData(QModelIndex());
0123     QVariant cache;
0124     model->match(QModelIndex(), -1, cache);
0125     model->mimeTypes();
0126     Q_ASSERT(model->parent(QModelIndex()) == QModelIndex());
0127     Q_ASSERT(model->rowCount() >= 0);
0128     QVariant variant;
0129     model->setData(QModelIndex(), variant, -1);
0130     model->setHeaderData(-1, Qt::Horizontal, QVariant());
0131     model->setHeaderData(999999, Qt::Horizontal, QVariant());
0132     model->sibling(0, 0, QModelIndex());
0133     model->span(QModelIndex());
0134     model->supportedDropActions();
0135 }
0136 
0137 /*!
0138     Tests model's implementation of QAbstractItemModel::rowCount() and hasChildren()
0139 
0140     Models that are dynamically populated are not as fully tested here.
0141  */
0142 void ModelTest::rowCount()
0143 {
0144 //     qDebug() << "rc";
0145     // check top row
0146     QModelIndex topIndex = model->index(0, 0, QModelIndex());
0147     int rows = model->rowCount(topIndex);
0148     Q_ASSERT(rows >= 0);
0149     if (rows > 0) {
0150         Q_ASSERT(model->hasChildren(topIndex) == true);
0151     }
0152 
0153     QModelIndex secondLevelIndex = model->index(0, 0, topIndex);
0154     if (secondLevelIndex.isValid()) {   // not the top level
0155         // check a row count where parent is valid
0156         rows = model->rowCount(secondLevelIndex);
0157         Q_ASSERT(rows >= 0);
0158         if (rows > 0) {
0159             Q_ASSERT(model->hasChildren(secondLevelIndex) == true);
0160         }
0161     }
0162 
0163     // The models rowCount() is tested more extensively in checkChildren(),
0164     // but this catches the big mistakes
0165 }
0166 
0167 /*!
0168     Tests model's implementation of QAbstractItemModel::columnCount() and hasChildren()
0169  */
0170 void ModelTest::columnCount()
0171 {
0172     // check top row
0173     QModelIndex topIndex = model->index(0, 0, QModelIndex());
0174     Q_ASSERT(model->columnCount(topIndex) >= 0);
0175 
0176     // check a column count where parent is valid
0177     QModelIndex childIndex = model->index(0, 0, topIndex);
0178     if (childIndex.isValid()) {
0179         Q_ASSERT(model->columnCount(childIndex) >= 0);
0180     }
0181 
0182     // columnCount() is tested more extensively in checkChildren(),
0183     // but this catches the big mistakes
0184 }
0185 
0186 /*!
0187     Tests model's implementation of QAbstractItemModel::hasIndex()
0188  */
0189 void ModelTest::hasIndex()
0190 {
0191 //     qDebug() << "hi";
0192     // Make sure that invalid values returns an invalid index
0193     Q_ASSERT(model->hasIndex(-2, -2) == false);
0194     Q_ASSERT(model->hasIndex(-2, 0) == false);
0195     Q_ASSERT(model->hasIndex(0, -2) == false);
0196 
0197     int rows = model->rowCount();
0198     int columns = model->columnCount();
0199 
0200     // check out of bounds
0201     Q_ASSERT(model->hasIndex(rows, columns) == false);
0202     Q_ASSERT(model->hasIndex(rows + 1, columns + 1) == false);
0203 
0204     if (rows > 0) {
0205         Q_ASSERT(model->hasIndex(0, 0) == true);
0206     }
0207 
0208     // hasIndex() is tested more extensively in checkChildren(),
0209     // but this catches the big mistakes
0210 }
0211 
0212 /*!
0213     Tests model's implementation of QAbstractItemModel::index()
0214  */
0215 void ModelTest::index()
0216 {
0217 //     qDebug() << "i";
0218     // Make sure that invalid values returns an invalid index
0219     Q_ASSERT(model->index(-2, -2) == QModelIndex());
0220     Q_ASSERT(model->index(-2, 0) == QModelIndex());
0221     Q_ASSERT(model->index(0, -2) == QModelIndex());
0222 
0223     int rows = model->rowCount();
0224     int columns = model->columnCount();
0225 
0226     if (rows == 0) {
0227         return;
0228     }
0229 
0230     // Catch off by one errors
0231     Q_ASSERT(model->index(rows, columns) == QModelIndex());
0232     Q_ASSERT(model->index(0, 0).isValid() == true);
0233 
0234     // Make sure that the same index is *always* returned
0235     QModelIndex a = model->index(0, 0);
0236     QModelIndex b = model->index(0, 0);
0237     Q_ASSERT(a == b);
0238 
0239     // index() is tested more extensively in checkChildren(),
0240     // but this catches the big mistakes
0241 }
0242 
0243 /*!
0244     Tests model's implementation of QAbstractItemModel::parent()
0245  */
0246 void ModelTest::parent()
0247 {
0248 //     qDebug() << "p";
0249     // Make sure the model wont crash and will return an invalid QModelIndex
0250     // when asked for the parent of an invalid index.
0251     Q_ASSERT(model->parent(QModelIndex()) == QModelIndex());
0252 
0253     if (model->rowCount() == 0) {
0254         return;
0255     }
0256 
0257     // Column 0                | Column 1    |
0258     // QModelIndex()           |             |
0259     //    \- topIndex          | topIndex1   |
0260     //         \- childIndex   | childIndex1 |
0261 
0262     // Common error test #1, make sure that a top level index has a parent
0263     // that is a invalid QModelIndex.
0264     QModelIndex topIndex = model->index(0, 0, QModelIndex());
0265     Q_ASSERT(model->parent(topIndex) == QModelIndex());
0266 
0267     // Common error test #2, make sure that a second level index has a parent
0268     // that is the first level index.
0269     if (model->rowCount(topIndex) > 0) {
0270         QModelIndex childIndex = model->index(0, 0, topIndex);
0271         Q_ASSERT(model->parent(childIndex) == topIndex);
0272     }
0273 
0274     // Common error test #3, the second column should NOT have the same children
0275     // as the first column in a row.
0276     // Usually the second column shouldn't have children.
0277     QModelIndex topIndex1 = model->index(0, 1, QModelIndex());
0278     if (model->rowCount(topIndex1) > 0) {
0279         QModelIndex childIndex = model->index(0, 0, topIndex);
0280         QModelIndex childIndex1 = model->index(0, 0, topIndex1);
0281         Q_ASSERT(childIndex != childIndex1);
0282     }
0283 
0284     // Full test, walk n levels deep through the model making sure that all
0285     // parent's children correctly specify their parent.
0286     checkChildren(QModelIndex());
0287 }
0288 
0289 /*!
0290     Called from the parent() test.
0291 
0292     A model that returns an index of parent X should also return X when asking
0293     for the parent of the index.
0294 
0295     This recursive function does pretty extensive testing on the whole model in an
0296     effort to catch edge cases.
0297 
0298     This function assumes that rowCount(), columnCount() and index() already work.
0299     If they have a bug it will point it out, but the above tests should have already
0300     found the basic bugs because it is easier to figure out the problem in
0301     those tests then this one.
0302  */
0303 void ModelTest::checkChildren(const QModelIndex& iParent, int currentDepth)
0304 {
0305     // First just try walking back up the tree.
0306     QModelIndex p = iParent;
0307     while (p.isValid()) {
0308         p = p.parent();
0309     }
0310 
0311     // For models that are dynamically populated
0312     if (model->canFetchMore(iParent)) {
0313         fetchingMore = true;
0314         model->fetchMore(iParent);
0315         fetchingMore = false;
0316     }
0317 
0318     int rows = model->rowCount(iParent);
0319     int columns = model->columnCount(iParent);
0320 
0321     if (rows > 0) {
0322         Q_ASSERT(model->hasChildren(iParent));
0323     }
0324 
0325     // Some further testing against rows(), columns(), and hasChildren()
0326     Q_ASSERT(rows >= 0);
0327     Q_ASSERT(columns >= 0);
0328     if (rows > 0) {
0329         Q_ASSERT(model->hasChildren(iParent) == true);
0330     }
0331 
0332     // qDebug() << "iParent:" << model->data(iParent).toString() << "rows:" << rows
0333     //         << "columns:" << columns << "iParent column:" << iParent.column();
0334 
0335     Q_ASSERT(model->hasIndex(rows + 1, 0, iParent) == false);
0336     for (int r = 0; r < rows; ++r) {
0337         if (model->canFetchMore(iParent)) {
0338             fetchingMore = true;
0339             model->fetchMore(iParent);
0340             fetchingMore = false;
0341         }
0342         Q_ASSERT(model->hasIndex(r, columns + 1, iParent) == false);
0343         for (int c = 0; c < columns; ++c) {
0344             Q_ASSERT(model->hasIndex(r, c, iParent) == true);
0345             QModelIndex idx = model->index(r, c, iParent);
0346             // rowCount() and columnCount() said that it existed...
0347             Q_ASSERT(idx.isValid() == true);
0348 
0349             // index() should always return the same index when called twice in a row
0350             QModelIndex modifiedIndex = model->index(r, c, iParent);
0351             Q_ASSERT(idx == modifiedIndex);
0352 
0353             // Make sure we get the same index if we request it twice in a row
0354             QModelIndex a = model->index(r, c, iParent);
0355             QModelIndex b = model->index(r, c, iParent);
0356             Q_ASSERT(a == b);
0357 
0358             // Some basic checking on the index that is returned
0359             Q_ASSERT(idx.model() == model);
0360             Q_ASSERT(idx.row() == r);
0361             Q_ASSERT(idx.column() == c);
0362             // While you can technically return a QVariant usually this is a sign
0363             // of an bug in data()  Disable if this really is ok in your model.
0364             Q_ASSERT(model->data(idx, Qt::DisplayRole).isValid() == true);
0365 
0366             // If the next test fails here is some somewhat useful debug you play with.
0367 
0368             if (model->parent(idx) != iParent) {
0369                 qDebug() << r << c << currentDepth << model->data(idx).toString()
0370                          << model->data(iParent).toString();
0371                 qDebug() << idx << iParent << model->parent(idx);
0372 //                 And a view that you can even use to show the model.
0373 //                 QTreeView view;
0374 //                 view.setModel(model);
0375 //                 view.show();
0376             }
0377 
0378             // Check that we can get back our real parent.
0379 //             qDebug() << model->parent ( index ) << parent;
0380             Q_ASSERT(model->parent(idx) == iParent);
0381 
0382             // recursively go down the children
0383             if (model->hasChildren(idx) && currentDepth < 10) {
0384                 // qDebug() << r << c << "has children" << model->rowCount(index);
0385                 checkChildren(idx, ++currentDepth);
0386             }/* else { if (currentDepth >= 10) qDebug() << "checked 10 deep"; };*/
0387 
0388             // make sure that after testing the children that the index doesn't change.
0389             QModelIndex newerIndex = model->index(r, c, iParent);
0390             Q_ASSERT(idx == newerIndex);
0391         }
0392     }
0393 }
0394 
0395 /*!
0396     Tests model's implementation of QAbstractItemModel::data()
0397  */
0398 void ModelTest::data()
0399 {
0400     // Invalid index should return an invalid qvariant
0401     Q_ASSERT(!model->data(QModelIndex()).isValid());
0402 
0403     int nbRows = model->rowCount();
0404     int nbColumns = model->columnCount();
0405     if (nbRows == 0 || nbColumns == 0) {
0406         return;
0407     }
0408 
0409 
0410     for (int r = 0; r < nbRows; ++r) {
0411         for (int c = 0; c < nbColumns; ++c) {
0412             // A valid index should have a valid QVariant data
0413             Q_ASSERT(model->index(r, c).isValid());
0414 
0415             // shouldn't be able to set data on an invalid index
0416             Q_ASSERT(model->setData(QModelIndex(), QStringLiteral("foo"), Qt::DisplayRole) == false);
0417 
0418             // General Purpose roles that should return a QString
0419             QVariant variant = model->data(model->index(r, c), Qt::ToolTipRole);
0420             if (variant.isValid()) {
0421                 Q_ASSERT(variant.canConvert<QString>());
0422             }
0423             variant = model->data(model->index(r, c), Qt::StatusTipRole);
0424             if (variant.isValid()) {
0425                 Q_ASSERT(variant.canConvert<QString>());
0426             }
0427             variant = model->data(model->index(r, c), Qt::WhatsThisRole);
0428             if (variant.isValid()) {
0429                 Q_ASSERT(variant.canConvert<QString>());
0430             }
0431 
0432             // General Purpose roles that should return a QSize
0433             variant = model->data(model->index(r, c), Qt::SizeHintRole);
0434             if (variant.isValid()) {
0435                 Q_ASSERT(variant.canConvert<QSize> ());
0436             }
0437 
0438             // MANKOWSKI: UserRole
0439             variant = model->data(model->index(r, c), Qt::UserRole);
0440             if (variant.isValid()) {
0441                 Q_ASSERT(variant.canConvert<QString>());
0442             }
0443 
0444             // General Purpose roles that should return a QFont
0445             QVariant fontVariant = model->data(model->index(r, c), Qt::FontRole);
0446             if (fontVariant.isValid()) {
0447                 Q_ASSERT(fontVariant.canConvert<QFont> ());
0448             }
0449 
0450             // Check that the alignment is one we know about
0451             QVariant textAlignmentVariant = model->data(model->index(r, c), Qt::TextAlignmentRole);
0452             if (textAlignmentVariant.isValid()) {
0453                 int alignment = textAlignmentVariant.toInt();
0454                 Q_ASSERT(static_cast<unsigned int>(alignment) == static_cast<unsigned int>(alignment & (Qt::AlignHorizontal_Mask | Qt::AlignVertical_Mask)));
0455             }
0456 
0457             // General Purpose roles that should return a QColor
0458             QVariant colorVariant = model->data(model->index(r, c), Qt::BackgroundColorRole);
0459             if (colorVariant.isValid()) {
0460                 Q_ASSERT(colorVariant.canConvert<QColor> ());
0461             }
0462 
0463             colorVariant = model->data(model->index(r, c), Qt::TextColorRole);
0464             if (colorVariant.isValid()) {
0465                 Q_ASSERT(colorVariant.canConvert<QColor> ());
0466             }
0467 
0468             // Check that the "check state" is one we know about.
0469             QVariant checkStateVariant = model->data(model->index(r, c), Qt::CheckStateRole);
0470             if (checkStateVariant.isValid()) {
0471                 int state = checkStateVariant.toInt();
0472                 Q_ASSERT(state == Qt::Unchecked ||
0473                          state == Qt::PartiallyChecked ||
0474                          state == Qt::Checked);
0475             }
0476         }
0477     }
0478 }
0479 
0480 /*!
0481     Store what is about to be inserted to make sure it actually happens
0482 
0483     \sa rowsInserted()
0484  */
0485 void ModelTest::rowsAboutToBeInserted(const QModelIndex& iParent, int start, int end)
0486 {
0487     Q_UNUSED(end)
0488 //    qDebug() << "rowsAboutToBeInserted" << "start=" << start << "end=" << end << "parent=" << model->data ( parent ).toString()
0489 //    << "current count of parent=" << model->rowCount ( parent );  // << "display of last=" << model->data( model->index(start-1, 0, parent) );
0490 //     qDebug() << model->index(start-1, 0, parent) << model->data( model->index(start-1, 0, parent) );
0491     Changing c;
0492     c.parent = iParent;
0493     c.oldSize = model->rowCount(iParent);
0494     c.last = model->data(model->index(start - 1, 0, iParent));
0495     c.next = model->data(model->index(start, 0, iParent));
0496     insert.push(c);
0497 }
0498 
0499 /*!
0500     Confirm that what was said was going to happen actually did
0501 
0502     \sa rowsAboutToBeInserted()
0503  */
0504 void ModelTest::rowsInserted(const QModelIndex& iParent, int start, int end)
0505 {
0506     Changing c = insert.pop();
0507     Q_ASSERT(c.parent == iParent);
0508 //    qDebug() << "rowsInserted"  << "start=" << start << "end=" << end << "oldsize=" << c.oldSize
0509 //    << "parent=" << model->data ( parent ).toString() << "current rowcount of parent=" << model->rowCount ( parent );
0510 
0511 //    for (int ii=start; ii <= end; ii++)
0512 //    {
0513 //      qDebug() << "itemWasInserted:" << ii << model->data ( model->index ( ii, 0, parent ));
0514 //    }
0515 //    qDebug();
0516 
0517     Q_ASSERT(c.oldSize + (end - start + 1) == model->rowCount(iParent));
0518     Q_ASSERT(c.last == model->data(model->index(start - 1, 0, c.parent)));
0519 
0520     if (c.next != model->data(model->index(end + 1, 0, c.parent))) {
0521         qDebug() << start << end;
0522         for (int i = 0; i < model->rowCount(); ++i) {
0523             qDebug() << model->index(i, 0).data().toString();
0524         }
0525         qDebug() << c.next << model->data(model->index(end + 1, 0, c.parent));
0526     }
0527 
0528     Q_ASSERT(c.next == model->data(model->index(end + 1, 0, c.parent)));
0529 }
0530 
0531 void ModelTest::layoutAboutToBeChanged()
0532 {
0533     for (int i = 0; i < qBound(0, model->rowCount(), 100); ++i) {
0534         changing.append(QPersistentModelIndex(model->index(i, 0)));
0535     }
0536 }
0537 
0538 void ModelTest::layoutChanged()
0539 {
0540     for (int i = 0; i < changing.count(); ++i) {
0541         QPersistentModelIndex p = changing.at(i);
0542         Q_ASSERT(p == model->index(p.row(), p.column(), p.parent()));
0543     }
0544     changing.clear();
0545 }
0546 
0547 /*!
0548     Store what is about to be inserted to make sure it actually happens
0549 
0550     \sa rowsRemoved()
0551  */
0552 void ModelTest::rowsAboutToBeRemoved(const QModelIndex& iParent, int start, int end)
0553 {
0554     qDebug() << "ratbr" << iParent << start << end;
0555     Changing c;
0556     c.parent = iParent;
0557     c.oldSize = model->rowCount(iParent);
0558     c.last = model->data(model->index(start - 1, 0, iParent));
0559     c.next = model->data(model->index(end + 1, 0, iParent));
0560     remove.push(c);
0561 }
0562 
0563 /*!
0564     Confirm that what was said was going to happen actually did
0565 
0566     \sa rowsAboutToBeRemoved()
0567  */
0568 void ModelTest::rowsRemoved(const QModelIndex& iParent, int start, int end)
0569 {
0570     qDebug() << "rr" << iParent << start << end;
0571     Changing c = remove.pop();
0572     Q_ASSERT(c.parent == iParent);
0573     Q_ASSERT(c.oldSize - (end - start + 1) == model->rowCount(iParent));
0574     Q_ASSERT(c.last == model->data(model->index(start - 1, 0, c.parent)));
0575     Q_ASSERT(c.next == model->data(model->index(start, 0, c.parent)));
0576 }
0577 
0578