24 #include "recurrence.h"
28 #include <QtCore/QBitArray>
29 #include <QtCore/QTime>
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)
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 if ((mStartDateTime != p.mStartDateTime &&
77 (mStartDateTime.isValid() || p.mStartDateTime.isValid())) ||
78 mAllDay != p.mAllDay ||
79 mRecurReadOnly != p.mRecurReadOnly ||
80 mExDates != p.mExDates ||
81 mExDateTimes != p.mExDateTimes ||
82 mRDates != p.mRDates ||
83 mRDateTimes != p.mRDateTimes) {
90 int end = mRRules.count();
91 if (end != p.mRRules.count()) {
94 for (i = 0; i < end; ++i) {
95 if (*mRRules[i] != *p.mRRules[i]) {
99 end = mExRules.count();
100 if (end != p.mExRules.count()) {
103 for (i = 0; i < end; ++i) {
104 if (*mExRules[i] != *p.mExRules[i]) {
122 for (i = 0, end = r.d->mRRules.count(); i < end; ++i) {
124 d->mRRules.append(rule);
127 for (i = 0, end = r.d->mExRules.count(); i < end; ++i) {
129 d->mExRules.append(rule);
136 qDeleteAll(d->mExRules);
137 qDeleteAll(d->mRRules);
143 return *d == *recurrence.d;
149 if (&recurrence ==
this) {
159 if (!d->mObservers.contains(observer)) {
160 d->mObservers.append(observer);
166 if (d->mObservers.contains(observer)) {
167 d->mObservers.removeAll(observer);
173 return d->mStartDateTime;
183 if (d->mRecurReadOnly ||
allDay == d->mAllDay) {
188 for (
int i = 0, end = d->mRRules.count(); i < end; ++i) {
189 d->mRRules[i]->setAllDay(
allDay);
191 for (
int i = 0, end = d->mExRules.count(); i < end; ++i) {
192 d->mExRules[i]->setAllDay(
allDay);
199 if (d->mRRules.isEmpty()) {
200 if (!create || d->mRecurReadOnly) {
208 return d->mRRules[0];
214 return d->mRRules.isEmpty() ? 0 : d->mRRules[0];
217 void 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()) {
333 if (KDateTime(qd, QTime(23, 59, 59), timeSpec) < d->mStartDateTime) {
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);
391 return !timesForDay.isEmpty();
398 KDateTime dtrecur = dt.toTimeSpec(d->mStartDateTime.timeSpec());
401 if (d->mExDateTimes.containsSorted(dtrecur) ||
402 d->mExDates.containsSorted(dtrecur.date())) {
406 for (i = 0, end = d->mExRules.count(); i < end; ++i) {
407 if (d->mExRules[i]->recursAt(dtrecur)) {
413 if (
startDateTime() == dtrecur || d->mRDateTimes.containsSorted(dtrecur)) {
416 for (i = 0, end = d->mRRules.count(); i < end; ++i) {
417 if (d->mRRules[i]->recursAt(dtrecur)) {
432 if (!d->mRDates.isEmpty()) {
433 dts << KDateTime(d->mRDates.last(), QTime(0, 0, 0), d->mStartDateTime.timeSpec());
435 if (!d->mRDateTimes.isEmpty()) {
436 dts << d->mRDateTimes.last();
438 for (
int i = 0, end = d->mRRules.count(); i < end; ++i) {
439 KDateTime rl(d->mRRules[i]->endDt());
447 return dts.isEmpty() ? KDateTime() : dts.last();
456 return end.isValid() ? end.date() : QDate();
461 KDateTime dt(date, d->mStartDateTime.time(), d->mStartDateTime.timeSpec());
463 dt.setTime(QTime(23, 59, 59));
470 if (d->mRecurReadOnly) {
484 return rrule ? rrule->
duration() : 0;
491 return rrule ? rrule->
durationTo(datetime) : 0;
496 return durationTo(KDateTime(date, QTime(23, 59, 59), d->mStartDateTime.timeSpec()));
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);
525 d->mRDateTimes[i].setTimeSpec(newSpec);
527 for (i = 0, end = d->mExDateTimes.count(); i < end; ++i) {
528 d->mExDateTimes[i] = d->mExDateTimes[i].toTimeSpec(oldSpec);
529 d->mExDateTimes[i].setTimeSpec(newSpec);
531 for (i = 0, end = d->mRRules.count(); i < end; ++i) {
532 d->mRRules[i]->shiftTimes(oldSpec, newSpec);
534 for (i = 0, end = d->mExRules.count(); i < end; ++i) {
535 d->mExRules[i]->shiftTimes(oldSpec, newSpec);
541 if (d->mRecurReadOnly) {
544 qDeleteAll(d->mRRules);
551 if (d->mRecurReadOnly) {
554 qDeleteAll(d->mRRules);
556 qDeleteAll(d->mExRules);
559 d->mRDateTimes.clear();
561 d->mExDateTimes.clear();
562 d->mCachedType = rMax;
568 d->mRecurReadOnly = readOnly;
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) {
637 if (bydays.at(i).pos() == 0) {
638 days.setBit(bydays.at(i).day() - 1);
652 return rrule->byMonthDays();
662 return rrule ? rrule->byDays() : QList<RecurrenceRule::WDayPos>();
670 return rrule ? rrule->byYearDays() : QList<int>();
681 return rrule ? rrule->byMonths() : QList<int>();
691 if (d->mRecurReadOnly || freq <= 0) {
695 qDeleteAll(d->mRRules);
702 rrule->setRecurrenceType(type);
710 if (setNewRecurrenceType(RecurrenceRule::rMinutely, _rFreq)) {
717 if (setNewRecurrenceType(RecurrenceRule::rHourly, _rFreq)) {
724 if (setNewRecurrenceType(RecurrenceRule::rDaily, _rFreq)) {
731 RecurrenceRule *rrule = setNewRecurrenceType(RecurrenceRule::rWeekly, freq);
752 if (setNewRecurrenceType(RecurrenceRule::rMonthly, freq)) {
760 if (d->mRecurReadOnly || pos > 53 || pos < -53) {
768 bool changed =
false;
769 QList<RecurrenceRule::WDayPos> positions = rrule->byDays();
771 for (
int i = 0; i < 7; ++i) {
772 if (
days.testBit(i)) {
774 if (!positions.contains(p)) {
781 rrule->setByDays(positions);
789 if (d->mRecurReadOnly || pos > 53 || pos < -53) {
797 QList<RecurrenceRule::WDayPos> positions = rrule->byDays();
800 if (!positions.contains(p)) {
802 rrule->setByDays(positions);
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);
864 if (d->mRecurReadOnly || month < 1 || month > 12) {
873 QList<int> months = rrule->byMonths();
874 if (!months.contains(month)) {
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)) {
903 if (dt.date() == date) {
907 bool foundDate =
false;
908 for (i = 0, end = d->mRDateTimes.count(); i < end; ++i) {
909 dt = d->mRDateTimes[i].toTimeSpec(timeSpec);
910 if (dt.date() == date) {
913 }
else if (foundDate) {
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);
926 if (dt.date() == date) {
927 extimes << dt.time();
929 }
else if (foundDate) {
934 for (i = 0, end = d->mExRules.count(); i < end; ++i) {
935 extimes += d->mExRules[i]->recurTimesOn(date, timeSpec);
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) {
961 times += d->mRDateTimes[i];
966 KDateTime kdt(d->mStartDateTime);
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;
990 int enddt = times.count();
991 for (i = 0, count = d->mExDates.count(); i < count && idt < enddt; ++i) {
992 while (idt < enddt && times[idt].date() < d->mExDates[i]) {
995 while (idt < enddt && times[idt].date() == d->mExDates[i]) {
1001 for (i = 0, count = d->mExRules.count(); i < count; ++i) {
1002 extimes += d->mExRules[i]->timesInInterval(start, end);
1004 extimes += d->mExDateTimes;
1008 for (i = 0, count = extimes.count(); i < count; ++i) {
1020 KDateTime nextDT = preDateTime;
1027 while (loop < 1000) {
1047 int i = d->mRDateTimes.findGT(nextDT);
1049 dates << d->mRDateTimes[i];
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) {
1063 KDateTime dt = d->mRRules[i]->getNextDate(nextDT);
1071 if (dates.isEmpty()) {
1074 nextDT = dates.first();
1077 if (!d->mExDates.containsSorted(nextDT.date()) &&
1078 !d->mExDateTimes.containsSorted(nextDT)) {
1079 bool allowed =
true;
1080 for (i = 0, end = d->mExRules.count(); i < end; ++i) {
1081 allowed = allowed && !(d->mExRules[i]->recursAt(nextDT));
1095 KDateTime prevDT = afterDateTime;
1100 while (loop < 1000) {
1117 int i = d->mRDateTimes.findLT(prevDT);
1119 dates << d->mRDateTimes[i];
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) {
1134 KDateTime dt = d->mRRules[i]->getPreviousDate(prevDT);
1142 if (dates.isEmpty()) {
1145 prevDT = dates.last();
1148 if (!d->mExDates.containsSorted(prevDT.date()) &&
1149 !d->mExDateTimes.containsSorted(prevDT)) {
1150 bool allowed =
true;
1151 for (i = 0, end = d->mExRules.count(); i < end; ++i) {
1152 allowed = allowed && !(d->mExRules[i]->recursAt(prevDT));
1166 RecurrenceRule::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);
1205 RecurrenceRule::List Recurrence::exRules()
const
1212 if (d->mRecurReadOnly || !exrule) {
1217 d->mExRules.append(exrule);
1224 if (d->mRecurReadOnly) {
1228 d->mExRules.removeAll(exrule);
1235 if (d->mRecurReadOnly) {
1239 d->mExRules.removeAll(exrule);
1246 return d->mRDateTimes;
1249 void Recurrence::setRDateTimes(
const DateTimeList &rdates)
1251 if (d->mRecurReadOnly) {
1255 d->mRDateTimes = rdates;
1260 void Recurrence::addRDateTime(
const KDateTime &rdate)
1262 if (d->mRecurReadOnly) {
1266 d->mRDateTimes.insertSorted(rdate);
1270 DateList Recurrence::rDates()
const
1275 void Recurrence::setRDates(
const DateList &rdates)
1277 if (d->mRecurReadOnly) {
1281 d->mRDates = rdates;
1286 void Recurrence::addRDate(
const QDate &rdate)
1288 if (d->mRecurReadOnly) {
1292 d->mRDates.insertSorted(rdate);
1298 return d->mExDateTimes;
1301 void Recurrence::setExDateTimes(
const DateTimeList &exdates)
1303 if (d->mRecurReadOnly) {
1307 d->mExDateTimes = exdates;
1311 void Recurrence::addExDateTime(
const KDateTime &exdate)
1313 if (d->mRecurReadOnly) {
1317 d->mExDateTimes.insertSorted(exdate);
1321 DateList Recurrence::exDates()
const
1326 void Recurrence::setExDates(
const DateList &exdates)
1328 if (d->mRecurReadOnly) {
1332 d->mExDates = exdates;
1337 void Recurrence::addExDate(
const QDate &exdate)
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) {
1375 kDebug() <<
" " << d->mRDates[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) {
1385 kDebug() <<
" " << d->mExDates[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();
1394 Recurrence::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();
1425 int rruleCount, exruleCount;
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
1430 >> exruleCount >> rruleCount;
1432 r->d->mExRules.
clear();
1433 r->d->mRRules.
clear();
1435 for (
int i=0; i<exruleCount; ++i) {
1439 r->d->mExRules.append(rule);
1442 for (
int i=0; i<rruleCount; ++i) {
1446 r->d->mRRules.append(rule);