File indexing completed on 2024-05-12 05:10:43

0001 /*
0002   SPDX-FileCopyrightText: 2011-2012 Sérgio Martins <iamsergio@gmail.com>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #pragma once
0008 
0009 #include "calendarbase_p.h"
0010 #include "calendarmodel_p.h"
0011 #include "etmcalendar.h"
0012 #include "incidencechanger.h"
0013 
0014 #include <Akonadi/EntityTreeModel>
0015 #include <KCheckableProxyModel>
0016 
0017 #include <QModelIndex>
0018 #include <QSet>
0019 
0020 class QAbstractItemModel;
0021 class CheckableProxyModel;
0022 class KSelectionProxyModel;
0023 
0024 namespace Akonadi
0025 {
0026 class EntityTreeModel;
0027 class EntityMimeTypeFilterModel;
0028 class CollectionFilterProxyModel;
0029 class CalFilterProxyModel;
0030 class CalFilterPartStatusProxyModel;
0031 
0032 static bool isStructuralCollection(const Akonadi::Collection &collection)
0033 {
0034     const QStringList mimeTypes = QStringList() << QStringLiteral("text/calendar") << KCalendarCore::Event::eventMimeType()
0035                                                 << KCalendarCore::Todo::todoMimeType() << KCalendarCore::Journal::journalMimeType();
0036     const QStringList collectionMimeTypes = collection.contentMimeTypes();
0037     for (const QString &mimeType : mimeTypes) {
0038         if (collectionMimeTypes.contains(mimeType)) {
0039             return false;
0040         }
0041     }
0042 
0043     return true;
0044 }
0045 
0046 class CheckableProxyModel : public KCheckableProxyModel
0047 {
0048     Q_OBJECT
0049 public:
0050     explicit CheckableProxyModel(QObject *parent = nullptr)
0051         : KCheckableProxyModel(parent)
0052     {
0053     }
0054 
0055     QVariant data(const QModelIndex &index, int role) const override
0056     {
0057         if (role == Qt::CheckStateRole) {
0058             // Don't show the checkbox if the collection can't contain incidences
0059             const auto collection = index.data(Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
0060             if (isStructuralCollection(collection)) {
0061                 return {};
0062             }
0063         }
0064         return KCheckableProxyModel::data(index, role);
0065     }
0066 };
0067 
0068 class ETMCalendarPrivate : public CalendarBasePrivate
0069 {
0070     Q_OBJECT
0071 public:
0072     explicit ETMCalendarPrivate(ETMCalendar *qq);
0073     ~ETMCalendarPrivate() override;
0074 
0075     void init();
0076     void setupFilteredETM();
0077     void loadFromETM();
0078 
0079 public Q_SLOTS:
0080     Akonadi::Item::List itemsFromModel(const QAbstractItemModel *model, const QModelIndex &parentIndex = QModelIndex(), int start = 0, int end = -1);
0081 
0082     Akonadi::Collection::List
0083     collectionsFromModel(const QAbstractItemModel *model, const QModelIndex &parentIndex = QModelIndex(), int start = 0, int end = -1);
0084 
0085     // KCalendarCore::CalFilter has changed.
0086     void onFilterChanged();
0087 
0088     void clear();
0089     void updateItem(const Akonadi::Item &item);
0090     Akonadi::Item itemFromIndex(const QModelIndex &idx);
0091     void itemsAdded(const Akonadi::Item::List &items);
0092     void itemsRemoved(const Akonadi::Item::List &items);
0093 
0094     void onRowsInserted(const QModelIndex &index, int start, int end);
0095     void onRowsRemoved(const QModelIndex &index, int start, int end);
0096     void onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
0097     void onRowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow);
0098 
0099     void onLayoutChangedInFilteredModel();
0100     void onModelResetInFilteredModel();
0101     void onDataChangedInFilteredModel(const QModelIndex &topLeft, const QModelIndex &bottomRight);
0102     void onRowsInsertedInFilteredModel(const QModelIndex &index, int start, int end);
0103     void onRowsAboutToBeRemovedInFilteredModel(const QModelIndex &index, int start, int end);
0104     void onCollectionChanged(const Akonadi::Collection &collection, const QSet<QByteArray> &attributeNames);
0105     void onCollectionPopulated(Akonadi::Collection::Id);
0106 
0107     void updateLoadingState();
0108 
0109 public:
0110     Akonadi::CalendarModel::Ptr mETM;
0111     Akonadi::EntityMimeTypeFilterModel *mFilteredETM = nullptr;
0112 
0113     // akonadi id to collections
0114     QHash<Akonadi::Collection::Id, Akonadi::Collection> mCollectionMap;
0115     CheckableProxyModel *mCheckableProxyModel = nullptr;
0116     Akonadi::CollectionFilterProxyModel *mCollectionProxyModel = nullptr;
0117     Akonadi::CalFilterProxyModel *mCalFilterProxyModel = nullptr; // KCalendarCore::CalFilter stuff
0118     // filter out all invitations and declined events
0119     Akonadi::CalFilterPartStatusProxyModel *mCalFilterPartStatusProxyModel = nullptr;
0120     KSelectionProxyModel *mSelectionProxy = nullptr;
0121     bool mCollectionFilteringEnabled = true;
0122     QSet<Akonadi::Collection::Id> mPopulatedCollectionIds;
0123     QStringList mMimeTypes;
0124 
0125 private:
0126     ETMCalendar *const q;
0127 };
0128 }