From 4605f0fd81497688664deee025de40f44837c10d Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Sun, 22 Dec 2024 13:33:18 +0100 Subject: [PATCH] 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 --- .../mysortfilterproxymodel.cpp | 4 +- .../itemmodels/qsortfilterproxymodel.cpp | 233 +++++++++++------- .../itemmodels/qsortfilterproxymodel.h | 15 ++ .../tst_qsortfilterproxymodel.cpp | 31 ++- 4 files changed, 173 insertions(+), 110 deletions(-) diff --git a/examples/widgets/itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp b/examples/widgets/itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp index 841b395bf98..d5e0376c48b 100644 --- a/examples/widgets/itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp +++ b/examples/widgets/itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp @@ -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] diff --git a/src/corelib/itemmodels/qsortfilterproxymodel.cpp b/src/corelib/itemmodels/qsortfilterproxymodel.cpp index 774dcfd9794..4bc09862e96 100644 --- a/src/corelib/itemmodels/qsortfilterproxymodel.cpp +++ b/src/corelib/itemmodels/qsortfilterproxymodel.cpp @@ -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 source_rows; QList 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>> proxy_intervals_for_source_items_to_add( const QList &proxy_to_source, const QList &source_items, - const QModelIndex &source_parent, Qt::Orientation orient) const; + const QModelIndex &source_parent, Direction direction) const; QList> proxy_intervals_for_source_items( const QList &source_to_proxy, const QList &source_items) const; void insert_source_items( QList &source_to_proxy, QList &proxy_to_source, const QList &source_items, const QModelIndex &source_parent, - Qt::Orientation orient, bool emit_signal = true); + Direction direction, bool emit_signal = true); void remove_source_items( QList &source_to_proxy, QList &proxy_to_source, const QList &source_items, const QModelIndex &source_parent, - Qt::Orientation orient, bool emit_signal = true); + Direction direction, bool emit_signal = true); void remove_proxy_interval( QList &source_to_proxy, QList &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 &proxy_to_source, QList &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 &source_to_proxy, const QList &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 handle_filter_changed( QList &source_to_proxy, QList &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 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> 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> QSortFilterProxyModelPrivate::proxy_intervals_for_sou void QSortFilterProxyModelPrivate::remove_source_items( QList &source_to_proxy, QList &proxy_to_source, const QList &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 &source_to_proxy, QList &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>> QSortFilterProxyModelPrivate::proxy_intervals_for_source_items_to_add( const QList &proxy_to_source, const QList &source_items, - const QModelIndex &source_parent, Qt::Orientation orient) const + const QModelIndex &source_parent, Direction direction) const { Q_Q(const QSortFilterProxyModel); QList>> proxy_intervals; @@ -833,7 +824,7 @@ QList>> 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 source_items_in_interval; int first_new_source_item = source_items.at(source_items_index); @@ -897,7 +888,7 @@ QList>> QSortFilterProxyModelPrivate::proxy_intervals_ void QSortFilterProxyModelPrivate::insert_source_items( QList &source_to_proxy, QList &proxy_to_source, const QList &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 &source_to_proxy = (orient == Qt::Vertical) ? m->proxy_rows : m->proxy_columns; - QList &proxy_to_source = (orient == Qt::Vertical) ? m->source_rows : m->source_columns; + QList &source_to_proxy = (direction == Direction::Rows) ? m->proxy_rows : m->proxy_columns; + QList &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 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 &orthogonal_proxy_to_source = (orient == Qt::Horizontal) ? m->source_rows : m->source_columns; - QList &orthogonal_source_to_proxy = (orient == Qt::Horizontal) ? m->proxy_rows : m->proxy_columns; + QList &orthogonal_proxy_to_source = (direction == Direction::Columns) ? m->source_rows : m->source_columns; + QList &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 &source_to_proxy = (orient == Qt::Vertical) ? m->proxy_rows : m->proxy_columns; - QList &proxy_to_source = (orient == Qt::Vertical) ? m->source_rows : m->source_columns; + QList &source_to_proxy = (direction == Direction::Rows) ? m->proxy_rows : m->proxy_columns; + QList &proxy_to_source = (direction == Direction::Rows) ? m->source_rows : m->source_columns; // figure out which items to remove QList 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 &source_to_proxy = (orient == Qt::Vertical) ? m->proxy_rows : m->proxy_columns; - QList &proxy_to_source = (orient == Qt::Vertical) ? m->source_rows : m->source_columns; + QList &source_to_proxy = (direction == Direction::Rows) ? m->proxy_rows : m->proxy_columns; + QList &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> 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 rows_removed = (dir & Direction::Rows) ? handle_filter_changed(m->proxy_rows, m->source_rows, source_parent, Qt::Vertical) : QSet(); - const QSet columns_removed = (dir & Direction::Columns) ? handle_filter_changed(m->proxy_columns, m->source_columns, source_parent, Qt::Horizontal) : QSet(); + const QSet rows_removed = (directions & Direction::Rows) + ? handle_filter_changed(m->proxy_rows, m->source_rows, source_parent, + Direction::Rows) + : QSet(); + const QSet columns_removed = (directions & Direction::Columns) + ? handle_filter_changed(m->proxy_columns, m->source_columns, source_parent, + Direction::Columns) + : QSet(); // 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::const_iterator removeIt = indexesToRemove.constEnd(); @@ -1324,14 +1322,14 @@ void QSortFilterProxyModelPrivate::filter_changed(Direction dir, const QModelInd */ QSet QSortFilterProxyModelPrivate::handle_filter_changed( QList &source_to_proxy, QList &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 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 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 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 source_rows_remove_set = qListToSet(source_rows_remove); QList::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 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); } /*! diff --git a/src/corelib/itemmodels/qsortfilterproxymodel.h b/src/corelib/itemmodels/qsortfilterproxymodel.h index b2d5a320fc4..e4a2d31636d 100644 --- a/src/corelib/itemmodels/qsortfilterproxymodel.h +++ b/src/corelib/itemmodels/qsortfilterproxymodel.h @@ -101,6 +101,13 @@ public: void setAutoAcceptChildRows(bool accept); QBindable 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 ®ularExpression); @@ -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 diff --git a/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp b/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp index 4d21fcbb593..ece1bfd912c 100644 --- a/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp +++ b/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp @@ -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