QSortFilterProxyModel: add endFilterChange, deprecate invalidateFilter

This adds the typical end*() call to match the beginFilterChange() call
introduced by 00ce45efe16ff440651746a94c62e0d5c1f6e435. Pairing those
calls is necessary to make sure that the model can keep track of changes
between the old to the new filtering and emit the correct signals.

By deprecating the invalidateFilter() functions, we also make it clear
that existing code needs to be ported to the new API calls to avoid the
potentially incorrect or missing signal emissions.

Introduce a new FilterDirection enum with flag type FilterDirections
to indicate whether a row- or column-filter (or a filter impacting both
directions) changed. Replace the internal Directions enum with that,
it's no longer necessary.

Task-number: QTBUG-115717
Change-Id: I31c43ba846d665ef26c8a013d064421484f006cb
Reviewed-by: David Faure <david.faure@kdab.com>
This commit is contained in:
Volker Hilsheimer 2024-12-22 13:33:18 +01:00
parent 40ad963e1a
commit 4605f0fd81
4 changed files with 173 additions and 110 deletions

View File

@ -17,7 +17,7 @@ void MySortFilterProxyModel::setFilterMinimumDate(QDate date)
{
beginFilterChange();
minDate = date;
invalidateRowsFilter();
endFilterChange(QSortFilterProxyModel::Direction::Rows);
}
//! [1]
@ -26,7 +26,7 @@ void MySortFilterProxyModel::setFilterMaximumDate(QDate date)
{
beginFilterChange();
maxDate = date;
invalidateRowsFilter();
endFilterChange(QSortFilterProxyModel::Direction::Rows);
}
//! [2]

View File

@ -111,12 +111,6 @@ class QSortFilterProxyModelPrivate : public QAbstractProxyModelPrivate
public:
Q_DECLARE_PUBLIC(QSortFilterProxyModel)
enum class Direction {
Rows = 1,
Columns = 2,
All = Rows | Columns
};
struct Mapping {
QList<int> source_rows;
QList<int> source_columns;
@ -327,6 +321,8 @@ public:
void _q_clearMapping();
using Direction = QSortFilterProxyModel::Direction;
using Directions = QSortFilterProxyModel::Directions;
void sort();
bool update_source_sort_column();
int find_source_sort_column() const;
@ -334,29 +330,29 @@ public:
const QModelIndex &source_parent) const;
QList<std::pair<int, QList<int>>> proxy_intervals_for_source_items_to_add(
const QList<int> &proxy_to_source, const QList<int> &source_items,
const QModelIndex &source_parent, Qt::Orientation orient) const;
const QModelIndex &source_parent, Direction direction) const;
QList<std::pair<int, int>> proxy_intervals_for_source_items(
const QList<int> &source_to_proxy, const QList<int> &source_items) const;
void insert_source_items(
QList<int> &source_to_proxy, QList<int> &proxy_to_source,
const QList<int> &source_items, const QModelIndex &source_parent,
Qt::Orientation orient, bool emit_signal = true);
Direction direction, bool emit_signal = true);
void remove_source_items(
QList<int> &source_to_proxy, QList<int> &proxy_to_source,
const QList<int> &source_items, const QModelIndex &source_parent,
Qt::Orientation orient, bool emit_signal = true);
Direction direction, bool emit_signal = true);
void remove_proxy_interval(
QList<int> &source_to_proxy, QList<int> &proxy_to_source,
int proxy_start, int proxy_end, const QModelIndex &proxy_parent,
Qt::Orientation orient, bool emit_signal = true);
Direction direction, bool emit_signal = true);
static inline void build_source_to_proxy_mapping(
const QList<int> &proxy_to_source, QList<int> &source_to_proxy, int start = 0);
void source_items_inserted(const QModelIndex &source_parent,
int start, int end, Qt::Orientation orient);
int start, int end, Direction direction);
void source_items_about_to_be_removed(const QModelIndex &source_parent,
int start, int end, Qt::Orientation orient);
int start, int end, Direction direction);
void source_items_removed(const QModelIndex &source_parent,
int start, int end, Qt::Orientation orient);
int start, int end, Direction direction);
void proxy_item_range(
const QList<int> &source_to_proxy, const QList<int> &source_items,
int &proxy_low, int &proxy_high) const;
@ -365,13 +361,13 @@ public:
void update_persistent_indexes(const QModelIndexPairList &source_indexes);
void filter_about_to_be_changed(const QModelIndex &source_parent = QModelIndex());
void filter_changed(Direction dir, const QModelIndex &source_parent = QModelIndex());
void filter_changed(Directions directions, const QModelIndex &source_parent = QModelIndex());
QSet<int> handle_filter_changed(
QList<int> &source_to_proxy, QList<int> &proxy_to_source,
const QModelIndex &source_parent, Qt::Orientation orient);
const QModelIndex &source_parent, Direction direction);
void updateChildrenMapping(const QModelIndex &source_parent, Mapping *parent_mapping,
Qt::Orientation orient, int start, int end, int delta_item_count, bool remove);
Direction direction, int start, int end, int delta_item_count, bool remove);
void _q_sourceModelDestroyed() override;
@ -384,11 +380,6 @@ public:
typedef QHash<QtPrivate::QModelIndexWrapper, QSortFilterProxyModelPrivate::Mapping *> IndexMap;
static bool operator&(QSortFilterProxyModelPrivate::Direction a, QSortFilterProxyModelPrivate::Direction b)
{
return int(a) & int(b);
}
void QSortFilterProxyModelPrivate::_q_sourceModelDestroyed()
{
QAbstractProxyModelPrivate::_q_sourceModelDestroyed();
@ -745,7 +736,7 @@ QList<std::pair<int, int>> QSortFilterProxyModelPrivate::proxy_intervals_for_sou
/*!
\internal
Given source-to-proxy mapping \a src_to_proxy and proxy-to-source mapping
Given source-to-proxy mapping \a source_to_proxy and proxy-to-source mapping
\a proxy_to_source, removes \a source_items from this proxy model.
The corresponding proxy items are removed in intervals, so that the proper
rows/columnsRemoved(start, end) signals will be generated.
@ -753,7 +744,7 @@ QList<std::pair<int, int>> QSortFilterProxyModelPrivate::proxy_intervals_for_sou
void QSortFilterProxyModelPrivate::remove_source_items(
QList<int> &source_to_proxy, QList<int> &proxy_to_source,
const QList<int> &source_items, const QModelIndex &source_parent,
Qt::Orientation orient, bool emit_signal)
Direction direction, bool emit_signal)
{
Q_Q(QSortFilterProxyModel);
QModelIndex proxy_parent = q->mapFromSource(source_parent);
@ -771,7 +762,7 @@ void QSortFilterProxyModelPrivate::remove_source_items(
const int proxy_start = interval.first;
const int proxy_end = interval.second;
remove_proxy_interval(source_to_proxy, proxy_to_source, proxy_start, proxy_end,
proxy_parent, orient, emit_signal);
proxy_parent, direction, emit_signal);
}
}
@ -784,11 +775,11 @@ void QSortFilterProxyModelPrivate::remove_source_items(
*/
void QSortFilterProxyModelPrivate::remove_proxy_interval(
QList<int> &source_to_proxy, QList<int> &proxy_to_source, int proxy_start, int proxy_end,
const QModelIndex &proxy_parent, Qt::Orientation orient, bool emit_signal)
const QModelIndex &proxy_parent, Direction direction, bool emit_signal)
{
Q_Q(QSortFilterProxyModel);
if (emit_signal) {
if (orient == Qt::Vertical)
if (direction == Direction::Rows)
q->beginRemoveRows(proxy_parent, proxy_start, proxy_end);
else
q->beginRemoveColumns(proxy_parent, proxy_start, proxy_end);
@ -802,7 +793,7 @@ void QSortFilterProxyModelPrivate::remove_proxy_interval(
build_source_to_proxy_mapping(proxy_to_source, source_to_proxy, proxy_start);
if (emit_signal) {
if (orient == Qt::Vertical)
if (direction == Direction::Rows)
q->endRemoveRows();
else
q->endRemoveColumns();
@ -823,7 +814,7 @@ void QSortFilterProxyModelPrivate::remove_proxy_interval(
*/
QList<std::pair<int, QList<int>>> QSortFilterProxyModelPrivate::proxy_intervals_for_source_items_to_add(
const QList<int> &proxy_to_source, const QList<int> &source_items,
const QModelIndex &source_parent, Qt::Orientation orient) const
const QModelIndex &source_parent, Direction direction) const
{
Q_Q(const QSortFilterProxyModel);
QList<std::pair<int, QList<int>>> proxy_intervals;
@ -833,7 +824,7 @@ QList<std::pair<int, QList<int>>> QSortFilterProxyModelPrivate::proxy_intervals_
int proxy_low = 0;
int proxy_item = 0;
int source_items_index = 0;
bool compare = (orient == Qt::Vertical && source_sort_column >= 0 && dynamic_sortfilter);
bool compare = (direction == Direction::Rows && source_sort_column >= 0 && dynamic_sortfilter);
while (source_items_index < source_items.size()) {
QList<int> source_items_in_interval;
int first_new_source_item = source_items.at(source_items_index);
@ -897,7 +888,7 @@ QList<std::pair<int, QList<int>>> QSortFilterProxyModelPrivate::proxy_intervals_
void QSortFilterProxyModelPrivate::insert_source_items(
QList<int> &source_to_proxy, QList<int> &proxy_to_source,
const QList<int> &source_items, const QModelIndex &source_parent,
Qt::Orientation orient, bool emit_signal)
Direction direction, bool emit_signal)
{
Q_Q(QSortFilterProxyModel);
QModelIndex proxy_parent = q->mapFromSource(source_parent);
@ -905,7 +896,7 @@ void QSortFilterProxyModelPrivate::insert_source_items(
return; // nothing to do (source_parent is not mapped)
const auto proxy_intervals = proxy_intervals_for_source_items_to_add(
proxy_to_source, source_items, source_parent, orient);
proxy_to_source, source_items, source_parent, direction);
const auto end = proxy_intervals.rend();
for (auto it = proxy_intervals.rbegin(); it != end; ++it) {
@ -915,7 +906,7 @@ void QSortFilterProxyModelPrivate::insert_source_items(
const int proxy_end = proxy_start + source_items.size() - 1;
if (emit_signal) {
if (orient == Qt::Vertical)
if (direction == Direction::Rows)
q->beginInsertRows(proxy_parent, proxy_start, proxy_end);
else
q->beginInsertColumns(proxy_parent, proxy_start, proxy_end);
@ -928,7 +919,7 @@ void QSortFilterProxyModelPrivate::insert_source_items(
build_source_to_proxy_mapping(proxy_to_source, source_to_proxy, proxy_start);
if (emit_signal) {
if (orient == Qt::Vertical)
if (direction == Direction::Rows)
q->endInsertRows();
else
q->endInsertColumns();
@ -949,7 +940,7 @@ void QSortFilterProxyModelPrivate::insert_source_items(
signals will be generated.
*/
void QSortFilterProxyModelPrivate::source_items_inserted(
const QModelIndex &source_parent, int start, int end, Qt::Orientation orient)
const QModelIndex &source_parent, int start, int end, Direction direction)
{
Q_Q(QSortFilterProxyModel);
if ((start < 0) || (end < 0))
@ -973,13 +964,13 @@ void QSortFilterProxyModelPrivate::source_items_inserted(
}
Mapping *m = it.value();
QList<int> &source_to_proxy = (orient == Qt::Vertical) ? m->proxy_rows : m->proxy_columns;
QList<int> &proxy_to_source = (orient == Qt::Vertical) ? m->source_rows : m->source_columns;
QList<int> &source_to_proxy = (direction == Direction::Rows) ? m->proxy_rows : m->proxy_columns;
QList<int> &proxy_to_source = (direction == Direction::Rows) ? m->source_rows : m->source_columns;
int delta_item_count = end - start + 1;
int old_item_count = source_to_proxy.size();
updateChildrenMapping(source_parent, m, orient, start, end, delta_item_count, false);
updateChildrenMapping(source_parent, m, direction, start, end, delta_item_count, false);
// Expand source-to-proxy mapping to account for new items
if (start < 0 || start > source_to_proxy.size()) {
@ -1003,7 +994,7 @@ void QSortFilterProxyModelPrivate::source_items_inserted(
// Figure out which items to add to mapping based on filter
QList<int> source_items;
for (int i = start; i <= end; ++i) {
if ((orient == Qt::Vertical)
if ((direction == Direction::Rows)
? filterAcceptsRowInternal(i, source_parent)
: q->filterAcceptsColumn(i, source_parent)) {
source_items.append(i);
@ -1015,21 +1006,21 @@ void QSortFilterProxyModelPrivate::source_items_inserted(
// If it was new rows make sure to create mappings for columns so that a
// valid mapping can be retrieved later and vice-versa.
QList<int> &orthogonal_proxy_to_source = (orient == Qt::Horizontal) ? m->source_rows : m->source_columns;
QList<int> &orthogonal_source_to_proxy = (orient == Qt::Horizontal) ? m->proxy_rows : m->proxy_columns;
QList<int> &orthogonal_proxy_to_source = (direction == Direction::Columns) ? m->source_rows : m->source_columns;
QList<int> &orthogonal_source_to_proxy = (direction == Direction::Columns) ? m->proxy_rows : m->proxy_columns;
if (orthogonal_source_to_proxy.isEmpty()) {
const int ortho_end = (orient == Qt::Horizontal) ? model->rowCount(source_parent) : model->columnCount(source_parent);
const int ortho_end = (direction == Direction::Columns) ? model->rowCount(source_parent) : model->columnCount(source_parent);
orthogonal_source_to_proxy.resize(ortho_end);
for (int ortho_item = 0; ortho_item < ortho_end; ++ortho_item) {
if ((orient == Qt::Horizontal) ? filterAcceptsRowInternal(ortho_item, source_parent)
if ((direction == Direction::Columns) ? filterAcceptsRowInternal(ortho_item, source_parent)
: q->filterAcceptsColumn(ortho_item, source_parent)) {
orthogonal_proxy_to_source.append(ortho_item);
}
}
if (orient == Qt::Horizontal) {
if (direction == Direction::Columns) {
// We're reacting to columnsInserted, but we've just inserted new rows. Sort them.
sort_source_rows(orthogonal_proxy_to_source, source_parent);
}
@ -1038,9 +1029,9 @@ void QSortFilterProxyModelPrivate::source_items_inserted(
}
// Sort and insert the items
if (orient == Qt::Vertical) // Only sort rows
if (direction == Direction::Rows) // Only sort rows
sort_source_rows(source_items, source_parent);
insert_source_items(source_to_proxy, proxy_to_source, source_items, source_parent, orient);
insert_source_items(source_to_proxy, proxy_to_source, source_items, source_parent, direction);
}
/*!
@ -1050,7 +1041,7 @@ void QSortFilterProxyModelPrivate::source_items_inserted(
(columnsAboutToBeRemoved(), rowsAboutToBeRemoved()).
*/
void QSortFilterProxyModelPrivate::source_items_about_to_be_removed(
const QModelIndex &source_parent, int start, int end, Qt::Orientation orient)
const QModelIndex &source_parent, int start, int end, Direction direction)
{
if ((start < 0) || (end < 0))
return;
@ -1061,8 +1052,8 @@ void QSortFilterProxyModelPrivate::source_items_about_to_be_removed(
}
Mapping *m = it.value();
QList<int> &source_to_proxy = (orient == Qt::Vertical) ? m->proxy_rows : m->proxy_columns;
QList<int> &proxy_to_source = (orient == Qt::Vertical) ? m->source_rows : m->source_columns;
QList<int> &source_to_proxy = (direction == Direction::Rows) ? m->proxy_rows : m->proxy_columns;
QList<int> &proxy_to_source = (direction == Direction::Rows) ? m->source_rows : m->source_columns;
// figure out which items to remove
QList<int> source_items_to_remove;
@ -1074,7 +1065,7 @@ void QSortFilterProxyModelPrivate::source_items_about_to_be_removed(
}
remove_source_items(source_to_proxy, proxy_to_source, source_items_to_remove,
source_parent, orient);
source_parent, direction);
}
/*!
@ -1083,7 +1074,7 @@ void QSortFilterProxyModelPrivate::source_items_about_to_be_removed(
Handles source model items removal (columnsRemoved(), rowsRemoved()).
*/
void QSortFilterProxyModelPrivate::source_items_removed(
const QModelIndex &source_parent, int start, int end, Qt::Orientation orient)
const QModelIndex &source_parent, int start, int end, Direction direction)
{
if ((start < 0) || (end < 0))
return;
@ -1094,8 +1085,8 @@ void QSortFilterProxyModelPrivate::source_items_removed(
}
Mapping *m = it.value();
QList<int> &source_to_proxy = (orient == Qt::Vertical) ? m->proxy_rows : m->proxy_columns;
QList<int> &proxy_to_source = (orient == Qt::Vertical) ? m->source_rows : m->source_columns;
QList<int> &source_to_proxy = (direction == Direction::Rows) ? m->proxy_rows : m->proxy_columns;
QList<int> &proxy_to_source = (direction == Direction::Rows) ? m->source_rows : m->source_columns;
if (end >= source_to_proxy.size())
end = source_to_proxy.size() - 1;
@ -1125,7 +1116,7 @@ void QSortFilterProxyModelPrivate::source_items_removed(
}
build_source_to_proxy_mapping(proxy_to_source, source_to_proxy);
updateChildrenMapping(source_parent, m, orient, start, end, delta_item_count, true);
updateChildrenMapping(source_parent, m, direction, start, end, delta_item_count, true);
}
@ -1135,14 +1126,14 @@ void QSortFilterProxyModelPrivate::source_items_removed(
updates the mapping of the children when inserting or removing items
*/
void QSortFilterProxyModelPrivate::updateChildrenMapping(const QModelIndex &source_parent, Mapping *parent_mapping,
Qt::Orientation orient, int start, int end, int delta_item_count, bool remove)
Direction direction, int start, int end, int delta_item_count, bool remove)
{
// see if any mapped children should be (re)moved
QList<std::pair<QModelIndex, Mapping *>> moved_source_index_mappings;
auto it2 = parent_mapping->mapped_children.begin();
for ( ; it2 != parent_mapping->mapped_children.end();) {
const QModelIndex source_child_index = *it2;
const int pos = (orient == Qt::Vertical)
const int pos = (direction == Direction::Rows)
? source_child_index.row()
: source_child_index.column();
if (pos < start) {
@ -1156,7 +1147,7 @@ void QSortFilterProxyModelPrivate::updateChildrenMapping(const QModelIndex &sour
// below the removed items -- recompute the index
QModelIndex new_index;
const int newpos = remove ? pos - delta_item_count : pos + delta_item_count;
if (orient == Qt::Vertical) {
if (direction == Direction::Rows) {
new_index = model->index(newpos,
source_child_index.column(),
source_parent);
@ -1280,14 +1271,21 @@ void QSortFilterProxyModelPrivate::filter_about_to_be_changed(const QModelIndex
Updates the proxy model (adds/removes rows) based on the
new filter.
*/
void QSortFilterProxyModelPrivate::filter_changed(Direction dir, const QModelIndex &source_parent)
void QSortFilterProxyModelPrivate::filter_changed(Directions directions,
const QModelIndex &source_parent)
{
IndexMap::const_iterator it = source_index_mapping.constFind(source_parent);
if (it == source_index_mapping.constEnd())
return;
Mapping *m = it.value();
const QSet<int> rows_removed = (dir & Direction::Rows) ? handle_filter_changed(m->proxy_rows, m->source_rows, source_parent, Qt::Vertical) : QSet<int>();
const QSet<int> columns_removed = (dir & Direction::Columns) ? handle_filter_changed(m->proxy_columns, m->source_columns, source_parent, Qt::Horizontal) : QSet<int>();
const QSet<int> rows_removed = (directions & Direction::Rows)
? handle_filter_changed(m->proxy_rows, m->source_rows, source_parent,
Direction::Rows)
: QSet<int>();
const QSet<int> columns_removed = (directions & Direction::Columns)
? handle_filter_changed(m->proxy_columns, m->source_columns, source_parent,
Direction::Columns)
: QSet<int>();
// We need to iterate over a copy of m->mapped_children because otherwise it may be changed by other code, invalidating
// the iterator it2.
@ -1301,7 +1299,7 @@ void QSortFilterProxyModelPrivate::filter_changed(Direction dir, const QModelInd
indexesToRemove.push_back(i);
remove_from_mapping(source_child_index);
} else {
filter_changed(dir, source_child_index);
filter_changed(directions, source_child_index);
}
}
QList<int>::const_iterator removeIt = indexesToRemove.constEnd();
@ -1324,14 +1322,14 @@ void QSortFilterProxyModelPrivate::filter_changed(Direction dir, const QModelInd
*/
QSet<int> QSortFilterProxyModelPrivate::handle_filter_changed(
QList<int> &source_to_proxy, QList<int> &proxy_to_source,
const QModelIndex &source_parent, Qt::Orientation orient)
const QModelIndex &source_parent, Direction direction)
{
Q_Q(QSortFilterProxyModel);
// Figure out which mapped items to remove
QList<int> source_items_remove;
for (int i = 0; i < proxy_to_source.size(); ++i) {
const int source_item = proxy_to_source.at(i);
if ((orient == Qt::Vertical)
if ((direction == Direction::Rows)
? !filterAcceptsRowInternal(source_item, source_parent)
: !q->filterAcceptsColumn(source_item, source_parent)) {
// This source item does not satisfy the filter, so it must be removed
@ -1343,7 +1341,7 @@ QSet<int> QSortFilterProxyModelPrivate::handle_filter_changed(
int source_count = source_to_proxy.size();
for (int source_item = 0; source_item < source_count; ++source_item) {
if (source_to_proxy.at(source_item) == -1) {
if ((orient == Qt::Vertical)
if ((direction == Direction::Rows)
? filterAcceptsRowInternal(source_item, source_parent)
: q->filterAcceptsColumn(source_item, source_parent)) {
// This source item satisfies the filter, so it must be added
@ -1354,11 +1352,11 @@ QSet<int> QSortFilterProxyModelPrivate::handle_filter_changed(
if (!source_items_remove.isEmpty() || !source_items_insert.isEmpty()) {
// Do item removal and insertion
remove_source_items(source_to_proxy, proxy_to_source,
source_items_remove, source_parent, orient);
if (orient == Qt::Vertical)
source_items_remove, source_parent, direction);
if (direction == Direction::Rows)
sort_source_rows(source_items_insert, source_parent);
insert_source_items(source_to_proxy, proxy_to_source,
source_items_insert, source_parent, orient);
source_items_insert, source_parent, direction);
}
return qListToSet(source_items_remove);
}
@ -1465,7 +1463,7 @@ void QSortFilterProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &sourc
if (!source_rows_remove.isEmpty()) {
remove_source_items(m->proxy_rows, m->source_rows,
source_rows_remove, source_parent, Qt::Vertical);
source_rows_remove, source_parent, Direction::Rows);
QSet<int> source_rows_remove_set = qListToSet(source_rows_remove);
QList<QModelIndex>::iterator childIt = m->mapped_children.end();
while (childIt != m->mapped_children.begin()) {
@ -1486,10 +1484,10 @@ void QSortFilterProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &sourc
emit q->layoutAboutToBeChanged(parents, QAbstractItemModel::VerticalSortHint);
QModelIndexPairList source_indexes = store_persistent_indexes();
remove_source_items(m->proxy_rows, m->source_rows, source_rows_resort,
source_parent, Qt::Vertical, false);
source_parent, Direction::Rows, false);
sort_source_rows(source_rows_resort, source_parent);
insert_source_items(m->proxy_rows, m->source_rows, source_rows_resort,
source_parent, Qt::Vertical, false);
source_parent, Direction::Rows, false);
update_persistent_indexes(source_indexes);
emit q->layoutChanged(parents, QAbstractItemModel::VerticalSortHint);
}
@ -1529,7 +1527,7 @@ void QSortFilterProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &sourc
if (!source_rows_insert.isEmpty()) {
sort_source_rows(source_rows_insert, source_parent);
insert_source_items(m->proxy_rows, m->source_rows,
source_rows_insert, source_parent, Qt::Vertical);
source_rows_insert, source_parent, Direction::Rows);
}
}
}
@ -1682,7 +1680,7 @@ void QSortFilterProxyModelPrivate::_q_sourceRowsInserted(
if (!filter_recursive || complete_insert) {
if (filter_recursive)
complete_insert = false;
source_items_inserted(source_parent, start, end, Qt::Vertical);
source_items_inserted(source_parent, start, end, Direction::Rows);
if (update_source_sort_column() && dynamic_sortfilter) //previous call to update_source_sort_column may fail if the model has no column.
sort(); // now it should succeed so we need to make sure to sort again
return;
@ -1711,14 +1709,14 @@ void QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeRemoved(
{
itemsBeingRemoved = QRowsRemoval(source_parent, start, end);
source_items_about_to_be_removed(source_parent, start, end,
Qt::Vertical);
Direction::Rows);
}
void QSortFilterProxyModelPrivate::_q_sourceRowsRemoved(
const QModelIndex &source_parent, int start, int end)
{
itemsBeingRemoved = QRowsRemoval();
source_items_removed(source_parent, start, end, Qt::Vertical);
source_items_removed(source_parent, start, end, Direction::Rows);
if (filter_recursive) {
// Find out if removing this visible row means that some ascendant
@ -1783,7 +1781,7 @@ void QSortFilterProxyModelPrivate::_q_sourceColumnsInserted(
const QModelIndex &source_parent, int start, int end)
{
Q_Q(const QSortFilterProxyModel);
source_items_inserted(source_parent, start, end, Qt::Horizontal);
source_items_inserted(source_parent, start, end, Direction::Columns);
if (source_parent.isValid())
return; //we sort according to the root column only
@ -1803,14 +1801,14 @@ void QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeRemoved(
const QModelIndex &source_parent, int start, int end)
{
source_items_about_to_be_removed(source_parent, start, end,
Qt::Horizontal);
Direction::Columns);
}
void QSortFilterProxyModelPrivate::_q_sourceColumnsRemoved(
const QModelIndex &source_parent, int start, int end)
{
Q_Q(const QSortFilterProxyModel);
source_items_removed(source_parent, start, end, Qt::Horizontal);
source_items_removed(source_parent, start, end, Direction::Columns);
if (source_parent.isValid())
return; //we sort according to the root column only
@ -1981,11 +1979,11 @@ void QSortFilterProxyModelPrivate::_q_sourceColumnsMoved(
example.)
If you are working with large amounts of filtering and have to invoke
invalidateFilter() repeatedly, using beginResetModel() / endResetModel() may
be more efficient, depending on the implementation of your model. However,
beginResetModel() / endResetModel() returns the
proxy model to its original state, losing selection information, and will
cause the proxy model to be repopulated.
beginFilterChange() / endFilterChange() repeatedly, using beginResetModel()
/ endResetModel() may be more efficient, depending on the implementation of
your model. However, beginResetModel() / endResetModel() returns the proxy
model to its original state, losing selection information, and will cause
the proxy model to be repopulated.
\section1 Subclassing
@ -2593,7 +2591,7 @@ void QSortFilterProxyModel::setFilterRegularExpression(const QRegularExpression
d->filter_regularexpression.setValueBypassingBindings(regularExpression);
if (cs != updatedCs)
d->filter_casesensitive.setValueBypassingBindings(updatedCs);
d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
d->filter_changed(Direction::Rows);
// Do not change the evaluation logic, but notify only if the regular
// expression has actually changed.
if (regExpChanged)
@ -2628,7 +2626,7 @@ void QSortFilterProxyModel::setFilterKeyColumn(int column)
d->filter_about_to_be_changed();
const auto oldColumn = d->filter_column.valueBypassingBindings();
d->filter_column.setValueBypassingBindings(column);
d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
d->filter_changed(Direction::Rows);
if (oldColumn != column)
d->filter_column.notify();
}
@ -2685,7 +2683,7 @@ void QSortFilterProxyModel::setFilterCaseSensitivity(Qt::CaseSensitivity cs)
QRegularExpression re = d->filter_regularexpression;
re.setPatternOptions(options);
d->filter_regularexpression.setValueBypassingBindings(re);
d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
d->filter_changed(Direction::Rows);
d->filter_regularexpression.notify();
d->filter_casesensitive.notify();
}
@ -2800,7 +2798,7 @@ void QSortFilterProxyModel::setFilterRegularExpression(const QString &pattern)
d->filter_regularexpression.removeBindingUnlessInWrapper();
d->filter_about_to_be_changed();
d->set_filter_pattern(pattern);
d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
d->filter_changed(Direction::Rows);
d->filter_regularexpression.notify();
}
@ -2824,7 +2822,7 @@ void QSortFilterProxyModel::setFilterWildcard(const QString &pattern)
d->filter_about_to_be_changed();
d->set_filter_pattern(QRegularExpression::wildcardToRegularExpression(
pattern, QRegularExpression::UnanchoredWildcardConversion));
d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
d->filter_changed(Direction::Rows);
d->filter_regularexpression.notify();
}
@ -2847,7 +2845,7 @@ void QSortFilterProxyModel::setFilterFixedString(const QString &pattern)
d->filter_regularexpression.removeBindingUnlessInWrapper();
d->filter_about_to_be_changed();
d->set_filter_pattern(QRegularExpression::escape(pattern));
d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
d->filter_changed(Direction::Rows);
d->filter_regularexpression.notify();
}
@ -2967,7 +2965,7 @@ void QSortFilterProxyModel::setFilterRole(int role)
return;
d->filter_about_to_be_changed();
d->filter_role.setValueBypassingBindings(role);
d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
d->filter_changed(Direction::Rows);
d->filter_role.notify(); // also emits a signal
}
@ -3009,7 +3007,7 @@ void QSortFilterProxyModel::setRecursiveFilteringEnabled(bool recursive)
return;
d->filter_about_to_be_changed();
d->filter_recursive.setValueBypassingBindings(recursive);
d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
d->filter_changed(Direction::Rows);
d->filter_recursive.notify(); // also emits a signal
}
@ -3054,7 +3052,7 @@ void QSortFilterProxyModel::setAutoAcceptChildRows(bool accept)
d->filter_about_to_be_changed();
d->accept_children.setValueBypassingBindings(accept);
d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
d->filter_changed(Direction::Rows);
d->accept_children.notify(); // also emits a signal
}
@ -3069,7 +3067,7 @@ QBindable<bool> QSortFilterProxyModel::bindableAutoAcceptChildRows()
Invalidates the current sorting and filtering.
\sa invalidateFilter()
\sa beginFilterChange(), endFilterChange()
*/
void QSortFilterProxyModel::invalidate()
{
@ -3089,7 +3087,11 @@ void QSortFilterProxyModel::invalidate()
\snippet ../widgets/itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp 2
\sa invalidateFilter(), invalidateColumnsFilter(), invalidateRowsFilter()
Once the filter has been changed, call endFilterChange() with Direction::Rows
for row-filters, Direction::Columns for column-filters, or Direction::Columns|Direction::Rows
if both rows and columns are filtered.
\sa endFilterChange()
*/
void QSortFilterProxyModel::beginFilterChange()
@ -3098,8 +3100,10 @@ void QSortFilterProxyModel::beginFilterChange()
d->create_mapping({});
}
#if QT_DEPRECATED_SINCE(6, 13)
/*!
\since 4.3
\deprecated [6.13] use beginFilterChange() and endFilterChange() instead.
Invalidates the current filtering.
@ -3116,11 +3120,12 @@ void QSortFilterProxyModel::beginFilterChange()
void QSortFilterProxyModel::invalidateFilter()
{
Q_D(QSortFilterProxyModel);
d->filter_changed(QSortFilterProxyModelPrivate::Direction::All);
d->filter_changed(Direction::Columns|Direction::Rows);
}
/*!
\since 6.0
\deprecated [6.13] use beginFilterChange() and endFilterChange(Direction::Rows) instead.
Invalidates the current filtering for the columns.
@ -3138,11 +3143,12 @@ void QSortFilterProxyModel::invalidateFilter()
void QSortFilterProxyModel::invalidateColumnsFilter()
{
Q_D(QSortFilterProxyModel);
d->filter_changed(QSortFilterProxyModelPrivate::Direction::Columns);
d->filter_changed(Direction::Columns);
}
/*!
\since 6.0
\deprecated [6.13] use beginFilterChange() and endFilterChange(Direction::Columns) instead.
Invalidates the current filtering for the rows.
@ -3160,7 +3166,44 @@ void QSortFilterProxyModel::invalidateColumnsFilter()
void QSortFilterProxyModel::invalidateRowsFilter()
{
Q_D(QSortFilterProxyModel);
d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
d->filter_changed(Direction::Rows);
}
#endif // QT_DEPRECATED_SINCE(6, 10)
/*!
\enum QSortFilterProxyModel::Direction
\since 6.10
This enum is used to specify the direction to which a custom filter applies
when the filter parameters are changed.
\value Rows The filter applies to \l{filterAcceptsRow()}{rows}
\value Columns The filter applies to \l{filterAcceptsColumn()}{columns}
\value Both The filter applies to both rows and columns
\sa beginFilterChange(), endFilterChange()
*/
/*!
\since 6.10
Invalidates the current filtering after the filter parameter has changed.
This function should be called if you implement custom filtering (e.g.
filterAcceptsRow()), and your filter parameters have changed. The \a directions
parameter specifies whether the custom filter impacts rows, columns, or both.
Call beginFilterChange() when the filter parameter is about to change, and
follow with a call to this function once the filter parameters have been
changed. Call with \a directions set to Direction::Rows for row-filters
(i.e. filterAcceptsRow() is implemented), Direction::Columns for
column-filters (i.e. filterAcceptsColumn() is implemented),
or \c{Direction::Both} if both filter functions are implemented.
*/
void QSortFilterProxyModel::endFilterChange(QSortFilterProxyModel::Directions directions)
{
Q_D(QSortFilterProxyModel);
d->filter_changed(directions);
}
/*!

View File

@ -101,6 +101,13 @@ public:
void setAutoAcceptChildRows(bool accept);
QBindable<bool> bindableAutoAcceptChildRows();
enum class Direction {
Rows = 0x01,
Columns = 0x02,
Both = Rows | Columns,
};
Q_DECLARE_FLAGS(Directions, Direction)
public Q_SLOTS:
void setFilterRegularExpression(const QString &pattern);
void setFilterRegularExpression(const QRegularExpression &regularExpression);
@ -114,9 +121,15 @@ protected:
virtual bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const;
void beginFilterChange();
void endFilterChange(Directions directions = Direction::Both);
#if QT_DEPRECATED_SINCE(6, 13)
QT_DEPRECATED_VERSION_X_6_13("Use begin/endFilterChange() instead")
void invalidateFilter();
QT_DEPRECATED_VERSION_X_6_13("Use begin/endFilterChange(QSortFilterProxyModel::Direction::Rows) instead")
void invalidateRowsFilter();
QT_DEPRECATED_VERSION_X_6_13("Use begin/endFilterChange(QSortFilterProxyModel::Direction::Columns) instead")
void invalidateColumnsFilter();
#endif
public:
using QObject::parent;
@ -175,6 +188,8 @@ private:
Q_DISABLE_COPY(QSortFilterProxyModel)
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QSortFilterProxyModel::Directions)
QT_END_NAMESPACE
#endif // QSORTFILTERPROXYMODEL_H

View File

@ -3635,7 +3635,7 @@ void tst_QSortFilterProxyModel::resetInvalidate()
endResetModel();
break;
case 2: invalidate(); break;
case 3: invalidateFilter(); break;
case 3: endFilterChange(); break;
}
}
};
@ -4090,7 +4090,7 @@ public slots:
void setMode(bool on)
{
mode = on;
invalidateFilter();
endFilterChange();
}
protected:
@ -4148,7 +4148,7 @@ public slots:
void setMode(bool on)
{
mode = on;
invalidateFilter();
endFilterChange();
}
protected:
@ -5163,7 +5163,8 @@ class SortFilterProxyModel final : public QSortFilterProxyModel
Q_OBJECT
public:
using QSortFilterProxyModel::QSortFilterProxyModel;
using QSortFilterProxyModel::invalidateFilter;
using QSortFilterProxyModel::beginFilterChange;
using QSortFilterProxyModel::endFilterChange;
void setSourceModel(QAbstractItemModel *m) override
{
@ -5209,15 +5210,17 @@ void tst_QSortFilterProxyModel::checkFilteredIndexes()
s.setSourceModel(&m);
s.sort(0);
s.invalidateFilter();
s.endFilterChange();
checkIndexes(s);
s.beginFilterChange();
s.m_filteredRows = 5; // every 5th row is filtered
s.invalidateFilter();
s.endFilterChange();
checkIndexes(s);
s.beginFilterChange();
s.m_filteredRows = 3; // every 3rd row is filtered
s.invalidateFilter();
s.endFilterChange();
checkIndexes(s);
}
@ -5252,6 +5255,8 @@ void tst_QSortFilterProxyModel::invalidateColumnsOrRowsFilter()
using QSortFilterProxyModel::invalidateFilter;
using QSortFilterProxyModel::invalidateRowsFilter;
using QSortFilterProxyModel::invalidateColumnsFilter;
using QSortFilterProxyModel::beginFilterChange;
using QSortFilterProxyModel::endFilterChange;
};
QStandardItemModel model(10, 4);
for (int i = 0; i < model.rowCount(); ++i) {
@ -5271,19 +5276,19 @@ void tst_QSortFilterProxyModel::invalidateColumnsOrRowsFilter()
QCOMPARE(proxy.columnFiltered, 44); // 4 parents + 4 * 10 children
proxy.rowFiltered = proxy.columnFiltered = 0;
proxy.invalidateFilter();
proxy.endFilterChange();
QCOMPARE(proxy.rowFiltered, 20);
QCOMPARE(proxy.columnFiltered, 44);
proxy.rowFiltered = proxy.columnFiltered = 0;
proxy.invalidateRowsFilter();
proxy.endFilterChange(QSortFilterProxyModel::Direction::Rows);
QCOMPARE(proxy.rowFiltered, 20);
QCOMPARE(proxy.columnFiltered, 0);
proxy.rowFiltered = proxy.columnFiltered = 0;
proxy.invalidateColumnsFilter();
proxy.endFilterChange(QSortFilterProxyModel::Direction::Columns);
QCOMPARE(proxy.rowFiltered, 0);
QCOMPARE(proxy.columnFiltered, 44);
@ -5291,12 +5296,12 @@ void tst_QSortFilterProxyModel::invalidateColumnsOrRowsFilter()
QCOMPARE(proxy.rowCount(), 10);
proxy.rejectA1 = true;
proxy.rowFiltered = proxy.columnFiltered = 0;
proxy.invalidateRowsFilter();
proxy.endFilterChange(QSortFilterProxyModel::Direction::Rows);
QCOMPARE(proxy.rowCount(), 9);
QCOMPARE(proxy.rowFiltered, 19); // it will not check the child row of A1
proxy.rowFiltered = proxy.columnFiltered = 0;
proxy.setRecursiveFilteringEnabled(true); // this triggers invalidateRowsFilter()
proxy.setRecursiveFilteringEnabled(true); // this triggers endFilterChange(QSortFilterProxyModel::Direction::Rows)
QCOMPARE(proxy.rowCount(), 10);
QCOMPARE(proxy.rowFiltered, 20);
}
@ -5512,7 +5517,7 @@ void tst_QSortFilterProxyModel::filterChangeEmitsModelChangedSignals()
beginFilterChange();
m_matchString = s;
invalidateFilter();
endFilterChange();
}
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override