24#include "recurrence.h"
28#include <QtCore/QBitArray>
29#include <QtCore/QTime>
34class KCalCore::Recurrence::Private
44 Private(
const Private &
p)
56 bool operator==(
const Private &
p)
const;
74bool Recurrence::Private::operator==(
const Recurrence::Private &
p)
const
91 if (end !=
p.mRRules.count()) {
94 for (
i = 0;
i < end; ++
i) {
100 if (end !=
p.mExRules.count()) {
103 for (
i = 0;
i < end; ++
i) {
122 for (
i = 0, end =
r.d->mRRules.count();
i < end; ++
i) {
124 d->mRRules.append(
rule);
125 rule->addObserver(
this);
127 for (
i = 0, end =
r.d->mExRules.count();
i < end; ++
i) {
129 d->mExRules.append(
rule);
130 rule->addObserver(
this);
143 return *
d == *recurrence.d;
149 if (&recurrence ==
this) {
173 return d->mStartDateTime;
183 if (
d->mRecurReadOnly ||
allDay ==
d->mAllDay) {
188 for (
int i = 0, end =
d->mRRules.count();
i < end; ++
i) {
191 for (
int i = 0, end =
d->mExRules.count();
i < end; ++
i) {
199 if (
d->mRRules.isEmpty()) {
200 if (!
create ||
d->mRecurReadOnly) {
208 return d->mRRules[0];
214 return d->mRRules.isEmpty() ? 0 :
d->mRRules[0];
217void Recurrence::updated()
220 d->mCachedType = rMax;
221 for (
int i = 0, end =
d->mObservers.count();
i < end; ++
i) {
222 if (
d->mObservers[
i]) {
223 d->mObservers[
i]->recurrenceUpdated(
this);
230 return !
d->mRRules.isEmpty() || !
d->mRDates.isEmpty() || !
d->mRDateTimes.isEmpty();
235 if (
d->mCachedType == rMax) {
238 return d->mCachedType;
249 if (!rrule->bySetPos().isEmpty() ||
250 !rrule->bySeconds().isEmpty() ||
251 !rrule->byWeekNumbers().isEmpty()) {
257 if (!rrule->byMinutes().isEmpty() || !rrule->byHours().isEmpty()) {
266 if ((!rrule->byYearDays().isEmpty() && type != RecurrenceRule::rYearly) ||
267 (!rrule->byMonths().isEmpty() && type != RecurrenceRule::rYearly)) {
270 if (!rrule->byDays().isEmpty()) {
271 if (type != RecurrenceRule::rYearly &&
272 type != RecurrenceRule::rMonthly &&
273 type != RecurrenceRule::rWeekly) {
279 case RecurrenceRule::rNone:
281 case RecurrenceRule::rMinutely:
283 case RecurrenceRule::rHourly:
285 case RecurrenceRule::rDaily:
287 case RecurrenceRule::rWeekly:
289 case RecurrenceRule::rMonthly:
291 if (rrule->byDays().isEmpty()) {
293 }
else if (rrule->byMonthDays().isEmpty()) {
299 case RecurrenceRule::rYearly:
305 if (!rrule->byDays().isEmpty()) {
307 if (rrule->byMonthDays().isEmpty() && rrule->byYearDays().isEmpty()) {
312 }
else if (!rrule->byYearDays().isEmpty()) {
314 if (rrule->byMonths().isEmpty() && rrule->byMonthDays().isEmpty()) {
338 if (
d->mExDates.containsSorted(
qd)) {
347 for (
i = 0, end =
d->mExRules.count();
i < end; ++
i) {
348 if (
d->mExRules[
i]->recursOn(
qd, timeSpec)) {
354 if (
d->mRDates.containsSorted(
qd)) {
360 for (
i = 0, end =
d->mRDateTimes.count();
i < end && !
recurs; ++
i) {
361 recurs = (
d->mRDateTimes[
i].toTimeSpec(timeSpec).date() ==
qd);
363 for (
i = 0, end =
d->mRRules.count();
i < end && !
recurs; ++
i) {
364 recurs =
d->mRRules[
i]->recursOn(
qd, timeSpec);
373 for (
i = 0, end =
d->mExDateTimes.count();
i < end && !
exon; ++
i) {
374 exon = (
d->mExDateTimes[
i].toTimeSpec(timeSpec).date() ==
qd);
377 for (
i = 0, end =
d->mExRules.count();
i < end && !
exon; ++
i) {
378 exon =
d->mExRules[
i]->recursOn(
qd, timeSpec);
401 if (
d->mExDateTimes.containsSorted(
dtrecur) ||
402 d->mExDates.containsSorted(
dtrecur.date())) {
406 for (
i = 0, end =
d->mExRules.count();
i < end; ++
i) {
416 for (
i = 0, end =
d->mRRules.count();
i < end; ++
i) {
432 if (!
d->mRDates.isEmpty()) {
435 if (!
d->mRDateTimes.isEmpty()) {
436 dts <<
d->mRDateTimes.last();
438 for (
int i = 0, end =
d->mRRules.count();
i < end; ++
i) {
456 return end.isValid() ? end.date() :
QDate();
470 if (
d->mRecurReadOnly) {
484 return rrule ? rrule->
duration() : 0;
501 if (
d->mRecurReadOnly) {
515 if (
d->mRecurReadOnly) {
519 d->mStartDateTime =
d->mStartDateTime.toTimeSpec(
oldSpec);
520 d->mStartDateTime.setTimeSpec(
newSpec);
523 for (
i = 0, end =
d->mRDateTimes.count();
i < end; ++
i) {
524 d->mRDateTimes[
i] =
d->mRDateTimes[
i].toTimeSpec(
oldSpec);
527 for (
i = 0, end =
d->mExDateTimes.count();
i < end; ++
i) {
528 d->mExDateTimes[
i] =
d->mExDateTimes[
i].toTimeSpec(
oldSpec);
531 for (
i = 0, end =
d->mRRules.count();
i < end; ++
i) {
534 for (
i = 0, end =
d->mExRules.count();
i < end; ++
i) {
541 if (
d->mRecurReadOnly) {
551 if (
d->mRecurReadOnly) {
559 d->mRDateTimes.clear();
561 d->mExDateTimes.clear();
562 d->mCachedType = rMax;
573 return d->mRecurReadOnly;
578 return d->mStartDateTime.date();
583 if (
d->mRecurReadOnly) {
586 d->mStartDateTime = start;
590 for (
i = 0, end =
d->mRRules.count();
i < end; ++
i) {
591 d->mRRules[
i]->setStartDt(start);
593 for (
i = 0, end =
d->mExRules.count();
i < end; ++
i) {
594 d->mExRules[
i]->setStartDt(start);
609 if (
d->mRecurReadOnly ||
freq <= 0) {
625 return rrule ? rrule->weekStart() : 1;
635 QList<RecurrenceRule::WDayPos>
bydays = rrule->byDays();
636 for (
int i = 0;
i <
bydays.size(); ++
i) {
652 return rrule->byMonthDays();
670 return rrule ? rrule->byYearDays() :
QList<int>();
681 return rrule ? rrule->byMonths() :
QList<int>();
691 if (
d->mRecurReadOnly ||
freq <= 0) {
702 rrule->setRecurrenceType(type);
710 if (setNewRecurrenceType(RecurrenceRule::rMinutely,
_rFreq)) {
717 if (setNewRecurrenceType(RecurrenceRule::rHourly,
_rFreq)) {
724 if (setNewRecurrenceType(RecurrenceRule::rDaily,
_rFreq)) {
752 if (setNewRecurrenceType(RecurrenceRule::rMonthly,
freq)) {
760 if (
d->mRecurReadOnly || pos > 53 || pos < -53) {
769 QList<RecurrenceRule::WDayPos>
positions = rrule->byDays();
771 for (
int i = 0;
i < 7; ++
i) {
772 if (
days.testBit(
i)) {
789 if (
d->mRecurReadOnly || pos > 53 || pos < -53) {
797 QList<RecurrenceRule::WDayPos>
positions = rrule->byDays();
809 if (
d->mRecurReadOnly || day > 31 || day < -31) {
818 QList<int>
monthDays = rrule->byMonthDays();
828 if (setNewRecurrenceType(RecurrenceRule::rYearly,
freq)) {
841 QList<int>
days = rrule->byYearDays();
842 if (!
days.contains(day)) {
844 rrule->setByYearDays(
days);
873 QList<int>
months = rrule->byMonths();
876 rrule->setByMonths(
months);
888 if (
d->mExDates.containsSorted(
date)) {
895 for (
i = 0, end =
d->mExRules.count();
i < end; ++
i) {
896 if (
d->mExRules[
i]->recursOn(
date, timeSpec)) {
908 for (
i = 0, end =
d->mRDateTimes.count();
i < end; ++
i) {
909 dt =
d->mRDateTimes[
i].toTimeSpec(timeSpec);
917 for (
i = 0, end =
d->mRRules.count();
i < end; ++
i) {
918 times +=
d->mRRules[
i]->recurTimesOn(
date, timeSpec);
924 for (
i = 0, end =
d->mExDateTimes.count();
i < end; ++
i) {
925 dt =
d->mExDateTimes[
i].toTimeSpec(timeSpec);
934 for (
i = 0, end =
d->mExRules.count();
i < end; ++
i) {
941 for (
i = 0, end =
extimes.count();
i < end; ++
i) {
954 for (
i = 0, count =
d->mRRules.count();
i < count; ++
i) {
955 times +=
d->mRRules[
i]->timesInInterval(start, end);
959 for (
i = 0, count =
d->mRDateTimes.count();
i < count; ++
i) {
960 if (
d->mRDateTimes[
i] >= start &&
d->mRDateTimes[
i] <= end) {
967 for (
i = 0, count =
d->mRDates.count();
i < count; ++
i) {
968 kdt.setDate(
d->mRDates[
i]);
969 if (
kdt >= start &&
kdt <= end) {
979 if ((!
d->mRDates.isEmpty() || !
d->mRDateTimes.isEmpty()) &&
980 d->mRRules.isEmpty() &&
981 start <=
d->mStartDateTime &&
982 end >=
d->mStartDateTime) {
983 times +=
d->mStartDateTime;
991 for (
i = 0, count =
d->mExDates.count();
i < count &&
idt <
enddt; ++
i) {
1001 for (
i = 0, count =
d->mExRules.count();
i < count; ++
i) {
1002 extimes +=
d->mExRules[
i]->timesInInterval(start, end);
1008 for (
i = 0, count =
extimes.count();
i < count; ++
i) {
1027 while (
loop < 1000) {
1047 int i =
d->mRDateTimes.findGT(
nextDT);
1053 for (
i = 0, end =
d->mRDates.count();
i < end; ++
i) {
1054 kdt.setDate(
d->mRDates[
i]);
1062 for (
i = 0, end =
d->mRRules.count();
i < end; ++
i) {
1071 if (
dates.isEmpty()) {
1077 if (!
d->mExDates.containsSorted(
nextDT.date()) &&
1078 !
d->mExDateTimes.containsSorted(
nextDT)) {
1080 for (
i = 0, end =
d->mExRules.count();
i < end; ++
i) {
1100 while (
loop < 1000) {
1117 int i =
d->mRDateTimes.findLT(
prevDT);
1123 for (
i =
d->mRDates.count(); --
i >= 0;) {
1124 kdt.setDate(
d->mRDates[
i]);
1133 for (
i = 0, end =
d->mRRules.count();
i < end; ++
i) {
1142 if (
dates.isEmpty()) {
1148 if (!
d->mExDates.containsSorted(
prevDT.date()) &&
1149 !
d->mExDateTimes.containsSorted(
prevDT)) {
1151 for (
i = 0, end =
d->mExRules.count();
i < end; ++
i) {
1166RecurrenceRule::List Recurrence::rRules()
const
1173 if (
d->mRecurReadOnly || !rrule) {
1178 d->mRRules.append(rrule);
1185 if (
d->mRecurReadOnly) {
1189 d->mRRules.removeAll(rrule);
1196 if (
d->mRecurReadOnly) {
1200 d->mRRules.removeAll(rrule);
1205RecurrenceRule::List Recurrence::exRules()
const
1212 if (
d->mRecurReadOnly || !
exrule) {
1216 exrule->setAllDay(
d->mAllDay);
1218 exrule->addObserver(
this);
1224 if (
d->mRecurReadOnly) {
1228 d->mExRules.removeAll(
exrule);
1229 exrule->removeObserver(
this);
1235 if (
d->mRecurReadOnly) {
1239 d->mExRules.removeAll(
exrule);
1246 return d->mRDateTimes;
1251 if (
d->mRecurReadOnly) {
1262 if (
d->mRecurReadOnly) {
1266 d->mRDateTimes.insertSorted(
rdate);
1277 if (
d->mRecurReadOnly) {
1288 if (
d->mRecurReadOnly) {
1292 d->mRDates.insertSorted(
rdate);
1298 return d->mExDateTimes;
1303 if (
d->mRecurReadOnly) {
1313 if (
d->mRecurReadOnly) {
1317 d->mExDateTimes.insertSorted(
exdate);
1321DateList Recurrence::exDates()
const
1328 if (
d->mRecurReadOnly) {
1339 if (
d->mRecurReadOnly) {
1343 d->mExDates.insertSorted(
exdate);
1359 int count =
d->mRRules.count();
1360 kDebug() <<
" -)" << count <<
"RRULEs:";
1361 for (
i = 0;
i < count; ++
i) {
1362 kDebug() <<
" -) RecurrenceRule: ";
1363 d->mRRules[
i]->dump();
1365 count =
d->mExRules.count();
1366 kDebug() <<
" -)" << count <<
"EXRULEs:";
1367 for (
i = 0;
i < count; ++
i) {
1368 kDebug() <<
" -) ExceptionRule :";
1369 d->mExRules[
i]->dump();
1372 count =
d->mRDates.count();
1373 kDebug() <<
endl <<
" -)" << count <<
"Recurrence Dates:";
1374 for (
i = 0;
i < count; ++
i) {
1377 count =
d->mRDateTimes.count();
1378 kDebug() <<
endl <<
" -)" << count <<
"Recurrence Date/Times:";
1379 for (
i = 0;
i < count; ++
i) {
1380 kDebug() <<
" " <<
d->mRDateTimes[
i].dateTime();
1382 count =
d->mExDates.count();
1383 kDebug() <<
endl <<
" -)" << count <<
"Exceptions Dates:";
1384 for (
i = 0;
i < count; ++
i) {
1387 count =
d->mExDateTimes.count();
1388 kDebug() <<
endl <<
" -)" << count <<
"Exception Date/Times:";
1389 for (
i = 0;
i < count; ++
i) {
1390 kDebug() <<
" " <<
d->mExDateTimes[
i].dateTime();
1394Recurrence::RecurrenceObserver::~RecurrenceObserver()
1403 out <<
r->d->mRDateTimes <<
r->d->mExDateTimes
1404 <<
r->d->mRDates <<
r->d->mStartDateTime <<
r->d->mCachedType
1405 <<
r->d->mAllDay <<
r->d->mRecurReadOnly <<
r->d->mExDates
1406 <<
r->d->mExRules.count() <<
r->d->mRRules.count();
1427 in >>
r->d->mRDateTimes >>
r->d->mExDateTimes
1428 >>
r->d->mRDates >>
r->d->mStartDateTime >>
r->d->mCachedType
1429 >>
r->d->mAllDay >>
r->d->mRecurReadOnly >>
r->d->mExDates
1432 r->d->mExRules.clear();
1433 r->d->mRRules.clear();
1437 rule->addObserver(
r);
1439 r->d->mExRules.append(
rule);
1444 rule->addObserver(
r);
1446 r->d->mRRules.append(
rule);
structure for describing the n-th weekday of the month/year.
This class represents a recurrence rule for a calendar incidence.
void setAllDay(bool allDay)
Sets whether the dtstart is all-day (i.e.
PeriodType
enum for describing the frequency how an event recurs, if at all.
void setDuration(int duration)
Sets the total number of times the event is to occur, including both the first and last.
void setFrequency(int freq)
Sets the recurrence frequency, in terms of the recurrence time period type.
uint frequency() const
Returns the recurrence frequency, in terms of the recurrence time period type.
int duration() const
Returns -1 if the event recurs infinitely, 0 if the end date is set, otherwise the total number of re...
int durationTo(const KDateTime &dt) const
Returns the number of recurrences up to and including the date/time specified.
void setEndDt(const KDateTime &endDateTime)
Sets the date and time of the last recurrence.
void addObserver(RuleObserver *observer)
Installs an observer.
void setStartDt(const KDateTime &start)
Sets the recurrence start date/time.
void removeObserver(RuleObserver *observer)
Removes an observer that was added with addObserver.
This class represents a recurrence rule for a calendar incidence.
ushort recurrenceType() const
Returns the event's recurrence status.
void removeRRule(RecurrenceRule *rrule)
Remove a recurrence rule from the recurrence.
void setEndDateTime(const KDateTime &endDateTime)
Sets the date and time of the last recurrence.
QList< RecurrenceRule::WDayPos > yearPositions() const
Returns the positions within a yearly recurrence.
void setRecurReadOnly(bool readOnly)
Set if recurrence is read-only or can be changed.
QList< int > yearDates() const
Returns the dates within a yearly recurrence.
void shiftTimes(const KDateTime::Spec &oldSpec, const KDateTime::Spec &newSpec)
Shift the times of the recurrence so that they appear at the same clock time as before but in a new t...
int frequency() const
Returns frequency of recurrence, in terms of the recurrence time period type.
void addYearlyDay(int day)
Adds day number of year within a yearly recurrence.
void setYearly(int freq)
Sets an event to recur yearly.
void setWeekly(int freq, int weekStart=1)
Sets an event to recur weekly.
bool recurs() const
Returns whether the event recurs at all.
void setStartDateTime(const KDateTime &start)
Set start of recurrence.
Recurrence & operator=(const Recurrence &r)
Assignment operator.
void setMinutely(int freq)
Sets an event to recur minutely.
void setMonthly(int freq)
Sets an event to recur monthly.
bool recursAt(const KDateTime &dt) const
Returns true if the date/time specified is one at which the event will recur.
KDateTime getPreviousDateTime(const KDateTime &afterDateTime) const
Returns the date and time of the last previous recurrence, before the specified date/time.
bool recursOn(const QDate &date, const KDateTime::Spec &timeSpec) const
Returns true if the date specified is one on which the event will recur.
void setFrequency(int freq)
Sets the frequency of recurrence, in terms of the recurrence time period type.
QList< int > monthDays() const
Returns list of day numbers of a month.
KDateTime endDateTime() const
Returns the date/time of the last recurrence.
void deleteExRule(RecurrenceRule *exrule)
Remove an exception rule from the recurrence and delete it.
void addYearlyMonth(short _rNum)
Adds month in yearly recurrence.
void deleteRRule(RecurrenceRule *rrule)
Remove a recurrence rule from the recurrence and delete it.
bool recurReadOnly() const
Returns true if the recurrence is read-only, or false if it can be changed.
void removeObserver(RecurrenceObserver *observer)
Removes an observer that was added with addObserver.
bool allDay() const
Set whether the recurrence has no time, just a date.
QDate startDate() const
Return the start date/time of the recurrence.
void addMonthlyPos(short pos, const QBitArray &days)
Adds a position (e.g.
void addObserver(RecurrenceObserver *observer)
Installs an observer.
void addYearlyDate(int date)
Adds date within a yearly recurrence.
QBitArray days() const
Returns week day mask (bit 0 = Monday).
void removeExRule(RecurrenceRule *exrule)
Remove an exception rule from the recurrence.
void addYearlyPos(short pos, const QBitArray &days)
Adds position within month/year within a yearly recurrence.
void setAllDay(bool allDay)
Sets whether the dtstart is a all-day (i.e.
void addRRule(RecurrenceRule *rrule)
Add a recurrence rule to the recurrence.
void setDaily(int freq)
Sets an event to recur daily.
void unsetRecurs()
Removes all recurrence rules.
KDateTime startDateTime() const
Return the start date/time of the recurrence (Time for all-day recurrences will be 0:00).
void dump() const
Debug output.
void addExRule(RecurrenceRule *exrule)
Add an exception rule to the recurrence.
void setEndDate(const QDate &endDate)
Sets the date of the last recurrence.
int weekStart() const
Returns the first day of the week.
QList< int > yearMonths() const
Returns the months within a yearly recurrence.
int durationTo(const KDateTime &dt) const
Returns the number of recurrences up to and including the date/time specified.
int duration() const
Returns -1 if the event recurs infinitely, 0 if the end date is set, otherwise the total number of re...
void setHourly(int freq)
Sets an event to recur hourly.
void clear()
Removes all recurrence and exception rules and dates.
void addMonthlyDate(short day)
Adds a date (e.g.
DateTimeList timesInInterval(const KDateTime &start, const KDateTime &end) const
Returns a list of all the times at which the recurrence will occur between two specified times.
KDateTime getNextDateTime(const KDateTime &preDateTime) const
Returns the date and time of the next recurrence, after the specified date/time.
QList< int > yearDays() const
Returns the day numbers within a yearly recurrence.
bool operator==(const Recurrence &r) const
Comparison operator for equality.
void addWeeklyDays(const QBitArray &days)
Adds days to the weekly day recurrence list.
QList< RecurrenceRule::WDayPos > monthPositions() const
Returns list of day positions in months.
QDate endDate() const
Returns the date of the last recurrence.
TimeList recurTimesOn(const QDate &date, const KDateTime::Spec &timeSpec) const
Returns a list of the times on the specified date at which the recurrence will occur.
void setDuration(int duration)
Sets the total number of times the event is to occur, including both the first and last.
Recurrence()
Constructs an empty recurrence.
A QList which can be sorted.
void sortUnique()
Sort the list.
KCALCORE_EXPORT QDataStream & operator>>(QDataStream &in, const KCalCore::Alarm::Ptr &)
Alarm deserializer.
KCALCORE_EXPORT QDataStream & operator<<(QDataStream &out, const KCalCore::Alarm::Ptr &)
Alarm serializer.
static uint qHash(const KDateTime &dt)
Private class that helps to provide binary compatibility between releases.