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

0001 // SPDX-FileCopyrightText: 2021 Claudio Cambra <claudio.cambra@gmail.com>
0002 // SPDX-License-Identifier: LGPL-2.1-or-later
0003 
0004 #pragma once
0005 
0006 #include <Akonadi/CalendarUtils>
0007 #include <Akonadi/ETMCalendar>
0008 #include <Akonadi/IncidenceTreeModel>
0009 #include <Akonadi/TodoModel>
0010 #include <KConfigWatcher>
0011 #include <KFormat>
0012 #include <KSharedConfig>
0013 #include <QObject>
0014 #include <QSortFilterProxyModel>
0015 #include <QTimer>
0016 
0017 class Filter;
0018 
0019 class TodoSortFilterProxyModel : public QSortFilterProxyModel
0020 {
0021     Q_OBJECT
0022     Q_PROPERTY(Akonadi::IncidenceChanger *incidenceChanger READ incidenceChanger WRITE setIncidenceChanger NOTIFY incidenceChangerChanged)
0023     Q_PROPERTY(Akonadi::ETMCalendar::Ptr calendar READ calendar WRITE setCalendar NOTIFY calendarChanged)
0024     Q_PROPERTY(Filter *filterObject READ filterObject WRITE setFilterObject NOTIFY filterObjectChanged)
0025     Q_PROPERTY(int showCompleted READ showCompleted WRITE setShowCompleted NOTIFY showCompletedChanged)
0026     Q_PROPERTY(int sortBy READ sortBy WRITE setSortBy NOTIFY sortByChanged)
0027     Q_PROPERTY(bool sortAscending READ sortAscending WRITE setSortAscending NOTIFY sortAscendingChanged)
0028     Q_PROPERTY(bool showCompletedSubtodosInIncomplete READ showCompletedSubtodosInIncomplete WRITE setShowCompletedSubtodosInIncomplete NOTIFY
0029     showCompletedSubtodosInIncompleteChanged)
0030     
0031 public:
0032     enum Roles {
0033         StartTimeRole = Akonadi::TodoModel::CalendarRole + 1,
0034         EndTimeRole,
0035         DisplayDueDateRole,
0036         LocationRole,
0037         AllDayRole,
0038         CompletedRole,
0039         PriorityRole,
0040         ColorRole,
0041         CollectionIdRole,
0042         DurationStringRole,
0043         RecursRole,
0044         IsOverdueRole,
0045         IncidenceIdRole,
0046         IncidenceTypeRole,
0047         IncidenceTypeStrRole,
0048         IncidenceTypeIconRole,
0049         IncidencePtrRole,
0050         TagsRole,
0051         ItemRole,
0052         CategoriesRole,
0053         CategoriesDisplayRole,
0054         TreeDepthRole,
0055         TopMostParentSummaryRole, // These three here are used to help us conserve the proper sections
0056         TopMostParentDueDateRole, // in the Kirigami TreeListView, which otherwise will create new
0057         TopMostParentPriorityRole, // sections for subtasks
0058     };
0059     Q_ENUM(Roles)
0060     
0061     enum BaseTodoModelColumns {
0062         SummaryColumn = Akonadi::TodoModel::SummaryColumn,
0063         PriorityColumn = Akonadi::TodoModel::PriorityColumn,
0064         PercentColumn = Akonadi::TodoModel::PercentColumn,
0065         StartDateColumn = Akonadi::TodoModel::StartDateColumn,
0066         DueDateColumn = Akonadi::TodoModel::DueDateColumn,
0067         CategoriesColumn = Akonadi::TodoModel::CategoriesColumn,
0068         DescriptionColumn = Akonadi::TodoModel::DescriptionColumn,
0069         CalendarColumn = Akonadi::TodoModel::CalendarColumn,
0070     };
0071     Q_ENUM(BaseTodoModelColumns)
0072     
0073     enum ShowComplete {
0074         ShowAll = 0,
0075         ShowCompleteOnly,
0076         ShowIncompleteOnly,
0077     };
0078     Q_ENUM(ShowComplete)
0079     
0080     enum DueDateDisplayFormat {
0081         DisplayDateOnly,
0082         DisplayDateTimeAndIfOverdue,
0083     };
0084     Q_ENUM(DueDateDisplayFormat)
0085     
0086     explicit TodoSortFilterProxyModel(QObject *parent = nullptr);
0087     ~TodoSortFilterProxyModel() = default;
0088     
0089     int columnCount(const QModelIndex &parent) const override;
0090     QHash<int, QByteArray> roleNames() const override;
0091     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
0092     bool filterAcceptsRow(int row, const QModelIndex &sourceParent) const override;
0093     
0094     bool filterAcceptsRowCheck(int row, const QModelIndex &sourceParent) const;
0095     bool hasAcceptedChildren(int row, const QModelIndex &sourceParent) const;
0096     
0097     Akonadi::ETMCalendar::Ptr calendar() const;
0098     Akonadi::IncidenceChanger *incidenceChanger() const;
0099     int showCompleted() const;
0100     Filter *filterObject() const;
0101     int sortBy() const;
0102     bool sortAscending() const;
0103     bool showCompletedSubtodosInIncomplete() const;
0104     
0105 Q_SIGNALS:
0106     void calendarChanged();
0107     void filterObjectAboutToChange();
0108     void filterObjectChanged();
0109     void showCompletedChanged();
0110     void sortByChanged();
0111     void sortAscendingChanged();
0112     void showCompletedSubtodosInIncompleteChanged();
0113     void incidenceChangerChanged();
0114     
0115 public Q_SLOTS:
0116     void setCalendar(Akonadi::ETMCalendar::Ptr &calendar);
0117     void setIncidenceChanger(Akonadi::IncidenceChanger *changer);
0118     void setFilterObject(Filter *filterObject);
0119     void setShowCompleted(const int showCompleted);
0120     void setSortBy(const int sortBy);
0121     void setSortAscending(const bool sortAscending);
0122     void setShowCompletedSubtodosInIncomplete(const bool showCompletedSubtodosInIncomplete);
0123     
0124     void sortTodoModel();
0125     void filterTodoName(const QString &name, const int showCompleted = ShowAll);
0126     
0127 protected:
0128     bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
0129     
0130 private Q_SLOTS:
0131     void setColorCache(const QHash<QString, QColor> colorCache);
0132     
0133     void loadColors();
0134     void updateDateLabels();
0135     void emitDateDataChanged(const QModelIndex &idx);
0136     
0137 private:
0138     QHash<QString, QColor> colorCache() const;
0139     QString todoDueDateDisplayString(const KCalendarCore::Todo::Ptr todo, const DueDateDisplayFormat format) const;
0140     
0141     int compareStartDates(const QModelIndex &left, const QModelIndex &right) const;
0142     int compareDueDates(const QModelIndex &left, const QModelIndex &right) const;
0143     int compareCompletedDates(const QModelIndex &left, const QModelIndex &right) const;
0144     int comparePriorities(const QModelIndex &left, const QModelIndex &right) const;
0145     int compareCompletion(const QModelIndex &left, const QModelIndex &right) const;
0146     
0147     Akonadi::ETMCalendar::Ptr m_calendar;
0148     QScopedPointer<Akonadi::IncidenceTreeModel> m_todoTreeModel;
0149     QScopedPointer<Akonadi::TodoModel> m_baseTodoModel;
0150     Akonadi::IncidenceChanger *m_lastSetChanger = nullptr;
0151     QHash<QString, QColor> m_colors;
0152     KConfigWatcher::Ptr m_colorWatcher;
0153     int m_showCompleted = ShowComplete::ShowAll;
0154     int m_showCompletedStore; // For when searches happen
0155     Filter *m_filterObject = nullptr;
0156     int m_sortColumn = DueDateColumn;
0157     bool m_sortAscending = false;
0158     bool m_showCompletedSubtodosInIncomplete = true;
0159     KFormat m_format;
0160     QTimer m_dateRefreshTimer;
0161     int m_dateRefreshTimerInterval = 60000; // msecs
0162     QDate m_lastDateRefreshDate = QDate::currentDate();
0163 };