[ca90cb1] | 1 | /* |
---|
| 2 | * Copyright (C) 2010 Ixonos Plc. |
---|
[ffb6be7] | 3 | * Copyright (C) 2011-2021 Philipp Spitzer, gregor herrmann, Stefan Stahl |
---|
[ca90cb1] | 4 | * |
---|
[6df32f2] | 5 | * This file is part of ConfClerk. |
---|
[ca90cb1] | 6 | * |
---|
[6df32f2] | 7 | * ConfClerk is free software: you can redistribute it and/or modify it |
---|
[ca90cb1] | 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 | * |
---|
[6df32f2] | 12 | * ConfClerk is distributed in the hope that it will be useful, but |
---|
[ca90cb1] | 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 |
---|
[6df32f2] | 18 | * ConfClerk. If not, see <http://www.gnu.org/licenses/>. |
---|
[ca90cb1] | 19 | */ |
---|
[d0d0a66] | 20 | #include "eventmodel.h" |
---|
[7680536] | 21 | #include "conference.h" |
---|
| 22 | #include "track.h" |
---|
| 23 | #include "room.h" |
---|
[a5e1f50] | 24 | #include "application.h" |
---|
[5b7fa79] | 25 | |
---|
[72cd3af] | 26 | const QString EventModel::COMMA_SEPARATOR = ", "; |
---|
| 27 | |
---|
[69393c0] | 28 | EventModel::EventModel() |
---|
[04acaf9] | 29 | { } |
---|
[d0d0a66] | 30 | |
---|
[12fe870] | 31 | |
---|
| 32 | void EventModel::Group::setTitle(const QList<Event>& mEvents) { |
---|
[41c4ceb] | 33 | QDateTime startTime = mEvents.at(mFirstEventIndex).start(); |
---|
| 34 | QDateTime endTime(startTime); |
---|
[12fe870] | 35 | for (int i = mFirstEventIndex; i != mFirstEventIndex + mChildCount; ++i) { |
---|
[41c4ceb] | 36 | endTime = qMax(mEvents.at(i).start().addSecs(mEvents.at(i).duration()), endTime); |
---|
[12fe870] | 37 | } |
---|
[5b7fa79] | 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")); |
---|
[12fe870] | 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. |
---|
[d0d0a66] | 49 | void EventModel::createTimeGroups() |
---|
| 50 | { |
---|
[4b6ae6b] | 51 | beginResetModel(); |
---|
| 52 | |
---|
[d0d0a66] | 53 | mGroups.clear(); |
---|
| 54 | mParents.clear(); |
---|
[12fe870] | 55 | if (mEvents.empty()) return; |
---|
[d0d0a66] | 56 | |
---|
[8f15208] | 57 | const int minTimeSpan = 3600; // one hour // minimum duration of a group in seconds |
---|
[6bf226b] | 58 | const int minChildCount = 3; // minimum number of events in one group |
---|
[d0d0a66] | 59 | |
---|
[8f15208] | 60 | QDateTime groupStartDateTime(mEvents.first().start().date(), QTime(mEvents.first().start().time().hour(), 0), mEvents.first().start().timeSpec()); |
---|
[0b595d2] | 61 | QDateTime groupEndDateTime = groupStartDateTime.addSecs(mEvents.first().duration()); |
---|
[12fe870] | 62 | mGroups << EventModel::Group("", 0); |
---|
| 63 | int timeSpan = minTimeSpan; |
---|
[d0d0a66] | 64 | |
---|
[12fe870] | 65 | for (int i = 0; i != mEvents.count(); ++i) { |
---|
[6bf226b] | 66 | QDateTime eventStartDateTime = mEvents.at(i).start(); |
---|
[0b595d2] | 67 | QDateTime eventEndDateTime = eventStartDateTime.addSecs(mEvents.at(i).duration()); |
---|
[d0d0a66] | 68 | |
---|
[0b595d2] | 69 | if (eventStartDateTime >= groupStartDateTime.addSecs(timeSpan)) { |
---|
[12fe870] | 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 |
---|
[6bf226b] | 74 | QDateTime prevEventStartDateTime = mEvents.at(i).start(); |
---|
[0b595d2] | 75 | if (i > 0 && qMax(prevEventStartDateTime.addSecs(mEvents.at(i-1).duration()), groupEndDateTime).secsTo(eventStartDateTime) < minTimeSpan) { |
---|
[12fe870] | 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); |
---|
[0b595d2] | 84 | groupStartDateTime = groupStartDateTime.addSecs(timeSpan); |
---|
| 85 | groupEndDateTime = groupStartDateTime.addSecs(mEvents.at(i).duration()); |
---|
[12fe870] | 86 | mGroups << EventModel::Group("", i); |
---|
| 87 | timeSpan = minTimeSpan; |
---|
[d0d0a66] | 88 | } |
---|
| 89 | |
---|
[12fe870] | 90 | // insert event into current group |
---|
[d0d0a66] | 91 | mParents[mEvents.at(i).id()] = mGroups.count() - 1; |
---|
[12fe870] | 92 | mGroups.last().mChildCount += 1; |
---|
[0b595d2] | 93 | groupEndDateTime = qMax(eventEndDateTime, groupEndDateTime); |
---|
[d0d0a66] | 94 | } |
---|
| 95 | |
---|
[12fe870] | 96 | // the last group needs a title as well |
---|
| 97 | mGroups.last().setTitle(mEvents); |
---|
[04acaf9] | 98 | |
---|
[4b6ae6b] | 99 | endResetModel(); |
---|
[d0d0a66] | 100 | } |
---|
| 101 | |
---|
[4693fa6] | 102 | void EventModel::createTrackGroups() { |
---|
[f6300c7] | 103 | mGroups.clear(); |
---|
| 104 | mParents.clear(); |
---|
| 105 | if (mEvents.empty()) |
---|
| 106 | { |
---|
| 107 | return; |
---|
| 108 | } |
---|
[4693fa6] | 109 | int trackId = mEvents.first().trackId(); |
---|
[9208bdb] | 110 | |
---|
[005e2b7] | 111 | mGroups << EventModel::Group(Track::retrieveTrackName(trackId), 0); |
---|
[4693fa6] | 112 | int nextTrackId = trackId; |
---|
[f6300c7] | 113 | |
---|
| 114 | for (int i=0; i<mEvents.count(); i++) |
---|
| 115 | { |
---|
[4693fa6] | 116 | trackId = mEvents.at(i).trackId(); |
---|
| 117 | if (nextTrackId != trackId) |
---|
[f6300c7] | 118 | { |
---|
| 119 | mGroups.last().mChildCount = i - mGroups.last().mFirstEventIndex; |
---|
[005e2b7] | 120 | mGroups << EventModel::Group(Track::retrieveTrackName(trackId), i); |
---|
[4693fa6] | 121 | nextTrackId = trackId; |
---|
[f6300c7] | 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 | |
---|
[7620de0] | 129 | void EventModel::createRoomGroups() |
---|
| 130 | { |
---|
[005e2b7] | 131 | mGroups.clear(); |
---|
| 132 | mParents.clear(); |
---|
| 133 | if (mEvents.empty()) |
---|
| 134 | { |
---|
| 135 | return; |
---|
| 136 | } |
---|
[7620de0] | 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()) |
---|
[005e2b7] | 145 | { |
---|
[7620de0] | 146 | roomId = event->roomId(); |
---|
| 147 | if (nextRoomId != roomId) |
---|
[005e2b7] | 148 | { |
---|
[7620de0] | 149 | mGroups.last().mChildCount = i - mGroups.last().mFirstEventIndex; |
---|
| 150 | mGroups << EventModel::Group(Room::retrieveRoomName(roomId), i); |
---|
| 151 | nextRoomId = roomId; |
---|
[005e2b7] | 152 | } |
---|
[7620de0] | 153 | mParents[event->id()] = mGroups.count() - 1; |
---|
| 154 | event++; |
---|
| 155 | i++; |
---|
[005e2b7] | 156 | } |
---|
[7620de0] | 157 | mGroups.last().mChildCount = mEvents.count() - mGroups.last().mFirstEventIndex; |
---|
[005e2b7] | 158 | } |
---|
| 159 | |
---|
[d0d0a66] | 160 | QVariant EventModel::data(const QModelIndex& index, int role) const |
---|
| 161 | { |
---|
| 162 | if (index.isValid() && role == Qt::DisplayRole) |
---|
| 163 | { |
---|
| 164 | if (index.internalId() == 0) |
---|
[5842349] | 165 | { |
---|
[d0d0a66] | 166 | return mGroups.at(index.row()).mTitle; |
---|
| 167 | } |
---|
[27102d5] | 168 | else //event data |
---|
[d0d0a66] | 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 | { |
---|
[79a7671] | 183 | return createIndex(row, column); |
---|
[d0d0a66] | 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 | |
---|
[79a7671] | 208 | return createIndex(mParents[event->id()], 0); |
---|
[d0d0a66] | 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 | } |
---|
[72f6fe4] | 234 | |
---|
[f6300c7] | 235 | void EventModel::clearModel() |
---|
[72f6fe4] | 236 | { |
---|
[4b6ae6b] | 237 | beginResetModel(); |
---|
[04acaf9] | 238 | mGroups.clear(); |
---|
[72f6fe4] | 239 | mEvents.clear(); |
---|
[04acaf9] | 240 | mParents.clear(); |
---|
[4b6ae6b] | 241 | endResetModel(); |
---|
[f6300c7] | 242 | } |
---|
[69393c0] | 243 | |
---|
[41c4ceb] | 244 | |
---|
| 245 | void EventModel::loadEvents(const QDate &aDate, int aConferenceId) { |
---|
[f6300c7] | 246 | clearModel(); |
---|
[41c4ceb] | 247 | mEvents = Event::getByDate(QDate(aDate.year(), aDate.month(), aDate.day()), aConferenceId, "start, duration"); |
---|
[72f6fe4] | 248 | createTimeGroups(); |
---|
| 249 | } |
---|
| 250 | |
---|
[41c4ceb] | 251 | |
---|
| 252 | void EventModel::loadFavEvents(const QDate &aDate, int aConferenceId) { |
---|
[f6300c7] | 253 | clearModel(); |
---|
[41c4ceb] | 254 | mEvents = Event::getFavByDate(QDate(aDate.year(), aDate.month(), aDate.day()), aConferenceId); |
---|
[6f39595] | 255 | createTimeGroups(); |
---|
| 256 | } |
---|
| 257 | |
---|
[9d8946b] | 258 | |
---|
[41c4ceb] | 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"; |
---|
[e662750] | 269 | } |
---|
[9d8946b] | 270 | |
---|
[e662750] | 271 | createTimeGroups(); |
---|
[9d8946b] | 272 | |
---|
| 273 | return mEvents.count(); |
---|
[e662750] | 274 | } |
---|
| 275 | |
---|
[41c4ceb] | 276 | |
---|
| 277 | void EventModel::loadEventsByTrack(const QDate &aDate, int aConferenceId) { |
---|
[f6300c7] | 278 | clearModel(); |
---|
[41c4ceb] | 279 | mEvents = Event::getByDate(QDate(aDate.year(), aDate.month(), aDate.day()), aConferenceId, "xid_track, start, duration"); |
---|
[4693fa6] | 280 | createTrackGroups(); |
---|
[f6300c7] | 281 | } |
---|
| 282 | |
---|
[41c4ceb] | 283 | |
---|
| 284 | void EventModel::loadEventsByRoom(const QDate &aDate, int aConferenceId) { |
---|
[7620de0] | 285 | clearModel(); |
---|
[41c4ceb] | 286 | mEvents = Event::getByDateAndRoom(QDate(aDate.year(), aDate.month(), aDate.day()), aConferenceId); |
---|
[7620de0] | 287 | createRoomGroups(); |
---|
| 288 | } |
---|
| 289 | |
---|
[b8a3ad1] | 290 | |
---|
[066b41f] | 291 | void EventModel::loadConflictEvents(int aEventId, int aConferenceId) { |
---|
[d49254d] | 292 | clearModel(); |
---|
[41c4ceb] | 293 | mEvents = Event::conflictEvents(aEventId, aConferenceId); |
---|
[d49254d] | 294 | createTimeGroups(); |
---|
| 295 | } |
---|
| 296 | |
---|
[41c4ceb] | 297 | |
---|
[c718a77] | 298 | void EventModel::updateModel(int aEventId) |
---|
[67c59a7] | 299 | { |
---|
[c718a77] | 300 | for(int i=0; i<mEvents.count(); i++) |
---|
| 301 | { |
---|
| 302 | if(mEvents[i].id() == aEventId) |
---|
[0bb39f5] | 303 | mEvents[i] = Event::getById(aEventId,Conference::activeConference()); |
---|
[c718a77] | 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 | { |
---|
[7b70507] | 315 | emit(dataChanged(groupIndex,groupIndex)); |
---|
[c718a77] | 316 | emit(dataChanged(eventIndex,eventIndex)); |
---|
| 317 | } |
---|
| 318 | } |
---|
| 319 | } |
---|
[67c59a7] | 320 | } |
---|
| 321 | |
---|