File indexing completed on 2024-04-28 07:41:19

0001 /*
0002   This file is part of the kcalcore library.
0003 
0004   SPDX-FileCopyrightText: 1998 Preston Brown <pbrown@kde.org>
0005   SPDX-FileCopyrightText: 2001, 2003, 2004 Cornelius Schumacher <schumacher@kde.org>
0006   SPDX-FileCopyrightText: 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
0007 
0008   SPDX-License-Identifier: LGPL-2.0-or-later
0009 */
0010 /**
0011   @file
0012   This file is part of the API for handling calendar data and
0013   defines the MemoryCalendar class.
0014 
0015   @brief
0016   This class provides a calendar stored as a local file.
0017 
0018   @author Preston Brown \<pbrown@kde.org\>
0019   @author Cornelius Schumacher \<schumacher@kde.org\>
0020  */
0021 
0022 #include "memorycalendar.h"
0023 #include "calformat.h"
0024 #include "kcalendarcore_debug.h"
0025 
0026 #include <QDate>
0027 
0028 #include <functional>
0029 
0030 using namespace KCalendarCore;
0031 
0032 /**
0033   Private class that helps to provide binary compatibility between releases.
0034   @internal
0035 */
0036 //@cond PRIVATE
0037 class Q_DECL_HIDDEN KCalendarCore::MemoryCalendar::Private
0038 {
0039 private:
0040     static constexpr int incidenceTypeCount = 4;
0041 
0042 public:
0043     Private(MemoryCalendar *qq)
0044         : q(qq)
0045         , mFormat(nullptr)
0046         , mUpdateLastModified(true)
0047     {
0048     }
0049     ~Private()
0050     {
0051     }
0052 
0053     MemoryCalendar *q;
0054     CalFormat *mFormat; // calendar format
0055     QString mIncidenceBeingUpdated; //  Instance identifier of Incidence currently being updated
0056     bool mUpdateLastModified; // Call setLastModified() on incidence modific ations
0057 
0058     /**
0059      * List of all incidences.
0060      * First indexed by incidence->type(), then by incidence->uid();
0061      */
0062     QMultiHash<QString, Incidence::Ptr> mIncidences[incidenceTypeCount];
0063 
0064     /**
0065      * Has all incidences, indexed by identifier.
0066      */
0067     QHash<QString, KCalendarCore::Incidence::Ptr> mIncidencesByIdentifier;
0068 
0069     /**
0070      * Contains incidences ( to-dos; non-recurring, non-multiday events; journals; )
0071      * indexed by start/due date.
0072      *
0073      * The QMap key is the incidence->type().
0074      * The QMultiHash key is the dtStart/dtDue() converted to calendar's timezone
0075      *
0076      * Note: We had 3 variables, mJournalsForDate, mTodosForDate and mEventsForDate
0077      * but i merged them into one (indexed by type) because it simplifies code using
0078      * it. No need to if else based on type.
0079      */
0080     QMultiHash<QDate, Incidence::Ptr> mIncidencesForDate[incidenceTypeCount];
0081 
0082     void insertIncidence(const Incidence::Ptr &incidence);
0083 
0084     Incidence::Ptr incidence(const QString &uid, IncidenceBase::IncidenceType type, const QDateTime &recurrenceId = {}) const;
0085 
0086     bool deleteIncidence(const QString &uid, IncidenceBase::IncidenceType type, const QDateTime &recurrenceId = {});
0087 
0088     void deleteAllIncidences(IncidenceBase::IncidenceType type);
0089 
0090     template<typename IncidenceType, typename Key>
0091     void forIncidences(const QMultiHash<Key, Incidence::Ptr> &incidences, const Key &key, std::function<void(const typename IncidenceType::Ptr &)> &&op) const
0092     {
0093         for (auto it = incidences.constFind(key), end = incidences.cend(); it != end && it.key() == key; ++it) {
0094             op(it.value().template staticCast<IncidenceType>());
0095         }
0096     }
0097 
0098     template<typename IncidenceType, typename Key>
0099     void forIncidences(const QMultiHash<Key, Incidence::Ptr> &incidences, std::function<void(const typename IncidenceType::Ptr &)> &&op) const
0100     {
0101         for (const auto &incidence : incidences) {
0102             op(incidence.template staticCast<IncidenceType>());
0103         }
0104     }
0105 
0106     template<typename IncidenceType>
0107     typename IncidenceType::List castIncidenceList(const QMultiHash<QString, Incidence::Ptr> &incidences) const
0108     {
0109         typename IncidenceType::List list;
0110         list.reserve(incidences.size());
0111         std::transform(incidences.cbegin(), incidences.cend(), std::back_inserter(list), [](const Incidence::Ptr &inc) {
0112             return inc.staticCast<IncidenceType>();
0113         });
0114         return list;
0115     }
0116 
0117     template<typename IncidenceType>
0118     typename IncidenceType::List incidenceInstances(IncidenceBase::IncidenceType type, const Incidence::Ptr &incidence) const
0119     {
0120         typename IncidenceType::List list;
0121         forIncidences<IncidenceType, QString>(mIncidences[type], incidence->uid(), [&list](const typename IncidenceType::Ptr &incidence) {
0122             if (incidence->hasRecurrenceId()) {
0123                 list.push_back(incidence);
0124             }
0125         });
0126         return list;
0127     }
0128 
0129     Incidence::Ptr findIncidence(const QMultiHash<QString, Incidence::Ptr> &incidences, const QString &uid, const QDateTime &recurrenceId) const
0130     {
0131         for (auto it = incidences.constFind(uid), end = incidences.cend(); it != end && it.key() == uid; ++it) {
0132             const auto &incidence = it.value();
0133             if (recurrenceId.isNull() && !incidence->hasRecurrenceId()) {
0134                 return incidence;
0135             } else if (!recurrenceId.isNull() && incidence->hasRecurrenceId() && recurrenceId == incidence->recurrenceId()) {
0136                 return incidence;
0137             }
0138         }
0139         return {};
0140     }
0141 };
0142 //@endcond
0143 
0144 MemoryCalendar::MemoryCalendar(const QTimeZone &timeZone)
0145     : Calendar(timeZone)
0146     , d(new KCalendarCore::MemoryCalendar::Private(this))
0147 {
0148 }
0149 
0150 MemoryCalendar::MemoryCalendar(const QByteArray &timeZoneId)
0151     : Calendar(timeZoneId)
0152     , d(new KCalendarCore::MemoryCalendar::Private(this))
0153 {
0154 }
0155 
0156 MemoryCalendar::~MemoryCalendar()
0157 {
0158     setObserversEnabled(false);
0159 
0160     // Don't call the virtual function deleteEvents() etc, the base class might have
0161     // other ways of deleting the data.
0162     d->deleteAllIncidences(Incidence::TypeEvent);
0163     d->deleteAllIncidences(Incidence::TypeTodo);
0164     d->deleteAllIncidences(Incidence::TypeJournal);
0165 
0166     d->mIncidencesByIdentifier.clear();
0167 
0168     setModified(false);
0169 
0170     setObserversEnabled(true);
0171 
0172     delete d;
0173 }
0174 
0175 void MemoryCalendar::doSetTimeZone(const QTimeZone &timeZone)
0176 {
0177     // Reset date based hashes before storing for the new zone.
0178     for (auto &table : d->mIncidencesForDate) {
0179         table.clear();
0180     }
0181 
0182     for (auto &table : d->mIncidences) {
0183         for (const auto &incidence : table) {
0184             const QDateTime dt = incidence->dateTime(Incidence::RoleCalendarHashing);
0185             if (dt.isValid()) {
0186                 d->mIncidencesForDate[incidence->type()].insert(dt.toTimeZone(timeZone).date(), incidence);
0187             }
0188         }
0189     }
0190 }
0191 
0192 bool MemoryCalendar::deleteIncidence(const Incidence::Ptr &incidence)
0193 {
0194     // Notify while the incidence is still available,
0195     // this is necessary so korganizer still has time to query for exceptions
0196     notifyIncidenceAboutToBeDeleted(incidence);
0197     incidence->unRegisterObserver(this);
0198     const Incidence::IncidenceType type = incidence->type();
0199     const QString &uid = incidence->uid();
0200     bool deleted = d->deleteIncidence(uid, type, incidence->recurrenceId());
0201     if (deleted) {
0202         setModified(true);
0203 
0204         // Delete child-incidences.
0205         if (!incidence->hasRecurrenceId() && incidence->recurs()) {
0206             deleteIncidenceInstances(incidence);
0207         }
0208     } else {
0209         qCWarning(KCALCORE_LOG) << incidence->typeStr() << " not found. uid=" << uid;
0210     }
0211     notifyIncidenceDeleted(incidence);
0212     return deleted;
0213 }
0214 
0215 bool MemoryCalendar::deleteIncidenceInstances(const Incidence::Ptr &incidence)
0216 {
0217     Incidence::List instances;
0218     for (auto it = d->mIncidences[incidence->type()].constFind(incidence->uid()), end = d->mIncidences[incidence->type()].constEnd();
0219          it != end && it.key() == incidence->uid();
0220          ++it) {
0221         if (it.value()->hasRecurrenceId()) {
0222             qCDebug(KCALCORE_LOG) << "deleting child"
0223                                   << ", type=" << int(incidence->type()) << ", uid="
0224                                   << incidence->uid()
0225                                   //                   << ", start=" << i->dtStart()
0226                                   << " from calendar";
0227             // Don't call deleteIncidence() now since it's modifying the
0228             // mIncidences map we're iterating over.
0229             instances.append(it.value());
0230         }
0231     }
0232     for (Incidence::Ptr instance : instances) {
0233         deleteIncidence(instance);
0234     }
0235 
0236     return true;
0237 }
0238 
0239 //@cond PRIVATE
0240 bool MemoryCalendar::Private::deleteIncidence(const QString &uid, IncidenceBase::IncidenceType type, const QDateTime &recurrenceId)
0241 {
0242     for (auto it = mIncidences[type].find(uid), end = mIncidences[type].end(); it != end && it.key() == uid; ++it) {
0243         Incidence::Ptr incidence = it.value();
0244         if (recurrenceId.isNull() && incidence->hasRecurrenceId()) {
0245             continue;
0246         } else if (!recurrenceId.isNull() && (!incidence->hasRecurrenceId() || recurrenceId != incidence->recurrenceId())) {
0247             continue;
0248         }
0249         mIncidences[type].erase(it);
0250         mIncidencesByIdentifier.remove(incidence->instanceIdentifier());
0251         const QDateTime dt = incidence->dateTime(Incidence::RoleCalendarHashing);
0252         if (dt.isValid()) {
0253             mIncidencesForDate[type].remove(dt.toTimeZone(q->timeZone()).date(), incidence);
0254         }
0255         return true;
0256     }
0257     return false;
0258 }
0259 
0260 void MemoryCalendar::Private::deleteAllIncidences(Incidence::IncidenceType incidenceType)
0261 {
0262     for (auto &incidence : mIncidences[incidenceType]) {
0263         q->notifyIncidenceAboutToBeDeleted(incidence);
0264         incidence->unRegisterObserver(q);
0265     }
0266     mIncidences[incidenceType].clear();
0267     mIncidencesForDate[incidenceType].clear();
0268 }
0269 
0270 Incidence::Ptr MemoryCalendar::Private::incidence(const QString &uid, Incidence::IncidenceType type, const QDateTime &recurrenceId) const
0271 {
0272     return findIncidence(mIncidences[type], uid, recurrenceId);
0273 }
0274 
0275 void MemoryCalendar::Private::insertIncidence(const Incidence::Ptr &incidence)
0276 {
0277     const QString uid = incidence->uid();
0278     const Incidence::IncidenceType type = incidence->type();
0279     if (!mIncidences[type].contains(uid, incidence)) {
0280         mIncidences[type].insert(uid, incidence);
0281         mIncidencesByIdentifier.insert(incidence->instanceIdentifier(), incidence);
0282         const QDateTime dt = incidence->dateTime(Incidence::RoleCalendarHashing);
0283         if (dt.isValid()) {
0284             mIncidencesForDate[type].insert(dt.toTimeZone(q->timeZone()).date(), incidence);
0285         }
0286 
0287     } else {
0288 #ifndef NDEBUG
0289         // if we already have an to-do with this UID, it must be the same incidence,
0290         // otherwise something's really broken
0291         Q_ASSERT(mIncidences[type].value(uid) == incidence);
0292 #endif
0293     }
0294 }
0295 //@endcond
0296 
0297 bool MemoryCalendar::addIncidence(const Incidence::Ptr &incidence)
0298 {
0299     d->insertIncidence(incidence);
0300 
0301     notifyIncidenceAdded(incidence);
0302 
0303     incidence->registerObserver(this);
0304 
0305     setModified(true);
0306 
0307     return true;
0308 }
0309 
0310 bool MemoryCalendar::addEvent(const Event::Ptr &event)
0311 {
0312     return addIncidence(event);
0313 }
0314 
0315 bool MemoryCalendar::deleteEvent(const Event::Ptr &event)
0316 {
0317     return deleteIncidence(event);
0318 }
0319 
0320 bool MemoryCalendar::deleteEventInstances(const Event::Ptr &event)
0321 {
0322     return deleteIncidenceInstances(event);
0323 }
0324 
0325 Event::Ptr MemoryCalendar::event(const QString &uid, const QDateTime &recurrenceId) const
0326 {
0327     return d->incidence(uid, Incidence::TypeEvent, recurrenceId).staticCast<Event>();
0328 }
0329 
0330 bool MemoryCalendar::addTodo(const Todo::Ptr &todo)
0331 {
0332     return addIncidence(todo);
0333 }
0334 
0335 bool MemoryCalendar::deleteTodo(const Todo::Ptr &todo)
0336 {
0337     return deleteIncidence(todo);
0338 }
0339 
0340 bool MemoryCalendar::deleteTodoInstances(const Todo::Ptr &todo)
0341 {
0342     return deleteIncidenceInstances(todo);
0343 }
0344 
0345 Todo::Ptr MemoryCalendar::todo(const QString &uid, const QDateTime &recurrenceId) const
0346 {
0347     return d->incidence(uid, Incidence::TypeTodo, recurrenceId).staticCast<Todo>();
0348 }
0349 
0350 Todo::List MemoryCalendar::rawTodos(TodoSortField sortField, SortDirection sortDirection) const
0351 {
0352     return Calendar::sortTodos(d->castIncidenceList<Todo>(d->mIncidences[Incidence::TypeTodo]), sortField, sortDirection);
0353 }
0354 
0355 Todo::List MemoryCalendar::todoInstances(const Incidence::Ptr &todo, TodoSortField sortField, SortDirection sortDirection) const
0356 {
0357     return Calendar::sortTodos(d->incidenceInstances<Todo>(Incidence::TypeTodo, todo), sortField, sortDirection);
0358 }
0359 
0360 Todo::List MemoryCalendar::rawTodosForDate(const QDate &date) const
0361 {
0362     Todo::List todoList;
0363 
0364     d->forIncidences<Todo>(d->mIncidencesForDate[Incidence::TypeTodo], date, [&todoList](const Todo::Ptr &todo) {
0365         todoList.append(todo);
0366     });
0367 
0368     // Iterate over all todos. Look for recurring todoss that occur on this date
0369     d->forIncidences<Todo>(d->mIncidences[Incidence::TypeTodo], [this, &todoList, &date](const Todo::Ptr &todo) {
0370         if (todo->recurs() && todo->recursOn(date, timeZone())) {
0371             todoList.append(todo);
0372         }
0373     });
0374 
0375     return todoList;
0376 }
0377 
0378 Todo::List MemoryCalendar::rawTodos(const QDate &start, const QDate &end, const QTimeZone &timeZone, bool inclusive) const
0379 {
0380     Q_UNUSED(inclusive); // use only exact dtDue/dtStart, not dtStart and dtEnd
0381 
0382     Todo::List todoList;
0383     const auto ts = timeZone.isValid() ? timeZone : this->timeZone();
0384     QDateTime st(start, QTime(0, 0, 0), ts);
0385     QDateTime nd(end, QTime(23, 59, 59, 999), ts);
0386 
0387     // Get todos
0388     for (const auto &incidence : d->mIncidences[Incidence::TypeTodo]) {
0389         const auto todo = incidence.staticCast<Todo>();
0390 
0391         QDateTime rStart = todo->hasDueDate() ? todo->dtDue() : todo->hasStartDate() ? todo->dtStart() : QDateTime();
0392         if (!rStart.isValid()) {
0393             continue;
0394         }
0395 
0396         if (!todo->recurs()) { // non-recurring todos
0397             if (nd.isValid() && nd < rStart) {
0398                 continue;
0399             }
0400             if (st.isValid() && rStart < st) {
0401                 continue;
0402             }
0403         } else { // recurring events
0404             switch (todo->recurrence()->duration()) {
0405             case -1: // infinite
0406                 break;
0407             case 0: // end date given
0408             default: // count given
0409                 QDateTime rEnd(todo->recurrence()->endDate(), QTime(23, 59, 59, 999), ts);
0410                 if (!rEnd.isValid()) {
0411                     continue;
0412                 }
0413                 if (st.isValid() && rEnd < st) {
0414                     continue;
0415                 }
0416                 break;
0417             } // switch(duration)
0418         } // if(recurs)
0419 
0420         todoList.append(todo);
0421     }
0422 
0423     return todoList;
0424 }
0425 
0426 Alarm::List MemoryCalendar::alarms(const QDateTime &from, const QDateTime &to, bool excludeBlockedAlarms) const
0427 {
0428     Q_UNUSED(excludeBlockedAlarms);
0429     Alarm::List alarmList;
0430 
0431     d->forIncidences<Event>(d->mIncidences[Incidence::TypeEvent], [this, &alarmList, &from, &to](const Event::Ptr &e) {
0432         if (e->recurs()) {
0433             appendRecurringAlarms(alarmList, e, from, to);
0434         } else {
0435             appendAlarms(alarmList, e, from, to);
0436         }
0437     });
0438 
0439     d->forIncidences<Todo>(d->mIncidences[IncidenceBase::TypeTodo], [this, &alarmList, &from, &to](const Todo::Ptr &t) {
0440         if (!t->isCompleted()) {
0441             appendAlarms(alarmList, t, from, to);
0442             if (t->recurs()) {
0443                 appendRecurringAlarms(alarmList, t, from, to);
0444             } else {
0445                 appendAlarms(alarmList, t, from, to);
0446             }
0447         }
0448     });
0449 
0450     return alarmList;
0451 }
0452 
0453 bool MemoryCalendar::updateLastModifiedOnChange() const
0454 {
0455     return d->mUpdateLastModified;
0456 }
0457 
0458 void MemoryCalendar::setUpdateLastModifiedOnChange(bool update)
0459 {
0460     d->mUpdateLastModified = update;
0461 }
0462 
0463 void MemoryCalendar::incidenceUpdate(const QString &uid, const QDateTime &recurrenceId)
0464 {
0465     Incidence::Ptr inc = incidence(uid, recurrenceId);
0466 
0467     if (inc) {
0468         if (!d->mIncidenceBeingUpdated.isEmpty()) {
0469             qCWarning(KCALCORE_LOG) << "Incidence::update() called twice without an updated() call in between.";
0470         }
0471 
0472         // Save it so we can detect changes to uid or recurringId.
0473         d->mIncidenceBeingUpdated = inc->instanceIdentifier();
0474 
0475         const QDateTime dt = inc->dateTime(Incidence::RoleCalendarHashing);
0476         if (dt.isValid()) {
0477             d->mIncidencesForDate[inc->type()].remove(dt.toTimeZone(timeZone()).date(), inc);
0478         }
0479     }
0480 }
0481 
0482 void MemoryCalendar::incidenceUpdated(const QString &uid, const QDateTime &recurrenceId)
0483 {
0484     Incidence::Ptr inc = incidence(uid, recurrenceId);
0485 
0486     if (inc) {
0487         if (d->mIncidenceBeingUpdated.isEmpty()) {
0488             qCWarning(KCALCORE_LOG) << "Incidence::updated() called twice without an update() call in between.";
0489         } else if (inc->instanceIdentifier() != d->mIncidenceBeingUpdated) {
0490             // Instance identifier changed, update our hash table
0491             d->mIncidencesByIdentifier.remove(d->mIncidenceBeingUpdated);
0492             d->mIncidencesByIdentifier.insert(inc->instanceIdentifier(), inc);
0493         }
0494 
0495         d->mIncidenceBeingUpdated = QString();
0496 
0497         if (d->mUpdateLastModified) {
0498             inc->setLastModified(QDateTime::currentDateTimeUtc());
0499         }
0500         // we should probably update the revision number here,
0501         // or internally in the Event itself when certain things change.
0502         // need to verify with ical documentation.
0503 
0504         const QDateTime dt = inc->dateTime(Incidence::RoleCalendarHashing);
0505         if (dt.isValid()) {
0506             d->mIncidencesForDate[inc->type()].insert(dt.toTimeZone(timeZone()).date(), inc);
0507         }
0508 
0509         notifyIncidenceChanged(inc);
0510 
0511         setModified(true);
0512     }
0513 }
0514 
0515 Event::List MemoryCalendar::rawEventsForDate(const QDate &date, const QTimeZone &timeZone, EventSortField sortField, SortDirection sortDirection) const
0516 {
0517     Event::List eventList;
0518 
0519     if (!date.isValid()) {
0520         // There can't be events on invalid dates
0521         return eventList;
0522     }
0523 
0524     if (timeZone.isValid() && timeZone != this->timeZone()) {
0525         // We cannot use the hash table on date, since time zone is different.
0526         eventList = rawEvents(date, date, timeZone, false);
0527         return Calendar::sortEvents(std::move(eventList), sortField, sortDirection);
0528     }
0529 
0530     // Iterate over all non-recurring, single-day events that start on this date
0531     d->forIncidences<Event>(d->mIncidencesForDate[Incidence::TypeEvent], date, [&eventList](const Event::Ptr &event) {
0532         eventList.append(event);
0533     });
0534 
0535     // Iterate over all events. Look for recurring events that occur on this date
0536     const auto ts = timeZone.isValid() ? timeZone : this->timeZone();
0537     for (const auto &event : d->mIncidences[Incidence::TypeEvent]) {
0538         const auto ev = event.staticCast<Event>();
0539         if (ev->recurs()) {
0540             if (ev->isMultiDay()) {
0541                 int extraDays = ev->dtStart().date().daysTo(ev->dtEnd().date());
0542                 for (int i = 0; i <= extraDays; ++i) {
0543                     if (ev->recursOn(date.addDays(-i), ts)) {
0544                         eventList.append(ev);
0545                         break;
0546                     }
0547                 }
0548             } else {
0549                 if (ev->recursOn(date, ts)) {
0550                     eventList.append(ev);
0551                 }
0552             }
0553         } else {
0554             if (ev->isMultiDay()) {
0555                 if (ev->dtStart().toTimeZone(ts).date() <= date && ev->dtEnd().toTimeZone(ts).date() >= date) {
0556                     eventList.append(ev);
0557                 }
0558             }
0559         }
0560     }
0561 
0562     return Calendar::sortEvents(std::move(eventList), sortField, sortDirection);
0563 }
0564 
0565 Event::List MemoryCalendar::rawEvents(const QDate &start, const QDate &end, const QTimeZone &timeZone, bool inclusive) const
0566 {
0567     Event::List eventList;
0568     const auto ts = timeZone.isValid() ? timeZone : this->timeZone();
0569     QDateTime st(start, QTime(0, 0, 0), ts);
0570     QDateTime nd(end, QTime(23, 59, 59, 999), ts);
0571 
0572     // Get non-recurring events
0573     for (const auto &e : d->mIncidences[Incidence::TypeEvent]) {
0574         const auto event = e.staticCast<Event>();
0575         QDateTime rStart = event->dtStart();
0576         if (nd.isValid() && nd < rStart) {
0577             continue;
0578         }
0579         if (inclusive && st.isValid() && rStart < st) {
0580             continue;
0581         }
0582 
0583         if (!event->recurs()) { // non-recurring events
0584             QDateTime rEnd = event->dtEnd();
0585             if (st.isValid() && rEnd < st) {
0586                 continue;
0587             }
0588             if (inclusive && nd.isValid() && nd < rEnd) {
0589                 continue;
0590             }
0591         } else { // recurring events
0592             switch (event->recurrence()->duration()) {
0593             case -1: // infinite
0594                 if (inclusive) {
0595                     continue;
0596                 }
0597                 break;
0598             case 0: // end date given
0599             default: // count given
0600                 QDateTime rEnd(event->recurrence()->endDate(), QTime(23, 59, 59, 999), ts);
0601                 if (!rEnd.isValid()) {
0602                     continue;
0603                 }
0604                 if (st.isValid() && rEnd < st) {
0605                     continue;
0606                 }
0607                 if (inclusive && nd.isValid() && nd < rEnd) {
0608                     continue;
0609                 }
0610                 break;
0611             } // switch(duration)
0612         } // if(recurs)
0613 
0614         eventList.append(event);
0615     }
0616 
0617     return eventList;
0618 }
0619 
0620 Event::List MemoryCalendar::rawEvents(EventSortField sortField, SortDirection sortDirection) const
0621 {
0622     return Calendar::sortEvents(d->castIncidenceList<Event>(d->mIncidences[Incidence::TypeEvent]), sortField, sortDirection);
0623 }
0624 
0625 Event::List MemoryCalendar::eventInstances(const Incidence::Ptr &event, EventSortField sortField, SortDirection sortDirection) const
0626 {
0627     return Calendar::sortEvents(d->incidenceInstances<Event>(Incidence::TypeEvent, event), sortField, sortDirection);
0628 }
0629 
0630 bool MemoryCalendar::addJournal(const Journal::Ptr &journal)
0631 {
0632     return addIncidence(journal);
0633 }
0634 
0635 bool MemoryCalendar::deleteJournal(const Journal::Ptr &journal)
0636 {
0637     return deleteIncidence(journal);
0638 }
0639 
0640 bool MemoryCalendar::deleteJournalInstances(const Journal::Ptr &journal)
0641 {
0642     return deleteIncidenceInstances(journal);
0643 }
0644 
0645 Journal::Ptr MemoryCalendar::journal(const QString &uid, const QDateTime &recurrenceId) const
0646 {
0647     return d->incidence(uid, Incidence::TypeJournal, recurrenceId).staticCast<Journal>();
0648 }
0649 
0650 Journal::List MemoryCalendar::rawJournals(JournalSortField sortField, SortDirection sortDirection) const
0651 {
0652     return Calendar::sortJournals(d->castIncidenceList<Journal>(d->mIncidences[Incidence::TypeJournal]), sortField, sortDirection);
0653 }
0654 
0655 Journal::List MemoryCalendar::journalInstances(const Incidence::Ptr &journal, JournalSortField sortField, SortDirection sortDirection) const
0656 {
0657     return Calendar::sortJournals(d->incidenceInstances<Journal>(Incidence::TypeJournal, journal), sortField, sortDirection);
0658 }
0659 
0660 Journal::List MemoryCalendar::rawJournalsForDate(const QDate &date) const
0661 {
0662     Journal::List journalList;
0663 
0664     d->forIncidences<Journal>(d->mIncidencesForDate[Incidence::TypeJournal], date, [&journalList](const Journal::Ptr &journal) {
0665         journalList.append(journal);
0666     });
0667 
0668     return journalList;
0669 }
0670 
0671 Incidence::Ptr MemoryCalendar::instance(const QString &identifier) const
0672 {
0673     return d->mIncidencesByIdentifier.value(identifier);
0674 }
0675 
0676 void MemoryCalendar::virtual_hook(int id, void *data)
0677 {
0678     Q_UNUSED(id);
0679     Q_UNUSED(data);
0680     Q_ASSERT(false);
0681 }
0682 
0683 #include "moc_memorycalendar.cpp"