File indexing completed on 2024-05-12 15:43:02
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 #include "ksortfilterproxymodel.h" 0022 0023 #include <QQmlContext> 0024 #include <QQmlEngine> 0025 0026 #include "kitemmodels_debug.h" 0027 0028 KSortFilterProxyModel::KSortFilterProxyModel(QObject *parent) 0029 : QSortFilterProxyModel(parent) 0030 { 0031 setDynamicSortFilter(true); 0032 connect(this, &KSortFilterProxyModel::modelReset, this, &KSortFilterProxyModel::rowCountChanged); 0033 connect(this, &KSortFilterProxyModel::rowsInserted, this, &KSortFilterProxyModel::rowCountChanged); 0034 connect(this, &KSortFilterProxyModel::rowsRemoved, this, &KSortFilterProxyModel::rowCountChanged); 0035 } 0036 0037 KSortFilterProxyModel::~KSortFilterProxyModel() 0038 { 0039 } 0040 0041 void KSortFilterProxyModel::syncRoleNames() 0042 { 0043 if (!sourceModel()) { 0044 return; 0045 } 0046 0047 m_roleIds.clear(); 0048 const QHash<int, QByteArray> rNames = roleNames(); 0049 m_roleIds.reserve(rNames.count()); 0050 for (auto i = rNames.constBegin(); i != rNames.constEnd(); ++i) { 0051 m_roleIds[QString::fromUtf8(i.value())] = i.key(); 0052 } 0053 } 0054 0055 int KSortFilterProxyModel::roleNameToId(const QString &name) const 0056 { 0057 return m_roleIds.value(name, Qt::DisplayRole); 0058 } 0059 0060 void KSortFilterProxyModel::setModel(QAbstractItemModel *model) 0061 { 0062 if (model == sourceModel()) { 0063 return; 0064 } 0065 0066 QSortFilterProxyModel::setSourceModel(model); 0067 if (m_componentCompleted) { 0068 syncRoleNames(); 0069 setFilterRole(m_filterRole); 0070 setSortRole(m_sortRole); 0071 } 0072 } 0073 0074 bool KSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const 0075 { 0076 if (m_filterRowCallback.isCallable()) { 0077 QJSEngine *engine = qjsEngine(this); 0078 QJSValueList args = {QJSValue(source_row), engine->toScriptValue(source_parent)}; 0079 0080 QJSValue result = const_cast<KSortFilterProxyModel *>(this)->m_filterRowCallback.call(args); 0081 if (result.isError()) { 0082 qCWarning(KITEMMODELS_LOG) << "Row filter callback produced an error:"; 0083 qCWarning(KITEMMODELS_LOG) << result.toString(); 0084 return true; 0085 } else { 0086 return result.toBool(); 0087 } 0088 } 0089 0090 return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); 0091 } 0092 0093 bool KSortFilterProxyModel::filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const 0094 { 0095 if (m_filterColumnCallback.isCallable()) { 0096 QJSEngine *engine = qjsEngine(this); 0097 QJSValueList args = {QJSValue(source_column), engine->toScriptValue(source_parent)}; 0098 0099 QJSValue result = const_cast<KSortFilterProxyModel *>(this)->m_filterColumnCallback.call(args); 0100 if (result.isError()) { 0101 qCWarning(KITEMMODELS_LOG) << "Row filter callback produced an error:"; 0102 qCWarning(KITEMMODELS_LOG) << result.toString(); 0103 return true; 0104 } else { 0105 return result.toBool(); 0106 } 0107 } 0108 0109 return QSortFilterProxyModel::filterAcceptsColumn(source_column, source_parent); 0110 } 0111 0112 void KSortFilterProxyModel::setFilterString(const QString &filterString) 0113 { 0114 if (filterString == m_filterString) { 0115 return; 0116 } 0117 m_filterString = filterString; 0118 QSortFilterProxyModel::setFilterFixedString(filterString); 0119 Q_EMIT filterStringChanged(); 0120 } 0121 0122 QString KSortFilterProxyModel::filterString() const 0123 { 0124 return m_filterString; 0125 } 0126 0127 QJSValue KSortFilterProxyModel::filterRowCallback() const 0128 { 0129 return m_filterRowCallback; 0130 } 0131 0132 void KSortFilterProxyModel::setFilterRowCallback(const QJSValue &callback) 0133 { 0134 if (m_filterRowCallback.strictlyEquals(callback)) { 0135 return; 0136 } 0137 0138 if (!callback.isNull() && !callback.isCallable()) { 0139 return; 0140 } 0141 0142 m_filterRowCallback = callback; 0143 invalidateFilter(); 0144 0145 Q_EMIT filterRowCallbackChanged(callback); 0146 } 0147 0148 void KSortFilterProxyModel::setFilterColumnCallback(const QJSValue &callback) 0149 { 0150 if (m_filterColumnCallback.strictlyEquals(callback)) { 0151 return; 0152 } 0153 0154 if (!callback.isNull() && !callback.isCallable()) { 0155 return; 0156 } 0157 0158 m_filterColumnCallback = callback; 0159 invalidateFilter(); 0160 0161 Q_EMIT filterColumnCallbackChanged(callback); 0162 } 0163 0164 QJSValue KSortFilterProxyModel::filterColumnCallback() const 0165 { 0166 return m_filterColumnCallback; 0167 } 0168 0169 void KSortFilterProxyModel::setFilterRole(const QVariant &role) 0170 { 0171 if (role.type() == QVariant::String) { 0172 QSortFilterProxyModel::setFilterRole(roleNameToId(role.toString())); 0173 m_filterRole = role; 0174 Q_EMIT filterRoleChanged(); 0175 } else if (role.canConvert<int>()) { 0176 QSortFilterProxyModel::setFilterRole(role.toInt()); 0177 m_filterRole = role; 0178 Q_EMIT filterRoleChanged(); 0179 } else if (!role.isNull()) { 0180 qCWarning(KITEMMODELS_LOG) << "invalid filter role:" << role; 0181 } 0182 } 0183 0184 QVariant KSortFilterProxyModel::filterRole() const 0185 { 0186 return m_filterRole; 0187 } 0188 0189 void KSortFilterProxyModel::setSortRole(const QVariant &role) 0190 { 0191 if (role.type() == QVariant::String) { 0192 m_sortRole = role; 0193 const auto roleName = role.toString(); 0194 if (roleName.isEmpty()) { 0195 sort(-1, Qt::AscendingOrder); 0196 } else if (sourceModel()) { 0197 QSortFilterProxyModel::setSortRole(roleNameToId(roleName)); 0198 sort(std::max(sortColumn(), 0), sortOrder()); 0199 } 0200 Q_EMIT sortRoleChanged(); 0201 } else if (role.canConvert<int>()) { 0202 m_sortRole = role; 0203 const auto roleId = role.toInt(); 0204 if (sourceModel()) { 0205 QSortFilterProxyModel::setSortRole(roleId); 0206 sort(std::max(sortColumn(), 0), sortOrder()); 0207 } 0208 Q_EMIT sortRoleChanged(); 0209 } else if (!role.isNull()) { 0210 qCWarning(KITEMMODELS_LOG) << "invalid sort role:" << role; 0211 } 0212 } 0213 0214 QVariant KSortFilterProxyModel::sortRole() const 0215 { 0216 return m_sortRole; 0217 } 0218 0219 void KSortFilterProxyModel::setSortOrder(const Qt::SortOrder order) 0220 { 0221 sort(std::max(sortColumn(), 0), order); 0222 Q_EMIT sortOrderChanged(); 0223 } 0224 0225 void KSortFilterProxyModel::setSortColumn(int column) 0226 { 0227 if (column == sortColumn()) { 0228 return; 0229 } 0230 sort(column, sortOrder()); 0231 Q_EMIT sortColumnChanged(); 0232 } 0233 0234 void KSortFilterProxyModel::classBegin() 0235 { 0236 } 0237 0238 void KSortFilterProxyModel::componentComplete() 0239 { 0240 m_componentCompleted = true; 0241 if (sourceModel()) { 0242 syncRoleNames(); 0243 setFilterRole(m_filterRole); 0244 setSortRole(m_sortRole); 0245 } 0246 } 0247 0248 void KSortFilterProxyModel::invalidateFilter() 0249 { 0250 QSortFilterProxyModel::invalidateFilter(); 0251 } 0252 0253 bool KSortFilterProxyModel::removeRow(int row, const QModelIndex &parent) 0254 { 0255 return QSortFilterProxyModel::removeRow(row, parent); 0256 } 0257 0258 bool KSortFilterProxyModel::removeRows(int row, int count, const QModelIndex &parent) 0259 { 0260 return QSortFilterProxyModel::removeRows(row, count, parent); 0261 } 0262 0263 #include "moc_ksortfilterproxymodel.cpp"