KCalendarCore

occurrenceiterator.cpp
Go to the documentation of this file.
1/*
2 This file is part of the kcalcore library.
3
4 SPDX-FileCopyrightText: 2013 Christian Mollekopf <mollekopf@kolabsys.com>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7*/
8/**
9 @file
10 This file is part of the API for handling calendar data and
11 defines the OccurrenceIterator class.
12
13 @brief
14 This class provides an iterator to iterate over all occurrences of incidences.
15
16 @author Christian Mollekopf <mollekopf@kolabsys.com>
17 */
18
19#include "occurrenceiterator.h"
20#include "calendar.h"
21#include "calfilter.h"
22
23#include <QDate>
24
25using namespace KCalendarCore;
26
27/**
28 Private class that helps to provide binary compatibility between releases.
29 @internal
30*/
31//@cond PRIVATE
32class Q_DECL_HIDDEN KCalendarCore::OccurrenceIterator::Private
33{
34public:
35 Private(OccurrenceIterator *qq)
36 : q(qq)
37 , occurrenceIt(occurrenceList)
38 {
39 }
40
44
45 struct Occurrence {
46 Occurrence()
47 {
48 }
49
50 Occurrence(const Incidence::Ptr &i, const QDateTime &recurrenceId,
51 const QDateTime &startDate, const QDateTime &endDate)
52 : incidence(i)
53 , recurrenceId(recurrenceId)
54 , startDate(startDate)
55 , endDate(endDate)
56 {
57 }
58
60 QDateTime recurrenceId;
61 QDateTime startDate;
62 QDateTime endDate;
63 };
64 QList<Occurrence> occurrenceList;
65 QListIterator<Occurrence> occurrenceIt;
66 Occurrence current;
67
68 /*
69 * KCalendarCore::CalFilter can't handle individual occurrences.
70 * When filtering completed to-dos, the CalFilter doesn't hide
71 * them if it's a recurring to-do.
72 */
73 bool occurrenceIsHidden(const Calendar &calendar, const Incidence::Ptr &inc, const QDateTime &occurrenceDate)
74 {
75 if ((inc->type() == Incidence::TypeTodo) && calendar.filter() && (calendar.filter()->criteria() & KCalendarCore::CalFilter::HideCompletedTodos)) {
76 if (inc->recurs()) {
77 const Todo::Ptr todo = inc.staticCast<Todo>();
78 if (todo && (occurrenceDate < todo->dtDue())) {
79 return true;
80 }
81 } else if (inc->hasRecurrenceId()) {
82 const Todo::Ptr mainTodo = calendar.todo(inc->uid());
83 if (mainTodo && mainTodo->isCompleted()) {
84 return true;
85 }
86 }
87 }
88 return false;
89 }
90
91 QDateTime occurrenceEnd(const Incidence::Ptr &inc, const QDateTime &start)
92 {
93 if (inc->hasDuration()) {
94 return inc->duration().end(start);
95 } else {
96 const QDateTime end = inc->dateTime(Incidence::RoleEnd);
97 if (end.isValid()) {
98 const Duration elapsed(inc->dtStart(), end, Duration::Seconds);
99 return elapsed.end(start);
100 }
101 }
102 return QDateTime();
103 }
104
105 void setupIterator(const Calendar &calendar, const Incidence::List &incidences)
106 {
107 for (const Incidence::Ptr &inc : std::as_const(incidences)) {
108 if (inc->hasRecurrenceId()) {
109 continue;
110 }
111 if (inc->recurs()) {
113 QDateTime incidenceRecStart = inc->dateTime(Incidence::RoleRecurrenceStart);
114 // const bool isAllDay = inc->allDay();
115 const auto lstInstances = calendar.instances(inc);
116 for (const Incidence::Ptr &exception : lstInstances) {
117 if (incidenceRecStart.isValid()) {
118 recurrenceIds.insert(exception->recurrenceId().toTimeZone(incidenceRecStart.timeZone()), exception);
119 }
120 }
121 const auto occurrences = inc->recurrence()->timesInInterval(start, end);
123 Incidence::Ptr lastInc(inc);
124 qint64 offset(0);
125 qint64 lastOffset(0);
126 QDateTime occurrenceStartDate;
127 for (const auto &recurrenceId : std::as_const(occurrences)) {
128 occurrenceStartDate = recurrenceId;
129
130 bool resetIncidence = false;
131 if (recurrenceIds.contains(recurrenceId)) {
132 // TODO: exclude exceptions where the start/end is not within
133 // (so the occurrence of the recurrence is omitted, but no exception is added)
134 incidence = recurrenceIds.value(recurrenceId);
135 occurrenceStartDate = incidence->dtStart();
136 resetIncidence = !incidence->thisAndFuture();
137 offset = incidence->recurrenceId().secsTo(incidence->dtStart());
138 if (incidence->thisAndFuture()) {
139 lastInc = incidence;
140 lastOffset = offset;
141 }
142 } else if (inc != incidence) { // thisAndFuture exception is active
143 occurrenceStartDate = occurrenceStartDate.addSecs(offset);
144 }
145
146 if (!occurrenceIsHidden(calendar, incidence, occurrenceStartDate)) {
147 const Period period = inc->recurrence()->rDateTimePeriod(occurrenceStartDate);
148 if (period.isValid()) {
149 occurrenceList << Private::Occurrence(incidence, recurrenceId, occurrenceStartDate, period.end());
150 } else {
151 occurrenceList << Private::Occurrence(incidence, recurrenceId, occurrenceStartDate, occurrenceEnd(incidence, occurrenceStartDate));
152 }
153 }
154
155 if (resetIncidence) {
156 incidence = lastInc;
157 offset = lastOffset;
158 }
159 }
160 } else {
161 occurrenceList << Private::Occurrence(inc, {}, inc->dtStart(),
162 inc->dateTime(Incidence::RoleEnd));
163 }
164 }
165 occurrenceIt = QListIterator<Private::Occurrence>(occurrenceList);
166 }
167};
168//@endcond
169
170/**
171 * Right now there is little point in the iterator, but:
172 * With an iterator it should be possible to solve this more memory efficiently
173 * and with immediate results at the beginning of the selected timeframe.
174 * Either all events are iterated simoulatneously, resulting in occurrences
175 * of all events in parallel in the correct time-order, or incidence after
176 * incidence, which would be even more efficient.
177 *
178 * By making this class a friend of calendar, we could also use the internally
179 * available data structures.
180 */
182 : d(new KCalendarCore::OccurrenceIterator::Private(this))
183{
184 d->start = start;
185 d->end = end;
186
187 Event::List events = calendar.rawEvents(start.date(), end.date(), start.timeZone());
188 if (calendar.filter()) {
189 calendar.filter()->apply(&events);
190 }
191
192 Todo::List todos = calendar.rawTodos(start.date(), end.date(), start.timeZone());
193 if (calendar.filter()) {
194 calendar.filter()->apply(&todos);
195 }
196
197 Journal::List journals;
198 const Journal::List allJournals = calendar.rawJournals();
199 for (const KCalendarCore::Journal::Ptr &journal : allJournals) {
200 const QDate journalStart = journal->dtStart().toTimeZone(start.timeZone()).date();
201 if (journal->dtStart().isValid() && journalStart >= start.date() && journalStart <= end.date()) {
202 journals << journal;
203 }
204 }
205
206 if (calendar.filter()) {
207 calendar.filter()->apply(&journals);
208 }
209
210 const Incidence::List incidences = KCalendarCore::Calendar::mergeIncidenceList(events, todos, journals);
211 d->setupIterator(calendar, incidences);
212}
213
214OccurrenceIterator::OccurrenceIterator(const Calendar &calendar, const Incidence::Ptr &incidence, const QDateTime &start, const QDateTime &end)
215 : d(new KCalendarCore::OccurrenceIterator::Private(this))
216{
217 Q_ASSERT(incidence);
218 d->start = start;
219 d->end = end;
220 d->setupIterator(calendar, Incidence::List() << incidence);
221}
222
223OccurrenceIterator::~OccurrenceIterator()
224{
225}
226
227bool OccurrenceIterator::hasNext() const
228{
229 return d->occurrenceIt.hasNext();
230}
231
233{
234 d->current = d->occurrenceIt.next();
235}
236
238{
239 return d->current.incidence;
240}
241
243{
244 return d->current.startDate;
245}
246
248{
249 return d->current.endDate;
250}
251
253{
254 return d->current.recurrenceId;
255}
This file is part of the API for handling calendar data and defines the Calendar class.
This file is part of the API for handling calendar data and defines the CalFilter class.
int criteria() const
Returns the inclusive filter criteria.
@ HideCompletedTodos
Remove completed to-dos.
Definition calfilter.h:50
Represents the main calendar class.
Definition calendar.h:133
CalFilter * filter() const
Returns the calendar filter.
Definition calendar.cpp:226
static Incidence::List mergeIncidenceList(const Event::List &events, const Todo::List &todos, const Journal::List &journals)
Create a merged list of Events, Todos, and Journals.
Definition calendar.cpp:769
virtual Incidence::List instances(const Incidence::Ptr &incidence) const
Returns an unfiltered list of all exceptions of this recurring incidence.
Definition calendar.cpp:264
virtual Journal::List rawJournals(JournalSortField sortField=JournalSortUnsorted, SortDirection sortDirection=SortDirectionAscending) const =0
Returns a sorted, unfiltered list of all Journals for this Calendar.
virtual Todo::Ptr todo(const QString &uid, const QDateTime &recurrenceId={}) const =0
Returns the Todo associated with the given unique identifier.
virtual Event::List rawEvents(EventSortField sortField=EventSortUnsorted, SortDirection sortDirection=SortDirectionAscending) const =0
Returns a sorted, unfiltered list of all Events for this Calendar.
virtual Todo::List rawTodos(TodoSortField sortField=TodoSortUnsorted, SortDirection sortDirection=SortDirectionAscending) const =0
Returns a sorted, unfiltered list of all Todos for this Calendar.
Represents a span of time measured in seconds or days.
Definition duration.h:44
@ Seconds
duration is a number of seconds
Definition duration.h:50
Iterate over calendar items in a calendar.
QDateTime recurrenceId() const
Returns the recurrence Id.
Incidence::Ptr incidence() const
Returns either main incidence or exception, depending on occurrence.
OccurrenceIterator(const Calendar &calendar, const QDateTime &start=QDateTime(), const QDateTime &end=QDateTime())
Creates iterator that iterates over all occurrences of all incidences between.
QDateTime occurrenceStartDate() const
Returns the start date of the occurrence.
QDateTime occurrenceEndDate() const
Returns the end date of the occurrence.
void next()
Advance iterator to the next occurrence.
The period can be defined by either a start time and an end time or by a start time and a duration.
Definition period.h:38
QDateTime end() const
Returns when this period ends.
Definition period.cpp:110
bool isValid() const
Returns true if the Period is not empty.
Definition period.cpp:100
Provides a To-do in the sense of RFC2445.
Definition todo.h:34
Q_SCRIPTABLE Q_NOREPLY void start()
AKONADI_CALENDAR_EXPORT KCalendarCore::Incidence::Ptr incidence(const Akonadi::Item &item)
AKONADI_CALENDAR_EXPORT KCalendarCore::Todo::Ptr todo(const Akonadi::Item &item)
Namespace for all KCalendarCore types.
Definition alarm.h:37
QAction * end(const QObject *recvr, const char *slot, QObject *parent)
This file is part of the API for handling calendar data and defines the OccurrenceIterator class.
QDateTime addSecs(qint64 s) const const
bool isValid() const const
QTimeZone timeZone() const const
bool contains(const Key &key) const const
iterator insert(const Key &key, const T &value)
T value(const Key &key) const const
QSharedPointer< X > staticCast() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Nov 22 2024 12:07:48 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.