KCalendarCore

recurrence.cpp
1 /*
2  This file is part of kcalcore library.
3 
4  SPDX-FileCopyrightText: 1998 Preston Brown <[email protected]>
5  SPDX-FileCopyrightText: 2001 Cornelius Schumacher <[email protected]>
6  SPDX-FileCopyrightText: 2002, 2006 David Jarvie <[email protected]>
7  SPDX-FileCopyrightText: 2005 Reinhold Kainhofer <[email protected]>
8 
9  SPDX-License-Identifier: LGPL-2.0-or-later
10 */
11 #include "recurrence.h"
12 #include "utils_p.h"
13 #include "recurrencehelper_p.h"
14 
15 #include "kcalendarcore_debug.h"
16 
17 #include <QDataStream>
18 #include <QTimeZone>
19 #include <QBitArray>
20 #include <QTime>
21 
22 using namespace KCalendarCore;
23 
24 //@cond PRIVATE
25 class Q_DECL_HIDDEN KCalendarCore::Recurrence::Private
26 {
27 public:
28  Private()
29  : mCachedType(rMax),
30  mAllDay(false),
31  mRecurReadOnly(false)
32  {
33  }
34 
35  Private(const Private &p)
36  : mRDateTimes(p.mRDateTimes),
37  mRDates(p.mRDates),
38  mExDateTimes(p.mExDateTimes),
39  mExDates(p.mExDates),
40  mStartDateTime(p.mStartDateTime),
41  mCachedType(p.mCachedType),
42  mAllDay(p.mAllDay),
43  mRecurReadOnly(p.mRecurReadOnly)
44  {
45  }
46 
47  bool operator==(const Private &p) const;
48 
49  RecurrenceRule::List mExRules;
50  RecurrenceRule::List mRRules;
51  QList<QDateTime> mRDateTimes;
52  DateList mRDates;
53  QList<QDateTime> mExDateTimes;
54  DateList mExDates;
55  QDateTime mStartDateTime; // date/time of first recurrence
56  QList<RecurrenceObserver *> mObservers;
57 
58  // Cache the type of the recurrence with the old system (e.g. MonthlyPos)
59  mutable ushort mCachedType;
60 
61  bool mAllDay = false; // the recurrence has no time, just a date
62  bool mRecurReadOnly = false;
63 };
64 
65 bool Recurrence::Private::operator==(const Recurrence::Private &p) const
66 {
67 // qCDebug(KCALCORE_LOG) << mStartDateTime << p.mStartDateTime;
68  if ((mStartDateTime != p.mStartDateTime &&
69  (mStartDateTime.isValid() || p.mStartDateTime.isValid())) ||
70  mAllDay != p.mAllDay ||
71  mRecurReadOnly != p.mRecurReadOnly ||
72  mExDates != p.mExDates ||
73  mExDateTimes != p.mExDateTimes ||
74  mRDates != p.mRDates ||
75  mRDateTimes != p.mRDateTimes) {
76  return false;
77  }
78 
79 // Compare the rrules, exrules! Assume they have the same order... This only
80 // matters if we have more than one rule (which shouldn't be the default anyway)
81  int i;
82  int end = mRRules.count();
83  if (end != p.mRRules.count()) {
84  return false;
85  }
86  for (i = 0; i < end; ++i) {
87  if (*mRRules[i] != *p.mRRules[i]) {
88  return false;
89  }
90  }
91  end = mExRules.count();
92  if (end != p.mExRules.count()) {
93  return false;
94  }
95  for (i = 0; i < end; ++i) {
96  if (*mExRules[i] != *p.mExRules[i]) {
97  return false;
98  }
99  }
100  return true;
101 }
102 //@endcond
103 
105  : d(new KCalendarCore::Recurrence::Private())
106 {
107 }
108 
110  : RecurrenceRule::RuleObserver(),
111  d(new KCalendarCore::Recurrence::Private(*r.d))
112 {
113  int i, end;
114  d->mRRules.reserve(r.d->mRRules.count());
115  for (i = 0, end = r.d->mRRules.count(); i < end; ++i) {
116  RecurrenceRule *rule = new RecurrenceRule(*r.d->mRRules[i]);
117  d->mRRules.append(rule);
118  rule->addObserver(this);
119  }
120  d->mExRules.reserve(r.d->mExRules.count());
121  for (i = 0, end = r.d->mExRules.count(); i < end; ++i) {
122  RecurrenceRule *rule = new RecurrenceRule(*r.d->mExRules[i]);
123  d->mExRules.append(rule);
124  rule->addObserver(this);
125  }
126 }
127 
129 {
130  qDeleteAll(d->mExRules);
131  qDeleteAll(d->mRRules);
132  delete d;
133 }
134 
135 bool Recurrence::operator==(const Recurrence &recurrence) const
136 {
137  return *d == *recurrence.d;
138 }
139 
140 #if KCALENDARCORE_BUILD_DEPRECATED_SINCE(5, 64)
142 {
143  // check for self assignment
144  if (&recurrence == this) {
145  return *this;
146  }
147 
148  // ### this copies the pointers in mExRules and mRRules eventually resulting in a double free!
149  // fortunately however this function is unused, we just can't remove it just yet, due to ABI guarantees
150 QT_WARNING_PUSH
151 QT_WARNING_DISABLE_GCC("-Wdeprecated-copy")
152  *d = *recurrence.d;
153 QT_WARNING_POP
154  return *this;
155 }
156 #endif
157 
158 void Recurrence::addObserver(RecurrenceObserver *observer)
159 {
160  if (!d->mObservers.contains(observer)) {
161  d->mObservers.append(observer);
162  }
163 }
164 
165 void Recurrence::removeObserver(RecurrenceObserver *observer)
166 {
167  d->mObservers.removeAll(observer);
168 }
169 
171 {
172  return d->mStartDateTime;
173 }
174 
175 bool Recurrence::allDay() const
176 {
177  return d->mAllDay;
178 }
179 
181 {
182  if (d->mRecurReadOnly || allDay == d->mAllDay) {
183  return;
184  }
185 
186  d->mAllDay = allDay;
187  for (int i = 0, end = d->mRRules.count(); i < end; ++i) {
188  d->mRRules[i]->setAllDay(allDay);
189  }
190  for (int i = 0, end = d->mExRules.count(); i < end; ++i) {
191  d->mExRules[i]->setAllDay(allDay);
192  }
193  updated();
194 }
195 
196 RecurrenceRule *Recurrence::defaultRRule(bool create) const
197 {
198  if (d->mRRules.isEmpty()) {
199  if (!create || d->mRecurReadOnly) {
200  return nullptr;
201  }
202  RecurrenceRule *rrule = new RecurrenceRule();
203  rrule->setStartDt(startDateTime());
204  const_cast<KCalendarCore::Recurrence *>(this)->addRRule(rrule);
205  return rrule;
206  } else {
207  return d->mRRules[0];
208  }
209 }
210 
211 RecurrenceRule *Recurrence::defaultRRuleConst() const
212 {
213  return d->mRRules.isEmpty() ? nullptr : d->mRRules[0];
214 }
215 
216 void Recurrence::updated()
217 {
218  // recurrenceType() re-calculates the type if it's rMax
219  d->mCachedType = rMax;
220  for (int i = 0, end = d->mObservers.count(); i < end; ++i) {
221  if (d->mObservers[i]) {
222  d->mObservers[i]->recurrenceUpdated(this);
223  }
224  }
225 }
226 
227 bool Recurrence::recurs() const
228 {
229  return !d->mRRules.isEmpty() || !d->mRDates.isEmpty() || !d->mRDateTimes.isEmpty();
230 }
231 
233 {
234  if (d->mCachedType == rMax) {
235  d->mCachedType = recurrenceType(defaultRRuleConst());
236  }
237  return d->mCachedType;
238 }
239 
241 {
242  if (!rrule) {
243  return rNone;
244  }
245  RecurrenceRule::PeriodType type = rrule->recurrenceType();
246 
247  // BYSETPOS, BYWEEKNUMBER and BYSECOND were not supported in old versions
248  if (!rrule->bySetPos().isEmpty() ||
249  !rrule->bySeconds().isEmpty() ||
250  !rrule->byWeekNumbers().isEmpty()) {
251  return rOther;
252  }
253 
254  // It wasn't possible to set BYMINUTES, BYHOUR etc. by the old code. So if
255  // it's set, it's none of the old types
256  if (!rrule->byMinutes().isEmpty() || !rrule->byHours().isEmpty()) {
257  return rOther;
258  }
259 
260  // Possible combinations were:
261  // BYDAY: with WEEKLY, MONTHLY, YEARLY
262  // BYMONTHDAY: with MONTHLY, YEARLY
263  // BYMONTH: with YEARLY
264  // BYYEARDAY: with YEARLY
265  if ((!rrule->byYearDays().isEmpty() && type != RecurrenceRule::rYearly) ||
266  (!rrule->byMonths().isEmpty() && type != RecurrenceRule::rYearly)) {
267  return rOther;
268  }
269  if (!rrule->byDays().isEmpty()) {
270  if (type != RecurrenceRule::rYearly &&
271  type != RecurrenceRule::rMonthly &&
272  type != RecurrenceRule::rWeekly) {
273  return rOther;
274  }
275  }
276 
277  switch (type) {
278  case RecurrenceRule::rNone:
279  return rNone;
280  case RecurrenceRule::rMinutely:
281  return rMinutely;
282  case RecurrenceRule::rHourly:
283  return rHourly;
284  case RecurrenceRule::rDaily:
285  return rDaily;
286  case RecurrenceRule::rWeekly:
287  return rWeekly;
288  case RecurrenceRule::rMonthly: {
289  if (rrule->byDays().isEmpty()) {
290  return rMonthlyDay;
291  } else if (rrule->byMonthDays().isEmpty()) {
292  return rMonthlyPos;
293  } else {
294  return rOther; // both position and date specified
295  }
296  }
297  case RecurrenceRule::rYearly: {
298  // Possible combinations:
299  // rYearlyMonth: [BYMONTH &] BYMONTHDAY
300  // rYearlyDay: BYYEARDAY
301  // rYearlyPos: [BYMONTH &] BYDAY
302  if (!rrule->byDays().isEmpty()) {
303  // can only by rYearlyPos
304  if (rrule->byMonthDays().isEmpty() && rrule->byYearDays().isEmpty()) {
305  return rYearlyPos;
306  } else {
307  return rOther;
308  }
309  } else if (!rrule->byYearDays().isEmpty()) {
310  // Can only be rYearlyDay
311  if (rrule->byMonths().isEmpty() && rrule->byMonthDays().isEmpty()) {
312  return rYearlyDay;
313  } else {
314  return rOther;
315  }
316  } else {
317  return rYearlyMonth;
318  }
319  }
320  default:
321  return rOther;
322  }
323 }
324 
325 bool Recurrence::recursOn(const QDate &qd, const QTimeZone &timeZone) const
326 {
327  // Don't waste time if date is before the start of the recurrence
328  if (QDateTime(qd, QTime(23, 59, 59), timeZone) < d->mStartDateTime) {
329  return false;
330  }
331 
332  // First handle dates. Exrules override
333  if (std::binary_search(d->mExDates.constBegin(), d->mExDates.constEnd(), qd)) {
334  return false;
335  }
336 
337  int i, end;
338  // For all-day events a matching exrule excludes the whole day
339  // since exclusions take precedence over inclusions, we know it can't occur on that day.
340  if (allDay()) {
341  for (i = 0, end = d->mExRules.count(); i < end; ++i) {
342  if (d->mExRules[i]->recursOn(qd, timeZone)) {
343  return false;
344  }
345  }
346  }
347 
348  if (std::binary_search(d->mRDates.constBegin(), d->mRDates.constEnd(), qd)) {
349  return true;
350  }
351 
352  // Check if it might recur today at all.
353  bool recurs = (startDate() == qd);
354  for (i = 0, end = d->mRDateTimes.count(); i < end && !recurs; ++i) {
355  recurs = (d->mRDateTimes[i].toTimeZone(timeZone).date() == qd);
356  }
357  for (i = 0, end = d->mRRules.count(); i < end && !recurs; ++i) {
358  recurs = d->mRRules[i]->recursOn(qd, timeZone);
359  }
360  // If the event wouldn't recur at all, simply return false, don't check ex*
361  if (!recurs) {
362  return false;
363  }
364 
365  // Check if there are any times for this day excluded, either by exdate or exrule:
366  bool exon = false;
367  for (i = 0, end = d->mExDateTimes.count(); i < end && !exon; ++i) {
368  exon = (d->mExDateTimes[i].toTimeZone(timeZone).date() == qd);
369  }
370  if (!allDay()) { // we have already checked all-day times above
371  for (i = 0, end = d->mExRules.count(); i < end && !exon; ++i) {
372  exon = d->mExRules[i]->recursOn(qd, timeZone);
373  }
374  }
375 
376  if (!exon) {
377  // Simple case, nothing on that day excluded, return the value from before
378  return recurs;
379  } else {
380  // Harder part: I don't think there is any way other than to calculate the
381  // whole list of items for that day.
382 //TODO: consider whether it would be more efficient to call
383 // Rule::recurTimesOn() instead of Rule::recursOn() from the start
384  TimeList timesForDay(recurTimesOn(qd, timeZone));
385  return !timesForDay.isEmpty();
386  }
387 }
388 
389 bool Recurrence::recursAt(const QDateTime &dt) const
390 {
391  // Convert to recurrence's time zone for date comparisons, and for more efficient time comparisons
392  const auto dtrecur = dt.toTimeZone(d->mStartDateTime.timeZone());
393 
394  // if it's excluded anyway, don't bother to check if it recurs at all.
395  if (std::binary_search(d->mExDateTimes.constBegin(), d->mExDateTimes.constEnd(), dtrecur) ||
396  std::binary_search(d->mExDates.constBegin(), d->mExDates.constEnd(), dtrecur.date())) {
397  return false;
398  }
399  int i, end;
400  for (i = 0, end = d->mExRules.count(); i < end; ++i) {
401  if (d->mExRules[i]->recursAt(dtrecur)) {
402  return false;
403  }
404  }
405 
406  // Check explicit recurrences, then rrules.
407  if (startDateTime() == dtrecur ||
408  std::binary_search(d->mRDateTimes.constBegin(), d->mRDateTimes.constEnd(), dtrecur)) {
409  return true;
410  }
411  for (i = 0, end = d->mRRules.count(); i < end; ++i) {
412  if (d->mRRules[i]->recursAt(dtrecur)) {
413  return true;
414  }
415  }
416 
417  return false;
418 }
419 
424 {
425  QList<QDateTime> dts;
426  dts << startDateTime();
427  if (!d->mRDates.isEmpty()) {
428  dts << QDateTime(d->mRDates.last(), QTime(0, 0, 0), d->mStartDateTime.timeZone());
429  }
430  if (!d->mRDateTimes.isEmpty()) {
431  dts << d->mRDateTimes.last();
432  }
433  for (int i = 0, end = d->mRRules.count(); i < end; ++i) {
434  auto rl = d->mRRules[i]->endDt();
435  // if any of the rules is infinite, the whole recurrence is
436  if (!rl.isValid()) {
437  return QDateTime();
438  }
439  dts << rl;
440  }
441  sortAndRemoveDuplicates(dts);
442  return dts.isEmpty() ? QDateTime() : dts.last();
443 }
444 
449 {
450  QDateTime end(endDateTime());
451  return end.isValid() ? end.date() : QDate();
452 }
453 
454 void Recurrence::setEndDate(const QDate &date)
455 {
456  QDateTime dt(date, d->mStartDateTime.time(), d->mStartDateTime.timeZone());
457  if (allDay()) {
458  dt.setTime(QTime(23, 59, 59));
459  }
460  setEndDateTime(dt);
461 }
462 
464 {
465  if (d->mRecurReadOnly) {
466  return;
467  }
468  RecurrenceRule *rrule = defaultRRule(true);
469  if (!rrule) {
470  return;
471  }
472 
473  // If the recurrence rule has a duration, and we're trying to set an invalid end date,
474  // we have to skip setting it to avoid setting the field dirty.
475  // The end date is already invalid since the duration is set and end date/duration
476  // are mutually exclusive.
477  // We can't use inequality check below, because endDt() also returns a valid date
478  // for a duration (it is calculated from the duration).
479  if (rrule->duration() > 0 && !dateTime.isValid()) {
480  return;
481  }
482 
483  if (dateTime != rrule->endDt()) {
484  rrule->setEndDt(dateTime);
485  updated();
486  }
487 }
488 
490 {
491  RecurrenceRule *rrule = defaultRRuleConst();
492  return rrule ? rrule->duration() : 0;
493 }
494 
495 int Recurrence::durationTo(const QDateTime &datetime) const
496 {
497  // Emulate old behavior: This is just an interface to the first rule!
498  RecurrenceRule *rrule = defaultRRuleConst();
499  return rrule ? rrule->durationTo(datetime) : 0;
500 }
501 
502 int Recurrence::durationTo(const QDate &date) const
503 {
504  return durationTo(QDateTime(date, QTime(23, 59, 59), d->mStartDateTime.timeZone()));
505 }
506 
508 {
509  if (d->mRecurReadOnly) {
510  return;
511  }
512 
513  RecurrenceRule *rrule = defaultRRule(true);
514  if (!rrule) {
515  return;
516  }
517 
518  if (duration != rrule->duration()) {
519  rrule->setDuration(duration);
520  updated();
521  }
522 }
523 
524 void Recurrence::shiftTimes(const QTimeZone &oldTz, const QTimeZone &newTz)
525 {
526  if (d->mRecurReadOnly) {
527  return;
528  }
529 
530  d->mStartDateTime = d->mStartDateTime.toTimeZone(oldTz);
531  d->mStartDateTime.setTimeZone(newTz);
532 
533  int i, end;
534  for (i = 0, end = d->mRDateTimes.count(); i < end; ++i) {
535  d->mRDateTimes[i] = d->mRDateTimes[i].toTimeZone(oldTz);
536  d->mRDateTimes[i].setTimeZone(newTz);
537  }
538  for (i = 0, end = d->mExDateTimes.count(); i < end; ++i) {
539  d->mExDateTimes[i] = d->mExDateTimes[i].toTimeZone(oldTz);
540  d->mExDateTimes[i].setTimeZone(newTz);
541  }
542  for (i = 0, end = d->mRRules.count(); i < end; ++i) {
543  d->mRRules[i]->shiftTimes(oldTz, newTz);
544  }
545  for (i = 0, end = d->mExRules.count(); i < end; ++i) {
546  d->mExRules[i]->shiftTimes(oldTz, newTz);
547  }
548 }
549 
551 {
552  if (d->mRecurReadOnly) {
553  return;
554  }
555  qDeleteAll(d->mRRules);
556  d->mRRules.clear();
557  updated();
558 }
559 
561 {
562  if (d->mRecurReadOnly) {
563  return;
564  }
565  qDeleteAll(d->mRRules);
566  d->mRRules.clear();
567  qDeleteAll(d->mExRules);
568  d->mExRules.clear();
569  d->mRDates.clear();
570  d->mRDateTimes.clear();
571  d->mExDates.clear();
572  d->mExDateTimes.clear();
573  d->mCachedType = rMax;
574  updated();
575 }
576 
577 void Recurrence::setRecurReadOnly(bool readOnly)
578 {
579  d->mRecurReadOnly = readOnly;
580 }
581 
583 {
584  return d->mRecurReadOnly;
585 }
586 
588 {
589  return d->mStartDateTime.date();
590 }
591 
592 void Recurrence::setStartDateTime(const QDateTime &start, bool isAllDay)
593 {
594  if (d->mRecurReadOnly) {
595  return;
596  }
597  d->mStartDateTime = start;
598  setAllDay(isAllDay); // set all RRULEs and EXRULEs
599 
600  int i, end;
601  for (i = 0, end = d->mRRules.count(); i < end; ++i) {
602  d->mRRules[i]->setStartDt(start);
603  }
604  for (i = 0, end = d->mExRules.count(); i < end; ++i) {
605  d->mExRules[i]->setStartDt(start);
606  }
607  updated();
608 }
609 
611 {
612  RecurrenceRule *rrule = defaultRRuleConst();
613  return rrule ? rrule->frequency() : 0;
614 }
615 
616 // Emulate the old behaviour. Make this methods just an interface to the
617 // first rrule
619 {
620  if (d->mRecurReadOnly || freq <= 0) {
621  return;
622  }
623 
624  RecurrenceRule *rrule = defaultRRule(true);
625  if (rrule) {
626  rrule->setFrequency(freq);
627  }
628  updated();
629 }
630 
631 // WEEKLY
632 
634 {
635  RecurrenceRule *rrule = defaultRRuleConst();
636  return rrule ? rrule->weekStart() : 1;
637 }
638 
639 // Emulate the old behavior
641 {
642  QBitArray days(7);
643  days.fill(0);
644  RecurrenceRule *rrule = defaultRRuleConst();
645  if (rrule) {
646  const QList<RecurrenceRule::WDayPos> &bydays = rrule->byDays();
647  for (int i = 0; i < bydays.size(); ++i) {
648  if (bydays.at(i).pos() == 0) {
649  days.setBit(bydays.at(i).day() - 1);
650  }
651  }
652  }
653  return days;
654 }
655 
656 // MONTHLY
657 
658 // Emulate the old behavior
660 {
661  RecurrenceRule *rrule = defaultRRuleConst();
662  if (rrule) {
663  return rrule->byMonthDays();
664  } else {
665  return QList<int>();
666  }
667 }
668 
669 // Emulate the old behavior
671 {
672  RecurrenceRule *rrule = defaultRRuleConst();
673  return rrule ? rrule->byDays() : QList<RecurrenceRule::WDayPos>();
674 }
675 
676 // YEARLY
677 
679 {
680  RecurrenceRule *rrule = defaultRRuleConst();
681  return rrule ? rrule->byYearDays() : QList<int>();
682 }
683 
685 {
686  return monthDays();
687 }
688 
690 {
691  RecurrenceRule *rrule = defaultRRuleConst();
692  return rrule ? rrule->byMonths() : QList<int>();
693 }
694 
696 {
697  return monthPositions();
698 }
699 
700 RecurrenceRule *Recurrence::setNewRecurrenceType(RecurrenceRule::PeriodType type, int freq)
701 {
702  if (d->mRecurReadOnly || freq <= 0) {
703  return nullptr;
704  }
705 
706  // Ignore the call if nothing has change
707  if (defaultRRuleConst() && defaultRRuleConst()->recurrenceType() == type && frequency() == freq) {
708  return nullptr;
709  }
710 
711  qDeleteAll(d->mRRules);
712  d->mRRules.clear();
713  updated();
714  RecurrenceRule *rrule = defaultRRule(true);
715  if (!rrule) {
716  return nullptr;
717  }
718  rrule->setRecurrenceType(type);
719  rrule->setFrequency(freq);
720  rrule->setDuration(-1);
721  return rrule;
722 }
723 
724 void Recurrence::setMinutely(int _rFreq)
725 {
726  if (setNewRecurrenceType(RecurrenceRule::rMinutely, _rFreq)) {
727  updated();
728  }
729 }
730 
731 void Recurrence::setHourly(int _rFreq)
732 {
733  if (setNewRecurrenceType(RecurrenceRule::rHourly, _rFreq)) {
734  updated();
735  }
736 }
737 
738 void Recurrence::setDaily(int _rFreq)
739 {
740  if (setNewRecurrenceType(RecurrenceRule::rDaily, _rFreq)) {
741  updated();
742  }
743 }
744 
745 void Recurrence::setWeekly(int freq, int weekStart)
746 {
747  RecurrenceRule *rrule = setNewRecurrenceType(RecurrenceRule::rWeekly, freq);
748  if (!rrule) {
749  return;
750  }
751  rrule->setWeekStart(weekStart);
752  updated();
753 }
754 
755 void Recurrence::setWeekly(int freq, const QBitArray &days, int weekStart)
756 {
757  setWeekly(freq, weekStart);
758  addMonthlyPos(0, days);
759 }
760 
762 {
763  addMonthlyPos(0, days);
764 }
765 
767 {
768  if (setNewRecurrenceType(RecurrenceRule::rMonthly, freq)) {
769  updated();
770  }
771 }
772 
773 void Recurrence::addMonthlyPos(short pos, const QBitArray &days)
774 {
775  // Allow 53 for yearly!
776  if (d->mRecurReadOnly || pos > 53 || pos < -53) {
777  return;
778  }
779 
780  RecurrenceRule *rrule = defaultRRule(false);
781  if (!rrule) {
782  return;
783  }
784  bool changed = false;
785  QList<RecurrenceRule::WDayPos> positions = rrule->byDays();
786 
787  for (int i = 0; i < 7; ++i) {
788  if (days.testBit(i)) {
789  RecurrenceRule::WDayPos p(pos, i + 1);
790  if (!positions.contains(p)) {
791  changed = true;
792  positions.append(p);
793  }
794  }
795  }
796  if (changed) {
797  rrule->setByDays(positions);
798  updated();
799  }
800 }
801 
802 void Recurrence::addMonthlyPos(short pos, ushort day)
803 {
804  // Allow 53 for yearly!
805  if (d->mRecurReadOnly || pos > 53 || pos < -53) {
806  return;
807  }
808 
809  RecurrenceRule *rrule = defaultRRule(false);
810  if (!rrule) {
811  return;
812  }
813  QList<RecurrenceRule::WDayPos> positions = rrule->byDays();
814 
815  RecurrenceRule::WDayPos p(pos, day);
816  if (!positions.contains(p)) {
817  positions.append(p);
818  setMonthlyPos(positions);
819  }
820 }
821 
822 void Recurrence::setMonthlyPos(const QList<RecurrenceRule::WDayPos> &monthlyDays)
823 {
824  if (d->mRecurReadOnly) {
825  return;
826  }
827 
828  RecurrenceRule *rrule = defaultRRule(true);
829  if (!rrule) {
830  return;
831  }
832 
833  //TODO: sort lists
834  // the position inside the list has no meaning, so sort the list before testing if it changed
835 
836  if (monthlyDays != rrule->byDays()) {
837  rrule->setByDays(monthlyDays);
838  updated();
839  }
840 }
841 
843 {
844  if (d->mRecurReadOnly || day > 31 || day < -31) {
845  return;
846  }
847 
848  RecurrenceRule *rrule = defaultRRule(true);
849  if (!rrule) {
850  return;
851  }
852 
853  QList<int> monthDays = rrule->byMonthDays();
854  if (!monthDays.contains(day)) {
855  monthDays.append(day);
856  setMonthlyDate(monthDays);
857  }
858 }
859 
860 void Recurrence::setMonthlyDate(const QList< int > &monthlyDays)
861 {
862  if (d->mRecurReadOnly) {
863  return;
864  }
865 
866  RecurrenceRule *rrule = defaultRRule(true);
867  if (!rrule) {
868  return;
869  }
870 
871  QList<int> mD(monthlyDays);
872  QList<int> rbD(rrule->byMonthDays());
873 
874  sortAndRemoveDuplicates(mD);
875  sortAndRemoveDuplicates(rbD);
876 
877  if (mD != rbD) {
878  rrule->setByMonthDays(monthlyDays);
879  updated();
880  }
881 }
882 
883 void Recurrence::setYearly(int freq)
884 {
885  if (setNewRecurrenceType(RecurrenceRule::rYearly, freq)) {
886  updated();
887  }
888 }
889 
890 // Daynumber within year
892 {
893  RecurrenceRule *rrule = defaultRRule(false); // It must already exist!
894  if (!rrule) {
895  return;
896  }
897 
898  QList<int> days = rrule->byYearDays();
899  if (!days.contains(day)) {
900  days << day;
901  setYearlyDay(days);
902  }
903 }
904 
905 void Recurrence::setYearlyDay(const QList<int> &days)
906 {
907  RecurrenceRule *rrule = defaultRRule(false); // It must already exist!
908  if (!rrule) {
909  return;
910  }
911 
912  QList<int> d(days);
913  QList<int> bYD(rrule->byYearDays());
914 
915  sortAndRemoveDuplicates(d);
916  sortAndRemoveDuplicates(bYD);
917 
918  if (d != bYD) {
919  rrule->setByYearDays(days);
920  updated();
921  }
922 }
923 
924 // day part of date within year
926 {
927  addMonthlyDate(day);
928 }
929 
930 void Recurrence::setYearlyDate(const QList<int> &dates)
931 {
932  setMonthlyDate(dates);
933 }
934 
935 // day part of date within year, given as position (n-th weekday)
936 void Recurrence::addYearlyPos(short pos, const QBitArray &days)
937 {
938  addMonthlyPos(pos, days);
939 }
940 
941 void Recurrence::setYearlyPos(const QList<RecurrenceRule::WDayPos> &days)
942 {
943  setMonthlyPos(days);
944 }
945 
946 // month part of date within year
947 void Recurrence::addYearlyMonth(short month)
948 {
949  if (d->mRecurReadOnly || month < 1 || month > 12) {
950  return;
951  }
952 
953  RecurrenceRule *rrule = defaultRRule(false);
954  if (!rrule) {
955  return;
956  }
957 
958  QList<int> months = rrule->byMonths();
959  if (!months.contains(month)) {
960  months << month;
961  setYearlyMonth(months);
962  }
963 }
964 
965 void Recurrence::setYearlyMonth(const QList<int> &months)
966 {
967  if (d->mRecurReadOnly) {
968  return;
969  }
970 
971  RecurrenceRule *rrule = defaultRRule(false);
972  if (!rrule) {
973  return;
974  }
975 
976  QList<int> m(months);
977  QList<int> bM(rrule->byMonths());
978 
979  sortAndRemoveDuplicates(m);
980  sortAndRemoveDuplicates(bM);
981 
982  if (m != bM) {
983  rrule->setByMonths(months);
984  updated();
985  }
986 }
987 
988 TimeList Recurrence::recurTimesOn(const QDate &date, const QTimeZone &timeZone) const
989 {
990 // qCDebug(KCALCORE_LOG) << "recurTimesOn(" << date << ")";
991  int i, end;
992  TimeList times;
993 
994  // The whole day is excepted
995  if (std::binary_search(d->mExDates.constBegin(), d->mExDates.constEnd(), date)) {
996  return times;
997  }
998 
999  // EXRULE takes precedence over RDATE entries, so for all-day events,
1000  // a matching excule also excludes the whole day automatically
1001  if (allDay()) {
1002  for (i = 0, end = d->mExRules.count(); i < end; ++i) {
1003  if (d->mExRules[i]->recursOn(date, timeZone)) {
1004  return times;
1005  }
1006  }
1007  }
1008 
1009  QDateTime dt = startDateTime().toTimeZone(timeZone);
1010  if (dt.date() == date) {
1011  times << dt.time();
1012  }
1013 
1014  bool foundDate = false;
1015  for (i = 0, end = d->mRDateTimes.count(); i < end; ++i) {
1016  dt = d->mRDateTimes[i].toTimeZone(timeZone);
1017  if (dt.date() == date) {
1018  times << dt.time();
1019  foundDate = true;
1020  } else if (foundDate) {
1021  break; // <= Assume that the rdatetime list is sorted
1022  }
1023  }
1024  for (i = 0, end = d->mRRules.count(); i < end; ++i) {
1025  times += d->mRRules[i]->recurTimesOn(date, timeZone);
1026  }
1027  sortAndRemoveDuplicates(times);
1028 
1029  foundDate = false;
1030  TimeList extimes;
1031  for (i = 0, end = d->mExDateTimes.count(); i < end; ++i) {
1032  dt = d->mExDateTimes[i].toTimeZone(timeZone);
1033  if (dt.date() == date) {
1034  extimes << dt.time();
1035  foundDate = true;
1036  } else if (foundDate) {
1037  break;
1038  }
1039  }
1040  if (!allDay()) { // we have already checked all-day times above
1041  for (i = 0, end = d->mExRules.count(); i < end; ++i) {
1042  extimes += d->mExRules[i]->recurTimesOn(date, timeZone);
1043  }
1044  }
1045  sortAndRemoveDuplicates(extimes);
1046  inplaceSetDifference(times, extimes);
1047  return times;
1048 }
1049 
1051 {
1052  int i, count;
1053  QList<QDateTime> times;
1054  for (i = 0, count = d->mRRules.count(); i < count; ++i) {
1055  times += d->mRRules[i]->timesInInterval(start, end);
1056  }
1057 
1058  // add rdatetimes that fit in the interval
1059  for (i = 0, count = d->mRDateTimes.count(); i < count; ++i) {
1060  if (d->mRDateTimes[i] >= start && d->mRDateTimes[i] <= end) {
1061  times += d->mRDateTimes[i];
1062  }
1063  }
1064 
1065  // add rdates that fit in the interval
1066  QDateTime kdt = d->mStartDateTime;
1067  for (i = 0, count = d->mRDates.count(); i < count; ++i) {
1068  kdt.setDate(d->mRDates[i]);
1069  if (kdt >= start && kdt <= end) {
1070  times += kdt;
1071  }
1072  }
1073 
1074  // Recurrence::timesInInterval(...) doesn't explicitly add mStartDateTime to the list
1075  // of times to be returned. It calls mRRules[i]->timesInInterval(...) which include
1076  // mStartDateTime.
1077  // So, If we have rdates/rdatetimes but don't have any rrule we must explicitly
1078  // add mStartDateTime to the list, otherwise we won't see the first occurrence.
1079  if ((!d->mRDates.isEmpty() || !d->mRDateTimes.isEmpty()) &&
1080  d->mRRules.isEmpty() &&
1081  start <= d->mStartDateTime &&
1082  end >= d->mStartDateTime) {
1083  times += d->mStartDateTime;
1084  }
1085 
1086  sortAndRemoveDuplicates(times);
1087 
1088  // Remove excluded times
1089  int idt = 0;
1090  int enddt = times.count();
1091  for (i = 0, count = d->mExDates.count(); i < count && idt < enddt; ++i) {
1092  while (idt < enddt && times[idt].date() < d->mExDates[i]) {
1093  ++idt;
1094  }
1095  while (idt < enddt && times[idt].date() == d->mExDates[i]) {
1096  times.removeAt(idt);
1097  --enddt;
1098  }
1099  }
1100  QList<QDateTime> extimes;
1101  for (i = 0, count = d->mExRules.count(); i < count; ++i) {
1102  extimes += d->mExRules[i]->timesInInterval(start, end);
1103  }
1104  extimes += d->mExDateTimes;
1105  sortAndRemoveDuplicates(extimes);
1106  inplaceSetDifference(times, extimes);
1107  return times;
1108 }
1109 
1111 {
1112  QDateTime nextDT = preDateTime;
1113  // prevent infinite loops, e.g. when an exrule extinguishes an rrule (e.g.
1114  // the exrule is identical to the rrule). If an occurrence is found, break
1115  // out of the loop by returning that QDateTime
1116 // TODO_Recurrence: Is a loop counter of 1000 really okay? I mean for secondly
1117 // recurrence, an exdate might exclude more than 1000 intervals!
1118  int loop = 0;
1119  while (loop < 1000) {
1120  // Outline of the algo:
1121  // 1) Find the next date/time after preDateTime when the event could recur
1122  // 1.0) Add the start date if it's after preDateTime
1123  // 1.1) Use the next occurrence from the explicit RDATE lists
1124  // 1.2) Add the next recurrence for each of the RRULEs
1125  // 2) Take the earliest recurrence of these = QDateTime nextDT
1126  // 3) If that date/time is not excluded, either explicitly by an EXDATE or
1127  // by an EXRULE, return nextDT as the next date/time of the recurrence
1128  // 4) If it's excluded, start all at 1), but starting at nextDT (instead
1129  // of preDateTime). Loop at most 1000 times.
1130  ++loop;
1131  // First, get the next recurrence from the RDate lists
1132  QList<QDateTime> dates;
1133  if (nextDT < startDateTime()) {
1134  dates << startDateTime();
1135  }
1136 
1137  // Assume that the rdatetime list is sorted
1138  const auto it = std::upper_bound(d->mRDateTimes.constBegin(), d->mRDateTimes.constEnd(), nextDT);
1139  if (it != d->mRDateTimes.constEnd()) {
1140  dates << *it;
1141  }
1142 
1143  QDateTime kdt(startDateTime());
1144  for (const auto &date : qAsConst(d->mRDates)) {
1145  kdt.setDate(date);
1146  if (kdt > nextDT) {
1147  dates << kdt;
1148  break;
1149  }
1150  }
1151 
1152  // Add the next occurrences from all RRULEs.
1153  for (const auto &rule : qAsConst(d->mRRules)) {
1154  QDateTime dt = rule->getNextDate(nextDT);
1155  if (dt.isValid()) {
1156  dates << dt;
1157  }
1158  }
1159 
1160  // Take the first of these (all others can't be used later on)
1161  sortAndRemoveDuplicates(dates);
1162  if (dates.isEmpty()) {
1163  return QDateTime();
1164  }
1165  nextDT = dates.first();
1166 
1167  // Check if that date/time is excluded explicitly or by an exrule:
1168  if (!std::binary_search(d->mExDates.constBegin(), d->mExDates.constEnd(), nextDT.date()) &&
1169  !std::binary_search(d->mExDateTimes.constBegin(), d->mExDateTimes.constEnd(), nextDT)) {
1170  bool allowed = true;
1171  for (const auto &rule : qAsConst(d->mExRules)) {
1172  allowed = allowed && !rule->recursAt(nextDT);
1173  }
1174  if (allowed) {
1175  return nextDT;
1176  }
1177  }
1178  }
1179 
1180  // Couldn't find a valid occurrences in 1000 loops, something is wrong!
1181  return QDateTime();
1182 }
1183 
1185 {
1186  QDateTime prevDT = afterDateTime;
1187  // prevent infinite loops, e.g. when an exrule extinguishes an rrule (e.g.
1188  // the exrule is identical to the rrule). If an occurrence is found, break
1189  // out of the loop by returning that QDateTime
1190  int loop = 0;
1191  while (loop < 1000) {
1192  // Outline of the algo:
1193  // 1) Find the next date/time after preDateTime when the event could recur
1194  // 1.1) Use the next occurrence from the explicit RDATE lists
1195  // 1.2) Add the next recurrence for each of the RRULEs
1196  // 2) Take the earliest recurrence of these = QDateTime nextDT
1197  // 3) If that date/time is not excluded, either explicitly by an EXDATE or
1198  // by an EXRULE, return nextDT as the next date/time of the recurrence
1199  // 4) If it's excluded, start all at 1), but starting at nextDT (instead
1200  // of preDateTime). Loop at most 1000 times.
1201  ++loop;
1202  // First, get the next recurrence from the RDate lists
1203  QList<QDateTime> dates;
1204  if (prevDT > startDateTime()) {
1205  dates << startDateTime();
1206  }
1207 
1208  const auto it = strictLowerBound(d->mRDateTimes.constBegin(), d->mRDateTimes.constEnd(), prevDT);
1209  if (it != d->mRDateTimes.constEnd()) {
1210  dates << *it;
1211  }
1212 
1213  QDateTime kdt(startDateTime());
1214  for (const auto &date : qAsConst(d->mRDates)) {
1215  kdt.setDate(date);
1216  if (kdt < prevDT) {
1217  dates << kdt;
1218  break;
1219  }
1220  }
1221 
1222  // Add the previous occurrences from all RRULEs.
1223  for (const auto &rule : qAsConst(d->mRRules)) {
1224  QDateTime dt = rule->getPreviousDate(prevDT);
1225  if (dt.isValid()) {
1226  dates << dt;
1227  }
1228  }
1229 
1230  // Take the last of these (all others can't be used later on)
1231  sortAndRemoveDuplicates(dates);
1232  if (dates.isEmpty()) {
1233  return QDateTime();
1234  }
1235  prevDT = dates.last();
1236 
1237  // Check if that date/time is excluded explicitly or by an exrule:
1238  if (!std::binary_search(d->mExDates.constBegin(), d->mExDates.constEnd(), prevDT.date()) &&
1239  !std::binary_search(d->mExDateTimes.constBegin(), d->mExDateTimes.constEnd(), prevDT)) {
1240  bool allowed = true;
1241  for (const auto &rule : qAsConst(d->mExRules)) {
1242  allowed = allowed && !rule->recursAt(prevDT);
1243  }
1244  if (allowed) {
1245  return prevDT;
1246  }
1247  }
1248  }
1249 
1250  // Couldn't find a valid occurrences in 1000 loops, something is wrong!
1251  return QDateTime();
1252 }
1253 
1254 /***************************** PROTECTED FUNCTIONS ***************************/
1255 
1256 RecurrenceRule::List Recurrence::rRules() const
1257 {
1258  return d->mRRules;
1259 }
1260 
1262 {
1263  if (d->mRecurReadOnly || !rrule) {
1264  return;
1265  }
1266 
1267  rrule->setAllDay(d->mAllDay);
1268  d->mRRules.append(rrule);
1269  rrule->addObserver(this);
1270  updated();
1271 }
1272 
1274 {
1275  if (d->mRecurReadOnly) {
1276  return;
1277  }
1278 
1279  d->mRRules.removeAll(rrule);
1280  rrule->removeObserver(this);
1281  updated();
1282 }
1283 
1285 {
1286  if (d->mRecurReadOnly) {
1287  return;
1288  }
1289 
1290  d->mRRules.removeAll(rrule);
1291  delete rrule;
1292  updated();
1293 }
1294 
1295 RecurrenceRule::List Recurrence::exRules() const
1296 {
1297  return d->mExRules;
1298 }
1299 
1301 {
1302  if (d->mRecurReadOnly || !exrule) {
1303  return;
1304  }
1305 
1306  exrule->setAllDay(d->mAllDay);
1307  d->mExRules.append(exrule);
1308  exrule->addObserver(this);
1309  updated();
1310 }
1311 
1313 {
1314  if (d->mRecurReadOnly) {
1315  return;
1316  }
1317 
1318  d->mExRules.removeAll(exrule);
1319  exrule->removeObserver(this);
1320  updated();
1321 }
1322 
1324 {
1325  if (d->mRecurReadOnly) {
1326  return;
1327  }
1328 
1329  d->mExRules.removeAll(exrule);
1330  delete exrule;
1331  updated();
1332 }
1333 
1334 QList<QDateTime> Recurrence::rDateTimes() const
1335 {
1336  return d->mRDateTimes;
1337 }
1338 
1339 void Recurrence::setRDateTimes(const QList<QDateTime> &rdates)
1340 {
1341  if (d->mRecurReadOnly) {
1342  return;
1343  }
1344 
1345  d->mRDateTimes = rdates;
1346  sortAndRemoveDuplicates(d->mRDateTimes);
1347  updated();
1348 }
1349 
1350 void Recurrence::addRDateTime(const QDateTime &rdate)
1351 {
1352  if (d->mRecurReadOnly) {
1353  return;
1354  }
1355 
1356  setInsert(d->mRDateTimes, rdate);
1357  updated();
1358 }
1359 
1360 DateList Recurrence::rDates() const
1361 {
1362  return d->mRDates;
1363 }
1364 
1365 void Recurrence::setRDates(const DateList &rdates)
1366 {
1367  if (d->mRecurReadOnly) {
1368  return;
1369  }
1370 
1371  d->mRDates = rdates;
1372  sortAndRemoveDuplicates(d->mRDates);
1373  updated();
1374 }
1375 
1376 void Recurrence::addRDate(const QDate &rdate)
1377 {
1378  if (d->mRecurReadOnly) {
1379  return;
1380  }
1381 
1382  setInsert(d->mRDates, rdate);
1383  updated();
1384 }
1385 
1386 QList<QDateTime> Recurrence::exDateTimes() const
1387 {
1388  return d->mExDateTimes;
1389 }
1390 
1391 void Recurrence::setExDateTimes(const QList<QDateTime> &exdates)
1392 {
1393  if (d->mRecurReadOnly) {
1394  return;
1395  }
1396 
1397  d->mExDateTimes = exdates;
1398  sortAndRemoveDuplicates(d->mExDateTimes);
1399 }
1400 
1401 void Recurrence::addExDateTime(const QDateTime &exdate)
1402 {
1403  if (d->mRecurReadOnly) {
1404  return;
1405  }
1406 
1407  setInsert(d->mExDateTimes, exdate);
1408  updated();
1409 }
1410 
1411 DateList Recurrence::exDates() const
1412 {
1413  return d->mExDates;
1414 }
1415 
1416 void Recurrence::setExDates(const DateList &exdates)
1417 {
1418  if (d->mRecurReadOnly) {
1419  return;
1420  }
1421 
1422  DateList l = exdates;
1423  sortAndRemoveDuplicates(l);
1424 
1425  if (d->mExDates != l) {
1426  d->mExDates = l;
1427  updated();
1428  }
1429 }
1430 
1431 void Recurrence::addExDate(const QDate &exdate)
1432 {
1433  if (d->mRecurReadOnly) {
1434  return;
1435  }
1436 
1437  setInsert(d->mExDates, exdate);
1438  updated();
1439 }
1440 
1441 void Recurrence::recurrenceChanged(RecurrenceRule *)
1442 {
1443  updated();
1444 }
1445 
1446 // %%%%%%%%%%%%%%%%%% end:Recurrencerule %%%%%%%%%%%%%%%%%%
1447 
1448 void Recurrence::dump() const
1449 {
1450  int i;
1451  int count = d->mRRules.count();
1452  qCDebug(KCALCORE_LOG) << " -)" << count << "RRULEs:";
1453  for (i = 0; i < count; ++i) {
1454  qCDebug(KCALCORE_LOG) << " -) RecurrenceRule: ";
1455  d->mRRules[i]->dump();
1456  }
1457  count = d->mExRules.count();
1458  qCDebug(KCALCORE_LOG) << " -)" << count << "EXRULEs:";
1459  for (i = 0; i < count; ++i) {
1460  qCDebug(KCALCORE_LOG) << " -) ExceptionRule :";
1461  d->mExRules[i]->dump();
1462  }
1463 
1464  count = d->mRDates.count();
1465  qCDebug(KCALCORE_LOG) << " -)" << count << "Recurrence Dates:";
1466  for (i = 0; i < count; ++i) {
1467  qCDebug(KCALCORE_LOG) << " " << d->mRDates[i];
1468  }
1469  count = d->mRDateTimes.count();
1470  qCDebug(KCALCORE_LOG) << " -)" << count << "Recurrence Date/Times:";
1471  for (i = 0; i < count; ++i) {
1472  qCDebug(KCALCORE_LOG) << " " << d->mRDateTimes[i];
1473  }
1474  count = d->mExDates.count();
1475  qCDebug(KCALCORE_LOG) << " -)" << count << "Exceptions Dates:";
1476  for (i = 0; i < count; ++i) {
1477  qCDebug(KCALCORE_LOG) << " " << d->mExDates[i];
1478  }
1479  count = d->mExDateTimes.count();
1480  qCDebug(KCALCORE_LOG) << " -)" << count << "Exception Date/Times:";
1481  for (i = 0; i < count; ++i) {
1482  qCDebug(KCALCORE_LOG) << " " << d->mExDateTimes[i];
1483  }
1484 }
1485 
1486 Recurrence::RecurrenceObserver::~RecurrenceObserver()
1487 {
1488 }
1489 
1491 {
1492  if (!r) {
1493  return out;
1494  }
1495 
1496  serializeQDateTimeList(out, r->d->mRDateTimes);
1497  serializeQDateTimeList(out, r->d->mExDateTimes);
1498  out << r->d->mRDates;
1499  serializeQDateTimeAsKDateTime(out, r->d->mStartDateTime);
1500  out << r->d->mCachedType
1501  << r->d->mAllDay << r->d->mRecurReadOnly << r->d->mExDates
1502  << r->d->mExRules.count() << r->d->mRRules.count();
1503 
1504  for (RecurrenceRule *rule : qAsConst(r->d->mExRules)) {
1505  out << rule;
1506  }
1507 
1508  for (RecurrenceRule *rule : qAsConst(r->d->mRRules)) {
1509  out << rule;
1510  }
1511 
1512  return out;
1513 }
1514 
1516 {
1517  if (!r) {
1518  return in;
1519  }
1520 
1521  int rruleCount, exruleCount;
1522 
1523  deserializeQDateTimeList(in, r->d->mRDateTimes);
1524  deserializeQDateTimeList(in, r->d->mExDateTimes);
1525  in >> r->d->mRDates;
1526  deserializeKDateTimeAsQDateTime(in, r->d->mStartDateTime);
1527  in >> r->d->mCachedType
1528  >> r->d->mAllDay >> r->d->mRecurReadOnly >> r->d->mExDates
1529  >> exruleCount >> rruleCount;
1530 
1531  r->d->mExRules.clear();
1532  r->d->mRRules.clear();
1533 
1534  for (int i = 0; i < exruleCount; ++i) {
1536  rule->addObserver(r);
1537  in >> rule;
1538  r->d->mExRules.append(rule);
1539  }
1540 
1541  for (int i = 0; i < rruleCount; ++i) {
1543  rule->addObserver(r);
1544  in >> rule;
1545  r->d->mRRules.append(rule);
1546  }
1547 
1548  return in;
1549 }
KCALENDARCORE_EXPORT QDataStream & operator<<(QDataStream &out, const KCalendarCore::Alarm::Ptr &)
Alarm serializer.
Definition: alarm.cpp:825
int duration() const
Returns -1 if the event recurs infinitely, 0 if the end date is set, otherwise the total number of re...
Definition: recurrence.cpp:489
bool recurs() const
Returns whether the event recurs at all.
Definition: recurrence.cpp:227
void addYearlyDate(int date)
Adds date within a yearly recurrence.
Definition: recurrence.cpp:925
void setFrequency(int freq)
Sets the frequency of recurrence, in terms of the recurrence time period type.
Definition: recurrence.cpp:618
void setWeekly(int freq, int weekStart=1)
Sets an event to recur weekly.
Definition: recurrence.cpp:745
void addYearlyPos(short pos, const QBitArray &days)
Adds position within month/year within a yearly recurrence.
Definition: recurrence.cpp:936
void addMonthlyPos(short pos, const QBitArray &days)
Adds a position (e.g.
Definition: recurrence.cpp:773
void setDuration(int duration)
Sets the total number of times the event is to occur, including both the first and last...
void setStartDt(const QDateTime &start)
Sets the recurrence start date/time.
void setBit(int i)
bool recursOn(const QDate &date, const QTimeZone &timeZone) const
Returns true if the date specified is one on which the event will recur.
Definition: recurrence.cpp:325
void addObserver(RuleObserver *observer)
Installs an observer.
QDateTime endDateTime() const
Returns the date/time of the last recurrence.
Definition: recurrence.cpp:423
void setYearly(int freq)
Sets an event to recur yearly.
Definition: recurrence.cpp:883
QDateTime getPreviousDateTime(const QDateTime &afterDateTime) const
Returns the date and time of the last previous recurrence, before the specified date/time.
const T & at(int i) const const
void removeAt(int i)
KCALENDARCORE_EXPORT QDataStream & operator>>(QDataStream &in, const KCalendarCore::Alarm::Ptr &)
Alarm deserializer.
Definition: alarm.cpp:849
void setTime(const QTime &time)
QTime time() const const
~Recurrence() override
Destructor.
Definition: recurrence.cpp:128
QDateTime endDt(bool *result=nullptr) const
Returns the date and time of the last recurrence.
void removeObserver(RuleObserver *observer)
Removes an observer that was added with addObserver.
void setDuration(int duration)
Sets the total number of times the event is to occur, including both the first and last...
Definition: recurrence.cpp:507
QDate endDate() const
Returns the date of the last recurrence.
Definition: recurrence.cpp:448
void setRecurReadOnly(bool readOnly)
Set if recurrence is read-only or can be changed.
Definition: recurrence.cpp:577
TimeList recurTimesOn(const QDate &date, const QTimeZone &timeZone) const
Returns a list of the times on the specified date at which the recurrence will occur.
Definition: recurrence.cpp:988
int frequency() const
Returns frequency of recurrence, in terms of the recurrence time period type.
Definition: recurrence.cpp:610
uint frequency() const
Returns the recurrence frequency, in terms of the recurrence time period type.
void setEndDate(const QDate &endDate)
Sets the date of the last recurrence.
Definition: recurrence.cpp:454
QDateTime toTimeZone(const QTimeZone &timeZone) const const
int size() const const
void removeObserver(RecurrenceObserver *observer)
Removes an observer that was added with addObserver.
Definition: recurrence.cpp:165
bool operator==(const Qt3DRender::QGraphicsApiFilter &reference, const Qt3DRender::QGraphicsApiFilter &sample)
structure for describing the n-th weekday of the month/year.
QList< RecurrenceRule::WDayPos > yearPositions() const
Returns the positions within a yearly recurrence.
Definition: recurrence.cpp:695
void setFrequency(int freq)
Sets the recurrence frequency, in terms of the recurrence time period type.
void setHourly(int freq)
Sets an event to recur hourly.
Definition: recurrence.cpp:731
int count(const T &value) const const
void setAllDay(bool allDay)
Sets whether the dtstart is all-day (i.e.
void addObserver(RecurrenceObserver *observer)
Installs an observer.
Definition: recurrence.cpp:158
void append(const T &value)
void setStartDateTime(const QDateTime &start, bool isAllDay)
Set start of recurrence.
Definition: recurrence.cpp:592
QList< int > yearDays() const
Returns the day numbers within a yearly recurrence.
Definition: recurrence.cpp:678
void clear()
Removes all recurrence and exception rules and dates.
Definition: recurrence.cpp:560
QList< RecurrenceRule::WDayPos > monthPositions() const
Returns list of day positions in months.
Definition: recurrence.cpp:670
Recurrence & operator=(const Recurrence &r)
Assignment operator.
Definition: recurrence.cpp:141
int weekStart() const
Returns the first day of the week.
Definition: recurrence.cpp:633
void deleteRRule(RecurrenceRule *rrule)
Remove a recurrence rule from the recurrence and delete it.
bool isEmpty() const const
PeriodType
enum for describing the frequency how an event recurs, if at all.
void setDate(const QDate &date)
T & first()
bool recurReadOnly() const
Returns true if the recurrence is read-only, or false if it can be changed.
Definition: recurrence.cpp:582
void removeExRule(RecurrenceRule *exrule)
Remove an exception rule from the recurrence.
void unsetRecurs()
Removes all recurrence rules.
Definition: recurrence.cpp:550
QDate startDate() const
Return the start date/time of the recurrence.
Definition: recurrence.cpp:587
QDateTime getNextDateTime(const QDateTime &preDateTime) const
Returns the start date/time of the earliest recurrence with a start date/time after the specified dat...
int durationTo(const QDateTime &dt) const
Returns the number of recurrences up to and including the date/time specified.
Definition: recurrence.cpp:495
bool operator==(const Recurrence &r) const
Comparison operator for equality.
Definition: recurrence.cpp:135
void setAllDay(bool allDay)
Sets whether the dtstart is a all-day (i.e.
Definition: recurrence.cpp:180
QList< int > yearDates() const
Returns the dates within a yearly recurrence.
Definition: recurrence.cpp:684
bool contains(const T &value) const const
void setEndDateTime(const QDateTime &endDateTime)
Sets the date and time of the last recurrence.
Definition: recurrence.cpp:463
void addRRule(RecurrenceRule *rrule)
Add a recurrence rule to the recurrence.
bool isValid() const const
void addYearlyDay(int day)
Adds day number of year within a yearly recurrence.
Definition: recurrence.cpp:891
const QList< QKeySequence > & end()
QList< int > yearMonths() const
Returns the months within a yearly recurrence.
Definition: recurrence.cpp:689
QBitArray days() const
Returns week day mask (bit 0 = Monday).
Definition: recurrence.cpp:640
This class represents a recurrence rule for a calendar incidence.
Definition: recurrence.h:76
QDate date() const const
void removeRRule(RecurrenceRule *rrule)
Remove a recurrence rule from the recurrence.
void addMonthlyDate(short day)
Adds a date (e.g.
Definition: recurrence.cpp:842
void deleteExRule(RecurrenceRule *exrule)
Remove an exception rule from the recurrence and delete it.
int durationTo(const QDateTime &dt) const
Returns the number of recurrences up to and including the date/time specified.
T & last()
void setMinutely(int freq)
Sets an event to recur minutely.
Definition: recurrence.cpp:724
QList< int > monthDays() const
Returns list of day numbers of a month.
Definition: recurrence.cpp:659
void setEndDt(const QDateTime &endDateTime)
Sets the date and time of the last recurrence.
void shiftTimes(const QTimeZone &oldZone, const QTimeZone &newZone)
Shift the times of the recurrence so that they appear at the same clock time as before but in a new t...
Definition: recurrence.cpp:524
ushort recurrenceType() const
Returns the event&#39;s recurrence status.
Definition: recurrence.cpp:232
void addYearlyMonth(short _rNum)
Adds month in yearly recurrence.
Definition: recurrence.cpp:947
QList< QDateTime > timesInInterval(const QDateTime &start, const QDateTime &end) const
Returns a list of all the times at which the recurrence will occur between two specified times...
void setDaily(int freq)
Sets an event to recur daily.
Definition: recurrence.cpp:738
int duration() const
Returns -1 if the event recurs infinitely, 0 if the end date is set, otherwise the total number of re...
Recurrence()
Constructs an empty recurrence.
Definition: recurrence.cpp:104
void dump() const
Debug output.
bool fill(bool value, int size)
This class represents a recurrence rule for a calendar incidence.
void addExRule(RecurrenceRule *exrule)
Add an exception rule to the recurrence.
void setMonthly(int freq)
Sets an event to recur monthly.
Definition: recurrence.cpp:766
void addWeeklyDays(const QBitArray &days)
Adds days to the weekly day recurrence list.
Definition: recurrence.cpp:761
bool testBit(int i) const const
QDateTime startDateTime() const
Return the start date/time of the recurrence (Time for all-day recurrences will be 0:00)...
Definition: recurrence.cpp:170
Namespace for all KCalendarCore types.
Definition: alarm.h:36
bool allDay() const
Set whether the recurrence has no time, just a date.
Definition: recurrence.cpp:175
bool recursAt(const QDateTime &dt) const
Returns true if the date/time specified is one at which the event will recur.
Definition: recurrence.cpp:389
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Mon Jan 25 2021 22:56:21 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.