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