1/*
2 This file is part of the kcalcore library.
3
4 Copyright (c) 1998 Preston Brown <pbrown@kde.org>
5 Copyright (c) 2001,2003 Cornelius Schumacher <schumacher@kde.org>
6 Copyright (c) 2002,2006 David Jarvie <software@astrojar.org.uk>
7 Copyright (C) 2005 Reinhold Kainhofer <reinhold@kainhofer.com>
8
9 This library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Library General Public
11 License as published by the Free Software Foundation; either
12 version 2 of the License, or (at your option) any later version.
13
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Library General Public License for more details.
18
19 You should have received a copy of the GNU Library General Public License
20 along with this library; see the file COPYING.LIB. If not, write to
21 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 Boston, MA 02110-1301, USA.
23*/
24#ifndef KCALCORE_RECURRENCE_H
25#define KCALCORE_RECURRENCE_H
26
27#include "kcalcore_export.h"
28#include "recurrencerule.h"
29
30class QBitArray;
31
32namespace KCalCore {
33
34class RecurrenceRule;
35
36/**
37 This class represents a recurrence rule for a calendar incidence.
38
39 It manages all recurrence rules, recurrence date/times, exception rules
40 and exception date times that can appear inside calendar items.
41 Each recurrence rule and exception rule is represented as an object
42 of type RecurrenceRule.
43
44 For the simple case where at most one recurrence
45 rule is present, this class provides shortcut methods to set the type:
46 setMinutely()
47 setHourly()
48 setDaily()
49 setWeekly()
50 setMonthly()
51 setYearly()
52 to set/get general information about the recurrence:
53 setEndDate()
54 setEndDateTime()
55 duration()
56 durationTo()
57 setDuration()
58 frequency()
59 setFrequency()
60 and to set/get specific information about the recurrence within the interval:
61 days()
62 monthDays()
63 monthPositions()
64 yearDays()
65 yearDates()
66 yearMonths()
67 yearPositions()
68 addMonthlyPos()
69 addMonthlyDate()
70 addYearlyDay()
71 addYearlyDate()
72 addYearlyPos()
73 addYearlyMonth()
74 These are all available so that you don't have to work on the RecurrenceRule
75 objects themselves.
76 In other words, in that simple situation the interface stays almost the
77 same compared to the old Recurrence class, which allowed only one
78 recurrence rule.
79
80 As soon as your recurrence consists of multiple recurrence rules or exception
81 rules, you cannot use the methods mentioned above any more (since each rule
82 will have a different type and different settings). If you still call
83 any of them, the set*ly methods will remove all rules and add one rule with
84 the specified type. The add* and the other set* methods will change only
85 the first recurrence rule, but leave the others untouched.
86*/
87class KCALCORE_EXPORT Recurrence : public RecurrenceRule::RuleObserver
88{
89public:
90 class RecurrenceObserver
91 {
92 public:
93 virtual ~RecurrenceObserver();
94 /** This method will be called on each change of the recurrence object */
95 virtual void recurrenceUpdated(Recurrence *r) = 0;
96 };
97
98 /** enumeration for describing how an event recurs, if at all. */
99 enum {
100 rNone = 0,
101 rMinutely = 0x001,
102 rHourly = 0x0002,
103 rDaily = 0x0003,
104 rWeekly = 0x0004,
105 rMonthlyPos = 0x0005,
106 rMonthlyDay = 0x0006,
107 rYearlyMonth = 0x0007,
108 rYearlyDay = 0x0008,
109 rYearlyPos = 0x0009,
110 rOther = 0x000A,
111 rMax=0x00FF
112 };
113
114 /**
115 Constructs an empty recurrence.
116 */
117 Recurrence();
118
119 /**
120 Copy constructor.
121 @param r instance to copy from
122 */
123 Recurrence(const Recurrence &r);
124
125 /**
126 Destructor.
127 */
128 ~Recurrence();
129
130 /**
131 Comparison operator for equality.
132 @param r instance to compare with
133 @return true if recurrences are the same, false otherwise
134 */
135 bool operator==(const Recurrence &r) const;
136
137 /**
138 Comparison operator for inequality.
139 @param r instance to compare with
140 @return true if recurrences are the different, false if the same
141 */
142 bool operator!=(const Recurrence &r) const {
143 return !operator==(r);
144 }
145
146 /**
147 Assignment operator.
148 @param r the recurrence which will be assigned to this.
149 */
150 Recurrence &operator=(const Recurrence &r);
151
152 /** Return the start date/time of the recurrence (Time for all-day recurrences will be 0:00).
153 @return the current start/time of the recurrence. */
154 KDateTime startDateTime() const;
155 /** Return the start date/time of the recurrence */
156 QDate startDate() const;
157 /** Set start of recurrence.
158 If @p start is date-only, the recurrence is set to all-day. Otherwise, the
159 start is set to a date and time, and the recurrence is set to non-all-day.
160 @param start the new start date or date/time of the recurrence.
161 */
162 void setStartDateTime(const KDateTime &start);
163
164 /** Set whether the recurrence has no time, just a date.
165 * All-day means -- according to rfc2445 -- that the event has no time
166 * associated.
167 * N.B. This property is derived by default from whether setStartDateTime() is
168 * called with a date-only or date/time parameter.
169 * @return whether the recurrence has a time (false) or it is just a date (true). */
170 bool allDay() const;
171 /** Sets whether the dtstart is a all-day (i.e. has no time attached)
172 @param allDay If the recurrence is for all-day item (true) or has a time associated (false).
173 */
174 void setAllDay(bool allDay);
175
176 /** Set if recurrence is read-only or can be changed. */
177 void setRecurReadOnly(bool readOnly);
178
179 /** Returns true if the recurrence is read-only, or false if it can be changed. */
180 bool recurReadOnly() const;
181
182 /** Returns whether the event recurs at all. */
183 bool recurs() const;
184
185 /** Returns the event's recurrence status. See the enumeration at the top
186 * of this file for possible values. */
187 ushort recurrenceType() const;
188
189 /** Returns the recurrence status for a recurrence rule.
190 * See the enumeration at the top of this file for possible values.
191 *
192 * @param rrule the recurrence rule to get the type for
193 */
194 static ushort recurrenceType(const RecurrenceRule *rrule);
195
196 /**
197 Returns true if the date specified is one on which the event will recur.
198
199 @param date date to check.
200 @param timeSpec time specification for @p date.
201 */
202 bool recursOn(const QDate &date, const KDateTime::Spec &timeSpec) const;
203
204 /**
205 Returns true if the date/time specified is one at which the event will
206 recur. Times are rounded down to the nearest minute to determine the
207 result.
208
209 @param dt is the date/time to check.
210 */
211 bool recursAt(const KDateTime &dt) const;
212
213 /**
214 Removes all recurrence rules. Recurrence dates and exceptions are
215 not removed.
216 */
217 void unsetRecurs();
218
219 /**
220 Removes all recurrence and exception rules and dates.
221 */
222 void clear();
223
224 /** Returns a list of the times on the specified date at which the
225 * recurrence will occur. The returned times should be interpreted in the
226 * context of @p timeSpec.
227 * @param date the date for which to find the recurrence times
228 * @param timeSpec time specification for @p date
229 */
230 TimeList recurTimesOn(const QDate &date, const KDateTime::Spec &timeSpec) const;
231
232 /** Returns a list of all the times at which the recurrence will occur
233 * between two specified times.
234 *
235 * There is a (large) maximum limit to the number of times returned. If due to
236 * this limit the list is incomplete, this is indicated by the last entry being
237 * set to an invalid KDateTime value. If you need further values, call the
238 * method again with a start time set to just after the last valid time returned.
239 *
240 * @param start inclusive start of interval
241 * @param end inclusive end of interval
242 * @return list of date/time values
243 */
244 DateTimeList timesInInterval(const KDateTime &start, const KDateTime &end) const;
245
246 /** Returns the date and time of the next recurrence, after the specified date/time.
247 * If the recurrence has no time, the next date after the specified date is returned.
248 * @param preDateTime the date/time after which to find the recurrence.
249 * @return date/time of next recurrence (strictly later than the given
250 * KDateTime), or invalid date if none.
251 */
252 KDateTime getNextDateTime(const KDateTime &preDateTime) const;
253
254 /** Returns the date and time of the last previous recurrence, before the specified date/time.
255 * If a time later than 00:00:00 is specified and the recurrence has no time, 00:00:00 on
256 * the specified date is returned if that date recurs.
257 *
258 * @param afterDateTime the date/time before which to find the recurrence.
259 * @return date/time of previous recurrence (strictly earlier than the given
260 * KDateTime), or invalid date if none.
261 */
262 KDateTime getPreviousDateTime(const KDateTime &afterDateTime) const;
263
264 /** Returns frequency of recurrence, in terms of the recurrence time period type. */
265 int frequency() const;
266
267 /** Sets the frequency of recurrence, in terms of the recurrence time period type. */
268 void setFrequency(int freq);
269
270 /**
271 * Returns -1 if the event recurs infinitely, 0 if the end date is set,
272 * otherwise the total number of recurrences, including the initial occurrence.
273 */
274 int duration() const;
275
276 /** Sets the total number of times the event is to occur, including both the
277 * first and last. */
278 void setDuration(int duration);
279
280 /** Returns the number of recurrences up to and including the date/time specified.
281 * @warning This function can be very time consuming - use it sparingly!
282 */
283 int durationTo(const KDateTime &dt) const;
284
285 /** Returns the number of recurrences up to and including the date specified.
286 * @warning This function can be very time consuming - use it sparingly!
287 */
288 int durationTo(const QDate &date) const;
289
290 /** Returns the date/time of the last recurrence.
291 * An invalid date is returned if the recurrence has no end.
292 */
293 KDateTime endDateTime() const;
294
295 /** Returns the date of the last recurrence.
296 * An invalid date is returned if the recurrence has no end.
297 */
298 QDate endDate() const;
299
300 /** Sets the date of the last recurrence. The end time is set to the recurrence start time.
301 * @param endDate the ending date after which to stop recurring. If the
302 * recurrence is not all-day, the end time will be 23:59.*/
303 void setEndDate(const QDate &endDate);
304
305 /** Sets the date and time of the last recurrence.
306 * @param endDateTime the ending date/time after which to stop recurring. */
307 void setEndDateTime(const KDateTime &endDateTime);
308
309 /**
310 Shift the times of the recurrence so that they appear at the same clock
311 time as before but in a new time zone. The shift is done from a viewing
312 time zone rather than from the actual recurrence time zone.
313
314 For example, shifting a recurrence whose start time is 09:00 America/New York,
315 using an old viewing time zone (@p oldSpec) of Europe/London, to a new time
316 zone (@p newSpec) of Europe/Paris, will result in the time being shifted
317 from 14:00 (which is the London time of the recurrence start) to 14:00 Paris
318 time.
319
320 @param oldSpec the time specification which provides the clock times
321 @param newSpec the new time specification
322 */
323 void shiftTimes(const KDateTime::Spec &oldSpec, const KDateTime::Spec &newSpec);
324
325 /** Sets an event to recur minutely. By default infinite recurrence is used.
326 To set an end date use the method setEndDate and to set the number
327 of occurrences use setDuration.
328
329 This method clears all recurrence rules and adds one rule with a
330 minutely recurrence. All other recurrence components (recurrence
331 date/times, exception date/times and exception rules) are not
332 modified.
333 * @param freq the frequency to recur, e.g. 2 is every other minute
334 */
335 void setMinutely(int freq);
336
337 /** Sets an event to recur hourly. By default infinite recurrence is used.
338 The minute of the recurrence is taken from the start date (if you
339 need to change it, you will have to modify the defaultRRule's
340 byMinute list manually.
341 To set an end date use the method setEndDate and to set the number
342 of occurrences use setDuration.
343
344 This method clears all recurrence rules and adds one rule with a
345 hourly recurrence. All other recurrence components (recurrence
346 date/times, exception date/times and exception rules) are not
347 modified.
348 * @param freq the frequency to recur, e.g. 2 is every other hour
349 */
350 void setHourly(int freq);
351
352 /** Sets an event to recur daily. By default infinite recurrence is used.
353 The minute and second of the recurrence is taken from the start date
354 (if you need to change them, you will have to modify the defaultRRule's
355 byMinute list manually.
356 To set an end date use the method setEndDate and to set the number
357 of occurrences use setDuration.
358
359 This method clears all recurrence rules and adds one rule with a
360 daily recurrence. All other recurrence components (recurrence
361 date/times, exception date/times and exception rules) are not
362 modified.
363 * @param freq the frequency to recur, e.g. 2 is every other day
364 */
365 void setDaily(int freq);
366
367 /** Sets an event to recur weekly. By default infinite recurrence is used.
368 To set an end date use the method setEndDate and to set the number
369 of occurrences use setDuration.
370
371 This method clears all recurrence rules and adds one rule with a
372 weekly recurrence. All other recurrence components (recurrence
373 date/times, exception date/times and exception rules) are not
374 modified.
375 * @param freq the frequency to recur, e.g. every other week etc.
376 * @param weekStart the first day of the week (Monday=1 .. Sunday=7, default is Monday).
377 */
378 void setWeekly(int freq, int weekStart = 1);
379 /** Sets an event to recur weekly. By default infinite recurrence is used.
380 To set an end date use the method setEndDate and to set the number
381 of occurrences use setDuration.
382
383 This method clears all recurrence rules and adds one rule with a
384 weekly recurrence. All other recurrence components (recurrence
385 date/times, exception date/times and exception rules) are not
386 modified.
387 * @param freq the frequency to recur, e.g. every other week etc.
388 * @param days a 7 bit array indicating which days on which to recur (bit 0 = Monday).
389 * @param weekStart the first day of the week (Monday=1 .. Sunday=7, default is Monday).
390 */
391 void setWeekly(int freq, const QBitArray &days, int weekStart = 1);
392
393 /** Adds days to the weekly day recurrence list.
394 * @param days a 7 bit array indicating which days on which to recur (bit 0 = Monday).
395 */
396 void addWeeklyDays(const QBitArray &days);
397 /** Returns the first day of the week. Uses only the
398 * first RRULE if present (i.e. a second RRULE as well as all EXRULES are
399 * ignored!
400 * @return Weekday of the first day of the week (Monday=1 .. Sunday=7)
401 */
402 int weekStart() const;
403
404 /** Returns week day mask (bit 0 = Monday). */
405 QBitArray days() const; // Emulate the old behavior
406
407 /** Sets an event to recur monthly. By default infinite recurrence is used.
408 The date of the monthly recurrence will be taken from the start date
409 unless you explicitly add one or more recurrence dates with
410 addMonthlyDate or a recurrence position in the month (e.g. first
411 monday) using addMonthlyPos.
412 To set an end date use the method setEndDate and to set the number
413 of occurrences use setDuration.
414
415 This method clears all recurrence rules and adds one rule with a
416 monthly recurrence. All other recurrence components (recurrence
417 date/times, exception date/times and exception rules) are not
418 modified.
419 * @param freq the frequency to recur, e.g. 3 for every third month.
420 */
421 void setMonthly(int freq);
422
423 /** Adds a position (e.g. first monday) to the monthly recurrence rule.
424 * @param pos the position in the month for the recurrence, with valid
425 * values being 1-5 (5 weeks max in a month).
426 * @param days the days for the position to recur on (bit 0 = Monday).
427 * Example: pos = 2, and bits 0 and 2 are set in days:
428 * the rule is to repeat every 2nd Monday and Wednesday in the month.
429 */
430 void addMonthlyPos(short pos, const QBitArray &days);
431 void addMonthlyPos(short pos, ushort day);
432
433 /** Adds a date (e.g. the 15th of each month) to the monthly day
434 * recurrence list.
435 * @param day the date in the month to recur.
436 */
437 void addMonthlyDate(short day);
438
439 /** Returns list of day positions in months. */
440 QList<RecurrenceRule::WDayPos> monthPositions() const;
441
442 /** Returns list of day numbers of a month. */
443 // Emulate old behavior
444 QList<int> monthDays() const;
445
446 /** Sets an event to recur yearly. By default, this will recur every year
447 * on the same date (e.g. every year on April 15 if the start date was
448 * April 15).
449 * The day of the year can be specified with addYearlyDay().
450 * The day of the month can be specified with addYearlyByDate
451 * If both a month and a day ar specified with addYearlyMonth and
452 * addYearlyDay, the day is understood as day number within the month.
453 *
454 * A position (e.g. 3rd Sunday of year/month, or last Friday of year/month)
455 * can be specified with addYearlyPos. Again, if a month is specified,
456 * this position is understood as within that month, otherwise within
457 * the year.
458 *
459 * By default infinite recurrence is used. To set an end date use the
460 * method setEndDate and to set the number of occurrences use setDuration.
461
462 This method clears all recurrence rules and adds one rule with a
463 yearly recurrence. All other recurrence components (recurrence
464 date/times, exception date/times and exception rules) are not
465 modified.
466 * @param freq the frequency to recur, e.g. 3 for every third year.
467 */
468 void setYearly(int freq);
469
470 /** Adds day number of year within a yearly recurrence.
471 * By default infinite recurrence is used. To set an end date use the
472 * method setEndDate and to set the number of occurrences use setDuration.
473 * @param day the day of the year for the event. E.g. if day is 60, this
474 * means Feb 29 in leap years and March 1 in non-leap years.
475 */
476 void addYearlyDay(int day);
477
478 /** Adds date within a yearly recurrence. The month(s) for the recurrence
479 * can be specified with addYearlyMonth(), otherwise the month of the
480 * start date is used.
481 *
482 * By default infinite recurrence is used. To set an end date use the
483 * method setEndDate and to set the number of occurrences use setDuration.
484 * @param date the day of the month for the event
485 */
486 void addYearlyDate(int date);
487
488 /** Adds month in yearly recurrence. You can specify specific day numbers
489 * within the months (by calling addYearlyDate()) or specific day positions
490 * within the month (by calling addYearlyPos).
491 * @param _rNum the month in which the event shall recur.
492 */
493 void addYearlyMonth(short _rNum);
494
495 /** Adds position within month/year within a yearly recurrence. If months
496 * are specified (via addYearlyMonth()), the parameters are understood as
497 * position within these months, otherwise within the year.
498 *
499 * By default infinite recurrence is used.
500 * To set an end date use the method setEndDate and to set the number
501 * of occurrences use setDuration.
502 * @param pos the position in the month/year for the recurrence, with valid
503 * values being 1 to 53 and -1 to -53 (53 weeks max in a year).
504 * @param days the days for the position to recur on (bit 0 = Monday).
505 * Example: pos = 2, and bits 0 and 2 are set in days
506 * If months are specified (via addYearlyMonth), e.g. March, the rule is
507 * to repeat every year on the 2nd Monday and Wednesday of March.
508 * If no months are specified, the fule is to repeat every year on the
509 * 2nd Monday and Wednesday of the year.
510 */
511 void addYearlyPos(short pos, const QBitArray &days);
512
513 /** Returns the day numbers within a yearly recurrence.
514 * @return the days of the year for the event. E.g. if the list contains
515 * 60, this means the recurrence happens on day 60 of the year, i.e.
516 * on Feb 29 in leap years and March 1 in non-leap years.
517 */
518 QList<int> yearDays() const;
519
520 /** Returns the dates within a yearly recurrence.
521 * @return the days of the month for the event. E.g. if the list contains
522 * 13, this means the recurrence happens on the 13th of the month.
523 * The months for the recurrence can be obtained through
524 * yearlyMonths(). If this list is empty, the month of the start
525 * date is used.
526 */
527 QList<int> yearDates() const;
528
529 /** Returns the months within a yearly recurrence.
530 * @return the months for the event. E.g. if the list contains
531 * 11, this means the recurrence happens in November.
532 * The days for the recurrence can be obtained either through
533 * yearDates() if they are given as dates within the month or
534 * through yearlyPositions() if they are given as positions within the
535 * month. If none is specified, the date of the start date is used.
536 */
537 QList<int> yearMonths() const;
538
539 /** Returns the positions within a yearly recurrence.
540 * @return the positions for the event, either within a month (if months
541 * are set through addYearlyMonth()) or within the year.
542 * E.g. if the list contains {Pos=3, Day=5}, this means the third
543 * friday. If a month is set this position is understoodas third
544 * Friday in the given months, otherwise as third Friday of the
545 * year.
546 */
547 /** Returns list of day positions in months, for a recursYearlyPos recurrence rule. */
548 QList<RecurrenceRule::WDayPos> yearPositions() const;
549
550 /** Upper date limit for recurrences */
551 static const QDate MAX_DATE;
552
553 /**
554 Debug output.
555 */
556 void dump() const;
557
558 // RRULE
559 RecurrenceRule::List rRules() const;
560 /**
561 Add a recurrence rule to the recurrence.
562 @param rrule the recurrence rule to add
563 */
564 void addRRule(RecurrenceRule *rrule);
565
566 /**
567 Remove a recurrence rule from the recurrence.
568 @p rrule is not deleted; it is the responsibility of the caller
569 to ensure that it is deleted.
570 @param rrule the recurrence rule to remove
571 */
572 void removeRRule(RecurrenceRule *rrule);
573
574 /**
575 Remove a recurrence rule from the recurrence and delete it.
576 @param rrule the recurrence rule to remove
577 */
578 void deleteRRule(RecurrenceRule *rrule);
579
580 // EXRULE
581 RecurrenceRule::List exRules() const;
582
583 /**
584 Add an exception rule to the recurrence.
585 @param exrule the exception rule to add
586 */
587 void addExRule(RecurrenceRule *exrule);
588
589 /**
590 Remove an exception rule from the recurrence.
591 @p exrule is not deleted; it is the responsibility of the caller
592 to ensure that it is deleted.
593 @param exrule the exception rule to remove
594 */
595 void removeExRule(RecurrenceRule *exrule);
596
597 /**
598 Remove an exception rule from the recurrence and delete it.
599 @param exrule the exception rule to remove
600 */
601 void deleteExRule(RecurrenceRule *exrule);
602
603 // RDATE
604 DateTimeList rDateTimes() const;
605 DateList rDates() const;
606 void setRDateTimes(const DateTimeList &rdates);
607 void setRDates(const DateList &rdates);
608 void addRDateTime(const KDateTime &rdate);
609 void addRDate(const QDate &rdate);
610
611 // ExDATE
612 DateTimeList exDateTimes() const;
613 DateList exDates() const;
614 void setExDateTimes(const DateTimeList &exdates);
615 void setExDates(const DateList &exdates);
616 void addExDateTime(const KDateTime &exdate);
617 void addExDate(const QDate &exdate);
618
619 RecurrenceRule *defaultRRule(bool create = false) const;
620 RecurrenceRule *defaultRRuleConst() const;
621 void updated();
622
623 /**
624 Installs an observer. Whenever some setting of this recurrence
625 object is changed, the recurrenceUpdated( Recurrence* ) method
626 of each observer will be called to inform it of changes.
627 @param observer the Recurrence::Observer-derived object, which
628 will be installed as an observer of this object.
629 */
630 void addObserver(RecurrenceObserver *observer);
631 /**
632 Removes an observer that was added with addObserver. If the
633 given object was not an observer, it does nothing.
634 @param observer the Recurrence::Observer-derived object to
635 be removed from the list of observers of this object.
636 */
637 void removeObserver(RecurrenceObserver *observer);
638
639 void recurrenceChanged(RecurrenceRule *);
640
641protected:
642 RecurrenceRule *setNewRecurrenceType(RecurrenceRule::PeriodType type, int freq);
643
644private:
645 //@cond PRIVATE
646 class Private;
647 Private *const d;
648 //@endcond
649
650 friend KCALCORE_EXPORT QDataStream& operator<<(QDataStream &out, KCalCore::Recurrence *);
651 friend KCALCORE_EXPORT QDataStream& operator>>(QDataStream &in, KCalCore::Recurrence *);
652};
653
654/**
655 * Recurrence serializer and deserializer.
656 * @since 4.12
657 */
658KCALCORE_EXPORT QDataStream& operator<<(QDataStream &out, KCalCore::Recurrence *);
659KCALCORE_EXPORT QDataStream& operator>>(QDataStream &in, KCalCore::Recurrence *);
660
661}
662
663#endif
664