• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.8.3 API Reference
  • KDE Home
  • Contact Us
 

KCalCore Library

recurrence.cpp
00001 /*
00002   This file is part of kcalcore library.
00003 
00004   Copyright (c) 1998 Preston Brown <pbrown@kde.org>
00005   Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
00006   Copyright (c) 2002,2006 David Jarvie <software@astrojar.org.uk>
00007   Copyright (C) 2005 Reinhold Kainhofer <kainhofer@kde.org>
00008 
00009   This library is free software; you can redistribute it and/or
00010   modify it under the terms of the GNU Library General Public
00011   License as published by the Free Software Foundation; either
00012   version 2 of the License, or (at your option) any later version.
00013 
00014   This library is distributed in the hope that it will be useful,
00015   but WITHOUT ANY WARRANTY; without even the implied warranty of
00016   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017   Library General Public License for more details.
00018 
00019   You should have received a copy of the GNU Library General Public License
00020   along with this library; see the file COPYING.LIB.  If not, write to
00021   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00022   Boston, MA 02110-1301, USA.
00023 */
00024 #include "recurrence.h"
00025 
00026 #include <KDebug>
00027 
00028 #include <QtCore/QBitArray>
00029 
00030 using namespace KCalCore;
00031 
00032 //@cond PRIVATE
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;    // date/time of first recurrence
00064     QList<RecurrenceObserver*> mObservers;
00065 
00066     // Cache the type of the recurrence with the old system (e.g. MonthlyPos)
00067     mutable ushort mCachedType;
00068 
00069     bool mAllDay;                // the recurrence has no time, just a date
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 // Compare the rrules, exrules! Assume they have the same order... This only
00089 // matters if we have more than one rule (which shouldn't be the default anyway)
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 //@endcond
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   // check for self assignment
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   // recurrenceType() re-calculates the type if it's rMax
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   // BYSETPOS, BYWEEKNUMBER and BYSECOND were not supported in old versions
00250   if ( !rrule->bySetPos().isEmpty() ||
00251        !rrule->bySeconds().isEmpty() ||
00252        !rrule->byWeekNumbers().isEmpty() ) {
00253     return rOther;
00254   }
00255 
00256   // It wasn't possible to set BYMINUTES, BYHOUR etc. by the old code. So if
00257   // it's set, it's none of the old types
00258   if ( !rrule->byMinutes().isEmpty() || !rrule->byHours().isEmpty() ) {
00259     return rOther;
00260   }
00261 
00262   // Possible combinations were:
00263   // BYDAY: with WEEKLY, MONTHLY, YEARLY
00264   // BYMONTHDAY: with MONTHLY, YEARLY
00265   // BYMONTH: with YEARLY
00266   // BYYEARDAY: with YEARLY
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; // both position and date specified
00298     }
00299   }
00300   case RecurrenceRule::rYearly:
00301   {
00302     // Possible combinations:
00303     //   rYearlyMonth: [BYMONTH &] BYMONTHDAY
00304     //   rYearlyDay: BYYEARDAY
00305     //   rYearlyPos: [BYMONTH &] BYDAY
00306     if ( !rrule->byDays().isEmpty() ) {
00307       // can only by rYearlyPos
00308       if ( rrule->byMonthDays().isEmpty() && rrule->byYearDays().isEmpty() ) {
00309         return rYearlyPos;
00310       } else {
00311         return rOther;
00312       }
00313     } else if ( !rrule->byYearDays().isEmpty() ) {
00314       // Can only be rYearlyDay
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   // Don't waste time if date is before the start of the recurrence
00333   if ( KDateTime( qd, QTime( 23, 59, 59 ), timeSpec ) < d->mStartDateTime ) {
00334     return false;
00335   }
00336 
00337   // First handle dates. Exrules override
00338   if ( d->mExDates.containsSorted( qd ) ) {
00339     return false;
00340   }
00341 
00342   int i, end;
00343   TimeList tms;
00344   // For all-day events a matching exrule excludes the whole day
00345   // since exclusions take precedence over inclusions, we know it can't occur on that day.
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   // Check if it might recur today at all.
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   // If the event wouldn't recur at all, simply return false, don't check ex*
00367   if ( !recurs ) {
00368     return false;
00369   }
00370 
00371   // Check if there are any times for this day excluded, either by exdate or exrule:
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() ) {     // we have already checked all-day times above
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     // Simple case, nothing on that day excluded, return the value from before
00384     return recurs;
00385   } else {
00386     // Harder part: I don't think there is any way other than to calculate the
00387     // whole list of items for that day.
00388 //TODO: consider whether it would be more efficient to call
00389 //      Rule::recurTimesOn() instead of Rule::recursOn() from the start
00390     TimeList timesForDay( recurTimesOn( qd, timeSpec ) );
00391     return !timesForDay.isEmpty();
00392   }
00393 }
00394 
00395 bool Recurrence::recursAt( const KDateTime &dt ) const
00396 {
00397   // Convert to recurrence's time zone for date comparisons, and for more efficient time comparisons
00398   KDateTime dtrecur = dt.toTimeSpec( d->mStartDateTime.timeSpec() );
00399 
00400   // if it's excluded anyway, don't bother to check if it recurs at all.
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   // Check explicit recurrences, then rrules.
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     // if any of the rules is infinite, the whole recurrence is
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   // Emulate old behavior: This is just an interface to the first rule!
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   qDeleteAll( d->mRRules );
00545   d->mRRules.clear();
00546   updated();
00547 }
00548 
00549 void Recurrence::clear()
00550 {
00551   if ( d->mRecurReadOnly ) {
00552     return;
00553   }
00554   qDeleteAll( d->mRRules );
00555   d->mRRules.clear();
00556   qDeleteAll( d->mExRules );
00557   d->mExRules.clear();
00558   d->mRDates.clear();
00559   d->mRDateTimes.clear();
00560   d->mExDates.clear();
00561   d->mExDateTimes.clear();
00562   d->mCachedType = rMax;
00563   updated();
00564 }
00565 
00566 void Recurrence::setRecurReadOnly( bool readOnly )
00567 {
00568   d->mRecurReadOnly = readOnly;
00569 }
00570 
00571 bool Recurrence::recurReadOnly() const
00572 {
00573   return d->mRecurReadOnly;
00574 }
00575 
00576 QDate Recurrence::startDate() const
00577 {
00578   return d->mStartDateTime.date();
00579 }
00580 
00581 void Recurrence::setStartDateTime( const KDateTime &start )
00582 {
00583   if ( d->mRecurReadOnly ) {
00584     return;
00585   }
00586   d->mStartDateTime = start;
00587   setAllDay( start.isDateOnly() );   // set all RRULEs and EXRULEs
00588 
00589   int i, end;
00590   for ( i = 0, end = d->mRRules.count();  i < end;  ++i ) {
00591     d->mRRules[i]->setStartDt( start );
00592   }
00593   for ( i = 0, end = d->mExRules.count();  i < end;  ++i ) {
00594     d->mExRules[i]->setStartDt( start );
00595   }
00596   updated();
00597 }
00598 
00599 int Recurrence::frequency() const
00600 {
00601   RecurrenceRule *rrule = defaultRRuleConst();
00602   return rrule ? rrule->frequency() : 0;
00603 }
00604 
00605 // Emulate the old behaviour. Make this methods just an interface to the
00606 // first rrule
00607 void Recurrence::setFrequency( int freq )
00608 {
00609   if ( d->mRecurReadOnly || freq <= 0 ) {
00610     return;
00611   }
00612 
00613   RecurrenceRule *rrule = defaultRRule( true );
00614   if ( rrule ) {
00615     rrule->setFrequency( freq );
00616   }
00617   updated();
00618 }
00619 
00620 // WEEKLY
00621 
00622 int Recurrence::weekStart() const
00623 {
00624   RecurrenceRule *rrule = defaultRRuleConst();
00625   return rrule ? rrule->weekStart() : 1;
00626 }
00627 
00628 // Emulate the old behavior
00629 QBitArray Recurrence::days() const
00630 {
00631   QBitArray days( 7 );
00632   days.fill( 0 );
00633   RecurrenceRule *rrule = defaultRRuleConst();
00634   if ( rrule ) {
00635     QList<RecurrenceRule::WDayPos> bydays = rrule->byDays();
00636     for ( int i = 0; i < bydays.size(); ++i ) {
00637       if ( bydays.at(i).pos() == 0 ) {
00638         days.setBit( bydays.at( i ).day() - 1 );
00639       }
00640     }
00641   }
00642   return days;
00643 }
00644 
00645 // MONTHLY
00646 
00647 // Emulate the old behavior
00648 QList<int> Recurrence::monthDays() const
00649 {
00650   RecurrenceRule *rrule = defaultRRuleConst();
00651   if ( rrule ) {
00652     return rrule->byMonthDays();
00653   } else {
00654     return QList<int>();
00655   }
00656 }
00657 
00658 // Emulate the old behavior
00659 QList<RecurrenceRule::WDayPos> Recurrence::monthPositions() const
00660 {
00661   RecurrenceRule *rrule = defaultRRuleConst();
00662   return rrule ? rrule->byDays() : QList<RecurrenceRule::WDayPos>();
00663 }
00664 
00665 // YEARLY
00666 
00667 QList<int> Recurrence::yearDays() const
00668 {
00669   RecurrenceRule *rrule = defaultRRuleConst();
00670   return rrule ? rrule->byYearDays() : QList<int>();
00671 }
00672 
00673 QList<int> Recurrence::yearDates() const
00674 {
00675   return monthDays();
00676 }
00677 
00678 QList<int> Recurrence::yearMonths() const
00679 {
00680   RecurrenceRule *rrule = defaultRRuleConst();
00681   return rrule ? rrule->byMonths() : QList<int>();
00682 }
00683 
00684 QList<RecurrenceRule::WDayPos> Recurrence::yearPositions() const
00685 {
00686   return monthPositions();
00687 }
00688 
00689 RecurrenceRule *Recurrence::setNewRecurrenceType( RecurrenceRule::PeriodType type, int freq )
00690 {
00691   if ( d->mRecurReadOnly || freq <= 0 ) {
00692     return 0;
00693   }
00694 
00695   qDeleteAll( d->mRRules );
00696   d->mRRules.clear();
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   // Allow 53 for yearly!
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   // Allow 53 for yearly!
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 // Daynumber within year
00834 void Recurrence::addYearlyDay( int day )
00835 {
00836   RecurrenceRule *rrule = defaultRRule( false ); // It must already exist!
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 // day part of date within year
00850 void Recurrence::addYearlyDate( int day )
00851 {
00852   addMonthlyDate( day );
00853 }
00854 
00855 // day part of date within year, given as position (n-th weekday)
00856 void Recurrence::addYearlyPos( short pos, const QBitArray &days )
00857 {
00858   addMonthlyPos( pos, days );
00859 }
00860 
00861 // month part of date within year
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 // kDebug() << "recurTimesOn(" << date << ")";
00884   int i, end;
00885   TimeList times;
00886 
00887   // The whole day is excepted
00888   if ( d->mExDates.containsSorted( date ) ) {
00889     return times;
00890   }
00891 
00892   // EXRULE takes precedence over RDATE entries, so for all-day events,
00893   // a matching excule also excludes the whole day automatically
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; // <= Assume that the rdatetime list is sorted
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() ) {     // we have already checked all-day times above
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   // add rdatetimes that fit in the interval
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   // add rdates that fit in the interval
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   // Recurrence::timesInInterval(...) doesn't explicitly add mStartDateTime to the list
00971   // of times to be returned. It calls mRRules[i]->timesInInterval(...) which include
00972   // mStartDateTime.
00973   // So, If we have rdates/rdatetimes but don't have any rrule we must explicitly
00974   // add mStartDateTime to the list, otherwise we won't see the first occurrence.
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   // Remove excluded times
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   // prevent infinite loops, e.g. when an exrule extinguishes an rrule (e.g.
01016   // the exrule is identical to the rrule). If an occurrence is found, break
01017   // out of the loop by returning that KDateTime
01018 // TODO_Recurrence: Is a loop counter of 1000 really okay? I mean for secondly
01019 // recurrence, an exdate might exclude more than 1000 intervals!
01020   int loop = 0;
01021   while ( loop < 1000 ) {
01022     // Outline of the algo:
01023     //   1) Find the next date/time after preDateTime when the event could recur
01024     //     1.0) Add the start date if it's after preDateTime
01025     //     1.1) Use the next occurrence from the explicit RDATE lists
01026     //     1.2) Add the next recurrence for each of the RRULEs
01027     //   2) Take the earliest recurrence of these = KDateTime nextDT
01028     //   3) If that date/time is not excluded, either explicitly by an EXDATE or
01029     //      by an EXRULE, return nextDT as the next date/time of the recurrence
01030     //   4) If it's excluded, start all at 1), but starting at nextDT (instead
01031     //      of preDateTime). Loop at most 1000 times.
01032     ++loop;
01033     // First, get the next recurrence from the RDate lists
01034     DateTimeList dates;
01035     if ( nextDT < startDateTime() ) {
01036       dates << startDateTime();
01037     }
01038 
01039     int end;
01040     // Assume that the rdatetime list is sorted
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     // Add the next occurrences from all RRULEs.
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     // Take the first of these (all others can't be used later on)
01064     dates.sortUnique();
01065     if ( dates.isEmpty() ) {
01066       return KDateTime();
01067     }
01068     nextDT = dates.first();
01069 
01070     // Check if that date/time is excluded explicitly or by an exrule:
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   // Couldn't find a valid occurrences in 1000 loops, something is wrong!
01084   return KDateTime();
01085 }
01086 
01087 KDateTime Recurrence::getPreviousDateTime( const KDateTime &afterDateTime ) const
01088 {
01089   KDateTime prevDT = afterDateTime;
01090   // prevent infinite loops, e.g. when an exrule extinguishes an rrule (e.g.
01091   // the exrule is identical to the rrule). If an occurrence is found, break
01092   // out of the loop by returning that KDateTime
01093   int loop = 0;
01094   while ( loop < 1000 ) {
01095     // Outline of the algo:
01096     //   1) Find the next date/time after preDateTime when the event could recur
01097     //     1.1) Use the next occurrence from the explicit RDATE lists
01098     //     1.2) Add the next recurrence for each of the RRULEs
01099     //   2) Take the earliest recurrence of these = KDateTime nextDT
01100     //   3) If that date/time is not excluded, either explicitly by an EXDATE or
01101     //      by an EXRULE, return nextDT as the next date/time of the recurrence
01102     //   4) If it's excluded, start all at 1), but starting at nextDT (instead
01103     //      of preDateTime). Loop at most 1000 times.
01104     ++loop;
01105     // First, get the next recurrence from the RDate lists
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     // Add the previous occurrences from all RRULEs.
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     // Take the last of these (all others can't be used later on)
01135     dates.sortUnique();
01136     if ( dates.isEmpty() ) {
01137       return KDateTime();
01138     }
01139     prevDT = dates.last();
01140 
01141     // Check if that date/time is excluded explicitly or by an exrule:
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   // Couldn't find a valid occurrences in 1000 loops, something is wrong!
01155   return KDateTime();
01156 }
01157 
01158 /***************************** PROTECTED FUNCTIONS ***************************/
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 // %%%%%%%%%%%%%%%%%% end:Recurrencerule %%%%%%%%%%%%%%%%%%
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 }
01387 
01388 Recurrence::RecurrenceObserver::~RecurrenceObserver()
01389 {
01390 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon May 14 2012 04:35:41 by doxygen 1.7.5 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KCalCore Library

Skip menu "KCalCore Library"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdepimlibs-4.8.3 API Reference

Skip menu "kdepimlibs-4.8.3 API Reference"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal