QSortFilterProxyModel: Keep invalid index updated on source model sort

If we have a filter applied that removes all entries, the source
model is sorted, and then we remove the filter, QSortFilterProxyModel
never emits rowsInserted. This is because it doesn't have the correct
source mapping and doesn't update when the filter is removed.

Change-Id: I447b2d150e509b128d27f4dabc4e081ca4ef037f
Task-number: QTBUG-46282
Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
This commit is contained in:
Daiwei Li 2015-05-22 01:26:08 -07:00
parent 862b1b3ceb
commit db377a4202
2 changed files with 48 additions and 0 deletions

View File

@ -272,6 +272,7 @@ public:
QModelIndexPairList store_persistent_indexes();
void update_persistent_indexes(const QModelIndexPairList &source_indexes);
void filter_about_to_be_changed(const QModelIndex &source_parent = QModelIndex());
void filter_changed(const QModelIndex &source_parent = QModelIndex());
QSet<int> handle_filter_changed(
QVector<int> &source_to_proxy, QVector<int> &proxy_to_source,
@ -1045,6 +1046,19 @@ void QSortFilterProxyModelPrivate::update_persistent_indexes(
q->changePersistentIndexList(from, to);
}
/*!
\internal
Updates the source_index mapping in case it's invalid and we
need it because we have a valid filter
*/
void QSortFilterProxyModelPrivate::filter_about_to_be_changed(const QModelIndex &source_parent)
{
if (!filter_regexp.pattern().isEmpty() &&
source_index_mapping.constFind(source_parent) == source_index_mapping.constEnd())
create_mapping(source_parent);
}
/*!
\internal
@ -2304,6 +2318,7 @@ QRegExp QSortFilterProxyModel::filterRegExp() const
void QSortFilterProxyModel::setFilterRegExp(const QRegExp &regExp)
{
Q_D(QSortFilterProxyModel);
d->filter_about_to_be_changed();
d->filter_regexp = regExp;
d->filter_changed();
}
@ -2325,6 +2340,7 @@ int QSortFilterProxyModel::filterKeyColumn() const
void QSortFilterProxyModel::setFilterKeyColumn(int column)
{
Q_D(QSortFilterProxyModel);
d->filter_about_to_be_changed();
d->filter_column = column;
d->filter_changed();
}
@ -2350,6 +2366,7 @@ void QSortFilterProxyModel::setFilterCaseSensitivity(Qt::CaseSensitivity cs)
Q_D(QSortFilterProxyModel);
if (cs == d->filter_regexp.caseSensitivity())
return;
d->filter_about_to_be_changed();
d->filter_regexp.setCaseSensitivity(cs);
d->filter_changed();
}
@ -2415,6 +2432,7 @@ void QSortFilterProxyModel::setSortLocaleAware(bool on)
void QSortFilterProxyModel::setFilterRegExp(const QString &pattern)
{
Q_D(QSortFilterProxyModel);
d->filter_about_to_be_changed();
d->filter_regexp.setPatternSyntax(QRegExp::RegExp);
d->filter_regexp.setPattern(pattern);
d->filter_changed();
@ -2429,6 +2447,7 @@ void QSortFilterProxyModel::setFilterRegExp(const QString &pattern)
void QSortFilterProxyModel::setFilterWildcard(const QString &pattern)
{
Q_D(QSortFilterProxyModel);
d->filter_about_to_be_changed();
d->filter_regexp.setPatternSyntax(QRegExp::Wildcard);
d->filter_regexp.setPattern(pattern);
d->filter_changed();
@ -2443,6 +2462,7 @@ void QSortFilterProxyModel::setFilterWildcard(const QString &pattern)
void QSortFilterProxyModel::setFilterFixedString(const QString &pattern)
{
Q_D(QSortFilterProxyModel);
d->filter_about_to_be_changed();
d->filter_regexp.setPatternSyntax(QRegExp::FixedString);
d->filter_regexp.setPattern(pattern);
d->filter_changed();
@ -2522,6 +2542,7 @@ void QSortFilterProxyModel::setFilterRole(int role)
Q_D(QSortFilterProxyModel);
if (d->filter_role == role)
return;
d->filter_about_to_be_changed();
d->filter_role = role;
d->filter_changed();
}

View File

@ -87,6 +87,7 @@ private slots:
void filter_qtbug30662();
void changeSourceLayout();
void changeSourceLayoutFilteredOut();
void removeSourceRows_data();
void removeSourceRows();
void insertSourceRows_data();
@ -1533,6 +1534,32 @@ void tst_QSortFilterProxyModel::changeSourceLayout()
}
}
void tst_QSortFilterProxyModel::changeSourceLayoutFilteredOut()
{
QStandardItemModel model(2, 1);
model.setData(model.index(0, 0), QString("b"));
model.setData(model.index(1, 0), QString("a"));
QSortFilterProxyModel proxy;
proxy.setSourceModel(&model);
int beforeSortFilter = proxy.rowCount();
QSignalSpy removeSpy(&proxy, &QSortFilterProxyModel::rowsRemoved);
// Filter everything out
proxy.setFilterRegExp(QRegExp("c"));
QCOMPARE(removeSpy.count(), 1);
QCOMPARE(0, proxy.rowCount());
// change layout of source model
model.sort(0, Qt::AscendingOrder);
QSignalSpy insertSpy(&proxy, &QSortFilterProxyModel::rowsInserted);
// Remove filter; we expect an insert
proxy.setFilterRegExp(QRegExp(""));
QCOMPARE(insertSpy.count(), 1);
QCOMPARE(beforeSortFilter, proxy.rowCount());
}
void tst_QSortFilterProxyModel::removeSourceRows_data()
{
QTest::addColumn<QStringList>("sourceItems");