summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Kelly <stephen.kelly@kdab.com>2011-11-23 20:50:55 +0100
committerQt by Nokia <qt-info@nokia.com>2011-11-24 16:46:15 +0100
commit8f1868e7c36cb890c9d71dcd9d07d7019058cf94 (patch)
treef6aa5e7dfc12175a6be24b316b6c2ab5c24759fe
parent11bf824c03d07a2c4ac7f1d614351c532d7a52d6 (diff)
Add a parents parameter to layoutChange signals.
This allows for more focussed notification of what part of the model has changed layout. The slots in the proxy models can be more optimized later. Change-Id: I1bd17465b4be6f8efdc107036db897c557fcb519 Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
-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