diff options
author | Stephen Kelly <stephen.kelly@kdab.com> | 2010-09-23 14:14:18 +0200 |
---|---|---|
committer | Gabriel de Dietrich <gabriel.dietrich-de@nokia.com> | 2011-06-27 18:13:45 +0200 |
commit | 0f6853e9c775dd8fbb64f66119c2c9b2ea23da29 (patch) | |
tree | 880ec281b07648a14b0a4b95473001b5fb8b5eb5 | |
parent | 031958c130904c16a4bafa5617aaa197469efa9e (diff) |
Provide the resetInternalData slot to cleanly reset data in proxy subclasses.
Direct subclasses of QAbstractItemModel are unnaffected as they can update
internal data in a slot connected to the sourceModel's modelReset signal or
layoutChanged signal.
Rehabilitated for 4.8. Should be reverted again in Qt 5.
Reviewed-by: gabi
Merge-request: 694
4 files changed, 198 insertions, 0 deletions
diff --git a/doc/src/snippets/code/src_corelib_kernel_qabstractitemmodel.cpp b/doc/src/snippets/code/src_corelib_kernel_qabstractitemmodel.cpp index 5919c01085..cf40f9a05a 100644 --- a/doc/src/snippets/code/src_corelib_kernel_qabstractitemmodel.cpp +++ b/doc/src/snippets/code/src_corelib_kernel_qabstractitemmodel.cpp @@ -86,3 +86,38 @@ beginMoveRows(parent, 2, 2, parent, 0); //! [9] beginMoveRows(parent, 2, 2, parent, 4); //! [9] + + +//! [10] +class CustomDataProxy : public QSortFilterProxyModel +{ + Q_OBJECT +public: + CustomDataProxy(QObject *parent) + : QSortFilterProxyModel(parent) + { + } + + ... + + QVariant data(const QModelIndex &index, int role) + { + if (role != Qt::BackgroundRole) + return QSortFilterProxyModel::data(index, role); + + if (m_customData.contains(index.row())) + return m_customData.value(index.row()); + return QSortFilterProxyModel::data(index, role); + } + +private slots: + void resetInternalData() + { + m_customData.clear(); + } + +private: + QHash<int, QVariant> m_customData; +}; +//! [10] + diff --git a/src/corelib/kernel/qabstractitemmodel.cpp b/src/corelib/kernel/qabstractitemmodel.cpp index b7ac6aa594..54cc301194 100644 --- a/src/corelib/kernel/qabstractitemmodel.cpp +++ b/src/corelib/kernel/qabstractitemmodel.cpp @@ -1348,6 +1348,26 @@ void QAbstractItemModelPrivate::columnsRemoved(const QModelIndex &parent, */ /*! + \since 4.8 + + This slot is called just after the internal data of a model is cleared + while it is being reset. + + This slot is provided the convenience of subclasses of concrete proxy + models, such as subclasses of QSortFilterProxyModel which maintain extra + data. + + \snippet doc/src/snippets/code/src_corelib_kernel_qabstractitemmodel.cpp 10 + + \sa modelAboutToBeReset(), modelReset() +*/ +void QAbstractItemModel::resetInternalData() +{ + +} + + +/*! Constructs an abstract item model with the given \a parent. */ QAbstractItemModel::QAbstractItemModel(QObject *parent) @@ -2888,6 +2908,7 @@ void QAbstractItemModel::reset() Q_D(QAbstractItemModel); emit modelAboutToBeReset(); d->invalidatePersistentIndexes(); + QMetaObject::invokeMethod(this, "resetInternalData"); emit modelReset(); } @@ -2930,6 +2951,7 @@ void QAbstractItemModel::endResetModel() { Q_D(QAbstractItemModel); d->invalidatePersistentIndexes(); + QMetaObject::invokeMethod(this, "resetInternalData"); emit modelReset(); } diff --git a/src/corelib/kernel/qabstractitemmodel.h b/src/corelib/kernel/qabstractitemmodel.h index c7af7a284f..43d8ac2526 100644 --- a/src/corelib/kernel/qabstractitemmodel.h +++ b/src/corelib/kernel/qabstractitemmodel.h @@ -303,6 +303,9 @@ protected: void setRoleNames(const QHash<int,QByteArray> &roleNames); +protected slots: + void resetInternalData(); + private: Q_DECLARE_PRIVATE(QAbstractItemModel) Q_DISABLE_COPY(QAbstractItemModel) diff --git a/tests/auto/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp b/tests/auto/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp index 613c611843..30589a89f6 100644 --- a/tests/auto/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp +++ b/tests/auto/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp @@ -149,6 +149,7 @@ private slots: void testMultipleProxiesWithSelection(); void mapSelectionFromSource(); + void testResetInternalData(); void filteredColumns(); protected: @@ -3271,5 +3272,142 @@ void tst_QSortFilterProxyModel::taskQTBUG_17812_resetInvalidate() QCOMPARE(ok, works); } +/** + * A proxy which changes the background color for items ending in 'y' or 'r' + */ +class CustomDataProxy : public QSortFilterProxyModel +{ + Q_OBJECT + +public: + CustomDataProxy(QObject *parent = 0) + : QSortFilterProxyModel(parent) + { + setDynamicSortFilter(true); + } + + void setSourceModel(QAbstractItemModel *sourceModel) + { + // It would be possible to use only the modelReset signal of the source model to clear + // the data in *this, however, this requires that the slot is connected + // before QSortFilterProxyModel::setSourceModel is called, and even then depends + // on the order of invokation of slots being the same as the order of connection. + // ie, not reliable. +// connect(sourceModel, SIGNAL(modelReset()), SLOT(resetInternalData())); + QSortFilterProxyModel::setSourceModel(sourceModel); + // Making the connect after the setSourceModel call clears the data too late. +// connect(sourceModel, SIGNAL(modelReset()), SLOT(resetInternalData())); + + // This could be done in data(), but the point is to need to cache something in the proxy + // which needs to be cleared on reset. + for (int i = 0; i < sourceModel->rowCount(); ++i) + { + if (sourceModel->index(i, 0).data().toString().endsWith(QLatin1Char('y'))) + { + m_backgroundColours.insert(i, Qt::blue); + } else if (sourceModel->index(i, 0).data().toString().endsWith(QLatin1Char('r'))) + { + m_backgroundColours.insert(i, Qt::red); + } + } + } + + QVariant data(const QModelIndex &index, int role) const + { + if (role != Qt::BackgroundRole) + return QSortFilterProxyModel::data(index, role); + return m_backgroundColours.value(index.row()); + } + +private slots: + void resetInternalData() + { + m_backgroundColours.clear(); + } + +private: + QHash<int, QColor> m_backgroundColours; +}; + +class ModelObserver : public QObject +{ + Q_OBJECT +public: + ModelObserver(QAbstractItemModel *model, QObject *parent = 0) + : QObject(parent), m_model(model) + { + connect(m_model, SIGNAL(modelAboutToBeReset()), SLOT(modelAboutToBeReset())); + connect(m_model, SIGNAL(modelReset()), SLOT(modelReset())); + } + +public slots: + void modelAboutToBeReset() + { + int reds = 0, blues = 0; + for (int i = 0; i < m_model->rowCount(); ++i) + { + QColor color = m_model->index(i, 0).data(Qt::BackgroundRole).value<QColor>(); + if (color == Qt::blue) + ++blues; + if (color == Qt::red) + ++reds; + } + QCOMPARE(blues, 11); + QCOMPARE(reds, 4); + } + + void modelReset() + { + int reds = 0, blues = 0; + for (int i = 0; i < m_model->rowCount(); ++i) + { + QColor color = m_model->index(i, 0).data(Qt::BackgroundRole).value<QColor>(); + if (color == Qt::blue) + ++blues; + if (color == Qt::red) + ++reds; + } + QCOMPARE(reds, 0); + QCOMPARE(blues, 0); + } + +private: + QAbstractItemModel * const m_model; + +}; + +void tst_QSortFilterProxyModel::testResetInternalData() +{ + + QStringListModel model(QStringList() << "Monday" + << "Tuesday" + << "Wednesday" + << "Thursday" + << "Friday" + << "January" + << "February" + << "March" + << "April" + << "May" + << "Saturday" + << "June" + << "Sunday" + << "July" + << "August" + << "September" + << "October" + << "November" + << "December"); + + CustomDataProxy proxy; + proxy.setSourceModel(&model); + + ModelObserver observer(&proxy); + + // Cause the source model to reset. + model.setStringList(QStringList() << "Spam" << "Eggs"); + +} + QTEST_MAIN(tst_QSortFilterProxyModel) #include "tst_qsortfilterproxymodel.moc" |