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