Changeset View
Changeset View
Standalone View
Standalone View
framework/src/domain/perioddayeventmodel.cpp
- This file was added.
1 | /* | ||||
---|---|---|---|---|---|
2 | Copyright (c) 2018 Michael Bohlender <michael.bohlender@kdemail.net> | ||||
3 | Copyright (c) 2018 Christian Mollekopf <mollekopf@kolabsys.com> | ||||
4 | Copyright (c) 2018 Rémi Nicole <minijackson@riseup.net> | ||||
5 | | ||||
6 | This library is free software; you can redistribute it and/or modify it | ||||
7 | under the terms of the GNU Library General Public License as published by | ||||
8 | the Free Software Foundation; either version 2 of the License, or (at your | ||||
9 | option) any later version. | ||||
10 | | ||||
11 | This library is distributed in the hope that it will be useful, but WITHOUT | ||||
12 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public | ||||
14 | License for more details. | ||||
15 | | ||||
16 | You should have received a copy of the GNU Library General Public License | ||||
17 | along with this library; see the file COPYING.LIB. If not, write to the | ||||
18 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||||
19 | 02110-1301, USA. | ||||
20 | */ | ||||
21 | | ||||
22 | #include "perioddayeventmodel.h" | ||||
23 | | ||||
24 | #include <sink/log.h> | ||||
25 | #include <sink/query.h> | ||||
26 | #include <sink/store.h> | ||||
27 | | ||||
28 | #include <QJsonArray> | ||||
29 | #include <QJsonObject> | ||||
30 | #include <QMetaEnum> | ||||
31 | | ||||
32 | PeriodDayEventModel::PeriodDayEventModel(QObject *parent) | ||||
33 | : QAbstractItemModel(parent), partitionedEvents(7) | ||||
34 | { | ||||
35 | Sink::Query query; | ||||
36 | query.setFlags(Sink::Query::LiveQuery); | ||||
37 | query.request<Event::Summary>(); | ||||
38 | query.request<Event::Description>(); | ||||
39 | query.request<Event::StartTime>(); | ||||
40 | query.request<Event::EndTime>(); | ||||
41 | | ||||
42 | eventModel = Sink::Store::loadModel<Event>(query); | ||||
43 | | ||||
44 | QObject::connect(eventModel.data(), &QAbstractItemModel::dataChanged, this, &PeriodDayEventModel::partitionData); | ||||
45 | QObject::connect(eventModel.data(), &QAbstractItemModel::layoutChanged, this, &PeriodDayEventModel::partitionData); | ||||
46 | QObject::connect(eventModel.data(), &QAbstractItemModel::modelReset, this, &PeriodDayEventModel::partitionData); | ||||
47 | QObject::connect(eventModel.data(), &QAbstractItemModel::rowsInserted, this, &PeriodDayEventModel::partitionData); | ||||
48 | QObject::connect(eventModel.data(), &QAbstractItemModel::rowsMoved, this, &PeriodDayEventModel::partitionData); | ||||
49 | QObject::connect(eventModel.data(), &QAbstractItemModel::rowsRemoved, this, &PeriodDayEventModel::partitionData); | ||||
50 | | ||||
51 | partitionData(); | ||||
52 | } | ||||
53 | | ||||
54 | void PeriodDayEventModel::partitionData() | ||||
55 | { | ||||
56 | SinkLog() << "Partitioning event data"; | ||||
57 | | ||||
58 | beginResetModel(); | ||||
59 | | ||||
60 | partitionedEvents = QVector<QList<QSharedPointer<Event>>>(mPeriodLength); | ||||
61 | | ||||
62 | for (int i = 0; i < eventModel->rowCount(); ++i) { | ||||
63 | auto event = eventModel->index(i, 0).data(Sink::Store::DomainObjectRole).value<Event::Ptr>(); | ||||
64 | QDate eventDate = event->getStartTime().date(); | ||||
65 | | ||||
66 | if (!eventDate.isValid()) { | ||||
67 | SinkWarning() << "Invalid date in the eventModel, ignoring..."; | ||||
68 | continue; | ||||
69 | } | ||||
70 | | ||||
71 | int bucket = bucketOf(eventDate); | ||||
72 | | ||||
73 | if (bucket >= 0) { | ||||
74 | SinkTrace() << "Adding event:" << event->getSummary() << "in bucket #" << bucket; | ||||
75 | partitionedEvents[bucket].append(event); | ||||
76 | } | ||||
77 | } | ||||
78 | | ||||
79 | endResetModel(); | ||||
80 | } | ||||
81 | | ||||
82 | int PeriodDayEventModel::bucketOf(const QDate &candidate) const | ||||
83 | { | ||||
cmollekopf: const QDate & | |||||
84 | int bucket = mPeriodStart.daysTo(candidate); | ||||
85 | if (bucket >= mPeriodLength || bucket < 0) { | ||||
86 | return -1; | ||||
87 | } | ||||
88 | | ||||
89 | return bucket; | ||||
90 | } | ||||
91 | | ||||
92 | QModelIndex PeriodDayEventModel::index(int row, int column, const QModelIndex &parent) const | ||||
93 | { | ||||
94 | if (!hasIndex(row, column, parent)) { | ||||
95 | return {}; | ||||
96 | } | ||||
97 | | ||||
98 | if (!parent.isValid()) { | ||||
99 | // Asking for a day | ||||
100 | | ||||
101 | if (!(0 <= row && row < mPeriodLength)) { | ||||
102 | return {}; | ||||
103 | } | ||||
104 | | ||||
105 | return createIndex(row, column, DAY_ID); | ||||
106 | } | ||||
107 | | ||||
108 | // Asking for an Event | ||||
109 | auto day = static_cast<int>(parent.row()); | ||||
110 | | ||||
111 | Q_ASSERT(0 <= day && day <= mPeriodLength); | ||||
112 | if (row >= partitionedEvents[day].size()) { | ||||
113 | return {}; | ||||
114 | } | ||||
115 | | ||||
116 | return createIndex(row, column, day); | ||||
117 | } | ||||
118 | | ||||
119 | QModelIndex PeriodDayEventModel::parent(const QModelIndex &index) const | ||||
120 | { | ||||
121 | if (!index.isValid()) { | ||||
122 | return {}; | ||||
123 | } | ||||
124 | | ||||
125 | if (index.internalId() == DAY_ID) { | ||||
126 | return {}; | ||||
127 | } | ||||
128 | | ||||
129 | auto day = index.internalId(); | ||||
130 | | ||||
131 | return this->index(day, 0); | ||||
132 | } | ||||
133 | | ||||
134 | int PeriodDayEventModel::rowCount(const QModelIndex &parent) const | ||||
135 | { | ||||
136 | if (!parent.isValid()) { | ||||
137 | return mPeriodLength; | ||||
138 | } | ||||
139 | | ||||
140 | auto day = parent.row(); | ||||
141 | | ||||
142 | return partitionedEvents[day].size(); | ||||
143 | } | ||||
144 | | ||||
145 | int PeriodDayEventModel::columnCount(const QModelIndex &parent) const | ||||
146 | { | ||||
147 | if (!parent.isValid()) { | ||||
148 | return 1; | ||||
149 | } | ||||
150 | | ||||
151 | return eventModel->columnCount(); | ||||
152 | } | ||||
153 | | ||||
154 | QVariant PeriodDayEventModel::data(const QModelIndex &id, int role) const | ||||
155 | { | ||||
156 | if (id.internalId() == DAY_ID) { | ||||
157 | auto day = id.row(); | ||||
158 | | ||||
159 | SinkTrace() << "Fetching data for day" << day << "with role" | ||||
160 | << QMetaEnum::fromType<Roles>().valueToKey(role); | ||||
161 | | ||||
162 | switch (role) { | ||||
163 | case Qt::DisplayRole: | ||||
164 | return mPeriodStart.addDays(day).toString(); | ||||
165 | case Events: { | ||||
166 | auto result = QVariantList{}; | ||||
167 | | ||||
168 | for (int i = 0; i < partitionedEvents[day].size(); ++i) { | ||||
169 | auto eventId = index(i, 0, id); | ||||
170 | SinkTrace() << "Appending event:" << data(eventId, Summary); | ||||
171 | | ||||
172 | auto startTime = data(eventId, StartTime).toDateTime().time(); | ||||
173 | | ||||
174 | result.append(QVariantMap{ | ||||
175 | {"text", data(eventId, Summary)}, | ||||
176 | {"description", data(eventId, Description)}, | ||||
177 | {"starts", startTime.hour() + startTime.minute() / 60.}, | ||||
178 | {"duration", data(eventId, Duration)}, | ||||
179 | {"color", "#134bab"}, | ||||
180 | {"indention", 0}, | ||||
181 | }); | ||||
182 | } | ||||
183 | | ||||
184 | return result; | ||||
185 | } | ||||
186 | default: | ||||
187 | SinkWarning() << "Unknown role for day:" << QMetaEnum::fromType<Roles>().valueToKey(role); | ||||
188 | return {}; | ||||
189 | } | ||||
190 | } else { | ||||
191 | auto day = id.internalId(); | ||||
192 | SinkTrace() << "Fetching data for event on day" << day << "with role" | ||||
193 | << QMetaEnum::fromType<Roles>().valueToKey(role); | ||||
194 | auto event = partitionedEvents[day].at(id.row()); | ||||
195 | | ||||
196 | switch (role) { | ||||
197 | case Summary: | ||||
198 | return event->getSummary(); | ||||
199 | case Description: | ||||
200 | return event->getDescription(); | ||||
201 | case StartTime: | ||||
202 | return event->getStartTime(); | ||||
203 | case Duration: { | ||||
204 | auto start = event->getStartTime(); | ||||
205 | auto end = event->getEndTime(); | ||||
206 | return start.secsTo(end) / 3600; | ||||
207 | } | ||||
208 | default: | ||||
209 | SinkWarning() << "Unknown role for event:" << QMetaEnum::fromType<Roles>().valueToKey(role); | ||||
210 | return {}; | ||||
211 | } | ||||
212 | } | ||||
213 | } | ||||
214 | | ||||
215 | QHash<int, QByteArray> PeriodDayEventModel::roleNames() const | ||||
216 | { | ||||
217 | return { | ||||
218 | {Events, "events"}, | ||||
cmollekopf: Perhaps convert this into:
```
return {{1, "foo"},
{2, "bar"}};
``` | |||||
219 | {Summary, "summary"}, | ||||
220 | {Description, "description"}, | ||||
221 | {StartTime, "starts"}, | ||||
222 | {Duration, "duration"}, | ||||
223 | }; | ||||
224 | } | ||||
225 | | ||||
226 | QDate PeriodDayEventModel::periodStart() const | ||||
227 | { | ||||
228 | return mPeriodStart; | ||||
229 | } | ||||
230 | | ||||
231 | void PeriodDayEventModel::setPeriodStart(const QDate &start) | ||||
232 | { | ||||
233 | if (!start.isValid()) { | ||||
234 | SinkWarning() << "Passed an invalid starting date in setPeriodStart, ignoring..."; | ||||
Pass all non-pod types by const-reference. and then don't move instead. cmollekopf: Pass all non-pod types by const-reference. and then don't move instead.
Or is there a… | |||||
I guess you're right. The really optimized version would be to write a setPeriodStart(const QDate &) plus a setPeriodStart(QDate &&) where move only happens in the second one. Plus, it also depends on how Qt pass the parameters from the view. I guess the C++98 default is the best in our case (simple and fairly optimized). More info here: https://youtu.be/xnqTKD8uD64?t=51m6s rnicole: I guess you're right. The really optimized version would be to write a `setPeriodStart(const… | |||||
235 | return; | ||||
236 | } | ||||
237 | | ||||
238 | mPeriodStart = start; | ||||
239 | partitionData(); | ||||
240 | } | ||||
241 | | ||||
242 | void PeriodDayEventModel::setPeriodStart(const QVariant &start) | ||||
243 | { | ||||
244 | setPeriodStart(start.toDate()); | ||||
245 | } | ||||
246 | | ||||
247 | int PeriodDayEventModel::periodLength() const | ||||
248 | { | ||||
249 | return mPeriodLength; | ||||
250 | } | ||||
251 | | ||||
252 | void PeriodDayEventModel::setPeriodLength(int length) | ||||
253 | { | ||||
254 | mPeriodLength = length; | ||||
255 | partitionData(); | ||||
256 | } | ||||
This std::move doesn't do anything AFAIK. int doesn't have a move constructor. cmollekopf: This std::move doesn't do anything AFAIK. int doesn't have a move constructor. | |||||
Right, I've just seen it. I think it's a leftover from when I wanted a setPeriodEnd instead of setPeriodLength rnicole: Right, I've just seen it. I think it's a leftover from when I wanted a `setPeriodEnd` instead… |
const QDate &