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 <[email protected]>
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 <[email protected]>
17  */
18 
19 #include "occurrenceiterator.h"
20 #include "calendar.h"
21 #include "calfilter.h"
22 
23 #include <QDate>
24 
25 using namespace KCalendarCore;
26 
27 /**
28  Private class that helps to provide binary compatibility between releases.
29  @internal
30 */
31 //@cond PRIVATE
32 class Q_DECL_HIDDEN KCalendarCore::OccurrenceIterator::Private
33 {
34 public:
35  Private(OccurrenceIterator *qq)
36  : q(qq)
37  , occurrenceIt(occurrenceList)
38  {
39  }
40 
42  QDateTime start;
43  QDateTime end;
44 
45  struct Occurrence {
46  Occurrence()
47  {
48  }
49 
50  Occurrence(const Incidence::Ptr &i, const QDateTime &recurrenceId, const QDateTime &startDate)
51  : incidence(i)
52  , recurrenceId(recurrenceId)
53  , startDate(startDate)
54  {
55  }
56 
57  Incidence::Ptr incidence;
58  QDateTime recurrenceId;
59  QDateTime startDate;
60  };
61  QList<Occurrence> occurrenceList;
62  QListIterator<Occurrence> occurrenceIt;
63  Occurrence current;
64 
65  /*
66  * KCalendarCore::CalFilter can't handle individual occurrences.
67  * When filtering completed to-dos, the CalFilter doesn't hide
68  * them if it's a recurring to-do.
69  */
70  bool occurrenceIsHidden(const Calendar &calendar, const Incidence::Ptr &inc, const QDateTime &occurrenceDate)
71  {
72  if ((inc->type() == Incidence::TypeTodo) && calendar.filter() && (calendar.filter()->criteria() & KCalendarCore::CalFilter::HideCompletedTodos)) {
73  if (inc->recurs()) {
74  const Todo::Ptr todo = inc.staticCast<Todo>();
75  if (todo && (occurrenceDate < todo->dtDue())) {
76  return true;
77  }
78  } else if (inc->hasRecurrenceId()) {
79  const Todo::Ptr mainTodo = calendar.todo(inc->uid());
80  if (mainTodo && mainTodo->isCompleted()) {
81  return true;
82  }
83  }
84  }
85  return false;
86  }
87 
88  void setupIterator(const Calendar &calendar, const Incidence::List &incidences)
89  {
90  for (const Incidence::Ptr &inc : qAsConst(incidences)) {
91  if (inc->hasRecurrenceId()) {
92  continue;
93  }
94  if (inc->recurs()) {
96  QDateTime incidenceRecStart = inc->dateTime(Incidence::RoleRecurrenceStart);
97  // const bool isAllDay = inc->allDay();
98  const auto lstInstances = calendar.instances(inc);
99  for (const Incidence::Ptr &exception : lstInstances) {
100  if (incidenceRecStart.isValid()) {
101  recurrenceIds.insert(exception->recurrenceId().toTimeZone(incidenceRecStart.timeZone()), exception);
102  }
103  }
104  const auto occurrences = inc->recurrence()->timesInInterval(start, end);
105  Incidence::Ptr incidence(inc), lastInc(inc);
106  qint64 offset(0), lastOffset(0);
107  QDateTime occurrenceStartDate;
108  for (const auto &recurrenceId : qAsConst(occurrences)) {
109  occurrenceStartDate = recurrenceId;
110 
111  bool resetIncidence = false;
112  if (recurrenceIds.contains(recurrenceId)) {
113  // TODO: exclude exceptions where the start/end is not within
114  // (so the occurrence of the recurrence is omitted, but no exception is added)
115  if (recurrenceIds.value(recurrenceId)->status() == Incidence::StatusCanceled) {
116  continue;
117  }
118 
119  incidence = recurrenceIds.value(recurrenceId);
120  occurrenceStartDate = incidence->dtStart();
121  resetIncidence = !incidence->thisAndFuture();
122  offset = incidence->recurrenceId().secsTo(incidence->dtStart());
123  if (incidence->thisAndFuture()) {
124  lastInc = incidence;
125  lastOffset = offset;
126  }
127  } else if (inc != incidence) { // thisAndFuture exception is active
128  occurrenceStartDate = occurrenceStartDate.addSecs(offset);
129  }
130 
131  if (!occurrenceIsHidden(calendar, incidence, occurrenceStartDate)) {
132  occurrenceList << Private::Occurrence(incidence, recurrenceId, occurrenceStartDate);
133  }
134 
135  if (resetIncidence) {
136  incidence = lastInc;
137  offset = lastOffset;
138  }
139  }
140  } else {
141  occurrenceList << Private::Occurrence(inc, {}, inc->dtStart());
142  }
143  }
144  occurrenceIt = QListIterator<Private::Occurrence>(occurrenceList);
145  }
146 };
147 //@endcond
148 
149 /**
150  * Right now there is little point in the iterator, but:
151  * With an iterator it should be possible to solve this more memory efficiently
152  * and with immediate results at the beginning of the selected timeframe.
153  * Either all events are iterated simoulatneously, resulting in occurrences
154  * of all events in parallel in the correct time-order, or incidence after
155  * incidence, which would be even more efficient.
156  *
157  * By making this class a friend of calendar, we could also use the internally
158  * available data structures.
159  */
160 OccurrenceIterator::OccurrenceIterator(const Calendar &calendar, const QDateTime &start, const QDateTime &end)
161  : d(new KCalendarCore::OccurrenceIterator::Private(this))
162 {
163  d->start = start;
164  d->end = end;
165 
166  Event::List events = calendar.rawEvents(start.date(), end.date(), start.timeZone());
167  if (calendar.filter()) {
168  calendar.filter()->apply(&events);
169  }
170 
171  Todo::List todos = calendar.rawTodos(start.date(), end.date(), start.timeZone());
172  if (calendar.filter()) {
173  calendar.filter()->apply(&todos);
174  }
175 
176  Journal::List journals;
177  const Journal::List allJournals = calendar.rawJournals();
178  for (const KCalendarCore::Journal::Ptr &journal : allJournals) {
179  const QDate journalStart = journal->dtStart().toTimeZone(start.timeZone()).date();
180  if (journal->dtStart().isValid() && journalStart >= start.date() && journalStart <= end.date()) {
181  journals << journal;
182  }
183  }
184 
185  if (calendar.filter()) {
186  calendar.filter()->apply(&journals);
187  }
188 
189  const Incidence::List incidences = KCalendarCore::Calendar::mergeIncidenceList(events, todos, journals);
190  d->setupIterator(calendar, incidences);
191 }
192 
194  : d(new KCalendarCore::OccurrenceIterator::Private(this))
195 {
196  Q_ASSERT(incidence);
197  d->start = start;
198  d->end = end;
199  d->setupIterator(calendar, Incidence::List() << incidence);
200 }
201 
202 OccurrenceIterator::~OccurrenceIterator()
203 {
204 }
205 
206 bool OccurrenceIterator::hasNext() const
207 {
208  return d->occurrenceIt.hasNext();
209 }
210 
212 {
213  d->current = d->occurrenceIt.next();
214 }
215 
217 {
218  return d->current.incidence;
219 }
220 
222 {
223  return d->current.startDate;
224 }
225 
227 {
228  return d->current.recurrenceId;
229 }
int criteria() const
Returns the inclusive filter criteria.
Definition: calfilter.cpp:212
QHash::iterator insert(const Key &key, const T &value)
QDateTime recurrenceId() const
Returns the recurrence Id.
Represents the main calendar class.
Definition: calendar.h:118
This file is part of the API for handling calendar data and defines the OccurrenceIterator class...
CalFilter * filter() const
Returns the calendar filter.
Definition: calendar.cpp:247
virtual Todo::Ptr todo(const QString &uid, const QDateTime &recurrenceId={}) const =0
Returns the Todo associated with the given unique identifier.
OccurrenceIterator(const Calendar &calendar, const QDateTime &start=QDateTime(), const QDateTime &end=QDateTime())
Creates iterator that iterates over all occurrences of all incidences between.
virtual Todo::List rawTodos(TodoSortField sortField=TodoSortUnsorted, SortDirection sortDirection=SortDirectionAscending) const =0
Returns a sorted, unfiltered list of all Todos for this Calendar.
Role for determining the start of the recurrence.
Incidence::Ptr incidence() const
Returns either main incidence or exception, depending on occurrence.
This file is part of the API for handling calendar data and defines the Calendar class.
QDateTime occurrenceStartDate() const
Returns the start date of the occurrence.
Provides a To-do in the sense of RFC2445.
Definition: todo.h:30
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:1159
void apply(Event::List *eventList) const
Applies the filter to a list of Events.
Definition: calfilter.cpp:69
const T value(const Key &key) const const
bool isValid() const const
const QList< QKeySequence > & end()
Iterate over calendar items in a calendar.
QDate date() const const
event or to-do canceled; journal removed
Definition: incidence.h:83
qint64 secsTo(const QDateTime &other) const const
virtual Incidence::List instances(const Incidence::Ptr &incidence) const
Returns an unfiltered list of all exceptions of this recurring incidence.
Definition: calendar.cpp:284
bool contains(const Key &key) const const
virtual Event::List rawEvents(EventSortField sortField=EventSortUnsorted, SortDirection sortDirection=SortDirectionAscending) const =0
Returns a sorted, unfiltered list of all Events for this Calendar.
This file is part of the API for handling calendar data and defines the CalFilter class...
QDateTime addSecs(qint64 s) const const
QSharedPointer< X > staticCast() const const
virtual Journal::List rawJournals(JournalSortField sortField=JournalSortUnsorted, SortDirection sortDirection=SortDirectionAscending) const =0
Returns a sorted, unfiltered list of all Journals for this Calendar.
void next()
Advance iterator to the next occurrence.
Namespace for all KCalendarCore types.
Definition: alarm.h:36
QTimeZone timeZone() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Apr 10 2021 22:50:59 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.