From 7db527dbdd911c79f31425d099d1fc9c63e42453 Mon Sep 17 00:00:00 2001 From: Giulio Camuffo Date: Tue, 19 May 2020 15:02:22 +0200 Subject: [PATCH] Add a property to QSFPM to show children of accepted items [ChangeLog][QtCore][QSortFilterProxyModel] Add a 'autoAcceptChildRows' property to always show children rows of accepted rows. Change-Id: I2402469ece438179d0f19888b9775cc27cf5c749 Reviewed-by: David Faure --- .../itemmodels/qsortfilterproxymodel.cpp | 87 ++++++++++++++++--- .../itemmodels/qsortfilterproxymodel.h | 5 ++ .../tst_qsortfilterproxymodel_recursive.cpp | 32 +++++++ 3 files changed, 114 insertions(+), 10 deletions(-) diff --git a/src/corelib/itemmodels/qsortfilterproxymodel.cpp b/src/corelib/itemmodels/qsortfilterproxymodel.cpp index 79a9875073..2c494aeec8 100644 --- a/src/corelib/itemmodels/qsortfilterproxymodel.cpp +++ b/src/corelib/itemmodels/qsortfilterproxymodel.cpp @@ -177,6 +177,7 @@ public: QModelIndex last_top_source; bool filter_recursive; + bool accept_children; bool complete_insert; bool dynamic_sortfilter; QRowsRemoval itemsBeingRemoved; @@ -305,7 +306,8 @@ public: bool needsReorder(const QVector &source_rows, const QModelIndex &source_parent) const; bool filterAcceptsRowInternal(int source_row, const QModelIndex &source_parent) const; - bool filterRecursiveAcceptsRow(int source_row, const QModelIndex &source_parent) const; + bool recursiveChildAcceptsRow(int source_row, const QModelIndex &source_parent) const; + bool recursiveParentAcceptsRow(const QModelIndex &source_parent) const; }; typedef QHash IndexMap; @@ -323,25 +325,51 @@ void QSortFilterProxyModelPrivate::_q_sourceModelDestroyed() } bool QSortFilterProxyModelPrivate::filterAcceptsRowInternal(int source_row, const QModelIndex &source_parent) const -{ - Q_Q(const QSortFilterProxyModel); - return filter_recursive - ? filterRecursiveAcceptsRow(source_row, source_parent) - : q->filterAcceptsRow(source_row, source_parent); -} - -bool QSortFilterProxyModelPrivate::filterRecursiveAcceptsRow(int source_row, const QModelIndex &source_parent) const { Q_Q(const QSortFilterProxyModel); if (q->filterAcceptsRow(source_row, source_parent)) return true; + // Go up the tree and accept this row if a parent is accepted + if (accept_children && recursiveParentAcceptsRow(source_parent)) + return true; + + // Go down the tree and accept this row if a child is accepted + if (filter_recursive && recursiveChildAcceptsRow(source_row, source_parent)) + return true; + + return false; +} + +bool QSortFilterProxyModelPrivate::recursiveParentAcceptsRow(const QModelIndex &source_parent) const +{ + Q_Q(const QSortFilterProxyModel); + + if (source_parent.isValid()) { + const QModelIndex index = source_parent.parent(); + + if (q->filterAcceptsRow(source_parent.row(), index)) + return true; + + return recursiveParentAcceptsRow(index); + } + + return false; +} + +bool QSortFilterProxyModelPrivate::recursiveChildAcceptsRow(int source_row, const QModelIndex &source_parent) const +{ + Q_Q(const QSortFilterProxyModel); + const QModelIndex index = model->index(source_row, 0, source_parent); const int count = model->rowCount(index); for (int i = 0; i < count; ++i) { - if (filterRecursiveAcceptsRow(i, index)) + if (q->filterAcceptsRow(i, index)) + return true; + + if (recursiveChildAcceptsRow(i, index)) return true; } @@ -1878,6 +1906,7 @@ QSortFilterProxyModel::QSortFilterProxyModel(QObject *parent) 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())); @@ -2763,6 +2792,7 @@ void QSortFilterProxyModel::setFilterRole(int role) The default value is false. + \sa autoAcceptChildRows \sa filterAcceptsRow() */ @@ -2789,6 +2819,43 @@ void QSortFilterProxyModel::setRecursiveFilteringEnabled(bool recursive) emit recursiveFilteringEnabledChanged(recursive); } +/*! + \since 6.0 + \property QSortFilterProxyModel::autoAcceptChildRows + \brief if true the proxy model will not filter out children of accepted + rows, even if they themselves would be filtered out otherwise. + + The default value is false. + + \sa recursiveFilteringEnabled + \sa filterAcceptsRow() +*/ + +/*! + \since 6.0 + \fn void QSortFilterProxyModel::showMatchesChildrenChanged(bool autoAcceptChildRows) + \brief This signals is emitted when the value of the \a autoAcceptChildRows property is changed. + + \sa autoAcceptChildRows +*/ +bool QSortFilterProxyModel::autoAcceptChildRows() const +{ + Q_D(const QSortFilterProxyModel); + return d->accept_children; +} + +void QSortFilterProxyModel::setAutoAcceptChildRows(bool accept) +{ + Q_D(QSortFilterProxyModel); + if (d->accept_children == accept) + return; + + d->filter_about_to_be_changed(); + d->accept_children = accept; + d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows); + emit autoAcceptChildRowsChanged(accept); +} + #if QT_DEPRECATED_SINCE(5, 11) /*! \obsolete diff --git a/src/corelib/itemmodels/qsortfilterproxymodel.h b/src/corelib/itemmodels/qsortfilterproxymodel.h index b7d4e69cb9..647b1616ce 100644 --- a/src/corelib/itemmodels/qsortfilterproxymodel.h +++ b/src/corelib/itemmodels/qsortfilterproxymodel.h @@ -72,6 +72,7 @@ class Q_CORE_EXPORT QSortFilterProxyModel : public QAbstractProxyModel Q_PROPERTY(int sortRole READ sortRole WRITE setSortRole NOTIFY sortRoleChanged) Q_PROPERTY(int filterRole READ filterRole WRITE setFilterRole NOTIFY filterRoleChanged) Q_PROPERTY(bool recursiveFilteringEnabled READ isRecursiveFilteringEnabled WRITE setRecursiveFilteringEnabled NOTIFY recursiveFilteringEnabledChanged) + Q_PROPERTY(bool autoAcceptChildRows READ autoAcceptChildRows WRITE setAutoAcceptChildRows NOTIFY autoAcceptChildRowsChanged) public: explicit QSortFilterProxyModel(QObject *parent = nullptr); @@ -116,6 +117,9 @@ public: bool isRecursiveFilteringEnabled() const; void setRecursiveFilteringEnabled(bool recursive); + bool autoAcceptChildRows() const; + void setAutoAcceptChildRows(bool accept); + public Q_SLOTS: #if QT_CONFIG(regularexpression) void setFilterRegularExpression(const QString &pattern); @@ -190,6 +194,7 @@ Q_SIGNALS: void sortRoleChanged(int sortRole); void filterRoleChanged(int filterRole); void recursiveFilteringEnabledChanged(bool recursiveFilteringEnabled); + void autoAcceptChildRowsChanged(bool autoAcceptChildRows); private: Q_DECLARE_PRIVATE(QSortFilterProxyModel) diff --git a/tests/auto/corelib/itemmodels/qsortfilterproxymodel_recursive/tst_qsortfilterproxymodel_recursive.cpp b/tests/auto/corelib/itemmodels/qsortfilterproxymodel_recursive/tst_qsortfilterproxymodel_recursive.cpp index dbafedbb5d..35ae7f4a7f 100644 --- a/tests/auto/corelib/itemmodels/qsortfilterproxymodel_recursive/tst_qsortfilterproxymodel_recursive.cpp +++ b/tests/auto/corelib/itemmodels/qsortfilterproxymodel_recursive/tst_qsortfilterproxymodel_recursive.cpp @@ -715,6 +715,38 @@ private Q_SLOTS: } + void testChildrenFiltering_data() + { + QTest::addColumn("sourceStr"); + QTest::addColumn("noChildrenProxyStr"); + QTest::addColumn("childrenProxyStr"); + QTest::addColumn("noParentProxyStr"); + + QTest::newRow("filter_parent") << "[1*[1.1 1.2[1.2.1]]]" << "[1*]" << "[1*[1.1 1.2[1.2.1]]]" << "[1*[1.1 1.2[1.2.1]]]"; + QTest::newRow("filter_child") << "[1[1.1 1.2*[1.2.1]]]" << "[1[1.2*]]" << "[1[1.2*[1.2.1]]]" << ""; + + } + + void testChildrenFiltering() + { + QFETCH(QString, sourceStr); + QFETCH(QString, noChildrenProxyStr); + QFETCH(QString, childrenProxyStr); + QFETCH(QString, noParentProxyStr); + + QStandardItemModel model; + fillModel(model, sourceStr); + + TestModel proxy(&model); + QCOMPARE(treeAsString(proxy), noChildrenProxyStr); + + proxy.setAutoAcceptChildRows(true); + QCOMPARE(treeAsString(proxy), childrenProxyStr); + + proxy.setRecursiveFilteringEnabled(false); + QCOMPARE(treeAsString(proxy), noParentProxyStr); + } + private: QStandardItem *itemByText(const QStandardItemModel& model, const QString &text) const { QModelIndexList list = model.match(model.index(0, 0), Qt::DisplayRole, text, 1, Qt::MatchRecursive);