libkcal Library API Documentation

calendarlocal.cpp

00001 /*
00002     This file is part of libkcal.
00003 
00004     Copyright (c) 1998 Preston Brown
00005     Copyright (c) 2001,2003,2004 Cornelius Schumacher <schumacher@kde.org>
00006 
00007     This library is free software; you can redistribute it and/or
00008     modify it under the terms of the GNU Library General Public
00009     License as published by the Free Software Foundation; either
00010     version 2 of the License, or (at your option) any later version.
00011 
00012     This library is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015     Library General Public License for more details.
00016 
00017     You should have received a copy of the GNU Library General Public License
00018     along with this library; see the file COPYING.LIB.  If not, write to
00019     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00020     Boston, MA 02111-1307, USA.
00021 */
00022 
00023 #include <qdatetime.h>
00024 #include <qstring.h>
00025 #include <qptrlist.h>
00026 
00027 #include <kdebug.h>
00028 
00029 #include "vcaldrag.h"
00030 #include "vcalformat.h"
00031 #include "icalformat.h"
00032 #include "exceptions.h"
00033 #include "incidence.h"
00034 #include "journal.h"
00035 #include "filestorage.h"
00036 
00037 #include "calendarlocal.h"
00038 
00039 using namespace KCal;
00040 
00041 CalendarLocal::CalendarLocal()
00042   : Calendar(), mEvents( 47 )
00043 {
00044   init();
00045 }
00046 
00047 CalendarLocal::CalendarLocal( const QString &timeZoneId )
00048   : Calendar( timeZoneId ), mEvents( 47 )
00049 {
00050   init();
00051 }
00052 
00053 void CalendarLocal::init()
00054 {
00055   mDeletedIncidences.setAutoDelete( true );
00056 }
00057 
00058 
00059 CalendarLocal::~CalendarLocal()
00060 {
00061   close();
00062 }
00063 
00064 bool CalendarLocal::load( const QString &fileName )
00065 {
00066   FileStorage storage( this, fileName );
00067   return storage.load();
00068 }
00069 
00070 bool CalendarLocal::save( const QString &fileName, CalFormat *format )
00071 {
00072   FileStorage storage( this, fileName, format );
00073   return storage.save();
00074 }
00075 
00076 void CalendarLocal::close()
00077 {
00078   setObserversEnabled( false );
00079 
00080   deleteAllEvents();
00081   deleteAllTodos();
00082   deleteAllJournals();
00083 
00084   mDeletedIncidences.clear();
00085   setModified( false );
00086 
00087   setObserversEnabled( true );
00088 }
00089 
00090 
00091 bool CalendarLocal::addEvent( Event *event )
00092 {
00093   insertEvent( event );
00094 
00095   event->registerObserver( this );
00096 
00097   setModified( true );
00098 
00099   notifyIncidenceAdded( event );
00100 
00101   return true;
00102 }
00103 
00104 void CalendarLocal::deleteEvent( Event *event )
00105 {
00106   kdDebug(5800) << "CalendarLocal::deleteEvent" << endl;
00107 
00108   if ( mEvents.remove( event->uid() ) ) {
00109     setModified( true );
00110     notifyIncidenceDeleted( event );
00111     mDeletedIncidences.append( event );
00112   } else {
00113     kdWarning() << "CalendarLocal::deleteEvent(): Event not found." << endl;
00114   }
00115 }
00116 
00117 void CalendarLocal::deleteAllEvents()
00118 {
00119   // kdDebug(5800) << "CalendarLocal::deleteAllEvents" << endl;
00120   QDictIterator<Event> it( mEvents );
00121   while( it.current() ) {
00122     notifyIncidenceDeleted( it.current() );
00123     ++it;
00124   }
00125 
00126   mEvents.setAutoDelete( true );
00127   mEvents.clear();
00128   mEvents.setAutoDelete( false );
00129 }
00130 
00131 Event *CalendarLocal::event( const QString &uid )
00132 {
00133 //  kdDebug(5800) << "CalendarLocal::event(): " << uid << endl;
00134   return mEvents[ uid ];
00135 }
00136 
00137 bool CalendarLocal::addTodo( Todo *todo )
00138 {
00139   mTodoList.append( todo );
00140 
00141   todo->registerObserver( this );
00142 
00143   // Set up subtask relations
00144   setupRelations( todo );
00145 
00146   setModified( true );
00147 
00148   notifyIncidenceAdded( todo );
00149 
00150   return true;
00151 }
00152 
00153 void CalendarLocal::deleteTodo( Todo *todo )
00154 {
00155   // Handle orphaned children
00156   removeRelations( todo );
00157 
00158   if ( mTodoList.removeRef( todo ) ) {
00159     setModified( true );
00160     notifyIncidenceDeleted( todo );
00161     mDeletedIncidences.append( todo );
00162   }
00163 }
00164 
00165 void CalendarLocal::deleteAllTodos()
00166 {
00167   // kdDebug(5800) << "CalendarLocal::deleteAllTodos()\n";
00168   Todo::List::ConstIterator it;
00169   for( it = mTodoList.begin(); it != mTodoList.end(); ++it ) {
00170     notifyIncidenceDeleted( *it );
00171   }
00172 
00173   mTodoList.setAutoDelete( true );
00174   mTodoList.clear();
00175   mTodoList.setAutoDelete( false );
00176 }
00177 
00178 Todo::List CalendarLocal::rawTodos()
00179 {
00180   return mTodoList;
00181 }
00182 
00183 Todo *CalendarLocal::todo( const QString &uid )
00184 {
00185   Todo::List::ConstIterator it;
00186   for ( it = mTodoList.begin(); it != mTodoList.end(); ++it ) {
00187     if ( (*it)->uid() == uid ) return *it;
00188   }
00189 
00190   return 0;
00191 }
00192 
00193 Todo::List CalendarLocal::rawTodosForDate( const QDate &date )
00194 {
00195   Todo::List todos;
00196 
00197   Todo::List::ConstIterator it;
00198   for ( it = mTodoList.begin(); it != mTodoList.end(); ++it ) {
00199     Todo *todo = *it;
00200     if ( todo->hasDueDate() && todo->dtDue().date() == date ) {
00201       todos.append( todo );
00202     }
00203   }
00204 
00205   return todos;
00206 }
00207 
00208 Alarm::List CalendarLocal::alarmsTo( const QDateTime &to )
00209 {
00210   return alarms( QDateTime( QDate( 1900, 1, 1 ) ), to );
00211 }
00212 
00213 Alarm::List CalendarLocal::alarms( const QDateTime &from, const QDateTime &to )
00214 {
00215 //  kdDebug(5800) << "CalendarLocal::alarms(" << from.toString() << " - "
00216 //                << to.toString() << ")" << endl;
00217 
00218   Alarm::List alarms;
00219 
00220   EventDictIterator it( mEvents );
00221   for( ; it.current(); ++it ) {
00222     Event *e = *it;
00223     if ( e->doesRecur() ) appendRecurringAlarms( alarms, e, from, to );
00224     else appendAlarms( alarms, e, from, to );
00225   }
00226 
00227   Todo::List::ConstIterator it2;
00228   for( it2 = mTodoList.begin(); it2 != mTodoList.end(); ++it2 ) {
00229     if (! (*it2)->isCompleted() ) appendAlarms( alarms, *it2, from, to );
00230   }
00231 
00232   return alarms;
00233 }
00234 
00235 void CalendarLocal::appendAlarms( Alarm::List &alarms, Incidence *incidence,
00236                                   const QDateTime &from, const QDateTime &to )
00237 {
00238   Alarm::List::ConstIterator it;
00239   for( it = incidence->alarms().begin(); it != incidence->alarms().end();
00240        ++it ) {
00241 //    kdDebug(5800) << "CalendarLocal::appendAlarms() '" << alarm->text()
00242 //                  << "': " << alarm->time().toString() << " - " << alarm->enabled() << endl;
00243     if ( (*it)->enabled() ) {
00244       if ( (*it)->time() >= from && (*it)->time() <= to ) {
00245 //         kdDebug(5800) << "CalendarLocal::appendAlarms() '"
00246 //                       << incidence->summary() << "': "
00247 //                       << (*it)->time().toString() << endl;
00248         alarms.append( *it );
00249       }
00250     }
00251   }
00252 }
00253 
00254 void CalendarLocal::appendRecurringAlarms( Alarm::List &alarms,
00255                                            Incidence *incidence,
00256                                            const QDateTime &from,
00257                                            const QDateTime &to )
00258 {
00259   Alarm::List::ConstIterator it;
00260   QDateTime qdt;
00261   int  endOffset = 0;
00262   bool endOffsetValid = false;
00263   for( it = incidence->alarms().begin(); it != incidence->alarms().end();
00264        ++it ) {
00265     Alarm *alarm = *it;
00266     if ( alarm->hasTime() ) {
00267       // The alarm time is defined as an absolute date/time
00268       qdt = alarm->time();
00269     } else {
00270       // The alarm time is defined by an offset from the event start or end time.
00271       // Find the offset from the event start time, which is also used as the
00272       // offset from the recurrence time.
00273       int offset = 0;
00274       if ( alarm->hasStartOffset() ) {
00275         offset = alarm->startOffset().asSeconds();
00276       } else if ( alarm->hasEndOffset() ) {
00277         if ( !endOffsetValid ) {
00278           endOffset = incidence->dtStart().secsTo( incidence->dtEnd() );
00279           endOffsetValid = true;
00280         }
00281         offset = alarm->endOffset().asSeconds() + endOffset;
00282       }
00283       // Adjust the 'from' date/time and find the next recurrence at or after it
00284       qdt = incidence->recurrence()->getNextDateTime( from.addSecs(-offset - 1) );
00285       if (!qdt.isValid() || incidence->isException(qdt.date()) )
00286         continue;
00287       // Remove the adjustment to get the alarm time
00288       qdt = qdt.addSecs( offset );
00289     }
00290     kdDebug(5800) << "CalendarLocal::appendAlarms() '" << incidence->summary()
00291                   << "': " << qdt.toString() << " - " << (*it)->enabled()
00292                   << endl;
00293     if ( (*it)->enabled() ) {
00294 //      kdDebug(5800) << "CalendarLocal::appendAlarms() '" << incidence->summary()
00295 //                    << "': " << (*it)->time().toString() << endl;
00296       if ( qdt >= from && qdt <= to ) {
00297         alarms.append( *it );
00298       }
00299     }
00300   }
00301 }
00302 
00303 
00304 void CalendarLocal::incidenceUpdated( IncidenceBase *incidence )
00305 {
00306   incidence->setSyncStatusSilent( Event::SYNCMOD );
00307   incidence->setLastModified( QDateTime::currentDateTime() );
00308   // we should probably update the revision number here,
00309   // or internally in the Event itself when certain things change.
00310   // need to verify with ical documentation.
00311 
00312   // The static_cast is ok as the CalendarLocal only observes Incidence objects
00313   notifyIncidenceChanged( static_cast<Incidence *>( incidence ) );
00314 
00315   setModified( true );
00316 }
00317 
00318 void CalendarLocal::insertEvent( Event *event )
00319 {
00320   QString uid = event->uid();
00321   if ( mEvents[ uid ] == 0 ) {
00322     mEvents.insert( uid, event );
00323   }
00324 #ifndef NDEBUG
00325   else // if we already have an event with this UID, it has to be the same event,
00326       // otherwise something's really broken
00327       Q_ASSERT( mEvents[uid] == event );
00328 #endif
00329 }
00330 
00331 
00332 Event::List CalendarLocal::rawEventsForDate( const QDate &qd, bool sorted )
00333 {
00334   Event::List eventList;
00335 
00336   EventDictIterator it( mEvents );
00337   for( ; it.current(); ++it ) {
00338     Event *event = *it;
00339 
00340     if ( event->doesRecur() ) {
00341       if ( event->isMultiDay() ) {
00342         int extraDays = event->dtStart().date().daysTo( event->dtEnd().date() );
00343         int i;
00344         for ( i = 0; i <= extraDays; i++ ) {
00345           if ( event->recursOn( qd.addDays( -i ) ) ) {
00346             eventList.append( event );
00347             break;
00348           }
00349         }
00350       } else {
00351         if ( event->recursOn( qd ) )
00352           eventList.append( event );
00353       }
00354     } else {
00355       if ( event->dtStart().date() <= qd && event->dtEnd().date() >= qd ) {
00356         eventList.append( event );
00357       }
00358     }
00359   }
00360 
00361   if ( !sorted ) {
00362     return eventList;
00363   }
00364 
00365   //  kdDebug(5800) << "Sorting events for date\n" << endl;
00366   // now, we have to sort it based on dtStart.time()
00367   Event::List eventListSorted;
00368   Event::List::Iterator sortIt;
00369   Event::List::Iterator eit;
00370   for ( eit = eventList.begin(); eit != eventList.end(); ++eit ) {
00371     sortIt = eventListSorted.begin();
00372     while ( sortIt != eventListSorted.end() &&
00373             (*eit)->dtStart().time() >= (*sortIt)->dtStart().time() ) {
00374       ++sortIt;
00375     }
00376     eventListSorted.insert( sortIt, *eit );
00377   }
00378   return eventListSorted;
00379 }
00380 
00381 
00382 Event::List CalendarLocal::rawEvents( const QDate &start, const QDate &end,
00383                                           bool inclusive )
00384 {
00385   Event::List eventList;
00386 
00387   // Get non-recurring events
00388   EventDictIterator it( mEvents );
00389   for( ; it.current(); ++it ) {
00390     Event *event = *it;
00391     if ( event->doesRecur() ) {
00392       QDate rStart = event->dtStart().date();
00393       bool found = false;
00394       if ( inclusive ) {
00395         if ( rStart >= start && rStart <= end ) {
00396           // Start date of event is in range. Now check for end date.
00397           // if duration is negative, event recurs forever, so do not include it.
00398           if ( event->recurrence()->duration() == 0 ) {  // End date set
00399             QDate rEnd = event->recurrence()->endDate();
00400             if ( rEnd >= start && rEnd <= end ) {  // End date within range
00401               found = true;
00402             }
00403           } else if ( event->recurrence()->duration() > 0 ) {  // Duration set
00404             // TODO: Calculate end date from duration. Should be done in Event
00405             // For now exclude all events with a duration.
00406           }
00407         }
00408       } else {
00409         if ( rStart <= end ) {  // Start date not after range
00410           if ( rStart >= start ) {  // Start date within range
00411             found = true;
00412           } else if ( event->recurrence()->duration() == -1 ) {  // Recurs forever
00413             found = true;
00414           } else if ( event->recurrence()->duration() == 0 ) {  // End date set
00415             QDate rEnd = event->recurrence()->endDate();
00416             if ( rEnd >= start && rEnd <= end ) {  // End date within range
00417               found = true;
00418             }
00419           } else {  // Duration set
00420             // TODO: Calculate end date from duration. Should be done in Event
00421             // For now include all events with a duration.
00422             found = true;
00423           }
00424         }
00425       }
00426 
00427       if ( found ) eventList.append( event );
00428     } else {
00429       QDate s = event->dtStart().date();
00430       QDate e = event->dtEnd().date();
00431 
00432       if ( inclusive ) {
00433         if ( s >= start && e <= end ) {
00434           eventList.append( event );
00435         }
00436       } else {
00437         if ( ( s >= start && s <= end ) || ( e >= start && e <= end ) ) {
00438           eventList.append( event );
00439         }
00440       }
00441     }
00442   }
00443 
00444   return eventList;
00445 }
00446 
00447 Event::List CalendarLocal::rawEventsForDate( const QDateTime &qdt )
00448 {
00449   return rawEventsForDate( qdt.date() );
00450 }
00451 
00452 // This bool is only used by the regression testing program, to save in a stable order
00453 bool KCal_CalendarLocal_saveOrdered = false;
00454 
00455 Event::List CalendarLocal::rawEvents()
00456 {
00457   Event::List eventList;
00458   if ( !KCal_CalendarLocal_saveOrdered ) { // normal case: save in random order
00459     EventDictIterator it( mEvents );
00460     for( ; it.current(); ++it )
00461       eventList.append( *it );
00462   } else { // regression testing: save in sorted order
00463     Event::List::Iterator sortIt;
00464     EventDictIterator it( mEvents );
00465     for( ; it.current(); ++it ) {
00466       sortIt = eventList.begin();
00467       while ( sortIt != eventList.end() &&
00468               it.current()->dtStart().time() >= (*sortIt)->dtStart().time() ) {
00469         ++sortIt;
00470       }
00471       eventList.insert( sortIt, it.current() );
00472     }
00473   }
00474   return eventList;
00475 }
00476 
00477 bool CalendarLocal::addJournal(Journal *journal)
00478 {
00479   if (journal->dtStart().isValid())
00480     kdDebug(5800) << "Adding Journal on " << journal->dtStart().toString() << endl;
00481   else
00482     kdDebug(5800) << "Adding Journal without a DTSTART" << endl;
00483 
00484   mJournalList.append(journal);
00485 
00486   journal->registerObserver( this );
00487 
00488   setModified( true );
00489 
00490   notifyIncidenceAdded( journal );
00491 
00492   return true;
00493 }
00494 
00495 void CalendarLocal::deleteJournal( Journal *journal )
00496 {
00497   if ( mJournalList.removeRef( journal ) ) {
00498     setModified( true );
00499     notifyIncidenceDeleted( journal );
00500     mDeletedIncidences.append( journal );
00501   }
00502 }
00503 
00504 void CalendarLocal::deleteAllJournals()
00505 {
00506   Journal::List::ConstIterator it;
00507   for( it = mJournalList.begin(); it != mJournalList.end(); ++it ) {
00508     notifyIncidenceDeleted( *it );
00509   }
00510 
00511   mJournalList.setAutoDelete( true );
00512   mJournalList.clear();
00513   mJournalList.setAutoDelete( false );
00514 }
00515 
00516 Journal *CalendarLocal::journal( const QDate &date )
00517 {
00518 //  kdDebug(5800) << "CalendarLocal::journal() " << date.toString() << endl;
00519 
00520   Journal::List::ConstIterator it;
00521   for ( it = mJournalList.begin(); it != mJournalList.end(); ++it )
00522     if ( (*it)->dtStart().date() == date )
00523       return *it;
00524 
00525   return 0;
00526 }
00527 
00528 Journal *CalendarLocal::journal( const QString &uid )
00529 {
00530   Journal::List::ConstIterator it;
00531   for ( it = mJournalList.begin(); it != mJournalList.end(); ++it )
00532     if ( (*it)->uid() == uid )
00533       return *it;
00534 
00535   return 0;
00536 }
00537 
00538 Journal::List CalendarLocal::journals()
00539 {
00540   return mJournalList;
00541 }
00542 
KDE Logo
This file is part of the documentation for libkcal Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Aug 23 18:18:39 2007 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003