File indexing completed on 2024-06-09 05:18:06

0001 /*
0002 
0003   SPDX-FileCopyrightText: 2010-2024 Laurent Montel <montel@kde.org>
0004 
0005   SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "entitycollectionorderproxymodel.h"
0009 #include "hierarchicalfoldermatcher_p.h"
0010 #include "kernel/mailkernel.h"
0011 #include "mailcommon_debug.h"
0012 #include "util/mailutil.h"
0013 #include <Akonadi/AgentManager>
0014 #include <Akonadi/Collection>
0015 #include <Akonadi/EntityTreeModel>
0016 #include <Akonadi/SpecialMailCollections>
0017 
0018 using namespace MailCommon;
0019 class Q_DECL_HIDDEN MailCommon::EntityCollectionOrderProxyModel::EntityCollectionOrderProxyModelPrivate
0020 {
0021 public:
0022     EntityCollectionOrderProxyModelPrivate() = default;
0023 
0024     int collectionRank(const Akonadi::Collection &collection)
0025     {
0026         const Akonadi::Collection::Id id = collection.id();
0027         const int cachedRank = collectionRanks.value(id, -1);
0028         if (cachedRank != -1) {
0029             return cachedRank;
0030         }
0031 
0032         int rank = 100;
0033         if (Kernel::folderIsInbox(collection)) {
0034             rank = 1;
0035         } else if (Kernel::self()->folderIsDraftOrOutbox(collection)) {
0036             if (Kernel::self()->folderIsDrafts(collection)) {
0037                 rank = 5;
0038             } else {
0039                 rank = 2;
0040             }
0041         } else if (Kernel::self()->folderIsSentMailFolder(collection)) {
0042             rank = 3;
0043         } else if (Kernel::self()->folderIsTrash(collection)) {
0044             rank = 4;
0045         } else if (Kernel::self()->folderIsTemplates(collection)) {
0046             rank = 6;
0047         } else if (MailCommon::Util::isVirtualCollection(collection)) {
0048             rank = 200;
0049         } else if (collection.parentCollection() == Akonadi::Collection::root() && MailCommon::Util::isUnifiedMailboxesAgent(collection)) {
0050             // special treatment for Unified Mailboxes: they are *always* on top
0051             rank = 0;
0052         } else if (!topLevelOrder.isEmpty()) {
0053             if (collection.parentCollection() == Akonadi::Collection::root()) {
0054                 const QString resource = collection.resource();
0055                 if (resource.isEmpty()) {
0056                     qCDebug(MAILCOMMON_LOG) << " collection has not resource: " << collection;
0057                     // Don't save in collectionranks because we don't have resource name => pb.
0058                     return rank;
0059                 }
0060                 const int order = topLevelOrder.indexOf(resource);
0061                 if (order != -1) {
0062                     rank = order + 1; /* top-level rank "0" belongs to Unified Mailboxes */
0063                 }
0064             }
0065         }
0066         collectionRanks.insert(id, rank);
0067         return rank;
0068     }
0069 
0070     QMap<Akonadi::Collection::Id, int> collectionRanks;
0071     QStringList topLevelOrder;
0072     HierarchicalFolderMatcher matcher;
0073     bool manualSortingActive = false;
0074 };
0075 
0076 EntityCollectionOrderProxyModel::EntityCollectionOrderProxyModel(QObject *parent)
0077     : EntityOrderProxyModel(parent)
0078     , d(new EntityCollectionOrderProxyModelPrivate())
0079 {
0080     setSortCaseSensitivity(Qt::CaseInsensitive);
0081     connect(Akonadi::SpecialMailCollections::self(),
0082             &Akonadi::SpecialMailCollections::defaultCollectionsChanged,
0083             this,
0084             &EntityCollectionOrderProxyModel::slotSpecialCollectionsChanged);
0085     connect(Akonadi::SpecialMailCollections::self(),
0086             &Akonadi::SpecialMailCollections::collectionsChanged,
0087             this,
0088             &EntityCollectionOrderProxyModel::slotSpecialCollectionsChanged);
0089 }
0090 
0091 EntityCollectionOrderProxyModel::~EntityCollectionOrderProxyModel()
0092 {
0093     if (d->manualSortingActive) {
0094         saveOrder();
0095     }
0096 }
0097 
0098 void EntityCollectionOrderProxyModel::slotSpecialCollectionsChanged()
0099 {
0100     if (!d->manualSortingActive) {
0101         d->collectionRanks.clear();
0102         invalidate();
0103     }
0104 }
0105 
0106 void EntityCollectionOrderProxyModel::setTopLevelOrder(const QStringList &list)
0107 {
0108     d->topLevelOrder = list;
0109     clearRanks();
0110 }
0111 
0112 void EntityCollectionOrderProxyModel::clearRanks()
0113 {
0114     d->collectionRanks.clear();
0115     invalidate();
0116 }
0117 
0118 bool EntityCollectionOrderProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
0119 {
0120     const auto leftData = left.data(Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
0121     const auto rightData = right.data(Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
0122     if (!d->manualSortingActive) {
0123         const int rankLeft = d->collectionRank(leftData);
0124         const int rankRight = d->collectionRank(rightData);
0125 
0126         if (rankLeft < rankRight) {
0127             return true;
0128         } else if (rankLeft > rankRight) {
0129             return false;
0130         }
0131 
0132         return QSortFilterProxyModel::lessThan(left, right);
0133     }
0134 
0135     if (MailCommon::Util::isUnifiedMailboxesAgent(leftData)) {
0136         return true;
0137     } else {
0138         return EntityOrderProxyModel::lessThan(left, right);
0139     }
0140 }
0141 
0142 void EntityCollectionOrderProxyModel::setManualSortingActive(bool active)
0143 {
0144     if (d->manualSortingActive == active) {
0145         return;
0146     }
0147 
0148     d->manualSortingActive = active;
0149     d->collectionRanks.clear();
0150     invalidate();
0151 }
0152 
0153 bool EntityCollectionOrderProxyModel::isManualSortingActive() const
0154 {
0155     return d->manualSortingActive;
0156 }
0157 
0158 void EntityCollectionOrderProxyModel::setFolderMatcher(const HierarchicalFolderMatcher &matcher)
0159 {
0160     d->matcher = matcher;
0161     invalidateFilter();
0162 }
0163 
0164 bool EntityCollectionOrderProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
0165 {
0166     if (d->matcher.isNull()) {
0167         return EntityOrderProxyModel::filterAcceptsRow(sourceRow, sourceParent);
0168     }
0169     const QModelIndex sourceIndex = sourceModel()->index(sourceRow, filterKeyColumn(), sourceParent);
0170     return d->matcher.matches(sourceModel(), sourceIndex, filterRole());
0171 }
0172 
0173 #include "moc_entitycollectionorderproxymodel.cpp"