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