summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/kernel/qabstractitemmodel.cpp12
-rw-r--r--src/corelib/kernel/qabstractitemmodel.h4
-rw-r--r--tests/auto/corelib/kernel/qabstractitemmodel/tst_qabstractitemmodel.cpp172
-rw-r--r--tests/auto/integrationtests/modeltest/dynamictreemodel.cpp52
-rw-r--r--tests/auto/integrationtests/modeltest/dynamictreemodel.h17
5 files changed, 253 insertions, 4 deletions
diff --git a/src/corelib/kernel/qabstractitemmodel.cpp b/src/corelib/kernel/qabstractitemmodel.cpp
index fbeb59a553..cbbb20a8c9 100644
--- a/src/corelib/kernel/qabstractitemmodel.cpp
+++ b/src/corelib/kernel/qabstractitemmodel.cpp
@@ -1306,7 +1306,7 @@ void QAbstractItemModelPrivate::columnsRemoved(const QModelIndex &parent,
*/
/*!
- \fn void QAbstractItemModel::layoutAboutToBeChanged()
+ \fn void QAbstractItemModel::layoutAboutToBeChanged(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>())
\since 4.2
This signal is emitted just before the layout of a model is changed.
@@ -1316,11 +1316,15 @@ void QAbstractItemModelPrivate::columnsRemoved(const QModelIndex &parent,
Subclasses should update any persistent model indexes after emitting
layoutAboutToBeChanged().
+ The optional @p parents parameter is used to give a more specific notification
+ about what parts of the layout of the model are changing. An empty list indicates
+ a change to the layout of the entire model.
+
\sa layoutChanged(), changePersistentIndex()
*/
/*!
- \fn void QAbstractItemModel::layoutChanged()
+ \fn void QAbstractItemModel::layoutChanged(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>())
This signal is emitted whenever the layout of items exposed by the model
has changed; for example, when the model has been sorted. When this signal
@@ -1332,6 +1336,10 @@ void QAbstractItemModelPrivate::columnsRemoved(const QModelIndex &parent,
altering the structure of the data you expose to views, and emit
layoutChanged() after changing the layout.
+ The optional @p parents parameter is used to give a more specific notification
+ about what parts of the layout of the model are changing. An empty list indicates
+ a change to the layout of the entire model.
+
Subclasses should update any persistent model indexes before emitting
layoutChanged(). In other words, when the structure changes:
diff --git a/src/corelib/kernel/qabstractitemmodel.h b/src/corelib/kernel/qabstractitemmodel.h
index 97c5b58482..0aa8144602 100644
--- a/src/corelib/kernel/qabstractitemmodel.h
+++ b/src/corelib/kernel/qabstractitemmodel.h
@@ -233,8 +233,8 @@ public:
Q_SIGNALS:
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QSet<int> &roles = QSet<int>());
void headerDataChanged(Qt::Orientation orientation, int first, int last);
- void layoutChanged();
- void layoutAboutToBeChanged();
+ void layoutChanged(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>());
+ void layoutAboutToBeChanged(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>());
#if !defined(Q_MOC_RUN) && !defined(qdoc)
private: // can only be emitted by QAbstractItemModel
diff --git a/tests/auto/corelib/kernel/qabstractitemmodel/tst_qabstractitemmodel.cpp b/tests/auto/corelib/kernel/qabstractitemmodel/tst_qabstractitemmodel.cpp
index 4b09b455ad..c704329717 100644
--- a/tests/auto/corelib/kernel/qabstractitemmodel/tst_qabstractitemmodel.cpp
+++ b/tests/auto/corelib/kernel/qabstractitemmodel/tst_qabstractitemmodel.cpp
@@ -112,6 +112,8 @@ private slots:
void testDataChanged();
+ void testChildrenLayoutsChanged();
+
private:
DynamicTreeModel *m_model;
};
@@ -1841,6 +1843,176 @@ void tst_QAbstractItemModel::testDataChanged()
QVERIFY(thirdRoles.contains(CustomRoleModel::Custom1));
}
+Q_DECLARE_METATYPE(QList<QPersistentModelIndex>)
+
+class SignalArgumentChecker : public QObject
+{
+ Q_OBJECT
+public:
+ SignalArgumentChecker(const QModelIndex &p1, const QModelIndex &p2, QObject *parent = 0)
+ : QObject(parent), m_p1(p1), m_p2(p2), m_p1Persistent(p1), m_p2Persistent(p2)
+ {
+ connect(p1.model(), SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>)), SLOT(layoutAboutToBeChanged(QList<QPersistentModelIndex>)));
+ connect(p1.model(), SIGNAL(layoutChanged(QList<QPersistentModelIndex>)), SLOT(layoutChanged(QList<QPersistentModelIndex>)));
+ }
+
+private slots:
+ void layoutAboutToBeChanged(const QList<QPersistentModelIndex> &parents)
+ {
+ QCOMPARE(parents.size(), 2);
+ QVERIFY(parents.first() != parents.at(1));
+ QVERIFY(parents.contains(m_p1));
+ QVERIFY(parents.contains(m_p2));
+ }
+
+ void layoutChanged(const QList<QPersistentModelIndex> &parents)
+ {
+ QCOMPARE(parents.size(), 2);
+ QVERIFY(parents.first() != parents.at(1));
+ QVERIFY(parents.contains(m_p1Persistent));
+ QVERIFY(parents.contains(m_p2Persistent));
+ QVERIFY(!parents.contains(m_p2)); // Has changed
+ }
+
+private:
+ QModelIndex m_p1;
+ QModelIndex m_p2;
+ QPersistentModelIndex m_p1Persistent;
+ QPersistentModelIndex m_p2Persistent;
+};
+
+void tst_QAbstractItemModel::testChildrenLayoutsChanged()
+{
+ DynamicTreeModel model;
+
+ ModelInsertCommand *insertCommand = new ModelInsertCommand(&model, this);
+ insertCommand->setStartRow(0);
+ insertCommand->setEndRow(9);
+ insertCommand->doCommand();
+
+ insertCommand = new ModelInsertCommand(&model, this);
+ insertCommand->setAncestorRowNumbers(QList<int>() << 2);
+ insertCommand->setStartRow(0);
+ insertCommand->setEndRow(9);
+ insertCommand->doCommand();
+
+ insertCommand = new ModelInsertCommand(&model, this);
+ insertCommand->setAncestorRowNumbers(QList<int>() << 5);
+ insertCommand->setStartRow(0);
+ insertCommand->setEndRow(9);
+ insertCommand->doCommand();
+
+ qRegisterMetaType<QList<QPersistentModelIndex> >();
+
+ {
+ const QModelIndex p1 = model.index(2, 0);
+ const QModelIndex p2 = model.index(5, 0);
+
+ const QPersistentModelIndex p1FirstPersistent = model.index(0, 0, p1);
+ const QPersistentModelIndex p1LastPersistent = model.index(9, 0, p1);
+ const QPersistentModelIndex p2FirstPersistent = model.index(0, 0, p2);
+ const QPersistentModelIndex p2LastPersistent = model.index(9, 0, p2);
+
+ QVERIFY(p1.isValid());
+ QVERIFY(p2.isValid());
+
+ QCOMPARE(model.rowCount(), 10);
+ QCOMPARE(model.rowCount(p1), 10);
+ QCOMPARE(model.rowCount(p2), 10);
+
+ QSignalSpy beforeSpy(&model, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>)));
+ QSignalSpy afterSpy(&model, SIGNAL(layoutChanged(QList<QPersistentModelIndex>)));
+
+ ModelChangeChildrenLayoutsCommand *changeCommand = new ModelChangeChildrenLayoutsCommand(&model, this);
+ changeCommand->setAncestorRowNumbers(QList<int>() << 2);
+ changeCommand->setSecondAncestorRowNumbers(QList<int>() << 5);
+ changeCommand->doCommand();
+
+ QCOMPARE(beforeSpy.size(), 1);
+ QCOMPARE(afterSpy.size(), 1);
+
+ const QVariantList beforeSignal = beforeSpy.first();
+ const QVariantList afterSignal = afterSpy.first();
+ QCOMPARE(beforeSignal.size(), 1);
+ QCOMPARE(afterSignal.size(), 1);
+
+ const QList<QPersistentModelIndex> beforeParents = beforeSignal.first().value<QList<QPersistentModelIndex> >();
+ QCOMPARE(beforeParents.size(), 2);
+ QVERIFY(beforeParents.first() != beforeParents.at(1));
+ QVERIFY(beforeParents.contains(p1));
+ QVERIFY(beforeParents.contains(p2));
+
+ const QList<QPersistentModelIndex> afterParents = afterSignal.first().value<QList<QPersistentModelIndex> >();
+ QCOMPARE(afterParents.size(), 2);
+ QVERIFY(afterParents.first() != afterParents.at(1));
+ QVERIFY(afterParents.contains(p1));
+ QVERIFY(afterParents.contains(p2));
+
+ // The first will be the last, and the lest will be the first.
+ QVERIFY(p1FirstPersistent.row() == 1);
+ QVERIFY(p1LastPersistent.row() == 0);
+ QVERIFY(p2FirstPersistent.row() == 9);
+ QVERIFY(p2LastPersistent.row() == 8);
+
+ }
+
+ insertCommand = new ModelInsertCommand(&model, this);
+ insertCommand->setAncestorRowNumbers(QList<int>() << 5 << 4);
+ insertCommand->setStartRow(0);
+ insertCommand->setEndRow(9);
+ insertCommand->doCommand();
+
+ delete insertCommand;
+
+ // Even when p2 itself is moved around, signal emission remains correct for its children.
+ {
+ const QModelIndex p1 = model.index(5, 0);
+ const QModelIndex p2 = model.index(4, 0, p1);
+
+ QVERIFY(p1.isValid());
+ QVERIFY(p2.isValid());
+
+ QCOMPARE(model.rowCount(), 10);
+ QCOMPARE(model.rowCount(p1), 10);
+ QCOMPARE(model.rowCount(p2), 10);
+
+ const QPersistentModelIndex p1Persistent = p1;
+ const QPersistentModelIndex p2Persistent = p2;
+
+ const QPersistentModelIndex p1FirstPersistent = model.index(0, 0, p1);
+ const QPersistentModelIndex p1LastPersistent = model.index(9, 0, p1);
+ const QPersistentModelIndex p2FirstPersistent = model.index(0, 0, p2);
+ const QPersistentModelIndex p2LastPersistent = model.index(9, 0, p2);
+
+ QSignalSpy beforeSpy(&model, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>)));
+ QSignalSpy afterSpy(&model, SIGNAL(layoutChanged(QList<QPersistentModelIndex>)));
+
+ // Because the arguments in the signal are persistent, we need to check them for the aboutToBe
+ // case at emission time - before they get updated.
+ SignalArgumentChecker checker(p1, p2);
+
+ ModelChangeChildrenLayoutsCommand *changeCommand = new ModelChangeChildrenLayoutsCommand(&model, this);
+ changeCommand->setAncestorRowNumbers(QList<int>() << 5);
+ changeCommand->setSecondAncestorRowNumbers(QList<int>() << 5 << 4);
+ changeCommand->doCommand();
+
+ // p2 has been moved.
+ QCOMPARE(p2Persistent.row(), p2.row() + 1);
+
+ QCOMPARE(beforeSpy.size(), 1);
+ QCOMPARE(afterSpy.size(), 1);
+
+ const QVariantList beforeSignal = beforeSpy.first();
+ const QVariantList afterSignal = afterSpy.first();
+ QCOMPARE(beforeSignal.size(), 1);
+ QCOMPARE(afterSignal.size(), 1);
+
+ QVERIFY(p1FirstPersistent.row() == 1);
+ QVERIFY(p1LastPersistent.row() == 0);
+ QVERIFY(p2FirstPersistent.row() == 9);
+ QVERIFY(p2LastPersistent.row() == 8);
+ }
+}
QTEST_MAIN(tst_QAbstractItemModel)
#include "tst_qabstractitemmodel.moc"
diff --git a/tests/auto/integrationtests/modeltest/dynamictreemodel.cpp b/tests/auto/integrationtests/modeltest/dynamictreemodel.cpp
index 2f8bb0a730..5ab37ab112 100644
--- a/tests/auto/integrationtests/modeltest/dynamictreemodel.cpp
+++ b/tests/auto/integrationtests/modeltest/dynamictreemodel.cpp
@@ -338,3 +338,55 @@ void ModelResetCommandFixed::emitPostSignal()
m_model->endResetModel();
}
+ModelChangeChildrenLayoutsCommand::ModelChangeChildrenLayoutsCommand(DynamicTreeModel* model, QObject* parent)
+ : ModelChangeCommand(model, parent)
+{
+
+}
+
+void ModelChangeChildrenLayoutsCommand::doCommand()
+{
+ const QPersistentModelIndex parent1 = findIndex(m_rowNumbers);
+ const QPersistentModelIndex parent2 = findIndex(m_secondRowNumbers);
+
+ QList<QPersistentModelIndex> parents;
+ parents << parent1;
+ parents << parent2;
+
+ emit m_model->layoutAboutToBeChanged(parents);
+
+ int rowSize1 = -1;
+ int rowSize2 = -1;
+
+ for (int column = 0; column < m_numCols; ++column)
+ {
+ {
+ QList<qint64> &l = m_model->m_childItems[parent1.internalId()][column];
+ rowSize1 = l.size();
+ l.prepend(l.takeLast());
+ }
+ {
+ QList<qint64> &l = m_model->m_childItems[parent2.internalId()][column];
+ rowSize2 = l.size();
+ l.append(l.takeFirst());
+ }
+ }
+
+ foreach (const QModelIndex &idx, m_model->persistentIndexList()) {
+ if (idx.parent() == parent1) {
+ if (idx.row() == rowSize1 - 1) {
+ m_model->changePersistentIndex(idx, m_model->createIndex(0, idx.column(), idx.internalPointer()));
+ } else {
+ m_model->changePersistentIndex(idx, m_model->createIndex(idx.row() + 1, idx.column(), idx.internalPointer()));
+ }
+ } else if (idx.parent() == parent2) {
+ if (idx.row() == 0) {
+ m_model->changePersistentIndex(idx, m_model->createIndex(rowSize2 - 1, idx.column(), idx.internalPointer()));
+ } else {
+ m_model->changePersistentIndex(idx, m_model->createIndex(idx.row() - 1, idx.column(), idx.internalPointer()));
+ }
+ }
+ }
+
+ emit m_model->layoutChanged(parents);
+}
diff --git a/tests/auto/integrationtests/modeltest/dynamictreemodel.h b/tests/auto/integrationtests/modeltest/dynamictreemodel.h
index 81ef80cc40..6f52d78588 100644
--- a/tests/auto/integrationtests/modeltest/dynamictreemodel.h
+++ b/tests/auto/integrationtests/modeltest/dynamictreemodel.h
@@ -89,6 +89,7 @@ private:
friend class ModelMoveCommand;
friend class ModelResetCommand;
friend class ModelResetCommandFixed;
+ friend class ModelChangeChildrenLayoutsCommand;
};
@@ -193,5 +194,21 @@ public:
};
+class ModelChangeChildrenLayoutsCommand : public ModelChangeCommand
+{
+ Q_OBJECT
+public:
+ ModelChangeChildrenLayoutsCommand(DynamicTreeModel *model, QObject *parent);
+
+ virtual ~ModelChangeChildrenLayoutsCommand() {}
+
+ virtual void doCommand();
+
+ void setSecondAncestorRowNumbers( QList<int> rows ) { m_secondRowNumbers = rows; }
+
+protected:
+ QList<int> m_secondRowNumbers;
+ int m_destRow;
+};
#endif