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

KDE's Doxygen guidelines are available online.