00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "recurrencerule.h"
00024
00025 #include <kdebug.h>
00026 #include <kglobal.h>
00027 #include <qdatetime.h>
00028 #include <qstringlist.h>
00029
00030 #include <limits.h>
00031 #include <math.h>
00032
00033 using namespace KCal;
00034
00035
00036 const int LOOP_LIMIT = 10000;
00037
00038
00039
00040
00060 long long ownSecsTo( const QDateTime &dt1, const QDateTime &dt2 )
00061 {
00062 long long res = static_cast<long long>( dt1.date().daysTo( dt2.date() ) ) * 24*3600;
00063 res += dt1.time().secsTo( dt2.time() );
00064 return res;
00065 }
00066
00067
00068
00069
00070
00071
00072
00073
00074 class DateHelper {
00075 public:
00076 #ifndef NDEBUG
00077 static QString dayName( short day );
00078 #endif
00079 static QDate getNthWeek( int year, int weeknumber, short weekstart = 1 );
00080 static int weekNumbersInYear( int year, short weekstart = 1 );
00081 static int getWeekNumber( const QDate &date, short weekstart, int *year = 0 );
00082 static int getWeekNumberNeg( const QDate &date, short weekstart, int *year = 0 );
00083 };
00084
00085
00086 #ifndef NDEBUG
00087 QString DateHelper::dayName( short day )
00088 {
00089 switch ( day ) {
00090 case 1: return "MO"; break;
00091 case 2: return "TU"; break;
00092 case 3: return "WE"; break;
00093 case 4: return "TH"; break;
00094 case 5: return "FR"; break;
00095 case 6: return "SA"; break;
00096 case 7: return "SU"; break;
00097 default: return "??";
00098 }
00099 }
00100 #endif
00101
00102
00103 QDate DateHelper::getNthWeek( int year, int weeknumber, short weekstart )
00104 {
00105 if ( weeknumber == 0 ) return QDate();
00106
00107 QDate dt( year, 1, 4 );
00108 int adjust = -(7 + dt.dayOfWeek() - weekstart) % 7;
00109 if ( weeknumber > 0 ) {
00110 dt = dt.addDays( 7 * (weeknumber-1) + adjust );
00111 } else if ( weeknumber < 0 ) {
00112 dt = dt.addYears( 1 );
00113 dt = dt.addDays( 7 * weeknumber + adjust );
00114 }
00115 return dt;
00116 }
00117
00118
00119 int DateHelper::getWeekNumber( const QDate &date, short weekstart, int *year )
00120 {
00121
00122 if ( year ) *year = date.year();
00123 QDate dt( date.year(), 1, 4 );
00124 dt = dt.addDays( -(7 + dt.dayOfWeek() - weekstart) % 7 );
00125 QDate dtn( date.year()+1, 1, 4 );
00126 dtn = dtn.addDays( -(7 + dtn.dayOfWeek() - weekstart) % 7 );
00127
00128 int daysto = dt.daysTo( date );
00129 int dayston = dtn.daysTo( date );
00130 if ( daysto < 0 ) {
00131 if ( year ) *year = date.year()-1;
00132 dt = QDate( date.year()-1, 1, 4 );
00133 dt = dt.addDays( -(7 + dt.dayOfWeek() - weekstart) % 7 );
00134 daysto = dt.daysTo( date );
00135 } else if ( dayston >= 0 ) {
00136
00137 if ( year ) *year = date.year() + 1;
00138 dt = dtn;
00139 daysto = dayston;
00140 }
00141 return daysto / 7 + 1;
00142 }
00143
00144 int DateHelper::weekNumbersInYear( int year, short weekstart )
00145 {
00146 QDate dt( year, 1, weekstart );
00147 QDate dt1( year + 1, 1, weekstart );
00148 return dt.daysTo( dt1 ) / 7;
00149 }
00150
00151
00152 int DateHelper::getWeekNumberNeg( const QDate &date, short weekstart, int *year )
00153 {
00154 int weekpos = getWeekNumber( date, weekstart, year );
00155 return weekNumbersInYear( *year, weekstart ) - weekpos - 1;
00156 }
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167 RecurrenceRule::Constraint::Constraint( int wkst )
00168 {
00169 weekstart = wkst;
00170 clear();
00171 }
00172
00173 RecurrenceRule::Constraint::Constraint( const QDateTime &preDate, PeriodType type, int wkst )
00174 {
00175 weekstart = wkst;
00176 readDateTime( preDate, type );
00177 }
00178
00179 void RecurrenceRule::Constraint::clear()
00180 {
00181 year = 0;
00182 month = 0;
00183 day = 0;
00184 hour = -1;
00185 minute = -1;
00186 second = -1;
00187 weekday = 0;
00188 weekdaynr = 0;
00189 weeknumber = 0;
00190 yearday = 0;
00191 }
00192
00193 bool RecurrenceRule::Constraint::matches( const QDate &dt, RecurrenceRule::PeriodType type ) const
00194 {
00195
00196
00197
00198 if ( weeknumber == 0 ) {
00199 if ( year > 0 && year != dt.year() ) return false;
00200 } else {
00201 int y;
00202 if ( weeknumber > 0 &&
00203 weeknumber != DateHelper::getWeekNumber( dt, weekstart, &y ) ) return false;
00204 if ( weeknumber < 0 &&
00205 weeknumber != DateHelper::getWeekNumberNeg( dt, weekstart, &y ) ) return false;
00206 if ( year > 0 && year != y ) return false;
00207 }
00208
00209 if ( month > 0 && month != dt.month() ) return false;
00210 if ( day > 0 && day != dt.day() ) return false;
00211 if ( day < 0 && dt.day() != (dt.daysInMonth() + day + 1 ) ) return false;
00212 if ( weekday > 0 ) {
00213 if ( weekday != dt.dayOfWeek() ) return false;
00214 if ( weekdaynr != 0 ) {
00215
00216
00217 bool inMonth = (type == rMonthly) || ( type == rYearly && month > 0 );
00218
00219 if ( weekdaynr > 0 && inMonth &&
00220 weekdaynr != (dt.day() - 1)/7 + 1 ) return false;
00221 if ( weekdaynr < 0 && inMonth &&
00222 weekdaynr != -((dt.daysInMonth() - dt.day() )/7 + 1 ) )
00223 return false;
00224
00225 if ( weekdaynr > 0 && !inMonth &&
00226 weekdaynr != (dt.dayOfYear() - 1)/7 + 1 ) return false;
00227 if ( weekdaynr < 0 && !inMonth &&
00228 weekdaynr != -((dt.daysInYear() - dt.dayOfYear() )/7 + 1 ) )
00229 return false;
00230 }
00231 }
00232 if ( yearday > 0 && yearday != dt.dayOfYear() ) return false;
00233 if ( yearday < 0 && yearday != dt.daysInYear() - dt.dayOfYear() + 1 )
00234 return false;
00235 return true;
00236 }
00237
00238 bool RecurrenceRule::Constraint::matches( const QDateTime &dt, RecurrenceRule::PeriodType type ) const
00239 {
00240 if ( !matches( dt.date(), type ) ) return false;
00241 if ( hour >= 0 && hour != dt.time().hour() ) return false;
00242 if ( minute >= 0 && minute != dt.time().minute() ) return false;
00243 if ( second >= 0 && second != dt.time().second() ) return false;
00244 return true;
00245 }
00246
00247 bool RecurrenceRule::Constraint::isConsistent( PeriodType ) const
00248 {
00249
00250 return true;
00251 }
00252
00253 QDateTime RecurrenceRule::Constraint::intervalDateTime( RecurrenceRule::PeriodType type ) const
00254 {
00255 QDateTime dt;
00256 dt.setTime( QTime( 0, 0, 0 ) );
00257 dt.setDate( QDate( year, (month>0)?month:1, (day>0)?day:1 ) );
00258 if ( day < 0 )
00259 dt = dt.addDays( dt.date().daysInMonth() + day );
00260 switch ( type ) {
00261 case rSecondly:
00262 dt.setTime( QTime( hour, minute, second ) ); break;
00263 case rMinutely:
00264 dt.setTime( QTime( hour, minute, 1 ) ); break;
00265 case rHourly:
00266 dt.setTime( QTime( hour, 1, 1 ) ); break;
00267 case rDaily:
00268 break;
00269 case rWeekly:
00270 dt = DateHelper::getNthWeek( year, weeknumber, weekstart ); break;
00271 case rMonthly:
00272 dt.setDate( QDate( year, month, 1 ) ); break;
00273 case rYearly:
00274 dt.setDate( QDate( year, 1, 1 ) ); break;
00275 default:
00276 break;
00277 }
00278 return dt;
00279 }
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299 DateTimeList RecurrenceRule::Constraint::dateTimes( RecurrenceRule::PeriodType type ) const
00300 {
00301
00302 DateTimeList result;
00303 bool done = false;
00304
00305 QTime tm( hour, minute, second );
00306 if ( !isConsistent( type ) ) return result;
00307
00308 if ( !done && day > 0 && month > 0 ) {
00309 QDateTime dt( QDate( year, month, day ), tm );
00310 if ( dt.isValid() ) result.append( dt );
00311 done = true;
00312 }
00313 if ( !done && day < 0 && month > 0 ) {
00314 QDateTime dt( QDate( year, month, 1 ), tm );
00315 dt = dt.addDays( dt.date().daysInMonth() + day );
00316 if ( dt.isValid() ) result.append( dt );
00317 done = true;
00318 }
00319
00320
00321 if ( !done && weekday == 0 && weeknumber == 0 && yearday == 0 ) {
00322
00323 uint mstart = (month>0) ? month : 1;
00324 uint mend = (month <= 0) ? 12 : month;
00325 for ( uint m = mstart; m <= mend; ++m ) {
00326 uint dstart, dend;
00327 if ( day > 0 ) {
00328 dstart = dend = day;
00329 } else if ( day < 0 ) {
00330 QDate date( year, month, 1 );
00331 dstart = dend = date.daysInMonth() + day + 1;
00332 } else {
00333 QDate date( year, month, 1 );
00334 dstart = 1;
00335 dend = date.daysInMonth();
00336 }
00337 for ( uint d = dstart; d <= dend; ++d ) {
00338 QDateTime dt( QDate( year, m, d ), tm );
00339 if ( dt.isValid() ) result.append( dt );
00340 }
00341 }
00342 done = true;
00343 }
00344
00345
00346
00347 if ( !done && yearday != 0 ) {
00348
00349 QDate d( year + ((yearday>0)?0:1), 1, 1 );
00350 d = d.addDays( yearday - ((yearday>0)?1:0) );
00351 result.append( QDateTime( d, tm ) );
00352 done = true;
00353 }
00354
00355
00356 if ( !done && weeknumber != 0 ) {
00357 QDate wst( DateHelper::getNthWeek( year, weeknumber, weekstart ) );
00358 if ( weekday != 0 ) {
00359 wst = wst.addDays( (7 + weekday - weekstart ) % 7 );
00360 result.append( QDateTime( wst, tm ) );
00361 } else {
00362 for ( int i = 0; i < 7; ++i ) {
00363 result.append( QDateTime( wst, tm ) );
00364 wst = wst.addDays( 1 );
00365 }
00366 }
00367 done = true;
00368 }
00369
00370
00371 if ( !done && weekday != 0 ) {
00372 QDate dt( year, 1, 1 );
00373
00374
00375 int maxloop = 53;
00376 bool inMonth = ( type == rMonthly) || ( type == rYearly && month > 0 );
00377 if ( inMonth && month > 0 ) {
00378 dt = QDate( year, month, 1 );
00379 maxloop = 5;
00380 }
00381 if ( weekdaynr < 0 ) {
00382
00383 if ( inMonth )
00384 dt = dt.addMonths( 1 );
00385 else
00386 dt = dt.addYears( 1 );
00387 }
00388 int adj = ( 7 + weekday - dt.dayOfWeek() ) % 7;
00389 dt = dt.addDays( adj );
00390
00391 if ( weekdaynr > 0 ) {
00392 dt = dt.addDays( ( weekdaynr - 1 ) * 7 );
00393 result.append( QDateTime( dt, tm ) );
00394 } else if ( weekdaynr < 0 ) {
00395 dt = dt.addDays( weekdaynr * 7 );
00396 result.append( QDateTime( dt, tm ) );
00397 } else {
00398
00399 for ( int i = 0; i < maxloop; ++i ) {
00400 result.append( QDateTime( dt, tm ) );
00401 dt = dt.addDays( 7 );
00402 }
00403 }
00404 }
00405
00406
00407
00408 DateTimeList valid;
00409 DateTimeList::Iterator it;
00410 for ( it = result.begin(); it != result.end(); ++it ) {
00411 if ( matches( *it, type ) ) valid.append( *it );
00412 }
00413
00414
00415 return valid;
00416 }
00417
00418
00419 bool RecurrenceRule::Constraint::increase( RecurrenceRule::PeriodType type, int freq )
00420 {
00421
00422
00423 QDateTime dt( intervalDateTime( type ) );
00424
00425
00426 switch ( type ) {
00427 case rSecondly:
00428 dt = dt.addSecs( freq ); break;
00429 case rMinutely:
00430 dt = dt.addSecs( 60*freq ); break;
00431 case rHourly:
00432 dt = dt.addSecs( 3600 * freq ); break;
00433 case rDaily:
00434 dt = dt.addDays( freq ); break;
00435 case rWeekly:
00436 dt = dt.addDays( 7*freq ); break;
00437 case rMonthly:
00438 dt = dt.addMonths( freq ); break;
00439 case rYearly:
00440 dt = dt.addYears( freq ); break;
00441 default:
00442 break;
00443 }
00444
00445 readDateTime( dt, type );
00446
00447 return true;
00448 }
00449
00450 bool RecurrenceRule::Constraint::readDateTime( const QDateTime &preDate, PeriodType type )
00451 {
00452 clear();
00453 switch ( type ) {
00454
00455 case rSecondly:
00456 second = preDate.time().second();
00457 case rMinutely:
00458 minute = preDate.time().minute();
00459 case rHourly:
00460 hour = preDate.time().hour();
00461 case rDaily:
00462 day = preDate.date().day();
00463 case rMonthly:
00464 month = preDate.date().month();
00465 case rYearly:
00466 year = preDate.date().year();
00467 break;
00468
00469 case rWeekly:
00470
00471 weeknumber = DateHelper::getWeekNumber( preDate.date(), weekstart, &year );
00472 break;
00473 default:
00474 break;
00475 }
00476 return true;
00477 }
00478
00479
00480 RecurrenceRule::RecurrenceRule( )
00481 : mPeriod( rNone ), mFrequency( 0 ), mIsReadOnly( false ),
00482 mFloating( false ),
00483 mWeekStart(1)
00484 {
00485 }
00486
00487 RecurrenceRule::RecurrenceRule( const RecurrenceRule &r )
00488 {
00489 mRRule = r.mRRule;
00490 mPeriod = r.mPeriod;
00491 mDateStart = r.mDateStart;
00492 mDuration = r.mDuration;
00493 mDateEnd = r.mDateEnd;
00494 mFrequency = r.mFrequency;
00495
00496 mIsReadOnly = r.mIsReadOnly;
00497 mFloating = r.mFloating;
00498
00499 mBySeconds = r.mBySeconds;
00500 mByMinutes = r.mByMinutes;
00501 mByHours = r.mByHours;
00502 mByDays = r.mByDays;
00503 mByMonthDays = r.mByMonthDays;
00504 mByYearDays = r.mByYearDays;
00505 mByWeekNumbers = r.mByWeekNumbers;
00506 mByMonths = r.mByMonths;
00507 mBySetPos = r.mBySetPos;
00508 mWeekStart = r.mWeekStart;
00509
00510 setDirty();
00511 }
00512
00513 RecurrenceRule::~RecurrenceRule()
00514 {
00515 }
00516
00517 bool RecurrenceRule::operator==( const RecurrenceRule& r ) const
00518 {
00519 if ( mPeriod != r.mPeriod ) return false;
00520 if ( mDateStart != r.mDateStart ) return false;
00521 if ( mDuration != r.mDuration ) return false;
00522 if ( mDateEnd != r.mDateEnd ) return false;
00523 if ( mFrequency != r.mFrequency ) return false;
00524
00525 if ( mIsReadOnly != r.mIsReadOnly ) return false;
00526 if ( mFloating != r.mFloating ) return false;
00527
00528 if ( mBySeconds != r.mBySeconds ) return false;
00529 if ( mByMinutes != r.mByMinutes ) return false;
00530 if ( mByHours != r.mByHours ) return false;
00531 if ( mByDays != r.mByDays ) return false;
00532 if ( mByMonthDays != r.mByMonthDays ) return false;
00533 if ( mByYearDays != r.mByYearDays ) return false;
00534 if ( mByWeekNumbers != r.mByWeekNumbers ) return false;
00535 if ( mByMonths != r.mByMonths ) return false;
00536 if ( mBySetPos != r.mBySetPos ) return false;
00537 if ( mWeekStart != r.mWeekStart ) return false;
00538
00539 return true;
00540 }
00541
00542 void RecurrenceRule::addObserver( Observer *observer )
00543 {
00544 if ( !mObservers.contains( observer ) )
00545 mObservers.append( observer );
00546 }
00547
00548 void RecurrenceRule::removeObserver( Observer *observer )
00549 {
00550 if ( mObservers.contains( observer ) )
00551 mObservers.remove( observer );
00552 }
00553
00554
00555
00556 void RecurrenceRule::setRecurrenceType( PeriodType period )
00557 {
00558 if ( isReadOnly() ) return;
00559 mPeriod = period;
00560 setDirty();
00561 }
00562
00563 QDateTime RecurrenceRule::endDt( bool *result ) const
00564 {
00565 if ( result ) *result = false;
00566 if ( mPeriod == rNone ) return QDateTime();
00567 if ( mDuration < 0 ) return QDateTime();
00568 if ( mDuration == 0 ) {
00569 if ( result ) *result = true;
00570 return mDateEnd;
00571 }
00572
00573 if ( ! mCached ) {
00574
00575 if ( !buildCache() ) return QDateTime();
00576 }
00577 if ( result ) *result = true;
00578 return mCachedDateEnd;
00579 }
00580
00581 void RecurrenceRule::setEndDt( const QDateTime &dateTime )
00582 {
00583 if ( isReadOnly() ) return;
00584 mDateEnd = dateTime;
00585 mDuration = 0;
00586 setDirty();
00587 }
00588
00589 void RecurrenceRule::setDuration(int duration)
00590 {
00591 if ( isReadOnly() ) return;
00592 mDuration = duration;
00593 setDirty();
00594 }
00595
00596 void RecurrenceRule::setFloats( bool floats )
00597 {
00598 if ( isReadOnly() ) return;
00599 mFloating = floats;
00600 setDirty();
00601 }
00602
00603 void RecurrenceRule::clear()
00604 {
00605 if ( isReadOnly() ) return;
00606 mPeriod = rNone;
00607 mBySeconds.clear();
00608 mByMinutes.clear();
00609 mByHours.clear();
00610 mByDays.clear();
00611 mByMonthDays.clear();
00612 mByYearDays.clear();
00613 mByWeekNumbers.clear();
00614 mByMonths.clear();
00615 mBySetPos.clear();
00616 mWeekStart = 1;
00617
00618 setDirty();
00619 }
00620
00621 void RecurrenceRule::setDirty()
00622 {
00623 mConstraints.clear();
00624 buildConstraints();
00625 mDirty = true;
00626 mCached = false;
00627 mCachedDates.clear();
00628 for ( QValueList<Observer*>::ConstIterator it = mObservers.begin();
00629 it != mObservers.end(); ++it ) {
00630 if ( (*it) ) (*it)->recurrenceChanged( this );
00631 }
00632 }
00633
00634 void RecurrenceRule::setStartDt( const QDateTime &start )
00635 {
00636 if ( isReadOnly() ) return;
00637 mDateStart = start;
00638 setDirty();
00639 }
00640
00641 void RecurrenceRule::setFrequency(int freq)
00642 {
00643 if ( isReadOnly() || freq <= 0 ) return;
00644 mFrequency = freq;
00645 setDirty();
00646 }
00647
00648 void RecurrenceRule::setBySeconds( const QValueList<int> bySeconds )
00649 {
00650 if ( isReadOnly() ) return;
00651 mBySeconds = bySeconds;
00652 setDirty();
00653 }
00654
00655 void RecurrenceRule::setByMinutes( const QValueList<int> byMinutes )
00656 {
00657 if ( isReadOnly() ) return;
00658 mByMinutes = byMinutes;
00659 setDirty();
00660 }
00661
00662 void RecurrenceRule::setByHours( const QValueList<int> byHours )
00663 {
00664 if ( isReadOnly() ) return;
00665 mByHours = byHours;
00666 setDirty();
00667 }
00668
00669
00670 void RecurrenceRule::setByDays( const QValueList<WDayPos> byDays )
00671 {
00672 if ( isReadOnly() ) return;
00673 mByDays = byDays;
00674 setDirty();
00675 }
00676
00677 void RecurrenceRule::setByMonthDays( const QValueList<int> byMonthDays )
00678 {
00679 if ( isReadOnly() ) return;
00680 mByMonthDays = byMonthDays;
00681 setDirty();
00682 }
00683
00684 void RecurrenceRule::setByYearDays( const QValueList<int> byYearDays )
00685 {
00686 if ( isReadOnly() ) return;
00687 mByYearDays = byYearDays;
00688 setDirty();
00689 }
00690
00691 void RecurrenceRule::setByWeekNumbers( const QValueList<int> byWeekNumbers )
00692 {
00693 if ( isReadOnly() ) return;
00694 mByWeekNumbers = byWeekNumbers;
00695 setDirty();
00696 }
00697
00698 void RecurrenceRule::setByMonths( const QValueList<int> byMonths )
00699 {
00700 if ( isReadOnly() ) return;
00701 mByMonths = byMonths;
00702 setDirty();
00703 }
00704
00705 void RecurrenceRule::setBySetPos( const QValueList<int> bySetPos )
00706 {
00707 if ( isReadOnly() ) return;
00708 mBySetPos = bySetPos;
00709 setDirty();
00710 }
00711
00712 void RecurrenceRule::setWeekStart( short weekStart )
00713 {
00714 if ( isReadOnly() ) return;
00715 mWeekStart = weekStart;
00716 setDirty();
00717 }
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777 void RecurrenceRule::buildConstraints()
00778 {
00779 mTimedRepetition = 0;
00780 mNoByRules = mBySetPos.isEmpty();
00781 mConstraints.clear();
00782 Constraint con;
00783 if ( mWeekStart > 0 ) con.weekstart = mWeekStart;
00784 mConstraints.append( con );
00785
00786 Constraint::List tmp;
00787 Constraint::List::const_iterator it;
00788 QValueList<int>::const_iterator intit;
00789
00790 #define intConstraint( list, element ) \
00791 if ( !list.isEmpty() ) { \
00792 mNoByRules = false; \
00793 for ( it = mConstraints.constBegin(); it != mConstraints.constEnd(); ++it ) { \
00794 for ( intit = list.constBegin(); intit != list.constEnd(); ++intit ) { \
00795 con = (*it); \
00796 con.element = (*intit); \
00797 tmp.append( con ); \
00798 } \
00799 } \
00800 mConstraints = tmp; \
00801 tmp.clear(); \
00802 }
00803
00804 intConstraint( mBySeconds, second );
00805 intConstraint( mByMinutes, minute );
00806 intConstraint( mByHours, hour );
00807 intConstraint( mByMonthDays, day );
00808 intConstraint( mByMonths, month );
00809 intConstraint( mByYearDays, yearday );
00810 intConstraint( mByWeekNumbers, weeknumber );
00811 #undef intConstraint
00812
00813 if ( !mByDays.isEmpty() ) {
00814 mNoByRules = false;
00815 for ( it = mConstraints.constBegin(); it != mConstraints.constEnd(); ++it ) {
00816 QValueList<WDayPos>::const_iterator dayit;
00817 for ( dayit = mByDays.constBegin(); dayit != mByDays.constEnd(); ++dayit ) {
00818 con = (*it);
00819 con.weekday = (*dayit).day();
00820 con.weekdaynr = (*dayit).pos();
00821 tmp.append( con );
00822 }
00823 }
00824 mConstraints = tmp;
00825 tmp.clear();
00826 }
00827
00828 #define fixConstraint( element, value ) \
00829 { \
00830 tmp.clear(); \
00831 for ( it = mConstraints.constBegin(); it != mConstraints.constEnd(); ++it ) { \
00832 con = (*it); con.element = value; tmp.append( con ); \
00833 } \
00834 mConstraints = tmp; \
00835 }
00836
00837
00838
00839
00840 if ( mPeriod == rWeekly && mByDays.isEmpty() ) {
00841 fixConstraint( weekday, mDateStart.date().dayOfWeek() );
00842 }
00843
00844
00845
00846 switch ( mPeriod ) {
00847 case rYearly:
00848 if ( mByDays.isEmpty() && mByWeekNumbers.isEmpty() && mByYearDays.isEmpty() && mByMonths.isEmpty() ) {
00849 fixConstraint( month, mDateStart.date().month() );
00850 }
00851 case rMonthly:
00852 if ( mByDays.isEmpty() && mByWeekNumbers.isEmpty() && mByYearDays.isEmpty() && mByMonthDays.isEmpty() ) {
00853 fixConstraint( day, mDateStart.date().day() );
00854 }
00855
00856 case rWeekly:
00857 case rDaily:
00858 if ( mByHours.isEmpty() ) {
00859 fixConstraint( hour, mDateStart.time().hour() );
00860 }
00861 case rHourly:
00862 if ( mByMinutes.isEmpty() ) {
00863 fixConstraint( minute, mDateStart.time().minute() );
00864 }
00865 case rMinutely:
00866 if ( mBySeconds.isEmpty() ) {
00867 fixConstraint( second, mDateStart.time().second() );
00868 }
00869 case rSecondly:
00870 default:
00871 break;
00872 }
00873 #undef fixConstraint
00874
00875 if ( mNoByRules ) {
00876 switch ( mPeriod ) {
00877 case rHourly:
00878 mTimedRepetition = mFrequency * 3600;
00879 break;
00880 case rMinutely:
00881 mTimedRepetition = mFrequency * 60;
00882 break;
00883 case rSecondly:
00884 mTimedRepetition = mFrequency;
00885 break;
00886 default:
00887 break;
00888 }
00889 } else {
00890 Constraint::List::Iterator conit = mConstraints.begin();
00891 while ( conit != mConstraints.end() ) {
00892 if ( (*conit).isConsistent( mPeriod ) ) {
00893 ++conit;
00894 } else {
00895 conit = mConstraints.remove( conit );
00896 }
00897 }
00898 }
00899 }
00900
00901 bool RecurrenceRule::buildCache() const
00902 {
00903 kdDebug(5800) << " RecurrenceRule::buildCache: " << endl;
00904
00905
00906 Constraint interval( getNextValidDateInterval( startDt(), recurrenceType() ) );
00907 QDateTime next;
00908
00909 DateTimeList dts = datesForInterval( interval, recurrenceType() );
00910 DateTimeList::Iterator it = dts.begin();
00911
00912
00913 while ( it != dts.end() ) {
00914 if ( (*it) < startDt() ) it = dts.remove( it );
00915 else ++it;
00916 }
00917
00918
00919
00920 int loopnr = 0;
00921 int dtnr = dts.count();
00922
00923
00924 while ( loopnr < 10000 && dtnr < mDuration ) {
00925 interval.increase( recurrenceType(), frequency() );
00926
00927 dts += datesForInterval( interval, recurrenceType() );
00928 dtnr = dts.count();
00929 ++loopnr;
00930 }
00931 if ( int(dts.count()) > mDuration ) {
00932
00933 it = dts.at( mDuration );
00934 while ( it != dts.end() ) it = dts.remove( it );
00935 }
00936 mCached = true;
00937 mCachedDates = dts;
00938
00939 kdDebug(5800) << " Finished Building Cache, cache has " << dts.count() << " entries:" << endl;
00940
00941
00942
00943
00944
00945 if ( int(dts.count()) == mDuration ) {
00946 mCachedDateEnd = dts.last();
00947 return true;
00948 } else {
00949 mCachedDateEnd = QDateTime();
00950 return false;
00951 }
00952 }
00953
00954 bool RecurrenceRule::dateMatchesRules( const QDateTime &qdt ) const
00955 {
00956 bool match = false;
00957 for ( Constraint::List::ConstIterator it = mConstraints.begin();
00958 it!=mConstraints.end(); ++it ) {
00959 match = match || ( (*it).matches( qdt, recurrenceType() ) );
00960 }
00961 return match;
00962 }
00963
00964 bool RecurrenceRule::recursOn( const QDate &qd ) const
00965 {
00966 int i, iend;
00967 if ( doesFloat() ) {
00968
00969 if ( qd < mDateStart.date() ) {
00970 return false;
00971 }
00972
00973 QDate endDate;
00974 if ( mDuration >= 0 ) {
00975 endDate = endDt().date();
00976 if ( qd > endDate ) {
00977 return false;
00978 }
00979 }
00980
00981
00982
00983 bool match = false;
00984 for ( i = 0, iend = mConstraints.count(); i < iend && !match; ++i ) {
00985 match = mConstraints[i].matches( qd, recurrenceType() );
00986 }
00987 if ( !match ) {
00988 return false;
00989 }
00990
00991 QDateTime start( qd, QTime( 0, 0, 0 ) );
00992 Constraint interval( getNextValidDateInterval( start, recurrenceType() ) );
00993
00994
00995 if ( !interval.matches( qd, recurrenceType() ) ) {
00996 return false;
00997 }
00998
00999
01000
01001 QDateTime end = start.addDays(1);
01002 do {
01003 DateTimeList dts = datesForInterval( interval, recurrenceType() );
01004 for ( i = 0, iend = dts.count(); i < iend; ++i ) {
01005 if ( dts[i].date() >= qd ) {
01006 return dts[i].date() == qd;
01007 }
01008 }
01009 interval.increase( recurrenceType(), frequency() );
01010 } while ( interval.intervalDateTime( recurrenceType() ) < end );
01011 return false;
01012 }
01013
01014
01015 QDateTime start( qd, QTime( 0, 0, 0 ) );
01016 QDateTime end = start.addDays( 1 );
01017 if ( end < mDateStart ) {
01018 return false;
01019 }
01020 if ( start < mDateStart ) {
01021 start = mDateStart;
01022 }
01023
01024
01025 if ( mDuration >= 0 ) {
01026 QDateTime endRecur = endDt();
01027 if ( endRecur.isValid() ) {
01028 if ( start > endRecur ) {
01029 return false;
01030 }
01031 if ( end > endRecur ) {
01032 end = endRecur;
01033 }
01034 }
01035 }
01036
01037 if ( mTimedRepetition ) {
01038
01039 int n = static_cast<int>( ( mDateStart.secsTo( start ) - 1 ) % mTimedRepetition );
01040 return start.addSecs( mTimedRepetition - n ) < end;
01041 }
01042
01043
01044 QDate startDay = start.date();
01045 QDate endDay = end.addSecs( -1 ).date();
01046 int dayCount = startDay.daysTo( endDay ) + 1;
01047
01048
01049
01050 bool match = false;
01051 for ( i = 0, iend = mConstraints.count(); i < iend && !match; ++i ) {
01052 match = mConstraints[i].matches( startDay, recurrenceType() );
01053 for ( int day = 1; day < dayCount && !match; ++day ) {
01054 match = mConstraints[i].matches( startDay.addDays( day ), recurrenceType() );
01055 }
01056 }
01057 if ( !match ) {
01058 return false;
01059 }
01060
01061 Constraint interval( getNextValidDateInterval( start, recurrenceType() ) );
01062
01063
01064 match = false;
01065 Constraint intervalm = interval;
01066 do {
01067 match = intervalm.matches( startDay, recurrenceType() );
01068 for ( int day = 1; day < dayCount && !match; ++day ) {
01069 match = intervalm.matches( startDay.addDays( day ), recurrenceType() );
01070 }
01071 if ( match ) {
01072 break;
01073 }
01074 intervalm.increase( recurrenceType(), frequency() );
01075 } while ( intervalm.intervalDateTime( recurrenceType() ) < end );
01076 if ( !match ) {
01077 return false;
01078 }
01079
01080
01081
01082
01083 do {
01084 DateTimeList dts = datesForInterval( interval, recurrenceType() );
01085 int i = findGE( dts, start, 0 );
01086 if ( i >= 0 ) {
01087 return dts[i] <= end;
01088 }
01089 interval.increase( recurrenceType(), frequency() );
01090 } while ( interval.intervalDateTime( recurrenceType() ) < end );
01091
01092 return false;
01093 }
01094
01095 bool RecurrenceRule::recursAt( const QDateTime &dt ) const
01096 {
01097 if ( doesFloat() ) {
01098 return recursOn( dt.date() );
01099 }
01100 if ( dt < mDateStart ) {
01101 return false;
01102 }
01103
01104 if ( mDuration >= 0 && dt > endDt() ) {
01105 return false;
01106 }
01107
01108 if ( mTimedRepetition ) {
01109
01110 return !( mDateStart.secsTo( dt ) % mTimedRepetition );
01111 }
01112
01113
01114
01115 if ( !dateMatchesRules( dt ) ) {
01116 return false;
01117 }
01118
01119
01120 Constraint interval( getNextValidDateInterval( dt, recurrenceType() ) );
01121
01122 if ( interval.matches( dt, recurrenceType() ) ) {
01123 return true;
01124 }
01125 return false;
01126 }
01127
01128 TimeList RecurrenceRule::recurTimesOn( const QDate &date ) const
01129 {
01130 TimeList lst;
01131 if ( doesFloat() ) {
01132 return lst;
01133 }
01134 QDateTime start( date, QTime( 0, 0, 0 ) );
01135 QDateTime end = start.addDays( 1 ).addSecs( -1 );
01136 DateTimeList dts = timesInInterval( start, end );
01137 for ( int i = 0, iend = dts.count(); i < iend; ++i ) {
01138 lst += dts[i].time();
01139 }
01140 return lst;
01141 }
01142
01144 int RecurrenceRule::durationTo( const QDateTime &dt ) const
01145 {
01146
01147
01148
01149 if ( dt < startDt() ) return 0;
01150
01151
01152 if ( mDuration > 0 && dt >= endDt() ) return mDuration;
01153
01154 QDateTime next( startDt() );
01155 int found = 0;
01156 while ( next.isValid() && next <= dt ) {
01157 ++found;
01158 next = getNextDate( next );
01159 }
01160 return found;
01161 }
01162
01163
01164 QDateTime RecurrenceRule::getPreviousDate( const QDateTime& afterDate ) const
01165 {
01166
01167
01168 if ( afterDate < startDt() )
01169 return QDateTime();
01170
01171
01172 QDateTime prev;
01173 if ( mDuration > 0 ) {
01174 if ( !mCached ) buildCache();
01175 DateTimeList::ConstIterator it = mCachedDates.begin();
01176 while ( it != mCachedDates.end() && (*it) < afterDate ) {
01177 prev = *it;
01178 ++it;
01179 }
01180 if ( prev.isValid() && prev < afterDate ) return prev;
01181 else return QDateTime();
01182 }
01183
01184
01185 prev = afterDate;
01186 if ( mDuration >= 0 && endDt().isValid() && afterDate > endDt() )
01187 prev = endDt().addSecs( 1 );
01188
01189 Constraint interval( getPreviousValidDateInterval( prev, recurrenceType() ) );
01190
01191
01192 DateTimeList dts = datesForInterval( interval, recurrenceType() );
01193 DateTimeList::Iterator dtit = dts.end();
01194 if ( dtit != dts.begin() ) {
01195 do {
01196 --dtit;
01197 } while ( dtit != dts.begin() && (*dtit) >= prev );
01198 if ( (*dtit) < prev ) {
01199 if ( (*dtit) >= startDt() ) return (*dtit);
01200 else return QDateTime();
01201 }
01202 }
01203
01204
01205 while ( interval.intervalDateTime( recurrenceType() ) > startDt() ) {
01206 interval.increase( recurrenceType(), -frequency() );
01207
01208
01209
01210 DateTimeList dts = datesForInterval( interval, recurrenceType() );
01211
01212 if ( dts.count() > 0 ) {
01213 prev = dts.last();
01214 if ( prev.isValid() && prev >= startDt() ) return prev;
01215 else return QDateTime();
01216 }
01217 }
01218 return QDateTime();
01219 }
01220
01221
01222 QDateTime RecurrenceRule::getNextDate( const QDateTime &preDate ) const
01223 {
01224
01225
01226 if ( mDuration >= 0 && endDt().isValid() && preDate >= endDt() )
01227 return QDateTime();
01228
01229
01230 QDateTime adjustedPreDate;
01231 if ( preDate < startDt() )
01232 adjustedPreDate = startDt().addSecs( -1 );
01233 else
01234 adjustedPreDate = preDate;
01235
01236 if ( mDuration > 0 ) {
01237 if ( !mCached ) buildCache();
01238 DateTimeList::ConstIterator it = mCachedDates.begin();
01239 while ( it != mCachedDates.end() && (*it) <= adjustedPreDate ) ++it;
01240 if ( it != mCachedDates.end() ) {
01241
01242 return (*it);
01243 }
01244 }
01245
01246
01247 Constraint interval( getNextValidDateInterval( adjustedPreDate, recurrenceType() ) );
01248 DateTimeList dts = datesForInterval( interval, recurrenceType() );
01249 DateTimeList::Iterator dtit = dts.begin();
01250 while ( dtit != dts.end() && (*dtit) <= adjustedPreDate ) ++dtit;
01251 if ( dtit != dts.end() ) {
01252 if ( mDuration >= 0 && (*dtit) > endDt() ) return QDateTime();
01253 else return (*dtit);
01254 }
01255
01256
01257
01258
01259 int loopnr = 0;
01260 while ( loopnr < 10000 ) {
01261 interval.increase( recurrenceType(), frequency() );
01262 DateTimeList dts = datesForInterval( interval, recurrenceType() );
01263 if ( dts.count() > 0 ) {
01264 QDateTime ret( dts.first() );
01265 if ( mDuration >= 0 && ret > endDt() ) return QDateTime();
01266 else return ret;
01267 }
01268 ++loopnr;
01269 }
01270 return QDateTime();
01271 }
01272
01273 DateTimeList RecurrenceRule::timesInInterval( const QDateTime &dtStart,
01274 const QDateTime &dtEnd ) const
01275 {
01276 QDateTime start = dtStart;
01277 QDateTime end = dtEnd;
01278 DateTimeList result;
01279 if ( end < mDateStart ) {
01280 return result;
01281 }
01282 QDateTime enddt = end;
01283 if ( mDuration >= 0 ) {
01284 QDateTime endRecur = endDt();
01285 if ( endRecur.isValid() ) {
01286 if ( start > endRecur ) {
01287 return result;
01288 }
01289 if ( end > endRecur ) {
01290 enddt = endRecur;
01291 }
01292 }
01293 }
01294
01295 if ( mTimedRepetition ) {
01296
01297 int n = static_cast<int>( ( mDateStart.secsTo( start ) - 1 ) % mTimedRepetition );
01298 QDateTime dt = start.addSecs( mTimedRepetition - n );
01299 if ( dt < enddt ) {
01300 n = static_cast<int>( ( dt.secsTo( enddt ) - 1 ) / mTimedRepetition ) + 1;
01301
01302 n = QMIN( n, LOOP_LIMIT );
01303 for ( int i = 0; i < n; dt = dt.addSecs( mTimedRepetition ), ++i ) {
01304 result += dt;
01305 }
01306 }
01307 return result;
01308 }
01309
01310 QDateTime st = start;
01311 bool done = false;
01312 if ( mDuration > 0 ) {
01313 if ( !mCached ) {
01314 buildCache();
01315 }
01316 if ( mCachedDateEnd.isValid() && start > mCachedDateEnd ) {
01317 return result;
01318 }
01319 int i = findGE( mCachedDates, start, 0 );
01320 if ( i >= 0 ) {
01321 int iend = findGT( mCachedDates, enddt, i );
01322 if ( iend < 0 ) {
01323 iend = mCachedDates.count();
01324 } else {
01325 done = true;
01326 }
01327 while ( i < iend ) {
01328 result += mCachedDates[i++];
01329 }
01330 }
01331 if ( mCachedDateEnd.isValid() ) {
01332 done = true;
01333 } else if ( !result.isEmpty() ) {
01334 result += QDateTime();
01335 done = true;
01336 }
01337 if ( done ) {
01338 return result;
01339 }
01340
01341 st = mCachedLastDate.addSecs( 1 );
01342 }
01343
01344 Constraint interval( getNextValidDateInterval( st, recurrenceType() ) );
01345 int loop = 0;
01346 do {
01347 DateTimeList dts = datesForInterval( interval, recurrenceType() );
01348 int i = 0;
01349 int iend = dts.count();
01350 if ( loop == 0 ) {
01351 i = findGE( dts, st, 0 );
01352 if ( i < 0 ) {
01353 i = iend;
01354 }
01355 }
01356 int j = findGT( dts, enddt, i );
01357 if ( j >= 0 ) {
01358 iend = j;
01359 loop = LOOP_LIMIT;
01360 }
01361 while ( i < iend ) {
01362 result += dts[i++];
01363 }
01364
01365 interval.increase( recurrenceType(), frequency() );
01366 } while ( ++loop < LOOP_LIMIT &&
01367 interval.intervalDateTime( recurrenceType() ) < end );
01368 return result;
01369 }
01370
01371 RecurrenceRule::Constraint RecurrenceRule::getPreviousValidDateInterval( const QDateTime &preDate, PeriodType type ) const
01372 {
01373
01374 long periods = 0;
01375 QDateTime nextValid = startDt();
01376 QDateTime start = startDt();
01377 int modifier = 1;
01378 QDateTime toDate( preDate );
01379
01380
01381
01382
01383
01384
01385
01386 switch ( type ) {
01387
01388
01389 case rHourly: modifier *= 60;
01390 case rMinutely: modifier *= 60;
01391 case rSecondly:
01392 periods = ownSecsTo( start, toDate ) / modifier;
01393
01394 periods = ( periods / frequency() ) * frequency();
01395 nextValid = start.addSecs( modifier * periods );
01396 break;
01397
01398 case rWeekly:
01399 toDate = toDate.addDays( -(7 + toDate.date().dayOfWeek() - mWeekStart) % 7 );
01400 start = start.addDays( -(7 + start.date().dayOfWeek() - mWeekStart) % 7 );
01401 modifier *= 7;
01402 case rDaily:
01403 periods = start.daysTo( toDate ) / modifier;
01404
01405 periods = ( periods / frequency() ) * frequency();
01406 nextValid = start.addDays( modifier * periods );
01407 break;
01408
01409 case rMonthly: {
01410 periods = 12*( toDate.date().year() - start.date().year() ) +
01411 ( toDate.date().month() - start.date().month() );
01412
01413 periods = ( periods / frequency() ) * frequency();
01414
01415
01416 start.setDate( QDate( start.date().year(), start.date().month(), 1 ) );
01417 nextValid.setDate( start.date().addMonths( periods ) );
01418 break; }
01419 case rYearly:
01420 periods = ( toDate.date().year() - start.date().year() );
01421
01422 periods = ( periods / frequency() ) * frequency();
01423 nextValid.setDate( start.date().addYears( periods ) );
01424 break;
01425 default:
01426 break;
01427 }
01428
01429
01430 return Constraint( nextValid, type, mWeekStart );
01431 }
01432
01433 RecurrenceRule::Constraint RecurrenceRule::getNextValidDateInterval( const QDateTime &preDate, PeriodType type ) const
01434 {
01435
01436
01437
01438 long periods = 0;
01439 QDateTime start = startDt();
01440 QDateTime nextValid( start );
01441 int modifier = 1;
01442 QDateTime toDate( preDate );
01443
01444
01445
01446
01447
01448
01449
01450 switch ( type ) {
01451
01452
01453 case rHourly: modifier *= 60;
01454 case rMinutely: modifier *= 60;
01455 case rSecondly:
01456 periods = ownSecsTo( start, toDate ) / modifier;
01457 periods = QMAX( 0, periods);
01458 if ( periods > 0 )
01459 periods += ( frequency() - 1 - ( (periods - 1) % frequency() ) );
01460 nextValid = start.addSecs( modifier * periods );
01461 break;
01462
01463 case rWeekly:
01464
01465 toDate = toDate.addDays( -(7 + toDate.date().dayOfWeek() - mWeekStart) % 7 );
01466 start = start.addDays( -(7 + start.date().dayOfWeek() - mWeekStart) % 7 );
01467 modifier *= 7;
01468 case rDaily:
01469 periods = start.daysTo( toDate ) / modifier;
01470 periods = QMAX( 0, periods);
01471 if ( periods > 0 )
01472 periods += (frequency() - 1 - ( (periods - 1) % frequency() ) );
01473 nextValid = start.addDays( modifier * periods );
01474 break;
01475
01476 case rMonthly: {
01477 periods = 12*( toDate.date().year() - start.date().year() ) +
01478 ( toDate.date().month() - start.date().month() );
01479 periods = QMAX( 0, periods);
01480 if ( periods > 0 )
01481 periods += (frequency() - 1 - ( (periods - 1) % frequency() ) );
01482
01483
01484 start.setDate( QDate( start.date().year(), start.date().month(), 1 ) );
01485 nextValid.setDate( start.date().addMonths( periods ) );
01486 break; }
01487 case rYearly:
01488 periods = ( toDate.date().year() - start.date().year() );
01489 periods = QMAX( 0, periods);
01490 if ( periods > 0 )
01491 periods += ( frequency() - 1 - ( (periods - 1) % frequency() ) );
01492 nextValid.setDate( start.date().addYears( periods ) );
01493 break;
01494 default:
01495 break;
01496 }
01497
01498
01499 return Constraint( nextValid, type, mWeekStart );
01500 }
01501
01502 bool RecurrenceRule::mergeIntervalConstraint( Constraint *merged,
01503 const Constraint &conit, const Constraint &interval ) const
01504 {
01505 Constraint result( interval );
01506
01507 #define mergeConstraint( name, cmparison ) \
01508 if ( conit.name cmparison ) { \
01509 if ( !(result.name cmparison) || result.name == conit.name ) { \
01510 result.name = conit.name; \
01511 } else return false;\
01512 }
01513
01514 mergeConstraint( year, > 0 );
01515 mergeConstraint( month, > 0 );
01516 mergeConstraint( day, != 0 );
01517 mergeConstraint( hour, >= 0 );
01518 mergeConstraint( minute, >= 0 );
01519 mergeConstraint( second, >= 0 );
01520
01521 mergeConstraint( weekday, != 0 );
01522 mergeConstraint( weekdaynr, != 0 );
01523 mergeConstraint( weeknumber, != 0 );
01524 mergeConstraint( yearday, != 0 );
01525
01526 #undef mergeConstraint
01527 if ( merged ) *merged = result;
01528 return true;
01529 }
01530
01531
01532 DateTimeList RecurrenceRule::datesForInterval( const Constraint &interval, PeriodType type ) const
01533 {
01534
01535
01536
01537
01538
01539
01540
01541
01542 DateTimeList lst;
01543 Constraint::List::ConstIterator conit = mConstraints.begin();
01544 for ( ; conit != mConstraints.end(); ++conit ) {
01545 Constraint merged;
01546 bool mergeok = mergeIntervalConstraint( &merged, *conit, interval );
01547
01548 if ( merged.year <= 0 || merged.hour < 0 || merged.minute < 0 || merged.second < 0 )
01549 mergeok = false;
01550 if ( mergeok ) {
01551
01552
01553
01554
01555 DateTimeList lstnew = merged.dateTimes( type );
01556 lst += lstnew;
01557 }
01558 }
01559
01560 qSortUnique( lst );
01561
01562
01563
01564
01565
01566
01567
01568
01569
01570
01571
01572 if ( !mBySetPos.isEmpty() ) {
01573 DateTimeList tmplst = lst;
01574 lst.clear();
01575 QValueList<int>::ConstIterator it;
01576 for ( it = mBySetPos.begin(); it != mBySetPos.end(); ++it ) {
01577 int pos = *it;
01578 if ( pos > 0 ) --pos;
01579 if ( pos < 0 ) pos += tmplst.count();
01580 if ( pos >= 0 && uint(pos) < tmplst.count() ) {
01581 lst.append( tmplst[pos] );
01582 }
01583 }
01584 qSortUnique( lst );
01585 }
01586
01587 return lst;
01588 }
01589
01590
01591 void RecurrenceRule::dump() const
01592 {
01593 #ifndef NDEBUG
01594 kdDebug(5800) << "RecurrenceRule::dump():" << endl;
01595 if ( !mRRule.isEmpty() )
01596 kdDebug(5800) << " RRULE=" << mRRule << endl;
01597 kdDebug(5800) << " Read-Only: " << isReadOnly() <<
01598 ", dirty: " << mDirty << endl;
01599
01600 kdDebug(5800) << " Period type: " << recurrenceType() << ", frequency: " << frequency() << endl;
01601 kdDebug(5800) << " #occurrences: " << duration() << endl;
01602 kdDebug(5800) << " start date: " << startDt() <<", end date: " << endDt() << endl;
01603
01604
01605 #define dumpByIntList(list,label) \
01606 if ( !list.isEmpty() ) {\
01607 QStringList lst;\
01608 for ( QValueList<int>::ConstIterator it = list.begin();\
01609 it != list.end(); ++it ) {\
01610 lst.append( QString::number( *it ) );\
01611 }\
01612 kdDebug(5800) << " " << label << lst.join(", ") << endl;\
01613 }
01614 dumpByIntList( mBySeconds, "BySeconds: " );
01615 dumpByIntList( mByMinutes, "ByMinutes: " );
01616 dumpByIntList( mByHours, "ByHours: " );
01617 if ( !mByDays.isEmpty() ) {
01618 QStringList lst;
01619 for ( QValueList<WDayPos>::ConstIterator it = mByDays.begin();
01620 it != mByDays.end(); ++it ) {
01621 lst.append( ( ((*it).pos()!=0) ? QString::number( (*it).pos() ) : "" ) +
01622 DateHelper::dayName( (*it).day() ) );
01623 }
01624 kdDebug(5800) << " ByDays: " << lst.join(", ") << endl;
01625 }
01626 dumpByIntList( mByMonthDays, "ByMonthDays:" );
01627 dumpByIntList( mByYearDays, "ByYearDays: " );
01628 dumpByIntList( mByWeekNumbers,"ByWeekNr: " );
01629 dumpByIntList( mByMonths, "ByMonths: " );
01630 dumpByIntList( mBySetPos, "BySetPos: " );
01631 #undef dumpByIntList
01632
01633 kdDebug(5800) << " Week start: " << DateHelper::dayName( mWeekStart ) << endl;
01634
01635 kdDebug(5800) << " Constraints:" << endl;
01636
01637 for ( Constraint::List::ConstIterator it = mConstraints.begin();
01638 it!=mConstraints.end(); ++it ) {
01639 (*it).dump();
01640 }
01641 #endif
01642 }
01643
01644 void RecurrenceRule::Constraint::dump() const
01645 {
01646 kdDebug(5800) << " ~> Y="<<year<<", M="<<month<<", D="<<day<<", H="<<hour<<", m="<<minute<<", S="<<second<<", wd="<<weekday<<",#wd="<<weekdaynr<<", #w="<<weeknumber<<", yd="<<yearday<<endl;
01647 }