File indexing completed on 2024-06-23 04:42:35

0001 // Copyright (c) 2018 Michael Bohlender <michael.bohlender@kdemail.net>
0002 // Copyright (c) 2018 Christian Mollekopf <mollekopf@kolabsys.com>
0003 // Copyright (c) 2018 RĂ©mi Nicole <minijackson@riseup.net>
0004 // Copyright (c) 2021 Carl Schwan <carlschwan@kde.org>
0005 // Copyright (c) 2021 Claudio Cambra <claudio.cambra@gmail.com>
0006 // SPDX-License-Identifier: LGPL-2.0-or-later
0007 
0008 #pragma once
0009 
0010 #include <QObject>
0011 #include <QQmlEngine>
0012 #include <Akonadi/ETMCalendar>
0013 
0014 #include <KConfigWatcher>
0015 #include <KFormat>
0016 #include <QAbstractItemModel>
0017 #include <QColor>
0018 #include <QDateTime>
0019 #include <QList>
0020 #include <QSharedPointer>
0021 #include <QTimer>
0022 
0023 class Filter;
0024 namespace KCalendarCore
0025 {
0026 class Incidence;
0027 }
0028 namespace Akonadi
0029 {
0030 class ETMCalendar;
0031 }
0032 
0033 using namespace KCalendarCore;
0034 
0035 /**
0036  * Loads all event occurrences within the given period and matching the given filter.
0037  *
0038  * Recurrences are expanded
0039  */
0040 class IncidenceOccurrenceModel : public QAbstractListModel
0041 {
0042     Q_OBJECT
0043     QML_ELEMENT
0044     Q_PROPERTY(QDate start READ start WRITE setStart NOTIFY startChanged)
0045     Q_PROPERTY(int length READ length WRITE setLength NOTIFY lengthChanged)
0046     Q_PROPERTY(Filter *filter READ filter WRITE setFilter NOTIFY filterChanged)
0047     Q_PROPERTY(Akonadi::ETMCalendar::Ptr calendar READ calendar WRITE setCalendar NOTIFY calendarChanged)
0048     Q_PROPERTY(bool loading READ loading NOTIFY loadingChanged)
0049     Q_PROPERTY(int resetThrottleInterval READ resetThrottleInterval WRITE setResetThrottleInterval NOTIFY resetThrottleIntervalChanged)
0050 
0051 public:
0052     enum Roles {
0053         Summary = Qt::UserRole + 1,
0054         Description,
0055         Location,
0056         StartTime,
0057         EndTime,
0058         Duration,
0059         DurationString,
0060         Recurs,
0061         HasReminders,
0062         Priority,
0063         Color,
0064         CollectionId,
0065         AllDay,
0066         TodoCompleted,
0067         IsOverdue,
0068         IsReadOnly,
0069         IncidenceId,
0070         IncidenceType,
0071         IncidenceTypeStr,
0072         IncidenceTypeIcon,
0073         IncidencePtr,
0074         IncidenceOccurrence,
0075         LastRole
0076     };
0077     Q_ENUM(Roles)
0078     explicit IncidenceOccurrenceModel(QObject *parent = nullptr);
0079     ~IncidenceOccurrenceModel() override = default;
0080 
0081     int rowCount(const QModelIndex &parent = {}) const override;
0082     QVariant data(const QModelIndex &index, int role) const override;
0083     QHash<int, QByteArray> roleNames() const override;
0084     
0085     Akonadi::ETMCalendar::Ptr calendar() const;
0086     QDate start() const;
0087     int length() const;
0088     Filter *filter() const;
0089     bool loading() const;
0090     int resetThrottleInterval() const;
0091 
0092     struct Occurrence {
0093         QDateTime start;
0094         QDateTime end;
0095         KCalendarCore::Incidence::Ptr incidence;
0096         QColor color;
0097         qint64 collectionId;
0098         bool allDay;
0099     };
0100 
0101 Q_SIGNALS:
0102     void startChanged();
0103     void lengthChanged();
0104     void filterChanged();
0105     void calendarChanged();
0106     void loadingChanged();
0107     void resetThrottleIntervalChanged();
0108 
0109 public Q_SLOTS:
0110     void setStart(const QDate &start);
0111     void setLength(int length);
0112     void setFilter(Filter *filter);
0113     void setCalendar(Akonadi::ETMCalendar::Ptr calendar);
0114     void setResetThrottleInterval(const int resetThrottleInterval);
0115 
0116 private Q_SLOTS:
0117     void loadColors();
0118     void scheduleReset();
0119     void resetFromSource();
0120 
0121     void slotSourceDataChanged(const QModelIndex &upperLeft, const QModelIndex &bottomRight);
0122     void slotSourceRowsInserted(const QModelIndex &parent, const int first, const int last);
0123 
0124     void setLoading(const bool loading);
0125 
0126 private:
0127     static std::pair<QDateTime, QDateTime> incidenceOccurrenceStartEnd(const QDateTime &ocStart, const KCalendarCore::Incidence::Ptr &incidence);
0128     static uint incidenceOccurrenceHash(const QDateTime &ocStart, const QDateTime &ocEnd, const QString &incidenceUid);
0129     bool incidencePassesFilter(const KCalendarCore::Incidence::Ptr &incidence);
0130 
0131     QColor getColor(const KCalendarCore::Incidence::Ptr &incidence);
0132     qint64 getCollectionId(const KCalendarCore::Incidence::Ptr &incidence);
0133 
0134     QSharedPointer<QAbstractItemModel> mSourceModel;
0135     QDate mStart;
0136     QDate mEnd;
0137     int mLength{0};
0138     Akonadi::ETMCalendar::Ptr m_coreCalendar;
0139 
0140     QTimer m_resetThrottlingTimer;
0141     int m_resetThrottleInterval = 100;
0142 
0143     bool m_loading = false;
0144     QVector<Occurrence> m_incidences; // We need incidences to be in a preditable order for the model
0145     QHash<uint, QPersistentModelIndex> m_occurrenceIndexHash;
0146     QHash<QString, QColor> m_colors;
0147     KConfigWatcher::Ptr m_colorWatcher;
0148     Filter *mFilter = nullptr;
0149     KFormat m_format;
0150 };
0151 
0152 Q_DECLARE_METATYPE(IncidenceOccurrenceModel::Occurrence)
0153 
0154 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0155 Q_DECLARE_METATYPE(KCalendarCore::Incidence::Ptr)
0156 #endif