File indexing completed on 2025-01-05 04:49:48
0001 /* 0002 * SPDX-FileCopyrightText: 2016 Daniel Vrátil <dvratil@kde.org> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 * 0006 */ 0007 0008 #include "eventdatavisitor.h" 0009 #include "pimdatasource.h" 0010 #include "pimeventsplugin_debug.h" 0011 0012 BaseEventDataVisitor::BaseEventDataVisitor(PimDataSource *dataSource, QDate start, QDate end) 0013 : mDataSource(dataSource) 0014 , mStart(start) 0015 , mEnd(end) 0016 { 0017 } 0018 0019 BaseEventDataVisitor::~BaseEventDataVisitor() = default; 0020 0021 bool BaseEventDataVisitor::act(const KCalendarCore::Incidence::Ptr &incidence) 0022 { 0023 return incidence->accept(*this, incidence); 0024 } 0025 0026 bool BaseEventDataVisitor::act(const KCalendarCore::Event::List &events) 0027 { 0028 bool ok = false; 0029 for (const KCalendarCore::Event::Ptr &event : events) { 0030 ok = event.staticCast<KCalendarCore::IncidenceBase>()->accept(*this, event) || ok; 0031 } 0032 return ok; 0033 } 0034 0035 bool BaseEventDataVisitor::act(const KCalendarCore::Todo::List &todos) 0036 { 0037 bool ok = false; 0038 for (const KCalendarCore::Todo::Ptr &todo : todos) { 0039 ok = todo.staticCast<KCalendarCore::IncidenceBase>()->accept(*this, todo) || ok; 0040 } 0041 return ok; 0042 } 0043 0044 bool BaseEventDataVisitor::isInRange(QDate start, QDate end) const 0045 { 0046 if (!mStart.isValid() || !mEnd.isValid()) { 0047 return true; 0048 } 0049 0050 if (!end.isValid() && start >= mStart && start <= mEnd) { 0051 return true; 0052 } else if (start < mStart) { 0053 return end >= mStart; 0054 } else if (end > mEnd) { 0055 return start <= mEnd; 0056 } else { 0057 return true; 0058 } 0059 } 0060 0061 QString BaseEventDataVisitor::generateUid(const KCalendarCore::Incidence::Ptr &incidence, const QDateTime &recurrenceId) const 0062 { 0063 // Get a corresponding Akonadi Item: Akonadi ID is the only reliably unique 0064 // and persistent identifier when dealing with incidences from multiple 0065 // calendars 0066 const qint64 itemId = mDataSource->akonadiIdForIncidence(incidence); 0067 if (itemId <= 0) { 0068 // Can this happen? What do we do now?! 0069 return {}; 0070 } 0071 0072 if (recurrenceId.isValid()) { 0073 return QStringLiteral("Akonadi-%1-%2").arg(itemId).arg(recurrenceId.toString(QStringLiteral("yyyyMMddThhmmsst"))); 0074 } else { 0075 return QStringLiteral("Akonadi-%1").arg(itemId); 0076 } 0077 } 0078 0079 QList<CalendarEvents::EventData> 0080 BaseEventDataVisitor::explodeIncidenceOccurences(const CalendarEvents::EventData &ed, const KCalendarCore::Incidence::Ptr &incidence, bool &ok) 0081 { 0082 Q_ASSERT(incidence->recurs()); 0083 0084 const qint64 duration = ed.startDateTime().secsTo(ed.endDateTime()); 0085 0086 QDateTime rec(mStart.addDays(-1), QTime(0, 0, 0)); 0087 rec = incidence->recurrence()->getNextDateTime(rec); 0088 QList<CalendarEvents::EventData> results; 0089 while (rec.isValid() && rec.date() <= mEnd) { 0090 CalendarEvents::EventData copy = ed; 0091 QDateTime dt; 0092 if (incidence->allDay()) { 0093 dt = QDateTime(rec.date(), QTime(0, 0, 0), Qt::LocalTime); 0094 } else { 0095 dt = rec.toLocalTime(); 0096 } 0097 copy.setStartDateTime(dt); 0098 copy.setEndDateTime(dt.addSecs(duration)); 0099 copy.setUid(generateUid(incidence, rec)); 0100 0101 results.push_back(copy); 0102 0103 rec = incidence->recurrence()->getNextDateTime(rec); 0104 } 0105 0106 ok = true; 0107 return results; 0108 } 0109 0110 EventDataVisitor::EventDataVisitor(PimDataSource *dataSource, const QDate &start, const QDate &end) 0111 : BaseEventDataVisitor(dataSource, start, end) 0112 { 0113 } 0114 0115 EventDataVisitor::~EventDataVisitor() = default; 0116 0117 const QMultiHash<QDate, CalendarEvents::EventData> &EventDataVisitor::results() const 0118 { 0119 return mResults; 0120 } 0121 0122 bool EventDataVisitor::visit(const KCalendarCore::Incidence::Ptr &incidence, CalendarEvents::EventData::EventType type) 0123 { 0124 CalendarEvents::EventData data = incidenceData(incidence); 0125 data.setEventType(type); 0126 if (incidence->recurs()) { 0127 bool ok = false; 0128 const auto list = explodeIncidenceOccurences(data, incidence, ok); 0129 if (ok) { 0130 for (const auto &dataCalendar : list) { 0131 insertResult(dataCalendar); 0132 } 0133 } 0134 return ok; 0135 } else if (isInRange(data.startDateTime().date(), data.endDateTime().date())) { 0136 insertResult(data); 0137 return true; 0138 } 0139 0140 return false; 0141 } 0142 0143 bool EventDataVisitor::visit(const KCalendarCore::Event::Ptr &event) 0144 { 0145 return visit(event, CalendarEvents::EventData::Event); 0146 } 0147 0148 bool EventDataVisitor::visit(const KCalendarCore::Todo::Ptr &todo) 0149 { 0150 return visit(todo, CalendarEvents::EventData::Todo); 0151 } 0152 0153 void EventDataVisitor::insertResult(const CalendarEvents::EventData &result) 0154 { 0155 QDate d = result.startDateTime().date(); 0156 const QDate end = result.endDateTime().date(); 0157 0158 // Agenda without start date will be placed at the end (due) date 0159 if (!d.isValid()) { 0160 mResults.insert(end, result); 0161 return; 0162 } 0163 0164 while (d <= end) { 0165 mResults.insert(d, result); 0166 d = d.addDays(1); 0167 } 0168 } 0169 0170 CalendarEvents::EventData EventDataVisitor::incidenceData(const KCalendarCore::Incidence::Ptr &incidence) const 0171 { 0172 CalendarEvents::EventData data; 0173 data.setTitle(incidence->summary()); 0174 data.setDescription(incidence->description()); 0175 data.setIsAllDay(incidence->allDay()); 0176 data.setIsMinor(false); 0177 data.setUid(generateUid(incidence)); 0178 data.setStartDateTime(incidence->dtStart().toLocalTime()); 0179 data.setEndDateTime(incidence->dateTime(KCalendarCore::Incidence::RoleEnd).toLocalTime()); 0180 data.setEventColor(mDataSource->calendarColorForIncidence(incidence)); 0181 return data; 0182 } 0183 0184 EventDataIdVisitor::EventDataIdVisitor(PimDataSource *dataSource, QDate start, QDate end) 0185 : BaseEventDataVisitor(dataSource, start, end) 0186 { 0187 } 0188 0189 const QStringList &EventDataIdVisitor::results() const 0190 { 0191 return mResults; 0192 } 0193 0194 bool EventDataIdVisitor::visit(const KCalendarCore::Event::Ptr &event) 0195 { 0196 return visit(event.staticCast<KCalendarCore::Incidence>()); 0197 } 0198 0199 bool EventDataIdVisitor::visit(const KCalendarCore::Todo::Ptr &todo) 0200 { 0201 return visit(todo.staticCast<KCalendarCore::Incidence>()); 0202 } 0203 0204 bool EventDataIdVisitor::visit(const KCalendarCore::Incidence::Ptr &incidence) 0205 { 0206 if (incidence->recurs()) { 0207 CalendarEvents::EventData ed; 0208 bool ok = false; 0209 const auto list = explodeIncidenceOccurences(ed, incidence, ok); 0210 if (ok) { 0211 for (const auto &data : list) { 0212 mResults.push_back(data.uid()); 0213 } 0214 } 0215 return ok; 0216 } else { 0217 mResults.push_back(generateUid(incidence, incidence->recurrenceId())); 0218 } 0219 return true; 0220 }