00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "recurrence.h"
00026 #include "recurrencerule.h"
00027
00028 #include <kglobal.h>
00029 #include <klocale.h>
00030 #include <kdebug.h>
00031
00032 #include <QtCore/QList>
00033 #include <QtCore/QBitArray>
00034
00035 #include <limits.h>
00036
00037 using namespace KCal;
00038
00039
00040 class KCal::Recurrence::Private
00041 {
00042 public:
00043 Private()
00044 : mCachedType( rMax ),
00045 mAllDay( false ),
00046 mRecurReadOnly( false )
00047 {
00048 mExRules.setAutoDelete( true );
00049 mRRules.setAutoDelete( true );
00050 }
00051
00052 Private( const Private &p )
00053 : mRDateTimes( p.mRDateTimes ),
00054 mRDates( p.mRDates ),
00055 mExDateTimes( p.mExDateTimes ),
00056 mExDates( p.mExDates ),
00057 mStartDateTime( p.mStartDateTime ),
00058 mCachedType( p.mCachedType ),
00059 mAllDay( p.mAllDay ),
00060 mRecurReadOnly( p.mRecurReadOnly )
00061 {
00062 mExRules.setAutoDelete( true );
00063 mRRules.setAutoDelete( true );
00064 }
00065
00066 bool operator==( const Private &p ) const;
00067
00068 RecurrenceRule::List mExRules;
00069 RecurrenceRule::List mRRules;
00070 DateTimeList mRDateTimes;
00071 DateList mRDates;
00072 DateTimeList mExDateTimes;
00073 DateList mExDates;
00074 KDateTime mStartDateTime;
00075 QList<RecurrenceObserver*> mObservers;
00076
00077
00078 mutable ushort mCachedType;
00079
00080 bool mAllDay;
00081 bool mRecurReadOnly;
00082 };
00083
00084 bool Recurrence::Private::operator==( const Recurrence::Private &p ) const
00085 {
00086 if ( mStartDateTime != p.mStartDateTime ||
00087 mAllDay != p.mAllDay ||
00088 mRecurReadOnly != p.mRecurReadOnly ||
00089 mExDates != p.mExDates ||
00090 mExDateTimes != p.mExDateTimes ||
00091 mRDates != p.mRDates ||
00092 mRDateTimes != p.mRDateTimes ) {
00093 return false;
00094 }
00095
00096
00097
00098 int i;
00099 int end = mRRules.count();
00100 if ( end != p.mRRules.count() ) {
00101 return false;
00102 }
00103 for ( i = 0; i < end; ++i ) {
00104 if ( *mRRules[i] != *p.mRRules[i] ) {
00105 return false;
00106 }
00107 }
00108 end = mExRules.count();
00109 if ( end != p.mExRules.count() ) {
00110 return false;
00111 }
00112 for ( i = 0; i < end; ++i ) {
00113 if ( *mExRules[i] != *p.mExRules[i] ) {
00114 return false;
00115 }
00116 }
00117 return true;
00118 }
00119
00120
00121 Recurrence::Recurrence()
00122 : d( new KCal::Recurrence::Private() )
00123 {
00124 }
00125
00126 Recurrence::Recurrence( const Recurrence &r )
00127 : RecurrenceRule::RuleObserver(),
00128 d( new KCal::Recurrence::Private( *r.d ) )
00129 {
00130 int i, end;
00131 for ( i = 0, end = r.d->mRRules.count(); i < end; ++i ) {
00132 RecurrenceRule *rule = new RecurrenceRule( *r.d->mRRules[i] );
00133 d->mRRules.append( rule );
00134 rule->addObserver( this );
00135 }
00136 for ( i = 0, end = r.d->mExRules.count(); i < end; ++i ) {
00137 RecurrenceRule *rule = new RecurrenceRule( *r.d->mExRules[i] );
00138 d->mExRules.append( rule );
00139 rule->addObserver( this );
00140 }
00141 }
00142
00143 Recurrence::~Recurrence()
00144 {
00145 delete d;
00146 }
00147
00148 bool Recurrence::operator==( const Recurrence &r2 ) const
00149 {
00150 return *d == *r2.d;
00151 }
00152
00153 void Recurrence::addObserver( RecurrenceObserver *observer )
00154 {
00155 if ( !d->mObservers.contains( observer ) ) {
00156 d->mObservers.append( observer );
00157 }
00158 }
00159
00160 void Recurrence::removeObserver( RecurrenceObserver *observer )
00161 {
00162 if ( d->mObservers.contains( observer ) ) {
00163 d->mObservers.removeAll( observer );
00164 }
00165 }
00166
00167 KDateTime Recurrence::startDateTime() const
00168 {
00169 return d->mStartDateTime;
00170 }
00171
00172 bool Recurrence::allDay() const
00173 {
00174 return d->mAllDay;
00175 }
00176
00177 void Recurrence::setAllDay( bool allDay )
00178 {
00179 if ( d->mRecurReadOnly || allDay == d->mAllDay ) {
00180 return;
00181 }
00182
00183 d->mAllDay = allDay;
00184 for ( int i = 0, end = d->mRRules.count(); i < end; ++i ) {
00185 d->mRRules[i]->setAllDay( allDay );
00186 }
00187 for ( int i = 0, end = d->mExRules.count(); i < end; ++i ) {
00188 d->mExRules[i]->setAllDay( allDay );
00189 }
00190 updated();
00191 }
00192
00193 RecurrenceRule *Recurrence::defaultRRule( bool create ) const
00194 {
00195 if ( d->mRRules.isEmpty() ) {
00196 if ( !create || d->mRecurReadOnly ) {
00197 return 0;
00198 }
00199 RecurrenceRule *rrule = new RecurrenceRule();
00200 rrule->setStartDt( startDateTime() );
00201 const_cast<KCal::Recurrence*>(this)->addRRule( rrule );
00202 return rrule;
00203 } else {
00204 return d->mRRules[0];
00205 }
00206 }
00207
00208 RecurrenceRule *Recurrence::defaultRRuleConst() const
00209 {
00210 return d->mRRules.isEmpty() ? 0 : d->mRRules[0];
00211 }
00212
00213 void Recurrence::updated()
00214 {
00215
00216 d->mCachedType = rMax;
00217 for ( int i = 0, end = d->mObservers.count(); i < end; ++i ) {
00218 if ( d->mObservers[i] ) {
00219 d->mObservers[i]->recurrenceUpdated( this );
00220 }
00221 }
00222 }
00223
00224 bool Recurrence::recurs() const
00225 {
00226 return !d->mRRules.isEmpty() || !d->mRDates.isEmpty() || !d->mRDateTimes.isEmpty();
00227 }
00228
00229 ushort Recurrence::recurrenceType() const
00230 {
00231 if ( d->mCachedType == rMax ) {
00232 d->mCachedType = recurrenceType( defaultRRuleConst() );
00233 }
00234 return d->mCachedType;
00235 }
00236
00237 ushort Recurrence::recurrenceType( const RecurrenceRule *rrule )
00238 {
00239 if ( !rrule ) {
00240 return rNone;
00241 }
00242 RecurrenceRule::PeriodType type = rrule->recurrenceType();
00243
00244
00245 if ( !rrule->bySetPos().isEmpty() ||
00246 !rrule->bySeconds().isEmpty() ||
00247 !rrule->byWeekNumbers().isEmpty() ) {
00248 return rOther;
00249 }
00250
00251
00252
00253 if ( !rrule->byMinutes().isEmpty() || !rrule->byHours().isEmpty() ) {
00254 return rOther;
00255 }
00256
00257
00258
00259
00260
00261
00262 if ( ( !rrule->byYearDays().isEmpty() && type != RecurrenceRule::rYearly ) ||
00263 ( !rrule->byMonths().isEmpty() && type != RecurrenceRule::rYearly ) ) {
00264 return rOther;
00265 }
00266 if ( !rrule->byDays().isEmpty() ) {
00267 if ( type != RecurrenceRule::rYearly &&
00268 type != RecurrenceRule::rMonthly &&
00269 type != RecurrenceRule::rWeekly ) {
00270 return rOther;
00271 }
00272 }
00273
00274 switch ( type ) {
00275 case RecurrenceRule::rNone:
00276 return rNone;
00277 case RecurrenceRule::rMinutely:
00278 return rMinutely;
00279 case RecurrenceRule::rHourly:
00280 return rHourly;
00281 case RecurrenceRule::rDaily:
00282 return rDaily;
00283 case RecurrenceRule::rWeekly:
00284 return rWeekly;
00285 case RecurrenceRule::rMonthly:
00286 {
00287 if ( rrule->byDays().isEmpty() ) {
00288 return rMonthlyDay;
00289 } else if ( rrule->byMonthDays().isEmpty() ) {
00290 return rMonthlyPos;
00291 } else {
00292 return rOther;
00293 }
00294 }
00295 case RecurrenceRule::rYearly:
00296 {
00297
00298
00299
00300
00301 if ( !rrule->byDays().isEmpty() ) {
00302
00303 if ( rrule->byMonthDays().isEmpty() && rrule->byYearDays().isEmpty() ) {
00304 return rYearlyPos;
00305 } else {
00306 return rOther;
00307 }
00308 } else if ( !rrule->byYearDays().isEmpty() ) {
00309
00310 if ( rrule->byMonths().isEmpty() && rrule->byMonthDays().isEmpty() ) {
00311 return rYearlyDay;
00312 } else {
00313 return rOther;
00314 }
00315 } else {
00316 return rYearlyMonth;
00317 }
00318 break;
00319 }
00320 default: return rOther;
00321 }
00322 return rOther;
00323 }
00324
00325 bool Recurrence::recursOn( const QDate &qd, const KDateTime::Spec &timeSpec ) const
00326 {
00327
00328 if ( KDateTime( qd, QTime( 23, 59, 59 ), timeSpec ) < d->mStartDateTime ) {
00329 return false;
00330 }
00331
00332
00333 if ( d->mExDates.containsSorted( qd ) ) {
00334 return false;
00335 }
00336
00337 int i, end;
00338 TimeList tms;
00339
00340
00341 if ( allDay() ) {
00342 for ( i = 0, end = d->mExRules.count(); i < end; ++i ) {
00343 if ( d->mExRules[i]->recursOn( qd, timeSpec ) ) {
00344 return false;
00345 }
00346 }
00347 }
00348
00349 if ( d->mRDates.containsSorted( qd ) ) {
00350 return true;
00351 }
00352
00353
00354 bool recurs = ( startDate() == qd );
00355 for ( i = 0, end = d->mRDateTimes.count(); i < end && !recurs; ++i ) {
00356 recurs = ( d->mRDateTimes[i].toTimeSpec( timeSpec ).date() == qd );
00357 }
00358 for ( i = 0, end = d->mRRules.count(); i < end && !recurs; ++i ) {
00359 recurs = d->mRRules[i]->recursOn( qd, timeSpec );
00360 }
00361
00362 if ( !recurs ) {
00363 return false;
00364 }
00365
00366
00367 bool exon = false;
00368 for ( i = 0, end = d->mExDateTimes.count(); i < end && !exon; ++i ) {
00369 exon = ( d->mExDateTimes[i].toTimeSpec( timeSpec ).date() == qd );
00370 }
00371 if ( !allDay() ) {
00372 for ( i = 0, end = d->mExRules.count(); i < end && !exon; ++i ) {
00373 exon = d->mExRules[i]->recursOn( qd, timeSpec );
00374 }
00375 }
00376
00377 if ( !exon ) {
00378
00379 return recurs;
00380 } else {
00381
00382
00383
00384
00385 TimeList timesForDay( recurTimesOn( qd, timeSpec ) );
00386 return !timesForDay.isEmpty();
00387 }
00388 }
00389
00390 bool Recurrence::recursAt( const KDateTime &dt ) const
00391 {
00392
00393 KDateTime dtrecur = dt.toTimeSpec( d->mStartDateTime.timeSpec() );
00394
00395
00396 if ( d->mExDateTimes.containsSorted( dtrecur ) ||
00397 d->mExDates.containsSorted( dtrecur.date() ) ) {
00398 return false;
00399 }
00400 int i, end;
00401 for ( i = 0, end = d->mExRules.count(); i < end; ++i ) {
00402 if ( d->mExRules[i]->recursAt( dtrecur ) ) {
00403 return false;
00404 }
00405 }
00406
00407
00408 if ( startDateTime() == dtrecur || d->mRDateTimes.containsSorted( dtrecur ) ) {
00409 return true;
00410 }
00411 for ( i = 0, end = d->mRRules.count(); i < end; ++i ) {
00412 if ( d->mRRules[i]->recursAt( dtrecur ) ) {
00413 return true;
00414 }
00415 }
00416
00417 return false;
00418 }
00419
00423 KDateTime Recurrence::endDateTime() const
00424 {
00425 DateTimeList dts;
00426 dts << startDateTime();
00427 if ( !d->mRDates.isEmpty() ) {
00428 dts << KDateTime( d->mRDates.last(), QTime( 0, 0, 0 ), d->mStartDateTime.timeSpec() );
00429 }
00430 if ( !d->mRDateTimes.isEmpty() ) {
00431 dts << d->mRDateTimes.last();
00432 }
00433 for ( int i = 0, end = d->mRRules.count(); i < end; ++i ) {
00434 KDateTime rl( d->mRRules[i]->endDt() );
00435
00436 if ( !rl.isValid() ) {
00437 return KDateTime();
00438 }
00439 dts << rl;
00440 }
00441 dts.sortUnique();
00442 return dts.isEmpty() ? KDateTime() : dts.last();
00443 }
00444
00448 QDate Recurrence::endDate() const
00449 {
00450 KDateTime end( endDateTime() );
00451 return end.isValid() ? end.date() : QDate();
00452 }
00453
00454 void Recurrence::setEndDate( const QDate &date )
00455 {
00456 KDateTime dt( date, d->mStartDateTime.time(), d->mStartDateTime.timeSpec() );
00457 if ( allDay() ) {
00458 dt.setTime( QTime( 23, 59, 59 ) );
00459 }
00460 setEndDateTime( dt );
00461 }
00462
00463 void Recurrence::setEndDateTime( const KDateTime &dateTime )
00464 {
00465 if ( d->mRecurReadOnly ) {
00466 return;
00467 }
00468 RecurrenceRule *rrule = defaultRRule( true );
00469 if ( !rrule ) {
00470 return;
00471 }
00472 rrule->setEndDt( dateTime );
00473 updated();
00474 }
00475
00476 int Recurrence::duration() const
00477 {
00478 RecurrenceRule *rrule = defaultRRuleConst();
00479 return rrule ? rrule->duration() : 0;
00480 }
00481
00482 int Recurrence::durationTo( const KDateTime &datetime ) const
00483 {
00484
00485 RecurrenceRule *rrule = defaultRRuleConst();
00486 return rrule ? rrule->durationTo( datetime ) : 0;
00487 }
00488
00489 int Recurrence::durationTo( const QDate &date ) const
00490 {
00491 return durationTo( KDateTime( date, QTime( 23, 59, 59 ), d->mStartDateTime.timeSpec() ) );
00492 }
00493
00494 void Recurrence::setDuration( int duration )
00495 {
00496 if ( d->mRecurReadOnly ) {
00497 return;
00498 }
00499
00500 RecurrenceRule *rrule = defaultRRule( true );
00501 if ( !rrule ) {
00502 return;
00503 }
00504 rrule->setDuration( duration );
00505 updated();
00506 }
00507
00508 void Recurrence::shiftTimes( const KDateTime::Spec &oldSpec, const KDateTime::Spec &newSpec )
00509 {
00510 if ( d->mRecurReadOnly ) {
00511 return;
00512 }
00513
00514 d->mStartDateTime = d->mStartDateTime.toTimeSpec( oldSpec );
00515 d->mStartDateTime.setTimeSpec( newSpec );
00516
00517 int i, end;
00518 for ( i = 0, end = d->mRDateTimes.count(); i < end; ++i ) {
00519 d->mRDateTimes[i] = d->mRDateTimes[i].toTimeSpec( oldSpec );
00520 d->mRDateTimes[i].setTimeSpec( newSpec );
00521 }
00522 for ( i = 0, end = d->mExDateTimes.count(); i < end; ++i ) {
00523 d->mExDateTimes[i] = d->mExDateTimes[i].toTimeSpec( oldSpec );
00524 d->mExDateTimes[i].setTimeSpec( newSpec );
00525 }
00526 for ( i = 0, end = d->mRRules.count(); i < end; ++i ) {
00527 d->mRRules[i]->shiftTimes( oldSpec, newSpec );
00528 }
00529 for ( i = 0, end = d->mExRules.count(); i < end; ++i ) {
00530 d->mExRules[i]->shiftTimes( oldSpec, newSpec );
00531 }
00532 }
00533
00534 void Recurrence::unsetRecurs()
00535 {
00536 if ( d->mRecurReadOnly ) {
00537 return;
00538 }
00539 d->mRRules.clear();
00540 updated();
00541 }
00542
00543 void Recurrence::clear()
00544 {
00545 if ( d->mRecurReadOnly ) {
00546 return;
00547 }
00548 d->mRRules.clearAll();
00549 d->mExRules.clearAll();
00550 d->mRDates.clear();
00551 d->mRDateTimes.clear();
00552 d->mExDates.clear();
00553 d->mExDateTimes.clear();
00554 d->mCachedType = rMax;
00555 updated();
00556 }
00557
00558 void Recurrence::setRecurReadOnly( bool readOnly )
00559 {
00560 d->mRecurReadOnly = readOnly;
00561 }
00562
00563 bool Recurrence::recurReadOnly() const
00564 {
00565 return d->mRecurReadOnly;
00566 }
00567
00568 QDate Recurrence::startDate() const
00569 {
00570 return d->mStartDateTime.date();
00571 }
00572
00573 void Recurrence::setStartDateTime( const KDateTime &start )
00574 {
00575 if ( d->mRecurReadOnly ) {
00576 return;
00577 }
00578 d->mStartDateTime = start;
00579 setAllDay( start.isDateOnly() );
00580
00581 int i, end;
00582 for ( i = 0, end = d->mRRules.count(); i < end; ++i ) {
00583 d->mRRules[i]->setStartDt( start );
00584 }
00585 for ( i = 0, end = d->mExRules.count(); i < end; ++i ) {
00586 d->mExRules[i]->setStartDt( start );
00587 }
00588 updated();
00589 }
00590
00591 int Recurrence::frequency() const
00592 {
00593 RecurrenceRule *rrule = defaultRRuleConst();
00594 return rrule ? rrule->frequency() : 0;
00595 }
00596
00597
00598
00599 void Recurrence::setFrequency( int freq )
00600 {
00601 if ( d->mRecurReadOnly || freq <= 0 ) {
00602 return;
00603 }
00604
00605 RecurrenceRule *rrule = defaultRRule( true );
00606 if ( rrule ) {
00607 rrule->setFrequency( freq );
00608 }
00609 updated();
00610 }
00611
00612
00613
00614 int Recurrence::weekStart() const
00615 {
00616 RecurrenceRule *rrule = defaultRRuleConst();
00617 return rrule ? rrule->weekStart() : 1;
00618 }
00619
00620
00621 QBitArray Recurrence::days() const
00622 {
00623 QBitArray days( 7 );
00624 days.fill( 0 );
00625 RecurrenceRule *rrule = defaultRRuleConst();
00626 if ( rrule ) {
00627 QList<RecurrenceRule::WDayPos> bydays = rrule->byDays();
00628 for ( int i = 0; i < bydays.size(); ++i ) {
00629 if ( bydays.at(i).pos() == 0 ) {
00630 days.setBit( bydays.at( i ).day() - 1 );
00631 }
00632 }
00633 }
00634 return days;
00635 }
00636
00637
00638
00639
00640 QList<int> Recurrence::monthDays() const
00641 {
00642 RecurrenceRule *rrule = defaultRRuleConst();
00643 if ( rrule ) {
00644 return rrule->byMonthDays();
00645 } else {
00646 return QList<int>();
00647 }
00648 }
00649
00650
00651 QList<RecurrenceRule::WDayPos> Recurrence::monthPositions() const
00652 {
00653 RecurrenceRule *rrule = defaultRRuleConst();
00654 return rrule ? rrule->byDays() : QList<RecurrenceRule::WDayPos>();
00655 }
00656
00657
00658
00659 QList<int> Recurrence::yearDays() const
00660 {
00661 RecurrenceRule *rrule = defaultRRuleConst();
00662 return rrule ? rrule->byYearDays() : QList<int>();
00663 }
00664
00665 QList<int> Recurrence::yearDates() const
00666 {
00667 return monthDays();
00668 }
00669
00670 QList<int> Recurrence::yearMonths() const
00671 {
00672 RecurrenceRule *rrule = defaultRRuleConst();
00673 return rrule ? rrule->byMonths() : QList<int>();
00674 }
00675
00676 QList<RecurrenceRule::WDayPos> Recurrence::yearPositions() const
00677 {
00678 return monthPositions();
00679 }
00680
00681 RecurrenceRule *Recurrence::setNewRecurrenceType( RecurrenceRule::PeriodType type, int freq )
00682 {
00683 if ( d->mRecurReadOnly || freq <= 0 ) {
00684 return 0;
00685 }
00686
00687 d->mRRules.clearAll();
00688 updated();
00689 RecurrenceRule *rrule = defaultRRule( true );
00690 if ( !rrule ) {
00691 return 0;
00692 }
00693 rrule->setRecurrenceType( type );
00694 rrule->setFrequency( freq );
00695 rrule->setDuration( -1 );
00696 return rrule;
00697 }
00698
00699 void Recurrence::setMinutely( int _rFreq )
00700 {
00701 if ( setNewRecurrenceType( RecurrenceRule::rMinutely, _rFreq ) ) {
00702 updated();
00703 }
00704 }
00705
00706 void Recurrence::setHourly( int _rFreq )
00707 {
00708 if ( setNewRecurrenceType( RecurrenceRule::rHourly, _rFreq ) ) {
00709 updated();
00710 }
00711 }
00712
00713 void Recurrence::setDaily( int _rFreq )
00714 {
00715 if ( setNewRecurrenceType( RecurrenceRule::rDaily, _rFreq ) ) {
00716 updated();
00717 }
00718 }
00719
00720 void Recurrence::setWeekly( int freq, int weekStart )
00721 {
00722 RecurrenceRule *rrule = setNewRecurrenceType( RecurrenceRule::rWeekly, freq );
00723 if ( !rrule ) {
00724 return;
00725 }
00726 rrule->setWeekStart( weekStart );
00727 updated();
00728 }
00729
00730 void Recurrence::setWeekly( int freq, const QBitArray &days, int weekStart )
00731 {
00732 setWeekly( freq, weekStart );
00733 addMonthlyPos( 0, days );
00734 }
00735
00736 void Recurrence::addWeeklyDays( const QBitArray &days )
00737 {
00738 addMonthlyPos( 0, days );
00739 }
00740
00741 void Recurrence::setMonthly( int freq )
00742 {
00743 if ( setNewRecurrenceType( RecurrenceRule::rMonthly, freq ) ) {
00744 updated();
00745 }
00746 }
00747
00748 void Recurrence::addMonthlyPos( short pos, const QBitArray &days )
00749 {
00750
00751 if ( d->mRecurReadOnly || pos > 53 || pos < -53 ) {
00752 return;
00753 }
00754
00755 RecurrenceRule *rrule = defaultRRule( false );
00756 if ( !rrule ) {
00757 return;
00758 }
00759 bool changed = false;
00760 QList<RecurrenceRule::WDayPos> positions = rrule->byDays();
00761
00762 for ( int i = 0; i < 7; ++i ) {
00763 if ( days.testBit(i) ) {
00764 RecurrenceRule::WDayPos p( pos, i + 1 );
00765 if ( !positions.contains( p ) ) {
00766 changed = true;
00767 positions.append( p );
00768 }
00769 }
00770 }
00771 if ( changed ) {
00772 rrule->setByDays( positions );
00773 updated();
00774 }
00775 }
00776
00777 void Recurrence::addMonthlyPos( short pos, ushort day )
00778 {
00779
00780 if ( d->mRecurReadOnly || pos > 53 || pos < -53 ) {
00781 return;
00782 }
00783
00784 RecurrenceRule *rrule = defaultRRule( false );
00785 if ( !rrule ) {
00786 return;
00787 }
00788 QList<RecurrenceRule::WDayPos> positions = rrule->byDays();
00789
00790 RecurrenceRule::WDayPos p( pos, day );
00791 if ( !positions.contains( p ) ) {
00792 positions.append( p );
00793 rrule->setByDays( positions );
00794 updated();
00795 }
00796 }
00797
00798 void Recurrence::addMonthlyDate( short day )
00799 {
00800 if ( d->mRecurReadOnly || day > 31 || day < -31 ) {
00801 return;
00802 }
00803
00804 RecurrenceRule *rrule = defaultRRule( true );
00805 if ( !rrule ) {
00806 return;
00807 }
00808
00809 QList<int> monthDays = rrule->byMonthDays();
00810 if ( !monthDays.contains( day ) ) {
00811 monthDays.append( day );
00812 rrule->setByMonthDays( monthDays );
00813 updated();
00814 }
00815 }
00816
00817 void Recurrence::setYearly( int freq )
00818 {
00819 if ( setNewRecurrenceType( RecurrenceRule::rYearly, freq ) ) {
00820 updated();
00821 }
00822 }
00823
00824
00825 void Recurrence::addYearlyDay( int day )
00826 {
00827 RecurrenceRule *rrule = defaultRRule( false );
00828 if ( !rrule ) {
00829 return;
00830 }
00831
00832 QList<int> days = rrule->byYearDays();
00833 if ( !days.contains( day ) ) {
00834 days << day;
00835 rrule->setByYearDays( days );
00836 updated();
00837 }
00838 }
00839
00840
00841 void Recurrence::addYearlyDate( int day )
00842 {
00843 addMonthlyDate( day );
00844 }
00845
00846
00847 void Recurrence::addYearlyPos( short pos, const QBitArray &days )
00848 {
00849 addMonthlyPos( pos, days );
00850 }
00851
00852
00853 void Recurrence::addYearlyMonth( short month )
00854 {
00855 if ( d->mRecurReadOnly || month < 1 || month > 12 ) {
00856 return;
00857 }
00858
00859 RecurrenceRule *rrule = defaultRRule( false );
00860 if ( !rrule ) {
00861 return;
00862 }
00863
00864 QList<int> months = rrule->byMonths();
00865 if ( !months.contains(month) ) {
00866 months << month;
00867 rrule->setByMonths( months );
00868 updated();
00869 }
00870 }
00871
00872 TimeList Recurrence::recurTimesOn( const QDate &date, const KDateTime::Spec &timeSpec ) const
00873 {
00874
00875 int i, end;
00876 TimeList times;
00877
00878
00879 if ( d->mExDates.containsSorted( date ) ) {
00880 return times;
00881 }
00882
00883
00884
00885 if ( allDay() ) {
00886 for ( i = 0, end = d->mExRules.count(); i < end; ++i ) {
00887 if ( d->mExRules[i]->recursOn( date, timeSpec ) ) {
00888 return times;
00889 }
00890 }
00891 }
00892
00893 KDateTime dt = startDateTime().toTimeSpec( timeSpec );
00894 if ( dt.date() == date ) {
00895 times << dt.time();
00896 }
00897
00898 bool foundDate = false;
00899 for ( i = 0, end = d->mRDateTimes.count(); i < end; ++i ) {
00900 dt = d->mRDateTimes[i].toTimeSpec( timeSpec );
00901 if ( dt.date() == date ) {
00902 times << dt.time();
00903 foundDate = true;
00904 } else if (foundDate) break;
00905 }
00906 for ( i = 0, end = d->mRRules.count(); i < end; ++i ) {
00907 times += d->mRRules[i]->recurTimesOn( date, timeSpec );
00908 }
00909 times.sortUnique();
00910
00911 foundDate = false;
00912 TimeList extimes;
00913 for ( i = 0, end = d->mExDateTimes.count(); i < end; ++i ) {
00914 dt = d->mExDateTimes[i].toTimeSpec( timeSpec );
00915 if ( dt.date() == date ) {
00916 extimes << dt.time();
00917 foundDate = true;
00918 } else if (foundDate) break;
00919 }
00920 if ( !allDay() ) {
00921 for ( i = 0, end = d->mExRules.count(); i < end; ++i ) {
00922 extimes += d->mExRules[i]->recurTimesOn( date, timeSpec );
00923 }
00924 }
00925 extimes.sortUnique();
00926
00927 int st = 0;
00928 for ( i = 0, end = extimes.count(); i < end; ++i ) {
00929 int j = times.removeSorted( extimes[i], st );
00930 if ( j >= 0 ) {
00931 st = j;
00932 }
00933 }
00934 return times;
00935 }
00936
00937 DateTimeList Recurrence::timesInInterval( const KDateTime &start, const KDateTime &end ) const
00938 {
00939 int i, count;
00940 DateTimeList times;
00941 for ( i = 0, count = d->mRRules.count(); i < count; ++i ) {
00942 times += d->mRRules[i]->timesInInterval( start, end );
00943 }
00944
00945
00946 for ( i = 0, count = d->mRDateTimes.count(); i < count; ++i ) {
00947 if ( d->mRDateTimes[i] >= start && d->mRDateTimes[i] <= end ) {
00948 times += d->mRDateTimes[i];
00949 }
00950 }
00951
00952
00953 KDateTime kdt( d->mStartDateTime );
00954 for ( i = 0, count = d->mRDates.count(); i < count; ++i ) {
00955 kdt.setDate( d->mRDates[i] );
00956 if ( kdt >= start && kdt <= end ) {
00957 times += kdt;
00958 }
00959 }
00960
00961
00962
00963
00964
00965
00966 if ( ( !d->mRDates.isEmpty() || !d->mRDateTimes.isEmpty() ) &&
00967 d->mRRules.isEmpty() &&
00968 start <= d->mStartDateTime &&
00969 end >= d->mStartDateTime ) {
00970 times += d->mStartDateTime;
00971 }
00972
00973 times.sortUnique();
00974
00975
00976 int idt = 0;
00977 int enddt = times.count();
00978 for ( i = 0, count = d->mExDates.count(); i < count && idt < enddt; ++i ) {
00979 while ( idt < enddt && times[idt].date() < d->mExDates[i] ) ++idt;
00980 while ( idt < enddt && times[idt].date() == d->mExDates[i] ) {
00981 times.removeAt(idt);
00982 --enddt;
00983 }
00984 }
00985 DateTimeList extimes;
00986 for ( i = 0, count = d->mExRules.count(); i < count; ++i ) {
00987 extimes += d->mExRules[i]->timesInInterval( start, end );
00988 }
00989 extimes += d->mExDateTimes;
00990 extimes.sortUnique();
00991
00992 int st = 0;
00993 for ( i = 0, count = extimes.count(); i < count; ++i ) {
00994 int j = times.removeSorted( extimes[i], st );
00995 if ( j >= 0 ) {
00996 st = j;
00997 }
00998 }
00999
01000 return times;
01001 }
01002
01003 KDateTime Recurrence::getNextDateTime( const KDateTime &preDateTime ) const
01004 {
01005 KDateTime nextDT = preDateTime;
01006
01007
01008
01009
01010
01011 int loop = 0;
01012 while ( loop < 1000 ) {
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023 ++loop;
01024
01025 DateTimeList dates;
01026 if ( nextDT < startDateTime() ) {
01027 dates << startDateTime();
01028 }
01029
01030 int end;
01031
01032 int i = d->mRDateTimes.findGT( nextDT );
01033 if ( i >= 0 ) {
01034 dates << d->mRDateTimes[i];
01035 }
01036
01037 KDateTime kdt( startDateTime() );
01038 for ( i = 0, end = d->mRDates.count(); i < end; ++i ) {
01039 kdt.setDate( d->mRDates[i] );
01040 if ( kdt > nextDT ) {
01041 dates << kdt;
01042 break;
01043 }
01044 }
01045
01046
01047 for ( i = 0, end = d->mRRules.count(); i < end; ++i ) {
01048 KDateTime dt = d->mRRules[i]->getNextDate( nextDT );
01049 if ( dt.isValid() ) {
01050 dates << dt;
01051 }
01052 }
01053
01054
01055 dates.sortUnique();
01056 if ( dates.isEmpty() ) {
01057 return KDateTime();
01058 }
01059 nextDT = dates.first();
01060
01061
01062 if ( !d->mExDates.containsSorted( nextDT.date() ) &&
01063 !d->mExDateTimes.containsSorted( nextDT ) ) {
01064 bool allowed = true;
01065 for ( i = 0, end = d->mExRules.count(); i < end; ++i ) {
01066 allowed = allowed && !( d->mExRules[i]->recursAt( nextDT ) );
01067 }
01068 if ( allowed ) {
01069 return nextDT;
01070 }
01071 }
01072 }
01073
01074
01075 return KDateTime();
01076 }
01077
01078 KDateTime Recurrence::getPreviousDateTime( const KDateTime &afterDateTime ) const
01079 {
01080 KDateTime prevDT = afterDateTime;
01081
01082
01083
01084 int loop = 0;
01085 while ( loop < 1000 ) {
01086
01087
01088
01089
01090
01091
01092
01093
01094
01095 ++loop;
01096
01097 DateTimeList dates;
01098 if ( prevDT > startDateTime() ) {
01099 dates << startDateTime();
01100 }
01101
01102 int i = d->mRDateTimes.findLT( prevDT );
01103 if ( i >= 0 ) {
01104 dates << d->mRDateTimes[i];
01105 }
01106
01107 KDateTime kdt( startDateTime() );
01108 for ( i = d->mRDates.count(); --i >= 0; ) {
01109 kdt.setDate( d->mRDates[i] );
01110 if ( kdt < prevDT ) {
01111 dates << kdt;
01112 break;
01113 }
01114 }
01115
01116
01117 int end;
01118 for ( i = 0, end = d->mRRules.count(); i < end; ++i ) {
01119 KDateTime dt = d->mRRules[i]->getPreviousDate( prevDT );
01120 if ( dt.isValid() ) {
01121 dates << dt;
01122 }
01123 }
01124
01125
01126 dates.sortUnique();
01127 if ( dates.isEmpty() ) {
01128 return KDateTime();
01129 }
01130 prevDT = dates.last();
01131
01132
01133 if ( !d->mExDates.containsSorted( prevDT.date() ) &&
01134 !d->mExDateTimes.containsSorted( prevDT ) ) {
01135 bool allowed = true;
01136 for ( i = 0, end = d->mExRules.count(); i < end; ++i ) {
01137 allowed = allowed && !( d->mExRules[i]->recursAt( prevDT ) );
01138 }
01139 if ( allowed ) {
01140 return prevDT;
01141 }
01142 }
01143 }
01144
01145
01146 return KDateTime();
01147 }
01148
01149
01150
01151 RecurrenceRule::List Recurrence::rRules() const
01152 {
01153 return d->mRRules;
01154 }
01155
01156 void Recurrence::addRRule( RecurrenceRule *rrule )
01157 {
01158 if ( d->mRecurReadOnly || !rrule ) {
01159 return;
01160 }
01161
01162 rrule->setAllDay( d->mAllDay );
01163 d->mRRules.append( rrule );
01164 rrule->addObserver( this );
01165 updated();
01166 }
01167
01168 void Recurrence::removeRRule( RecurrenceRule *rrule )
01169 {
01170 if (d->mRecurReadOnly) {
01171 return;
01172 }
01173
01174 d->mRRules.removeAll( rrule );
01175 rrule->removeObserver( this );
01176 updated();
01177 }
01178
01179 void Recurrence::deleteRRule( RecurrenceRule *rrule )
01180 {
01181 if (d->mRecurReadOnly) {
01182 return;
01183 }
01184
01185 d->mRRules.removeAll( rrule );
01186 delete rrule;
01187 updated();
01188 }
01189
01190 RecurrenceRule::List Recurrence::exRules() const
01191 {
01192 return d->mExRules;
01193 }
01194
01195 void Recurrence::addExRule( RecurrenceRule *exrule )
01196 {
01197 if ( d->mRecurReadOnly || !exrule ) {
01198 return;
01199 }
01200
01201 exrule->setAllDay( d->mAllDay );
01202 d->mExRules.append( exrule );
01203 exrule->addObserver( this );
01204 updated();
01205 }
01206
01207 void Recurrence::removeExRule( RecurrenceRule *exrule )
01208 {
01209 if ( d->mRecurReadOnly ) {
01210 return;
01211 }
01212
01213 d->mExRules.removeAll( exrule );
01214 exrule->removeObserver( this );
01215 updated();
01216 }
01217
01218 void Recurrence::deleteExRule( RecurrenceRule *exrule )
01219 {
01220 if ( d->mRecurReadOnly ) {
01221 return;
01222 }
01223
01224 d->mExRules.removeAll( exrule );
01225 delete exrule;
01226 updated();
01227 }
01228
01229 DateTimeList Recurrence::rDateTimes() const
01230 {
01231 return d->mRDateTimes;
01232 }
01233
01234 void Recurrence::setRDateTimes( const DateTimeList &rdates )
01235 {
01236 if ( d->mRecurReadOnly ) {
01237 return;
01238 }
01239
01240 d->mRDateTimes = rdates;
01241 d->mRDateTimes.sortUnique();
01242 updated();
01243 }
01244
01245 void Recurrence::addRDateTime( const KDateTime &rdate )
01246 {
01247 if ( d->mRecurReadOnly ) {
01248 return;
01249 }
01250
01251 d->mRDateTimes.insertSorted( rdate );
01252 updated();
01253 }
01254
01255 DateList Recurrence::rDates() const
01256 {
01257 return d->mRDates;
01258 }
01259
01260 void Recurrence::setRDates( const DateList &rdates )
01261 {
01262 if ( d->mRecurReadOnly ) {
01263 return;
01264 }
01265
01266 d->mRDates = rdates;
01267 d->mRDates.sortUnique();
01268 updated();
01269 }
01270
01271 void Recurrence::addRDate( const QDate &rdate )
01272 {
01273 if ( d->mRecurReadOnly ) {
01274 return;
01275 }
01276
01277 d->mRDates.insertSorted( rdate );
01278 updated();
01279 }
01280
01281 DateTimeList Recurrence::exDateTimes() const
01282 {
01283 return d->mExDateTimes;
01284 }
01285
01286 void Recurrence::setExDateTimes( const DateTimeList &exdates )
01287 {
01288 if ( d->mRecurReadOnly ) {
01289 return;
01290 }
01291
01292 d->mExDateTimes = exdates;
01293 d->mExDateTimes.sortUnique();
01294 }
01295
01296 void Recurrence::addExDateTime( const KDateTime &exdate )
01297 {
01298 if ( d->mRecurReadOnly ) {
01299 return;
01300 }
01301
01302 d->mExDateTimes.insertSorted( exdate );
01303 updated();
01304 }
01305
01306 DateList Recurrence::exDates() const
01307 {
01308 return d->mExDates;
01309 }
01310
01311 void Recurrence::setExDates( const DateList &exdates )
01312 {
01313 if ( d->mRecurReadOnly ) {
01314 return;
01315 }
01316
01317 d->mExDates = exdates;
01318 d->mExDates.sortUnique();
01319 updated();
01320 }
01321
01322 void Recurrence::addExDate( const QDate &exdate )
01323 {
01324 if ( d->mRecurReadOnly ) {
01325 return;
01326 }
01327
01328 d->mExDates.insertSorted( exdate );
01329 updated();
01330 }
01331
01332 void Recurrence::recurrenceChanged( RecurrenceRule * )
01333 {
01334 updated();
01335 }
01336
01337
01338
01339 void Recurrence::dump() const
01340 {
01341 kDebug();
01342
01343 int i;
01344 int count = d->mRRules.count();
01345 kDebug() << " -)" << count << "RRULEs:";
01346 for ( i = 0; i < count; ++i ) {
01347 kDebug() << " -) RecurrenceRule: ";
01348 d->mRRules[i]->dump();
01349 }
01350 count = d->mExRules.count();
01351 kDebug() << " -)" << count << "EXRULEs:";
01352 for ( i = 0; i < count; ++i ) {
01353 kDebug() << " -) ExceptionRule :";
01354 d->mExRules[i]->dump();
01355 }
01356
01357 count = d->mRDates.count();
01358 kDebug() << endl << " -)" << count << "Recurrence Dates:";
01359 for ( i = 0; i < count; ++i ) {
01360 kDebug() << " " << d->mRDates[i];
01361 }
01362 count = d->mRDateTimes.count();
01363 kDebug() << endl << " -)" << count << "Recurrence Date/Times:";
01364 for ( i = 0; i < count; ++i ) {
01365 kDebug() << " " << d->mRDateTimes[i].dateTime();
01366 }
01367 count = d->mExDates.count();
01368 kDebug() << endl << " -)" << count << "Exceptions Dates:";
01369 for ( i = 0; i < count; ++i ) {
01370 kDebug() << " " << d->mExDates[i];
01371 }
01372 count = d->mExDateTimes.count();
01373 kDebug() << endl << " -)" << count << "Exception Date/Times:";
01374 for ( i = 0; i < count; ++i ) {
01375 kDebug() << " " << d->mExDateTimes[i].dateTime();
01376 }
01377 }