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 }