1 /*
2 * resourcemodel.h - models containing flat list of resources
3 * Program: kalarm
4 * SPDX-FileCopyrightText: 2010-2021 David Jarvie <djarvie@kde.org>
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9 #pragma once
10
11 #include "resource.h"
12
13 #include <KAlarmCal/KACalendar>
14
15 #include <KDescendantsProxyModel>
16 #include <KCheckableProxyModel>
17
18 #include <QSortFilterProxyModel>
19 #include <QListView>
20
21 using namespace KAlarmCal;
22
23 /*=============================================================================
24 = Class: ResourceFilterModel
25 = Proxy model to filter a resource data model to restrict its contents to
26 = resources, not events, containing specified alarm types.
27 = It can optionally be restricted to writable and/or enabled resources.
28 =============================================================================*/
29 class ResourceFilterModel : public QSortFilterProxyModel
30 {
31 Q_OBJECT
32 public:
33 /** Constructs a new instance.
34 * @tparam DataModel The data model class to use as the source model. It must
35 * have the following methods:
36 * static Model* instance(); - returns the unique instance.
37 * QModelIndex resourceIndex(const Resource&) const;
38 */
39 template <class DataModel>
40 static ResourceFilterModel* create(QObject* parent = nullptr);
41
42 /** Set the alarm type to include in the model.
43 * @param type If EMPTY, include all alarm types;
44 * otherwise, include only resources with the specified alarm type.
45 */
46 void setEventTypeFilter(CalEvent::Type);
47
48 /** Filter on resources' writable status.
49 * @param enabled If true, only include writable resources;
50 * if false, ignore writable status.
51 */
52 void setFilterWritable(bool writable);
53
54 /** Filter on resources' enabled status.
55 * @param enabled If true, only include enabled resources;
56 * if false, ignore enabled status.
57 */
58 void setFilterEnabled(bool enabled);
59
60 /** Filter on resources' display names, using a simple text search. */
61 void setFilterText(const QString& text);
62
63 QModelIndex resourceIndex(const Resource&) const;
64
65 bool hasChildren(const QModelIndex &parent = QModelIndex()) const override;
66 bool canFetchMore(const QModelIndex &parent) const override;
67 QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits = 1, Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchStartsWith | Qt::MatchWrap)) const override;
68 int columnCount(const QModelIndex &parent = QModelIndex()) const override;
69
70 protected:
71 bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
72 bool filterAcceptsColumn(int sourceColumn, const QModelIndex &sourceParent) const override;
73
74 private:
75 explicit ResourceFilterModel(QObject* parent);
76
77 QModelIndex (*mResourceIndexFunction)(const Resource&) {nullptr}; // function to fetch resource index from data model
78 QString mFilterText; // only include resources whose display names include this
79 CalEvent::Type mAlarmType {CalEvent::EMPTY}; // only include resources with this alarm type
80 bool mWritableOnly {false}; // only include writable resources
81 bool mEnabledOnly {false}; // only include enabled resources
82 };
83
84 /*=============================================================================
85 = Class: ResourceListModel
86 = Proxy model converting the resource tree into a flat list.
87 = The model may be restricted to specified alarm types.
88 = It can optionally be restricted to writable and/or enabled resources.
89 =============================================================================*/
90 class ResourceListModel : public KDescendantsProxyModel
91 {
92 Q_OBJECT
93 public:
94 /** Constructs a new instance.
95 * @tparam DataModel The data model class to use as the source model. It must
96 * have the following methods:
97 * static DataModel* instance(); - returns the unique instance.
98 * QModelIndex resourceIndex(const Resource&) const;
99 */
100 template <class DataModel>
101 static ResourceListModel* create(QObject* parent = nullptr);
102
103 void setEventTypeFilter(CalEvent::Type);
104 void setFilterWritable(bool writable);
105 void setFilterEnabled(bool enabled);
106 void setFilterText(const QString& text);
useResourceColour(bool use)107 void useResourceColour(bool use) { mUseResourceColour = use; }
108 Resource resource(int row) const;
109 Resource resource(const QModelIndex&) const;
110 QModelIndex resourceIndex(const Resource&) const;
111 virtual bool isDescendantOf(const QModelIndex& ancestor, const QModelIndex& descendant) const;
112 QVariant data(const QModelIndex&, int role = Qt::DisplayRole) const override;
113
114 private:
115 explicit ResourceListModel(QObject* parent);
116
117 bool mUseResourceColour {true};
118 };
119
120
121 /*=============================================================================
122 = Class: ResourceCheckListModel
123 = Proxy model providing a checkable list of all Resources.
124 = An alarm type is specified, whereby Resources which are enabled for that
125 = alarm type are checked; Resources which do not contain that alarm type, or
126 = which are disabled for that alarm type, are unchecked.
127 =============================================================================*/
128 class ResourceCheckListModel : public KCheckableProxyModel
129 {
130 Q_OBJECT
131 public:
132 /** Constructs a new instance.
133 * @tparam DataModel The data model class to use as the source model. It must
134 * have the following methods:
135 * static DataModel* instance(); - returns the unique instance.
136 * QModelIndex resourceIndex(const Resource&) const;
137 */
138 template <class DataModel>
139 static ResourceCheckListModel* create(CalEvent::Type, QObject* parent = nullptr);
140
141 ~ResourceCheckListModel() override;
142 Resource resource(int row) const;
143 Resource resource(const QModelIndex&) const;
disable()144 void disable() { mDisabled = true; }
145 QVariant data(const QModelIndex&, int role = Qt::DisplayRole) const override;
146 bool setData(const QModelIndex&, const QVariant& value, int role) override;
147
148 Q_SIGNALS:
149 void resourceTypeChange(ResourceCheckListModel*);
150
151 private Q_SLOTS:
152 void selectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
153 void slotRowsInsertedRemoved();
154 void resourceSettingsChanged(Resource&, ResourceType::Changes);
155
156 private:
157 ResourceCheckListModel(CalEvent::Type, QObject* parent);
158 void init();
159 void setSelectionStatus(const Resource&, const QModelIndex&);
160 QByteArray debugType(const char* func) const;
161
162 static ResourceListModel* mModel;
163 static int mInstanceCount;
164 CalEvent::Type mAlarmType; // alarm type contained in this model
165 QItemSelectionModel* mSelectionModel;
166 bool mResetting {false}; // currently handling rows inserted/removed
167 bool mDisabled {false}; // resources are being deleted on program exit
168 };
169
170
171 /*=============================================================================
172 = Class: ResourceFilterCheckListModel
173 = Proxy model providing a checkable resource list, filtered to contain only one
174 = alarm type. The selected alarm type may be changed as desired.
175 =============================================================================*/
176 class ResourceFilterCheckListModel : public QSortFilterProxyModel
177 {
178 Q_OBJECT
179 public:
180 /** Constructs an instance.
181 * @tparam DataModel The data model class to use as the source model. It must
182 * have the following methods:
183 * static DataModel* instance(); - returns the unique instance.
184 * QModelIndex resourceIndex(const Resource&) const;
185 * QString tooltip(const Resource&, CalEvent::Types) const;
186 */
187 template <class DataModel>
188 static ResourceFilterCheckListModel* create(QObject* parent = nullptr);
189
190 ~ResourceFilterCheckListModel() override;
191 void setEventTypeFilter(CalEvent::Type);
192 Resource resource(int row) const;
193 Resource resource(const QModelIndex&) const;
194 static void disable();
195 QVariant data(const QModelIndex&, int role = Qt::DisplayRole) const override;
196
197 protected:
198 bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override;
199
200 private Q_SLOTS:
201 void resourceTypeChanged(ResourceCheckListModel*);
202 void slotRowsAboutToBeInserted(const QModelIndex& parent, int start, int end);
203 void slotRowsAboutToBeRemoved(const QModelIndex& parent, int start, int end);
204 void slotRowsInserted();
205 void slotRowsRemoved();
206
207 private:
208 explicit ResourceFilterCheckListModel(QObject* parent);
209 void init();
210
211 static QVector<ResourceFilterCheckListModel*> mInstances;
212 ResourceCheckListModel* mActiveModel {nullptr};
213 ResourceCheckListModel* mArchivedModel {nullptr};
214 ResourceCheckListModel* mTemplateModel {nullptr};
215 CalEvent::Type mAlarmType {CalEvent::EMPTY}; // alarm type contained in this model
216 QString (*mTooltipFunction)(const Resource&, CalEvent::Types) {nullptr}; // function to fetch tooltip from data model
217 };
218
219
220 /*=============================================================================
221 = Class: ResourceView
222 = View for a ResourceFilterCheckListModel.
223 =============================================================================*/
224 class ResourceView : public QListView
225 {
226 Q_OBJECT
227 public:
228 explicit ResourceView(ResourceFilterCheckListModel*, QWidget* parent = nullptr);
229 ResourceFilterCheckListModel* resourceModel() const;
230 Resource resource(int row) const;
231 Resource resource(const QModelIndex&) const;
232
233 protected:
234 void mouseReleaseEvent(QMouseEvent*) override;
235 bool viewportEvent(QEvent*) override;
236 };
237
238
239 /*=============================================================================
240 * Template definitions.
241 *============================================================================*/
242
243 template <class DataModel>
create(QObject * parent)244 ResourceFilterModel* ResourceFilterModel::create(QObject* parent)
245 {
246 auto model = new ResourceFilterModel(parent);
247 model->setSourceModel(DataModel::instance());
248 model->mResourceIndexFunction = [](const Resource& r) { return DataModel::instance()->resourceIndex(r); };
249 return model;
250 }
251
252 template <class DataModel>
create(QObject * parent)253 ResourceListModel* ResourceListModel::create(QObject* parent)
254 {
255 auto model = new ResourceListModel(parent);
256 model->setSourceModel(ResourceFilterModel::create<DataModel>(model));
257 return model;
258 }
259
260 template <class DataModel>
create(CalEvent::Type type,QObject * parent)261 ResourceCheckListModel* ResourceCheckListModel::create(CalEvent::Type type, QObject* parent)
262 {
263 auto model = new ResourceCheckListModel(type, parent);
264 if (!mModel)
265 mModel = ResourceListModel::create<DataModel>(nullptr);
266 model->init();
267 return model;
268 }
269
270 template <class DataModel>
create(QObject * parent)271 ResourceFilterCheckListModel* ResourceFilterCheckListModel::create(QObject* parent)
272 {
273 ResourceFilterCheckListModel* instance = new ResourceFilterCheckListModel(parent);
274 mInstances.append(instance);
275 instance->mActiveModel = ResourceCheckListModel::create<DataModel>(CalEvent::ACTIVE, instance);
276 instance->mArchivedModel = ResourceCheckListModel::create<DataModel>(CalEvent::ARCHIVED, instance);
277 instance->mTemplateModel = ResourceCheckListModel::create<DataModel>(CalEvent::TEMPLATE, instance);
278 instance->mTooltipFunction = [](const Resource& r, CalEvent::Types t) { return DataModel::instance()->tooltip(r, t); };
279 instance->init();
280 return instance;
281 }
282
283
284 // vim: et sw=4:
285