Warning, file /pim/mailcommon/src/folder/foldertreewidgetproxymodel.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002   SPDX-FileCopyrightText: 2009-2024 Laurent Montel <montel@kde.org>
0003 
0004   SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "foldertreewidgetproxymodel.h"
0008 #include "foldersettings.h"
0009 #include "kernel/mailkernel.h"
0010 #include "util/mailutil.h"
0011 
0012 #include <MessageCore/MessageCoreSettings>
0013 
0014 #include <Akonadi/AgentInstance>
0015 #include <Akonadi/AgentManager>
0016 #include <Akonadi/EntityTreeModel>
0017 #include <Akonadi/MimeTypeChecker>
0018 
0019 #include <Akonadi/CollectionQuotaAttribute>
0020 #include <KColorScheme>
0021 #include <KLocalizedString>
0022 
0023 #include <QIcon>
0024 #include <QPalette>
0025 
0026 using namespace MailCommon;
0027 class FolderTreeWidgetProxyModel::FolderTreeWidgetProxyModelPrivate
0028 {
0029 public:
0030     FolderTreeWidgetProxyModelPrivate(FolderTreeWidgetProxyModel *qq)
0031         : q(qq)
0032     {
0033     }
0034 
0035     bool checkQuotaExcedded(const QModelIndex &index, qreal &percentage)
0036     {
0037         if (threshold >= 0.0) {
0038             if (index.model()->hasChildren(index)) {
0039                 const int rowCount = index.model()->rowCount(index);
0040                 for (int row = 0; row < rowCount; row++) {
0041                     const QModelIndex firstIndex = q->mapToSource(index.model()->index(row, 0, index));
0042 
0043                     const auto collectionFirst = q->sourceModel()->data(firstIndex, Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
0044                     if (collectionFirst.isValid() && collectionFirst.hasAttribute<Akonadi::CollectionQuotaAttribute>()) {
0045                         const auto quota = collectionFirst.attribute<Akonadi::CollectionQuotaAttribute>();
0046 
0047                         if (quota->currentValue() > -1 && quota->maximumValue() > 0) {
0048                             percentage = (100.0 * quota->currentValue()) / quota->maximumValue();
0049                             if (percentage >= threshold) {
0050                                 return true;
0051                             }
0052                         }
0053                     }
0054                 }
0055             }
0056         }
0057         return false;
0058     }
0059 
0060     QSet<QString> includedMimeTypes;
0061     Akonadi::MimeTypeChecker checker;
0062 
0063     QColor brokenAccountColor;
0064     qreal threshold = -1.0;
0065     FolderTreeWidgetProxyModel *const q;
0066     bool enableCheck = false;
0067     bool hideVirtualFolder = false;
0068     bool hideSpecificFolder = false;
0069     bool hideOutboxFolder = false;
0070 };
0071 
0072 FolderTreeWidgetProxyModel::FolderTreeWidgetProxyModel(QObject *parent, FolderTreeWidgetProxyModelOptions option)
0073     : Akonadi::EntityRightsFilterModel(parent)
0074     , d(new FolderTreeWidgetProxyModelPrivate(this))
0075 {
0076     setDynamicSortFilter(true);
0077     setFilterCaseSensitivity(Qt::CaseInsensitive);
0078 
0079     if (option & HideVirtualFolder) {
0080         d->hideVirtualFolder = true;
0081     }
0082     if (option & HideSpecificFolder) {
0083         d->hideSpecificFolder = true;
0084     }
0085     if (option & HideOutboxFolder) {
0086         d->hideOutboxFolder = true;
0087     }
0088     readConfig();
0089 }
0090 
0091 FolderTreeWidgetProxyModel::~FolderTreeWidgetProxyModel() = default;
0092 
0093 void FolderTreeWidgetProxyModel::setWarningThreshold(qreal threshold)
0094 {
0095     d->threshold = threshold;
0096 }
0097 
0098 void FolderTreeWidgetProxyModel::readConfig()
0099 {
0100     invalidate();
0101 }
0102 
0103 Qt::ItemFlags FolderTreeWidgetProxyModel::flags(const QModelIndex &index) const
0104 {
0105     if (d->enableCheck) {
0106         const QModelIndex sourceIndex = mapToSource(index);
0107         const QModelIndex rowIndex = sourceIndex.sibling(sourceIndex.row(), 0);
0108         const auto collection = sourceModel()->data(rowIndex, Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
0109         if (!MailCommon::Util::isVirtualCollection(collection)) {
0110             const Akonadi::AgentInstance instance = Akonadi::AgentManager::self()->instance(collection.resource());
0111             if (instance.status() == Akonadi::AgentInstance::Broken) {
0112                 return QSortFilterProxyModel::flags(sourceIndex) & ~(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
0113             }
0114         }
0115         return Akonadi::EntityRightsFilterModel::flags(index);
0116     }
0117     return QSortFilterProxyModel::flags(index);
0118 }
0119 
0120 void FolderTreeWidgetProxyModel::setEnabledCheck(bool enable)
0121 {
0122     if (d->enableCheck == enable) {
0123         return;
0124     }
0125 
0126     d->enableCheck = enable;
0127     if (enable) {
0128         setAccessRights(Akonadi::Collection::CanCreateItem | Akonadi::Collection::CanCreateCollection);
0129     }
0130 }
0131 
0132 bool FolderTreeWidgetProxyModel::enabledCheck() const
0133 {
0134     return d->enableCheck;
0135 }
0136 
0137 void FolderTreeWidgetProxyModel::setHideVirtualFolder(bool exclude)
0138 {
0139     if (d->hideVirtualFolder != exclude) {
0140         d->hideVirtualFolder = exclude;
0141         invalidate();
0142     }
0143 }
0144 
0145 bool FolderTreeWidgetProxyModel::hideVirtualFolder() const
0146 {
0147     return d->hideVirtualFolder;
0148 }
0149 
0150 void FolderTreeWidgetProxyModel::setHideSpecificFolder(bool hide)
0151 {
0152     if (d->hideSpecificFolder != hide) {
0153         d->hideSpecificFolder = hide;
0154         invalidate();
0155     }
0156 }
0157 
0158 bool FolderTreeWidgetProxyModel::hideSpecificFolder() const
0159 {
0160     return d->hideSpecificFolder;
0161 }
0162 
0163 void FolderTreeWidgetProxyModel::setHideOutboxFolder(bool hide)
0164 {
0165     if (d->hideOutboxFolder != hide) {
0166         d->hideOutboxFolder = hide;
0167         invalidate();
0168     }
0169 }
0170 
0171 bool FolderTreeWidgetProxyModel::hideOutboxFolder() const
0172 {
0173     return d->hideOutboxFolder;
0174 }
0175 
0176 bool FolderTreeWidgetProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
0177 {
0178     const QModelIndex modelIndex = sourceModel()->index(sourceRow, 0, sourceParent);
0179 
0180     const auto collection = sourceModel()->data(modelIndex, Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
0181     if (!d->checker.isWantedCollection(collection)) {
0182         return false;
0183     }
0184 
0185     if (d->hideVirtualFolder) {
0186         if (Util::isVirtualCollection(collection)) {
0187             return false;
0188         }
0189     }
0190 
0191     if (d->hideSpecificFolder) {
0192         const QSharedPointer<FolderSettings> col = FolderSettings::forCollection(collection, false);
0193         if (!col.isNull() && col->hideInSelectionDialog()) {
0194             return false;
0195         }
0196     }
0197 
0198     if (d->hideOutboxFolder) {
0199         if (collection == Kernel::self()->outboxCollectionFolder()) {
0200             return false;
0201         }
0202     }
0203 
0204     return EntityRightsFilterModel::filterAcceptsRow(sourceRow, sourceParent);
0205 }
0206 
0207 QVariant FolderTreeWidgetProxyModel::data(const QModelIndex &index, int role) const
0208 {
0209     if (role == Qt::ForegroundRole) {
0210         const QModelIndex sourceIndex = mapToSource(index);
0211         const QModelIndex rowIndex = sourceIndex.sibling(sourceIndex.row(), 0);
0212         const auto collection = sourceModel()->data(rowIndex, Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
0213 
0214         if (!MailCommon::Util::isVirtualCollection(collection)) {
0215             const Akonadi::AgentInstance instance = Akonadi::AgentManager::self()->instance(collection.resource());
0216 
0217             if (instance.status() == Akonadi::AgentInstance::Broken) {
0218                 if (!d->brokenAccountColor.isValid()) {
0219                     const KColorScheme scheme(QPalette::Active, KColorScheme::View);
0220                     d->brokenAccountColor = scheme.foreground(KColorScheme::NegativeText).color();
0221                 }
0222                 return d->brokenAccountColor;
0223             }
0224         }
0225     } else if (role == Qt::DisplayRole) {
0226         const QModelIndex sourceIndex = mapToSource(index);
0227         const QModelIndex rowIndex = sourceIndex.sibling(sourceIndex.row(), 0);
0228         const auto collection = sourceModel()->data(rowIndex, Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
0229         if (!MailCommon::Util::isVirtualCollection(collection)) {
0230             const Akonadi::AgentInstance instance = Akonadi::AgentManager::self()->instance(collection.resource());
0231             if (collection.parentCollection() == Akonadi::Collection::root()) {
0232                 if (!instance.isOnline()) {
0233                     return i18n("%1 (Offline)", Akonadi::EntityRightsFilterModel::data(index, role).toString());
0234                 }
0235                 qreal percentage = 0.0;
0236                 if (d->checkQuotaExcedded(index, percentage)) {
0237                     return i18n("%1 (Reached %2% quota)", Akonadi::EntityRightsFilterModel::data(index, role).toString(), static_cast<int>(percentage));
0238                 }
0239             }
0240         }
0241     } else if (role == Qt::DecorationRole) {
0242         const QModelIndex sourceIndex = mapToSource(index);
0243         const QModelIndex rowIndex = sourceIndex.sibling(sourceIndex.row(), 0);
0244         const auto collection = sourceModel()->data(rowIndex, Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
0245         if (!MailCommon::Util::isVirtualCollection(collection)) {
0246             if (collection.parentCollection() == Akonadi::Collection::root()) {
0247                 qreal percentage = 0.0;
0248                 if (d->checkQuotaExcedded(index, percentage)) {
0249                     return QIcon::fromTheme(QStringLiteral("emblem-warning"));
0250                 }
0251             }
0252         }
0253     }
0254     return Akonadi::EntityRightsFilterModel::data(index, role);
0255 }
0256 
0257 void FolderTreeWidgetProxyModel::updatePalette()
0258 {
0259     if (d->brokenAccountColor.isValid()) {
0260         KColorScheme scheme(QPalette::Active, KColorScheme::View);
0261         d->brokenAccountColor = scheme.foreground(KColorScheme::NegativeText).color();
0262         invalidate();
0263     }
0264 }
0265 
0266 void FolderTreeWidgetProxyModel::addContentMimeTypeInclusionFilter(const QString &mimeType)
0267 {
0268     d->includedMimeTypes << mimeType;
0269     d->checker.setWantedMimeTypes(d->includedMimeTypes.values());
0270     invalidateFilter();
0271 }
0272 
0273 #include "moc_foldertreewidgetproxymodel.cpp"