00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <limits.h>
00024
00025 #include <kdebug.h>
00026 #include <kglobal.h>
00027 #include <klocale.h>
00028
00029 #include "incidence.h"
00030
00031 #include "recurrence.h"
00032
00033 using namespace KCal;
00034
00035
00036 Recurrence::Recurrence(Incidence *parent, int compatVersion)
00037 : recurs(rNone),
00038 rWeekStart(1),
00039 rDays(7),
00040 mFloats(parent ? parent->doesFloat() : false),
00041 mRecurReadOnly(false),
00042 mRecurExDatesCount(0),
00043 mCompatVersion(compatVersion ? compatVersion : INT_MAX),
00044 mCompatRecurs(rNone),
00045 mCompatDuration(0),
00046 mParent(parent)
00047 {
00048 rMonthDays.setAutoDelete( true );
00049 rMonthPositions.setAutoDelete( true );
00050 rYearNums.setAutoDelete( true );
00051 }
00052
00053 Recurrence::Recurrence(const Recurrence &r, Incidence *parent)
00054 : recurs(r.recurs),
00055 rWeekStart(r.rWeekStart),
00056 rDays(r.rDays.copy()),
00057 rFreq(r.rFreq),
00058 rDuration(r.rDuration),
00059 rEndDateTime(r.rEndDateTime),
00060 mRecurStart(r.mRecurStart),
00061 mFloats(r.mFloats),
00062 mRecurReadOnly(r.mRecurReadOnly),
00063 mRecurExDatesCount(r.mRecurExDatesCount),
00064 mCompatVersion(r.mCompatVersion),
00065 mCompatRecurs(r.mCompatRecurs),
00066 mCompatDuration(r.mCompatDuration),
00067 mParent(parent)
00068 {
00069 for (QPtrListIterator<rMonthPos> mp(r.rMonthPositions); mp.current(); ++mp) {
00070 rMonthPos *tmp = new rMonthPos;
00071 tmp->rPos = mp.current()->rPos;
00072 tmp->negative = mp.current()->negative;
00073 tmp->rDays = mp.current()->rDays.copy();
00074 rMonthPositions.append(tmp);
00075 }
00076 for (QPtrListIterator<int> md(r.rMonthDays); md.current(); ++md) {
00077 int *tmp = new int;
00078 *tmp = *md.current();
00079 rMonthDays.append(tmp);
00080 }
00081 for (QPtrListIterator<int> yn(r.rYearNums); yn.current(); ++yn) {
00082 int *tmp = new int;
00083 *tmp = *yn.current();
00084 rYearNums.append(tmp);
00085 }
00086 rMonthDays.setAutoDelete( true );
00087 rMonthPositions.setAutoDelete( true );
00088 rYearNums.setAutoDelete( true );
00089 }
00090
00091 Recurrence::~Recurrence()
00092 {
00093 }
00094
00095 void Recurrence::setCompatVersion(int version)
00096 {
00097 mCompatVersion = version ? version : INT_MAX;
00098 }
00099
00100 ushort Recurrence::doesRecur() const
00101 {
00102 return recurs;
00103 }
00104
00105 bool Recurrence::recursOnPure(const QDate &qd) const
00106 {
00107 switch(recurs) {
00108 case rMinutely:
00109 return recursSecondly(qd, rFreq*60);
00110 case rHourly:
00111 return recursSecondly(qd, rFreq*3600);
00112 case rDaily:
00113 return recursDaily(qd);
00114 case rWeekly:
00115 return recursWeekly(qd);
00116 case rMonthlyPos:
00117 case rMonthlyDay:
00118 return recursMonthly(qd);
00119 case rYearlyMonth:
00120 return recursYearlyByMonth(qd);
00121 case rYearlyDay:
00122 return recursYearlyByDay(qd);
00123 case rYearlyPos:
00124 return recursYearlyByPos(qd);
00125 default:
00126
00127 kdDebug(5800) << "Control should never reach here in recursOnPure()!" << endl;
00128 case rNone:
00129 return false;
00130 }
00131 }
00132
00133 bool Recurrence::recursAtPure(const QDateTime &dt) const
00134 {
00135 switch(recurs) {
00136 case rMinutely:
00137 return recursMinutelyAt(dt, rFreq);
00138 case rHourly:
00139 return recursMinutelyAt(dt, rFreq*60);
00140 default:
00141 if (dt.time() != mRecurStart.time())
00142 return false;
00143 switch(recurs) {
00144 case rDaily:
00145 return recursDaily(dt.date());
00146 case rWeekly:
00147 return recursWeekly(dt.date());
00148 case rMonthlyPos:
00149 case rMonthlyDay:
00150 return recursMonthly(dt.date());
00151 case rYearlyMonth:
00152 return recursYearlyByMonth(dt.date());
00153 case rYearlyDay:
00154 return recursYearlyByDay(dt.date());
00155 case rYearlyPos:
00156 return recursYearlyByPos(dt.date());
00157 default:
00158
00159 kdDebug(5800) << "Control should never reach here in recursAtPure()!" << endl;
00160 case rNone:
00161 return false;
00162 }
00163 }
00164 }
00165
00166 QDate Recurrence::endDate() const
00167 {
00168 int count = 0;
00169 QDate end;
00170 if (recurs != rNone) {
00171 if (rDuration < 0)
00172 return QDate();
00173 if (rDuration == 0)
00174 return rEndDateTime.date();
00175
00176
00177 QDate dStart = mRecurStart.date();
00178 switch (recurs)
00179 {
00180 case rMinutely:
00181 return mRecurStart.addSecs((rDuration-1+mRecurExDatesCount)*rFreq*60).date();
00182 case rHourly:
00183 return mRecurStart.addSecs((rDuration-1+mRecurExDatesCount)*rFreq*3600).date();
00184 case rDaily:
00185 return dStart.addDays((rDuration-1+mRecurExDatesCount)*rFreq);
00186
00187 case rWeekly:
00188 count = weeklyCalc(END_DATE_AND_COUNT, end);
00189 break;
00190 case rMonthlyPos:
00191 case rMonthlyDay:
00192 count = monthlyCalc(END_DATE_AND_COUNT, end);
00193 break;
00194 case rYearlyMonth:
00195 count = yearlyMonthCalc(END_DATE_AND_COUNT, end);
00196 break;
00197 case rYearlyDay:
00198 count = yearlyDayCalc(END_DATE_AND_COUNT, end);
00199 break;
00200 case rYearlyPos:
00201 count = yearlyPosCalc(END_DATE_AND_COUNT, end);
00202 break;
00203 default:
00204
00205 kdDebug(5800) << "Control should never reach here in endDate()!" << endl;
00206 break;
00207 }
00208 }
00209 if (!count)
00210 return QDate();
00211 return end;
00212 }
00213
00214 QDateTime Recurrence::endDateTime() const
00215 {
00216 int count = 0;
00217 QDate end;
00218 if (recurs != rNone) {
00219 if (rDuration < 0)
00220 return QDateTime();
00221 if (rDuration == 0)
00222 return rEndDateTime;
00223
00224
00225 QDate dStart = mRecurStart.date();
00226 switch (recurs)
00227 {
00228 case rMinutely:
00229 return mRecurStart.addSecs((rDuration-1+mRecurExDatesCount)*rFreq*60);
00230 case rHourly:
00231 return mRecurStart.addSecs((rDuration-1+mRecurExDatesCount)*rFreq*3600);
00232 case rDaily:
00233 return dStart.addDays((rDuration-1+mRecurExDatesCount)*rFreq);
00234
00235 case rWeekly:
00236 count = weeklyCalc(END_DATE_AND_COUNT, end);
00237 break;
00238 case rMonthlyPos:
00239 case rMonthlyDay:
00240 count = monthlyCalc(END_DATE_AND_COUNT, end);
00241 break;
00242 case rYearlyMonth:
00243 count = yearlyMonthCalc(END_DATE_AND_COUNT, end);
00244 break;
00245 case rYearlyDay:
00246 count = yearlyDayCalc(END_DATE_AND_COUNT, end);
00247 break;
00248 case rYearlyPos:
00249 count = yearlyPosCalc(END_DATE_AND_COUNT, end);
00250 break;
00251 default:
00252
00253 kdDebug(5800) << "Control should never reach here in endDate()!" << endl;
00254 break;
00255 }
00256 }
00257 if (!count)
00258 return QDateTime();
00259 return QDateTime(end, mRecurStart.time());
00260 }
00261
00262 int Recurrence::durationTo(const QDate &date) const
00263 {
00264 QDate d = date;
00265 return recurCalc(COUNT_TO_DATE, d);
00266 }
00267
00268 int Recurrence::durationTo(const QDateTime &datetime) const
00269 {
00270 QDateTime dt = datetime;
00271 return recurCalc(COUNT_TO_DATE, dt);
00272 }
00273
00274 void Recurrence::unsetRecurs()
00275 {
00276 if (mRecurReadOnly) return;
00277 recurs = rNone;
00278 rMonthPositions.clear();
00279 rMonthDays.clear();
00280 rYearNums.clear();
00281 }
00282
00283 void Recurrence::setRecurStart(const QDateTime &start)
00284 {
00285 mRecurStart = start;
00286 mFloats = false;
00287 switch (recurs)
00288 {
00289 case rMinutely:
00290 case rHourly:
00291 break;
00292 case rDaily:
00293 case rWeekly:
00294 case rMonthlyPos:
00295 case rMonthlyDay:
00296 case rYearlyMonth:
00297 case rYearlyDay:
00298 case rYearlyPos:
00299 default:
00300 rEndDateTime.setTime(start.time());
00301 break;
00302 }
00303 }
00304
00305 void Recurrence::setRecurStart(const QDate &start)
00306 {
00307 mRecurStart.setDate(start);
00308 mRecurStart.setTime(QTime(0,0,0));
00309 switch (recurs)
00310 {
00311 case rMinutely:
00312 case rHourly:
00313 break;
00314 case rDaily:
00315 case rWeekly:
00316 case rMonthlyPos:
00317 case rMonthlyDay:
00318 case rYearlyMonth:
00319 case rYearlyDay:
00320 case rYearlyPos:
00321 default:
00322 mFloats = true;
00323 break;
00324 }
00325 }
00326
00327 void Recurrence::setFloats(bool f)
00328 {
00329 switch (recurs)
00330 {
00331 case rDaily:
00332 case rWeekly:
00333 case rMonthlyPos:
00334 case rMonthlyDay:
00335 case rYearlyMonth:
00336 case rYearlyDay:
00337 case rYearlyPos:
00338 break;
00339 case rMinutely:
00340 case rHourly:
00341 default:
00342 return;
00343 }
00344 mFloats = f;
00345 if (f) {
00346 mRecurStart.setTime(QTime(0,0,0));
00347 rEndDateTime.setTime(QTime(0,0,0));
00348 }
00349 }
00350
00351 int Recurrence::frequency() const
00352 {
00353 return rFreq;
00354 }
00355
00356 int Recurrence::duration() const
00357 {
00358 return rDuration;
00359 }
00360
00361 void Recurrence::setDuration(int _rDuration)
00362 {
00363 if (mRecurReadOnly) return;
00364 if (_rDuration > 0) {
00365 rDuration = _rDuration;
00366
00367
00368 mCompatDuration = 0;
00369 }
00370 }
00371
00372 QString Recurrence::endDateStr(bool shortfmt) const
00373 {
00374 return KGlobal::locale()->formatDate(rEndDateTime.date(),shortfmt);
00375 }
00376
00377 const QBitArray &Recurrence::days() const
00378 {
00379 return rDays;
00380 }
00381
00382 const QPtrList<Recurrence::rMonthPos> &Recurrence::monthPositions() const
00383 {
00384 return rMonthPositions;
00385 }
00386
00387 const QPtrList<Recurrence::rMonthPos> &Recurrence::yearMonthPositions() const
00388 {
00389 return rMonthPositions;
00390 }
00391
00392 const QPtrList<int> &Recurrence::monthDays() const
00393 {
00394 return rMonthDays;
00395 }
00396
00397 void Recurrence::setMinutely(int _rFreq, int _rDuration)
00398 {
00399 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1)
00400 return;
00401 setDailySub(rMinutely, _rFreq, _rDuration);
00402 }
00403
00404 void Recurrence::setMinutely(int _rFreq, const QDateTime &_rEndDateTime)
00405 {
00406 if (mRecurReadOnly) return;
00407 rEndDateTime = _rEndDateTime;
00408 setDailySub(rMinutely, _rFreq, 0);
00409 }
00410
00411 void Recurrence::setHourly(int _rFreq, int _rDuration)
00412 {
00413 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1)
00414 return;
00415 setDailySub(rHourly, _rFreq, _rDuration);
00416 }
00417
00418 void Recurrence::setHourly(int _rFreq, const QDateTime &_rEndDateTime)
00419 {
00420 if (mRecurReadOnly) return;
00421 rEndDateTime = _rEndDateTime;
00422 setDailySub(rHourly, _rFreq, 0);
00423 }
00424
00425 void Recurrence::setDaily(int _rFreq, int _rDuration)
00426 {
00427 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1)
00428 return;
00429 setDailySub(rDaily, _rFreq, _rDuration);
00430 }
00431
00432 void Recurrence::setDaily(int _rFreq, const QDate &_rEndDate)
00433 {
00434 if (mRecurReadOnly) return;
00435 rEndDateTime.setDate(_rEndDate);
00436 rEndDateTime.setTime(mRecurStart.time());
00437 setDailySub(rDaily, _rFreq, 0);
00438 }
00439
00440 void Recurrence::setWeekly(int _rFreq, const QBitArray &_rDays,
00441 int _rDuration, int _rWeekStart)
00442 {
00443 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1)
00444 return;
00445 recurs = rWeekly;
00446
00447 rFreq = _rFreq;
00448 rDays = _rDays;
00449 rWeekStart = _rWeekStart;
00450 rDuration = _rDuration;
00451 if (mCompatVersion < 310 && _rDuration > 0) {
00452
00453
00454
00455
00456 mCompatDuration = _rDuration;
00457 int weeks = ((mCompatDuration-1+mRecurExDatesCount)*7) + (7 - mRecurStart.date().dayOfWeek());
00458 QDate end(mRecurStart.date().addDays(weeks * rFreq));
00459 rDuration = INT_MAX;
00460 rDuration = weeklyCalc(COUNT_TO_DATE, end);
00461 } else {
00462 mCompatDuration = 0;
00463 }
00464 rMonthPositions.clear();
00465 rMonthDays.clear();
00466 if (mParent) mParent->updated();
00467 }
00468
00469 void Recurrence::setWeekly(int _rFreq, const QBitArray &_rDays,
00470 const QDate &_rEndDate, int _rWeekStart)
00471 {
00472 if (mRecurReadOnly) return;
00473 recurs = rWeekly;
00474
00475 rFreq = _rFreq;
00476 rDays = _rDays;
00477 rWeekStart = _rWeekStart;
00478 rEndDateTime.setDate(_rEndDate);
00479 rEndDateTime.setTime(mRecurStart.time());
00480 rDuration = 0;
00481 mCompatDuration = 0;
00482 rMonthPositions.clear();
00483 rMonthDays.clear();
00484 rYearNums.clear();
00485 if (mParent) mParent->updated();
00486 }
00487
00488 void Recurrence::setMonthly(short type, int _rFreq, int _rDuration)
00489 {
00490 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1)
00491 return;
00492 recurs = type;
00493
00494 rFreq = _rFreq;
00495 rDuration = _rDuration;
00496 if (mCompatVersion < 310)
00497 mCompatDuration = (_rDuration > 0) ? _rDuration : 0;
00498 rYearNums.clear();
00499 if (mParent) mParent->updated();
00500 }
00501
00502 void Recurrence::setMonthly(short type, int _rFreq,
00503 const QDate &_rEndDate)
00504 {
00505 if (mRecurReadOnly) return;
00506 recurs = type;
00507
00508 rFreq = _rFreq;
00509 rEndDateTime.setDate(_rEndDate);
00510 rEndDateTime.setTime(mRecurStart.time());
00511 rDuration = 0;
00512 mCompatDuration = 0;
00513 rYearNums.clear();
00514 if (mParent) mParent->updated();
00515 }
00516
00517 void Recurrence::addMonthlyPos(short _rPos, const QBitArray &_rDays)
00518 {
00519 if (recurs == rMonthlyPos)
00520 addMonthlyPos_(_rPos, _rDays);
00521 }
00522
00523 void Recurrence::addMonthlyPos_(short _rPos, const QBitArray &_rDays)
00524 {
00525 if (mRecurReadOnly
00526 || _rPos == 0 || _rPos > 5 || _rPos < -5)
00527 return;
00528
00529 for (rMonthPos* it = rMonthPositions.first(); it; it = rMonthPositions.next()) {
00530 int itPos = it->negative ? -it->rPos : it->rPos;
00531 if (_rPos == itPos) {
00532
00533
00534 it->rDays |= _rDays;
00535 if (mParent) mParent->updated();
00536 return;
00537 }
00538 }
00539
00540 rMonthPos *tmpPos = new rMonthPos;
00541 if (_rPos > 0) {
00542 tmpPos->rPos = _rPos;
00543 tmpPos->negative = false;
00544 } else {
00545 tmpPos->rPos = -_rPos;
00546 tmpPos->negative = true;
00547 }
00548 tmpPos->rDays = _rDays;
00549 tmpPos->rDays.detach();
00550 rMonthPositions.append(tmpPos);
00551
00552 if (mCompatVersion < 310 && mCompatDuration > 0) {
00553
00554
00555
00556 int monthsAhead = (mCompatDuration-1+mRecurExDatesCount) * rFreq;
00557 int month = mRecurStart.date().month() - 1 + monthsAhead;
00558 QDate end(mRecurStart.date().year() + month/12, month%12 + 1, 31);
00559 rDuration = INT_MAX;
00560 rDuration = recurCalc(COUNT_TO_DATE, end);
00561 }
00562
00563 if (mParent) mParent->updated();
00564 }
00565
00566 void Recurrence::addMonthlyDay(short _rDay)
00567 {
00568 if (mRecurReadOnly || recurs != rMonthlyDay
00569 || _rDay == 0 || _rDay > 31 || _rDay < -31)
00570 return;
00571 for (int* it = rMonthDays.first(); it; it = rMonthDays.next()) {
00572 if (_rDay == *it)
00573 return;
00574 }
00575 int *tmpDay = new int;
00576 *tmpDay = _rDay;
00577 rMonthDays.append(tmpDay);
00578
00579 if (mCompatVersion < 310 && mCompatDuration > 0) {
00580
00581
00582
00583 int monthsAhead = (mCompatDuration-1+mRecurExDatesCount) * rFreq;
00584 int month = mRecurStart.date().month() - 1 + monthsAhead;
00585 QDate end(mRecurStart.date().year() + month/12, month%12 + 1, 31);
00586 rDuration = INT_MAX;
00587 rDuration = recurCalc(COUNT_TO_DATE, end);
00588 }
00589
00590 if (mParent) mParent->updated();
00591 }
00592
00593 void Recurrence::setYearly(int type, int _rFreq, int _rDuration)
00594 {
00595 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1)
00596 return;
00597 if (mCompatVersion < 310)
00598 mCompatDuration = (_rDuration > 0) ? _rDuration : 0;
00599 setYearly_(type, _rFreq, _rDuration);
00600 }
00601
00602 void Recurrence::setYearly(int type, int _rFreq, const QDate &_rEndDate)
00603 {
00604 if (mRecurReadOnly) return;
00605 rEndDateTime.setDate(_rEndDate);
00606 rEndDateTime.setTime(mRecurStart.time());
00607 mCompatDuration = 0;
00608 setYearly_(type, _rFreq, 0);
00609 }
00610
00611 void Recurrence::addYearlyMonthPos(short _rPos, const QBitArray &_rDays)
00612 {
00613 if (recurs == rYearlyPos)
00614 addMonthlyPos_(_rPos, _rDays);
00615 }
00616
00617 const QPtrList<int> &Recurrence::yearNums() const
00618 {
00619 return rYearNums;
00620 }
00621
00622 void Recurrence::addYearlyNum(short _rNum)
00623 {
00624 if (mRecurReadOnly
00625 || (recurs != rYearlyMonth && recurs != rYearlyDay && recurs != rYearlyPos)
00626 || _rNum <= 0)
00627 return;
00628
00629 if (mCompatVersion < 310 && mCompatRecurs == rYearlyDay) {
00630
00631
00632
00633 if (_rNum <= 0 || _rNum > 366 || (_rNum == 366 && mRecurStart.date().daysInYear() < 366))
00634 return;
00635 _rNum = QDate(mRecurStart.date().year(), 1, 1).addDays(_rNum - 1).month();
00636 } else
00637 if ((recurs == rYearlyMonth || recurs == rYearlyPos) && _rNum > 12
00638 || recurs == rYearlyDay && _rNum > 366)
00639 return;
00640
00641 uint i = 0;
00642 for (int* it = rYearNums.first(); it && _rNum >= *it; it = rYearNums.next()) {
00643 if (_rNum == *it)
00644 return;
00645 ++i;
00646 }
00647
00648 int *tmpNum = new int;
00649 *tmpNum = _rNum;
00650 rYearNums.insert(i, tmpNum);
00651
00652 if (mCompatVersion < 310 && mCompatDuration > 0) {
00653
00654
00655
00656 QDate end(mRecurStart.date().year() + (mCompatDuration-1+mRecurExDatesCount)*rFreq, 12, 31);
00657 rDuration = INT_MAX;
00658 rDuration = recurCalc(COUNT_TO_DATE, end);
00659 }
00660
00661 if (mParent) mParent->updated();
00662 }
00663
00664
00665 QDateTime Recurrence::getNextDateTime(const QDateTime &preDateTime, bool *last) const
00666 {
00667 int freq;
00668 switch (recurs)
00669 {
00670 case rMinutely:
00671 freq = rFreq * 60;
00672 break;
00673 case rHourly:
00674 freq = rFreq * 3600;
00675 break;
00676 case rDaily:
00677 case rWeekly:
00678 case rMonthlyPos:
00679 case rMonthlyDay:
00680 case rYearlyMonth:
00681 case rYearlyDay:
00682 case rYearlyPos: {
00683 QDate preDate = preDateTime.date();
00684 if (!mFloats && mRecurStart.time() > preDateTime.time())
00685 preDate = preDate.addDays(-1);
00686 return QDateTime(getNextDateNoTime(preDate, last), mRecurStart.time());
00687 }
00688 default:
00689 return QDateTime();
00690 }
00691
00692
00693 if (last)
00694 *last = false;
00695 if (preDateTime < mRecurStart)
00696 return mRecurStart;
00697 int count = mRecurStart.secsTo(preDateTime) / freq + 2;
00698 if (rDuration > 0) {
00699 if (count > rDuration)
00700 return QDateTime();
00701 if (last && count == rDuration)
00702 *last = true;
00703 }
00704 QDateTime endtime = mRecurStart.addSecs((count - 1)*freq);
00705 if (rDuration == 0) {
00706 if (endtime > rEndDateTime)
00707 return QDateTime();
00708 if (last && endtime == rEndDateTime)
00709 *last = true;
00710 }
00711 return endtime;
00712 }
00713
00714 QDate Recurrence::getNextDate(const QDate &preDate, bool *last) const
00715 {
00716 switch (recurs)
00717 {
00718 case rMinutely:
00719 case rHourly:
00720 return getNextDateTime(QDateTime(preDate, QTime(23,59,59)), last).date();
00721 case rDaily:
00722 case rWeekly:
00723 case rMonthlyPos:
00724 case rMonthlyDay:
00725 case rYearlyMonth:
00726 case rYearlyDay:
00727 case rYearlyPos:
00728 return getNextDateNoTime(preDate, last);
00729 default:
00730 return QDate();
00731 }
00732 }
00733
00734
00735 QDateTime Recurrence::getPreviousDateTime(const QDateTime &afterDateTime, bool *last) const
00736 {
00737 int freq;
00738 switch (recurs)
00739 {
00740 case rMinutely:
00741 freq = rFreq * 60;
00742 break;
00743 case rHourly:
00744 freq = rFreq * 3600;
00745 break;
00746 case rDaily:
00747 case rWeekly:
00748 case rMonthlyPos:
00749 case rMonthlyDay:
00750 case rYearlyMonth:
00751 case rYearlyDay:
00752 case rYearlyPos: {
00753 QDate afterDate = afterDateTime.date();
00754 if (!mFloats && mRecurStart.time() < afterDateTime.time())
00755 afterDate = afterDate.addDays(1);
00756 return QDateTime(getPreviousDateNoTime(afterDate, last), mRecurStart.time());
00757 }
00758 default:
00759 return QDateTime();
00760 }
00761
00762
00763 if (last)
00764 *last = false;
00765 if (afterDateTime <= mRecurStart)
00766 return QDateTime();
00767 int count = (mRecurStart.secsTo(afterDateTime) - 1) / freq + 1;
00768 if (rDuration > 0) {
00769 if (count > rDuration)
00770 count = rDuration;
00771 if (last && count == rDuration)
00772 *last = true;
00773 }
00774 QDateTime endtime = mRecurStart.addSecs((count - 1)*freq);
00775 if (rDuration == 0) {
00776 if (endtime > rEndDateTime)
00777 endtime = rEndDateTime;
00778 if (last && endtime == rEndDateTime)
00779 *last = true;
00780 }
00781 return endtime;
00782 }
00783
00784 QDate Recurrence::getPreviousDate(const QDate &afterDate, bool *last) const
00785 {
00786 switch (recurs)
00787 {
00788 case rMinutely:
00789 case rHourly:
00790 return getPreviousDateTime(QDateTime(afterDate, QTime(0,0,0)), last).date();
00791 case rDaily:
00792 case rWeekly:
00793 case rMonthlyPos:
00794 case rMonthlyDay:
00795 case rYearlyMonth:
00796 case rYearlyDay:
00797 case rYearlyPos:
00798 return getPreviousDateNoTime(afterDate, last);
00799 default:
00800 return QDate();
00801 }
00802 }
00803
00804
00805
00806
00807 bool Recurrence::recursSecondly(const QDate &qd, int secondFreq) const
00808 {
00809 if ((qd >= mRecurStart.date()) &&
00810 ((rDuration > 0) && (qd <= endDate()) ||
00811 ((rDuration == 0) && (qd <= rEndDateTime.date())) ||
00812 (rDuration == -1))) {
00813
00814 if (secondFreq < 24*3600)
00815 return true;
00816 int after = mRecurStart.secsTo(QDateTime(qd));
00817 if (after / secondFreq != (after + 24*3600) / secondFreq)
00818 return true;
00819 }
00820 return false;
00821 }
00822
00823 bool Recurrence::recursMinutelyAt(const QDateTime &dt, int minuteFreq) const
00824 {
00825 if ((dt >= mRecurStart) &&
00826 ((rDuration > 0) && (dt <= endDateTime()) ||
00827 ((rDuration == 0) && (dt <= rEndDateTime)) ||
00828 (rDuration == -1))) {
00829
00830 if (((mRecurStart.secsTo(dt) / 60) % minuteFreq) == 0)
00831 return true;
00832 }
00833 return false;
00834 }
00835
00836 bool Recurrence::recursDaily(const QDate &qd) const
00837 {
00838 QDate dStart = mRecurStart.date();
00839 if ((dStart.daysTo(qd) % rFreq) == 0) {
00840
00841 if (qd >= dStart
00842 && ((rDuration > 0 && qd <= endDate()) ||
00843 (rDuration == 0 && qd <= rEndDateTime.date()) ||
00844 rDuration == -1)) {
00845
00846 return true;
00847 }
00848 }
00849 return false;
00850 }
00851
00852 bool Recurrence::recursWeekly(const QDate &qd) const
00853 {
00854 QDate dStart = mRecurStart.date();
00855 if ((dStart.daysTo(qd)/7) % rFreq == 0) {
00856
00857 if (qd >= dStart
00858 && ((rDuration > 0 && qd <= endDate()) ||
00859 (rDuration == 0 && qd <= rEndDateTime.date()) ||
00860 rDuration == -1)) {
00861
00862
00863 int i = qd.dayOfWeek()-1;
00864 if (rDays.testBit((uint) i))
00865 return true;
00866 }
00867 }
00868 return false;
00869 }
00870
00871 bool Recurrence::recursMonthly(const QDate &qd) const
00872 {
00873 QDate dStart = mRecurStart.date();
00874 int year = qd.year();
00875 int month = qd.month();
00876 int day = qd.day();
00877
00878
00879 int monthsAhead = (year - dStart.year()) * 12 + (month - dStart.month());
00880 if ((monthsAhead % rFreq) == 0) {
00881
00882 if (qd >= dStart
00883 && ((rDuration > 0 && qd <= endDate()) ||
00884 (rDuration == 0 && qd <= rEndDateTime.date()) ||
00885 rDuration == -1)) {
00886
00887 QValueList<int> days;
00888 int daysInMonth = qd.daysInMonth();
00889 if (recurs == rMonthlyDay)
00890 getMonthlyDayDays(days, daysInMonth);
00891 else if (recurs == rMonthlyPos)
00892 getMonthlyPosDays(days, daysInMonth, QDate(year, month, 1).dayOfWeek());
00893 for (QValueList<int>::Iterator it = days.begin(); it != days.end(); ++it) {
00894 if (*it == day)
00895 return true;
00896 }
00897
00898 }
00899 }
00900 return false;
00901 }
00902
00903 bool Recurrence::recursYearlyByMonth(const QDate &qd) const
00904 {
00905 QDate dStart = mRecurStart.date();
00906 if (qd.day() == dStart.day()) {
00907
00908
00909 int yearsAhead = (qd.year() - dStart.year());
00910 if (yearsAhead % rFreq == 0) {
00911
00912 if (qd >= dStart
00913 && ((rDuration > 0 && qd <= endDate()) ||
00914 (rDuration == 0 && qd <= rEndDateTime.date()) ||
00915 rDuration == -1)) {
00916
00917 int i = qd.month();
00918 for (QPtrListIterator<int> qlin(rYearNums); qlin.current(); ++qlin) {
00919 if (i == *qlin.current())
00920 return true;
00921 }
00922 }
00923 }
00924 }
00925 return false;
00926 }
00927
00928 bool Recurrence::recursYearlyByPos(const QDate &qd) const
00929 {
00930 QDate dStart = mRecurStart.date();
00931 int year = qd.year();
00932 int month = qd.month();
00933 int day = qd.day();
00934
00935
00936 int yearsAhead = (year - dStart.year());
00937 if (yearsAhead % rFreq == 0) {
00938
00939 if (qd >= dStart
00940 && ((rDuration > 0 && qd <= endDate()) ||
00941 (rDuration == 0 && qd <= rEndDateTime.date()) ||
00942 rDuration == -1)) {
00943
00944 for (QPtrListIterator<int> qlin(rYearNums); qlin.current(); ++qlin) {
00945 if (month == *qlin.current()) {
00946
00947 QValueList<int> days;
00948 getMonthlyPosDays(days, qd.daysInMonth(), QDate(year, month, 1).dayOfWeek());
00949 for (QValueList<int>::Iterator it = days.begin(); it != days.end(); ++it) {
00950 if (*it == day)
00951 return true;
00952 }
00953 }
00954 }
00955 }
00956 }
00957 return false;
00958 }
00959
00960 bool Recurrence::recursYearlyByDay(const QDate &qd) const
00961 {
00962 QDate dStart = mRecurStart.date();
00963
00964
00965 int yearsAhead = (qd.year() - dStart.year());
00966 if (yearsAhead % rFreq == 0) {
00967
00968 if (qd >= dStart
00969 && ((rDuration > 0 && qd <= endDate()) ||
00970 (rDuration == 0 && qd <= rEndDateTime.date()) ||
00971 rDuration == -1)) {
00972
00973 int i = qd.dayOfYear();
00974 for (QPtrListIterator<int> qlin(rYearNums); qlin.current(); ++qlin) {
00975 if (i == *qlin.current())
00976 return true;
00977 }
00978 }
00979 }
00980 return false;
00981 }
00982
00983
00984
00985
00986
00987
00988 QDate Recurrence::getNextDateNoTime(const QDate &preDate, bool *last) const
00989 {
00990 if (last)
00991 *last = false;
00992 QDate dStart = mRecurStart.date();
00993 if (preDate < dStart)
00994 return dStart;
00995 QDate earliestDate = preDate.addDays(1);
00996 QDate nextDate;
00997
00998 switch (recurs) {
00999 case rDaily:
01000 nextDate = dStart.addDays((dStart.daysTo(preDate)/rFreq + 1) * rFreq);
01001 break;
01002
01003 case rWeekly: {
01004 QDate start = dStart.addDays(1 - dStart.dayOfWeek());
01005 int earliestDayOfWeek = earliestDate.dayOfWeek();
01006 int weeksAhead = start.daysTo(earliestDate) / 7;
01007 int notThisWeek = weeksAhead % rFreq;
01008 weeksAhead -= notThisWeek;
01009 int weekday = 0;
01010
01011 if (!notThisWeek)
01012 weekday = getFirstDayInWeek(earliestDayOfWeek);
01013
01014 if (!weekday && earliestDayOfWeek > 1)
01015 weekday = getFirstDayInWeek(rWeekStart) + rFreq*7;
01016 if (weekday)
01017 nextDate = start.addDays(weeksAhead*7 + weekday - 1);
01018 break;
01019 }
01020 case rMonthlyDay:
01021 case rMonthlyPos: {
01022 int startYear = dStart.year();
01023 int startMonth = dStart.month();
01024 int earliestYear = earliestDate.year();
01025 int monthsAhead = (earliestYear - startYear)*12 + earliestDate.month() - startMonth;
01026 int notThisMonth = monthsAhead % rFreq;
01027 monthsAhead -= notThisMonth;
01028
01029 if (!notThisMonth)
01030 nextDate = getFirstDateInMonth(earliestDate);
01031 if (!nextDate.isValid() && earliestDate.day() > 1) {
01032
01033 int months = startMonth - 1 + monthsAhead + rFreq;
01034 nextDate = getFirstDateInMonth(QDate(startYear + months/12, months%12 + 1, 1));
01035 }
01036 break;
01037 }
01038 case rYearlyMonth:
01039 case rYearlyPos:
01040 case rYearlyDay: {
01041 int startYear = dStart.year();
01042 int yearsAhead = earliestDate.year() - startYear;
01043 int notThisYear = yearsAhead % rFreq;
01044 yearsAhead -= notThisYear;
01045
01046 if (!notThisYear)
01047 nextDate = getFirstDateInYear(earliestDate);
01048
01049 if (!nextDate.isValid() && earliestDate.dayOfYear() > 1)
01050 nextDate = getFirstDateInYear(QDate(startYear + yearsAhead + rFreq, 1, 1));
01051 break;
01052 }
01053 case rNone:
01054 default:
01055 return QDate();
01056 }
01057
01058 if (rDuration >= 0 && nextDate.isValid()) {
01059
01060 QDate end = endDate();
01061 if (nextDate > end)
01062 return QDate();
01063 if (last && nextDate == end)
01064 *last = true;
01065 }
01066 return nextDate;
01067 }
01068
01069
01070
01071
01072 QDate Recurrence::getPreviousDateNoTime(const QDate &afterDate, bool *last) const
01073 {
01074 if (last)
01075 *last = false;
01076 QDate dStart = mRecurStart.date();
01077 QDate latestDate = afterDate.addDays(-1);
01078 if (latestDate < dStart)
01079 return QDate();
01080 QDate prevDate;
01081
01082 switch (recurs) {
01083 case rDaily:
01084 prevDate = dStart.addDays((dStart.daysTo(latestDate) / rFreq) * rFreq);
01085 break;
01086
01087 case rWeekly: {
01088 QDate start = dStart.addDays(1 - dStart.dayOfWeek());
01089 int latestDayOfWeek = latestDate.dayOfWeek();
01090 int weeksAhead = start.daysTo(latestDate) / 7;
01091 int notThisWeek = weeksAhead % rFreq;
01092 weeksAhead -= notThisWeek;
01093 int weekday = 0;
01094
01095 if (!notThisWeek)
01096 weekday = getLastDayInWeek(latestDayOfWeek);
01097
01098 if (!weekday) {
01099 int weekEnd = (rWeekStart + 5)%7 + 1;
01100 if (latestDayOfWeek < weekEnd) {
01101 if (!notThisWeek)
01102 weeksAhead -= rFreq;
01103 weekday = getLastDayInWeek(weekEnd);
01104 }
01105 }
01106 if (weekday)
01107 prevDate = start.addDays(weeksAhead*7 + weekday - 1);
01108 break;
01109 }
01110 case rMonthlyDay:
01111 case rMonthlyPos: {
01112 int startYear = dStart.year();
01113 int startMonth = dStart.month();
01114 int latestYear = latestDate.year();
01115 int monthsAhead = (latestYear - startYear)*12 + latestDate.month() - startMonth;
01116 int notThisMonth = monthsAhead % rFreq;
01117 monthsAhead -= notThisMonth;
01118
01119 if (!notThisMonth)
01120 prevDate = getLastDateInMonth(latestDate);
01121 if (!prevDate.isValid() && latestDate.day() < latestDate.daysInMonth()) {
01122
01123 if (!notThisMonth)
01124 monthsAhead -= rFreq;
01125 int months = startMonth + monthsAhead;
01126 prevDate = getLastDateInMonth(QDate(startYear + months/12, months%12 + 1, 1).addDays(-1));
01127 }
01128 break;
01129 }
01130 case rYearlyMonth:
01131 case rYearlyPos:
01132 case rYearlyDay: {
01133 int startYear = dStart.year();
01134 int yearsAhead = latestDate.year() - startYear;
01135 int notThisYear = yearsAhead % rFreq;
01136 yearsAhead -= notThisYear;
01137
01138 if (!notThisYear)
01139 prevDate = getLastDateInYear(latestDate);
01140 if (!prevDate.isValid() && latestDate.dayOfYear() < latestDate.daysInYear()) {
01141
01142 if (!notThisYear)
01143 yearsAhead -= rFreq;
01144 prevDate = getLastDateInYear(QDate(startYear + yearsAhead, 12, 31));
01145 }
01146 break;
01147 }
01148 case rNone:
01149 default:
01150 return QDate();
01151 }
01152
01153 if (prevDate.isValid()) {
01154
01155 if (prevDate < dStart)
01156 return QDate();
01157 if (rDuration >= 0) {
01158 QDate end = endDate();
01159 if (prevDate >= end) {
01160 if (last)
01161 *last = true;
01162 return end;
01163 }
01164 }
01165 }
01166 return prevDate;
01167 }
01168
01169 void Recurrence::setDailySub(short type, int freq, int duration)
01170 {
01171 recurs = type;
01172 rFreq = freq;
01173 rDuration = duration;
01174 rMonthPositions.clear();
01175 rMonthDays.clear();
01176 rYearNums.clear();
01177 if (type != rDaily)
01178 mFloats = false;
01179 if (mParent) mParent->updated();
01180 }
01181
01182 void Recurrence::setYearly_(short type, int freq, int duration)
01183 {
01184 recurs = type;
01185 if (mCompatVersion < 310 && type == rYearlyDay) {
01186 mCompatRecurs = rYearlyDay;
01187 recurs = rYearlyMonth;
01188 }
01189
01190 rFreq = freq;
01191 rDuration = duration;
01192 if (type != rYearlyPos)
01193 rMonthPositions.clear();
01194 rMonthDays.clear();
01195 if (mParent) mParent->updated();
01196 }
01197
01198 int Recurrence::recurCalc(PeriodFunc func, QDateTime &endtime) const
01199 {
01200 QDate enddate = endtime.date();
01201 switch (func) {
01202 case END_DATE_AND_COUNT:
01203 if (rDuration < 0) {
01204 endtime = QDateTime();
01205 return 0;
01206 }
01207 if (rDuration == 0) {
01208 endtime = rEndDateTime;
01209 func = COUNT_TO_DATE;
01210 }
01211 break;
01212 case COUNT_TO_DATE:
01213
01214 if (endtime < mRecurStart)
01215 return 0;
01216 if (rDuration == 0 && endtime > rEndDateTime)
01217 enddate = rEndDateTime.date();
01218 else if (!mFloats && mRecurStart.time() > endtime.time())
01219 enddate = enddate.addDays(-1);
01220 break;
01221 case NEXT_AFTER_DATE:
01222 if (endtime < mRecurStart) {
01223 endtime = mRecurStart;
01224 return 1;
01225 }
01226 if (rDuration == 0 && endtime >= rEndDateTime) {
01227 endtime = QDateTime();
01228 return 0;
01229 }
01230 if (!mFloats && mRecurStart.time() > endtime.time())
01231 enddate = enddate.addDays(-1);
01232 break;
01233 default:
01234 endtime = QDateTime();
01235 return 0;
01236 }
01237
01238 int count = 0;
01239 bool timed = false;
01240 switch (recurs) {
01241 case rMinutely:
01242 timed = true;
01243 count = secondlyCalc(func, endtime, rFreq*60);
01244 break;
01245 case rHourly:
01246 timed = true;
01247 count = secondlyCalc(func, endtime, rFreq*3600);
01248 break;
01249 case rDaily:
01250 count = dailyCalc(func, enddate);
01251 break;
01252 case rWeekly:
01253 count = weeklyCalc(func, enddate);
01254 break;
01255 case rMonthlyPos:
01256 case rMonthlyDay:
01257 count = monthlyCalc(func, enddate);
01258 break;
01259 case rYearlyMonth:
01260 count = yearlyMonthCalc(func, enddate);
01261 break;
01262 case rYearlyPos:
01263 count = yearlyPosCalc(func, enddate);
01264 break;
01265 case rYearlyDay:
01266 count = yearlyDayCalc(func, enddate);
01267 break;
01268 default:
01269 break;
01270 }
01271
01272 switch (func) {
01273 case END_DATE_AND_COUNT:
01274 case NEXT_AFTER_DATE:
01275 if (count == 0)
01276 endtime = QDateTime();
01277 else if (!timed) {
01278 endtime.setDate(enddate);
01279 endtime.setTime(mRecurStart.time());
01280 }
01281 break;
01282 case COUNT_TO_DATE:
01283 break;
01284 }
01285 return count;
01286 }
01287
01288 int Recurrence::recurCalc(PeriodFunc func, QDate &enddate) const
01289 {
01290 QDateTime endtime(enddate, QTime(23,59,59));
01291 switch (func) {
01292 case END_DATE_AND_COUNT:
01293 if (rDuration < 0) {
01294 enddate = QDate();
01295 return 0;
01296 }
01297 if (rDuration == 0) {
01298 enddate = rEndDateTime.date();
01299 func = COUNT_TO_DATE;
01300 }
01301 break;
01302 case COUNT_TO_DATE:
01303
01304 if (enddate < mRecurStart.date())
01305 return 0;
01306 if (rDuration == 0 && enddate > rEndDateTime.date()) {
01307 enddate = rEndDateTime.date();
01308 endtime.setDate(enddate);
01309 }
01310 break;
01311 case NEXT_AFTER_DATE:
01312 if (enddate < mRecurStart.date()) {
01313 enddate = mRecurStart.date();
01314 return 1;
01315 }
01316 if (rDuration == 0 && enddate >= rEndDateTime.date()) {
01317 enddate = QDate();
01318 return 0;
01319 }
01320 break;
01321 default:
01322 enddate = QDate();
01323 return 0;
01324 }
01325
01326 int count = 0;
01327 bool timed = false;
01328 switch (recurs) {
01329 case rMinutely:
01330 timed = true;
01331 count = secondlyCalc(func, endtime, rFreq*60);
01332 break;
01333 case rHourly:
01334 timed = true;
01335 count = secondlyCalc(func, endtime, rFreq*3600);
01336 break;
01337 case rDaily:
01338 count = dailyCalc(func, enddate);
01339 break;
01340 case rWeekly:
01341 count = weeklyCalc(func, enddate);
01342 break;
01343 case rMonthlyPos:
01344 case rMonthlyDay:
01345 count = monthlyCalc(func, enddate);
01346 break;
01347 case rYearlyMonth:
01348 count = yearlyMonthCalc(func, enddate);
01349 break;
01350 case rYearlyPos:
01351 count = yearlyPosCalc(func, enddate);
01352 break;
01353 case rYearlyDay:
01354 count = yearlyDayCalc(func, enddate);
01355 break;
01356 default:
01357 break;
01358 }
01359
01360 switch (func) {
01361 case END_DATE_AND_COUNT:
01362 case NEXT_AFTER_DATE:
01363 if (count == 0)
01364 endtime = QDate();
01365 else if (timed)
01366 enddate = endtime.date();
01367 break;
01368 case COUNT_TO_DATE:
01369 break;
01370 }
01371 return count;
01372 }
01373
01374
01375
01376
01377
01378
01379 int Recurrence::secondlyCalc(PeriodFunc func, QDateTime &endtime, int freq) const
01380 {
01381 switch (func) {
01382 case END_DATE_AND_COUNT:
01383 endtime = mRecurStart.addSecs((rDuration + mRecurExDatesCount - 1) * freq);
01384 return rDuration + mRecurExDatesCount;
01385 case COUNT_TO_DATE: {
01386 int n = mRecurStart.secsTo(endtime)/freq + 1;
01387 if (rDuration > 0 && n > rDuration + mRecurExDatesCount)
01388 return rDuration + mRecurExDatesCount;
01389 return n;
01390 }
01391 case NEXT_AFTER_DATE: {
01392 int count = mRecurStart.secsTo(endtime) / freq + 2;
01393 if (rDuration > 0 && count > rDuration)
01394 return 0;
01395 endtime = mRecurStart.addSecs((count - 1)*freq);
01396 return count;
01397 }
01398 }
01399 return 0;
01400 }
01401
01402
01403
01404
01405
01406
01407 int Recurrence::dailyCalc(PeriodFunc func, QDate &enddate) const
01408 {
01409 QDate dStart = mRecurStart.date();
01410 switch (func) {
01411 case END_DATE_AND_COUNT:
01412 enddate = dStart.addDays((rDuration + mRecurExDatesCount - 1) * rFreq);
01413 return rDuration + mRecurExDatesCount;
01414 case COUNT_TO_DATE: {
01415 int n = dStart.daysTo(enddate)/rFreq + 1;
01416 if (rDuration > 0 && n > rDuration + mRecurExDatesCount)
01417 return rDuration + mRecurExDatesCount;
01418 return n;
01419 }
01420 case NEXT_AFTER_DATE: {
01421 int count = dStart.daysTo(enddate) / rFreq + 2;
01422 if (rDuration > 0 && count > rDuration)
01423 return 0;
01424 enddate = dStart.addDays((count - 1)*rFreq);
01425 return count;
01426 }
01427 }
01428 return 0;
01429 }
01430
01431
01432
01433
01434
01435
01436 int Recurrence::weeklyCalc(PeriodFunc func, QDate &enddate) const
01437 {
01438 int daysPerWeek = 0;
01439 for (int i = 0; i < 7; ++i) {
01440 if (rDays.testBit((uint)i))
01441 ++daysPerWeek;
01442 }
01443 if (!daysPerWeek)
01444 return 0;
01445
01446 switch (func) {
01447 case END_DATE_AND_COUNT:
01448 return weeklyCalcEndDate(enddate, daysPerWeek);
01449 case COUNT_TO_DATE:
01450 return weeklyCalcToDate(enddate, daysPerWeek);
01451 case NEXT_AFTER_DATE:
01452 return weeklyCalcNextAfter(enddate, daysPerWeek);
01453 }
01454 return 0;
01455 }
01456
01457 int Recurrence::weeklyCalcEndDate(QDate &enddate, int daysPerWeek) const
01458 {
01459 int startDayOfWeek = mRecurStart.date().dayOfWeek();
01460 int countGone = 0;
01461 int daysGone = 0;
01462 uint countTogo = rDuration + mRecurExDatesCount;
01463 if (startDayOfWeek != rWeekStart) {
01464
01465 for (int i = startDayOfWeek - 1; i != rWeekStart - 1; i = (i + 1) % 7) {
01466 ++daysGone;
01467 if (rDays.testBit((uint)i)) {
01468 ++countGone;
01469 if (--countTogo == 0)
01470 break;
01471 }
01472 }
01473 daysGone += 7 * (rFreq - 1);
01474 }
01475 if (countTogo) {
01476
01477
01478 int wholeWeeks = (countTogo - 1) / daysPerWeek;
01479 daysGone += wholeWeeks * 7 * rFreq;
01480 countGone += wholeWeeks * daysPerWeek;
01481 countTogo -= wholeWeeks * daysPerWeek;
01482
01483 for (int i = rWeekStart - 1; ; i = (i + 1) % 7) {
01484 ++daysGone;
01485 if (rDays.testBit((uint)i)) {
01486 ++countGone;
01487 if (--countTogo == 0)
01488 break;
01489 }
01490 }
01491 }
01492 enddate = mRecurStart.date().addDays(daysGone);
01493 return countGone;
01494 }
01495
01496 int Recurrence::weeklyCalcToDate(const QDate &enddate, int daysPerWeek) const
01497 {
01498 QDate dStart = mRecurStart.date();
01499 int startDayOfWeek = dStart.dayOfWeek();
01500 int countGone = 0;
01501 int daysGone = 0;
01502 int totalDays = dStart.daysTo(enddate) + 1;
01503 int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX;
01504
01505 if (startDayOfWeek != rWeekStart) {
01506
01507 for (int i = startDayOfWeek - 1; i != rWeekStart - 1; i = (i + 1) % 7) {
01508 if (rDays.testBit((uint)i)) {
01509 if (++countGone >= countMax)
01510 return countMax;
01511 }
01512 if (++daysGone == totalDays)
01513 return countGone;
01514 }
01515 daysGone += 7 * (rFreq - 1);
01516 if (daysGone >= totalDays)
01517 return countGone;
01518 }
01519
01520 int wholeWeeks = (totalDays - daysGone) / 7;
01521 countGone += (wholeWeeks / rFreq) * daysPerWeek;
01522 if (countGone >= countMax)
01523 return countMax;
01524 daysGone += wholeWeeks * 7;
01525 if (daysGone >= totalDays
01526 || wholeWeeks % rFreq)
01527 return countGone;
01528
01529
01530 for (int i = rWeekStart - 1; ; i = (i + 1) % 7) {
01531 if (rDays.testBit((uint)i)) {
01532 if (++countGone >= countMax)
01533 return countMax;
01534 }
01535 if (++daysGone == totalDays)
01536 return countGone;
01537 }
01538 return countGone;
01539 }
01540
01541 int Recurrence::weeklyCalcNextAfter(QDate &enddate, int daysPerWeek) const
01542 {
01543 QDate dStart = mRecurStart.date();
01544 int startDayOfWeek = dStart.dayOfWeek();
01545 int totalDays = dStart.daysTo(enddate) + 1;
01546 uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX;
01547 int countGone = 0;
01548 int daysGone = 0;
01549 int recurWeeks;
01550
01551 if (startDayOfWeek != rWeekStart) {
01552
01553 for (int i = startDayOfWeek - 1; i != rWeekStart - 1; i = (i + 1) % 7) {
01554 ++daysGone;
01555 if (rDays.testBit((uint)i)) {
01556 ++countGone;
01557 if (daysGone > totalDays)
01558 goto ex;
01559 if (--countTogo == 0)
01560 return 0;
01561 }
01562 }
01563 daysGone += 7 * (rFreq - 1);
01564 }
01565
01566
01567 recurWeeks = (totalDays - daysGone) / (7 * rFreq);
01568 if (recurWeeks) {
01569 int n = recurWeeks * daysPerWeek;
01570 if (static_cast<uint>(n) > countTogo)
01571 return 0;
01572 countGone += n;
01573 countTogo -= n;
01574 daysGone += recurWeeks * 7 * rFreq;
01575 }
01576
01577
01578 for ( ; ; ) {
01579 for (int i = rWeekStart - 1; ; i = (i + 1) % 7) {
01580 ++daysGone;
01581 if (rDays.testBit((uint)i)) {
01582 ++countGone;
01583 if (daysGone > totalDays)
01584 goto ex;
01585 if (--countTogo == 0)
01586 return 0;
01587 }
01588 }
01589 daysGone += 7 * (rFreq - 1);
01590 }
01591 ex:
01592 enddate = dStart.addDays(daysGone);
01593 return countGone;
01594 }
01595
01596
01597
01598
01599
01600
01601 struct Recurrence::MonthlyData {
01602 const Recurrence *recurrence;
01603 int year;
01604 int month;
01605 int day;
01606 bool varies;
01607 private:
01608 QValueList<int> days28, days29, days30, days31;
01609 QValueList<int> *recurDays[4];
01610 public:
01611 MonthlyData(const Recurrence* r, const QDate &date)
01612 : recurrence(r), year(date.year()), month(date.month()-1), day(date.day())
01613 { recurDays[0] = &days28;
01614 recurDays[1] = &days29;
01615 recurDays[2] = &days30;
01616 recurDays[3] = &days31;
01617 varies = (recurrence->recurs == rMonthlyPos)
01618 ? true : recurrence->getMonthlyDayDays(days31, 31);
01619 }
01620 const QValueList<int>* dayList() const {
01621 if (!varies)
01622 return &days31;
01623 QDate startOfMonth(year, month + 1, 1);
01624 int daysInMonth = startOfMonth.daysInMonth();
01625 QValueList<int>* days = recurDays[daysInMonth - 28];
01626 if (recurrence->recurs == rMonthlyPos)
01627 recurrence->getMonthlyPosDays(*days, daysInMonth, startOfMonth.dayOfWeek());
01628 else if (days->isEmpty())
01629 recurrence->getMonthlyDayDays(*days, daysInMonth);
01630 return days;
01631 }
01632 int yearMonth() const { return year*12 + month; }
01633 void addMonths(int diff) { month += diff; year += month / 12; month %= 12; }
01634 QDate date() const { return QDate(year, month + 1, day); }
01635 };
01636
01637 int Recurrence::monthlyCalc(PeriodFunc func, QDate &enddate) const
01638 {
01639 if (recurs == rMonthlyPos && rMonthPositions.isEmpty()
01640 || recurs == rMonthlyDay && rMonthDays.isEmpty())
01641 return 0;
01642
01643 MonthlyData data(this, mRecurStart.date());
01644 switch (func) {
01645 case END_DATE_AND_COUNT:
01646 return monthlyCalcEndDate(enddate, data);
01647 case COUNT_TO_DATE:
01648 return monthlyCalcToDate(enddate, data);
01649 case NEXT_AFTER_DATE:
01650 return monthlyCalcNextAfter(enddate, data);
01651 }
01652 return 0;
01653 }
01654
01655 int Recurrence::monthlyCalcEndDate(QDate &enddate, MonthlyData &data) const
01656 {
01657 uint countTogo = rDuration + mRecurExDatesCount;
01658 int countGone = 0;
01659 QValueList<int>::ConstIterator it;
01660 const QValueList<int>* days = data.dayList();
01661
01662 if (data.day > 1) {
01663
01664 for (it = days->begin(); it != days->end(); ++it) {
01665 if (*it >= data.day) {
01666 ++countGone;
01667 if (--countTogo == 0) {
01668 data.day = *it;
01669 break;
01670 }
01671 }
01672 }
01673 if (countTogo) {
01674 data.day = 1;
01675 data.addMonths(rFreq);
01676 }
01677 }
01678 if (countTogo) {
01679 if (data.varies) {
01680
01681
01682 for ( ; ; ) {
01683 days = data.dayList();
01684 uint n = days->count();
01685 if (n >= countTogo)
01686 break;
01687 countTogo -= n;
01688 countGone += n;
01689 data.addMonths(rFreq);
01690 }
01691 } else {
01692
01693
01694
01695
01696 int daysPerMonth = days->count();
01697 int wholeMonths = (countTogo - 1) / daysPerMonth;
01698 data.addMonths(wholeMonths * rFreq);
01699 countGone += wholeMonths * daysPerMonth;
01700 countTogo -= wholeMonths * daysPerMonth;
01701 }
01702 if (countTogo) {
01703
01704 for (it = days->begin(); it != days->end(); ++it) {
01705 ++countGone;
01706 if (--countTogo == 0) {
01707 data.day = *it;
01708 break;
01709 }
01710 }
01711 }
01712 }
01713 enddate = data.date();
01714 return countGone;
01715 }
01716
01717 int Recurrence::monthlyCalcToDate(const QDate &enddate, MonthlyData &data) const
01718 {
01719 int countGone = 0;
01720 int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX;
01721 int endYear = enddate.year();
01722 int endMonth = enddate.month() - 1;
01723 int endDay = enddate.day();
01724 int endYearMonth = endYear*12 + endMonth;
01725 QValueList<int>::ConstIterator it;
01726 const QValueList<int>* days = data.dayList();
01727
01728 if (data.day > 1) {
01729
01730 for (it = days->begin(); it != days->end(); ++it) {
01731 if (*it >= data.day) {
01732 if (data.yearMonth() == endYearMonth && *it > endDay)
01733 return countGone;
01734 if (++countGone >= countMax)
01735 return countMax;
01736 }
01737 }
01738 data.day = 1;
01739 data.addMonths(rFreq);
01740 }
01741
01742 if (data.varies) {
01743
01744
01745 while (data.yearMonth() < endYearMonth) {
01746 countGone += data.dayList()->count();
01747 if (countGone >= countMax)
01748 return countMax;
01749 data.addMonths(rFreq);
01750 }
01751 days = data.dayList();
01752 } else {
01753
01754
01755
01756 int daysPerMonth = days->count();
01757 int wholeMonths = endYearMonth - data.yearMonth();
01758 countGone += (wholeMonths / rFreq) * daysPerMonth;
01759 if (countGone >= countMax)
01760 return countMax;
01761 if (wholeMonths % rFreq)
01762 return countGone;
01763 data.year = endYear;
01764 data.month = endMonth;
01765 }
01766
01767
01768 for (it = days->begin(); it != days->end(); ++it) {
01769 if (*it > endDay)
01770 return countGone;
01771 if (++countGone >= countMax)
01772 return countMax;
01773 }
01774 return countGone;
01775 }
01776
01777 int Recurrence::monthlyCalcNextAfter(QDate &enddate, MonthlyData &data) const
01778 {
01779 uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX;
01780 int countGone = 0;
01781 int endYear = enddate.year();
01782 int endDay = enddate.day();
01783 int endYearMonth = endYear*12 + enddate.month() - 1;
01784 QValueList<int>::ConstIterator it;
01785 const QValueList<int>* days = data.dayList();
01786
01787 if (data.day > 1) {
01788
01789 for (it = days->begin(); it != days->end(); ++it) {
01790 if (*it >= data.day) {
01791 ++countGone;
01792 if (data.yearMonth() == endYearMonth && *it > endDay) {
01793 data.day = *it;
01794 goto ex;
01795 }
01796 if (--countTogo == 0)
01797 return 0;
01798 }
01799 }
01800 data.day = 1;
01801 data.addMonths(rFreq);
01802 }
01803
01804 if (data.varies) {
01805
01806
01807 while (data.yearMonth() <= endYearMonth) {
01808 days = data.dayList();
01809 uint n = days->count();
01810 if (data.yearMonth() == endYearMonth && days->last() > endDay)
01811 break;
01812 if (n >= countTogo)
01813 return 0;
01814 countGone += n;
01815 countTogo -= n;
01816 data.addMonths(rFreq);
01817 }
01818 days = data.dayList();
01819 } else {
01820
01821
01822
01823 int daysPerMonth = days->count();
01824 int elapsed = endYearMonth - data.yearMonth();
01825 int recurMonths = (elapsed + rFreq - 1) / rFreq;
01826 if (elapsed % rFreq == 0 && days->last() <= endDay)
01827 ++recurMonths;
01828 if (recurMonths) {
01829 int n = recurMonths * daysPerMonth;
01830 if (static_cast<uint>(n) > countTogo)
01831 return 0;
01832 countTogo -= n;
01833 countGone += n;
01834 data.addMonths(recurMonths * rFreq);
01835 }
01836 }
01837
01838
01839 for (it = days->begin(); it != days->end(); ++it) {
01840 ++countGone;
01841 if (data.yearMonth() > endYearMonth || *it > endDay) {
01842 data.day = *it;
01843 break;
01844 }
01845 if (--countTogo == 0)
01846 return 0;
01847 }
01848 ex:
01849 enddate = data.date();
01850 return countGone;
01851 }
01852
01853
01854
01855
01856
01857
01858
01859 struct Recurrence::YearlyMonthData {
01860 const Recurrence *recurrence;
01861 int year;
01862 int month;
01863 int day;
01864 bool varies;
01865 private:
01866 QValueList<int> months;
01867 QValueList<int> leapMonths;
01868 public:
01869 YearlyMonthData(const Recurrence* r, const QDate &date)
01870 : recurrence(r), year(date.year()), month(date.month()), day(date.day())
01871 { varies = recurrence->getYearlyMonthMonths(day, months, leapMonths); }
01872 const QValueList<int>* monthList() const
01873 { return (varies && QDate::leapYear(year)) ? &leapMonths : &months; }
01874 QDate date() const { return QDate(year, month, day); }
01875 };
01876
01877 int Recurrence::yearlyMonthCalc(PeriodFunc func, QDate &enddate) const
01878 {
01879 if (rYearNums.isEmpty())
01880 return 0;
01881 YearlyMonthData data(this, mRecurStart.date());
01882 switch (func) {
01883 case END_DATE_AND_COUNT:
01884 return yearlyMonthCalcEndDate(enddate, data);
01885 case COUNT_TO_DATE:
01886 return yearlyMonthCalcToDate(enddate, data);
01887 case NEXT_AFTER_DATE:
01888 return yearlyMonthCalcNextAfter(enddate, data);
01889 }
01890 return 0;
01891 }
01892
01893 int Recurrence::yearlyMonthCalcEndDate(QDate &enddate, YearlyMonthData &data) const
01894 {
01895 uint countTogo = rDuration + mRecurExDatesCount;
01896 int countGone = 0;
01897 QValueList<int>::ConstIterator it;
01898 const QValueList<int>* mons = data.monthList();
01899
01900 if (data.month > 1) {
01901
01902 for (it = mons->begin(); it != mons->end(); ++it) {
01903 if (*it >= data.month) {
01904 ++countGone;
01905 if (--countTogo == 0) {
01906 data.month = *it;
01907 break;
01908 }
01909 }
01910 }
01911 if (countTogo) {
01912 data.month = 1;
01913 data.year += rFreq;
01914 }
01915 }
01916 if (countTogo) {
01917 if (data.varies) {
01918
01919
01920 for ( ; ; ) {
01921 mons = data.monthList();
01922 uint n = mons->count();
01923 if (n >= countTogo)
01924 break;
01925 countTogo -= n;
01926 countGone += n;
01927 data.year += rFreq;
01928 }
01929 } else {
01930
01931
01932
01933
01934 int monthsPerYear = mons->count();
01935 int wholeYears = (countTogo - 1) / monthsPerYear;
01936 data.year += wholeYears * rFreq;
01937 countGone += wholeYears * monthsPerYear;
01938 countTogo -= wholeYears * monthsPerYear;
01939 }
01940 if (countTogo) {
01941
01942 for (it = mons->begin(); it != mons->end(); ++it) {
01943 ++countGone;
01944 if (--countTogo == 0) {
01945 data.month = *it;
01946 break;
01947 }
01948 }
01949 }
01950 }
01951 enddate = data.date();
01952 return countGone;
01953 }
01954
01955 int Recurrence::yearlyMonthCalcToDate(const QDate &enddate, YearlyMonthData &data) const
01956 {
01957 int countGone = 0;
01958 int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX;
01959 int endYear = enddate.year();
01960 int endMonth = enddate.month();
01961 if (enddate.day() < data.day && --endMonth == 0) {
01962 endMonth = 12;
01963 --endYear;
01964 }
01965 QValueList<int>::ConstIterator it;
01966 const QValueList<int>* mons = data.monthList();
01967
01968 if (data.month > 1) {
01969
01970 for (it = mons->begin(); it != mons->end(); ++it) {
01971 if (*it >= data.month) {
01972 if (data.year == endYear && *it > endMonth)
01973 return countGone;
01974 if (++countGone >= countMax)
01975 return countMax;
01976 }
01977 }
01978 data.month = 1;
01979 data.year += rFreq;
01980 }
01981 if (data.varies) {
01982
01983
01984 while (data.year < endYear) {
01985 countGone += data.monthList()->count();
01986 if (countGone >= countMax)
01987 return countMax;
01988 data.year += rFreq;
01989 }
01990 mons = data.monthList();
01991 } else {
01992
01993
01994
01995 int monthsPerYear = mons->count();
01996 int wholeYears = endYear - data.year;
01997 countGone += (wholeYears / rFreq) * monthsPerYear;
01998 if (countGone >= countMax)
01999 return countMax;
02000 if (wholeYears % rFreq)
02001 return countGone;
02002 data.year = endYear;
02003 }
02004
02005
02006 for (it = mons->begin(); it != mons->end(); ++it) {
02007 if (*it > endMonth)
02008 return countGone;
02009 if (++countGone >= countMax)
02010 return countMax;
02011 }
02012 return countGone;
02013 }
02014
02015 int Recurrence::yearlyMonthCalcNextAfter(QDate &enddate, YearlyMonthData &data) const
02016 {
02017 uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX;
02018 int countGone = 0;
02019 int endYear = enddate.year();
02020 int endMonth = enddate.month();
02021 if (enddate.day() < data.day && --endMonth == 0) {
02022 endMonth = 12;
02023 --endYear;
02024 }
02025 QValueList<int>::ConstIterator it;
02026 const QValueList<int>* mons = data.monthList();
02027
02028 if (data.month > 1) {
02029
02030 for (it = mons->begin(); it != mons->end(); ++it) {
02031 if (*it >= data.month) {
02032 ++countGone;
02033 if (data.year == endYear && *it > endMonth) {
02034 data.month = *it;
02035 goto ex;
02036 }
02037 if (--countTogo == 0)
02038 return 0;
02039 }
02040 }
02041 data.month = 1;
02042 data.year += rFreq;
02043 }
02044
02045 if (data.varies) {
02046
02047
02048 while (data.year <= endYear) {
02049 mons = data.monthList();
02050 if (data.year == endYear && mons->last() > endMonth)
02051 break;
02052 uint n = mons->count();
02053 if (n >= countTogo)
02054 break;
02055 countTogo -= n;
02056 countGone += n;
02057 data.year += rFreq;
02058 }
02059 mons = data.monthList();
02060 } else {
02061
02062
02063
02064 int monthsPerYear = mons->count();
02065 int recurYears = (endYear - data.year + rFreq - 1) / rFreq;
02066 if ((endYear - data.year)%rFreq == 0
02067 && mons->last() <= endMonth)
02068 ++recurYears;
02069 if (recurYears) {
02070 int n = recurYears * monthsPerYear;
02071 if (static_cast<uint>(n) > countTogo)
02072 return 0;
02073 countTogo -= n;
02074 countGone += n;
02075 data.year += recurYears * rFreq;
02076 }
02077 }
02078
02079
02080 for (it = mons->begin(); it != mons->end(); ++it) {
02081 ++countGone;
02082 if (data.year > endYear || *it > endMonth) {
02083 data.month = *it;
02084 break;
02085 }
02086 if (--countTogo == 0)
02087 return 0;
02088 }
02089 ex:
02090 enddate = data.date();
02091 return countGone;
02092 }
02093
02094
02095
02096
02097
02098
02099
02100 struct Recurrence::YearlyPosData {
02101 const Recurrence *recurrence;
02102 int year;
02103 int month;
02104 int day;
02105 int daysPerMonth;
02106 int count;
02107 bool varies;
02108 private:
02109 mutable QValueList<int> days;
02110 public:
02111 YearlyPosData(const Recurrence* r, const QDate &date)
02112 : recurrence(r), year(date.year()), month(date.month()), day(date.day()), count(-1)
02113 { if ((daysPerMonth = r->countMonthlyPosDays()) > 0)
02114 count = daysPerMonth * r->rYearNums.count();
02115 varies = (daysPerMonth < 0);
02116 }
02117 const QValueList<int>* dayList() const {
02118 QDate startOfMonth(year, month, 1);
02119 recurrence->getMonthlyPosDays(days, startOfMonth.daysInMonth(), startOfMonth.dayOfWeek());
02120 return &days;
02121 }
02122 int yearMonth() const { return year*12 + month - 1; }
02123 void addMonths(int diff) { month += diff - 1; year += month / 12; month = month % 12 + 1; }
02124 QDate date() const { return QDate(year, month, day); }
02125 };
02126
02127 int Recurrence::yearlyPosCalc(PeriodFunc func, QDate &enddate) const
02128 {
02129 if (rYearNums.isEmpty() || rMonthPositions.isEmpty())
02130 return 0;
02131 YearlyPosData data(this, mRecurStart.date());
02132 switch (func) {
02133 case END_DATE_AND_COUNT:
02134 return yearlyPosCalcEndDate(enddate, data);
02135 case COUNT_TO_DATE:
02136 return yearlyPosCalcToDate(enddate, data);
02137 case NEXT_AFTER_DATE:
02138 return yearlyPosCalcNextAfter(enddate, data);
02139 }
02140 return 0;
02141 }
02142
02143 int Recurrence::yearlyPosCalcEndDate(QDate &enddate, YearlyPosData &data) const
02144 {
02145 uint countTogo = rDuration + mRecurExDatesCount;
02146 int countGone = 0;
02147 QValueList<int>::ConstIterator id;
02148 const QValueList<int>* days;
02149
02150 if (data.month > 1 || data.day > 1) {
02151
02152 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) {
02153 if (*im.current() >= data.month) {
02154
02155 if (data.day > 1 || data.varies
02156 || static_cast<uint>(data.daysPerMonth) >= countTogo) {
02157 data.month = *im.current();
02158 days = data.dayList();
02159 for (id = days->begin(); id != days->end(); ++id) {
02160 if (*id >= data.day) {
02161 ++countGone;
02162 if (--countTogo == 0) {
02163 data.month = *im.current();
02164 data.day = *id;
02165 goto ex;
02166 }
02167 }
02168 }
02169 data.day = 1;
02170 } else {
02171
02172
02173 countTogo -= data.daysPerMonth;
02174 countGone += data.daysPerMonth;
02175 }
02176 }
02177 }
02178 data.month = 1;
02179 data.year += rFreq;
02180 }
02181
02182 if (data.varies) {
02183
02184 for ( ; ; ) {
02185 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) {
02186 data.month = *im.current();
02187 days = data.dayList();
02188 int n = days->count();
02189 if (static_cast<uint>(n) >= countTogo) {
02190
02191 for (id = days->begin(); id != days->end(); ++id) {
02192 ++countGone;
02193 if (--countTogo == 0) {
02194 data.day = *id;
02195 goto ex;
02196 }
02197 }
02198 }
02199 countTogo -= n;
02200 countGone += n;
02201 }
02202 data.year += rFreq;
02203 }
02204 } else {
02205
02206
02207
02208
02209 int wholeYears = (countTogo - 1) / data.count;
02210 data.year += wholeYears * rFreq;
02211 countGone += wholeYears * data.count;
02212 countTogo -= wholeYears * data.count;
02213
02214
02215 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) {
02216 if (static_cast<uint>(data.daysPerMonth) >= countTogo) {
02217
02218 data.month = *im.current();
02219 days = data.dayList();
02220 for (id = days->begin(); id != days->end(); ++id) {
02221 ++countGone;
02222 if (--countTogo == 0) {
02223 data.day = *id;
02224 goto ex;
02225 }
02226 }
02227 }
02228 countTogo -= data.daysPerMonth;
02229 countGone += data.daysPerMonth;
02230 }
02231 data.year += rFreq;
02232 }
02233 ex:
02234 enddate = data.date();
02235 return countGone;
02236 }
02237
02238 int Recurrence::yearlyPosCalcToDate(const QDate &enddate, YearlyPosData &data) const
02239 {
02240 int countGone = 0;
02241 int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX;
02242 int endYear = enddate.year();
02243 int endMonth = enddate.month();
02244 int endDay = enddate.day();
02245 if (endDay < data.day && --endMonth == 0) {
02246 endMonth = 12;
02247 --endYear;
02248 }
02249 int endYearMonth = endYear*12 + endMonth;
02250 QValueList<int>::ConstIterator id;
02251 const QValueList<int>* days;
02252
02253 if (data.month > 1 || data.day > 1) {
02254
02255 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) {
02256 if (*im.current() >= data.month) {
02257 data.month = *im.current();
02258 if (data.yearMonth() > endYearMonth)
02259 return countGone;
02260
02261 bool lastMonth = (data.yearMonth() == endYearMonth);
02262 if (lastMonth || data.day > 1 || data.varies) {
02263 days = data.dayList();
02264 if (lastMonth || data.day > 1) {
02265 for (id = days->begin(); id != days->end(); ++id) {
02266 if (*id >= data.day) {
02267 if (lastMonth && *id > endDay)
02268 return countGone;
02269 if (++countGone >= countMax)
02270 return countMax;
02271 }
02272 }
02273 } else {
02274 countGone += days->count();
02275 if (countGone >= countMax)
02276 return countMax;
02277 }
02278 data.day = 1;
02279 } else {
02280
02281
02282 countGone += data.daysPerMonth;
02283 if (countGone >= countMax)
02284 return countMax;
02285 }
02286 }
02287 }
02288 data.month = 1;
02289 data.year += rFreq;
02290 }
02291
02292 if (data.varies) {
02293
02294 for ( ; ; ) {
02295 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) {
02296 data.month = *im.current();
02297 days = data.dayList();
02298 if (data.yearMonth() >= endYearMonth) {
02299 if (data.yearMonth() > endYearMonth)
02300 return countGone;
02301
02302 for (id = days->begin(); id != days->end(); ++id) {
02303 if (*id > endDay)
02304 return countGone;
02305 if (++countGone >= countMax)
02306 return countMax;
02307 }
02308 } else {
02309 countGone += days->count();
02310 if (countGone >= countMax)
02311 return countMax;
02312 }
02313 }
02314 data.year += rFreq;
02315 }
02316 } else {
02317
02318
02319
02320
02321 int wholeYears = endYear - data.year;
02322 countGone += (wholeYears / rFreq) * data.count;
02323 if (countGone >= countMax)
02324 return countMax;
02325 if (wholeYears % rFreq)
02326 return countGone;
02327 data.year = endYear;
02328
02329
02330 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) {
02331 data.month = *im.current();
02332 if (data.month >= endMonth) {
02333 if (data.month > endMonth)
02334 return countGone;
02335
02336 days = data.dayList();
02337 for (id = days->begin(); id != days->end(); ++id) {
02338 if (*id > endDay)
02339 return countGone;
02340 if (++countGone >= countMax)
02341 return countMax;
02342 }
02343 } else {
02344 countGone += data.daysPerMonth;
02345 if (countGone >= countMax)
02346 return countMax;
02347 }
02348 }
02349 }
02350 return countGone;
02351 }
02352
02353 int Recurrence::yearlyPosCalcNextAfter(QDate &enddate, YearlyPosData &data) const
02354 {
02355 uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX;
02356 int countGone = 0;
02357 int endYear = enddate.year();
02358 int endMonth = enddate.month();
02359 int endDay = enddate.day();
02360 if (endDay < data.day && --endMonth == 0) {
02361 endMonth = 12;
02362 --endYear;
02363 }
02364 int endYearMonth = endYear*12 + endMonth;
02365 QValueList<int>::ConstIterator id;
02366 const QValueList<int>* days;
02367
02368 if (data.varies) {
02369
02370 for ( ; ; ) {
02371
02372 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) {
02373 if (*im.current() >= data.month) {
02374
02375 data.month = *im.current();
02376 int ended = data.yearMonth() - endYearMonth;
02377 days = data.dayList();
02378 if (ended >= 0 || data.day > 1) {
02379
02380 for (id = days->begin(); id != days->end(); ++id) {
02381 if (*id >= data.day) {
02382 ++countGone;
02383 if (ended > 0 || (ended == 0 && *id > endDay)) {
02384 data.day = *id;
02385 goto ex;
02386 }
02387 if (--countTogo == 0)
02388 return 0;
02389 }
02390 }
02391 } else {
02392
02393 uint n = days->count();
02394 if (n >= countTogo)
02395 return 0;
02396 countGone += n;
02397 }
02398 data.day = 1;
02399 }
02400 }
02401 data.month = 1;
02402 data.year += rFreq;
02403 }
02404 } else {
02405
02406 if (data.month > 1 || data.day > 1) {
02407
02408 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) {
02409 if (*im.current() >= data.month) {
02410
02411 data.month = *im.current();
02412 int ended = data.yearMonth() - endYearMonth;
02413 if (ended >= 0 || data.day > 1) {
02414
02415 days = data.dayList();
02416 for (id = days->begin(); id != days->end(); ++id) {
02417 if (*id >= data.day) {
02418 ++countGone;
02419 if (ended > 0 || (ended == 0 && *id > endDay)) {
02420 data.day = *id;
02421 goto ex;
02422 }
02423 if (--countTogo == 0)
02424 return 0;
02425 }
02426 }
02427 data.day = 1;
02428 } else {
02429
02430 if (static_cast<uint>(data.daysPerMonth) >= countTogo)
02431 return 0;
02432 countGone += data.daysPerMonth;
02433 }
02434 }
02435 }
02436 data.year += rFreq;
02437 }
02438
02439 int recurYears = (endYear - data.year + rFreq - 1) / rFreq;
02440 if ((endYear - data.year)%rFreq == 0
02441 && *rYearNums.getLast() <= endMonth)
02442 ++recurYears;
02443 if (recurYears) {
02444 int n = recurYears * data.count;
02445 if (static_cast<uint>(n) > countTogo)
02446 return 0;
02447 countTogo -= n;
02448 countGone += n;
02449 data.year += recurYears * rFreq;
02450 }
02451
02452
02453 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) {
02454 data.month = *im.current();
02455 int ended = data.yearMonth() - endYearMonth;
02456 if (ended >= 0) {
02457
02458 days = data.dayList();
02459 for (id = days->begin(); id != days->end(); ++id) {
02460 ++countGone;
02461 if (ended > 0 || (ended == 0 && *id > endDay)) {
02462 data.day = *id;
02463 goto ex;
02464 }
02465 if (--countTogo == 0)
02466 return 0;
02467 }
02468 } else {
02469
02470 if (static_cast<uint>(data.daysPerMonth) >= countTogo)
02471 return 0;
02472 countGone += data.daysPerMonth;
02473 }
02474 }
02475 }
02476 ex:
02477 enddate = data.date();
02478 return countGone;
02479 }
02480
02481
02482
02483
02484
02485
02486
02487 struct Recurrence::YearlyDayData {
02488 int year;
02489 int day;
02490 bool varies;
02491 private:
02492 int daycount;
02493 public:
02494 YearlyDayData(const Recurrence* r, const QDate &date)
02495 : year(date.year()), day(date.dayOfYear()), varies(*r->rYearNums.getLast() == 366),
02496 daycount(r->rYearNums.count()) { }
02497 bool leapYear() const { return QDate::leapYear(year); }
02498 int dayCount() const { return daycount - (varies && !QDate::leapYear(year) ? 1 : 0); }
02499 bool isMaxDayCount() const { return !varies || QDate::leapYear(year); }
02500 QDate date() const { return QDate(year, 1, 1).addDays(day - 1); }
02501 };
02502
02503 int Recurrence::yearlyDayCalc(PeriodFunc func, QDate &enddate) const
02504 {
02505 if (rYearNums.isEmpty())
02506 return 0;
02507 YearlyDayData data(this, mRecurStart.date());
02508 switch (func) {
02509 case END_DATE_AND_COUNT:
02510 return yearlyDayCalcEndDate(enddate, data);
02511 case COUNT_TO_DATE:
02512 return yearlyDayCalcToDate(enddate, data);
02513 case NEXT_AFTER_DATE:
02514 return yearlyDayCalcNextAfter(enddate, data);
02515 }
02516 return 0;
02517 }
02518
02519 int Recurrence::yearlyDayCalcEndDate(QDate &enddate, YearlyDayData &data) const
02520 {
02521 uint countTogo = rDuration + mRecurExDatesCount;
02522 int countGone = 0;
02523
02524 if (data.day > 1) {
02525
02526 bool leapOK = data.isMaxDayCount();
02527 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) {
02528 int d = *it.current();
02529 if (d >= data.day && (leapOK || d < 366)) {
02530 ++countGone;
02531 if (--countTogo == 0) {
02532 data.day = d;
02533 goto ex;
02534 }
02535 }
02536 }
02537 data.day = 1;
02538 data.year += rFreq;
02539 }
02540
02541 if (data.varies) {
02542
02543
02544 for ( ; ; ) {
02545 uint n = data.dayCount();
02546 if (n >= countTogo)
02547 break;
02548 countTogo -= n;
02549 countGone += n;
02550 data.year += rFreq;
02551 }
02552 } else {
02553
02554
02555
02556
02557 int daysPerYear = rYearNums.count();
02558 int wholeYears = (countTogo - 1) / daysPerYear;
02559 data.year += wholeYears * rFreq;
02560 countGone += wholeYears * daysPerYear;
02561 countTogo -= wholeYears * daysPerYear;
02562 }
02563 if (countTogo) {
02564
02565 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) {
02566 ++countGone;
02567 if (--countTogo == 0) {
02568 data.day = *it.current();
02569 break;
02570 }
02571 }
02572 }
02573 ex:
02574 enddate = data.date();
02575 return countGone;
02576 }
02577
02578 int Recurrence::yearlyDayCalcToDate(const QDate &enddate, YearlyDayData &data) const
02579 {
02580 int countGone = 0;
02581 int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX;
02582 int endYear = enddate.year();
02583 int endDay = enddate.dayOfYear();
02584
02585 if (data.day > 1) {
02586
02587 bool leapOK = data.isMaxDayCount();
02588 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) {
02589 int d = *it.current();
02590 if (d >= data.day && (leapOK || d < 366)) {
02591 if (data.year == endYear && d > endDay)
02592 return countGone;
02593 if (++countGone >= countMax)
02594 return countMax;
02595 }
02596 }
02597 data.day = 1;
02598 data.year += rFreq;
02599 }
02600
02601 if (data.varies) {
02602
02603
02604 while (data.year < endYear) {
02605 uint n = data.dayCount();
02606 countGone += n;
02607 if (countGone >= countMax)
02608 return countMax;
02609 data.year += rFreq;
02610 }
02611 if (data.year > endYear)
02612 return countGone;
02613 } else {
02614
02615
02616 int wholeYears = endYear - data.year;
02617 countGone += (wholeYears / rFreq) * rYearNums.count();
02618 if (countGone >= countMax)
02619 return countMax;
02620 if (wholeYears % rFreq)
02621 return countGone;
02622 data.year = endYear;
02623 }
02624
02625 if (data.year <= endYear) {
02626
02627 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) {
02628 if (*it.current() > endDay)
02629 return countGone;
02630 if (++countGone >= countMax)
02631 return countMax;
02632 }
02633 }
02634 return countGone;
02635 }
02636
02637 int Recurrence::yearlyDayCalcNextAfter(QDate &enddate, YearlyDayData &data) const
02638 {
02639 uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX;
02640 int countGone = 0;
02641 int endYear = enddate.year();
02642 int endDay = enddate.dayOfYear();
02643
02644 if (data.day > 1) {
02645
02646 bool leapOK = data.isMaxDayCount();
02647 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) {
02648 int d = *it.current();
02649 if (d >= data.day && (leapOK || d < 366)) {
02650 ++countGone;
02651 if (data.year == endYear && d > endDay) {
02652 data.day = d;
02653 goto ex;
02654 }
02655 if (--countTogo == 0)
02656 return 0;
02657 }
02658 }
02659 data.day = 1;
02660 data.year += rFreq;
02661 }
02662
02663 if (data.varies) {
02664
02665
02666 while (data.year <= endYear) {
02667 uint n = data.dayCount();
02668 if (data.year == endYear && *rYearNums.getLast() > endDay)
02669 break;
02670 if (n >= countTogo)
02671 break;
02672 countTogo -= n;
02673 countGone += n;
02674 data.year += rFreq;
02675 }
02676 } else {
02677
02678
02679
02680 int daysPerYear = rYearNums.count();
02681 int recurYears = (endYear - data.year + rFreq - 1) / rFreq;
02682 if ((endYear - data.year)%rFreq == 0
02683 && *rYearNums.getLast() <= endDay)
02684 ++recurYears;
02685 if (recurYears) {
02686 int n = recurYears * daysPerYear;
02687 if (static_cast<uint>(n) > countTogo)
02688 return 0;
02689 countTogo -= n;
02690 countGone += n;
02691 data.year += recurYears * rFreq;
02692 }
02693 }
02694
02695
02696 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) {
02697 ++countGone;
02698 int d = *it.current();
02699 if (data.year > endYear || d > endDay) {
02700 data.day = d;
02701 break;
02702 }
02703 if (--countTogo == 0)
02704 return 0;
02705 }
02706 ex:
02707 enddate = data.date();
02708 return countGone;
02709 }
02710
02711
02712
02713
02714 void Recurrence::getMonthlyPosDays(QValueList<int> &list, int daysInMonth, int startDayOfWeek) const
02715 {
02716 list.clear();
02717 int endDayOfWeek = (startDayOfWeek + daysInMonth - 2) % 7 + 1;
02718
02719 Q_UINT32 days = 0;
02720 for (QPtrListIterator<rMonthPos> pos(rMonthPositions); pos.current(); ++pos) {
02721 int weeknum = pos.current()->rPos - 1;
02722 QBitArray &rdays = pos.current()->rDays;
02723 if (pos.current()->negative) {
02724
02725 for (uint i = 1; i <= 7; ++i) {
02726 if (rdays.testBit(i - 1)) {
02727 int day = daysInMonth - weeknum*7 - (endDayOfWeek - i + 7) % 7;
02728 if (day > 0)
02729 days |= 1 << (day - 1);
02730 }
02731 }
02732 } else {
02733
02734 for (uint i = 1; i <= 7; ++i) {
02735 if (rdays.testBit(i - 1)) {
02736 int day = 1 + weeknum*7 + (i - startDayOfWeek + 7) % 7;
02737 if (day <= daysInMonth)
02738 days |= 1 << (day - 1);
02739 }
02740 }
02741 }
02742 }
02743
02744 Q_UINT32 mask = 1;
02745 for (int i = 0; i < daysInMonth; mask <<= 1, ++i) {
02746 if (days & mask)
02747 list.append(i + 1);
02748 }
02749 }
02750
02751
02752
02753 int Recurrence::countMonthlyPosDays() const
02754 {
02755 int count = 0;
02756 Q_UINT8 positive[5] = { 0, 0, 0, 0, 0 };
02757 Q_UINT8 negative[4] = { 0, 0, 0, 0 };
02758 for (QPtrListIterator<rMonthPos> pos(rMonthPositions); pos.current(); ++pos) {
02759 int weeknum = pos.current()->rPos;
02760 Q_UINT8* wk;
02761 if (pos.current()->negative) {
02762
02763 if (weeknum > 4)
02764 return -1;
02765 wk = &negative[4 - weeknum];
02766 } else {
02767
02768 if (weeknum > 4)
02769 return -1;
02770 wk = &positive[weeknum - 1];
02771 }
02772 QBitArray &rdays = pos.current()->rDays;
02773 for (uint i = 0; i < 7; ++i) {
02774 if (rdays.testBit(i)) {
02775 ++count;
02776 *wk |= (1 << i);
02777 }
02778 }
02779 }
02780
02781
02782 for (int i = 0; i < 4; ++i) {
02783 if (negative[i] & (positive[i] | positive[i+1]))
02784 return -1;
02785 }
02786 return count;
02787 }
02788
02789
02790
02791 bool Recurrence::getMonthlyDayDays(QValueList<int> &list, int daysInMonth) const
02792 {
02793 list.clear();
02794 bool variable = false;
02795 Q_UINT32 days = 0;
02796 for (QPtrListIterator<int> it(rMonthDays); it.current(); ++it) {
02797 int day = *it.current();
02798 if (day > 0) {
02799
02800 if (day <= daysInMonth)
02801 days |= 1 << (day - 1);
02802 if (day > 28 && day <= 31)
02803 variable = true;
02804 } else if (day < 0) {
02805
02806 variable = true;
02807 day = daysInMonth + day;
02808 if (day >= 0)
02809 days |= 1 << day;
02810 }
02811 }
02812
02813 Q_UINT32 mask = 1;
02814 for (int i = 0; i < daysInMonth; mask <<= 1, ++i) {
02815 if (days & mask)
02816 list.append(i + 1);
02817 }
02818 return variable;
02819 }
02820
02821
02822
02823 bool Recurrence::getYearlyMonthMonths(int day, QValueList<int> &list, QValueList<int> &leaplist) const
02824 {
02825 list.clear();
02826 leaplist.clear();
02827 bool feb29 = false;
02828 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) {
02829 int month = *it.current();
02830 if (month == 2) {
02831 if (day <= 28) {
02832 list.append(month);
02833 leaplist.append(month);
02834 }
02835 else if (day == 29) {
02836 leaplist.append(month);
02837 feb29 = true;
02838 }
02839 }
02840 else if (day <= 30 || QDate(2000, month, 1).daysInMonth() == 31) {
02841 list.append(month);
02842 leaplist.append(month);
02843 }
02844 }
02845 return feb29;
02846 }
02847
02848
02849
02850
02851
02852
02853
02854
02855 int Recurrence::getFirstDayInWeek(int startDay, bool useWeekStart) const
02856 {
02857 int last = ((useWeekStart ? rWeekStart : startDay) + 5)%7;
02858 for (int i = startDay - 1; ; i = (i + 1)%7) {
02859 if (rDays.testBit(i))
02860 return i + 1;
02861 if (i == last)
02862 return 0;
02863 }
02864 }
02865
02866
02867
02868
02869
02870
02871
02872
02873 int Recurrence::getLastDayInWeek(int endDay, bool useWeekStart) const
02874 {
02875 int last = useWeekStart ? rWeekStart - 1 : endDay%7;
02876 for (int i = endDay - 1; ; i = (i + 6)%7) {
02877 if (rDays.testBit(i))
02878 return i + 1;
02879 if (i == last)
02880 return 0;
02881 }
02882 }
02883
02884
02885
02886
02887
02888 QDate Recurrence::getFirstDateInMonth(const QDate &earliestDate) const
02889 {
02890 int earliestDay = earliestDate.day();
02891 int daysInMonth = earliestDate.daysInMonth();
02892 switch (recurs) {
02893 case rMonthlyDay: {
02894 int minday = daysInMonth + 1;
02895 for (QPtrListIterator<int> it(rMonthDays); it.current(); ++it) {
02896 int day = *it.current();
02897 if (day < 0)
02898 day = daysInMonth + day + 1;
02899 if (day >= earliestDay && day < minday)
02900 minday = day;
02901 }
02902 if (minday <= daysInMonth)
02903 return earliestDate.addDays(minday - earliestDay);
02904 break;
02905 }
02906 case rMonthlyPos:
02907 case rYearlyPos: {
02908 QDate monthBegin(earliestDate.addDays(1 - earliestDay));
02909 QValueList<int> dayList;
02910 getMonthlyPosDays(dayList, daysInMonth, monthBegin.dayOfWeek());
02911 for (QValueList<int>::ConstIterator id = dayList.begin(); id != dayList.end(); ++id) {
02912 if (*id >= earliestDay)
02913 return monthBegin.addDays(*id - 1);
02914 }
02915 break;
02916 }
02917 }
02918 return QDate();
02919 }
02920
02921
02922
02923
02924
02925 QDate Recurrence::getLastDateInMonth(const QDate &latestDate) const
02926 {
02927 int latestDay = latestDate.day();
02928 int daysInMonth = latestDate.daysInMonth();
02929 switch (recurs) {
02930 case rMonthlyDay: {
02931 int maxday = -1;
02932 for (QPtrListIterator<int> it(rMonthDays); it.current(); ++it) {
02933 int day = *it.current();
02934 if (day < 0)
02935 day = daysInMonth + day + 1;
02936 if (day <= latestDay && day > maxday)
02937 maxday = day;
02938 }
02939 if (maxday > 0)
02940 return QDate(latestDate.year(), latestDate.month(), maxday);
02941 break;
02942 }
02943 case rMonthlyPos:
02944 case rYearlyPos: {
02945 QDate monthBegin(latestDate.addDays(1 - latestDay));
02946 QValueList<int> dayList;
02947 getMonthlyPosDays(dayList, daysInMonth, monthBegin.dayOfWeek());
02948 for (QValueList<int>::ConstIterator id = dayList.fromLast(); id != dayList.end(); --id) {
02949 if (*id <= latestDay)
02950 return monthBegin.addDays(*id - 1);
02951 }
02952 break;
02953 }
02954 }
02955 return QDate();
02956 }
02957
02958
02959
02960
02961
02962 QDate Recurrence::getFirstDateInYear(const QDate &earliestDate) const
02963 {
02964 QPtrListIterator<int> it(rYearNums);
02965 switch (recurs) {
02966 case rYearlyMonth: {
02967 int day = recurStart().date().day();
02968 int earliestYear = earliestDate.year();
02969 int earliestMonth = earliestDate.month();
02970 if (earliestDate.day() > day) {
02971
02972
02973 if (++earliestMonth > 12)
02974 return QDate();
02975 }
02976 for ( ; it.current(); ++it) {
02977 int month = *it.current();
02978 if (month >= earliestMonth
02979 && (day <= 28 || QDate::isValid(earliestYear, month, day)))
02980 return QDate(earliestYear, month, day);
02981 }
02982 break;
02983 }
02984 case rYearlyPos: {
02985 QValueList<int> dayList;
02986 int earliestYear = earliestDate.year();
02987 int earliestMonth = earliestDate.month();
02988 int earliestDay = earliestDate.day();
02989 for ( ; it.current(); ++it) {
02990 int month = *it.current();
02991 if (month >= earliestMonth) {
02992 QDate monthBegin(earliestYear, month, 1);
02993 getMonthlyPosDays(dayList, monthBegin.daysInMonth(), monthBegin.dayOfWeek());
02994 for (QValueList<int>::ConstIterator id = dayList.begin(); id != dayList.end(); ++id) {
02995 if (*id >= earliestDay)
02996 return monthBegin.addDays(*id - 1);
02997 }
02998 earliestDay = 1;
02999 }
03000 }
03001 break;
03002 }
03003 case rYearlyDay: {
03004 int earliestDay = earliestDate.dayOfYear();
03005 for ( ; it.current(); ++it) {
03006 int day = *it.current();
03007 if (day >= earliestDay && (day <= 365 || day <= earliestDate.daysInYear()))
03008 return earliestDate.addDays(day - earliestDay);
03009 }
03010 break;
03011 }
03012 }
03013 return QDate();
03014 }
03015
03016
03017
03018
03019
03020 QDate Recurrence::getLastDateInYear(const QDate &latestDate) const
03021 {
03022 QPtrListIterator<int> it(rYearNums);
03023 switch (recurs) {
03024 case rYearlyMonth: {
03025 int day = recurStart().date().day();
03026 int latestYear = latestDate.year();
03027 int latestMonth = latestDate.month();
03028 if (latestDate.day() > day) {
03029
03030
03031 if (--latestMonth <= 0)
03032 return QDate();
03033 }
03034 for (it.toLast(); it.current(); --it) {
03035 int month = *it.current();
03036 if (month <= latestMonth
03037 && (day <= 28 || QDate::isValid(latestYear, month, day)))
03038 return QDate(latestYear, month, day);
03039 }
03040 break;
03041 }
03042 case rYearlyPos: {
03043 QValueList<int> dayList;
03044 int latestYear = latestDate.year();
03045 int latestMonth = latestDate.month();
03046 int latestDay = latestDate.day();
03047 for (it.toLast(); it.current(); --it) {
03048 int month = *it.current();
03049 if (month <= latestMonth) {
03050 QDate monthBegin(latestYear, month, 1);
03051 getMonthlyPosDays(dayList, monthBegin.daysInMonth(), monthBegin.dayOfWeek());
03052 for (QValueList<int>::ConstIterator id = dayList.fromLast(); id != dayList.end(); --id) {
03053 if (*id <= latestDay)
03054 return monthBegin.addDays(*id - 1);
03055 }
03056 latestDay = 31;
03057 }
03058 }
03059 break;
03060 }
03061 case rYearlyDay: {
03062 int latestDay = latestDate.dayOfYear();
03063 for (it.toLast(); it.current(); --it) {
03064 int day = *it.current();
03065 if (day <= latestDay)
03066 return latestDate.addDays(day - latestDay);
03067 }
03068 break;
03069 }
03070 }
03071 return QDate();
03072 }