File indexing completed on 2025-03-23 06:49:11
0001 /* 0002 * Copyright 2010 by Marco Martin <mart@kde.org> 0003 * Copyright 2019 by David Edmundson <davidedmundson@kde.org> 0004 * 0005 * This program is free software; you can redistribute it and/or modify 0006 * it under the terms of the GNU Library General Public License as 0007 * published by the Free Software Foundation; either version 2, or 0008 * (at your option) any later version. 0009 * 0010 * This program is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 * GNU General Public License for more details 0014 * 0015 * You should have received a copy of the GNU Library General Public 0016 * License along with this program; if not, write to the 0017 * Free Software Foundation, Inc., 0018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 0019 */ 0020 0021 #ifndef KSORTFILTERPROXYMODEL_H 0022 #define KSORTFILTERPROXYMODEL_H 0023 0024 #include <QAbstractItemModel> 0025 #include <QJSValue> 0026 #include <QList> 0027 #include <QQmlParserStatus> 0028 #include <QSortFilterProxyModel> 0029 0030 #include <array> 0031 0032 /** 0033 * @class SortFilterModel 0034 * @short Filter and sort an existing QAbstractItemModel 0035 * 0036 * @since 5.67 0037 */ 0038 class KSortFilterProxyModel : public QSortFilterProxyModel, public QQmlParserStatus 0039 { 0040 Q_OBJECT 0041 Q_INTERFACES(QQmlParserStatus) 0042 0043 /** 0044 * The string for the filter, only rows with their filterRole matching filterString will be displayed 0045 */ 0046 Q_PROPERTY(QString filterString READ filterString WRITE setFilterString NOTIFY filterStringChanged) 0047 /** 0048 * A JavaScript callable that can be used to perform advanced filters on a given row. 0049 * The callback is passed the source row, and source parent for a given row as arguments 0050 * 0051 * The callable's return value is evaluated as boolean to determine 0052 * whether the row is accepted (true) or filtered out (false). It overrides the default implementation 0053 * that uses filterRegExp or filterString; while filterCallback is set those two properties are 0054 * ignored. Attempts to write a non-callable to this property are silently ignored, but you can set 0055 * it to null. 0056 * 0057 * @code 0058 * filterRowCallback: function(source_row, source_parent) { 0059 * return sourceModel.data(sourceModel.index(source_row, 0, source_parent), Qt.DisplayRole) == "..."; 0060 * }; 0061 * @endcode 0062 */ 0063 Q_PROPERTY(QJSValue filterRowCallback READ filterRowCallback WRITE setFilterRowCallback NOTIFY filterRowCallbackChanged) 0064 0065 /** 0066 * A JavaScript callable that can be used to perform advanced filters on a given column. 0067 * The callback is passed the source column, and source parent for a given column as arguments. 0068 * 0069 * @see filterRowCallback 0070 */ 0071 Q_PROPERTY(QJSValue filterColumnCallback READ filterColumnCallback WRITE setFilterColumnCallback NOTIFY filterColumnCallbackChanged) 0072 0073 /** 0074 * The role of the sourceModel on which the filter will be applied. 0075 * This can either be the numerical role value or the role name as a string. 0076 */ 0077 Q_PROPERTY(QString filterRoleName READ filterRoleName WRITE setFilterRoleName NOTIFY filterRoleNameChanged) 0078 0079 /** 0080 * The role of the sourceModel that will be used for sorting. if empty the order will be left unaltered 0081 * This can either be the numerical role value or the role name as a string. 0082 */ 0083 Q_PROPERTY(QString sortRoleName READ sortRoleName WRITE setSortRoleName NOTIFY sortRoleNameChanged) 0084 0085 /** 0086 * One of Qt.AscendingOrder or Qt.DescendingOrder 0087 */ 0088 Q_PROPERTY(Qt::SortOrder sortOrder READ sortOrder WRITE setSortOrder NOTIFY sortOrderChanged) 0089 0090 /** 0091 * Specify which column should be used for sorting 0092 * The default value is -1. 0093 * If \a sortRole is set, the default value is 0. 0094 */ 0095 Q_PROPERTY(int sortColumn READ sortColumn WRITE setSortColumn NOTIFY sortColumnChanged) 0096 0097 /** 0098 * The number of top level rows. 0099 */ 0100 Q_PROPERTY(int count READ rowCount NOTIFY rowCountChanged) 0101 0102 public: 0103 explicit KSortFilterProxyModel(QObject *parent = nullptr); 0104 ~KSortFilterProxyModel() override; 0105 0106 void setSourceModel(QAbstractItemModel *sourceModel) override; 0107 0108 void setFilterRowCallback(const QJSValue &callback); 0109 QJSValue filterRowCallback() const; 0110 0111 void setFilterString(const QString &filterString); 0112 QString filterString() const; 0113 0114 void setFilterColumnCallback(const QJSValue &callback); 0115 QJSValue filterColumnCallback() const; 0116 0117 void setFilterRoleName(const QString &roleName); 0118 QString filterRoleName() const; 0119 0120 void setSortRoleName(const QString &roleName); 0121 QString sortRoleName() const; 0122 0123 void setSortOrder(const Qt::SortOrder order); 0124 void setSortColumn(int column); 0125 0126 void classBegin() override; 0127 void componentComplete() override; 0128 0129 public Q_SLOTS: 0130 /** 0131 * Invalidates the current filtering. 0132 * 0133 * This function should be called if you are implementing custom filtering through 0134 * filterRowCallback or filterColumnCallback, and your filter parameters have changed. 0135 * 0136 * @since 5.70 0137 */ 0138 void invalidateFilter(); 0139 0140 Q_SIGNALS: 0141 void filterStringChanged(); 0142 void filterRoleNameChanged(); 0143 void sortRoleNameChanged(); 0144 void sortOrderChanged(); 0145 void sortColumnChanged(); 0146 void filterRowCallbackChanged(const QJSValue &); 0147 void filterColumnCallbackChanged(const QJSValue &); 0148 void rowCountChanged(); 0149 0150 protected: 0151 int roleNameToId(const QString &name) const; 0152 bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; 0153 bool filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const override; 0154 0155 protected Q_SLOTS: 0156 // This method is called whenever we suspect that role names mapping might have gone stale. 0157 // It must not alter the source of truth for sort/filter properties. 0158 void syncRoleNames(); 0159 // These methods are dealing with individual pairs of properties. They are 0160 // called on various occasions, and need to check whether the invocation 0161 // has been caused by a standalone base type's property change 0162 // (switching source of truth to role ID) or as a side-effect of a sync. 0163 void syncSortRoleProperties(); 0164 void syncFilterRoleProperties(); 0165 0166 private: 0167 // conveniently, role ID is the default source of truth, turning it into 0168 // zero-initialization. 0169 enum SourceOfTruthForRoleProperty : bool { 0170 SourceOfTruthIsRoleID = false, 0171 SourceOfTruthIsRoleName = true, 0172 }; 0173 0174 bool m_componentCompleted : 1; 0175 SourceOfTruthForRoleProperty m_sortRoleSourceOfTruth : 1; 0176 SourceOfTruthForRoleProperty m_filterRoleSourceOfTruth : 1; 0177 bool m_sortRoleGuard : 1; 0178 bool m_filterRoleGuard : 1; 0179 // default role name corresponds to the standard mapping of the default Qt::DisplayRole in QAbstractItemModel::roleNames 0180 QString m_sortRoleName{QStringLiteral("display")}; 0181 QString m_filterRoleName{QStringLiteral("display")}; 0182 QString m_filterString; 0183 QJSValue m_filterRowCallback; 0184 QJSValue m_filterColumnCallback; 0185 QHash<QString, int> m_roleIds; 0186 std::array<QMetaObject::Connection, 3> m_sourceModelConnections; 0187 }; 0188 0189 #endif