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

KCal Library

calendar.cpp
Go to the documentation of this file.
00001 /*
00002   This file is part of the kcal library.
00003 
00004   Copyright (c) 1998 Preston Brown <pbrown@kde.org>
00005   Copyright (c) 2000-2004 Cornelius Schumacher <schumacher@kde.org>
00006   Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
00007   Copyright (c) 2006 David Jarvie <software@astrojar.org.uk>
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 */
00038 #include "calendar.h"
00039 #include "exceptions.h"
00040 #include "calfilter.h"
00041 #include "icaltimezones.h"
00042 #include <kdebug.h>
00043 #include <klocale.h>
00044 
00045 extern "C" {
00046   #include <icaltimezone.h>
00047 }
00048 
00049 using namespace KCal;
00050 
00055 //@cond PRIVATE
00056 class KCal::Calendar::Private
00057 {
00058   public:
00059     Private()
00060       : mTimeZones( new ICalTimeZones ),
00061         mModified( false ),
00062         mNewObserver( false ),
00063         mObserversEnabled( true ),
00064         mDefaultFilter( new CalFilter )
00065     {
00066       // Setup default filter, which does nothing
00067       mFilter = mDefaultFilter;
00068       mFilter->setEnabled( false );
00069 
00070       // user information...
00071       mOwner.setName( i18n( "Unknown Name" ) );
00072       mOwner.setEmail( i18n( "unknown@nowhere" ) );
00073     }
00074 
00075     ~Private()
00076     {
00077       delete mTimeZones;
00078       if ( mFilter != mDefaultFilter ) {
00079         delete mFilter;
00080       }
00081       delete mDefaultFilter;
00082     }
00083     KDateTime::Spec timeZoneIdSpec( const QString &timeZoneId, bool view );
00084 
00085     QString mProductId;
00086     Person mOwner;
00087     ICalTimeZones *mTimeZones; // collection of time zones used in this calendar
00088     ICalTimeZone mBuiltInTimeZone;   // cached time zone lookup
00089     ICalTimeZone mBuiltInViewTimeZone;   // cached viewing time zone lookup
00090     KDateTime::Spec mTimeSpec;
00091     mutable KDateTime::Spec mViewTimeSpec;
00092     bool mModified;
00093     bool mNewObserver;
00094     bool mObserversEnabled;
00095     QList<CalendarObserver*> mObservers;
00096 
00097     CalFilter *mDefaultFilter;
00098     CalFilter *mFilter;
00099 
00100     // These lists are used to put together related To-dos
00101     QMultiHash<QString, Incidence*> mOrphans;
00102     QMultiHash<QString, Incidence*> mOrphanUids;
00103 };
00104 //@endcond
00105 
00106 Calendar::Calendar( const KDateTime::Spec &timeSpec )
00107   : d( new KCal::Calendar::Private )
00108 {
00109   d->mTimeSpec = timeSpec;
00110   d->mViewTimeSpec = timeSpec;
00111 }
00112 
00113 Calendar::Calendar( const QString &timeZoneId )
00114   : d( new KCal::Calendar::Private )
00115 {
00116   setTimeZoneId( timeZoneId );
00117 }
00118 
00119 Calendar::~Calendar()
00120 {
00121   delete d;
00122 }
00123 
00124 Person Calendar::owner() const
00125 {
00126   return d->mOwner;
00127 }
00128 
00129 void Calendar::setOwner( const Person &owner )
00130 {
00131   d->mOwner = owner;
00132 
00133   setModified( true );
00134 }
00135 
00136 void Calendar::setTimeSpec( const KDateTime::Spec &timeSpec )
00137 {
00138   d->mTimeSpec = timeSpec;
00139   d->mBuiltInTimeZone = ICalTimeZone();
00140   setViewTimeSpec( timeSpec );
00141 
00142   doSetTimeSpec( d->mTimeSpec );
00143 }
00144 
00145 KDateTime::Spec Calendar::timeSpec() const
00146 {
00147   return d->mTimeSpec;
00148 }
00149 
00150 void Calendar::setTimeZoneId( const QString &timeZoneId )
00151 {
00152   d->mTimeSpec = d->timeZoneIdSpec( timeZoneId, false );
00153   d->mViewTimeSpec = d->mTimeSpec;
00154   d->mBuiltInViewTimeZone = d->mBuiltInTimeZone;
00155 
00156   doSetTimeSpec( d->mTimeSpec );
00157 }
00158 
00159 //@cond PRIVATE
00160 KDateTime::Spec Calendar::Private::timeZoneIdSpec( const QString &timeZoneId,
00161                                                    bool view )
00162 {
00163   if ( view ) {
00164     mBuiltInViewTimeZone = ICalTimeZone();
00165   } else {
00166     mBuiltInTimeZone = ICalTimeZone();
00167   }
00168   if ( timeZoneId == QLatin1String( "UTC" ) ) {
00169     return KDateTime::UTC;
00170   }
00171   ICalTimeZone tz = mTimeZones->zone( timeZoneId );
00172   if ( !tz.isValid() ) {
00173     ICalTimeZoneSource tzsrc;
00174     tz = tzsrc.parse( icaltimezone_get_builtin_timezone( timeZoneId.toLatin1() ) );
00175     if ( view ) {
00176       mBuiltInViewTimeZone = tz;
00177     } else {
00178       mBuiltInTimeZone = tz;
00179     }
00180   }
00181   if ( tz.isValid() ) {
00182     return tz;
00183   } else {
00184     return KDateTime::ClockTime;
00185   }
00186 }
00187 //@endcond
00188 
00189 QString Calendar::timeZoneId() const
00190 {
00191   KTimeZone tz = d->mTimeSpec.timeZone();
00192   return tz.isValid() ? tz.name() : QString();
00193 }
00194 
00195 void Calendar::setViewTimeSpec( const KDateTime::Spec &timeSpec ) const
00196 {
00197   d->mViewTimeSpec = timeSpec;
00198   d->mBuiltInViewTimeZone = ICalTimeZone();
00199 }
00200 
00201 void Calendar::setViewTimeZoneId( const QString &timeZoneId ) const
00202 {
00203   d->mViewTimeSpec = d->timeZoneIdSpec( timeZoneId, true );
00204 }
00205 
00206 KDateTime::Spec Calendar::viewTimeSpec() const
00207 {
00208   return d->mViewTimeSpec;
00209 }
00210 
00211 QString Calendar::viewTimeZoneId() const
00212 {
00213   KTimeZone tz = d->mViewTimeSpec.timeZone();
00214   return tz.isValid() ? tz.name() : QString();
00215 }
00216 
00217 ICalTimeZones *Calendar::timeZones() const
00218 {
00219   return d->mTimeZones;
00220 }
00221 
00222 void Calendar::shiftTimes( const KDateTime::Spec &oldSpec,
00223                            const KDateTime::Spec &newSpec )
00224 {
00225   setTimeSpec( newSpec );
00226 
00227   int i, end;
00228   Event::List ev = events();
00229   for ( i = 0, end = ev.count();  i < end;  ++i ) {
00230     ev[i]->shiftTimes( oldSpec, newSpec );
00231   }
00232 
00233   Todo::List to = todos();
00234   for ( i = 0, end = to.count();  i < end;  ++i ) {
00235     to[i]->shiftTimes( oldSpec, newSpec );
00236   }
00237 
00238   Journal::List jo = journals();
00239   for ( i = 0, end = jo.count();  i < end;  ++i ) {
00240     jo[i]->shiftTimes( oldSpec, newSpec );
00241   }
00242 }
00243 
00244 void Calendar::setFilter( CalFilter *filter )
00245 {
00246   if ( filter ) {
00247     d->mFilter = filter;
00248   } else {
00249     d->mFilter = d->mDefaultFilter;
00250   }
00251 }
00252 
00253 CalFilter *Calendar::filter()
00254 {
00255   return d->mFilter;
00256 }
00257 
00258 QStringList Calendar::categories()
00259 {
00260   Incidence::List rawInc( rawIncidences() );
00261   QStringList cats, thisCats;
00262   // @TODO: For now just iterate over all incidences. In the future,
00263   // the list of categories should be built when reading the file.
00264   for ( Incidence::List::ConstIterator i = rawInc.constBegin();
00265         i != rawInc.constEnd(); ++i ) {
00266     thisCats = (*i)->categories();
00267     for ( QStringList::ConstIterator si = thisCats.constBegin();
00268           si != thisCats.constEnd(); ++si ) {
00269       if ( !cats.contains( *si ) ) {
00270         cats.append( *si );
00271       }
00272     }
00273   }
00274   return cats;
00275 }
00276 
00277 Incidence::List Calendar::incidences( const QDate &date )
00278 {
00279   return mergeIncidenceList( events( date ), todos( date ), journals( date ) );
00280 }
00281 
00282 Incidence::List Calendar::incidences()
00283 {
00284   return mergeIncidenceList( events(), todos(), journals() );
00285 }
00286 
00287 Incidence::List Calendar::rawIncidences()
00288 {
00289   return mergeIncidenceList( rawEvents(), rawTodos(), rawJournals() );
00290 }
00291 
00292 Event::List Calendar::sortEvents( Event::List *eventList,
00293                                   EventSortField sortField,
00294                                   SortDirection sortDirection )
00295 {
00296   Event::List eventListSorted;
00297   Event::List tempList;
00298   Event::List alphaList;
00299   Event::List::Iterator sortIt;
00300   Event::List::Iterator eit;
00301 
00302   // Notice we alphabetically presort Summaries first.
00303   // We do this so comparison "ties" stay in a nice order.
00304 
00305   switch( sortField ) {
00306   case EventSortUnsorted:
00307     eventListSorted = *eventList;
00308     break;
00309 
00310   case EventSortStartDate:
00311     alphaList = sortEvents( eventList, EventSortSummary, sortDirection );
00312     for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00313       if ( (*eit)->dtStart().isDateOnly() ) {
00314         tempList.append( *eit );
00315         continue;
00316       }
00317       sortIt = eventListSorted.begin();
00318       if ( sortDirection == SortDirectionAscending ) {
00319         while ( sortIt != eventListSorted.end() &&
00320                 (*eit)->dtStart() >= (*sortIt)->dtStart() ) {
00321           ++sortIt;
00322         }
00323       } else {
00324         while ( sortIt != eventListSorted.end() &&
00325                 (*eit)->dtStart() < (*sortIt)->dtStart() ) {
00326           ++sortIt;
00327         }
00328       }
00329       eventListSorted.insert( sortIt, *eit );
00330     }
00331     if ( sortDirection == SortDirectionAscending ) {
00332       // Prepend the list of all-day Events
00333       tempList += eventListSorted;
00334       eventListSorted = tempList;
00335     } else {
00336       // Append the list of all-day Events
00337       eventListSorted += tempList;
00338     }
00339     break;
00340 
00341   case EventSortEndDate:
00342     alphaList = sortEvents( eventList, EventSortSummary, sortDirection );
00343     for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00344       if ( (*eit)->hasEndDate() ) {
00345         sortIt = eventListSorted.begin();
00346         if ( sortDirection == SortDirectionAscending ) {
00347           while ( sortIt != eventListSorted.end() &&
00348                   (*eit)->dtEnd() >= (*sortIt)->dtEnd() ) {
00349             ++sortIt;
00350           }
00351         } else {
00352           while ( sortIt != eventListSorted.end() &&
00353                   (*eit)->dtEnd() < (*sortIt)->dtEnd() ) {
00354             ++sortIt;
00355           }
00356         }
00357       } else {
00358         // Keep a list of the Events without End DateTimes
00359         tempList.append( *eit );
00360       }
00361       eventListSorted.insert( sortIt, *eit );
00362     }
00363     if ( sortDirection == SortDirectionAscending ) {
00364       // Append the list of Events without End DateTimes
00365       eventListSorted += tempList;
00366     } else {
00367       // Prepend the list of Events without End DateTimes
00368       tempList += eventListSorted;
00369       eventListSorted = tempList;
00370     }
00371     break;
00372 
00373   case EventSortSummary:
00374     for ( eit = eventList->begin(); eit != eventList->end(); ++eit ) {
00375       sortIt = eventListSorted.begin();
00376       if ( sortDirection == SortDirectionAscending ) {
00377         while ( sortIt != eventListSorted.end() &&
00378                 (*eit)->summary() >= (*sortIt)->summary() ) {
00379           ++sortIt;
00380         }
00381       } else {
00382         while ( sortIt != eventListSorted.end() &&
00383                 (*eit)->summary() < (*sortIt)->summary() ) {
00384           ++sortIt;
00385         }
00386       }
00387       eventListSorted.insert( sortIt, *eit );
00388     }
00389     break;
00390   }
00391 
00392   return eventListSorted;
00393 }
00394 
00395 Event::List Calendar::sortEventsForDate( Event::List *eventList,
00396                                          const QDate &date,
00397                                          const KDateTime::Spec &timeSpec,
00398                                          EventSortField sortField,
00399                                          SortDirection sortDirection )
00400 {
00401   Event::List eventListSorted;
00402   Event::List tempList;
00403   Event::List alphaList;
00404   Event::List::Iterator sortIt;
00405   Event::List::Iterator eit;
00406 
00407   switch( sortField ) {
00408   case EventSortStartDate:
00409     alphaList = sortEvents( eventList, EventSortSummary, sortDirection );
00410     for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00411       if ( (*eit)->allDay() ) {
00412         tempList.append( *eit );
00413         continue;
00414       }
00415       sortIt = eventListSorted.begin();
00416       if ( sortDirection == SortDirectionAscending ) {
00417         while ( sortIt != eventListSorted.end() ) {
00418           if ( !(*eit)->recurs() ) {
00419             if ( (*eit)->dtStart().time() >= (*sortIt)->dtStart().time() ) {
00420               ++sortIt;
00421             } else {
00422               break;
00423             }
00424           } else {
00425             if ( (*eit)->recursOn( date, timeSpec ) ) {
00426               if ( (*eit)->dtStart().time() >= (*sortIt)->dtStart().time() ) {
00427                 ++sortIt;
00428               } else {
00429                 break;
00430               }
00431             } else {
00432               ++sortIt;
00433             }
00434           }
00435         }
00436       } else { // descending
00437         while ( sortIt != eventListSorted.end() ) {
00438           if ( !(*eit)->recurs() ) {
00439             if ( (*eit)->dtStart().time() < (*sortIt)->dtStart().time() ) {
00440               ++sortIt;
00441             } else {
00442               break;
00443             }
00444           } else {
00445             if ( (*eit)->recursOn( date, timeSpec ) ) {
00446               if ( (*eit)->dtStart().time() < (*sortIt)->dtStart().time() ) {
00447                 ++sortIt;
00448               } else {
00449                 break;
00450               }
00451             } else {
00452               ++sortIt;
00453             }
00454           }
00455         }
00456       }
00457       eventListSorted.insert( sortIt, *eit );
00458     }
00459     if ( sortDirection == SortDirectionAscending ) {
00460       // Prepend the list of all-day Events
00461       tempList += eventListSorted;
00462       eventListSorted = tempList;
00463     } else {
00464       // Append the list of all-day Events
00465       eventListSorted += tempList;
00466     }
00467     break;
00468 
00469   case EventSortEndDate:
00470     alphaList = sortEvents( eventList, EventSortSummary, sortDirection );
00471     for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00472       if ( (*eit)->hasEndDate() ) {
00473         sortIt = eventListSorted.begin();
00474         if ( sortDirection == SortDirectionAscending ) {
00475           while ( sortIt != eventListSorted.end() ) {
00476             if ( !(*eit)->recurs() ) {
00477               if ( (*eit)->dtEnd().time() >= (*sortIt)->dtEnd().time() ) {
00478                 ++sortIt;
00479               } else {
00480                 break;
00481               }
00482             } else {
00483               if ( (*eit)->recursOn( date, timeSpec ) ) {
00484                 if ( (*eit)->dtEnd().time() >= (*sortIt)->dtEnd().time() ) {
00485                   ++sortIt;
00486                 } else {
00487                   break;
00488                 }
00489               } else {
00490                 ++sortIt;
00491               }
00492             }
00493           }
00494         } else { // descending
00495           while ( sortIt != eventListSorted.end() ) {
00496             if ( !(*eit)->recurs() ) {
00497               if ( (*eit)->dtEnd().time() < (*sortIt)->dtEnd().time() ) {
00498                 ++sortIt;
00499               } else {
00500                 break;
00501               }
00502             } else {
00503               if ( (*eit)->recursOn( date, timeSpec ) ) {
00504                 if ( (*eit)->dtEnd().time() < (*sortIt)->dtEnd().time() ) {
00505                   ++sortIt;
00506                 } else {
00507                   break;
00508                 }
00509               } else {
00510                 ++sortIt;
00511               }
00512             }
00513           }
00514         }
00515       } else {
00516         // Keep a list of the Events without End DateTimes
00517         tempList.append( *eit );
00518       }
00519       eventListSorted.insert( sortIt, *eit );
00520     }
00521     if ( sortDirection == SortDirectionAscending ) {
00522       // Prepend the list of Events without End DateTimes
00523       tempList += eventListSorted;
00524       eventListSorted = tempList;
00525     } else {
00526       // Append the list of Events without End DateTimes
00527       eventListSorted += tempList;
00528     }
00529     break;
00530 
00531   default:
00532     eventListSorted = sortEvents( eventList, sortField, sortDirection );
00533     break;
00534   }
00535 
00536   return eventListSorted;
00537 }
00538 
00539 Event::List Calendar::events( const QDate &date,
00540                               const KDateTime::Spec &timeSpec,
00541                               EventSortField sortField,
00542                               SortDirection sortDirection )
00543 {
00544   Event::List el = rawEventsForDate( date, timeSpec, sortField, sortDirection );
00545   d->mFilter->apply( &el );
00546   return el;
00547 }
00548 
00549 Event::List Calendar::events( const KDateTime &dt )
00550 {
00551   Event::List el = rawEventsForDate( dt );
00552   d->mFilter->apply( &el );
00553   return el;
00554 }
00555 
00556 Event::List Calendar::events( const QDate &start, const QDate &end,
00557                               const KDateTime::Spec &timeSpec,
00558                               bool inclusive )
00559 {
00560   Event::List el = rawEvents( start, end, timeSpec, inclusive );
00561   d->mFilter->apply( &el );
00562   return el;
00563 }
00564 
00565 Event::List Calendar::events( EventSortField sortField,
00566                               SortDirection sortDirection )
00567 {
00568   Event::List el = rawEvents( sortField, sortDirection );
00569   d->mFilter->apply( &el );
00570   return el;
00571 }
00572 
00573 bool Calendar::addIncidence( Incidence *incidence )
00574 {
00575   Incidence::AddVisitor<Calendar> v( this );
00576 
00577   return incidence->accept( v );
00578 }
00579 
00580 bool Calendar::deleteIncidence( Incidence *incidence )
00581 {
00582   if ( beginChange( incidence ) ) {
00583     Incidence::DeleteVisitor<Calendar> v( this );
00584     bool result = incidence->accept( v );
00585     endChange( incidence );
00586     return result;
00587   } else {
00588     return false;
00589   }
00590 }
00591 
00592 // Dissociate a single occurrence or all future occurrences from a recurring
00593 // sequence. The new incidence is returned, but not automatically inserted
00594 // into the calendar, which is left to the calling application.
00595 Incidence *Calendar::dissociateOccurrence( Incidence *incidence,
00596                                            const QDate &date,
00597                                            const KDateTime::Spec &spec,
00598                                            bool single )
00599 {
00600   if ( !incidence || !incidence->recurs() ) {
00601     return 0;
00602   }
00603 
00604   Incidence *newInc = incidence->clone();
00605   newInc->recreate();
00606   // Do not call setRelatedTo() when dissociating recurring to-dos, otherwise the new to-do
00607   // will appear as a child.  Originally, we planned to set a relation with reltype SIBLING
00608   // when dissociating to-dos, but currently kcal only supports reltype PARENT.
00609   // We can uncomment the following line when we support the PARENT reltype.
00610   //newInc->setRelatedTo( incidence );
00611   Recurrence *recur = newInc->recurrence();
00612   if ( single ) {
00613     recur->clear();
00614   } else {
00615     // Adjust the recurrence for the future incidences. In particular adjust
00616     // the "end after n occurrences" rules! "No end date" and "end by ..."
00617     // don't need to be modified.
00618     int duration = recur->duration();
00619     if ( duration > 0 ) {
00620       int doneduration = recur->durationTo( date.addDays( -1 ) );
00621       if ( doneduration >= duration ) {
00622         kDebug() << "The dissociated event already occurred more often"
00623                  << "than it was supposed to ever occur. ERROR!";
00624         recur->clear();
00625       } else {
00626         recur->setDuration( duration - doneduration );
00627       }
00628     }
00629   }
00630   // Adjust the date of the incidence
00631   if ( incidence->type() == "Event" ) {
00632     Event *ev = static_cast<Event *>( newInc );
00633     KDateTime start( ev->dtStart() );
00634     int daysTo = start.toTimeSpec( spec ).date().daysTo( date );
00635     ev->setDtStart( start.addDays( daysTo ) );
00636     ev->setDtEnd( ev->dtEnd().addDays( daysTo ) );
00637   } else if ( incidence->type() == "Todo" ) {
00638     Todo *td = static_cast<Todo *>( newInc );
00639     bool haveOffset = false;
00640     int daysTo = 0;
00641     if ( td->hasDueDate() ) {
00642       KDateTime due( td->dtDue() );
00643       daysTo = due.toTimeSpec( spec ).date().daysTo( date );
00644       td->setDtDue( due.addDays( daysTo ), true );
00645       haveOffset = true;
00646     }
00647     if ( td->hasStartDate() ) {
00648       KDateTime start( td->dtStart() );
00649       if ( !haveOffset ) {
00650         daysTo = start.toTimeSpec( spec ).date().daysTo( date );
00651       }
00652       td->setDtStart( start.addDays( daysTo ) );
00653       haveOffset = true;
00654     }
00655   }
00656   recur = incidence->recurrence();
00657   if ( recur ) {
00658     if ( single ) {
00659       recur->addExDate( date );
00660     } else {
00661       // Make sure the recurrence of the past events ends
00662       // at the corresponding day
00663       recur->setEndDate( date.addDays(-1) );
00664     }
00665   }
00666   return newInc;
00667 }
00668 
00669 Incidence *Calendar::incidence( const QString &uid )
00670 {
00671   Incidence *i = event( uid );
00672   if ( i ) {
00673     return i;
00674   }
00675 
00676   i = todo( uid );
00677   if ( i ) {
00678     return i;
00679   }
00680 
00681   i = journal( uid );
00682   return i;
00683 }
00684 
00685 Incidence::List Calendar::incidencesFromSchedulingID( const QString &sid )
00686 {
00687   Incidence::List result;
00688   const Incidence::List incidences = rawIncidences();
00689   Incidence::List::const_iterator it = incidences.begin();
00690   for ( ; it != incidences.end(); ++it ) {
00691     if ( (*it)->schedulingID() == sid ) {
00692       result.append( *it );
00693     }
00694   }
00695   return result;
00696 }
00697 
00698 Incidence *Calendar::incidenceFromSchedulingID( const QString &UID )
00699 {
00700   const Incidence::List incidences = rawIncidences();
00701   Incidence::List::const_iterator it = incidences.begin();
00702   for ( ; it != incidences.end(); ++it ) {
00703     if ( (*it)->schedulingID() == UID ) {
00704       // Touchdown, and the crowd goes wild
00705       return *it;
00706     }
00707   }
00708   // Not found
00709   return 0;
00710 }
00711 
00712 Todo::List Calendar::sortTodos( Todo::List *todoList,
00713                                 TodoSortField sortField,
00714                                 SortDirection sortDirection )
00715 {
00716   Todo::List todoListSorted;
00717   Todo::List tempList, t;
00718   Todo::List alphaList;
00719   Todo::List::Iterator sortIt;
00720   Todo::List::Iterator eit;
00721 
00722   // Notice we alphabetically presort Summaries first.
00723   // We do this so comparison "ties" stay in a nice order.
00724 
00725   // Note that To-dos may not have Start DateTimes nor due DateTimes.
00726 
00727   switch( sortField ) {
00728   case TodoSortUnsorted:
00729     todoListSorted = *todoList;
00730     break;
00731 
00732   case TodoSortStartDate:
00733     alphaList = sortTodos( todoList, TodoSortSummary, sortDirection );
00734     for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00735       if ( (*eit)->hasStartDate() ) {
00736         sortIt = todoListSorted.begin();
00737         if ( sortDirection == SortDirectionAscending ) {
00738           while ( sortIt != todoListSorted.end() &&
00739                   (*eit)->dtStart() >= (*sortIt)->dtStart() ) {
00740             ++sortIt;
00741           }
00742         } else {
00743           while ( sortIt != todoListSorted.end() &&
00744                   (*eit)->dtStart() < (*sortIt)->dtStart() ) {
00745             ++sortIt;
00746           }
00747         }
00748         todoListSorted.insert( sortIt, *eit );
00749       } else {
00750         // Keep a list of the To-dos without Start DateTimes
00751         tempList.append( *eit );
00752       }
00753     }
00754     if ( sortDirection == SortDirectionAscending ) {
00755       // Append the list of To-dos without Start DateTimes
00756       todoListSorted += tempList;
00757     } else {
00758       // Prepend the list of To-dos without Start DateTimes
00759       tempList += todoListSorted;
00760       todoListSorted = tempList;
00761     }
00762     break;
00763 
00764   case TodoSortDueDate:
00765     alphaList = sortTodos( todoList, TodoSortSummary, sortDirection );
00766     for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00767       if ( (*eit)->hasDueDate() ) {
00768         sortIt = todoListSorted.begin();
00769         if ( sortDirection == SortDirectionAscending ) {
00770           while ( sortIt != todoListSorted.end() &&
00771                   (*eit)->dtDue() >= (*sortIt)->dtDue() ) {
00772             ++sortIt;
00773           }
00774         } else {
00775           while ( sortIt != todoListSorted.end() &&
00776                   (*eit)->dtDue() < (*sortIt)->dtDue() ) {
00777             ++sortIt;
00778           }
00779         }
00780         todoListSorted.insert( sortIt, *eit );
00781       } else {
00782         // Keep a list of the To-dos without Due DateTimes
00783         tempList.append( *eit );
00784       }
00785     }
00786     if ( sortDirection == SortDirectionAscending ) {
00787       // Append the list of To-dos without Due DateTimes
00788       todoListSorted += tempList;
00789     } else {
00790       // Prepend the list of To-dos without Due DateTimes
00791       tempList += todoListSorted;
00792       todoListSorted = tempList;
00793     }
00794     break;
00795 
00796   case TodoSortPriority:
00797     alphaList = sortTodos( todoList, TodoSortSummary, sortDirection );
00798     for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00799       sortIt = todoListSorted.begin();
00800       if ( sortDirection == SortDirectionAscending ) {
00801         while ( sortIt != todoListSorted.end() &&
00802                 (*eit)->priority() >= (*sortIt)->priority() ) {
00803           ++sortIt;
00804         }
00805       } else {
00806         while ( sortIt != todoListSorted.end() &&
00807                 (*eit)->priority() < (*sortIt)->priority() ) {
00808           ++sortIt;
00809         }
00810       }
00811       todoListSorted.insert( sortIt, *eit );
00812     }
00813     break;
00814 
00815   case TodoSortPercentComplete:
00816     alphaList = sortTodos( todoList, TodoSortSummary, sortDirection );
00817     for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00818       sortIt = todoListSorted.begin();
00819       if ( sortDirection == SortDirectionAscending ) {
00820         while ( sortIt != todoListSorted.end() &&
00821                 (*eit)->percentComplete() >= (*sortIt)->percentComplete() ) {
00822           ++sortIt;
00823         }
00824       } else {
00825         while ( sortIt != todoListSorted.end() &&
00826                 (*eit)->percentComplete() < (*sortIt)->percentComplete() ) {
00827           ++sortIt;
00828         }
00829       }
00830       todoListSorted.insert( sortIt, *eit );
00831     }
00832     break;
00833 
00834   case TodoSortSummary:
00835     for ( eit = todoList->begin(); eit != todoList->end(); ++eit ) {
00836       sortIt = todoListSorted.begin();
00837       if ( sortDirection == SortDirectionAscending ) {
00838         while ( sortIt != todoListSorted.end() &&
00839                 (*eit)->summary() >= (*sortIt)->summary() ) {
00840           ++sortIt;
00841         }
00842       } else {
00843         while ( sortIt != todoListSorted.end() &&
00844                 (*eit)->summary() < (*sortIt)->summary() ) {
00845           ++sortIt;
00846         }
00847       }
00848       todoListSorted.insert( sortIt, *eit );
00849     }
00850     break;
00851   }
00852 
00853   return todoListSorted;
00854 }
00855 
00856 Todo::List Calendar::todos( TodoSortField sortField,
00857                             SortDirection sortDirection )
00858 {
00859   Todo::List tl = rawTodos( sortField, sortDirection );
00860   d->mFilter->apply( &tl );
00861   return tl;
00862 }
00863 
00864 Todo::List Calendar::todos( const QDate &date )
00865 {
00866   Todo::List el = rawTodosForDate( date );
00867   d->mFilter->apply( &el );
00868   return el;
00869 }
00870 
00871 Journal::List Calendar::sortJournals( Journal::List *journalList,
00872                                       JournalSortField sortField,
00873                                       SortDirection sortDirection )
00874 {
00875   Journal::List journalListSorted;
00876   Journal::List::Iterator sortIt;
00877   Journal::List::Iterator eit;
00878 
00879   switch( sortField ) {
00880   case JournalSortUnsorted:
00881     journalListSorted = *journalList;
00882     break;
00883 
00884   case JournalSortDate:
00885     for ( eit = journalList->begin(); eit != journalList->end(); ++eit ) {
00886       sortIt = journalListSorted.begin();
00887       if ( sortDirection == SortDirectionAscending ) {
00888         while ( sortIt != journalListSorted.end() &&
00889                 (*eit)->dtStart() >= (*sortIt)->dtStart() ) {
00890           ++sortIt;
00891         }
00892       } else {
00893         while ( sortIt != journalListSorted.end() &&
00894                 (*eit)->dtStart() < (*sortIt)->dtStart() ) {
00895           ++sortIt;
00896         }
00897       }
00898       journalListSorted.insert( sortIt, *eit );
00899     }
00900     break;
00901 
00902   case JournalSortSummary:
00903     for ( eit = journalList->begin(); eit != journalList->end(); ++eit ) {
00904       sortIt = journalListSorted.begin();
00905       if ( sortDirection == SortDirectionAscending ) {
00906         while ( sortIt != journalListSorted.end() &&
00907                 (*eit)->summary() >= (*sortIt)->summary() ) {
00908           ++sortIt;
00909         }
00910       } else {
00911         while ( sortIt != journalListSorted.end() &&
00912                 (*eit)->summary() < (*sortIt)->summary() ) {
00913           ++sortIt;
00914         }
00915       }
00916       journalListSorted.insert( sortIt, *eit );
00917     }
00918     break;
00919   }
00920 
00921   return journalListSorted;
00922 }
00923 
00924 Journal::List Calendar::journals( JournalSortField sortField,
00925                                   SortDirection sortDirection )
00926 {
00927   Journal::List jl = rawJournals( sortField, sortDirection );
00928   d->mFilter->apply( &jl );
00929   return jl;
00930 }
00931 
00932 Journal::List Calendar::journals( const QDate &date )
00933 {
00934   Journal::List el = rawJournalsForDate( date );
00935   d->mFilter->apply( &el );
00936   return el;
00937 }
00938 
00939 void Calendar::beginBatchAdding()
00940 {
00941   emit batchAddingBegins();
00942 }
00943 
00944 void Calendar::endBatchAdding()
00945 {
00946   emit batchAddingEnds();
00947 }
00948 
00949 // When this is called, the to-dos have already been added to the calendar.
00950 // This method is only about linking related to-dos.
00951 void Calendar::setupRelations( Incidence *forincidence )
00952 {
00953   if ( !forincidence ) {
00954     return;
00955   }
00956 
00957   QString uid = forincidence->uid();
00958 
00959   // First, go over the list of orphans and see if this is their parent
00960   QList<Incidence*> l = d->mOrphans.values( uid );
00961   d->mOrphans.remove( uid );
00962   for ( int i = 0, end = l.count();  i < end;  ++i ) {
00963     l[i]->setRelatedTo( forincidence );
00964     forincidence->addRelation( l[i] );
00965     d->mOrphanUids.remove( l[i]->uid() );
00966   }
00967 
00968   // Now see about this incidences parent
00969   if ( !forincidence->relatedTo() && !forincidence->relatedToUid().isEmpty() ) {
00970     // Incidence has a uid it is related to but is not registered to it yet.
00971     // Try to find it
00972     Incidence *parent = incidence( forincidence->relatedToUid() );
00973     if ( parent ) {
00974       // Found it
00975 
00976       // look for hierarchy loops
00977       if ( isAncestorOf( forincidence, parent ) ) {
00978         forincidence->setRelatedToUid( QString() );
00979         kWarning() << "hierarchy loop beetween " << forincidence->uid() << " and " << parent->uid();
00980       } else {
00981         forincidence->setRelatedTo( parent );
00982         parent->addRelation( forincidence );
00983       }
00984 
00985     } else {
00986       // Not found, put this in the mOrphans list
00987       // Note that the mOrphans dict might contain multiple entries with the
00988       // same key! which are multiple children that wait for the parent
00989       // incidence to be inserted.
00990       d->mOrphans.insert( forincidence->relatedToUid(), forincidence );
00991       d->mOrphanUids.insert( forincidence->uid(), forincidence );
00992     }
00993   }
00994 }
00995 
00996 // If a to-do with sub-to-dos is deleted, move it's sub-to-dos to the orphan list
00997 void Calendar::removeRelations( Incidence *incidence )
00998 {
00999   if ( !incidence ) {
01000     kDebug() << "Warning: incidence is 0";
01001     return;
01002   }
01003 
01004   QString uid = incidence->uid();
01005   foreach ( Incidence *i, incidence->relations() ) {
01006     if ( !d->mOrphanUids.contains( i->uid() ) ) {
01007       d->mOrphans.insert( uid, i );
01008       d->mOrphanUids.insert( i->uid(), i );
01009       i->setRelatedTo( 0 );
01010       i->setRelatedToUid( uid );
01011     }
01012   }
01013 
01014   // If this incidence is related to something else, tell that about it
01015   if ( incidence->relatedTo() ) {
01016     incidence->relatedTo()->removeRelation( incidence );
01017   }
01018 
01019   // Remove this one from the orphans list
01020   if ( d->mOrphanUids.remove( uid ) ) {
01021     // This incidence is located in the orphans list - it should be removed
01022     // Since the mOrphans dict might contain the same key (with different
01023     // child incidence pointers!) multiple times, take care that we remove
01024     // the correct one. So we need to remove all items with the given
01025     // parent UID, and readd those that are not for this item. Also, there
01026     // might be other entries with differnet UID that point to this
01027     // incidence (this might happen when the relatedTo of the item is
01028     // changed before its parent is inserted. This might happen with
01029     // groupware servers....). Remove them, too
01030     QStringList relatedToUids;
01031 
01032     // First, create a list of all keys in the mOrphans list which point
01033     // to the removed item
01034     relatedToUids << incidence->relatedToUid();
01035     for ( QMultiHash<QString, Incidence*>::Iterator it = d->mOrphans.begin();
01036           it != d->mOrphans.end(); ++it ) {
01037       if ( it.value()->uid() == uid ) {
01038         relatedToUids << it.key();
01039       }
01040     }
01041 
01042     // now go through all uids that have one entry that point to the incidence
01043     for ( QStringList::const_iterator uidit = relatedToUids.constBegin();
01044           uidit != relatedToUids.constEnd(); ++uidit ) {
01045       Incidence::List tempList;
01046       // Remove all to get access to the remaining entries
01047       QList<Incidence*> l = d->mOrphans.values( *uidit );
01048       d->mOrphans.remove( *uidit );
01049       foreach ( Incidence *i, l ) {
01050         if ( i != incidence ) {
01051           tempList.append( i );
01052         }
01053       }
01054       // Readd those that point to a different orphan incidence
01055       for ( Incidence::List::Iterator incit = tempList.begin();
01056             incit != tempList.end(); ++incit ) {
01057         d->mOrphans.insert( *uidit, *incit );
01058       }
01059     }
01060   }
01061 
01062   // Make sure the deleted incidence doesn't relate to a non-deleted incidence,
01063   // since that would cause trouble in CalendarLocal::close(), as the deleted
01064   // incidences are destroyed after the non-deleted incidences. The destructor
01065   // of the deleted incidences would then try to access the already destroyed
01066   // non-deleted incidence, which would segfault.
01067   //
01068   // So in short: Make sure dead incidences don't point to alive incidences
01069   // via the relation.
01070   //
01071   // This crash is tested in CalendarLocalTest::testRelationsCrash().
01072   incidence->setRelatedTo( 0 );
01073 }
01074 
01075 bool Calendar::isAncestorOf( Incidence *ancestor, Incidence *incidence )
01076 {
01077   if ( !incidence || incidence->relatedToUid().isEmpty() ) {
01078     return false;
01079   } else if ( incidence->relatedToUid() == ancestor->uid() ) {
01080     return true;
01081   } else {
01082     return isAncestorOf( ancestor, this->incidence( incidence->relatedToUid() ) );
01083   }
01084 }
01085 
01086 void Calendar::CalendarObserver::calendarModified( bool modified, Calendar *calendar )
01087 {
01088   Q_UNUSED( modified );
01089   Q_UNUSED( calendar );
01090 }
01091 
01092 void Calendar::CalendarObserver::calendarIncidenceAdded( Incidence *incidence )
01093 {
01094   Q_UNUSED( incidence );
01095 }
01096 
01097 void Calendar::CalendarObserver::calendarIncidenceChanged( Incidence *incidence )
01098 {
01099   Q_UNUSED( incidence );
01100 }
01101 
01102 void Calendar::CalendarObserver::calendarIncidenceDeleted( Incidence *incidence )
01103 {
01104   Q_UNUSED( incidence );
01105 }
01106 
01107 void Calendar::registerObserver( CalendarObserver *observer )
01108 {
01109   if ( !d->mObservers.contains( observer ) ) {
01110     d->mObservers.append( observer );
01111   }
01112   d->mNewObserver = true;
01113 }
01114 
01115 void Calendar::unregisterObserver( CalendarObserver *observer )
01116 {
01117   d->mObservers.removeAll( observer );
01118 }
01119 
01120 bool Calendar::isSaving()
01121 {
01122   return false;
01123 }
01124 
01125 void Calendar::setModified( bool modified )
01126 {
01127   if ( modified != d->mModified || d->mNewObserver ) {
01128     d->mNewObserver = false;
01129     foreach ( CalendarObserver *observer, d->mObservers ) {
01130       observer->calendarModified( modified, this );
01131     }
01132     d->mModified = modified;
01133   }
01134 }
01135 
01136 bool Calendar::isModified() const
01137 {
01138   return d->mModified;
01139 }
01140 
01141 void Calendar::incidenceUpdated( IncidenceBase *incidence )
01142 {
01143   incidence->setLastModified( KDateTime::currentUtcDateTime() );
01144   // we should probably update the revision number here,
01145   // or internally in the Event itself when certain things change.
01146   // need to verify with ical documentation.
01147 
01148   // The static_cast is ok as the CalendarLocal only observes Incidence objects
01149   notifyIncidenceChanged( static_cast<Incidence *>( incidence ) );
01150 
01151   setModified( true );
01152 }
01153 
01154 void Calendar::doSetTimeSpec( const KDateTime::Spec &timeSpec )
01155 {
01156   Q_UNUSED( timeSpec );
01157 }
01158 
01159 void Calendar::notifyIncidenceAdded( Incidence *i )
01160 {
01161   if ( !d->mObserversEnabled ) {
01162     return;
01163   }
01164 
01165   foreach ( CalendarObserver *observer, d->mObservers ) {
01166     observer->calendarIncidenceAdded( i );
01167   }
01168 }
01169 
01170 void Calendar::notifyIncidenceChanged( Incidence *i )
01171 {
01172   if ( !d->mObserversEnabled ) {
01173     return;
01174   }
01175 
01176   foreach ( CalendarObserver *observer, d->mObservers ) {
01177     observer->calendarIncidenceChanged( i );
01178   }
01179 }
01180 
01181 void Calendar::notifyIncidenceDeleted( Incidence *i )
01182 {
01183   if ( !d->mObserversEnabled ) {
01184     return;
01185   }
01186 
01187   foreach ( CalendarObserver *observer, d->mObservers ) {
01188     observer->calendarIncidenceDeleted( i );
01189   }
01190 }
01191 
01192 void Calendar::customPropertyUpdated()
01193 {
01194   setModified( true );
01195 }
01196 
01197 void Calendar::setProductId( const QString &id )
01198 {
01199   d->mProductId = id;
01200 }
01201 
01202 QString Calendar::productId() const
01203 {
01204   return d->mProductId;
01205 }
01206 
01207 Incidence::List Calendar::mergeIncidenceList( const Event::List &events,
01208                                               const Todo::List &todos,
01209                                               const Journal::List &journals )
01210 {
01211   Incidence::List incidences;
01212 
01213   int i, end;
01214   for ( i = 0, end = events.count();  i < end;  ++i ) {
01215     incidences.append( events[i] );
01216   }
01217 
01218   for ( i = 0, end = todos.count();  i < end;  ++i ) {
01219     incidences.append( todos[i] );
01220   }
01221 
01222   for ( i = 0, end = journals.count();  i < end;  ++i ) {
01223     incidences.append( journals[i] );
01224   }
01225 
01226   return incidences;
01227 }
01228 
01229 bool Calendar::beginChange( Incidence *incidence )
01230 {
01231   Q_UNUSED( incidence );
01232   return true;
01233 }
01234 
01235 bool Calendar::endChange( Incidence *incidence )
01236 {
01237   Q_UNUSED( incidence );
01238   return true;
01239 }
01240 
01241 void Calendar::setObserversEnabled( bool enabled )
01242 {
01243   d->mObserversEnabled = enabled;
01244 }
01245 
01246 void Calendar::appendAlarms( Alarm::List &alarms, Incidence *incidence,
01247                              const KDateTime &from, const KDateTime &to )
01248 {
01249   KDateTime preTime = from.addSecs(-1);
01250 
01251   Alarm::List alarmlist = incidence->alarms();
01252   for ( int i = 0, iend = alarmlist.count();  i < iend;  ++i ) {
01253     if ( alarmlist[i]->enabled() ) {
01254       KDateTime dt = alarmlist[i]->nextRepetition( preTime );
01255       if ( dt.isValid() && dt <= to ) {
01256         kDebug() << incidence->summary() << "':" << dt.toString();
01257         alarms.append( alarmlist[i] );
01258       }
01259     }
01260   }
01261 }
01262 
01263 void Calendar::appendRecurringAlarms( Alarm::List &alarms,
01264                                       Incidence *incidence,
01265                                       const KDateTime &from,
01266                                       const KDateTime &to )
01267 {
01268   KDateTime dt;
01269   Duration endOffset( 0 );
01270   bool endOffsetValid = false;
01271   Duration period( from, to );
01272 
01273   Event *e = static_cast<Event *>( incidence );
01274   Todo *t = static_cast<Todo *>( incidence );
01275 
01276   Alarm::List alarmlist = incidence->alarms();
01277   for ( int i = 0, iend = alarmlist.count();  i < iend;  ++i ) {
01278     Alarm *a = alarmlist[i];
01279     if ( a->enabled() ) {
01280       if ( a->hasTime() ) {
01281         // The alarm time is defined as an absolute date/time
01282         dt = a->nextRepetition( from.addSecs( -1 ) );
01283         if ( !dt.isValid() || dt > to ) {
01284           continue;
01285         }
01286       } else {
01287         // Alarm time is defined by an offset from the event start or end time.
01288         // Find the offset from the event start time, which is also used as the
01289         // offset from the recurrence time.
01290         Duration offset( 0 );
01291         if ( a->hasStartOffset() ) {
01292           offset = a->startOffset();
01293         } else if ( a->hasEndOffset() ) {
01294           offset = a->endOffset();
01295           if ( !endOffsetValid ) {
01296             if ( incidence->type() == "Event" ) {
01297               endOffset = Duration( e->dtStart(), e->dtEnd() );
01298               endOffsetValid = true;
01299             } else if ( incidence->type() == "Todo" &&
01300                         t->hasStartDate() && t->hasDueDate() ) {
01301               endOffset = Duration( t->dtStart(), t->dtEnd() );
01302               endOffsetValid = true;
01303             }
01304           }
01305         }
01306 
01307         // Find the incidence's earliest alarm
01308         KDateTime alarmStart;
01309         if ( incidence->type() == "Event" ) {
01310           alarmStart =
01311             offset.end( a->hasEndOffset() ? e->dtEnd() : e->dtStart() );
01312         } else if ( incidence->type() == "Todo" ) {
01313           alarmStart =
01314             offset.end( a->hasEndOffset() ? t->dtDue() : t->dtStart() );
01315         }
01316 
01317         if ( alarmStart.isValid() && alarmStart > to ) {
01318           continue;
01319         }
01320 
01321         KDateTime baseStart;
01322         if ( incidence->type() == "Event" ) {
01323           baseStart = e->dtStart();
01324         } else if ( incidence->type() == "Todo" ) {
01325           baseStart = t->dtDue();
01326         }
01327         if ( alarmStart.isValid() && from > alarmStart ) {
01328           alarmStart = from;   // don't look earlier than the earliest alarm
01329           baseStart = (-offset).end( (-endOffset).end( alarmStart ) );
01330         }
01331 
01332         // Adjust the 'alarmStart' date/time and find the next recurrence
01333         // at or after it. Treat the two offsets separately in case one
01334         // is daily and the other not.
01335         dt = incidence->recurrence()->getNextDateTime( baseStart.addSecs( -1 ) );
01336         if ( !dt.isValid() ||
01337              ( dt = endOffset.end( offset.end( dt ) ) ) > to ) // adjust 'dt' to get the alarm time
01338         {
01339           // The next recurrence is too late.
01340           if ( !a->repeatCount() ) {
01341             continue;
01342           }
01343 
01344           // The alarm has repetitions, so check whether repetitions of
01345           // previous recurrences fall within the time period.
01346           bool found = false;
01347           Duration alarmDuration = a->duration();
01348           for ( KDateTime base = baseStart;
01349                 ( dt = incidence->recurrence()->getPreviousDateTime( base ) ).isValid();
01350                 base = dt ) {
01351             if ( a->duration().end( dt ) < base ) {
01352               break;  // this recurrence's last repetition is too early, so give up
01353             }
01354 
01355             // The last repetition of this recurrence is at or after
01356             // 'alarmStart' time. Check if a repetition occurs between
01357             // 'alarmStart' and 'to'.
01358             int snooze = a->snoozeTime().value();   // in seconds or days
01359             if ( a->snoozeTime().isDaily() ) {
01360               Duration toFromDuration( dt, base );
01361               int toFrom = toFromDuration.asDays();
01362               if ( a->snoozeTime().end( from ) <= to ||
01363                    ( toFromDuration.isDaily() && toFrom % snooze == 0 ) ||
01364                    ( toFrom / snooze + 1 ) * snooze <= toFrom + period.asDays() ) {
01365                 found = true;
01366 #ifndef NDEBUG
01367                 // for debug output
01368                 dt = offset.end( dt ).addDays( ( ( toFrom - 1 ) / snooze + 1 ) * snooze );
01369 #endif
01370                 break;
01371               }
01372             } else {
01373               int toFrom = dt.secsTo( base );
01374               if ( period.asSeconds() >= snooze ||
01375                    toFrom % snooze == 0 ||
01376                    ( toFrom / snooze + 1 ) * snooze <= toFrom + period.asSeconds() )
01377               {
01378                 found = true;
01379 #ifndef NDEBUG
01380                 // for debug output
01381                 dt = offset.end( dt ).addSecs( ( ( toFrom - 1 ) / snooze + 1 ) * snooze );
01382 #endif
01383                 break;
01384               }
01385             }
01386           }
01387           if ( !found ) {
01388             continue;
01389           }
01390         }
01391       }
01392       kDebug() << incidence->summary() << "':" << dt.toString();
01393       alarms.append( a );
01394     }
01395   }
01396 }
01397 
01398 #include "calendar.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon May 14 2012 05:05:29 by doxygen 1.7.5 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KCal Library

Skip menu "KCal Library"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • 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