1/*
2 This file is part of the kcalcore library.
3
4 Copyright (c) 1998 Preston Brown <pbrown@kde.org>
5 Copyright (c) 2001,2003,2004 Cornelius Schumacher <schumacher@kde.org>
6 Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
17
18 You should have received a copy of the GNU Library General Public License
19 along with this library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA.
22*/
23/**
24 @file
25 This file is part of the API for handling calendar data and
26 defines the MemoryCalendar class.
27
28 @brief
29 This class provides a calendar stored as a local file.
30
31 @author Preston Brown \<pbrown@kde.org\>
32 @author Cornelius Schumacher \<schumacher@kde.org\>
33 */
34
35#include "memorycalendar.h"
36
37#include <KDebug>
38#include <QDate>
39#include <QDataStream>
40#include <KDateTime>
41
42using namespace KCalCore;
43
44/**
45 Private class that helps to provide binary compatibility between releases.
46 @internal
47*/
48//@cond PRIVATE
49class KCalCore::MemoryCalendar::Private
50{
51public:
52 Private(MemoryCalendar *qq)
53 : q(qq), mFormat(0)
54 {
55 }
56 ~Private()
57 {
58 }
59
60 MemoryCalendar *q;
61 CalFormat *mFormat; // calendar format
62 QString mIncidenceBeingUpdated; // Instance identifier of Incidence currently being updated
63
64 /**
65 * List of all incidences.
66 * First indexed by incidence->type(), then by incidence->uid();
67 */
68 QMap<IncidenceBase::IncidenceType, QMultiHash<QString, Incidence::Ptr> > mIncidences;
69
70 /**
71 * Has all incidences, indexed by identifier.
72 */
73 QHash<QString,KCalCore::Incidence::Ptr> mIncidencesByIdentifier;
74
75 /**
76 * List of all deleted incidences.
77 * First indexed by incidence->type(), then by incidence->uid();
78 */
79 QMap<IncidenceBase::IncidenceType, QMultiHash<QString, Incidence::Ptr> > mDeletedIncidences;
80
81 /**
82 * Contains incidences ( to-dos; non-recurring, non-multiday events; journals; )
83 * indexed by start/due date.
84 *
85 * The QMap key is the incidence->type().
86 * The QMultiHash key is the dtStart/dtDue().toString()
87 *
88 * Note: We had 3 variables, mJournalsForDate, mTodosForDate and mEventsForDate
89 * but i merged them into one (indexed by type) because it simplifies code using
90 * it. No need to if else based on type.
91 */
92 QMap<IncidenceBase::IncidenceType, QMultiHash<QString, IncidenceBase::Ptr> > mIncidencesForDate;
93
94 void insertIncidence(const Incidence::Ptr &incidence);
95
96 Incidence::Ptr incidence(const QString &uid,
97 const IncidenceBase::IncidenceType type,
98 const KDateTime &recurrenceId = KDateTime()) const;
99
100 Incidence::Ptr deletedIncidence(const QString &uid,
101 const KDateTime &recurrenceId,
102 const IncidenceBase::IncidenceType type) const;
103
104 void deleteAllIncidences(const IncidenceBase::IncidenceType type);
105
106};
107//@endcond
108
109MemoryCalendar::MemoryCalendar(const KDateTime::Spec &timeSpec)
110 : Calendar(timeSpec),
111 d(new KCalCore::MemoryCalendar::Private(this))
112{
113}
114
115MemoryCalendar::MemoryCalendar(const QString &timeZoneId)
116 : Calendar(timeZoneId),
117 d(new KCalCore::MemoryCalendar::Private(this))
118{
119}
120
121MemoryCalendar::~MemoryCalendar()
122{
123 close();
124 delete d;
125}
126
127void MemoryCalendar::close()
128{
129 setObserversEnabled(false);
130
131 // Don't call the virtual function deleteEvents() etc, the base class might have
132 // other ways of deleting the data.
133 d->deleteAllIncidences(Incidence::TypeEvent);
134 d->deleteAllIncidences(Incidence::TypeTodo);
135 d->deleteAllIncidences(Incidence::TypeJournal);
136
137 d->mIncidencesByIdentifier.clear();
138 d->mDeletedIncidences.clear();
139
140 setModified(false);
141
142 setObserversEnabled(true);
143}
144
145bool MemoryCalendar::deleteIncidence(const Incidence::Ptr &incidence)
146{
147 // Handle orphaned children
148 // relations is an Incidence's property, not a Todo's, so
149 // we remove relations in deleteIncidence, not in deleteTodo.
150 removeRelations(incidence);
151 const Incidence::IncidenceType type = incidence->type();
152 const QString uid = incidence->uid();
153 if (d->mIncidences[type].remove(uid, incidence)) {
154 d->mIncidencesByIdentifier.remove(incidence->instanceIdentifier());
155 setModified(true);
156 notifyIncidenceDeleted(incidence);
157 if (deletionTracking())
158 d->mDeletedIncidences[type].insert(uid, incidence);
159
160 const KDateTime dt = incidence->dateTime(Incidence::RoleCalendarHashing);
161 if (dt.isValid()) {
162 d->mIncidencesForDate[type].remove(dt.date().toString(), incidence);
163 }
164 // Delete child-incidences.
165 if (!incidence->hasRecurrenceId()) {
166 deleteIncidenceInstances(incidence);
167 }
168 return true;
169 } else {
170 kWarning() << incidence->typeStr() << " not found. uid=" << uid;
171 return false;
172 }
173}
174
175bool MemoryCalendar::deleteIncidenceInstances(const Incidence::Ptr &incidence)
176{
177 const Incidence::IncidenceType type = incidence->type();
178 QList<Incidence::Ptr> values = d->mIncidences[type].values(incidence->uid());
179 QList<Incidence::Ptr>::const_iterator it;
180 for (it = values.constBegin(); it != values.constEnd(); ++it) {
181 Incidence::Ptr i = *it;
182 if (i->hasRecurrenceId()) {
183 kDebug() << "deleting child"
184 << ", type=" << int(type)
185 << ", uid=" << i->uid()
186 << ", start=" << i->dtStart()
187 << " from calendar";
188 deleteIncidence(i);
189 }
190 }
191
192 return true;
193}
194
195//@cond PRIVATE
196void MemoryCalendar::Private::deleteAllIncidences(const Incidence::IncidenceType incidenceType)
197{
198 QHashIterator<QString, Incidence::Ptr>i(mIncidences[incidenceType]);
199 while (i.hasNext()) {
200 i.next();
201 q->notifyIncidenceDeleted(i.value());
202 i.value()->unRegisterObserver(q);
203 }
204 mIncidences[incidenceType].clear();
205 mIncidencesForDate[incidenceType].clear();
206}
207
208Incidence::Ptr MemoryCalendar::Private::incidence(const QString &uid,
209 const Incidence::IncidenceType type,
210 const KDateTime &recurrenceId) const
211{
212 QList<Incidence::Ptr> values = mIncidences[type].values(uid);
213 QList<Incidence::Ptr>::const_iterator it;
214 for (it = values.constBegin(); it != values.constEnd(); ++it) {
215 Incidence::Ptr i = *it;
216 if (recurrenceId.isNull()) {
217 if (!i->hasRecurrenceId()) {
218 return i;
219 }
220 } else {
221 if (i->hasRecurrenceId() && i->recurrenceId() == recurrenceId) {
222 return i;
223 }
224 }
225 }
226 return Incidence::Ptr();
227}
228
229Incidence::Ptr
230MemoryCalendar::Private::deletedIncidence(const QString &uid,
231 const KDateTime &recurrenceId,
232 const IncidenceBase::IncidenceType type) const
233{
234 if (!q->deletionTracking()) {
235 return Incidence::Ptr();
236 }
237
238 QList<Incidence::Ptr> values = mDeletedIncidences[type].values(uid);
239 QList<Incidence::Ptr>::const_iterator it;
240 for (it = values.constBegin(); it != values.constEnd(); ++it) {
241 Incidence::Ptr i = *it;
242 if (recurrenceId.isNull()) {
243 if (!i->hasRecurrenceId()) {
244 return i;
245 }
246 } else {
247 if (i->hasRecurrenceId() && i->recurrenceId() == recurrenceId) {
248 return i;
249 }
250 }
251 }
252 return Incidence::Ptr();
253}
254
255void MemoryCalendar::Private::insertIncidence(const Incidence::Ptr &incidence)
256{
257 const QString uid = incidence->uid();
258 const Incidence::IncidenceType type = incidence->type();
259 if (!mIncidences[type].contains(uid, incidence)) {
260 mIncidences[type].insert(uid, incidence);
261 mIncidencesByIdentifier.insert(incidence->instanceIdentifier(), incidence);
262 const KDateTime dt = incidence->dateTime(Incidence::RoleCalendarHashing);
263 if (dt.isValid()) {
264 mIncidencesForDate[type].insert(dt.date().toString(), incidence);
265 }
266
267 } else {
268#ifndef NDEBUG
269 // if we already have an to-do with this UID, it must be the same incidence,
270 // otherwise something's really broken
271 Q_ASSERT(mIncidences[type].value(uid) == incidence);
272#endif
273 }
274}
275//@endcond
276
277bool MemoryCalendar::addIncidence(const Incidence::Ptr &incidence)
278{
279 d->insertIncidence(incidence);
280
281 notifyIncidenceAdded(incidence);
282
283 incidence->registerObserver(this);
284
285 setupRelations(incidence);
286
287 setModified(true);
288
289 return true;
290}
291
292bool MemoryCalendar::addEvent(const Event::Ptr &event)
293{
294 return addIncidence(event);
295}
296
297bool MemoryCalendar::deleteEvent(const Event::Ptr &event)
298{
299 return deleteIncidence(event);
300}
301
302bool MemoryCalendar::deleteEventInstances(const Event::Ptr &event)
303{
304 return deleteIncidenceInstances(event);
305}
306
307void MemoryCalendar::deleteAllEvents()
308{
309 d->deleteAllIncidences(Incidence::TypeEvent);
310}
311
312Event::Ptr MemoryCalendar::event(const QString &uid,
313 const KDateTime &recurrenceId) const
314{
315 return d->incidence(uid, Incidence::TypeEvent, recurrenceId).staticCast<Event>();
316}
317
318Event::Ptr MemoryCalendar::deletedEvent(const QString &uid, const KDateTime &recurrenceId) const
319{
320 return d->deletedIncidence(uid, recurrenceId, Incidence::TypeEvent).staticCast<Event>();
321}
322
323bool MemoryCalendar::addTodo(const Todo::Ptr &todo)
324{
325 return addIncidence(todo);
326}
327
328bool MemoryCalendar::deleteTodo(const Todo::Ptr &todo)
329{
330 return deleteIncidence(todo);
331}
332
333bool MemoryCalendar::deleteTodoInstances(const Todo::Ptr &todo)
334{
335 return deleteIncidenceInstances(todo);
336}
337
338void MemoryCalendar::deleteAllTodos()
339{
340 d->deleteAllIncidences(Incidence::TypeTodo);
341}
342
343Todo::Ptr MemoryCalendar::todo(const QString &uid,
344 const KDateTime &recurrenceId) const
345{
346 return d->incidence(uid, Incidence::TypeTodo, recurrenceId).staticCast<Todo>();
347}
348
349Todo::Ptr MemoryCalendar::deletedTodo(const QString &uid,
350 const KDateTime &recurrenceId) const
351{
352 return d->deletedIncidence(uid, recurrenceId, Incidence::TypeTodo).staticCast<Todo>();
353}
354
355Todo::List MemoryCalendar::rawTodos(TodoSortField sortField,
356 SortDirection sortDirection) const
357{
358 Todo::List todoList;
359 QHashIterator<QString, Incidence::Ptr>i(d->mIncidences[Incidence::TypeTodo]);
360 while (i.hasNext()) {
361 i.next();
362 todoList.append(i.value().staticCast<Todo>());
363 }
364 return Calendar::sortTodos(todoList, sortField, sortDirection);
365}
366
367Todo::List MemoryCalendar::deletedTodos(TodoSortField sortField,
368 SortDirection sortDirection) const
369{
370 if (!deletionTracking()) {
371 return Todo::List();
372 }
373
374 Todo::List todoList;
375 QHashIterator<QString, Incidence::Ptr >i(d->mDeletedIncidences[Incidence::TypeTodo]);
376 while (i.hasNext()) {
377 i.next();
378 todoList.append(i.value().staticCast<Todo>());
379 }
380 return Calendar::sortTodos(todoList, sortField, sortDirection);
381}
382
383Todo::List MemoryCalendar::todoInstances(const Incidence::Ptr &todo,
384 TodoSortField sortField,
385 SortDirection sortDirection) const
386{
387 Todo::List list;
388
389 QList<Incidence::Ptr > values = d->mIncidences[Incidence::TypeTodo].values(todo->uid());
390 QList<Incidence::Ptr>::const_iterator it;
391 for (it = values.constBegin(); it != values.constEnd(); ++it) {
392 Todo::Ptr t = (*it).staticCast<Todo>();
393 if (t->hasRecurrenceId()) {
394 list.append(t);
395 }
396 }
397 return Calendar::sortTodos(list, sortField, sortDirection);
398}
399
400Todo::List MemoryCalendar::rawTodosForDate(const QDate &date) const
401{
402 Todo::List todoList;
403 Todo::Ptr t;
404
405 KDateTime::Spec ts = timeSpec();
406 const QString dateStr = date.toString();
407 QMultiHash<QString, IncidenceBase::Ptr >::const_iterator it =
408 d->mIncidencesForDate[Incidence::TypeTodo].constFind(dateStr);
409 while (it != d->mIncidencesForDate[Incidence::TypeTodo].constEnd() && it.key() == dateStr) {
410 t = it.value().staticCast<Todo>();
411 todoList.append(t);
412 ++it;
413 }
414
415 // Iterate over all todos. Look for recurring todoss that occur on this date
416 QHashIterator<QString, Incidence::Ptr >i(d->mIncidences[Incidence::TypeTodo]);
417 while (i.hasNext()) {
418 i.next();
419 t = i.value().staticCast<Todo>();
420 if (t->recurs()) {
421 if (t->recursOn(date, ts)) {
422 todoList.append(t);
423 }
424 }
425 }
426
427 return todoList;
428}
429
430Todo::List MemoryCalendar::rawTodos(const QDate &start,
431 const QDate &end,
432 const KDateTime::Spec &timespec,
433 bool inclusive) const
434{
435 Q_UNUSED(inclusive); // use only exact dtDue/dtStart, not dtStart and dtEnd
436
437 Todo::List todoList;
438 KDateTime::Spec ts = timespec.isValid() ? timespec : timeSpec();
439 KDateTime st(start, ts);
440 KDateTime nd(end, ts);
441
442 // Get todos
443 QHashIterator<QString, Incidence::Ptr >i(d->mIncidences[Incidence::TypeTodo]);
444 Todo::Ptr todo;
445 while (i.hasNext()) {
446 i.next();
447 todo = i.value().staticCast<Todo>();
448 if (!isVisible(todo)) {
449 continue;
450 }
451
452 KDateTime rStart = todo->hasDueDate() ? todo->dtDue() :
453 todo->hasStartDate() ? todo->dtStart() : KDateTime();
454 if (!rStart.isValid()) {
455 continue;
456 }
457
458 if (!todo->recurs()) { // non-recurring todos
459 if (nd.isValid() && nd < rStart) {
460 continue;
461 }
462 if (st.isValid() && rStart < st) {
463 continue;
464 }
465 } else { // recurring events
466 switch (todo->recurrence()->duration()) {
467 case -1: // infinite
468 break;
469 case 0: // end date given
470 default: // count given
471 KDateTime rEnd(todo->recurrence()->endDate(), ts);
472 if (!rEnd.isValid()) {
473 continue;
474 }
475 if (st.isValid() && rEnd < st) {
476 continue;
477 }
478 break;
479 } // switch(duration)
480 } //if(recurs)
481
482 todoList.append(todo);
483 }
484
485 return todoList;
486}
487
488Alarm::List MemoryCalendar::alarmsTo(const KDateTime &to) const
489{
490 return alarms(KDateTime(QDate(1900, 1, 1)), to);
491}
492
493Alarm::List MemoryCalendar::alarms(const KDateTime &from, const KDateTime &to) const
494{
495 Alarm::List alarmList;
496 QHashIterator<QString, Incidence::Ptr>ie(d->mIncidences[Incidence::TypeEvent]);
497 Event::Ptr e;
498 while (ie.hasNext()) {
499 ie.next();
500 e = ie.value().staticCast<Event>();
501 if (e->recurs()) {
502 appendRecurringAlarms(alarmList, e, from, to);
503 } else {
504 appendAlarms(alarmList, e, from, to);
505 }
506 }
507
508 QHashIterator<QString, Incidence::Ptr>it(d->mIncidences[Incidence::TypeTodo]);
509 Todo::Ptr t;
510 while (it.hasNext()) {
511 it.next();
512 t = it.value().staticCast<Todo>();
513
514 if (!t->isCompleted()) {
515 appendAlarms(alarmList, t, from, to);
516 if (t->recurs()) {
517 appendRecurringAlarms(alarmList, t, from, to);
518 } else {
519 appendAlarms(alarmList, t, from, to);
520 }
521 }
522 }
523
524 return alarmList;
525}
526
527void MemoryCalendar::incidenceUpdate(const QString &uid, const KDateTime &recurrenceId)
528{
529 Incidence::Ptr inc = incidence(uid, recurrenceId);
530
531 if (inc) {
532 if (!d->mIncidenceBeingUpdated.isEmpty()) {
533 kWarning() << "Incidence::update() called twice without an updated() call in between.";
534 }
535
536 // Save it so we can detect changes to uid or recurringId.
537 d->mIncidenceBeingUpdated = inc->instanceIdentifier();
538
539 const KDateTime dt = inc->dateTime(Incidence::RoleCalendarHashing);
540 if (dt.isValid()) {
541 const Incidence::IncidenceType type = inc->type();
542 d->mIncidencesForDate[type].remove(dt.date().toString(), inc);
543 }
544 }
545}
546
547void MemoryCalendar::incidenceUpdated(const QString &uid, const KDateTime &recurrenceId)
548{
549 Incidence::Ptr inc = incidence(uid, recurrenceId);
550
551 if (inc) {
552
553 if (d->mIncidenceBeingUpdated.isEmpty()) {
554 kWarning() << "Incidence::updated() called twice without an update() call in between.";
555 } else if (inc->instanceIdentifier() != d->mIncidenceBeingUpdated) {
556 // Instance identifier changed, update our hash table
557 d->mIncidencesByIdentifier.remove(d->mIncidenceBeingUpdated);
558 d->mIncidencesByIdentifier.insert(inc->instanceIdentifier(), inc);
559 }
560
561 d->mIncidenceBeingUpdated = QString();
562
563 inc->setLastModified(KDateTime::currentUtcDateTime());
564 // we should probably update the revision number here,
565 // or internally in the Event itself when certain things change.
566 // need to verify with ical documentation.
567
568 const KDateTime dt = inc->dateTime(Incidence::RoleCalendarHashing);
569 if (dt.isValid()) {
570 const Incidence::IncidenceType type = inc->type();
571 d->mIncidencesForDate[type].insert(dt.date().toString(), inc);
572 }
573
574 notifyIncidenceChanged(inc);
575
576 setModified(true);
577 }
578}
579
580Event::List MemoryCalendar::rawEventsForDate(const QDate &date,
581 const KDateTime::Spec &timespec,
582 EventSortField sortField,
583 SortDirection sortDirection) const
584{
585 Event::List eventList;
586
587 if (!date.isValid()) {
588 // There can't be events on invalid dates
589 return eventList;
590 }
591
592 Event::Ptr ev;
593
594 // Find the hash for the specified date
595 const QString dateStr = date.toString();
596 QMultiHash<QString, IncidenceBase::Ptr >::const_iterator it =
597 d->mIncidencesForDate[Incidence::TypeEvent].constFind(dateStr);
598 // Iterate over all non-recurring, single-day events that start on this date
599 KDateTime::Spec ts = timespec.isValid() ? timespec : timeSpec();
600 KDateTime kdt(date, ts);
601 while (it != d->mIncidencesForDate[Incidence::TypeEvent].constEnd() && it.key() == dateStr) {
602 ev = it.value().staticCast<Event>();
603 KDateTime end(ev->dtEnd().toTimeSpec(ev->dtStart()));
604 if (ev->allDay()) {
605 end.setDateOnly(true);
606 } else {
607 end = end.addSecs(-1);
608 }
609 if (end >= kdt) {
610 eventList.append(ev);
611 }
612 ++it;
613 }
614
615 // Iterate over all events. Look for recurring events that occur on this date
616 QHashIterator<QString, Incidence::Ptr>i(d->mIncidences[Incidence::TypeEvent]);
617 while (i.hasNext()) {
618 i.next();
619 ev = i.value().staticCast<Event>();
620 if (ev->recurs()) {
621 if (ev->isMultiDay()) {
622 int extraDays = ev->dtStart().date().daysTo(ev->dtEnd().date());
623 for (int i = 0; i <= extraDays; ++i) {
624 if (ev->recursOn(date.addDays(-i), ts)) {
625 eventList.append(ev);
626 break;
627 }
628 }
629 } else {
630 if (ev->recursOn(date, ts)) {
631 eventList.append(ev);
632 }
633 }
634 } else {
635 if (ev->isMultiDay()) {
636 if (ev->dtStart().date() <= date && ev->dtEnd().date() >= date) {
637 eventList.append(ev);
638 }
639 }
640 }
641 }
642
643 return Calendar::sortEvents(eventList, sortField, sortDirection);
644}
645
646Event::List MemoryCalendar::rawEvents(const QDate &start,
647 const QDate &end,
648 const KDateTime::Spec &timespec,
649 bool inclusive) const
650{
651 Event::List eventList;
652 KDateTime::Spec ts = timespec.isValid() ? timespec : timeSpec();
653 KDateTime st(start, ts);
654 KDateTime nd(end, ts);
655 KDateTime yesterStart = st.addDays(-1);
656
657 // Get non-recurring events
658 QHashIterator<QString, Incidence::Ptr>i(d->mIncidences[Incidence::TypeEvent]);
659 Event::Ptr event;
660 while (i.hasNext()) {
661 i.next();
662 event = i.value().staticCast<Event>();
663 KDateTime rStart = event->dtStart();
664 if (nd < rStart) {
665 continue;
666 }
667 if (inclusive && rStart < st) {
668 continue;
669 }
670
671 if (!event->recurs()) { // non-recurring events
672 KDateTime rEnd = event->dtEnd();
673 if (rEnd < st) {
674 continue;
675 }
676 if (inclusive && nd < rEnd) {
677 continue;
678 }
679 } else { // recurring events
680 switch (event->recurrence()->duration()) {
681 case -1: // infinite
682 if (inclusive) {
683 continue;
684 }
685 break;
686 case 0: // end date given
687 default: // count given
688 KDateTime rEnd(event->recurrence()->endDate(), ts);
689 if (!rEnd.isValid()) {
690 continue;
691 }
692 if (rEnd < st) {
693 continue;
694 }
695 if (inclusive && nd < rEnd) {
696 continue;
697 }
698 break;
699 } // switch(duration)
700 } //if(recurs)
701
702 eventList.append(event);
703 }
704
705 return eventList;
706}
707
708Event::List MemoryCalendar::rawEventsForDate(const KDateTime &kdt) const
709{
710 return rawEventsForDate(kdt.date(), kdt.timeSpec());
711}
712
713Event::List MemoryCalendar::rawEvents(EventSortField sortField,
714 SortDirection sortDirection) const
715{
716 Event::List eventList;
717 QHashIterator<QString, Incidence::Ptr> i(d->mIncidences[Incidence::TypeEvent]);
718 while (i.hasNext()) {
719 i.next();
720 eventList.append(i.value().staticCast<Event>());
721 }
722 return Calendar::sortEvents(eventList, sortField, sortDirection);
723}
724
725Event::List MemoryCalendar::deletedEvents(EventSortField sortField,
726 SortDirection sortDirection) const
727{
728 if (!deletionTracking()) {
729 return Event::List();
730 }
731
732 Event::List eventList;
733 QHashIterator<QString, Incidence::Ptr>i(d->mDeletedIncidences[Incidence::TypeEvent]);
734 while (i.hasNext()) {
735 i.next();
736 eventList.append(i.value().staticCast<Event>());
737 }
738 return Calendar::sortEvents(eventList, sortField, sortDirection);
739}
740
741Event::List MemoryCalendar::eventInstances(const Incidence::Ptr &event,
742 EventSortField sortField,
743 SortDirection sortDirection) const
744{
745 Event::List list;
746
747 QList<Incidence::Ptr> values = d->mIncidences[Incidence::TypeEvent].values(event->uid());
748 QList<Incidence::Ptr>::const_iterator it;
749 for (it = values.constBegin(); it != values.constEnd(); ++it) {
750 Event::Ptr ev = (*it).staticCast<Event>();
751 if (ev->hasRecurrenceId()) {
752 list.append(ev);
753 }
754 }
755 return Calendar::sortEvents(list, sortField, sortDirection);
756}
757
758bool MemoryCalendar::addJournal(const Journal::Ptr &journal)
759{
760 return addIncidence(journal);
761}
762
763bool MemoryCalendar::deleteJournal(const Journal::Ptr &journal)
764{
765 return deleteIncidence(journal);
766}
767
768bool MemoryCalendar::deleteJournalInstances(const Journal::Ptr &journal)
769{
770 return deleteIncidenceInstances(journal);
771}
772
773void MemoryCalendar::deleteAllJournals()
774{
775 d->deleteAllIncidences(Incidence::TypeJournal);
776}
777
778Journal::Ptr MemoryCalendar::journal(const QString &uid,
779 const KDateTime &recurrenceId) const
780{
781 return d->incidence(uid, Incidence::TypeJournal, recurrenceId).staticCast<Journal>();
782}
783
784Journal::Ptr MemoryCalendar::deletedJournal(const QString &uid,
785 const KDateTime &recurrenceId) const
786{
787 return d->deletedIncidence(uid, recurrenceId, Incidence::TypeJournal).staticCast<Journal>();
788}
789
790Journal::List MemoryCalendar::rawJournals(JournalSortField sortField,
791 SortDirection sortDirection) const
792{
793 Journal::List journalList;
794 QHashIterator<QString, Incidence::Ptr>i(d->mIncidences[Incidence::TypeJournal]);
795 while (i.hasNext()) {
796 i.next();
797 journalList.append(i.value().staticCast<Journal>());
798 }
799 return Calendar::sortJournals(journalList, sortField, sortDirection);
800}
801
802Journal::List MemoryCalendar::deletedJournals(JournalSortField sortField,
803 SortDirection sortDirection) const
804{
805 if (!deletionTracking()) {
806 return Journal::List();
807 }
808
809 Journal::List journalList;
810 QHashIterator<QString, Incidence::Ptr>i(d->mDeletedIncidences[Incidence::TypeJournal]);
811 while (i.hasNext()) {
812 i.next();
813 journalList.append(i.value().staticCast<Journal>());
814 }
815 return Calendar::sortJournals(journalList, sortField, sortDirection);
816}
817
818Journal::List MemoryCalendar::journalInstances(const Incidence::Ptr &journal,
819 JournalSortField sortField,
820 SortDirection sortDirection) const
821{
822 Journal::List list;
823
824 QList<Incidence::Ptr> values = d->mIncidences[Incidence::TypeJournal].values(journal->uid());
825 QList<Incidence::Ptr>::const_iterator it;
826 for (it = values.constBegin(); it != values.constEnd(); ++it) {
827 Journal::Ptr j = (*it).staticCast<Journal>();
828 if (j->hasRecurrenceId()) {
829 list.append(j);
830 }
831 }
832 return Calendar::sortJournals(list, sortField, sortDirection);
833}
834
835Journal::List MemoryCalendar::rawJournalsForDate(const QDate &date) const
836{
837 Journal::List journalList;
838 Journal::Ptr j;
839
840 QString dateStr = date.toString();
841 QMultiHash<QString, IncidenceBase::Ptr >::const_iterator it =
842 d->mIncidencesForDate[Incidence::TypeJournal].constFind(dateStr);
843
844 while (it != d->mIncidencesForDate[Incidence::TypeJournal].constEnd() && it.key() == dateStr) {
845 j = it.value().staticCast<Journal>();
846 journalList.append(j);
847 ++it;
848 }
849 return journalList;
850}
851
852Incidence::Ptr MemoryCalendar::instance(const QString &identifier) const
853{
854 return d->mIncidencesByIdentifier.value(identifier);
855}
856
857void MemoryCalendar::virtual_hook(int id, void *data)
858{
859 Q_UNUSED(id);
860 Q_UNUSED(data);
861 Q_ASSERT(false);
862}
863