File indexing completed on 2024-05-19 16:39:56
0001 /* 0002 * SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 #include "ProcessSortFilterModel.h" 0008 0009 #include <QDebug> 0010 0011 #include <processcore/process_data_model.h> 0012 0013 using namespace KSysGuard; 0014 0015 ProcessSortFilterModel::ProcessSortFilterModel(QObject *parent) 0016 : QSortFilterProxyModel(parent) 0017 { 0018 setSortRole(ProcessDataModel::Value); 0019 setSortCaseSensitivity(Qt::CaseInsensitive); 0020 setSortLocaleAware(true); 0021 0022 setFilterRole(ProcessDataModel::Value); 0023 setFilterCaseSensitivity(Qt::CaseInsensitive); 0024 setRecursiveFilteringEnabled(true); 0025 } 0026 0027 void ProcessSortFilterModel::setSourceModel(QAbstractItemModel *newSourceModel) 0028 { 0029 auto oldSourceModel = sourceModel(); 0030 0031 if (newSourceModel == oldSourceModel) { 0032 return; 0033 } 0034 0035 if (oldSourceModel) { 0036 oldSourceModel->disconnect(this); 0037 } 0038 0039 QSortFilterProxyModel::setSourceModel(newSourceModel); 0040 if (newSourceModel) { 0041 connect(newSourceModel, &QAbstractItemModel::modelReset, this, &ProcessSortFilterModel::findColumns); 0042 connect(newSourceModel, &QAbstractItemModel::columnsInserted, this, &ProcessSortFilterModel::findColumns); 0043 connect(newSourceModel, &QAbstractItemModel::columnsRemoved, this, &ProcessSortFilterModel::findColumns); 0044 connect(newSourceModel, &QAbstractItemModel::columnsMoved, this, &ProcessSortFilterModel::findColumns); 0045 findColumns(); 0046 } 0047 } 0048 0049 bool ProcessSortFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const 0050 { 0051 // not handled a reset yet, we'll invalidate at the end of modelReset anyway 0052 if (m_uidColumn == -1 && m_pidColumn == -1 && filterKeyColumn() == -1) { 0053 return false; 0054 } 0055 0056 0057 auto source = sourceModel(); 0058 0059 // Show regardless if an ancestor matches, this is kinda the inverse of recursiveFilteringEnabled 0060 if (sourceParent.parent().isValid()) { 0061 if (filterAcceptsRow(sourceParent.row(), sourceParent.parent())) { 0062 return true; 0063 } 0064 } 0065 0066 bool result = true; 0067 0068 if (m_viewMode != ViewAll && m_uidColumn != -1) { 0069 auto uid = source->data(source->index(sourceRow, m_uidColumn, sourceParent), ProcessDataModel::Value).toUInt(); 0070 0071 switch (m_viewMode) { 0072 case ViewOwn: 0073 result = m_currentUser.userId().nativeId() == uid; 0074 break; 0075 case ViewUser: 0076 result = uid >= 1000 && uid < 65534; 0077 break; 0078 case ViewSystem: 0079 result = uid < 1000 || uid >= 65534; 0080 break; 0081 default: 0082 break; 0083 } 0084 } 0085 0086 if (!m_filterPids.isEmpty()) { 0087 auto pid = source->data(source->index(sourceRow, m_pidColumn, sourceParent), ProcessDataModel::Value); 0088 result = m_filterPids.contains(pid); 0089 } 0090 0091 if (!result) { 0092 return false; 0093 } 0094 0095 if (filterString().isEmpty()) { 0096 return true; 0097 } 0098 0099 const QString name = source->data(source->index(sourceRow, 0, sourceParent), filterRole()).toString(); 0100 0101 const QString filter = filterString(); 0102 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0103 const QVector<QStringRef> splitFilterStrings = filter.splitRef(QLatin1Char(','), Qt::SkipEmptyParts); 0104 0105 for (const QStringRef &string : splitFilterStrings) { 0106 #else 0107 const QVector<QStringView> splitFilterStrings = QStringView(filter).split(QLatin1Char(','), Qt::SkipEmptyParts); 0108 0109 for (const QStringView &string : splitFilterStrings) { 0110 #endif 0111 if (name.contains(string.trimmed(), Qt::CaseInsensitive)) { 0112 return true; 0113 } 0114 } 0115 0116 return false; 0117 } 0118 0119 bool ProcessSortFilterModel::filterAcceptsColumn(int sourceColumn, const QModelIndex &sourceParent) const 0120 { 0121 Q_UNUSED(sourceParent) 0122 0123 auto attribute = sourceModel()->headerData(sourceColumn, Qt::Horizontal, ProcessDataModel::Attribute).toString(); 0124 if (m_hiddenAttributes.contains(attribute)) { 0125 return false; 0126 } 0127 0128 return true; 0129 } 0130 0131 QString ProcessSortFilterModel::filterString() const 0132 { 0133 return m_filterString; 0134 } 0135 0136 void ProcessSortFilterModel::setFilterString(const QString &newFilterString) 0137 { 0138 if (newFilterString == m_filterString) { 0139 return; 0140 } 0141 0142 m_filterString = newFilterString; 0143 setFilterWildcard(m_filterString); 0144 Q_EMIT filterStringChanged(); 0145 } 0146 0147 ProcessSortFilterModel::ViewMode ProcessSortFilterModel::viewMode() const 0148 { 0149 return m_viewMode; 0150 } 0151 0152 void ProcessSortFilterModel::setViewMode(ViewMode newViewMode) 0153 { 0154 if (newViewMode == m_viewMode) { 0155 return; 0156 } 0157 0158 m_viewMode = newViewMode; 0159 invalidateFilter(); 0160 Q_EMIT viewModeChanged(); 0161 } 0162 0163 QStringList ProcessSortFilterModel::hiddenAttributes() const 0164 { 0165 return m_hiddenAttributes; 0166 } 0167 0168 void ProcessSortFilterModel::setHiddenAttributes(const QStringList &newHiddenAttributes) 0169 { 0170 if (newHiddenAttributes == m_hiddenAttributes) { 0171 return; 0172 } 0173 0174 m_hiddenAttributes = newHiddenAttributes; 0175 invalidateFilter(); 0176 Q_EMIT hiddenAttributesChanged(); 0177 } 0178 0179 QVariantList ProcessSortFilterModel::filterPids() const 0180 { 0181 return m_filterPids; 0182 } 0183 0184 void ProcessSortFilterModel::setFilterPids(const QVariantList &newFilterPids) 0185 { 0186 if (newFilterPids == m_filterPids) { 0187 return; 0188 } 0189 0190 m_filterPids = newFilterPids; 0191 invalidateFilter(); 0192 Q_EMIT filterPidsChanged(); 0193 } 0194 0195 void ProcessSortFilterModel::sort(int column, Qt::SortOrder order) 0196 { 0197 QSortFilterProxyModel::sort(column, order); 0198 } 0199 0200 void ProcessSortFilterModel::findColumns() 0201 { 0202 m_uidColumn = -1; 0203 m_pidColumn = -1; 0204 int nameColumn = -1; 0205 0206 auto source = sourceModel(); 0207 0208 for (auto column = 0; column < source->columnCount(); ++column) { 0209 auto attribute = source->headerData(column, Qt::Horizontal, ProcessDataModel::Attribute).toString(); 0210 if (attribute == QStringLiteral("uid")) { 0211 m_uidColumn = column; 0212 } else if (attribute == QStringLiteral("pid")) { 0213 m_pidColumn = column; 0214 } else if (attribute == QStringLiteral("name")) { 0215 nameColumn = column; 0216 } 0217 } 0218 setFilterKeyColumn(nameColumn); 0219 }