summaryrefslogtreecommitdiffstats
path: root/src/corelib/itemmodels/qsortfilterproxymodel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/itemmodels/qsortfilterproxymodel.cpp')
-rw-r--r--src/corelib/itemmodels/qsortfilterproxymodel.cpp791
1 files changed, 493 insertions, 298 deletions
diff --git a/src/corelib/itemmodels/qsortfilterproxymodel.cpp b/src/corelib/itemmodels/qsortfilterproxymodel.cpp
index fb09c22798..a9ead2e1eb 100644
--- a/src/corelib/itemmodels/qsortfilterproxymodel.cpp
+++ b/src/corelib/itemmodels/qsortfilterproxymodel.cpp
@@ -1,57 +1,21 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsortfilterproxymodel.h"
#include "qitemselectionmodel.h"
#include <qsize.h>
#include <qdebug.h>
#include <qdatetime.h>
-#include <qpair.h>
#include <qstringlist.h>
#include <private/qabstractitemmodel_p.h>
#include <private/qabstractproxymodel_p.h>
+#include <private/qproperty_p.h>
#include <algorithm>
QT_BEGIN_NAMESPACE
-typedef QList<QPair<QModelIndex, QPersistentModelIndex>> QModelIndexPairList;
+using QModelIndexPairList = QList<std::pair<QModelIndex, QPersistentModelIndex>>;
struct QSortFilterProxyModelDataChanged
{
@@ -144,9 +108,9 @@ private:
class QSortFilterProxyModelPrivate : public QAbstractProxyModelPrivate
{
+public:
Q_DECLARE_PUBLIC(QSortFilterProxyModel)
-public:
enum class Direction {
Rows = 1,
Columns = 2,
@@ -164,35 +128,143 @@ public:
mutable QHash<QModelIndex, Mapping*> source_index_mapping;
- int source_sort_column;
- int proxy_sort_column;
- Qt::SortOrder sort_order;
- Qt::CaseSensitivity sort_casesensitivity;
- int sort_role;
- bool sort_localeaware;
+ void setSortCaseSensitivityForwarder(Qt::CaseSensitivity cs)
+ {
+ q_func()->setSortCaseSensitivity(cs);
+ }
+ void sortCaseSensitivityChangedForwarder(Qt::CaseSensitivity cs)
+ {
+ emit q_func()->sortCaseSensitivityChanged(cs);
+ }
- int filter_column;
- int filter_role;
- QRegularExpression filter_data;
- QModelIndex last_top_source;
+ void setSortRoleForwarder(int role) { q_func()->setSortRole(role); }
+ void sortRoleChangedForwarder(int role) { emit q_func()->sortRoleChanged(role); }
+
+ void setSortLocaleAwareForwarder(bool on) { q_func()->setSortLocaleAware(on); }
+ void sortLocaleAwareChangedForwarder(bool on) { emit q_func()->sortLocaleAwareChanged(on); }
+
+ void setFilterKeyColumnForwarder(int column) { q_func()->setFilterKeyColumn(column); }
+
+ void setFilterRoleForwarder(int role) { q_func()->setFilterRole(role); }
+ void filterRoleChangedForwarder(int role) { emit q_func()->filterRoleChanged(role); }
+
+ void setRecursiveFilteringEnabledForwarder(bool recursive)
+ {
+ q_func()->setRecursiveFilteringEnabled(recursive);
+ }
+ void recursiveFilteringEnabledChangedForwarder(bool recursive)
+ {
+ emit q_func()->recursiveFilteringEnabledChanged(recursive);
+ }
+
+ void setAutoAcceptChildRowsForwarder(bool accept) { q_func()->setAutoAcceptChildRows(accept); }
+ void autoAcceptChildRowsChangedForwarder(bool accept)
+ {
+ emit q_func()->autoAcceptChildRowsChanged(accept);
+ }
+
+ void setDynamicSortFilterForwarder(bool enable) { q_func()->setDynamicSortFilter(enable); }
+
+ void setFilterCaseSensitivityForwarder(Qt::CaseSensitivity cs)
+ {
+ q_func()->setFilterCaseSensitivity(cs);
+ }
+ void filterCaseSensitivityChangedForwarder(Qt::CaseSensitivity cs)
+ {
+ emit q_func()->filterCaseSensitivityChanged(cs);
+ }
+
+ void setFilterRegularExpressionForwarder(const QRegularExpression &re)
+ {
+ q_func()->setFilterRegularExpression(re);
+ }
+
+ int source_sort_column = -1;
+ int proxy_sort_column = -1;
+ Qt::SortOrder sort_order = Qt::AscendingOrder;
+ bool complete_insert = false;
+
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(
+ QSortFilterProxyModelPrivate, Qt::CaseSensitivity, sort_casesensitivity,
+ &QSortFilterProxyModelPrivate::setSortCaseSensitivityForwarder,
+ &QSortFilterProxyModelPrivate::sortCaseSensitivityChangedForwarder, Qt::CaseSensitive)
+
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QSortFilterProxyModelPrivate, int, sort_role,
+ &QSortFilterProxyModelPrivate::setSortRoleForwarder,
+ &QSortFilterProxyModelPrivate::sortRoleChangedForwarder,
+ Qt::DisplayRole)
+
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QSortFilterProxyModelPrivate, int, filter_column,
+ &QSortFilterProxyModelPrivate::setFilterKeyColumnForwarder,
+ 0)
+
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QSortFilterProxyModelPrivate, int, filter_role,
+ &QSortFilterProxyModelPrivate::setFilterRoleForwarder,
+ &QSortFilterProxyModelPrivate::filterRoleChangedForwarder,
+ Qt::DisplayRole)
+
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(
+ QSortFilterProxyModelPrivate, bool, sort_localeaware,
+ &QSortFilterProxyModelPrivate::setSortLocaleAwareForwarder,
+ &QSortFilterProxyModelPrivate::sortLocaleAwareChangedForwarder, false)
+
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(
+ QSortFilterProxyModelPrivate, bool, filter_recursive,
+ &QSortFilterProxyModelPrivate::setRecursiveFilteringEnabledForwarder,
+ &QSortFilterProxyModelPrivate::recursiveFilteringEnabledChangedForwarder, false)
+
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(
+ QSortFilterProxyModelPrivate, bool, accept_children,
+ &QSortFilterProxyModelPrivate::setAutoAcceptChildRowsForwarder,
+ &QSortFilterProxyModelPrivate::autoAcceptChildRowsChangedForwarder, false)
+
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QSortFilterProxyModelPrivate, bool, dynamic_sortfilter,
+ &QSortFilterProxyModelPrivate::setDynamicSortFilterForwarder,
+ true)
- bool filter_recursive;
- bool accept_children;
- bool complete_insert;
- bool dynamic_sortfilter;
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(
+ QSortFilterProxyModelPrivate, Qt::CaseSensitivity, filter_casesensitive,
+ &QSortFilterProxyModelPrivate::setFilterCaseSensitivityForwarder,
+ &QSortFilterProxyModelPrivate::filterCaseSensitivityChangedForwarder, Qt::CaseSensitive)
+
+ Q_OBJECT_COMPAT_PROPERTY(QSortFilterProxyModelPrivate, QRegularExpression,
+ filter_regularexpression,
+ &QSortFilterProxyModelPrivate::setFilterRegularExpressionForwarder)
+
+ QModelIndex last_top_source;
QRowsRemoval itemsBeingRemoved;
QModelIndexPairList saved_persistent_indexes;
QList<QPersistentModelIndex> saved_layoutChange_parents;
+ std::array<QMetaObject::Connection, 18> sourceConnections;
+
QHash<QModelIndex, Mapping *>::const_iterator create_mapping(
const QModelIndex &source_parent) const;
+ QHash<QModelIndex, Mapping *>::const_iterator create_mapping_recursive(
+ const QModelIndex &source_parent) const;
QModelIndex proxy_to_source(const QModelIndex &proxyIndex) const;
QModelIndex source_to_proxy(const QModelIndex &sourceIndex) const;
bool can_create_mapping(const QModelIndex &source_parent) const;
void remove_from_mapping(const QModelIndex &source_parent);
+ /*
+ * Legacy: changing the pattern through a string does not change the
+ * case sensitivity.
+ */
+ void set_filter_pattern(const QString &pattern)
+ {
+ QRegularExpression re = filter_regularexpression.valueBypassingBindings();
+ const auto cs = re.patternOptions() & QRegularExpression::CaseInsensitiveOption;
+ re.setPattern(pattern);
+ re.setPatternOptions(cs);
+ // This is a helper function, which is supposed to be called from a
+ // more complicated context. Because of that, the caller is responsible
+ // for calling notify() and removeBindingUnlessInWrapper(), if needed.
+ filter_regularexpression.setValueBypassingBindings(re);
+ }
+
inline QHash<QModelIndex, Mapping *>::const_iterator index_to_iterator(
const QModelIndex &proxy_index) const
{
@@ -260,10 +332,10 @@ public:
int find_source_sort_column() const;
void sort_source_rows(QList<int> &source_rows,
const QModelIndex &source_parent) const;
- QList<QPair<int, QList<int>>> proxy_intervals_for_source_items_to_add(
+ 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;
- QList<QPair<int, int>> proxy_intervals_for_source_items(
+ 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,
@@ -379,7 +451,7 @@ bool QSortFilterProxyModelPrivate::recursiveChildAcceptsRow(int source_row, cons
void QSortFilterProxyModelPrivate::remove_from_mapping(const QModelIndex &source_parent)
{
if (Mapping *m = source_index_mapping.take(source_parent)) {
- for (const QModelIndex &mappedIdx : qAsConst(m->mapped_children))
+ for (const QModelIndex &mappedIdx : std::as_const(m->mapped_children))
remove_from_mapping(mappedIdx);
delete m;
}
@@ -445,6 +517,29 @@ IndexMap::const_iterator QSortFilterProxyModelPrivate::create_mapping(
return it;
}
+// Go up the tree, creating mappings, unless of course the parent is filtered out
+IndexMap::const_iterator QSortFilterProxyModelPrivate::create_mapping_recursive(const QModelIndex &source_parent) const
+{
+ if (source_parent.isValid()) {
+ const QModelIndex source_grand_parent = source_parent.parent();
+ IndexMap::const_iterator it = source_index_mapping.constFind(source_grand_parent);
+ IndexMap::const_iterator end = source_index_mapping.constEnd();
+ if (it == end) {
+ it = create_mapping_recursive(source_grand_parent);
+ end = source_index_mapping.constEnd();
+ if (it == end)
+ return end;
+ }
+ Mapping *gm = it.value();
+ if (gm->proxy_rows.at(source_parent.row()) == -1 ||
+ gm->proxy_columns.at(source_parent.column()) == -1) {
+ // Can't do, parent is filtered
+ return end;
+ }
+ }
+ return create_mapping(source_parent);
+}
+
QModelIndex QSortFilterProxyModelPrivate::proxy_to_source(const QModelIndex &proxy_index) const
{
if (!proxy_index.isValid())
@@ -609,10 +704,10 @@ void QSortFilterProxyModelPrivate::sort_source_rows(
The result is a vector of pairs, where each pair represents a
(start, end) tuple, sorted in ascending order.
*/
-QList<QPair<int, int>> QSortFilterProxyModelPrivate::proxy_intervals_for_source_items(
+QList<std::pair<int, int>> QSortFilterProxyModelPrivate::proxy_intervals_for_source_items(
const QList<int> &source_to_proxy, const QList<int> &source_items) const
{
- QList<QPair<int, int>> proxy_intervals;
+ QList<std::pair<int, int>> proxy_intervals;
if (source_items.isEmpty())
return proxy_intervals;
@@ -629,22 +724,19 @@ QList<QPair<int, int>> QSortFilterProxyModelPrivate::proxy_intervals_for_source_
++source_items_index;
}
// Add interval to result
- proxy_intervals.append(QPair<int, int>(first_proxy_item, last_proxy_item));
+ proxy_intervals.emplace_back(first_proxy_item, last_proxy_item);
}
std::stable_sort(proxy_intervals.begin(), proxy_intervals.end());
// Consolidate adjacent intervals
for (int i = proxy_intervals.size()-1; i > 0; --i) {
- QPair<int, int> &interval = proxy_intervals[i];
- QPair<int, int> &preceeding_interval = proxy_intervals[i - 1];
+ std::pair<int, int> &interval = proxy_intervals[i];
+ std::pair<int, int> &preceeding_interval = proxy_intervals[i - 1];
if (interval.first == preceeding_interval.second + 1) {
preceeding_interval.second = interval.second;
interval.first = interval.second = -1;
}
}
- proxy_intervals.erase(
- std::remove_if(proxy_intervals.begin(), proxy_intervals.end(),
- [](QPair<int, int> &interval) { return interval.first < 0; }),
- proxy_intervals.end());
+ proxy_intervals.removeIf([](std::pair<int, int> interval) { return interval.first < 0; });
return proxy_intervals;
}
@@ -663,15 +755,17 @@ void QSortFilterProxyModelPrivate::remove_source_items(
{
Q_Q(QSortFilterProxyModel);
QModelIndex proxy_parent = q->mapFromSource(source_parent);
- if (!proxy_parent.isValid() && source_parent.isValid())
+ if (!proxy_parent.isValid() && source_parent.isValid()) {
+ proxy_to_source.clear();
return; // nothing to do (already removed)
+ }
const auto proxy_intervals = proxy_intervals_for_source_items(
source_to_proxy, source_items);
const auto end = proxy_intervals.rend();
for (auto it = proxy_intervals.rbegin(); it != end; ++it) {
- const QPair<int, int> &interval = *it;
+ const std::pair<int, int> &interval = *it;
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,
@@ -725,22 +819,21 @@ void QSortFilterProxyModelPrivate::remove_proxy_interval(
items), where items is a vector containing the (sorted) source items that
should be inserted at that proxy model location.
*/
-QList<QPair<int, QList<int>>> QSortFilterProxyModelPrivate::proxy_intervals_for_source_items_to_add(
+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
{
Q_Q(const QSortFilterProxyModel);
- QList<QPair<int, QList<int>>> proxy_intervals;
+ QList<std::pair<int, QList<int>>> proxy_intervals;
if (source_items.isEmpty())
return proxy_intervals;
int proxy_low = 0;
int proxy_item = 0;
int source_items_index = 0;
- QList<int> source_items_in_interval;
bool compare = (orient == Qt::Vertical && source_sort_column >= 0 && dynamic_sortfilter);
while (source_items_index < source_items.size()) {
- source_items_in_interval.clear();
+ QList<int> source_items_in_interval;
int first_new_source_item = source_items.at(source_items_index);
source_items_in_interval.append(first_new_source_item);
++source_items_index;
@@ -786,7 +879,7 @@ QList<QPair<int, QList<int>>> QSortFilterProxyModelPrivate::proxy_intervals_for_
}
// Add interval to result
- proxy_intervals.append(QPair<int, QList<int>>(proxy_item, source_items_in_interval));
+ proxy_intervals.emplace_back(proxy_item, std::move(source_items_in_interval));
}
return proxy_intervals;
}
@@ -814,7 +907,7 @@ void QSortFilterProxyModelPrivate::insert_source_items(
const auto end = proxy_intervals.rend();
for (auto it = proxy_intervals.rbegin(); it != end; ++it) {
- const QPair<int, QList<int>> &interval = *it;
+ const std::pair<int, QList<int>> &interval = *it;
const int proxy_start = interval.first;
const QList<int> &source_items = interval.second;
const int proxy_end = proxy_start + source_items.size() - 1;
@@ -826,8 +919,9 @@ void QSortFilterProxyModelPrivate::insert_source_items(
q->beginInsertColumns(proxy_parent, proxy_start, proxy_end);
}
- for (int i = 0; i < source_items.size(); ++i)
- proxy_to_source.insert(proxy_start + i, source_items.at(i));
+ // TODO: use the range QList::insert() overload once it is implemented (QTBUG-58633).
+ proxy_to_source.insert(proxy_start, source_items.size(), 0);
+ std::copy(source_items.cbegin(), source_items.cend(), proxy_to_source.begin() + proxy_start);
build_source_to_proxy_mapping(proxy_to_source, source_to_proxy, proxy_start);
@@ -865,12 +959,12 @@ void QSortFilterProxyModelPrivate::source_items_inserted(
it = create_mapping(source_parent);
Mapping *m = it.value();
QModelIndex proxy_parent = q->mapFromSource(source_parent);
- if (m->source_rows.count() > 0) {
- q->beginInsertRows(proxy_parent, 0, m->source_rows.count() - 1);
+ if (m->source_rows.size() > 0) {
+ q->beginInsertRows(proxy_parent, 0, m->source_rows.size() - 1);
q->endInsertRows();
}
- if (m->source_columns.count() > 0) {
- q->beginInsertColumns(proxy_parent, 0, m->source_columns.count() - 1);
+ if (m->source_columns.size() > 0) {
+ q->beginInsertColumns(proxy_parent, 0, m->source_columns.size() - 1);
q->endInsertColumns();
}
return;
@@ -1042,7 +1136,7 @@ void QSortFilterProxyModelPrivate::updateChildrenMapping(const QModelIndex &sour
Qt::Orientation orient, int start, int end, int delta_item_count, bool remove)
{
// see if any mapped children should be (re)moved
- QList<QPair<QModelIndex, Mapping *>> moved_source_index_mappings;
+ 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;
@@ -1076,12 +1170,12 @@ void QSortFilterProxyModelPrivate::updateChildrenMapping(const QModelIndex &sour
Mapping *cm = source_index_mapping.take(source_child_index);
Q_ASSERT(cm);
// we do not reinsert right away, because the new index might be identical with another, old index
- moved_source_index_mappings.append(QPair<QModelIndex, Mapping*>(new_index, cm));
+ moved_source_index_mappings.emplace_back(new_index, cm);
}
}
// reinsert moved, mapped indexes
- for (auto &pair : qAsConst(moved_source_index_mappings)) {
+ for (auto &pair : std::as_const(moved_source_index_mappings)) {
pair.second->source_parent = pair.first;
source_index_mapping.insert(pair.first, pair.second);
}
@@ -1096,7 +1190,7 @@ void QSortFilterProxyModelPrivate::proxy_item_range(
{
proxy_low = INT_MAX;
proxy_high = INT_MIN;
- for (int i = 0; i < source_items.count(); ++i) {
+ for (int i = 0; i < source_items.size(); ++i) {
int proxy_item = source_to_proxy.at(source_items.at(i));
Q_ASSERT(proxy_item != -1);
if (proxy_item < proxy_low)
@@ -1129,11 +1223,11 @@ QModelIndexPairList QSortFilterProxyModelPrivate::store_persistent_indexes() con
{
Q_Q(const QSortFilterProxyModel);
QModelIndexPairList source_indexes;
- source_indexes.reserve(persistent.indexes.count());
- for (const QPersistentModelIndexData *data : qAsConst(persistent.indexes)) {
+ source_indexes.reserve(persistent.indexes.size());
+ for (const QPersistentModelIndexData *data : std::as_const(persistent.indexes)) {
const QModelIndex &proxy_index = data->index;
QModelIndex source_index = q->mapToSource(proxy_index);
- source_indexes.append(qMakePair(proxy_index, QPersistentModelIndex(source_index)));
+ source_indexes.emplace_back(proxy_index, source_index);
}
return source_indexes;
}
@@ -1149,7 +1243,7 @@ void QSortFilterProxyModelPrivate::update_persistent_indexes(
{
Q_Q(QSortFilterProxyModel);
QModelIndexList from, to;
- const int numSourceIndexes = source_indexes.count();
+ const int numSourceIndexes = source_indexes.size();
from.reserve(numSourceIndexes);
to.reserve(numSourceIndexes);
for (const auto &indexPair : source_indexes) {
@@ -1171,9 +1265,10 @@ void QSortFilterProxyModelPrivate::update_persistent_indexes(
*/
void QSortFilterProxyModelPrivate::filter_about_to_be_changed(const QModelIndex &source_parent)
{
- if (!filter_data.pattern().isEmpty() &&
- source_index_mapping.constFind(source_parent) == source_index_mapping.constEnd())
- create_mapping(source_parent);
+ if (!filter_regularexpression.valueBypassingBindings().pattern().isEmpty()
+ && source_index_mapping.constFind(source_parent) == source_index_mapping.constEnd()) {
+ create_mapping(source_parent);
+ }
}
@@ -1232,7 +1327,7 @@ QSet<int> QSortFilterProxyModelPrivate::handle_filter_changed(
Q_Q(QSortFilterProxyModel);
// Figure out which mapped items to remove
QList<int> source_items_remove;
- for (int i = 0; i < proxy_to_source.count(); ++i) {
+ for (int i = 0; i < proxy_to_source.size(); ++i) {
const int source_item = proxy_to_source.at(i);
if ((orient == Qt::Vertical)
? !filterAcceptsRowInternal(source_item, source_parent)
@@ -1319,11 +1414,20 @@ void QSortFilterProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &sourc
const QModelIndex &source_bottom_right = data_changed.bottomRight;
const QModelIndex source_parent = source_top_left.parent();
+ bool change_in_unmapped_parent = false;
IndexMap::const_iterator it = source_index_mapping.constFind(source_parent);
if (it == source_index_mapping.constEnd()) {
- // Don't care, since we don't have mapping for this index
- continue;
+ // We don't have mapping for this index, so we cannot know how things
+ // changed (in case the change affects filtering) in order to forward
+ // the change correctly.
+ // But we can at least forward the signal "as is", if the row isn't
+ // filtered out, this is better than nothing.
+ it = create_mapping_recursive(source_parent);
+ if (it == source_index_mapping.constEnd())
+ continue;
+ change_in_unmapped_parent = true;
}
+
Mapping *m = it.value();
// Figure out how the source changes affect us
@@ -1331,9 +1435,9 @@ void QSortFilterProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &sourc
QList<int> source_rows_insert;
QList<int> source_rows_change;
QList<int> source_rows_resort;
- int end = qMin(source_bottom_right.row(), m->proxy_rows.count() - 1);
+ int end = qMin(source_bottom_right.row(), m->proxy_rows.size() - 1);
for (int source_row = source_top_left.row(); source_row <= end; ++source_row) {
- if (dynamic_sortfilter) {
+ if (dynamic_sortfilter && !change_in_unmapped_parent) {
if (m->proxy_rows.at(source_row) != -1) {
if (!filterAcceptsRowInternal(source_row, source_parent)) {
// This source row no longer satisfies the filter, so it must be removed
@@ -1404,15 +1508,19 @@ void QSortFilterProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &sourc
while (source_left_column < source_bottom_right.column()
&& m->proxy_columns.at(source_left_column) == -1)
++source_left_column;
- const QModelIndex proxy_top_left = create_index(
- proxy_start_row, m->proxy_columns.at(source_left_column), it);
- int source_right_column = source_bottom_right.column();
- while (source_right_column > source_top_left.column()
- && m->proxy_columns.at(source_right_column) == -1)
- --source_right_column;
- const QModelIndex proxy_bottom_right = create_index(
- proxy_end_row, m->proxy_columns.at(source_right_column), it);
- emit q->dataChanged(proxy_top_left, proxy_bottom_right, roles);
+ if (m->proxy_columns.at(source_left_column) != -1) {
+ const QModelIndex proxy_top_left = create_index(
+ proxy_start_row, m->proxy_columns.at(source_left_column), it);
+ int source_right_column = source_bottom_right.column();
+ while (source_right_column > source_top_left.column()
+ && m->proxy_columns.at(source_right_column) == -1)
+ --source_right_column;
+ if (m->proxy_columns.at(source_right_column) != -1) {
+ const QModelIndex proxy_bottom_right = create_index(
+ proxy_end_row, m->proxy_columns.at(source_right_column), it);
+ emit q->dataChanged(proxy_top_left, proxy_bottom_right, roles);
+ }
+ }
}
}
@@ -1479,9 +1587,7 @@ void QSortFilterProxyModelPrivate::_q_sourceReset()
_q_clearMapping();
// All internal structures are deleted in clear()
q->endResetModel();
- create_mapping(QModelIndex());
- update_source_sort_column();
- if (dynamic_sortfilter && update_source_sort_column())
+ if (update_source_sort_column() && dynamic_sortfilter)
sort();
}
@@ -1545,8 +1651,8 @@ void QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeInserted(
const bool toplevel = !source_parent.isValid();
const bool recursive_accepted = filter_recursive && !toplevel && filterAcceptsRowInternal(source_parent.row(), source_parent.parent());
- //Force the creation of a mapping now, even if its empty.
- //We need it because the proxy can be acessed at the moment it emits rowsAboutToBeInserted in insert_source_items
+ //Force the creation of a mapping now, even if it's empty.
+ //We need it because the proxy can be accessed at the moment it emits rowsAboutToBeInserted in insert_source_items
if (!filter_recursive || toplevel || recursive_accepted) {
if (can_create_mapping(source_parent))
create_mapping(source_parent);
@@ -1665,8 +1771,8 @@ void QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeInserted(
{
Q_UNUSED(start);
Q_UNUSED(end);
- //Force the creation of a mapping now, even if its empty.
- //We need it because the proxy can be acessed at the moment it emits columnsAboutToBeInserted in insert_source_items
+ //Force the creation of a mapping now, even if it's empty.
+ //We need it because the proxy can be accessed at the moment it emits columnsAboutToBeInserted in insert_source_items
if (can_create_mapping(source_parent))
create_mapping(source_parent);
}
@@ -1713,7 +1819,10 @@ void QSortFilterProxyModelPrivate::_q_sourceColumnsRemoved(
source_sort_column = -1;
}
- proxy_sort_column = q->mapFromSource(model->index(0,source_sort_column, source_parent)).column();
+ if (source_sort_column >= 0)
+ proxy_sort_column = q->mapFromSource(model->index(0,source_sort_column, source_parent)).column();
+ else
+ proxy_sort_column = -1;
}
void QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeMoved(
@@ -1898,18 +2007,8 @@ QSortFilterProxyModel::QSortFilterProxyModel(QObject *parent)
: QAbstractProxyModel(*new QSortFilterProxyModelPrivate, parent)
{
Q_D(QSortFilterProxyModel);
- d->proxy_sort_column = d->source_sort_column = -1;
- d->sort_order = Qt::AscendingOrder;
- d->sort_casesensitivity = Qt::CaseSensitive;
- d->sort_role = Qt::DisplayRole;
- d->sort_localeaware = false;
- d->filter_column = 0;
- d->filter_role = Qt::DisplayRole;
- d->filter_recursive = false;
- d->accept_children = false;
- d->dynamic_sortfilter = true;
- d->complete_insert = false;
- connect(this, SIGNAL(modelReset()), this, SLOT(_q_clearMapping()));
+ QObjectPrivate::connect(this, &QAbstractItemModel::modelReset, d,
+ &QSortFilterProxyModelPrivate::_q_clearMapping);
}
/*!
@@ -1934,56 +2033,10 @@ void QSortFilterProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
beginResetModel();
- disconnect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QList<int>)),
- this, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex,QList<int>)));
-
- disconnect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
- this, SLOT(_q_sourceHeaderDataChanged(Qt::Orientation,int,int)));
-
- disconnect(d->model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
- this, SLOT(_q_sourceRowsAboutToBeInserted(QModelIndex,int,int)));
-
- disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
- this, SLOT(_q_sourceRowsInserted(QModelIndex,int,int)));
-
- disconnect(d->model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
- this, SLOT(_q_sourceColumnsAboutToBeInserted(QModelIndex,int,int)));
-
- disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
- this, SLOT(_q_sourceColumnsInserted(QModelIndex,int,int)));
-
- disconnect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
-
- disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sourceRowsRemoved(QModelIndex,int,int)));
-
- disconnect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sourceColumnsAboutToBeRemoved(QModelIndex,int,int)));
-
- disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sourceColumnsRemoved(QModelIndex,int,int)));
-
- disconnect(d->model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
-
- disconnect(d->model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)));
-
- disconnect(d->model, SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sourceColumnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
-
- disconnect(d->model, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sourceColumnsMoved(QModelIndex,int,int,QModelIndex,int)));
-
- disconnect(d->model, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- this, SLOT(_q_sourceLayoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
-
- disconnect(d->model, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- this, SLOT(_q_sourceLayoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
-
- disconnect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_sourceAboutToBeReset()));
- disconnect(d->model, SIGNAL(modelReset()), this, SLOT(_q_sourceReset()));
+ if (d->model) {
+ for (const QMetaObject::Connection &connection : std::as_const(d->sourceConnections))
+ disconnect(connection);
+ }
// same as in _q_sourceReset()
d->invalidatePersistentIndexes();
@@ -1991,59 +2044,62 @@ void QSortFilterProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
QAbstractProxyModel::setSourceModel(sourceModel);
- connect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QList<int>)),
- this, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex,QList<int>)));
+ d->sourceConnections = std::array<QMetaObject::Connection, 18>{
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::dataChanged, d,
+ &QSortFilterProxyModelPrivate::_q_sourceDataChanged),
- connect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
- this, SLOT(_q_sourceHeaderDataChanged(Qt::Orientation,int,int)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::headerDataChanged, d,
+ &QSortFilterProxyModelPrivate::_q_sourceHeaderDataChanged),
- connect(d->model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
- this, SLOT(_q_sourceRowsAboutToBeInserted(QModelIndex,int,int)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::rowsAboutToBeInserted, d,
+ &QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeInserted),
- connect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
- this, SLOT(_q_sourceRowsInserted(QModelIndex,int,int)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::rowsInserted, d,
+ &QSortFilterProxyModelPrivate::_q_sourceRowsInserted),
- connect(d->model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
- this, SLOT(_q_sourceColumnsAboutToBeInserted(QModelIndex,int,int)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::columnsAboutToBeInserted, d,
+ &QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeInserted),
- connect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
- this, SLOT(_q_sourceColumnsInserted(QModelIndex,int,int)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::columnsInserted, d,
+ &QSortFilterProxyModelPrivate::_q_sourceColumnsInserted),
- connect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::rowsAboutToBeRemoved, d,
+ &QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeRemoved),
- connect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sourceRowsRemoved(QModelIndex,int,int)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::rowsRemoved, d,
+ &QSortFilterProxyModelPrivate::_q_sourceRowsRemoved),
- connect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sourceColumnsAboutToBeRemoved(QModelIndex,int,int)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::columnsAboutToBeRemoved, d,
+ &QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeRemoved),
- connect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sourceColumnsRemoved(QModelIndex,int,int)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::columnsRemoved, d,
+ &QSortFilterProxyModelPrivate::_q_sourceColumnsRemoved),
- connect(d->model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::rowsAboutToBeMoved, d,
+ &QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeMoved),
- connect(d->model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::rowsMoved, d,
+ &QSortFilterProxyModelPrivate::_q_sourceRowsMoved),
- connect(d->model, SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sourceColumnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::columnsAboutToBeMoved, d,
+ &QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeMoved),
- connect(d->model, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sourceColumnsMoved(QModelIndex,int,int,QModelIndex,int)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::columnsMoved, d,
+ &QSortFilterProxyModelPrivate::_q_sourceColumnsMoved),
- connect(d->model, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- this, SLOT(_q_sourceLayoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::layoutAboutToBeChanged, d,
+ &QSortFilterProxyModelPrivate::_q_sourceLayoutAboutToBeChanged),
- connect(d->model, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- this, SLOT(_q_sourceLayoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::layoutChanged, d,
+ &QSortFilterProxyModelPrivate::_q_sourceLayoutChanged),
- connect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_sourceAboutToBeReset()));
- connect(d->model, SIGNAL(modelReset()), this, SLOT(_q_sourceReset()));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::modelAboutToBeReset, d,
+ &QSortFilterProxyModelPrivate::_q_sourceAboutToBeReset),
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::modelReset, d,
+ &QSortFilterProxyModelPrivate::_q_sourceReset)
+ };
endResetModel();
- d->create_mapping(QModelIndex());
if (d->update_source_sort_column() && d->dynamic_sortfilter)
d->sort();
}
@@ -2059,7 +2115,7 @@ QModelIndex QSortFilterProxyModel::index(int row, int column, const QModelIndex
QModelIndex source_parent = mapToSource(parent); // parent is already mapped at this point
IndexMap::const_iterator it = d->create_mapping(source_parent); // but make sure that the children are mapped
- if (it.value()->source_rows.count() <= row || it.value()->source_columns.count() <= column)
+ if (it.value()->source_rows.size() <= row || it.value()->source_columns.size() <= column)
return QModelIndex();
return d->create_index(row, column, it);
@@ -2090,7 +2146,7 @@ QModelIndex QSortFilterProxyModel::sibling(int row, int column, const QModelInde
return QModelIndex();
const IndexMap::const_iterator it = d->index_to_iterator(idx);
- if (it.value()->source_rows.count() <= row || it.value()->source_columns.count() <= column)
+ if (it.value()->source_rows.size() <= row || it.value()->source_columns.size() <= column)
return QModelIndex();
return d->create_index(row, column, it);
@@ -2106,7 +2162,7 @@ int QSortFilterProxyModel::rowCount(const QModelIndex &parent) const
if (parent.isValid() && !source_parent.isValid())
return 0;
IndexMap::const_iterator it = d->create_mapping(source_parent);
- return it.value()->source_rows.count();
+ return it.value()->source_rows.size();
}
/*!
@@ -2119,7 +2175,7 @@ int QSortFilterProxyModel::columnCount(const QModelIndex &parent) const
if (parent.isValid() && !source_parent.isValid())
return 0;
IndexMap::const_iterator it = d->create_mapping(source_parent);
- return it.value()->source_columns.count();
+ return it.value()->source_columns.size();
}
/*!
@@ -2138,7 +2194,7 @@ bool QSortFilterProxyModel::hasChildren(const QModelIndex &parent) const
return true; //we assume we might have children that can be fetched
QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
- return m->source_rows.count() != 0 && m->source_columns.count() != 0;
+ return m->source_rows.size() != 0 && m->source_columns.size() != 0;
}
/*!
@@ -2172,15 +2228,15 @@ QVariant QSortFilterProxyModel::headerData(int section, Qt::Orientation orientat
{
Q_D(const QSortFilterProxyModel);
IndexMap::const_iterator it = d->create_mapping(QModelIndex());
- if (it.value()->source_rows.count() * it.value()->source_columns.count() > 0)
+ if (it.value()->source_rows.size() * it.value()->source_columns.size() > 0)
return QAbstractProxyModel::headerData(section, orientation, role);
int source_section;
if (orientation == Qt::Vertical) {
- if (section < 0 || section >= it.value()->source_rows.count())
+ if (section < 0 || section >= it.value()->source_rows.size())
return QVariant();
source_section = it.value()->source_rows.at(section);
} else {
- if (section < 0 || section >= it.value()->source_columns.count())
+ if (section < 0 || section >= it.value()->source_columns.size())
return QVariant();
source_section = it.value()->source_columns.at(section);
}
@@ -2195,15 +2251,15 @@ bool QSortFilterProxyModel::setHeaderData(int section, Qt::Orientation orientati
{
Q_D(QSortFilterProxyModel);
IndexMap::const_iterator it = d->create_mapping(QModelIndex());
- if (it.value()->source_rows.count() * it.value()->source_columns.count() > 0)
+ if (it.value()->source_rows.size() * it.value()->source_columns.size() > 0)
return QAbstractProxyModel::setHeaderData(section, orientation, value, role);
int source_section;
if (orientation == Qt::Vertical) {
- if (section < 0 || section >= it.value()->source_rows.count())
+ if (section < 0 || section >= it.value()->source_rows.size())
return false;
source_section = it.value()->source_rows.at(section);
} else {
- if (section < 0 || section >= it.value()->source_columns.count())
+ if (section < 0 || section >= it.value()->source_columns.size())
return false;
source_section = it.value()->source_columns.at(section);
}
@@ -2217,7 +2273,7 @@ QMimeData *QSortFilterProxyModel::mimeData(const QModelIndexList &indexes) const
{
Q_D(const QSortFilterProxyModel);
QModelIndexList source_indexes;
- source_indexes.reserve(indexes.count());
+ source_indexes.reserve(indexes.size());
for (const QModelIndex &idx : indexes)
source_indexes << mapToSource(idx);
return d->model->mimeData(source_indexes);
@@ -2263,10 +2319,10 @@ bool QSortFilterProxyModel::insertRows(int row, int count, const QModelIndex &pa
if (parent.isValid() && !source_parent.isValid())
return false;
QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
- if (row > m->source_rows.count())
+ if (row > m->source_rows.size())
return false;
- int source_row = (row >= m->source_rows.count()
- ? m->proxy_rows.count()
+ int source_row = (row >= m->source_rows.size()
+ ? m->proxy_rows.size()
: m->source_rows.at(row));
return d->model->insertRows(source_row, count, source_parent);
}
@@ -2283,10 +2339,10 @@ bool QSortFilterProxyModel::insertColumns(int column, int count, const QModelInd
if (parent.isValid() && !source_parent.isValid())
return false;
QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
- if (column > m->source_columns.count())
+ if (column > m->source_columns.size())
return false;
- int source_column = (column >= m->source_columns.count()
- ? m->proxy_columns.count()
+ int source_column = (column >= m->source_columns.size()
+ ? m->proxy_columns.size()
: m->source_columns.at(column));
return d->model->insertColumns(source_column, count, source_parent);
}
@@ -2303,10 +2359,10 @@ bool QSortFilterProxyModel::removeRows(int row, int count, const QModelIndex &pa
if (parent.isValid() && !source_parent.isValid())
return false;
QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
- if (row + count > m->source_rows.count())
+ if (row + count > m->source_rows.size())
return false;
if ((count == 1)
- || ((d->source_sort_column < 0) && (m->proxy_rows.count() == m->source_rows.count()))) {
+ || ((d->source_sort_column < 0) && (m->proxy_rows.size() == m->source_rows.size()))) {
int source_row = m->source_rows.at(row);
return d->model->removeRows(source_row, count, source_parent);
}
@@ -2318,7 +2374,7 @@ bool QSortFilterProxyModel::removeRows(int row, int count, const QModelIndex &pa
rows.append(m->source_rows.at(i));
std::sort(rows.begin(), rows.end());
- int pos = rows.count() - 1;
+ int pos = rows.size() - 1;
bool ok = true;
while (pos >= 0) {
const int source_end = rows.at(pos--);
@@ -2345,9 +2401,9 @@ bool QSortFilterProxyModel::removeColumns(int column, int count, const QModelInd
if (parent.isValid() && !source_parent.isValid())
return false;
QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value();
- if (column + count > m->source_columns.count())
+ if (column + count > m->source_columns.size())
return false;
- if ((count == 1) || (m->proxy_columns.count() == m->source_columns.count())) {
+ if ((count == 1) || (m->proxy_columns.size() == m->source_columns.size())) {
int source_column = m->source_columns.at(column);
return d->model->removeColumns(source_column, count, source_parent);
}
@@ -2357,7 +2413,7 @@ bool QSortFilterProxyModel::removeColumns(int column, int count, const QModelInd
for (int i = column; i < column + count; ++i)
columns.append(m->source_columns.at(i));
- int pos = columns.count() - 1;
+ int pos = columns.size() - 1;
bool ok = true;
while (pos >= 0) {
const int source_end = columns.at(pos--);
@@ -2377,11 +2433,7 @@ bool QSortFilterProxyModel::removeColumns(int column, int count, const QModelInd
*/
void QSortFilterProxyModel::fetchMore(const QModelIndex &parent)
{
- Q_D(QSortFilterProxyModel);
- QModelIndex source_parent;
- if (d->indexValid(parent))
- source_parent = mapToSource(parent);
- d->model->fetchMore(source_parent);
+ QAbstractProxyModel::fetchMore(parent);
}
/*!
@@ -2389,11 +2441,7 @@ void QSortFilterProxyModel::fetchMore(const QModelIndex &parent)
*/
bool QSortFilterProxyModel::canFetchMore(const QModelIndex &parent) const
{
- Q_D(const QSortFilterProxyModel);
- QModelIndex source_parent;
- if (d->indexValid(parent))
- source_parent = mapToSource(parent);
- return d->model->canFetchMore(source_parent);
+ return QAbstractProxyModel::canFetchMore(parent);
}
/*!
@@ -2401,11 +2449,7 @@ bool QSortFilterProxyModel::canFetchMore(const QModelIndex &parent) const
*/
Qt::ItemFlags QSortFilterProxyModel::flags(const QModelIndex &index) const
{
- Q_D(const QSortFilterProxyModel);
- QModelIndex source_index;
- if (d->indexValid(index))
- source_index = mapToSource(index);
- return d->model->flags(source_index);
+ return QAbstractProxyModel::flags(index);
}
/*!
@@ -2461,9 +2505,12 @@ void QSortFilterProxyModel::sort(int column, Qt::SortOrder order)
/*!
\since 4.5
- \brief the column currently used for sorting
+ \return the column currently used for sorting
- This returns the most recently used sort column.
+ This returns the most recently used sort column. The default value is -1,
+ which means that this proxy model does not sort.
+
+ \sa sort()
*/
int QSortFilterProxyModel::sortColumn() const
{
@@ -2473,9 +2520,12 @@ int QSortFilterProxyModel::sortColumn() const
/*!
\since 4.5
- \brief the order currently used for sorting
+ \return the order currently used for sorting
+
+ This returns the most recently used sort order. The default value is
+ Qt::AscendingOrder.
- This returns the most recently used sort order.
+ \sa sort()
*/
Qt::SortOrder QSortFilterProxyModel::sortOrder() const
{
@@ -2483,35 +2533,62 @@ Qt::SortOrder QSortFilterProxyModel::sortOrder() const
return d->sort_order;
}
-#if QT_CONFIG(regularexpression)
/*!
\since 5.12
\property QSortFilterProxyModel::filterRegularExpression
\brief the QRegularExpression used to filter the contents of the source model
- Setting this property overwrites the current
- \l{QSortFilterProxyModel::filterCaseSensitivity}{filterCaseSensitivity}.
+ Setting this property through the QRegularExpression overload overwrites the
+ current \l{QSortFilterProxyModel::filterCaseSensitivity}{filterCaseSensitivity}.
By default, the QRegularExpression is an empty string matching all contents.
If no QRegularExpression or an empty string is set, everything in the source
model will be accepted.
+ \note Setting this property propagates the case sensitivity of the new
+ regular expression to the \l filterCaseSensitivity property, and so breaks
+ its binding. Likewise explicitly setting \l filterCaseSensitivity changes
+ the case sensitivity of the current regular expression, thereby breaking
+ its binding.
+
\sa filterCaseSensitivity, setFilterWildcard(), setFilterFixedString()
*/
QRegularExpression QSortFilterProxyModel::filterRegularExpression() const
{
Q_D(const QSortFilterProxyModel);
- return d->filter_data;
+ return d->filter_regularexpression;
+}
+
+QBindable<QRegularExpression> QSortFilterProxyModel::bindableFilterRegularExpression()
+{
+ Q_D(QSortFilterProxyModel);
+ return QBindable<QRegularExpression>(&d->filter_regularexpression);
}
void QSortFilterProxyModel::setFilterRegularExpression(const QRegularExpression &regularExpression)
{
Q_D(QSortFilterProxyModel);
+ const QScopedPropertyUpdateGroup guard;
+ const bool regExpChanged =
+ regularExpression != d->filter_regularexpression.valueBypassingBindings();
+ d->filter_regularexpression.removeBindingUnlessInWrapper();
+ d->filter_casesensitive.removeBindingUnlessInWrapper();
+ const Qt::CaseSensitivity cs = d->filter_casesensitive.valueBypassingBindings();
d->filter_about_to_be_changed();
- d->filter_data = regularExpression;
+ const Qt::CaseSensitivity updatedCs =
+ regularExpression.patternOptions() & QRegularExpression::CaseInsensitiveOption
+ ? Qt::CaseInsensitive : Qt::CaseSensitive;
+ d->filter_regularexpression.setValueBypassingBindings(regularExpression);
+ if (cs != updatedCs)
+ d->filter_casesensitive.setValueBypassingBindings(updatedCs);
d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
+ // Do not change the evaluation logic, but notify only if the regular
+ // expression has actually changed.
+ if (regExpChanged)
+ d->filter_regularexpression.notify();
+ if (cs != updatedCs)
+ d->filter_casesensitive.notify();
}
-#endif
/*!
\property QSortFilterProxyModel::filterKeyColumn
@@ -2529,10 +2606,25 @@ int QSortFilterProxyModel::filterKeyColumn() const
void QSortFilterProxyModel::setFilterKeyColumn(int column)
{
+ // While introducing new bindable properties, we still update the value
+ // unconditionally (even if it didn't really change), and call the
+ // filter_about_to_be_changed()/filter_changed() methods, so that we do
+ // not break any code. However we do notify the observing bindings only
+ // if the column has actually changed
Q_D(QSortFilterProxyModel);
+ d->filter_column.removeBindingUnlessInWrapper();
d->filter_about_to_be_changed();
- d->filter_column = column;
+ const auto oldColumn = d->filter_column.valueBypassingBindings();
+ d->filter_column.setValueBypassingBindings(column);
d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
+ if (oldColumn != column)
+ d->filter_column.notify();
+}
+
+QBindable<int> QSortFilterProxyModel::bindableFilterKeyColumn()
+{
+ Q_D(QSortFilterProxyModel);
+ return QBindable<int>(&d->filter_column);
}
/*!
@@ -2543,6 +2635,11 @@ void QSortFilterProxyModel::setFilterKeyColumn(int column)
By default, the filter is case sensitive.
+ \note Setting this property propagates the new case sensitivity to the
+ \l filterRegularExpression property, and so breaks its binding. Likewise
+ explicitly setting \l filterRegularExpression changes the current case
+ sensitivity, thereby breaking its binding.
+
\sa filterRegularExpression, sortCaseSensitivity
*/
@@ -2555,22 +2652,36 @@ void QSortFilterProxyModel::setFilterKeyColumn(int column)
Qt::CaseSensitivity QSortFilterProxyModel::filterCaseSensitivity() const
{
Q_D(const QSortFilterProxyModel);
- return d->filter_data.patternOptions() & QRegularExpression::CaseInsensitiveOption ?
- Qt::CaseInsensitive : Qt::CaseSensitive;
+ return d->filter_casesensitive;
}
void QSortFilterProxyModel::setFilterCaseSensitivity(Qt::CaseSensitivity cs)
{
Q_D(QSortFilterProxyModel);
- QRegularExpression::PatternOptions o = QRegularExpression::NoPatternOption;
- if (cs == Qt::CaseInsensitive)
- o = QRegularExpression::CaseInsensitiveOption;
- if (o == d->filter_data.patternOptions())
+ d->filter_casesensitive.removeBindingUnlessInWrapper();
+ d->filter_regularexpression.removeBindingUnlessInWrapper();
+ if (cs == d->filter_casesensitive)
return;
+
+ const QScopedPropertyUpdateGroup guard;
+ QRegularExpression::PatternOptions options =
+ d->filter_regularexpression.value().patternOptions();
+ options.setFlag(QRegularExpression::CaseInsensitiveOption, cs == Qt::CaseInsensitive);
+ d->filter_casesensitive.setValueBypassingBindings(cs);
+
d->filter_about_to_be_changed();
- d->filter_data.setPatternOptions(o);
+ QRegularExpression re = d->filter_regularexpression;
+ re.setPatternOptions(options);
+ d->filter_regularexpression.setValueBypassingBindings(re);
d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
- emit filterCaseSensitivityChanged(cs);
+ d->filter_regularexpression.notify();
+ d->filter_casesensitive.notify();
+}
+
+QBindable<Qt::CaseSensitivity> QSortFilterProxyModel::bindableFilterCaseSensitivity()
+{
+ Q_D(QSortFilterProxyModel);
+ return QBindable<Qt::CaseSensitivity>(&d->filter_casesensitive);
}
/*!
@@ -2598,12 +2709,19 @@ Qt::CaseSensitivity QSortFilterProxyModel::sortCaseSensitivity() const
void QSortFilterProxyModel::setSortCaseSensitivity(Qt::CaseSensitivity cs)
{
Q_D(QSortFilterProxyModel);
+ d->sort_casesensitivity.removeBindingUnlessInWrapper();
if (d->sort_casesensitivity == cs)
return;
- d->sort_casesensitivity = cs;
+ d->sort_casesensitivity.setValueBypassingBindings(cs);
d->sort();
- emit sortCaseSensitivityChanged(cs);
+ d->sort_casesensitivity.notify(); // also emits a signal
+}
+
+QBindable<Qt::CaseSensitivity> QSortFilterProxyModel::bindableSortCaseSensitivity()
+{
+ Q_D(QSortFilterProxyModel);
+ return QBindable<Qt::CaseSensitivity>(&d->sort_casesensitivity);
}
/*!
@@ -2631,15 +2749,21 @@ bool QSortFilterProxyModel::isSortLocaleAware() const
void QSortFilterProxyModel::setSortLocaleAware(bool on)
{
Q_D(QSortFilterProxyModel);
+ d->sort_localeaware.removeBindingUnlessInWrapper();
if (d->sort_localeaware == on)
return;
- d->sort_localeaware = on;
+ d->sort_localeaware.setValueBypassingBindings(on);
d->sort();
- emit sortLocaleAwareChanged(on);
+ d->sort_localeaware.notify(); // also emits a signal
+}
+
+QBindable<bool> QSortFilterProxyModel::bindableIsSortLocaleAware()
+{
+ Q_D(QSortFilterProxyModel);
+ return QBindable<bool>(&d->sort_localeaware);
}
-#if QT_CONFIG(regularexpression)
/*!
\since 5.12
@@ -2649,46 +2773,70 @@ void QSortFilterProxyModel::setSortLocaleAware(bool on)
This method should be preferred for new code as it will use
QRegularExpression internally.
+ This method will reset the regular expression options
+ but respect case sensitivity.
+
+ \note Calling this method updates the regular expression, thereby breaking
+ the binding for \l filterRegularExpression. However it has no effect on the
+ \l filterCaseSensitivity bindings.
+
\sa setFilterCaseSensitivity(), setFilterWildcard(), setFilterFixedString(), filterRegularExpression()
*/
void QSortFilterProxyModel::setFilterRegularExpression(const QString &pattern)
{
Q_D(QSortFilterProxyModel);
+ d->filter_regularexpression.removeBindingUnlessInWrapper();
d->filter_about_to_be_changed();
- QRegularExpression rx(pattern,
- d->filter_data.patternOptions() & QRegularExpression::CaseInsensitiveOption);
- d->filter_data.setPattern(pattern);
+ d->set_filter_pattern(pattern);
d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
+ d->filter_regularexpression.notify();
}
-#endif
/*!
Sets the wildcard expression used to filter the contents
of the source model to the given \a pattern.
+ This method will reset the regular expression options
+ but respect case sensitivity.
+
+ \note Calling this method updates the regular expression, thereby breaking
+ the binding for \l filterRegularExpression. However it has no effect on the
+ \l filterCaseSensitivity bindings.
+
\sa setFilterCaseSensitivity(), setFilterRegularExpression(), setFilterFixedString(), filterRegularExpression()
*/
void QSortFilterProxyModel::setFilterWildcard(const QString &pattern)
{
Q_D(QSortFilterProxyModel);
+ d->filter_regularexpression.removeBindingUnlessInWrapper();
d->filter_about_to_be_changed();
- QString p = QRegularExpression::wildcardToRegularExpression(pattern, QRegularExpression::UnanchoredWildcardConversion);
- d->filter_data.setPattern(p);
+ d->set_filter_pattern(QRegularExpression::wildcardToRegularExpression(
+ pattern, QRegularExpression::UnanchoredWildcardConversion));
d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
+ d->filter_regularexpression.notify();
}
/*!
Sets the fixed string used to filter the contents
of the source model to the given \a pattern.
+ This method will reset the regular expression options
+ but respect case sensitivity.
+
+ \note Calling this method updates the regular expression, thereby breaking
+ the binding for \l filterRegularExpression. However it has no effect on the
+ \l filterCaseSensitivity bindings.
+
\sa setFilterCaseSensitivity(), setFilterRegularExpression(), setFilterWildcard(), filterRegularExpression()
*/
void QSortFilterProxyModel::setFilterFixedString(const QString &pattern)
{
Q_D(QSortFilterProxyModel);
+ d->filter_regularexpression.removeBindingUnlessInWrapper();
d->filter_about_to_be_changed();
- d->filter_data.setPattern(QRegularExpression::escape(pattern));
+ d->set_filter_pattern(QRegularExpression::escape(pattern));
d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
+ d->filter_regularexpression.notify();
}
/*!
@@ -2706,6 +2854,8 @@ void QSortFilterProxyModel::setFilterFixedString(const QString &pattern)
QComboBox.
The default value is true.
+
+ \sa sortColumn()
*/
bool QSortFilterProxyModel::dynamicSortFilter() const
{
@@ -2715,10 +2865,25 @@ bool QSortFilterProxyModel::dynamicSortFilter() const
void QSortFilterProxyModel::setDynamicSortFilter(bool enable)
{
+ // While introducing new bindable properties, we still update the value
+ // unconditionally (even if it didn't really change), and call the
+ // sort() method, so that we do not break any code.
+ // However we do notify the observing bindings only if the value has
+ // actually changed.
Q_D(QSortFilterProxyModel);
- d->dynamic_sortfilter = enable;
+ d->dynamic_sortfilter.removeBindingUnlessInWrapper();
+ const bool valueChanged = d->dynamic_sortfilter.value() != enable;
+ d->dynamic_sortfilter.setValueBypassingBindings(enable);
if (enable)
d->sort();
+ if (valueChanged)
+ d->dynamic_sortfilter.notify();
+}
+
+QBindable<bool> QSortFilterProxyModel::bindableDynamicSortFilter()
+{
+ Q_D(QSortFilterProxyModel);
+ return QBindable<bool>(&d->dynamic_sortfilter);
}
/*!
@@ -2746,11 +2911,18 @@ int QSortFilterProxyModel::sortRole() const
void QSortFilterProxyModel::setSortRole(int role)
{
Q_D(QSortFilterProxyModel);
- if (d->sort_role == role)
+ d->sort_role.removeBindingUnlessInWrapper();
+ if (d->sort_role.valueBypassingBindings() == role)
return;
- d->sort_role = role;
+ d->sort_role.setValueBypassingBindings(role);
d->sort();
- emit sortRoleChanged(role);
+ d->sort_role.notify(); // also emits a signal
+}
+
+QBindable<int> QSortFilterProxyModel::bindableSortRole()
+{
+ Q_D(QSortFilterProxyModel);
+ return QBindable<int>(&d->sort_role);
}
/*!
@@ -2778,12 +2950,19 @@ int QSortFilterProxyModel::filterRole() const
void QSortFilterProxyModel::setFilterRole(int role)
{
Q_D(QSortFilterProxyModel);
- if (d->filter_role == role)
+ d->filter_role.removeBindingUnlessInWrapper();
+ if (d->filter_role.valueBypassingBindings() == role)
return;
d->filter_about_to_be_changed();
- d->filter_role = role;
+ d->filter_role.setValueBypassingBindings(role);
d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
- emit filterRoleChanged(role);
+ d->filter_role.notify(); // also emits a signal
+}
+
+QBindable<int> QSortFilterProxyModel::bindableFilterRole()
+{
+ Q_D(QSortFilterProxyModel);
+ return QBindable<int>(&d->filter_role);
}
/*!
@@ -2813,12 +2992,19 @@ bool QSortFilterProxyModel::isRecursiveFilteringEnabled() const
void QSortFilterProxyModel::setRecursiveFilteringEnabled(bool recursive)
{
Q_D(QSortFilterProxyModel);
+ d->filter_recursive.removeBindingUnlessInWrapper();
if (d->filter_recursive == recursive)
return;
d->filter_about_to_be_changed();
- d->filter_recursive = recursive;
+ d->filter_recursive.setValueBypassingBindings(recursive);
d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
- emit recursiveFilteringEnabledChanged(recursive);
+ d->filter_recursive.notify(); // also emits a signal
+}
+
+QBindable<bool> QSortFilterProxyModel::bindableRecursiveFilteringEnabled()
+{
+ Q_D(QSortFilterProxyModel);
+ return QBindable<bool>(&d->filter_recursive);
}
/*!
@@ -2850,13 +3036,20 @@ bool QSortFilterProxyModel::autoAcceptChildRows() const
void QSortFilterProxyModel::setAutoAcceptChildRows(bool accept)
{
Q_D(QSortFilterProxyModel);
+ d->accept_children.removeBindingUnlessInWrapper();
if (d->accept_children == accept)
return;
d->filter_about_to_be_changed();
- d->accept_children = accept;
+ d->accept_children.setValueBypassingBindings(accept);
d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
- emit autoAcceptChildRowsChanged(accept);
+ d->accept_children.notify(); // also emits a signal
+}
+
+QBindable<bool> QSortFilterProxyModel::bindableAutoAcceptChildRows()
+{
+ Q_D(QSortFilterProxyModel);
+ return QBindable<bool>(&d->accept_children);
}
/*!
@@ -2999,23 +3192,25 @@ bool QSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &
{
Q_D(const QSortFilterProxyModel);
- if (d->filter_data.pattern().isEmpty())
+ if (d->filter_regularexpression.value().pattern().isEmpty())
return true;
+
+ int column_count = d->model->columnCount(source_parent);
if (d->filter_column == -1) {
- int column_count = d->model->columnCount(source_parent);
for (int column = 0; column < column_count; ++column) {
QModelIndex source_index = d->model->index(source_row, column, source_parent);
QString key = d->model->data(source_index, d->filter_role).toString();
- if (d->filter_data.match(key).hasMatch())
+ if (key.contains(d->filter_regularexpression.value()))
return true;
}
return false;
}
- QModelIndex source_index = d->model->index(source_row, d->filter_column, source_parent);
- if (!source_index.isValid()) // the column may not exist
+
+ if (d->filter_column >= column_count) // the column may not exist
return true;
+ QModelIndex source_index = d->model->index(source_row, d->filter_column, source_parent);
QString key = d->model->data(source_index, d->filter_role).toString();
- return d->filter_data.match(key).hasMatch();
+ return key.contains(d->filter_regularexpression.value());
}
/*!