Clean up #includes.
[debian/confclerk.git] / src / mvc / eventmodel.cpp
1 /*
2  * Copyright (C) 2010 Ixonos Plc.
3  * Copyright (C) 2011-2021 Philipp Spitzer, gregor herrmann, Stefan Stahl
4  *
5  * This file is part of ConfClerk.
6  *
7  * ConfClerk is free software: you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation, either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * ConfClerk is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License along with
18  * ConfClerk.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 #include "eventmodel.h"
21 #include "conference.h"
22 #include "track.h"
23 #include "room.h"
24 #include "application.h"
25
26 const QString EventModel::COMMA_SEPARATOR = ", ";
27
28 EventModel::EventModel()
29 { }
30
31
32 void EventModel::Group::setTitle(const QList<Event>& mEvents) {
33     QDateTime startTime = mEvents.at(mFirstEventIndex).start();
34     QDateTime endTime(startTime);
35     for (int i = mFirstEventIndex; i != mFirstEventIndex + mChildCount; ++i) {
36         endTime = qMax(mEvents.at(i).start().addSecs(mEvents.at(i).duration()), endTime);
37     }
38     Conference& conference = ((Application*) qApp)->activeConference();
39     QTime s = conference.shiftTime(startTime.time());
40     QTime e = conference.shiftTime(endTime.time());
41     mTitle = QString("%1 - %2").arg(s.toString("HH:mm")).arg(e.toString("HH:mm"));
42 }
43
44
45 // We want to group the events into "time slots/time groups" that
46 // should start at full hours and have the duration of either
47 // one hour or (if less than 3 events are in one time slot)
48 // multiple of one hour.
49 void EventModel::createTimeGroups()
50 {
51     beginResetModel();
52
53     mGroups.clear();
54     mParents.clear();
55     if (mEvents.empty()) return;
56
57     const int minTimeSpan = 3600; // one hour // minimum duration of a group in seconds
58     const int minChildCount = 3;  // minimum number of events in one group
59
60     QDateTime groupStartDateTime(mEvents.first().start().date(), QTime(mEvents.first().start().time().hour(), 0), mEvents.first().start().timeSpec());
61     QDateTime groupEndDateTime = groupStartDateTime.addSecs(mEvents.first().duration());
62     mGroups << EventModel::Group("", 0);
63     int timeSpan = minTimeSpan;
64
65     for (int i = 0; i != mEvents.count(); ++i) {
66         QDateTime eventStartDateTime = mEvents.at(i).start();
67         QDateTime eventEndDateTime = eventStartDateTime.addSecs(mEvents.at(i).duration());
68
69         if (eventStartDateTime >= groupStartDateTime.addSecs(timeSpan)) {
70             // a new group could be necessary
71             if (mGroups.last().mChildCount < minChildCount) {
72                 // too few events in the group => no new group
73                 // except a gap in time would occur that is longer than minTimeSpan
74                 QDateTime prevEventStartDateTime = mEvents.at(i).start();
75                 if (i > 0 && qMax(prevEventStartDateTime.addSecs(mEvents.at(i-1).duration()), groupEndDateTime).secsTo(eventStartDateTime) < minTimeSpan) {
76                     timeSpan += minTimeSpan;
77                     --i;
78                     continue; // repeat with the same event
79                 }
80             }
81
82             // a new group is necessary
83             mGroups.last().setTitle(mEvents);
84             groupStartDateTime = groupStartDateTime.addSecs(timeSpan);
85             groupEndDateTime = groupStartDateTime.addSecs(mEvents.at(i).duration());
86             mGroups << EventModel::Group("", i);
87             timeSpan = minTimeSpan;
88         }
89
90         // insert event into current group
91         mParents[mEvents.at(i).id()] = mGroups.count() - 1;
92         mGroups.last().mChildCount += 1;
93         groupEndDateTime = qMax(eventEndDateTime, groupEndDateTime);
94     }
95
96     // the last group needs a title as well
97     mGroups.last().setTitle(mEvents);
98
99     endResetModel();
100 }
101
102 void EventModel::createTrackGroups() {
103     mGroups.clear();
104     mParents.clear();
105     if (mEvents.empty())
106     {
107         return;
108     }
109     int trackId = mEvents.first().trackId();
110
111     mGroups << EventModel::Group(Track::retrieveTrackName(trackId), 0);
112     int nextTrackId = trackId;
113
114     for (int i=0; i<mEvents.count(); i++)
115     {
116         trackId = mEvents.at(i).trackId();
117         if (nextTrackId != trackId)
118         {
119             mGroups.last().mChildCount = i - mGroups.last().mFirstEventIndex;
120             mGroups << EventModel::Group(Track::retrieveTrackName(trackId), i);
121             nextTrackId = trackId;
122         }
123         // add parent-child relation
124         mParents[mEvents.at(i).id()] = mGroups.count() - 1;
125     }
126     mGroups.last().mChildCount = mEvents.count() - mGroups.last().mFirstEventIndex;
127 }
128
129 void EventModel::createRoomGroups()
130 {
131     mGroups.clear();
132     mParents.clear();
133     if (mEvents.empty())
134     {
135         return;
136     }
137     int roomId = mEvents.first().roomId();
138
139     mGroups << EventModel::Group(Room::retrieveRoomName(roomId), 0);
140     int nextRoomId = roomId;
141
142     QList<Event>::iterator event = mEvents.begin();
143     int i = 0;
144     while (event != mEvents.end())
145     {
146         roomId = event->roomId();
147         if (nextRoomId != roomId)
148         {
149             mGroups.last().mChildCount = i - mGroups.last().mFirstEventIndex;
150             mGroups << EventModel::Group(Room::retrieveRoomName(roomId), i);
151             nextRoomId = roomId;
152         }
153         mParents[event->id()] = mGroups.count() - 1;
154         event++;
155         i++;
156     }
157     mGroups.last().mChildCount = mEvents.count() - mGroups.last().mFirstEventIndex;
158 }
159
160 QVariant EventModel::data(const QModelIndex& index, int role) const
161 {
162     if (index.isValid() && role == Qt::DisplayRole)
163     {
164         if (index.internalId() == 0)
165         {
166             return mGroups.at(index.row()).mTitle;
167         }
168         else //event data
169         {
170             return static_cast<Event*>(index.internalPointer())->id();
171         }
172     }
173
174     return QVariant();
175 }
176
177 QModelIndex EventModel::index(int row, int column, const QModelIndex& parent) const
178 {
179     // TODO: add checks for out of range rows
180
181     if (!parent.isValid())
182     {
183         return createIndex(row, column);
184     }
185     else if (parent.internalId() == 0)
186     {
187         const Group& group = mGroups.at(parent.row());
188         Event* event = const_cast<Event*>(&mEvents.at(row + group.mFirstEventIndex));
189         return createIndex(row, column, reinterpret_cast<void*>(event));
190     }
191     else
192     {
193         return QModelIndex();
194     }
195 }
196
197 QModelIndex EventModel::parent(const QModelIndex & index) const
198 {
199     if (index.isValid())
200     {
201         if (index.internalId() == 0)
202         {
203             return QModelIndex();
204         }
205
206         Event * event = static_cast<Event*>(index.internalPointer());
207
208         return createIndex(mParents[event->id()], 0);
209     }
210
211     return QModelIndex();
212 }
213
214 int EventModel::columnCount(const QModelIndex & parent) const
215 {
216     Q_UNUSED(parent);
217     return 1;
218 }
219
220 int EventModel::rowCount (const QModelIndex & parent) const
221 {
222     if (!parent.isValid())
223     {
224         return mGroups.count();
225     }
226
227     if (parent.internalId() == 0)
228     {
229         return mGroups.at(parent.row()).mChildCount;
230     }
231
232     return 0;
233 }
234
235 void EventModel::clearModel()
236 {
237     beginResetModel();
238     mGroups.clear();
239     mEvents.clear();
240     mParents.clear();
241     endResetModel();
242 }
243
244
245 void EventModel::loadEvents(const QDate &aDate, int aConferenceId) {
246     clearModel();
247     mEvents = Event::getByDate(QDate(aDate.year(), aDate.month(), aDate.day()), aConferenceId, "start, duration");
248     createTimeGroups();
249 }
250
251
252 void EventModel::loadFavEvents(const QDate &aDate, int aConferenceId) {
253     clearModel();
254     mEvents = Event::getFavByDate(QDate(aDate.year(), aDate.month(), aDate.day()), aConferenceId);
255     createTimeGroups();
256 }
257
258
259 int EventModel::loadSearchResultEvents(const QDate &aDate, int aConferenceId) {
260     clearModel();
261     try {
262         mEvents = Event::getSearchResultByDate(QDate(aDate.year(), aDate.month(), aDate.day()), aConferenceId, "start, duration");
263     }
264     catch( OrmException &e  ){
265         qDebug() << "Event::getSearchResultByDate failed: " << e.text();
266     }
267     catch(...){
268         qDebug() << "Event::getSearchResultByDate failed";
269     }
270
271     createTimeGroups();
272
273     return mEvents.count();
274 }
275
276
277 void EventModel::loadEventsByTrack(const QDate &aDate, int aConferenceId) {
278     clearModel();
279     mEvents = Event::getByDate(QDate(aDate.year(), aDate.month(), aDate.day()), aConferenceId, "xid_track, start, duration");
280     createTrackGroups();
281 }
282
283
284 void EventModel::loadEventsByRoom(const QDate &aDate, int aConferenceId) {
285     clearModel();
286     mEvents = Event::getByDateAndRoom(QDate(aDate.year(), aDate.month(), aDate.day()), aConferenceId);
287     createRoomGroups();
288 }
289
290
291 void EventModel::loadConflictEvents(int aEventId, int aConferenceId) {
292     clearModel();
293     mEvents = Event::conflictEvents(aEventId, aConferenceId);
294     createTimeGroups();
295 }
296
297
298 void EventModel::updateModel(int aEventId)
299 {
300     for(int i=0; i<mEvents.count(); i++)
301     {
302         if(mEvents[i].id() == aEventId)
303             mEvents[i] = Event::getById(aEventId,Conference::activeConference());
304     }
305
306     // find the ModelIndex for given aEventId
307     for(int i=0; i<mGroups.count(); i++)
308     {
309         QModelIndex groupIndex = index(i,0,QModelIndex());
310         for(int j=0; j<mGroups[i].mChildCount; j++)
311         {
312             QModelIndex eventIndex = index(j,0,groupIndex);
313             if(static_cast<Event*>(eventIndex.internalPointer())->id() == aEventId)
314             {
315                 emit(dataChanged(groupIndex,groupIndex));
316                 emit(dataChanged(eventIndex,eventIndex));
317             }
318         }
319     }
320 }
321