QSortFilterProxyModel inserting at bottom of source model

Before this change, if you try to insert a row at the bottom of QSortFilterProxyModel
the row will be inserted in the source model at position proxy->rowCount rather
than at the bottom. This causes insert at apparently random positions in the source.

[ChangeLog][QtCore][QSortFilterProxyModel]
QSortFilterProxyModel::insertRows(row,count,parent) with
row == QSortFilterProxyModel::rowCount will insert at the bottom of the source model
rather than at the row QSortFilterProxyModel::rowCount of the source model

Task-number: QTBUG-58499
Task-number: QTBUG-69158
Change-Id: Ie78416c8fbc429303b8c9c98375630e3e4d85f6d
Reviewed-by: David Faure <david.faure@kdab.com>
This commit is contained in:
Luca Beldi 2018-08-17 09:04:17 +01:00
parent 29778037f8
commit 70ba75519d
2 changed files with 239 additions and 2 deletions

View File

@ -2191,7 +2191,7 @@ bool QSortFilterProxyModel::insertRows(int row, int count, const QModelIndex &pa
if (row > m->source_rows.count())
return false;
int source_row = (row >= m->source_rows.count()
? m->source_rows.count()
? m->proxy_rows.count()
: m->source_rows.at(row));
return d->model->insertRows(source_row, count, source_parent);
}
@ -2211,7 +2211,7 @@ bool QSortFilterProxyModel::insertColumns(int column, int count, const QModelInd
if (column > m->source_columns.count())
return false;
int source_column = (column >= m->source_columns.count()
? m->source_columns.count()
? m->proxy_columns.count()
: m->source_columns.at(column));
return d->model->insertColumns(source_column, count, source_parent);
}

View File

@ -152,6 +152,11 @@ private slots:
void emitLayoutChangedOnlyIfSortingChanged();
void checkSetNewModel();
void filterAndInsertRow_data();
void filterAndInsertRow();
void filterAndInsertColumn_data();
void filterAndInsertColumn();
protected:
void buildHierarchy(const QStringList &data, QAbstractItemModel *model);
void checkHierarchy(const QStringList &data, const QAbstractItemModel *model);
@ -4612,5 +4617,237 @@ void tst_QSortFilterProxyModel::checkSetNewModel()
QCoreApplication::processEvents();
}
enum ColumnFilterMode {
FilterNothing,
FilterOutMiddle,
FilterOutBeginEnd,
FilterAll
};
Q_DECLARE_METATYPE(ColumnFilterMode)
void tst_QSortFilterProxyModel::filterAndInsertColumn_data()
{
QTest::addColumn<int>("insertCol");
QTest::addColumn<ColumnFilterMode>("filterMode");
QTest::addColumn<QStringList>("expectedModelList");
QTest::addColumn<QStringList>("expectedProxyModelList");
QTest::newRow("at_beginning_filter_out_middle")
<< 0
<< FilterOutMiddle
<< QStringList{{"", "A1", "B1", "C1", "D1"}}
<< QStringList{{"", "D1"}}
;
QTest::newRow("at_end_filter_out_middle")
<< 2
<< FilterOutMiddle
<< QStringList{{"A1", "B1", "C1", "D1", ""}}
<< QStringList{{"A1", ""}}
;
QTest::newRow("in_the_middle_filter_out_middle")
<< 1
<< FilterOutMiddle
<< QStringList{{"A1", "B1", "C1", "", "D1"}}
<< QStringList{{"A1", "D1"}}
;
QTest::newRow("at_beginning_filter_out_begin_and_end")
<< 0
<< FilterOutBeginEnd
<< QStringList{{"A1", "", "B1", "C1", "D1"}}
<< QStringList{{"", "B1", "C1"}}
;
QTest::newRow("at_end_filter_out_begin_and_end")
<< 2
<< FilterOutBeginEnd
<< QStringList{{"A1", "B1", "C1", "D1", ""}}
<< QStringList{{"B1", "C1", "D1"}}
;
QTest::newRow("in_the_middle_filter_out_begin_and_end")
<< 1
<< FilterOutBeginEnd
<< QStringList{{"A1", "B1", "", "C1", "D1"}}
<< QStringList{{"B1", "", "C1"}}
;
QTest::newRow("at_beginning_filter_nothing")
<< 0
<< FilterAll
<< QStringList{{"", "A1", "B1", "C1", "D1"}}
<< QStringList{{"", "A1", "B1", "C1", "D1"}}
;
QTest::newRow("at_end_filter_nothing")
<< 4
<< FilterAll
<< QStringList{{"A1", "B1", "C1", "D1", ""}}
<< QStringList{{"A1", "B1", "C1", "D1", ""}}
;
QTest::newRow("in_the_middle_nothing")
<< 2
<< FilterAll
<< QStringList{{"A1", "B1", "", "C1", "D1"}}
<< QStringList{{"A1", "B1", "", "C1", "D1"}}
;
QTest::newRow("filter_all")
<< 0
<< FilterNothing
<< QStringList{{"A1", "B1", "C1", "D1", ""}}
<< QStringList{}
;
}
void tst_QSortFilterProxyModel::filterAndInsertColumn()
{
class ColumnFilterProxy : public QSortFilterProxyModel {
Q_DISABLE_COPY(ColumnFilterProxy)
ColumnFilterMode filerMode;
public:
ColumnFilterProxy(ColumnFilterMode mode)
: filerMode(mode)
{}
bool filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const override
{
Q_UNUSED(source_parent)
switch (filerMode){
case FilterAll:
return true;
case FilterNothing:
return false;
case FilterOutMiddle:
return source_column == 0 || source_column == sourceModel()->columnCount() - 1;
case FilterOutBeginEnd:
return source_column > 0 && source_column< sourceModel()->columnCount() - 1;
}
Q_UNREACHABLE();
}
};
QFETCH(int, insertCol);
QFETCH(ColumnFilterMode, filterMode);
QFETCH(QStringList, expectedModelList);
QFETCH(QStringList, expectedProxyModelList);
QStandardItemModel model;
model.insertColumns(0, 4);
model.insertRows(0, 1);
for (int i = 0; i < model.rowCount(); ++i) {
for (int j = 0; j < model.columnCount(); ++j)
model.setData(model.index(i, j), QString('A' + j) + QString::number(i + 1));
}
ColumnFilterProxy proxy(filterMode);
proxy.setSourceModel(&model);
QVERIFY(proxy.insertColumn(insertCol));
proxy.invalidate();
QStringList modelStringList;
for (int i = 0; i < model.rowCount(); ++i) {
for (int j = 0; j < model.columnCount(); ++j)
modelStringList.append(model.index(i, j).data().toString());
}
QCOMPARE(expectedModelList, modelStringList);
modelStringList.clear();
for (int i = 0; i < proxy.rowCount(); ++i) {
for (int j = 0; j < proxy.columnCount(); ++j)
modelStringList.append(proxy.index(i, j).data().toString());
}
QCOMPARE(expectedProxyModelList, modelStringList);
}
void tst_QSortFilterProxyModel::filterAndInsertRow_data()
{
QTest::addColumn<QStringList>("initialModelList");
QTest::addColumn<int>("row");
QTest::addColumn<QString>("filterRegExp");
QTest::addColumn<QStringList>("expectedModelList");
QTest::addColumn<QStringList>("expectedProxyModelList");
QTest::newRow("at_beginning_filter_out_middle")
<< QStringList{{"A5", "B5", "B6", "A7"}}
<< 0
<< "^A"
<< QStringList{{"", "A5", "B5", "B6", "A7"}}
<< QStringList{{"A5", "A7"}};
QTest::newRow("at_end_filter_out_middle")
<< QStringList{{"A5", "B5", "B6", "A7"}}
<< 2
<< "^A"
<< QStringList{{"A5", "B5", "B6", "A7", ""}}
<< QStringList{{"A5", "A7"}};
QTest::newRow("in_the_middle_filter_out_middle")
<< QStringList{{"A5", "B5", "B6", "A7"}}
<< 1
<< "^A"
<< QStringList{{"A5", "B5", "B6", "", "A7"}}
<< QStringList{{"A5", "A7"}};
QTest::newRow("at_beginning_filter_out_first_and_last")
<< QStringList{{"A5", "B5", "B6", "A7"}}
<< 0
<< "^B"
<< QStringList{{"A5", "", "B5", "B6", "A7"}}
<< QStringList{{"B5", "B6"}};
QTest::newRow("at_end_filter_out_first_and_last")
<< QStringList{{"A5", "B5", "B6", "A7"}}
<< 2
<< "^B"
<< QStringList{{"A5", "B5", "B6", "A7", ""}}
<< QStringList{{"B5", "B6"}};
QTest::newRow("in_the_middle_filter_out_first_and_last")
<< QStringList{{"A5", "B5", "B6", "A7"}}
<< 1
<< "^B"
<< QStringList{{"A5", "B5", "", "B6", "A7"}}
<< QStringList{{"B5", "B6"}};
QTest::newRow("at_beginning_no_filter")
<< QStringList{{"A5", "B5", "B6", "A7"}}
<< 0
<< ".*"
<< QStringList{{"", "A5", "B5", "B6", "A7"}}
<< QStringList{{"", "A5", "B5", "B6", "A7"}};
QTest::newRow("at_end_no_filter")
<< QStringList{{"A5", "B5", "B6", "A7"}}
<< 4
<< ".*"
<< QStringList{{"A5", "B5", "B6", "A7", ""}}
<< QStringList{{"A5", "B5", "B6", "A7", ""}};
QTest::newRow("in_the_middle_no_filter")
<< QStringList{{"A5", "B5", "B6", "A7"}}
<< 2
<< ".*"
<< QStringList{{"A5", "B5", "", "B6", "A7"}}
<< QStringList{{"A5", "B5", "", "B6", "A7"}};
QTest::newRow("filter_all")
<< QStringList{{"A5", "B5", "B6", "A7"}}
<< 0
<< "$a"
<< QStringList{{"A5", "B5", "B6", "A7", ""}}
<< QStringList{};
}
void tst_QSortFilterProxyModel::filterAndInsertRow()
{
QFETCH(QStringList, initialModelList);
QFETCH(int, row);
QFETCH(QString, filterRegExp);
QFETCH(QStringList, expectedModelList);
QFETCH(QStringList, expectedProxyModelList);
QStringListModel model;
QSortFilterProxyModel proxyModel;
model.setStringList(initialModelList);
proxyModel.setSourceModel(&model);
proxyModel.setDynamicSortFilter(true);
proxyModel.setFilterRegExp(filterRegExp);
QVERIFY(proxyModel.insertRow(row));
QCOMPARE(model.stringList(), expectedModelList);
QCOMPARE(proxyModel.rowCount(), expectedProxyModelList.count());
for (int r = 0; r < proxyModel.rowCount(); ++r) {
QModelIndex index = proxyModel.index(r, 0);
QVERIFY(index.isValid());
QCOMPARE(proxyModel.data(index).toString(), expectedProxyModelList.at(r));
}
}
QTEST_MAIN(tst_QSortFilterProxyModel)
#include "tst_qsortfilterproxymodel.moc"