File indexing completed on 2024-04-28 09:46:21
0001 /* 0002 * SPDX-FileCopyrightText: 2020 Dimitris Kardarakos <dimkard@posteo.net> 0003 * 0004 * SPDX-License-Identifier: GPL-3.0-or-later 0005 */ 0006 0007 #include "eventmodel.h" 0008 #include <KCalendarCore/CalFilter> 0009 #include <KLocalizedString> 0010 #include "settingscontroller.h" 0011 0012 EventModel::EventModel(QObject *parent) : 0013 QAbstractListModel {parent}, 0014 m_events {KCalendarCore::Event::List {}}, 0015 m_filterdt {QDate {}}, 0016 m_category {QString {}}, 0017 m_local_calendar {nullptr}, 0018 m_settings_controller {new SettingsController} 0019 { 0020 connect(this, &EventModel::filterdtChanged, this, &EventModel::loadEvents); 0021 connect(this, &EventModel::calendarChanged, this, &EventModel::loadEvents); 0022 connect(this, &EventModel::eventCategoryChanged, this, &EventModel::loadEvents); 0023 } 0024 0025 QDate EventModel::filterdt() const 0026 { 0027 return m_filterdt; 0028 } 0029 0030 void EventModel::setFilterdt(const QDate &filterDate) 0031 { 0032 m_filterdt = filterDate; 0033 0034 Q_EMIT filterdtChanged(); 0035 } 0036 0037 LocalCalendar *EventModel::calendar() const 0038 { 0039 return m_local_calendar; 0040 } 0041 0042 void EventModel::setCalendar(LocalCalendar *const calendarPtr) 0043 { 0044 m_local_calendar = calendarPtr; 0045 0046 connect(m_local_calendar, &LocalCalendar::eventsChanged, this, &EventModel::loadEvents); 0047 0048 Q_EMIT calendarChanged(); 0049 } 0050 0051 QHash<int, QByteArray> EventModel::roleNames() const 0052 { 0053 return { 0054 { Uid, "uid" }, 0055 { EventStartDt, "eventStartDt" }, 0056 { EventDt, "eventDt" }, 0057 { ShiftedEventDt, "shiftedEventDt" }, 0058 { ShiftedEventDtLocal, "shiftedEventDtLocal" }, 0059 { ScheduleStartDt, "scheduleStartDt" }, 0060 { AllDay, "allday" }, 0061 { Description, "description" }, 0062 { Summary, "summary" }, 0063 { LastModified, "lastmodified" }, 0064 { Location, "location" }, 0065 { Categories, "categories" }, 0066 { Priority, "priority" }, 0067 { Created, "created" }, 0068 { Secrecy, "secrecy" }, 0069 { EventEndDt, "eventEndDt" }, 0070 { ScheduleEndDt, "scheduleEndDt" }, 0071 { Transparency, "transparency" }, 0072 { RepeatPeriodType, "repeatType" }, 0073 { RepeatEvery, "repeatEvery" }, 0074 { RepeatStopAfter, "repeatStopAfter" }, 0075 { IsRepeating, "isRepeating" }, 0076 { EventCategories, "eventCategories" }, 0077 { Url, "url" }, 0078 { ShiftedStartEndDt, "shiftedStartEndDt" }, 0079 { ShiftedStartEndDtLocal, "shiftedStartEndDtLocal" }, 0080 { ShiftedStartEndTime, "shiftedStartEndTime" }, 0081 { ShiftedStartEndTimeLocal, "shiftedStartEndTimeLocal" }, 0082 { StartEndDt, "startEndDt" }, 0083 { StartEndDtLocal, "startEndDtLocal" }, 0084 { Overlapping, "overlapping" }, 0085 { ConferenceTzId, "conferenceTzId" } 0086 }; 0087 } 0088 0089 static void applyTimeZone(QDateTime &dt, const QTimeZone &tz) 0090 { 0091 if (dt.timeSpec() == Qt::LocalTime) { 0092 dt.setTimeZone(tz); 0093 } else { 0094 dt = dt.toTimeZone(tz); 0095 } 0096 } 0097 0098 QVariant EventModel::data(const QModelIndex &index, int role) const 0099 { 0100 if (!index.isValid()) { 0101 return QVariant {}; 0102 } 0103 0104 auto row = index.row(); 0105 auto calendarTz = m_local_calendar->memorycalendar()->timeZone(); 0106 auto startDtTime = m_events.at(row)->dtStart(); 0107 auto endDtTime = m_events.at(row)->dtEnd(); 0108 auto allDay = m_events.at(row)->allDay(); 0109 0110 switch (role) { 0111 case Uid : 0112 return m_events.at(row)->uid(); 0113 case EventStartDt: 0114 return startDtTime; 0115 case EventDt: 0116 return startDtTime.toString("dddd d MMMM"); 0117 case ShiftedEventDt: { 0118 applyTimeZone(startDtTime, calendarTz); 0119 return startDtTime.toString("dddd d MMMM"); 0120 } 0121 case ShiftedEventDtLocal: { 0122 startDtTime = startDtTime.toTimeZone(QTimeZone::systemTimeZone()); 0123 return startDtTime.toString("dddd d MMMM"); 0124 } 0125 case ScheduleStartDt: { 0126 applyTimeZone(startDtTime, calendarTz); 0127 return startDtTime; 0128 } 0129 case AllDay: 0130 return allDay; 0131 case Description: 0132 return m_events.at(row)->description(); 0133 case Summary: 0134 return m_events.at(row)->summary(); 0135 case LastModified: 0136 return m_events.at(row)->lastModified(); 0137 case Location: 0138 return m_events.at(row)->location(); 0139 case Categories: 0140 return m_events.at(row)->categories(); 0141 case Priority: 0142 return m_events.at(row)->priority(); 0143 case Created: 0144 return m_events.at(row)->created(); 0145 case Secrecy: 0146 return m_events.at(row)->secrecy(); 0147 case EventEndDt: 0148 return endDtTime; 0149 case ScheduleEndDt: { 0150 applyTimeZone(endDtTime, calendarTz); 0151 return endDtTime; 0152 } 0153 case Transparency: 0154 return m_events.at(row)->transparency(); 0155 case RepeatPeriodType: 0156 return repeatPeriodType(row); 0157 case RepeatEvery: 0158 return repeatEvery(row); 0159 case RepeatStopAfter: 0160 return repeatStopAfter(row); 0161 case IsRepeating: 0162 return m_events.at(row)->recurs(); 0163 case EventCategories: 0164 return m_events.at(row)->categoriesStr(); 0165 case Url: 0166 return m_events.at(row)->url(); 0167 case ShiftedStartEndDt: { 0168 // Shift and convert time to the time zone of the conference 0169 applyTimeZone(startDtTime, calendarTz); 0170 applyTimeZone(endDtTime, calendarTz); 0171 0172 return formatStartEndDt(startDtTime, endDtTime, allDay); 0173 } 0174 case ShiftedStartEndDtLocal: { 0175 // Shift time to the time zone of the conference and convert to the system time zone 0176 startDtTime = startDtTime.toTimeZone(QTimeZone::systemTimeZone()); 0177 endDtTime = endDtTime.toTimeZone(QTimeZone::systemTimeZone()); 0178 0179 return formatStartEndDt(startDtTime, endDtTime, allDay); 0180 } 0181 case ShiftedStartEndTime: { 0182 // Shift time to the time zone of the conference 0183 applyTimeZone(startDtTime, calendarTz); 0184 applyTimeZone(endDtTime, calendarTz); 0185 0186 return formatStartEndTime(startDtTime, endDtTime); 0187 } 0188 case ShiftedStartEndTimeLocal: { 0189 // Shift time to the conference time zone and convert time to the system time zone 0190 startDtTime = startDtTime.toTimeZone(QTimeZone::systemTimeZone()); 0191 endDtTime = endDtTime.toTimeZone(QTimeZone::systemTimeZone()); 0192 0193 return formatStartEndTime(startDtTime, endDtTime); 0194 } 0195 case StartEndDt: { 0196 // Convert time to the time zone of the conference 0197 applyTimeZone(startDtTime, calendarTz); 0198 applyTimeZone(endDtTime, calendarTz); 0199 0200 return formatStartEndDt(startDtTime, endDtTime, allDay); 0201 } 0202 case StartEndDtLocal: { 0203 //Convert time to the system time zone 0204 startDtTime = startDtTime.toTimeZone(QTimeZone::systemTimeZone()); 0205 endDtTime = endDtTime.toTimeZone(QTimeZone::systemTimeZone()); 0206 0207 return formatStartEndDt(startDtTime, endDtTime, allDay); 0208 } 0209 case Overlapping: 0210 return overlappingEvents(row); 0211 case ConferenceTzId: { 0212 return calendarTz.id(); 0213 } 0214 default: 0215 return QVariant {}; 0216 } 0217 } 0218 0219 int EventModel::rowCount(const QModelIndex &parent) const 0220 { 0221 if (parent.isValid()) { 0222 return 0; 0223 } 0224 0225 return m_events.count(); 0226 } 0227 0228 void EventModel::loadEvents() 0229 { 0230 beginResetModel(); 0231 m_events.clear(); 0232 0233 if (m_local_calendar != nullptr && m_local_calendar->memorycalendar() != nullptr && m_filterdt.isValid()) { 0234 auto filterTz = m_settings_controller->displayInLocalTimezone() ? QTimeZone::systemTimeZone() : m_local_calendar->memorycalendar()->timeZone(); 0235 auto dayEvents = m_local_calendar->memorycalendar()->rawEvents(m_filterdt, m_filterdt, filterTz, true); 0236 m_events = KCalendarCore::Calendar::sortEvents(std::move(dayEvents), KCalendarCore::EventSortField::EventSortStartDate, KCalendarCore::SortDirection::SortDirectionAscending); 0237 } 0238 0239 if (m_local_calendar != nullptr && m_local_calendar->memorycalendar() != nullptr && m_filterdt.isNull()) { 0240 m_events = m_local_calendar->memorycalendar()->rawEvents(KCalendarCore::EventSortStartDate, KCalendarCore::SortDirectionAscending); 0241 } 0242 0243 if (m_local_calendar != nullptr && !(m_category.isEmpty())) { 0244 QStringList categories {m_category}; 0245 KCalendarCore::CalFilter filter {}; 0246 filter.setCategoryList(categories); 0247 filter.setCriteria(KCalendarCore::CalFilter::ShowCategories); 0248 filter.apply(&m_events); 0249 } 0250 0251 endResetModel(); 0252 } 0253 0254 int EventModel::repeatEvery(const int idx) const 0255 { 0256 if (!(m_events.at(idx)->recurs())) { 0257 return 0; 0258 } 0259 0260 return m_events.at(idx)->recurrence()->frequency(); 0261 } 0262 0263 int EventModel::repeatStopAfter(const int idx) const 0264 { 0265 0266 if (!(m_events.at(idx)->recurs())) { 0267 return -1; 0268 } 0269 0270 return m_events.at(idx)->recurrence()->duration(); 0271 } 0272 0273 ushort EventModel::repeatPeriodType(const int idx) const 0274 { 0275 if (!(m_events.at(idx)->recurs())) { 0276 return KCalendarCore::Recurrence::rNone; 0277 } 0278 0279 return m_events.at(idx)->recurrence()->recurrenceType(); 0280 } 0281 0282 void EventModel::setEventCategory(const QString &category) 0283 { 0284 if (m_category != category) { 0285 m_category = category; 0286 Q_EMIT eventCategoryChanged(); 0287 } 0288 } 0289 0290 QString EventModel::eventCategory() const 0291 { 0292 return m_category; 0293 } 0294 0295 int EventModel::overlappingEvents(const int idx) const 0296 { 0297 int cnt = 0; 0298 0299 for (const auto &e : m_events) { 0300 if ((m_events.at(idx)->dtStart() < e->dtEnd()) && (m_events.at(idx)->dtEnd() > e->dtStart()) && (m_events.at(idx)->uid() != e->uid())) { 0301 ++cnt; 0302 } 0303 } 0304 0305 return cnt; 0306 } 0307 0308 QString EventModel::formatStartEndTime(const QDateTime &startDtTime, const QDateTime &endDtTime) const 0309 { 0310 if (startDtTime.date() == endDtTime.date()) { 0311 return QString {"%1 - %2"}.arg(startDtTime.time().toString("hh:mm"), endDtTime.time().toString("hh:mm")); 0312 } 0313 0314 auto displayStartDtTime = QString {"%1 %2"}.arg(startDtTime.date().toString("ddd d MMM yyyy"), startDtTime.time().toString("hh:mm")); 0315 auto displayEndDtTime = QString {"%1 %2"}.arg(endDtTime.date().toString("ddd d MMM yyyy"), endDtTime.time().toString("hh:mm")); 0316 0317 return QString {"%1 - %2 %3"}.arg(displayStartDtTime, displayEndDtTime, startDtTime.timeZoneAbbreviation()); 0318 } 0319 0320 QString EventModel::formatStartEndDt(const QDateTime &startDtTime, const QDateTime &endDtTime, bool allDay) const 0321 { 0322 if (allDay) { 0323 return startDtTime.date().toString("ddd d MMM yyyy"); 0324 } 0325 0326 if (startDtTime.date() == endDtTime.date()) { 0327 0328 auto displayDt = startDtTime.date().toString("ddd d MMM yyyy"); 0329 auto displayTime = QString {"%1 - %2"}.arg(startDtTime.time().toString("hh:mm"), endDtTime.time().toString("hh:mm")); 0330 0331 return QString {"%1 %2 %3"}.arg(displayDt, displayTime, startDtTime.timeZoneAbbreviation()); 0332 } 0333 0334 auto displayStartDtTime = QString {"%1 %2"}.arg(startDtTime.date().toString("ddd d MMM yyyy"), startDtTime.time().toString("hh:mm")); 0335 auto displayEndDtTime = QString {"%1 %2"}.arg(endDtTime.date().toString("ddd d MMM yyyy"), endDtTime.time().toString("hh:mm")); 0336 0337 return QString {"%1 - %2 %3"}.arg(displayStartDtTime, displayEndDtTime, startDtTime.timeZoneAbbreviation()); 0338 } 0339 0340 #include "moc_eventmodel.cpp"