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
00968 if ( !qd.isValid() ) {
00969
00970 kdWarning() << k_funcinfo << " Called with invalid date: " << qd << endl;
00971 kdWarning() << kdBacktrace();
00972 return false;
00973 }
00974
00975 if ( doesFloat() ) {
00976
00977 if ( qd < mDateStart.date() ) {
00978 return false;
00979 }
00980
00981 QDate endDate;
00982 if ( mDuration >= 0 ) {
00983 endDate = endDt().date();
00984 if ( qd > endDate ) {
00985 return false;
00986 }
00987 }
00988
00989
00990
00991 bool match = false;
00992 for ( i = 0, iend = mConstraints.count(); i < iend && !match; ++i ) {
00993 match = mConstraints[i].matches( qd, recurrenceType() );
00994 }
00995 if ( !match ) {
00996 return false;
00997 }
00998
00999 QDateTime start( qd, QTime( 0, 0, 0 ) );
01000 Constraint interval( getNextValidDateInterval( start, recurrenceType() ) );
01001
01002
01003 if ( !interval.matches( qd, recurrenceType() ) ) {
01004 return false;
01005 }
01006
01007
01008
01009 QDateTime end = start.addDays(1);
01010 do {
01011 DateTimeList dts = datesForInterval( interval, recurrenceType() );
01012 for ( i = 0, iend = dts.count(); i < iend; ++i ) {
01013 if ( dts[i].date() >= qd ) {
01014 return dts[i].date() == qd;
01015 }
01016 }
01017 interval.increase( recurrenceType(), frequency() );
01018 } while ( interval.intervalDateTime( recurrenceType() ) < end );
01019 return false;
01020 }
01021
01022
01023 QDateTime start( qd, QTime( 0, 0, 0 ) );
01024 QDateTime end = start.addDays( 1 );
01025 if ( end < mDateStart ) {
01026 return false;
01027 }
01028 if ( start < mDateStart ) {
01029 start = mDateStart;
01030 }
01031
01032
01033 if ( mDuration >= 0 ) {
01034 QDateTime endRecur = endDt();
01035 if ( endRecur.isValid() ) {
01036 if ( start > endRecur ) {
01037 return false;
01038 }
01039 if ( end > endRecur ) {
01040 end = endRecur;
01041 }
01042 }
01043 }
01044
01045 if ( mTimedRepetition ) {
01046
01047 int n = static_cast<int>( ( mDateStart.secsTo( start ) - 1 ) % mTimedRepetition );
01048 return start.addSecs( mTimedRepetition - n ) < end;
01049 }
01050
01051
01052 QDate startDay = start.date();
01053 QDate endDay = end.addSecs( -1 ).date();
01054 int dayCount = startDay.daysTo( endDay ) + 1;
01055
01056
01057
01058 bool match = false;
01059 for ( i = 0, iend = mConstraints.count(); i < iend && !match; ++i ) {
01060 match = mConstraints[i].matches( startDay, recurrenceType() );
01061 for ( int day = 1; day < dayCount && !match; ++day ) {
01062 match = mConstraints[i].matches( startDay.addDays( day ), recurrenceType() );
01063 }
01064 }
01065 if ( !match ) {
01066 return false;
01067 }
01068
01069 Constraint interval( getNextValidDateInterval( start, recurrenceType() ) );
01070
01071
01072 match = false;
01073 Constraint intervalm = interval;
01074 do {
01075 match = intervalm.matches( startDay, recurrenceType() );
01076 for ( int day = 1; day < dayCount && !match; ++day ) {
01077 match = intervalm.matches( startDay.addDays( day ), recurrenceType() );
01078 }
01079 if ( match ) {
01080 break;
01081 }
01082 intervalm.increase( recurrenceType(), frequency() );
01083 } while ( intervalm.intervalDateTime( recurrenceType() ) < end );
01084 if ( !match ) {
01085 return false;
01086 }
01087
01088
01089
01090
01091 do {
01092 DateTimeList dts = datesForInterval( interval, recurrenceType() );
01093 int i = findGE( dts, start, 0 );
01094 if ( i >= 0 ) {
01095 return dts[i] <= end;
01096 }
01097 interval.increase( recurrenceType(), frequency() );
01098 } while ( interval.intervalDateTime( recurrenceType() ) < end );
01099
01100 return false;
01101 }
01102
01103 bool RecurrenceRule::recursAt( const QDateTime &dt ) const
01104 {
01105 if ( doesFloat() ) {
01106 return recursOn( dt.date() );
01107 }
01108 if ( dt < mDateStart ) {
01109 return false;
01110 }
01111
01112 if ( mDuration >= 0 && dt > endDt() ) {
01113 return false;
01114 }
01115
01116 if ( mTimedRepetition ) {
01117
01118 return !( mDateStart.secsTo( dt ) % mTimedRepetition );
01119 }
01120
01121
01122
01123 if ( !dateMatchesRules( dt ) ) {
01124 return false;
01125 }
01126
01127
01128 Constraint interval( getNextValidDateInterval( dt, recurrenceType() ) );
01129
01130 if ( interval.matches( dt, recurrenceType() ) ) {
01131 return true;
01132 }
01133 return false;
01134 }
01135
01136 TimeList RecurrenceRule::recurTimesOn( const QDate &date ) const
01137 {
01138 TimeList lst;
01139 if ( doesFloat() ) {
01140 return lst;
01141 }
01142 QDateTime start( date, QTime( 0, 0, 0 ) );
01143 QDateTime end = start.addDays( 1 ).addSecs( -1 );
01144 DateTimeList dts = timesInInterval( start, end );
01145 for ( int i = 0, iend = dts.count(); i < iend; ++i ) {
01146 lst += dts[i].time();
01147 }
01148 return lst;
01149 }
01150
01152 int RecurrenceRule::durationTo( const QDateTime &dt ) const
01153 {
01154
01155
01156
01157 if ( dt < startDt() ) return 0;
01158
01159
01160 if ( mDuration > 0 && dt >= endDt() ) return mDuration;
01161
01162 QDateTime next( startDt() );
01163 int found = 0;
01164 while ( next.isValid() && next <= dt ) {
01165 ++found;
01166 next = getNextDate( next );
01167 }
01168 return found;
01169 }
01170
01171
01172 QDateTime RecurrenceRule::getPreviousDate( const QDateTime& afterDate ) const
01173 {
01174
01175
01176 if ( afterDate < startDt() )
01177 return QDateTime();
01178
01179
01180 QDateTime prev;
01181 if ( mDuration > 0 ) {
01182 if ( !mCached ) buildCache();
01183 DateTimeList::ConstIterator it = mCachedDates.begin();
01184 while ( it != mCachedDates.end() && (*it) < afterDate ) {
01185 prev = *it;
01186 ++it;
01187 }
01188 if ( prev.isValid() && prev < afterDate ) return prev;
01189 else return QDateTime();
01190 }
01191
01192
01193 prev = afterDate;
01194 if ( mDuration >= 0 && endDt().isValid() && afterDate > endDt() )
01195 prev = endDt().addSecs( 1 );
01196
01197 Constraint interval( getPreviousValidDateInterval( prev, recurrenceType() ) );
01198
01199
01200 DateTimeList dts = datesForInterval( interval, recurrenceType() );
01201 DateTimeList::Iterator dtit = dts.end();
01202 if ( dtit != dts.begin() ) {
01203 do {
01204 --dtit;
01205 } while ( dtit != dts.begin() && (*dtit) >= prev );
01206 if ( (*dtit) < prev ) {
01207 if ( (*dtit) >= startDt() ) return (*dtit);
01208 else return QDateTime();
01209 }
01210 }
01211
01212
01213 while ( interval.intervalDateTime( recurrenceType() ) > startDt() ) {
01214 interval.increase( recurrenceType(), -frequency() );
01215
01216
01217
01218 DateTimeList dts = datesForInterval( interval, recurrenceType() );
01219
01220 if ( dts.count() > 0 ) {
01221 prev = dts.last();
01222 if ( prev.isValid() && prev >= startDt() ) return prev;
01223 else return QDateTime();
01224 }
01225 }
01226 return QDateTime();
01227 }
01228
01229
01230 QDateTime RecurrenceRule::getNextDate( const QDateTime &preDate ) const
01231 {
01232
01233
01234 if ( mDuration >= 0 && endDt().isValid() && preDate >= endDt() )
01235 return QDateTime();
01236
01237
01238 QDateTime adjustedPreDate;
01239 if ( preDate < startDt() )
01240 adjustedPreDate = startDt().addSecs( -1 );
01241 else
01242 adjustedPreDate = preDate;
01243
01244 if ( mDuration > 0 ) {
01245 if ( !mCached ) buildCache();
01246 DateTimeList::ConstIterator it = mCachedDates.begin();
01247 while ( it != mCachedDates.end() && (*it) <= adjustedPreDate ) ++it;
01248 if ( it != mCachedDates.end() ) {
01249
01250 return (*it);
01251 }
01252 }
01253
01254
01255 Constraint interval( getNextValidDateInterval( adjustedPreDate, recurrenceType() ) );
01256 DateTimeList dts = datesForInterval( interval, recurrenceType() );
01257 DateTimeList::Iterator dtit = dts.begin();
01258 while ( dtit != dts.end() && (*dtit) <= adjustedPreDate ) ++dtit;
01259 if ( dtit != dts.end() ) {
01260 if ( mDuration >= 0 && (*dtit) > endDt() ) return QDateTime();
01261 else return (*dtit);
01262 }
01263
01264
01265
01266
01267 int loopnr = 0;
01268 while ( loopnr < 10000 ) {
01269 interval.increase( recurrenceType(), frequency() );
01270 DateTimeList dts = datesForInterval( interval, recurrenceType() );
01271 if ( dts.count() > 0 ) {
01272 QDateTime ret( dts.first() );
01273 if ( mDuration >= 0 && ret > endDt() ) return QDateTime();
01274 else return ret;
01275 }
01276 ++loopnr;
01277 }
01278 return QDateTime();
01279 }
01280
01281 DateTimeList RecurrenceRule::timesInInterval( const QDateTime &dtStart,
01282 const QDateTime &dtEnd ) const
01283 {
01284 QDateTime start = dtStart;
01285 QDateTime end = dtEnd;
01286 DateTimeList result;
01287 if ( end < mDateStart ) {
01288 return result;
01289 }
01290 QDateTime enddt = end;
01291 if ( mDuration >= 0 ) {
01292 QDateTime endRecur = endDt();
01293 if ( endRecur.isValid() ) {
01294 if ( start > endRecur ) {
01295 return result;
01296 }
01297 if ( end > endRecur ) {
01298 enddt = endRecur;
01299 }
01300 }
01301 }
01302
01303 if ( mTimedRepetition ) {
01304
01305 int n = static_cast<int>( ( mDateStart.secsTo( start ) - 1 ) % mTimedRepetition );
01306 QDateTime dt = start.addSecs( mTimedRepetition - n );
01307 if ( dt < enddt ) {
01308 n = static_cast<int>( ( dt.secsTo( enddt ) - 1 ) / mTimedRepetition ) + 1;
01309
01310 n = QMIN( n, LOOP_LIMIT );
01311 for ( int i = 0; i < n; dt = dt.addSecs( mTimedRepetition ), ++i ) {
01312 result += dt;
01313 }
01314 }
01315 return result;
01316 }
01317
01318 QDateTime st = start;
01319 bool done = false;
01320 if ( mDuration > 0 ) {
01321 if ( !mCached ) {
01322 buildCache();
01323 }
01324 if ( mCachedDateEnd.isValid() && start > mCachedDateEnd ) {
01325 return result;
01326 }
01327 int i = findGE( mCachedDates, start, 0 );
01328 if ( i >= 0 ) {
01329 int iend = findGT( mCachedDates, enddt, i );
01330 if ( iend < 0 ) {
01331 iend = mCachedDates.count();
01332 } else {
01333 done = true;
01334 }
01335 while ( i < iend ) {
01336 result += mCachedDates[i++];
01337 }
01338 }
01339 if ( mCachedDateEnd.isValid() ) {
01340 done = true;
01341 } else if ( !result.isEmpty() ) {
01342 result += QDateTime();
01343 done = true;
01344 }
01345 if ( done ) {
01346 return result;
01347 }
01348
01349 st = mCachedLastDate.addSecs( 1 );
01350 }
01351
01352 Constraint interval( getNextValidDateInterval( st, recurrenceType() ) );
01353 int loop = 0;
01354 do {
01355 DateTimeList dts = datesForInterval( interval, recurrenceType() );
01356 int i = 0;
01357 int iend = dts.count();
01358 if ( loop == 0 ) {
01359 i = findGE( dts, st, 0 );
01360 if ( i < 0 ) {
01361 i = iend;
01362 }
01363 }
01364 int j = findGT( dts, enddt, i );
01365 if ( j >= 0 ) {
01366 iend = j;
01367 loop = LOOP_LIMIT;
01368 }
01369 while ( i < iend ) {
01370 result += dts[i++];
01371 }
01372
01373 interval.increase( recurrenceType(), frequency() );
01374 } while ( ++loop < LOOP_LIMIT &&
01375 interval.intervalDateTime( recurrenceType() ) < end );
01376 return result;
01377 }
01378
01379 RecurrenceRule::Constraint RecurrenceRule::getPreviousValidDateInterval( const QDateTime &preDate, PeriodType type ) const
01380 {
01381
01382 long periods = 0;
01383 QDateTime nextValid = startDt();
01384 QDateTime start = startDt();
01385 int modifier = 1;
01386 QDateTime toDate( preDate );
01387
01388
01389
01390
01391
01392
01393
01394 switch ( type ) {
01395
01396
01397 case rHourly: modifier *= 60;
01398 case rMinutely: modifier *= 60;
01399 case rSecondly:
01400 periods = ownSecsTo( start, toDate ) / modifier;
01401
01402 periods = ( periods / frequency() ) * frequency();
01403 nextValid = start.addSecs( modifier * periods );
01404 break;
01405
01406 case rWeekly:
01407 toDate = toDate.addDays( -(7 + toDate.date().dayOfWeek() - mWeekStart) % 7 );
01408 start = start.addDays( -(7 + start.date().dayOfWeek() - mWeekStart) % 7 );
01409 modifier *= 7;
01410 case rDaily:
01411 periods = start.daysTo( toDate ) / modifier;
01412
01413 periods = ( periods / frequency() ) * frequency();
01414 nextValid = start.addDays( modifier * periods );
01415 break;
01416
01417 case rMonthly: {
01418 periods = 12*( toDate.date().year() - start.date().year() ) +
01419 ( toDate.date().month() - start.date().month() );
01420
01421 periods = ( periods / frequency() ) * frequency();
01422
01423
01424 start.setDate( QDate( start.date().year(), start.date().month(), 1 ) );
01425 nextValid.setDate( start.date().addMonths( periods ) );
01426 break; }
01427 case rYearly:
01428 periods = ( toDate.date().year() - start.date().year() );
01429
01430 periods = ( periods / frequency() ) * frequency();
01431 nextValid.setDate( start.date().addYears( periods ) );
01432 break;
01433 default:
01434 break;
01435 }
01436
01437
01438 return Constraint( nextValid, type, mWeekStart );
01439 }
01440
01441 RecurrenceRule::Constraint RecurrenceRule::getNextValidDateInterval( const QDateTime &preDate, PeriodType type ) const
01442 {
01443
01444
01445
01446 long periods = 0;
01447 QDateTime start = startDt();
01448 QDateTime nextValid( start );
01449 int modifier = 1;
01450 QDateTime toDate( preDate );
01451
01452
01453
01454
01455
01456
01457
01458 switch ( type ) {
01459
01460
01461 case rHourly: modifier *= 60;
01462 case rMinutely: modifier *= 60;
01463 case rSecondly:
01464 periods = ownSecsTo( start, toDate ) / modifier;
01465 periods = QMAX( 0, periods);
01466 if ( periods > 0 )
01467 periods += ( frequency() - 1 - ( (periods - 1) % frequency() ) );
01468 nextValid = start.addSecs( modifier * periods );
01469 break;
01470
01471 case rWeekly:
01472
01473 toDate = toDate.addDays( -(7 + toDate.date().dayOfWeek() - mWeekStart) % 7 );
01474 start = start.addDays( -(7 + start.date().dayOfWeek() - mWeekStart) % 7 );
01475 modifier *= 7;
01476 case rDaily:
01477 periods = start.daysTo( toDate ) / modifier;
01478 periods = QMAX( 0, periods);
01479 if ( periods > 0 )
01480 periods += (frequency() - 1 - ( (periods - 1) % frequency() ) );
01481 nextValid = start.addDays( modifier * periods );
01482 break;
01483
01484 case rMonthly: {
01485 periods = 12*( toDate.date().year() - start.date().year() ) +
01486 ( toDate.date().month() - start.date().month() );
01487 periods = QMAX( 0, periods);
01488 if ( periods > 0 )
01489 periods += (frequency() - 1 - ( (periods - 1) % frequency() ) );
01490
01491
01492 start.setDate( QDate( start.date().year(), start.date().month(), 1 ) );
01493 nextValid.setDate( start.date().addMonths( periods ) );
01494 break; }
01495 case rYearly:
01496 periods = ( toDate.date().year() - start.date().year() );
01497 periods = QMAX( 0, periods);
01498 if ( periods > 0 )
01499 periods += ( frequency() - 1 - ( (periods - 1) % frequency() ) );
01500 nextValid.setDate( start.date().addYears( periods ) );
01501 break;
01502 default:
01503 break;
01504 }
01505
01506
01507 return Constraint( nextValid, type, mWeekStart );
01508 }
01509
01510 bool RecurrenceRule::mergeIntervalConstraint( Constraint *merged,
01511 const Constraint &conit, const Constraint &interval ) const
01512 {
01513 Constraint result( interval );
01514
01515 #define mergeConstraint( name, cmparison ) \
01516 if ( conit.name cmparison ) { \
01517 if ( !(result.name cmparison) || result.name == conit.name ) { \
01518 result.name = conit.name; \
01519 } else return false;\
01520 }
01521
01522 mergeConstraint( year, > 0 );
01523 mergeConstraint( month, > 0 );
01524 mergeConstraint( day, != 0 );
01525 mergeConstraint( hour, >= 0 );
01526 mergeConstraint( minute, >= 0 );
01527 mergeConstraint( second, >= 0 );
01528
01529 mergeConstraint( weekday, != 0 );
01530 mergeConstraint( weekdaynr, != 0 );
01531 mergeConstraint( weeknumber, != 0 );
01532 mergeConstraint( yearday, != 0 );
01533
01534 #undef mergeConstraint
01535 if ( merged ) *merged = result;
01536 return true;
01537 }
01538
01539
01540 DateTimeList RecurrenceRule::datesForInterval( const Constraint &interval, PeriodType type ) const
01541 {
01542
01543
01544
01545
01546
01547
01548
01549
01550 DateTimeList lst;
01551 Constraint::List::ConstIterator conit = mConstraints.begin();
01552 for ( ; conit != mConstraints.end(); ++conit ) {
01553 Constraint merged;
01554 bool mergeok = mergeIntervalConstraint( &merged, *conit, interval );
01555
01556 if ( merged.year <= 0 || merged.hour < 0 || merged.minute < 0 || merged.second < 0 )
01557 mergeok = false;
01558 if ( mergeok ) {
01559
01560
01561
01562
01563 DateTimeList lstnew = merged.dateTimes( type );
01564 lst += lstnew;
01565 }
01566 }
01567
01568 qSortUnique( lst );
01569
01570
01571
01572
01573
01574
01575
01576
01577
01578
01579
01580 if ( !mBySetPos.isEmpty() ) {
01581 DateTimeList tmplst = lst;
01582 lst.clear();
01583 QValueList<int>::ConstIterator it;
01584 for ( it = mBySetPos.begin(); it != mBySetPos.end(); ++it ) {
01585 int pos = *it;
01586 if ( pos > 0 ) --pos;
01587 if ( pos < 0 ) pos += tmplst.count();
01588 if ( pos >= 0 && uint(pos) < tmplst.count() ) {
01589 lst.append( tmplst[pos] );
01590 }
01591 }
01592 qSortUnique( lst );
01593 }
01594
01595 return lst;
01596 }
01597
01598
01599 void RecurrenceRule::dump() const
01600 {
01601 #ifndef NDEBUG
01602 kdDebug(5800) << "RecurrenceRule::dump():" << endl;
01603 if ( !mRRule.isEmpty() )
01604 kdDebug(5800) << " RRULE=" << mRRule << endl;
01605 kdDebug(5800) << " Read-Only: " << isReadOnly() <<
01606 ", dirty: " << mDirty << endl;
01607
01608 kdDebug(5800) << " Period type: " << recurrenceType() << ", frequency: " << frequency() << endl;
01609 kdDebug(5800) << " #occurrences: " << duration() << endl;
01610 kdDebug(5800) << " start date: " << startDt() <<", end date: " << endDt() << endl;
01611
01612
01613 #define dumpByIntList(list,label) \
01614 if ( !list.isEmpty() ) {\
01615 QStringList lst;\
01616 for ( QValueList<int>::ConstIterator it = list.begin();\
01617 it != list.end(); ++it ) {\
01618 lst.append( QString::number( *it ) );\
01619 }\
01620 kdDebug(5800) << " " << label << lst.join(", ") << endl;\
01621 }
01622 dumpByIntList( mBySeconds, "BySeconds: " );
01623 dumpByIntList( mByMinutes, "ByMinutes: " );
01624 dumpByIntList( mByHours, "ByHours: " );
01625 if ( !mByDays.isEmpty() ) {
01626 QStringList lst;
01627 for ( QValueList<WDayPos>::ConstIterator it = mByDays.begin();
01628 it != mByDays.end(); ++it ) {
01629 lst.append( ( ((*it).pos()!=0) ? QString::number( (*it).pos() ) : "" ) +
01630 DateHelper::dayName( (*it).day() ) );
01631 }
01632 kdDebug(5800) << " ByDays: " << lst.join(", ") << endl;
01633 }
01634 dumpByIntList( mByMonthDays, "ByMonthDays:" );
01635 dumpByIntList( mByYearDays, "ByYearDays: " );
01636 dumpByIntList( mByWeekNumbers,"ByWeekNr: " );
01637 dumpByIntList( mByMonths, "ByMonths: " );
01638 dumpByIntList( mBySetPos, "BySetPos: " );
01639 #undef dumpByIntList
01640
01641 kdDebug(5800) << " Week start: " << DateHelper::dayName( mWeekStart ) << endl;
01642
01643 kdDebug(5800) << " Constraints:" << endl;
01644
01645 for ( Constraint::List::ConstIterator it = mConstraints.begin();
01646 it!=mConstraints.end(); ++it ) {
01647 (*it).dump();
01648 }
01649 #endif
01650 }
01651
01652 void RecurrenceRule::Constraint::dump() const
01653 {
01654 kdDebug(5800) << " ~> Y="<<year<<", M="<<month<<", D="<<day<<", H="<<hour<<", m="<<minute<<", S="<<second<<", wd="<<weekday<<",#wd="<<weekdaynr<<", #w="<<weeknumber<<", yd="<<yearday<<endl;
01655 }