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"