[ca90cb1] | 1 | /* |
---|
| 2 | * Copyright (C) 2010 Ixonos Plc. |
---|
[de5d0f1] | 3 | * Copyright (C) 2011-2017 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" |
---|
[d1fb9ee] | 24 | |
---|
[72cd3af] | 25 | const QString EventModel::COMMA_SEPARATOR = ", "; |
---|
| 26 | |
---|
[69393c0] | 27 | EventModel::EventModel() |
---|
[04acaf9] | 28 | { } |
---|
[d0d0a66] | 29 | |
---|
[12fe870] | 30 | |
---|
| 31 | void EventModel::Group::setTitle(const QList<Event>& mEvents) { |
---|
[41c4ceb] | 32 | QDateTime startTime = mEvents.at(mFirstEventIndex).start(); |
---|
| 33 | QDateTime endTime(startTime); |
---|
[12fe870] | 34 | for (int i = mFirstEventIndex; i != mFirstEventIndex + mChildCount; ++i) { |
---|
[41c4ceb] | 35 | endTime = qMax(mEvents.at(i).start().addSecs(mEvents.at(i).duration()), endTime); |
---|
[12fe870] | 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. |
---|
[d0d0a66] | 45 | void EventModel::createTimeGroups() |
---|
| 46 | { |
---|
[4b6ae6b] | 47 | beginResetModel(); |
---|
| 48 | |
---|
[d0d0a66] | 49 | mGroups.clear(); |
---|
| 50 | mParents.clear(); |
---|
[12fe870] | 51 | if (mEvents.empty()) return; |
---|
[d0d0a66] | 52 | |
---|
[8f15208] | 53 | const int minTimeSpan = 3600; // one hour // minimum duration of a group in seconds |
---|
[6bf226b] | 54 | const int minChildCount = 3; // minimum number of events in one group |
---|
[d0d0a66] | 55 | |
---|
[8f15208] | 56 | QDateTime groupStartDateTime(mEvents.first().start().date(), QTime(mEvents.first().start().time().hour(), 0), mEvents.first().start().timeSpec()); |
---|
[0b595d2] | 57 | QDateTime groupEndDateTime = groupStartDateTime.addSecs(mEvents.first().duration()); |
---|
[12fe870] | 58 | mGroups << EventModel::Group("", 0); |
---|
| 59 | int timeSpan = minTimeSpan; |
---|
[d0d0a66] | 60 | |
---|
[12fe870] | 61 | for (int i = 0; i != mEvents.count(); ++i) { |
---|
[6bf226b] | 62 | QDateTime eventStartDateTime = mEvents.at(i).start(); |
---|
[0b595d2] | 63 | QDateTime eventEndDateTime = eventStartDateTime.addSecs(mEvents.at(i).duration()); |
---|
[d0d0a66] | 64 | |
---|
[0b595d2] | 65 | if (eventStartDateTime >= groupStartDateTime.addSecs(timeSpan)) { |
---|
[12fe870] | 66 | // a new group could be necessary |
---|
| 67 | if (mGroups.last().mChildCount < minChildCount) { |
---|
| 68 | // too few events in the group => no new group |
---|
| 69 | // except a gap in time would occur that is longer than minTimeSpan |
---|
[6bf226b] | 70 | QDateTime prevEventStartDateTime = mEvents.at(i).start(); |
---|
[0b595d2] | 71 | if (i > 0 && qMax(prevEventStartDateTime.addSecs(mEvents.at(i-1).duration()), groupEndDateTime).secsTo(eventStartDateTime) < minTimeSpan) { |
---|
[12fe870] | 72 | timeSpan += minTimeSpan; |
---|
| 73 | --i; |
---|
| 74 | continue; // repeat with the same event |
---|
| 75 | } |
---|
| 76 | } |
---|
| 77 | |
---|
| 78 | // a new group is necessary |
---|
| 79 | mGroups.last().setTitle(mEvents); |
---|
[0b595d2] | 80 | groupStartDateTime = groupStartDateTime.addSecs(timeSpan); |
---|
| 81 | groupEndDateTime = groupStartDateTime.addSecs(mEvents.at(i).duration()); |
---|
[12fe870] | 82 | mGroups << EventModel::Group("", i); |
---|
| 83 | timeSpan = minTimeSpan; |
---|
[d0d0a66] | 84 | } |
---|
| 85 | |
---|
[12fe870] | 86 | // insert event into current group |
---|
[d0d0a66] | 87 | mParents[mEvents.at(i).id()] = mGroups.count() - 1; |
---|
[12fe870] | 88 | mGroups.last().mChildCount += 1; |
---|
[0b595d2] | 89 | groupEndDateTime = qMax(eventEndDateTime, groupEndDateTime); |
---|
[d0d0a66] | 90 | } |
---|
| 91 | |
---|
[12fe870] | 92 | // the last group needs a title as well |
---|
| 93 | mGroups.last().setTitle(mEvents); |
---|
[04acaf9] | 94 | |
---|
[4b6ae6b] | 95 | endResetModel(); |
---|
[d0d0a66] | 96 | } |
---|
| 97 | |
---|
[4693fa6] | 98 | void EventModel::createTrackGroups() { |
---|
[f6300c7] | 99 | mGroups.clear(); |
---|
| 100 | mParents.clear(); |
---|
| 101 | if (mEvents.empty()) |
---|
| 102 | { |
---|
| 103 | return; |
---|
| 104 | } |
---|
[4693fa6] | 105 | int trackId = mEvents.first().trackId(); |
---|
[9208bdb] | 106 | |
---|
[005e2b7] | 107 | mGroups << EventModel::Group(Track::retrieveTrackName(trackId), 0); |
---|
[4693fa6] | 108 | int nextTrackId = trackId; |
---|
[f6300c7] | 109 | |
---|
| 110 | for (int i=0; i<mEvents.count(); i++) |
---|
| 111 | { |
---|
[4693fa6] | 112 | trackId = mEvents.at(i).trackId(); |
---|
| 113 | if (nextTrackId != trackId) |
---|
[f6300c7] | 114 | { |
---|
| 115 | mGroups.last().mChildCount = i - mGroups.last().mFirstEventIndex; |
---|
[005e2b7] | 116 | mGroups << EventModel::Group(Track::retrieveTrackName(trackId), i); |
---|
[4693fa6] | 117 | nextTrackId = trackId; |
---|
[f6300c7] | 118 | } |
---|
| 119 | // add parent-child relation |
---|
| 120 | mParents[mEvents.at(i).id()] = mGroups.count() - 1; |
---|
| 121 | } |
---|
| 122 | mGroups.last().mChildCount = mEvents.count() - mGroups.last().mFirstEventIndex; |
---|
| 123 | } |
---|
| 124 | |
---|
[7620de0] | 125 | void EventModel::createRoomGroups() |
---|
| 126 | { |
---|
[005e2b7] | 127 | mGroups.clear(); |
---|
| 128 | mParents.clear(); |
---|
| 129 | if (mEvents.empty()) |
---|
| 130 | { |
---|
| 131 | return; |
---|
| 132 | } |
---|
[7620de0] | 133 | int roomId = mEvents.first().roomId(); |
---|
| 134 | |
---|
| 135 | mGroups << EventModel::Group(Room::retrieveRoomName(roomId), 0); |
---|
| 136 | int nextRoomId = roomId; |
---|
| 137 | |
---|
| 138 | QList<Event>::iterator event = mEvents.begin(); |
---|
| 139 | int i = 0; |
---|
| 140 | while (event != mEvents.end()) |
---|
[005e2b7] | 141 | { |
---|
[7620de0] | 142 | roomId = event->roomId(); |
---|
| 143 | if (nextRoomId != roomId) |
---|
[005e2b7] | 144 | { |
---|
[7620de0] | 145 | mGroups.last().mChildCount = i - mGroups.last().mFirstEventIndex; |
---|
| 146 | mGroups << EventModel::Group(Room::retrieveRoomName(roomId), i); |
---|
| 147 | nextRoomId = roomId; |
---|
[005e2b7] | 148 | } |
---|
[7620de0] | 149 | mParents[event->id()] = mGroups.count() - 1; |
---|
| 150 | event++; |
---|
| 151 | i++; |
---|
[005e2b7] | 152 | } |
---|
[7620de0] | 153 | mGroups.last().mChildCount = mEvents.count() - mGroups.last().mFirstEventIndex; |
---|
[005e2b7] | 154 | } |
---|
| 155 | |
---|
[d0d0a66] | 156 | QVariant EventModel::data(const QModelIndex& index, int role) const |
---|
| 157 | { |
---|
| 158 | if (index.isValid() && role == Qt::DisplayRole) |
---|
| 159 | { |
---|
| 160 | if (index.internalId() == 0) |
---|
[5842349] | 161 | { |
---|
[d0d0a66] | 162 | return mGroups.at(index.row()).mTitle; |
---|
| 163 | } |
---|
[27102d5] | 164 | else //event data |
---|
[d0d0a66] | 165 | { |
---|
| 166 | return static_cast<Event*>(index.internalPointer())->id(); |
---|
| 167 | } |
---|
| 168 | } |
---|
| 169 | |
---|
| 170 | return QVariant(); |
---|
| 171 | } |
---|
| 172 | |
---|
| 173 | QModelIndex EventModel::index(int row, int column, const QModelIndex& parent) const |
---|
| 174 | { |
---|
| 175 | // TODO: add checks for out of range rows |
---|
| 176 | |
---|
| 177 | if (!parent.isValid()) |
---|
| 178 | { |
---|
[4b6ae6b] | 179 | return createIndex(row, column, (quintptr) 0); |
---|
[d0d0a66] | 180 | } |
---|
| 181 | else if (parent.internalId() == 0) |
---|
| 182 | { |
---|
| 183 | const Group& group = mGroups.at(parent.row()); |
---|
| 184 | Event* event = const_cast<Event*>(&mEvents.at(row + group.mFirstEventIndex)); |
---|
| 185 | return createIndex(row, column, reinterpret_cast<void*>(event)); |
---|
| 186 | } |
---|
| 187 | else |
---|
| 188 | { |
---|
| 189 | return QModelIndex(); |
---|
| 190 | } |
---|
| 191 | } |
---|
| 192 | |
---|
| 193 | QModelIndex EventModel::parent(const QModelIndex & index) const |
---|
| 194 | { |
---|
| 195 | if (index.isValid()) |
---|
| 196 | { |
---|
| 197 | if (index.internalId() == 0) |
---|
| 198 | { |
---|
| 199 | return QModelIndex(); |
---|
| 200 | } |
---|
| 201 | |
---|
| 202 | Event * event = static_cast<Event*>(index.internalPointer()); |
---|
| 203 | |
---|
[4b6ae6b] | 204 | return createIndex(mParents[event->id()], 0, (quintptr) 0); |
---|
[d0d0a66] | 205 | } |
---|
| 206 | |
---|
| 207 | return QModelIndex(); |
---|
| 208 | } |
---|
| 209 | |
---|
| 210 | int EventModel::columnCount(const QModelIndex & parent) const |
---|
| 211 | { |
---|
| 212 | Q_UNUSED(parent); |
---|
| 213 | return 1; |
---|
| 214 | } |
---|
| 215 | |
---|
| 216 | int EventModel::rowCount (const QModelIndex & parent) const |
---|
| 217 | { |
---|
| 218 | if (!parent.isValid()) |
---|
| 219 | { |
---|
| 220 | return mGroups.count(); |
---|
| 221 | } |
---|
| 222 | |
---|
| 223 | if (parent.internalId() == 0) |
---|
| 224 | { |
---|
| 225 | return mGroups.at(parent.row()).mChildCount; |
---|
| 226 | } |
---|
| 227 | |
---|
| 228 | return 0; |
---|
| 229 | } |
---|
[72f6fe4] | 230 | |
---|
[f6300c7] | 231 | void EventModel::clearModel() |
---|
[72f6fe4] | 232 | { |
---|
[4b6ae6b] | 233 | beginResetModel(); |
---|
[04acaf9] | 234 | mGroups.clear(); |
---|
[72f6fe4] | 235 | mEvents.clear(); |
---|
[04acaf9] | 236 | mParents.clear(); |
---|
[4b6ae6b] | 237 | endResetModel(); |
---|
[f6300c7] | 238 | } |
---|
[69393c0] | 239 | |
---|
[41c4ceb] | 240 | |
---|
| 241 | void EventModel::loadEvents(const QDate &aDate, int aConferenceId) { |
---|
[f6300c7] | 242 | clearModel(); |
---|
[41c4ceb] | 243 | mEvents = Event::getByDate(QDate(aDate.year(), aDate.month(), aDate.day()), aConferenceId, "start, duration"); |
---|
[72f6fe4] | 244 | createTimeGroups(); |
---|
| 245 | } |
---|
| 246 | |
---|
[41c4ceb] | 247 | |
---|
| 248 | void EventModel::loadFavEvents(const QDate &aDate, int aConferenceId) { |
---|
[f6300c7] | 249 | clearModel(); |
---|
[41c4ceb] | 250 | mEvents = Event::getFavByDate(QDate(aDate.year(), aDate.month(), aDate.day()), aConferenceId); |
---|
[6f39595] | 251 | createTimeGroups(); |
---|
| 252 | } |
---|
| 253 | |
---|
[9d8946b] | 254 | |
---|
[41c4ceb] | 255 | int EventModel::loadSearchResultEvents(const QDate &aDate, int aConferenceId) { |
---|
| 256 | clearModel(); |
---|
| 257 | try { |
---|
| 258 | mEvents = Event::getSearchResultByDate(QDate(aDate.year(), aDate.month(), aDate.day()), aConferenceId, "start, duration"); |
---|
| 259 | } |
---|
| 260 | catch( OrmException &e ){ |
---|
| 261 | qDebug() << "Event::getSearchResultByDate failed: " << e.text(); |
---|
| 262 | } |
---|
| 263 | catch(...){ |
---|
| 264 | qDebug() << "Event::getSearchResultByDate failed"; |
---|
[e662750] | 265 | } |
---|
[9d8946b] | 266 | |
---|
[e662750] | 267 | createTimeGroups(); |
---|
[9d8946b] | 268 | |
---|
| 269 | return mEvents.count(); |
---|
[e662750] | 270 | } |
---|
| 271 | |
---|
[41c4ceb] | 272 | |
---|
| 273 | void EventModel::loadEventsByTrack(const QDate &aDate, int aConferenceId) { |
---|
[f6300c7] | 274 | clearModel(); |
---|
[41c4ceb] | 275 | mEvents = Event::getByDate(QDate(aDate.year(), aDate.month(), aDate.day()), aConferenceId, "xid_track, start, duration"); |
---|
[4693fa6] | 276 | createTrackGroups(); |
---|
[f6300c7] | 277 | } |
---|
| 278 | |
---|
[41c4ceb] | 279 | |
---|
| 280 | void EventModel::loadEventsByRoom(const QDate &aDate, int aConferenceId) { |
---|
[7620de0] | 281 | clearModel(); |
---|
[41c4ceb] | 282 | mEvents = Event::getByDateAndRoom(QDate(aDate.year(), aDate.month(), aDate.day()), aConferenceId); |
---|
[7620de0] | 283 | createRoomGroups(); |
---|
| 284 | } |
---|
| 285 | |
---|
[b8a3ad1] | 286 | |
---|
[066b41f] | 287 | void EventModel::loadConflictEvents(int aEventId, int aConferenceId) { |
---|
[d49254d] | 288 | clearModel(); |
---|
[41c4ceb] | 289 | mEvents = Event::conflictEvents(aEventId, aConferenceId); |
---|
[d49254d] | 290 | createTimeGroups(); |
---|
| 291 | } |
---|
| 292 | |
---|
[41c4ceb] | 293 | |
---|
[c718a77] | 294 | void EventModel::updateModel(int aEventId) |
---|
[67c59a7] | 295 | { |
---|
[c718a77] | 296 | for(int i=0; i<mEvents.count(); i++) |
---|
| 297 | { |
---|
| 298 | if(mEvents[i].id() == aEventId) |
---|
[0bb39f5] | 299 | mEvents[i] = Event::getById(aEventId,Conference::activeConference()); |
---|
[c718a77] | 300 | } |
---|
| 301 | |
---|
| 302 | // find the ModelIndex for given aEventId |
---|
| 303 | for(int i=0; i<mGroups.count(); i++) |
---|
| 304 | { |
---|
| 305 | QModelIndex groupIndex = index(i,0,QModelIndex()); |
---|
| 306 | for(int j=0; j<mGroups[i].mChildCount; j++) |
---|
| 307 | { |
---|
| 308 | QModelIndex eventIndex = index(j,0,groupIndex); |
---|
| 309 | if(static_cast<Event*>(eventIndex.internalPointer())->id() == aEventId) |
---|
| 310 | { |
---|
[7b70507] | 311 | emit(dataChanged(groupIndex,groupIndex)); |
---|
[c718a77] | 312 | emit(dataChanged(eventIndex,eventIndex)); |
---|
| 313 | } |
---|
| 314 | } |
---|
| 315 | } |
---|
[67c59a7] | 316 | } |
---|
| 317 | |
---|