source: src/mvc/eventmodel.cpp @ 0b595d2

qt5
Last change on this file since 0b595d2 was 0b595d2, checked in by gregor herrmann <gregoa@…>, 10 years ago

createTimeGroups(): use QDateTime instead of QTime to avoid "midnight overflow".
Cf. #42

  • Property mode set to 100644
File size: 9.9 KB
Line 
1/*
2 * Copyright (C) 2010 Ixonos Plc.
3 * Copyright (C) 2011-2012 Philipp Spitzer, gregor herrmann
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
25const QString EventModel::COMMA_SEPARATOR = ", ";
26
27EventModel::EventModel()
28{ }
29
30
31void EventModel::Group::setTitle(const QList<Event>& mEvents) {
32    QTime startTime = mEvents.at(mFirstEventIndex).start().time();
33    QTime endTime(0, 0);
34    for (int i = mFirstEventIndex; i != mFirstEventIndex + mChildCount; ++i) {
35        endTime = qMax(mEvents.at(i).start().time().addSecs(mEvents.at(i).duration()), endTime);
36    }
37    mTitle = QString("%1 - %2").arg(startTime.toString("HH:mm")).arg(endTime.toString("HH:mm"));
38}
39
40
41// We want to group the events into "time slots/time groups" that
42// should start at full hours and have the duration of either
43// one hour or (if less than 3 events are in one time slot)
44// multiple of one hour.
45void EventModel::createTimeGroups()
46{
47    mGroups.clear();
48    mParents.clear();
49    if (mEvents.empty()) return;
50
51    const int minTimeSpan = 3600; // one hour
52    const int minChildCount = 3; // minimum number of events in one group
53
54    // Create the first time group. The events have to be sorted by start time at this point!
55    QDateTime groupStartDateTime(mEvents.first().start().date(), mEvents.first().start().time());
56    QDateTime groupEndDateTime = groupStartDateTime.addSecs(mEvents.first().duration());
57    mGroups << EventModel::Group("", 0);
58    int timeSpan = minTimeSpan;
59
60    for (int i = 0; i != mEvents.count(); ++i) {
61        QDateTime eventStartDateTime (mEvents.at(i).start().date(), mEvents.at(i).start().time());
62        QDateTime eventEndDateTime = eventStartDateTime.addSecs(mEvents.at(i).duration());
63
64        if (eventStartDateTime >= groupStartDateTime.addSecs(timeSpan)) {
65            // a new group could be necessary
66            if (mGroups.last().mChildCount < minChildCount) {
67                // too few events in the group => no new group
68                // except a gap in time would occur that is longer than minTimeSpan
69                QDateTime prevEventStartDateTime (mEvents.at(i).start().date(), mEvents.at(i).start().time());
70                if (i > 0 && qMax(prevEventStartDateTime.addSecs(mEvents.at(i-1).duration()), groupEndDateTime).secsTo(eventStartDateTime) < minTimeSpan) {
71                    timeSpan += minTimeSpan;
72                    --i;
73                    continue; // repeat with the same event
74                }
75            }
76
77            // a new group is necessary
78            mGroups.last().setTitle(mEvents);
79            groupStartDateTime = groupStartDateTime.addSecs(timeSpan);
80            groupEndDateTime = groupStartDateTime.addSecs(mEvents.at(i).duration());
81            mGroups << EventModel::Group("", i);
82            timeSpan = minTimeSpan;
83        }
84
85        // insert event into current group
86        mParents[mEvents.at(i).id()] = mGroups.count() - 1;
87        mGroups.last().mChildCount += 1;
88        groupEndDateTime = qMax(eventEndDateTime, groupEndDateTime);
89    }
90
91    // the last group needs a title as well
92    mGroups.last().setTitle(mEvents);
93
94    reset();
95}
96
97void EventModel::createTrackGroups() {
98    mGroups.clear();
99    mParents.clear();
100    if (mEvents.empty())
101    {
102        return;
103    }
104    int trackId = mEvents.first().trackId();
105
106    mGroups << EventModel::Group(Track::retrieveTrackName(trackId), 0);
107    int nextTrackId = trackId;
108
109    for (int i=0; i<mEvents.count(); i++)
110    {
111        trackId = mEvents.at(i).trackId();
112        if (nextTrackId != trackId)
113        {
114            mGroups.last().mChildCount = i - mGroups.last().mFirstEventIndex;
115            mGroups << EventModel::Group(Track::retrieveTrackName(trackId), i);
116            nextTrackId = trackId;
117        }
118        // add parent-child relation
119        mParents[mEvents.at(i).id()] = mGroups.count() - 1;
120    }
121    mGroups.last().mChildCount = mEvents.count() - mGroups.last().mFirstEventIndex;
122}
123
124void EventModel::createRoomGroups()
125{
126    mGroups.clear();
127    mParents.clear();
128    if (mEvents.empty())
129    {
130        return;
131    }
132    int roomId = mEvents.first().roomId();
133
134    mGroups << EventModel::Group(Room::retrieveRoomName(roomId), 0);
135    int nextRoomId = roomId;
136
137    QList<Event>::iterator event = mEvents.begin();
138    int i = 0;
139    while (event != mEvents.end())
140    {
141        roomId = event->roomId();
142        if (nextRoomId != roomId)
143        {
144            mGroups.last().mChildCount = i - mGroups.last().mFirstEventIndex;
145            mGroups << EventModel::Group(Room::retrieveRoomName(roomId), i);
146            nextRoomId = roomId;
147        }
148        mParents[event->id()] = mGroups.count() - 1;
149        event++;
150        i++;
151    }
152    mGroups.last().mChildCount = mEvents.count() - mGroups.last().mFirstEventIndex;
153}
154
155QVariant EventModel::data(const QModelIndex& index, int role) const
156{
157    if (index.isValid() && role == Qt::DisplayRole)
158    {
159        if (index.internalId() == 0)
160        {
161            return mGroups.at(index.row()).mTitle;
162        }
163        else //event data
164        {
165            return static_cast<Event*>(index.internalPointer())->id();
166        }
167    }
168
169    return QVariant();
170}
171
172QModelIndex EventModel::index(int row, int column, const QModelIndex& parent) const
173{
174    // TODO: add checks for out of range rows
175
176    if (!parent.isValid())
177    {
178        return createIndex(row, column, 0);
179    }
180    else if (parent.internalId() == 0)
181    {
182        const Group& group = mGroups.at(parent.row());
183        Event* event = const_cast<Event*>(&mEvents.at(row + group.mFirstEventIndex));
184        return createIndex(row, column, reinterpret_cast<void*>(event));
185    }
186    else
187    {
188        return QModelIndex();
189    }
190}
191
192QModelIndex EventModel::parent(const QModelIndex & index) const
193{
194    if (index.isValid())
195    {
196        if (index.internalId() == 0)
197        {
198            return QModelIndex();
199        }
200
201        Event * event = static_cast<Event*>(index.internalPointer());
202
203        return createIndex(mParents[event->id()], 0, 0);
204    }
205
206    return QModelIndex();
207}
208
209int EventModel::columnCount(const QModelIndex & parent) const
210{
211    Q_UNUSED(parent);
212    return 1;
213}
214
215int EventModel::rowCount (const QModelIndex & parent) const
216{
217    if (!parent.isValid())
218    {
219        return mGroups.count();
220    }
221
222    if (parent.internalId() == 0)
223    {
224        return mGroups.at(parent.row()).mChildCount;
225    }
226
227    return 0;
228}
229
230void EventModel::clearModel()
231{
232    mGroups.clear();
233    mEvents.clear();
234    mParents.clear();
235
236    reset();
237}
238
239void EventModel::loadEvents(const QDate &aDate, int aConferenceId)
240{
241    clearModel();
242    // check for existence of the conference in the DB
243    if(Conference::getAll().count())
244    {
245        mEvents = Event::getByDate(QDate(aDate.year(), aDate.month(), aDate.day()), aConferenceId, "start, duration");
246    }
247    createTimeGroups();
248}
249
250void EventModel::loadFavEvents(const QDate &aDate, int aConferenceId)
251{
252    clearModel();
253    // check for existence of the conference in the DB
254    if(Conference::getAll().count())
255    {
256        mEvents = Event::getFavByDate(QDate(aDate.year(), aDate.month(), aDate.day()), aConferenceId);
257    }
258    createTimeGroups();
259}
260
261int EventModel::loadSearchResultEvents(const QDate &aDate, int aConferenceId)
262{
263    clearModel();
264    // check for existence of the conference in the DB
265    if(Conference::getAll().count())
266    {
267        try{
268            mEvents = Event::getSearchResultByDate(QDate(aDate.year(), aDate.month(), aDate.day()), aConferenceId, "start, duration");
269        }
270        catch( OrmException &e  ){
271            qDebug() << "Event::getSearchResultByDate failed: " << e.text();
272        }
273        catch(...){
274            qDebug() << "Event::getSearchResultByDate failed";
275        }
276
277    }
278
279    createTimeGroups();
280
281    return mEvents.count();
282}
283
284void EventModel::loadEventsByTrack(const QDate &aDate, int aConferenceId)
285{
286    clearModel();
287    if (Conference::getAll().count())
288    {
289        mEvents = Event::getByDate(QDate(aDate.year(), aDate.month(), aDate.day()), aConferenceId, "xid_track, start, duration");
290    }
291    createTrackGroups();
292}
293
294void EventModel::loadEventsByRoom(const QDate &aDate, int aConferenceId)
295{
296    clearModel();
297    if (Conference::getAll().count())
298    {
299        mEvents = Event::getByDateAndRoom(QDate(aDate.year(), aDate.month(), aDate.day()), aConferenceId);
300    }
301    createRoomGroups();
302}
303
304
305void EventModel::loadConflictEvents(int aEventId, int aConferenceId) {
306    clearModel();
307    // check for existence of the conference in the DB
308    if(Conference::getAll().count())
309    {
310        mEvents = Event::conflictEvents(aEventId, aConferenceId);
311    }
312    createTimeGroups();
313}
314
315void EventModel::updateModel(int aEventId)
316{
317    for(int i=0; i<mEvents.count(); i++)
318    {
319        if(mEvents[i].id() == aEventId)
320            mEvents[i] = Event::getById(aEventId,Conference::activeConference());
321    }
322
323    // find the ModelIndex for given aEventId
324    for(int i=0; i<mGroups.count(); i++)
325    {
326        QModelIndex groupIndex = index(i,0,QModelIndex());
327        for(int j=0; j<mGroups[i].mChildCount; j++)
328        {
329            QModelIndex eventIndex = index(j,0,groupIndex);
330            if(static_cast<Event*>(eventIndex.internalPointer())->id() == aEventId)
331            {
332                emit(dataChanged(groupIndex,groupIndex));
333                emit(dataChanged(eventIndex,eventIndex));
334            }
335        }
336    }
337}
338
Note: See TracBrowser for help on using the repository browser.