Provide the resetInternalData slot to cleanly reset data in proxy subclasses.

This was part of Qt 4.8, but Qt 5.0 was branched before that, so
the commit was lost.

Change-Id: I2a2ab3c75a0943ac734d588ebd74bc158dd6aaaf
Reviewed-by: Nils Jeisecke <jeisecke@saltation.de>
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
This commit is contained in:
Stephen Kelly 2013-01-28 19:17:21 +01:00 committed by The Qt Project
parent b28d56588a
commit 8eae3a923a
4 changed files with 198 additions and 0 deletions

View File

@ -97,3 +97,37 @@ beginResetModel();
myData.clear();
endResetModel();
//! [11]
//! [12]
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;
};
//! [12]

View File

@ -865,6 +865,27 @@ 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 code/src_corelib_kernel_qabstractitemmodel.cpp 12
\note Due to a mistake, this slot is missing in Qt 5.0.
\sa modelAboutToBeReset(), modelReset()
*/
void QAbstractItemModel::resetInternalData()
{
}
/*!
\class QModelIndex
\inmodule QtCore
@ -3055,6 +3076,7 @@ void QAbstractItemModel::endResetModel()
{
Q_D(QAbstractItemModel);
d->invalidatePersistentIndexes();
QMetaObject::invokeMethod(this, "resetInternalData");
emit modelReset(QPrivateSignal());
}

View File

@ -330,6 +330,10 @@ public Q_SLOTS:
virtual bool submit();
virtual void revert();
protected Q_SLOTS:
// Qt 6: Make virtual
void resetInternalData();
protected:
QAbstractItemModel(QAbstractItemModelPrivate &dd, QObject *parent = 0);

View File

@ -136,6 +136,7 @@ private slots:
void testMultipleProxiesWithSelection();
void mapSelectionFromSource();
void testResetInternalData();
void filteredColumns();
void headerDataChanged();
@ -3242,6 +3243,143 @@ void tst_QSortFilterProxyModel::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 invocation 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");
}
void tst_QSortFilterProxyModel::testParentLayoutChanged()
{
QStandardItemModel model;