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