File indexing completed on 2024-05-19 05:14:36

0001 /*
0002     SPDX-FileCopyrightText: 2014 Jonathan Marten <jjm@keelhaul.me.uk>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "categoryfilterproxymodel.h"
0008 
0009 #include "kaddressbook_debug.h"
0010 
0011 #include <Akonadi/EntityTreeModel>
0012 #include <Akonadi/Item>
0013 
0014 #include <KContacts/Addressee>
0015 #include <KContacts/ContactGroup>
0016 
0017 #include "categoryselectwidget.h"
0018 
0019 using namespace Akonadi;
0020 
0021 class CategoryFilterProxyModelPrivate : public QObject
0022 {
0023     Q_OBJECT
0024     Q_DECLARE_PUBLIC(CategoryFilterProxyModel)
0025 
0026 public:
0027     explicit CategoryFilterProxyModelPrivate(CategoryFilterProxyModel *parent);
0028 
0029     QList<Tag> filterTagList;
0030     bool filterEnabled = false;
0031 
0032     bool containsId(Akonadi::Tag::Id id) const
0033     {
0034         for (const Tag &tag : filterTagList) {
0035             if (tag.id() == id) {
0036                 return true; // a category matches filter
0037             }
0038         }
0039         return false;
0040     }
0041     bool containsName(const QString &cat) const
0042     {
0043         for (const Tag &tag : filterTagList) {
0044             if (tag.name() == cat) {
0045                 return true; // a category matches filter
0046             }
0047         }
0048         return false;
0049     }
0050 
0051 private:
0052     CategoryFilterProxyModel *const q_ptr;
0053 };
0054 
0055 CategoryFilterProxyModelPrivate::CategoryFilterProxyModelPrivate(CategoryFilterProxyModel *parent)
0056     : QObject()
0057     , q_ptr(parent)
0058 {
0059 }
0060 
0061 CategoryFilterProxyModel::CategoryFilterProxyModel(QObject *parent)
0062     : QSortFilterProxyModel(parent)
0063     , d_ptr(new CategoryFilterProxyModelPrivate(this))
0064 {
0065     setDynamicSortFilter(true);
0066 }
0067 
0068 CategoryFilterProxyModel::~CategoryFilterProxyModel() = default;
0069 
0070 bool CategoryFilterProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const
0071 {
0072     Q_D(const CategoryFilterProxyModel);
0073 
0074     const QModelIndex index = sourceModel()->index(row, 0, parent);
0075     const auto item = index.data(EntityTreeModel::ItemRole).value<Akonadi::Item>();
0076 
0077     if (!d->filterEnabled) {
0078         return true; // filter not enabled
0079     }
0080     if (d->filterTagList.isEmpty()) {
0081         return false; // nothing accepted
0082     }
0083     // all accepted
0084     if (d->filterTagList.at(0).id() == CategorySelectWidget::FilterAll) {
0085         return true;
0086     }
0087 
0088     if (item.hasPayload<KContacts::Addressee>()) {
0089         const auto contact = item.payload<KContacts::Addressee>();
0090 
0091         const QStringList categories = contact.categories();
0092 
0093         int validCategories = 0;
0094         int count = categories.count();
0095         for (int i = 0; i < count; ++i) {
0096             const QString cat = categories.at(i);
0097             if (cat.startsWith(QLatin1StringView("akonadi:"))) {
0098                 const int idx = cat.indexOf(QLatin1StringView("?tag="));
0099                 if (idx >= 0) {
0100                     ++validCategories;
0101                     Tag::Id id = QStringView(cat).mid(idx + 5).toInt();
0102                     if (d->containsId(id)) {
0103                         return true; // a category matches filter
0104                     }
0105                 }
0106             } else {
0107                 ++validCategories;
0108                 if (d->containsName(cat)) {
0109                     return true; // a category matches filter
0110                 }
0111             }
0112         }
0113 
0114         if (validCategories > 0) {
0115             return false; // categorised but no match
0116         } else {
0117             return d->containsId(CategorySelectWidget::FilterUntagged);
0118         }
0119     } else if (item.hasPayload<KContacts::ContactGroup>()) { // a contact group item
0120         return d->containsId(CategorySelectWidget::FilterGroups);
0121     }
0122 
0123     return true; // not a recognised item
0124 }
0125 
0126 void CategoryFilterProxyModel::setFilterCategories(const QList<Akonadi::Tag> &tagList)
0127 {
0128     Q_D(CategoryFilterProxyModel);
0129 
0130     if (tagList != d->filterTagList) {
0131         d->filterTagList = tagList;
0132         invalidateFilter();
0133     }
0134 }
0135 
0136 void CategoryFilterProxyModel::setFilterEnabled(bool enable)
0137 {
0138     Q_D(CategoryFilterProxyModel);
0139 
0140     if (enable != d->filterEnabled) {
0141         d->filterEnabled = enable;
0142         invalidateFilter();
0143     }
0144 }
0145 
0146 #include "categoryfilterproxymodel.moc"
0147 
0148 #include "moc_categoryfilterproxymodel.cpp"