24 #include "recurrence.h"
28 #include <QtCore/QBitArray>
29 #include <QtCore/QTime>
31 using namespace KCalCore;
34 class KCalCore::Recurrence::Private
44 Private(
const Private &p)
45 : mRDateTimes(p.mRDateTimes),
47 mExDateTimes(p.mExDateTimes),
49 mStartDateTime(p.mStartDateTime),
50 mCachedType(p.mCachedType),
52 mRecurReadOnly(p.mRecurReadOnly)
56 bool operator==(
const Private &p)
const;
58 RecurrenceRule::List mExRules;
59 RecurrenceRule::List mRRules;
64 KDateTime mStartDateTime;
65 QList<RecurrenceObserver*> mObservers;
68 mutable ushort mCachedType;
74 bool Recurrence::Private::operator==(
const Recurrence::Private &p)
const
76 kDebug() << mStartDateTime << p.mStartDateTime;
78 if ((mStartDateTime != p.mStartDateTime &&
79 (mStartDateTime.isValid() || p.mStartDateTime.isValid())) ||
80 mAllDay != p.mAllDay ||
81 mRecurReadOnly != p.mRecurReadOnly ||
82 mExDates != p.mExDates ||
83 mExDateTimes != p.mExDateTimes ||
84 mRDates != p.mRDates ||
85 mRDateTimes != p.mRDateTimes) {
92 int end = mRRules.count();
93 if (end != p.mRRules.count()) {
96 for (i = 0; i < end; ++i) {
97 if (*mRRules[i] != *p.mRRules[i]) {
101 end = mExRules.count();
102 if (end != p.mExRules.count()) {
105 for (i = 0; i < end; ++i) {
106 if (*mExRules[i] != *p.mExRules[i]) {
124 for (i = 0, end = r.d->mRRules.count(); i < end; ++i) {
126 d->mRRules.append(rule);
129 for (i = 0, end = r.d->mExRules.count(); i < end; ++i) {
131 d->mExRules.append(rule);
138 qDeleteAll(d->mExRules);
139 qDeleteAll(d->mRRules);
145 return *d == *recurrence.d;
151 if (&recurrence ==
this) {
161 if (!d->mObservers.contains(observer)) {
162 d->mObservers.append(observer);
168 if (d->mObservers.contains(observer)) {
169 d->mObservers.removeAll(observer);
175 return d->mStartDateTime;
185 if (d->mRecurReadOnly || allDay == d->mAllDay) {
190 for (
int i = 0, end = d->mRRules.count(); i < end; ++i) {
191 d->mRRules[i]->setAllDay(allDay);
193 for (
int i = 0, end = d->mExRules.count(); i < end; ++i) {
194 d->mExRules[i]->setAllDay(allDay);
201 if (d->mRRules.isEmpty()) {
202 if (!create || d->mRecurReadOnly) {
210 return d->mRRules[0];
216 return d->mRRules.isEmpty() ? 0 : d->mRRules[0];
219 void Recurrence::updated()
222 d->mCachedType = rMax;
223 for (
int i = 0, end = d->mObservers.count(); i < end; ++i) {
224 if (d->mObservers[i]) {
225 d->mObservers[i]->recurrenceUpdated(
this);
232 return !d->mRRules.isEmpty() || !d->mRDates.isEmpty() || !d->mRDateTimes.isEmpty();
237 if (d->mCachedType == rMax) {
240 return d->mCachedType;
251 if (!rrule->bySetPos().isEmpty() ||
252 !rrule->bySeconds().isEmpty() ||
253 !rrule->byWeekNumbers().isEmpty()) {
259 if (!rrule->byMinutes().isEmpty() || !rrule->byHours().isEmpty()) {
268 if ((!rrule->byYearDays().isEmpty() && type != RecurrenceRule::rYearly) ||
269 (!rrule->byMonths().isEmpty() && type != RecurrenceRule::rYearly)) {
272 if (!rrule->byDays().isEmpty()) {
273 if (type != RecurrenceRule::rYearly &&
274 type != RecurrenceRule::rMonthly &&
275 type != RecurrenceRule::rWeekly) {
281 case RecurrenceRule::rNone:
283 case RecurrenceRule::rMinutely:
285 case RecurrenceRule::rHourly:
287 case RecurrenceRule::rDaily:
289 case RecurrenceRule::rWeekly:
291 case RecurrenceRule::rMonthly:
293 if (rrule->byDays().isEmpty()) {
295 }
else if (rrule->byMonthDays().isEmpty()) {
301 case RecurrenceRule::rYearly:
307 if (!rrule->byDays().isEmpty()) {
309 if (rrule->byMonthDays().isEmpty() && rrule->byYearDays().isEmpty()) {
314 }
else if (!rrule->byYearDays().isEmpty()) {
316 if (rrule->byMonths().isEmpty() && rrule->byMonthDays().isEmpty()) {
335 if (KDateTime(qd, QTime(23, 59, 59), timeSpec) < d->mStartDateTime) {
340 if (d->mExDates.containsSorted(qd)) {
349 for (i = 0, end = d->mExRules.count(); i < end; ++i) {
350 if (d->mExRules[i]->recursOn(qd, timeSpec)) {
356 if (d->mRDates.containsSorted(qd)) {
362 for (i = 0, end = d->mRDateTimes.count(); i < end && !
recurs; ++i) {
363 recurs = (d->mRDateTimes[i].toTimeSpec(timeSpec).date() == qd);
365 for (i = 0, end = d->mRRules.count(); i < end && !
recurs; ++i) {
366 recurs = d->mRRules[i]->recursOn(qd, timeSpec);
375 for (i = 0, end = d->mExDateTimes.count(); i < end && !exon; ++i) {
376 exon = (d->mExDateTimes[i].toTimeSpec(timeSpec).date() == qd);
379 for (i = 0, end = d->mExRules.count(); i < end && !exon; ++i) {
380 exon = d->mExRules[i]->recursOn(qd, timeSpec);
393 return !timesForDay.isEmpty();
400 KDateTime dtrecur = dt.toTimeSpec(d->mStartDateTime.timeSpec());
403 if (d->mExDateTimes.containsSorted(dtrecur) ||
404 d->mExDates.containsSorted(dtrecur.date())) {
408 for (i = 0, end = d->mExRules.count(); i < end; ++i) {
409 if (d->mExRules[i]->recursAt(dtrecur)) {
415 if (
startDateTime() == dtrecur || d->mRDateTimes.containsSorted(dtrecur)) {
418 for (i = 0, end = d->mRRules.count(); i < end; ++i) {
419 if (d->mRRules[i]->recursAt(dtrecur)) {
434 if (!d->mRDates.isEmpty()) {
435 dts << KDateTime(d->mRDates.last(), QTime(0, 0, 0), d->mStartDateTime.timeSpec());
437 if (!d->mRDateTimes.isEmpty()) {
438 dts << d->mRDateTimes.last();
440 for (
int i = 0, end = d->mRRules.count(); i < end; ++i) {
441 KDateTime rl(d->mRRules[i]->endDt());
449 return dts.isEmpty() ? KDateTime() : dts.last();
458 return end.isValid() ? end.date() : QDate();
463 KDateTime dt(date, d->mStartDateTime.time(), d->mStartDateTime.timeSpec());
465 dt.setTime(QTime(23, 59, 59));
472 if (d->mRecurReadOnly) {
486 return rrule ? rrule->
duration() : 0;
493 return rrule ? rrule->
durationTo(datetime) : 0;
498 return durationTo(KDateTime(date, QTime(23, 59, 59), d->mStartDateTime.timeSpec()));
503 if (d->mRecurReadOnly) {
517 if (d->mRecurReadOnly) {
521 d->mStartDateTime = d->mStartDateTime.toTimeSpec(oldSpec);
522 d->mStartDateTime.setTimeSpec(newSpec);
525 for (i = 0, end = d->mRDateTimes.count(); i < end; ++i) {
526 d->mRDateTimes[i] = d->mRDateTimes[i].toTimeSpec(oldSpec);
527 d->mRDateTimes[i].setTimeSpec(newSpec);
529 for (i = 0, end = d->mExDateTimes.count(); i < end; ++i) {
530 d->mExDateTimes[i] = d->mExDateTimes[i].toTimeSpec(oldSpec);
531 d->mExDateTimes[i].setTimeSpec(newSpec);
533 for (i = 0, end = d->mRRules.count(); i < end; ++i) {
534 d->mRRules[i]->shiftTimes(oldSpec, newSpec);
536 for (i = 0, end = d->mExRules.count(); i < end; ++i) {
537 d->mExRules[i]->shiftTimes(oldSpec, newSpec);
543 if (d->mRecurReadOnly) {
546 qDeleteAll(d->mRRules);
553 if (d->mRecurReadOnly) {
556 qDeleteAll(d->mRRules);
558 qDeleteAll(d->mExRules);
561 d->mRDateTimes.clear();
563 d->mExDateTimes.clear();
564 d->mCachedType = rMax;
570 d->mRecurReadOnly = readOnly;
575 return d->mRecurReadOnly;
580 return d->mStartDateTime.date();
585 if (d->mRecurReadOnly) {
588 d->mStartDateTime = start;
592 for (i = 0, end = d->mRRules.count(); i < end; ++i) {
593 d->mRRules[i]->setStartDt(start);
595 for (i = 0, end = d->mExRules.count(); i < end; ++i) {
596 d->mExRules[i]->setStartDt(start);
611 if (d->mRecurReadOnly || freq <= 0) {
627 return rrule ? rrule->weekStart() : 1;
637 QList<RecurrenceRule::WDayPos> bydays = rrule->byDays();
638 for (
int i = 0; i < bydays.size(); ++i) {
639 if (bydays.at(i).pos() == 0) {
640 days.setBit(bydays.at(i).day() - 1);
654 return rrule->byMonthDays();
664 return rrule ? rrule->byDays() : QList<RecurrenceRule::WDayPos>();
672 return rrule ? rrule->byYearDays() : QList<int>();
683 return rrule ? rrule->byMonths() : QList<int>();
693 if (d->mRecurReadOnly || freq <= 0) {
697 qDeleteAll(d->mRRules);
704 rrule->setRecurrenceType(type);
712 if (setNewRecurrenceType(RecurrenceRule::rMinutely, _rFreq)) {
719 if (setNewRecurrenceType(RecurrenceRule::rHourly, _rFreq)) {
726 if (setNewRecurrenceType(RecurrenceRule::rDaily, _rFreq)) {
733 RecurrenceRule *rrule = setNewRecurrenceType(RecurrenceRule::rWeekly, freq);
737 rrule->setWeekStart(weekStart);
754 if (setNewRecurrenceType(RecurrenceRule::rMonthly, freq)) {
762 if (d->mRecurReadOnly || pos > 53 || pos < -53) {
770 bool changed =
false;
771 QList<RecurrenceRule::WDayPos> positions = rrule->byDays();
773 for (
int i = 0; i < 7; ++i) {
774 if (days.testBit(i)) {
776 if (!positions.contains(p)) {
783 rrule->setByDays(positions);
791 if (d->mRecurReadOnly || pos > 53 || pos < -53) {
799 QList<RecurrenceRule::WDayPos> positions = rrule->byDays();
802 if (!positions.contains(p)) {
804 rrule->setByDays(positions);
811 if (d->mRecurReadOnly || day > 31 || day < -31) {
820 QList<int>
monthDays = rrule->byMonthDays();
821 if (!monthDays.contains(day)) {
822 monthDays.append(day);
823 rrule->setByMonthDays(monthDays);
830 if (setNewRecurrenceType(RecurrenceRule::rYearly, freq)) {
843 QList<int>
days = rrule->byYearDays();
844 if (!days.contains(day)) {
846 rrule->setByYearDays(days);
866 if (d->mRecurReadOnly || month < 1 || month > 12) {
875 QList<int> months = rrule->byMonths();
876 if (!months.contains(month)) {
878 rrule->setByMonths(months);
890 if (d->mExDates.containsSorted(date)) {
897 for (i = 0, end = d->mExRules.count(); i < end; ++i) {
898 if (d->mExRules[i]->recursOn(date, timeSpec)) {
905 if (dt.date() == date) {
909 bool foundDate =
false;
910 for (i = 0, end = d->mRDateTimes.count(); i < end; ++i) {
911 dt = d->mRDateTimes[i].toTimeSpec(timeSpec);
912 if (dt.date() == date) {
915 }
else if (foundDate) {
919 for (i = 0, end = d->mRRules.count(); i < end; ++i) {
920 times += d->mRRules[i]->recurTimesOn(date, timeSpec);
926 for (i = 0, end = d->mExDateTimes.count(); i < end; ++i) {
927 dt = d->mExDateTimes[i].toTimeSpec(timeSpec);
928 if (dt.date() == date) {
929 extimes << dt.time();
931 }
else if (foundDate) {
936 for (i = 0, end = d->mExRules.count(); i < end; ++i) {
937 extimes += d->mExRules[i]->recurTimesOn(date, timeSpec);
943 for (i = 0, end = extimes.count(); i < end; ++i) {
956 for (i = 0, count = d->mRRules.count(); i < count; ++i) {
957 times += d->mRRules[i]->timesInInterval(start, end);
961 for (i = 0, count = d->mRDateTimes.count(); i < count; ++i) {
962 if (d->mRDateTimes[i] >= start && d->mRDateTimes[i] <= end) {
963 times += d->mRDateTimes[i];
968 KDateTime kdt(d->mStartDateTime);
969 for (i = 0, count = d->mRDates.count(); i < count; ++i) {
970 kdt.setDate(d->mRDates[i]);
971 if (kdt >= start && kdt <= end) {
981 if ((!d->mRDates.isEmpty() || !d->mRDateTimes.isEmpty()) &&
982 d->mRRules.isEmpty() &&
983 start <= d->mStartDateTime &&
984 end >= d->mStartDateTime) {
985 times += d->mStartDateTime;
992 int enddt = times.count();
993 for (i = 0, count = d->mExDates.count(); i < count && idt < enddt; ++i) {
994 while (idt < enddt && times[idt].date() < d->mExDates[i]) {
997 while (idt < enddt && times[idt].date() == d->mExDates[i]) {
1003 for (i = 0, count = d->mExRules.count(); i < count; ++i) {
1004 extimes += d->mExRules[i]->timesInInterval(start, end);
1006 extimes += d->mExDateTimes;
1010 for (i = 0, count = extimes.count(); i < count; ++i) {
1022 KDateTime nextDT = preDateTime;
1029 while (loop < 1000) {
1049 int i = d->mRDateTimes.findGT(nextDT);
1051 dates << d->mRDateTimes[i];
1055 for (i = 0, end = d->mRDates.count(); i < end; ++i) {
1056 kdt.setDate(d->mRDates[i]);
1064 for (i = 0, end = d->mRRules.count(); i < end; ++i) {
1065 KDateTime dt = d->mRRules[i]->getNextDate(nextDT);
1073 if (dates.isEmpty()) {
1076 nextDT = dates.first();
1079 if (!d->mExDates.containsSorted(nextDT.date()) &&
1080 !d->mExDateTimes.containsSorted(nextDT)) {
1081 bool allowed =
true;
1082 for (i = 0, end = d->mExRules.count(); i < end; ++i) {
1083 allowed = allowed && !(d->mExRules[i]->recursAt(nextDT));
1097 KDateTime prevDT = afterDateTime;
1102 while (loop < 1000) {
1119 int i = d->mRDateTimes.findLT(prevDT);
1121 dates << d->mRDateTimes[i];
1125 for (i = d->mRDates.count(); --i >= 0;) {
1126 kdt.setDate(d->mRDates[i]);
1135 for (i = 0, end = d->mRRules.count(); i < end; ++i) {
1136 KDateTime dt = d->mRRules[i]->getPreviousDate(prevDT);
1144 if (dates.isEmpty()) {
1147 prevDT = dates.last();
1150 if (!d->mExDates.containsSorted(prevDT.date()) &&
1151 !d->mExDateTimes.containsSorted(prevDT)) {
1152 bool allowed =
true;
1153 for (i = 0, end = d->mExRules.count(); i < end; ++i) {
1154 allowed = allowed && !(d->mExRules[i]->recursAt(prevDT));
1168 RecurrenceRule::List Recurrence::rRules()
const
1175 if (d->mRecurReadOnly || !rrule) {
1180 d->mRRules.append(rrule);
1187 if (d->mRecurReadOnly) {
1191 d->mRRules.removeAll(rrule);
1198 if (d->mRecurReadOnly) {
1202 d->mRRules.removeAll(rrule);
1207 RecurrenceRule::List Recurrence::exRules()
const
1214 if (d->mRecurReadOnly || !exrule) {
1219 d->mExRules.append(exrule);
1226 if (d->mRecurReadOnly) {
1230 d->mExRules.removeAll(exrule);
1237 if (d->mRecurReadOnly) {
1241 d->mExRules.removeAll(exrule);
1248 return d->mRDateTimes;
1251 void Recurrence::setRDateTimes(
const DateTimeList &rdates)
1253 if (d->mRecurReadOnly) {
1257 d->mRDateTimes = rdates;
1262 void Recurrence::addRDateTime(
const KDateTime &rdate)
1264 if (d->mRecurReadOnly) {
1268 d->mRDateTimes.insertSorted(rdate);
1272 DateList Recurrence::rDates()
const
1277 void Recurrence::setRDates(
const DateList &rdates)
1279 if (d->mRecurReadOnly) {
1283 d->mRDates = rdates;
1288 void Recurrence::addRDate(
const QDate &rdate)
1290 if (d->mRecurReadOnly) {
1294 d->mRDates.insertSorted(rdate);
1300 return d->mExDateTimes;
1303 void Recurrence::setExDateTimes(
const DateTimeList &exdates)
1305 if (d->mRecurReadOnly) {
1309 d->mExDateTimes = exdates;
1313 void Recurrence::addExDateTime(
const KDateTime &exdate)
1315 if (d->mRecurReadOnly) {
1319 d->mExDateTimes.insertSorted(exdate);
1323 DateList Recurrence::exDates()
const
1328 void Recurrence::setExDates(
const DateList &exdates)
1330 if (d->mRecurReadOnly) {
1334 d->mExDates = exdates;
1339 void Recurrence::addExDate(
const QDate &exdate)
1341 if (d->mRecurReadOnly) {
1345 d->mExDates.insertSorted(exdate);
1361 int count = d->mRRules.count();
1362 kDebug() <<
" -)" << count <<
"RRULEs:";
1363 for (i = 0; i < count; ++i) {
1364 kDebug() <<
" -) RecurrenceRule: ";
1365 d->mRRules[i]->dump();
1367 count = d->mExRules.count();
1368 kDebug() <<
" -)" << count <<
"EXRULEs:";
1369 for (i = 0; i < count; ++i) {
1370 kDebug() <<
" -) ExceptionRule :";
1371 d->mExRules[i]->dump();
1374 count = d->mRDates.count();
1375 kDebug() << endl <<
" -)" << count <<
"Recurrence Dates:";
1376 for (i = 0; i < count; ++i) {
1377 kDebug() <<
" " << d->mRDates[i];
1379 count = d->mRDateTimes.count();
1380 kDebug() << endl <<
" -)" << count <<
"Recurrence Date/Times:";
1381 for (i = 0; i < count; ++i) {
1382 kDebug() <<
" " << d->mRDateTimes[i].dateTime();
1384 count = d->mExDates.count();
1385 kDebug() << endl <<
" -)" << count <<
"Exceptions Dates:";
1386 for (i = 0; i < count; ++i) {
1387 kDebug() <<
" " << d->mExDates[i];
1389 count = d->mExDateTimes.count();
1390 kDebug() << endl <<
" -)" << count <<
"Exception Date/Times:";
1391 for (i = 0; i < count; ++i) {
1392 kDebug() <<
" " << d->mExDateTimes[i].dateTime();
1396 Recurrence::RecurrenceObserver::~RecurrenceObserver()