• Skip to content
  • Skip to link menu
KDE 4.0 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • Sitemap
  • Contact Us
 

KCal Library

calendarlocal.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) 2001,2003,2004 Cornelius Schumacher <schumacher@kde.org>
00006   Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
00007 
00008   This library is free software; you can redistribute it and/or
00009   modify it under the terms of the GNU Library General Public
00010   License as published by the Free Software Foundation; either
00011   version 2 of the License, or (at your option) any later version.
00012 
00013   This library is distributed in the hope that it will be useful,
00014   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016   Library General Public License for more details.
00017 
00018   You should have received a copy of the GNU Library General Public License
00019   along with this library; see the file COPYING.LIB.  If not, write to
00020   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00021   Boston, MA 02110-1301, USA.
00022 */
00035 #include "calendarlocal.h"
00036 
00037 #include "incidence.h"
00038 #include "event.h"
00039 #include "todo.h"
00040 #include "journal.h"
00041 #include "filestorage.h"
00042 #include <QtCore/QDate>
00043 #include <QtCore/QHash>
00044 #include <QtCore/QMultiHash>
00045 #include <QtCore/QString>
00046 
00047 #include <kdebug.h>
00048 #include <kdatetime.h>
00049 #include <klocale.h>
00050 #include <kmessagebox.h>
00051 
00052 using namespace KCal;
00053 
00058 //@cond PRIVATE
00059 class KCal::CalendarLocal::Private
00060 {
00061   public:
00062     Private()
00063     {
00064       mDeletedIncidences.setAutoDelete( true );
00065     }
00066     QString mFileName;                      // filename where calendar is stored
00067     CalFormat *mFormat;                     // calendar format
00068 
00069     QHash<QString, Event *> mEvents;        // hash on uids of all Events
00070     QMultiHash<QString, Event *> mEventsForDate; // on start dates of all non-recurring Events
00071     QHash<QString, Todo *> mTodos;          // hash on uids of all To-dos
00072     QMultiHash<QString, Todo*>mTodosForDate;// on due dates for all Todos
00073     QHash<QString, Journal *> mJournals;    // hash on uids of all Journals
00074     QMultiHash<QString, Journal *>mJournalsForDate; // on dates of all Journals
00075     Incidence::List mDeletedIncidences;     // list of all deleted Incidences
00076 
00077     void insertEvent( Event *event );
00078     void insertTodo( Todo *todo );
00079     void insertJournal( Journal *journal );
00080 };
00081 //@endcond
00082 
00083 CalendarLocal::CalendarLocal( const KDateTime::Spec &timeSpec )
00084   : Calendar( timeSpec ),
00085     d( new KCal::CalendarLocal::Private )
00086 {
00087 }
00088 
00089 CalendarLocal::CalendarLocal( const QString &timeZoneId )
00090   : Calendar( timeZoneId ),
00091     d( new KCal::CalendarLocal::Private )
00092 {
00093 }
00094 
00095 CalendarLocal::~CalendarLocal()
00096 {
00097   close();
00098   delete d;
00099 }
00100 
00101 bool CalendarLocal::load( const QString &fileName, CalFormat *format )
00102 {
00103   d->mFileName = fileName;
00104   FileStorage storage( this, fileName, format );
00105   return storage.load();
00106 }
00107 
00108 bool CalendarLocal::reload()
00109 {
00110   const QString filename = d->mFileName;
00111   save();
00112   close();
00113   d->mFileName = filename;
00114   FileStorage storage( this, d->mFileName );
00115   return storage.load();
00116 }
00117 
00118 bool CalendarLocal::save()
00119 {
00120   if ( d->mFileName.isEmpty() ) {
00121     return false;
00122   }
00123 
00124   if ( isModified() ) {
00125     FileStorage storage( this, d->mFileName, d->mFormat );
00126     return storage.save();
00127   } else {
00128     return true;
00129   }
00130 }
00131 
00132 bool CalendarLocal::save( const QString &fileName, CalFormat *format )
00133 {
00134   // Save only if the calendar is either modified, or saved to a
00135   // different file than it was loaded from
00136   if ( d->mFileName != fileName || isModified() ) {
00137     FileStorage storage( this, fileName, format );
00138     return storage.save();
00139   } else {
00140     return true;
00141   }
00142 }
00143 
00144 void CalendarLocal::close()
00145 {
00146   setObserversEnabled( false );
00147   d->mFileName.clear();
00148 
00149   deleteAllEvents();
00150   deleteAllTodos();
00151   deleteAllJournals();
00152 
00153   d->mDeletedIncidences.clear();
00154   setModified( false );
00155 
00156   setObserversEnabled( true );
00157 }
00158 
00159 bool CalendarLocal::addEvent( Event *event )
00160 {
00161   d->insertEvent( event );
00162 
00163   event->registerObserver( this );
00164 
00165   setModified( true );
00166 
00167   notifyIncidenceAdded( event );
00168 
00169   return true;
00170 }
00171 
00172 bool CalendarLocal::deleteEvent( Event *event )
00173 {
00174   QString uid = event->uid();
00175   if ( d->mEvents.remove( uid ) ) {
00176     setModified( true );
00177     notifyIncidenceDeleted( event );
00178     d->mDeletedIncidences.append( event );
00179     if ( !event->recurs() ) {
00180       d->mEventsForDate.remove( event->dtStart().date().toString(), event );
00181     }
00182     return true;
00183   } else {
00184     kWarning() << "CalendarLocal::deleteEvent(): Event not found.";
00185     return false;
00186   }
00187 }
00188 
00189 void CalendarLocal::deleteAllEvents()
00190 {
00191   QHashIterator<QString, Event *>i( d->mEvents );
00192   while ( i.hasNext() ) {
00193     i.next();
00194     notifyIncidenceDeleted( i.value() );
00195   }
00196   qDeleteAll( d->mEvents );
00197   d->mEvents.clear();
00198   d->mEventsForDate.clear();
00199 }
00200 
00201 Event *CalendarLocal::event( const QString &uid )
00202 {
00203   return d->mEvents.value( uid );
00204 }
00205 
00206 bool CalendarLocal::addTodo( Todo *todo )
00207 {
00208   d->insertTodo( todo );
00209 
00210   todo->registerObserver( this );
00211 
00212   // Set up sub-to-do relations
00213   setupRelations( todo );
00214 
00215   setModified( true );
00216 
00217   notifyIncidenceAdded( todo );
00218 
00219   return true;
00220 }
00221 
00222 //@cond PRIVATE
00223 void CalendarLocal::Private::insertTodo( Todo *todo )
00224 {
00225   QString uid = todo->uid();
00226   if ( mTodos.value( uid ) == 0 ) {
00227     mTodos.insert( uid, todo );
00228     if ( todo->hasDueDate() ) {
00229       mTodosForDate.insert( todo->dtDue().date().toString(), todo );
00230     }
00231 
00232   } else {
00233 #ifndef NDEBUG
00234     // if we already have an to-do with this UID, it must be the same to-do,
00235     // otherwise something's really broken
00236     Q_ASSERT( mTodos.value( uid ) == todo );
00237 #endif
00238   }
00239 }
00240 //@endcond
00241 
00242 bool CalendarLocal::deleteTodo( Todo *todo )
00243 {
00244   // Handle orphaned children
00245   removeRelations( todo );
00246 
00247   if ( d->mTodos.remove( todo->uid() ) ) {
00248     setModified( true );
00249     notifyIncidenceDeleted( todo );
00250     d->mDeletedIncidences.append( todo );
00251     if ( todo->hasDueDate() ) {
00252       d->mTodosForDate.remove( todo->dtDue().date().toString(), todo );
00253     }
00254     return true;
00255   } else {
00256     kWarning() << "CalendarLocal::deleteTodo(): Todo not found.";
00257     return false;
00258   }
00259 }
00260 
00261 void CalendarLocal::deleteAllTodos()
00262 {
00263   QHashIterator<QString, Todo *>i( d->mTodos );
00264   while ( i.hasNext() ) {
00265     i.next();
00266     notifyIncidenceDeleted( i.value() );
00267   }
00268   qDeleteAll( d->mTodos );
00269   d->mTodos.clear();
00270   d->mTodosForDate.clear();
00271 }
00272 
00273 Todo *CalendarLocal::todo( const QString &uid )
00274 {
00275   return d->mTodos.value( uid );
00276 }
00277 
00278 Todo::List CalendarLocal::rawTodos( TodoSortField sortField,
00279                                     SortDirection sortDirection )
00280 {
00281   Todo::List todoList;
00282   QHashIterator<QString, Todo *>i( d->mTodos );
00283   while ( i.hasNext() ) {
00284     i.next();
00285     todoList.append( i.value() );
00286   }
00287   return sortTodos( &todoList, sortField, sortDirection );
00288 }
00289 
00290 Todo::List CalendarLocal::rawTodosForDate( const QDate &date )
00291 {
00292   Todo::List todoList;
00293   Todo *t;
00294 
00295   QString dateStr = date.toString();
00296   QMultiHash<QString, Todo *>::iterator it = d->mTodosForDate.find( dateStr );
00297   while ( it != d->mTodosForDate.end() && it.key() == dateStr ) {
00298     t = it.value();
00299     todoList.append( t );
00300     ++it;
00301   }
00302   return todoList;
00303 }
00304 
00305 Alarm::List CalendarLocal::alarmsTo( const KDateTime &to )
00306 {
00307   return alarms( KDateTime( QDate( 1900, 1, 1 ) ), to );
00308 }
00309 
00310 Alarm::List CalendarLocal::alarms( const KDateTime &from, const KDateTime &to )
00311 {
00312   Alarm::List alarmList;
00313   QHashIterator<QString, Event *>ie( d->mEvents );
00314   Event *e;
00315   while ( ie.hasNext() ) {
00316     ie.next();
00317     e = ie.value();
00318     if ( e->recurs() ) {
00319       appendRecurringAlarms( alarmList, e, from, to );
00320     } else {
00321       appendAlarms( alarmList, e, from, to );
00322     }
00323   }
00324 
00325   QHashIterator<QString, Todo *>it( d->mTodos );
00326   Todo *t;
00327   while ( it.hasNext() ) {
00328     it.next();
00329     t = it.value();
00330     if (! t->isCompleted() ) {
00331       appendAlarms( alarmList, t, from, to );
00332     }
00333   }
00334 
00335   return alarmList;
00336 }
00337 
00338 //@cond PRIVATE
00339 void CalendarLocal::Private::insertEvent( Event *event )
00340 {
00341   QString uid = event->uid();
00342   if ( mEvents.value( uid ) == 0 ) {
00343     mEvents.insert( uid, event );
00344     if ( !event->recurs() ) {
00345       mEventsForDate.insert( event->dtStart().date().toString(), event );
00346     }
00347   } else {
00348 #ifdef NDEBUG
00349     // if we already have an event with this UID, it must be the same event,
00350     // otherwise something's really broken
00351     Q_ASSERT( mEvents.value( uid ) == event );
00352 #endif
00353   }
00354 }
00355 //@endcond
00356 
00357 void CalendarLocal::incidenceUpdated( IncidenceBase *incidence )
00358 {
00359   KDateTime nowUTC = KDateTime::currentUtcDateTime();
00360   incidence->setLastModified( nowUTC );
00361   // we should probably update the revision number here,
00362   // or internally in the Event itself when certain things change.
00363   // need to verify with ical documentation.
00364 
00365   // The static_cast is ok as the CalendarLocal only observes Incidence objects
00366   notifyIncidenceChanged( static_cast<Incidence *>( incidence ) );
00367 
00368   setModified( true );
00369 }
00370 
00371 Event::List CalendarLocal::rawEventsForDate( const QDate &date,
00372                                              const KDateTime::Spec &timespec,
00373                                              EventSortField sortField,
00374                                              SortDirection sortDirection )
00375 {
00376   Event::List eventList;
00377   Event *ev;
00378 
00379   // Find the hash for the specified date
00380   QString dateStr = date.toString();
00381   QMultiHash<QString, Event *>::iterator it = d->mEventsForDate.find( dateStr );
00382   // Iterate over all non-recurring events that start on this date
00383   KDateTime::Spec ts = timespec.isValid() ? timespec : timeSpec();
00384   KDateTime kdt( date, ts );
00385   while ( it != d->mEventsForDate.end() && it.key() == dateStr ) {
00386     ev = it.value();
00387     KDateTime end( ev->dtEnd().toTimeSpec( ev->dtStart() ) );
00388     if ( ev->allDay() ) {
00389       end.setDateOnly( true );
00390     } else {
00391       end = end.addSecs(-1);
00392     }
00393     if ( end >= kdt ) {
00394       eventList.append( ev );
00395     }
00396     ++it;
00397   }
00398 
00399   // Iterate over all events. Look for recurring events that occur on this date
00400   QHashIterator<QString, Event *>i( d->mEvents );
00401   while ( i.hasNext() ) {
00402     i.next();
00403     ev = i.value();
00404     if ( ev->recurs() ) {
00405       if ( ev->isMultiDay() ) {
00406         int extraDays = ev->dtStart().date().daysTo( ev->dtEnd().date() );
00407         int i;
00408         for ( i = 0; i <= extraDays; i++ ) {
00409           if ( ev->recursOn( date.addDays( -i ), ts ) ) {
00410             eventList.append( ev );
00411             break;
00412           }
00413         }
00414       } else {
00415         if ( ev->recursOn( date, ts ) ) {
00416           eventList.append( ev );
00417         }
00418       }
00419     }
00420   }
00421 
00422   return sortEvents( &eventList, sortField, sortDirection );
00423 }
00424 
00425 Event::List CalendarLocal::rawEvents( const QDate &start, const QDate &end,
00426                                       const KDateTime::Spec &timespec, bool inclusive )
00427 {
00428   Event::List eventList;
00429   KDateTime::Spec ts = timespec.isValid() ? timespec : timeSpec();
00430   KDateTime st( start, ts );
00431   KDateTime nd( end, ts );
00432   KDateTime yesterStart = st.addDays( -1 );
00433 
00434   // Get non-recurring events
00435   QHashIterator<QString, Event *>i( d->mEvents );
00436   Event *event;
00437   while ( i.hasNext() ) {
00438     i.next();
00439     event = i.value();
00440     KDateTime rStart = event->dtStart();
00441     if ( nd < rStart ) {
00442       continue;
00443     }
00444     if ( inclusive && rStart < st ) {
00445       continue;
00446     }
00447 
00448     if ( !event->recurs() ) { // non-recurring events
00449       KDateTime rEnd = event->dtEnd();
00450       if ( rEnd < st ) {
00451         continue;
00452       }
00453       if ( inclusive && nd < rEnd ) {
00454         continue;
00455       }
00456     } else { // recurring events
00457       switch( event->recurrence()->duration() ) {
00458       case -1: // infinite
00459         if ( inclusive ) {
00460           continue;
00461         }
00462         break;
00463       case 0: // end date given
00464       default: // count given
00465         KDateTime rEnd( event->recurrence()->endDate(), ts );
00466         if ( !rEnd.isValid() ) {
00467           continue;
00468         }
00469         if ( rEnd < st ) {
00470           continue;
00471         }
00472         if ( inclusive && nd < rEnd ) {
00473           continue;
00474         }
00475         break;
00476       } // switch(duration)
00477     } //if(recurs)
00478 
00479     eventList.append( event );
00480   }
00481 
00482   return eventList;
00483 }
00484 
00485 Event::List CalendarLocal::rawEventsForDate( const KDateTime &kdt )
00486 {
00487   return rawEventsForDate( kdt.date(), kdt.timeSpec() );
00488 }
00489 
00490 Event::List CalendarLocal::rawEvents( EventSortField sortField,
00491                                       SortDirection sortDirection )
00492 {
00493   Event::List eventList;
00494   QHashIterator<QString, Event *>i( d->mEvents );
00495   while ( i.hasNext() ) {
00496     i.next();
00497     eventList.append( i.value() );
00498   }
00499   return sortEvents( &eventList, sortField, sortDirection );
00500 }
00501 
00502 bool CalendarLocal::addJournal( Journal *journal )
00503 {
00504   d->insertJournal( journal );
00505 
00506   journal->registerObserver( this );
00507 
00508   setModified( true );
00509 
00510   notifyIncidenceAdded( journal );
00511 
00512   return true;
00513 }
00514 
00515 //@cond PRIVATE
00516 void CalendarLocal::Private::insertJournal( Journal *journal )
00517 {
00518   QString uid = journal->uid();
00519   if ( mJournals.value( uid ) == 0 ) {
00520     mJournals.insert( uid, journal );
00521     mJournalsForDate.insert( journal->dtStart().date().toString(), journal );
00522   } else {
00523 #ifndef NDEBUG
00524     // if we already have an journal with this UID, it must be the same journal,
00525     // otherwise something's really broken
00526     Q_ASSERT( mJournals.value( uid ) == journal );
00527 #endif
00528   }
00529 }
00530 //@endcond
00531 
00532 bool CalendarLocal::deleteJournal( Journal *journal )
00533 {
00534   if ( d->mJournals.remove( journal->uid() ) ) {
00535     setModified( true );
00536     notifyIncidenceDeleted( journal );
00537     d->mDeletedIncidences.append( journal );
00538     d->mJournalsForDate.remove( journal->dtStart().date().toString(), journal );
00539     return true;
00540   } else {
00541     kWarning() << "CalendarLocal::deleteJournal(): Journal not found.";
00542     return false;
00543   }
00544 }
00545 
00546 void CalendarLocal::deleteAllJournals()
00547 {
00548   QHashIterator<QString, Journal *>i( d->mJournals );
00549   while ( i.hasNext() ) {
00550     i.next();
00551     notifyIncidenceDeleted( i.value() );
00552   }
00553   qDeleteAll( d->mJournals );
00554   d->mJournals.clear();
00555   d->mJournalsForDate.clear();
00556 }
00557 
00558 Journal *CalendarLocal::journal( const QString &uid )
00559 {
00560   return d->mJournals.value( uid );
00561 }
00562 
00563 Journal::List CalendarLocal::rawJournals( JournalSortField sortField,
00564                                           SortDirection sortDirection )
00565 {
00566   Journal::List journalList;
00567   QHashIterator<QString, Journal *>i( d->mJournals );
00568   while ( i.hasNext() ) {
00569     i.next();
00570     journalList.append( i.value() );
00571   }
00572   return sortJournals( &journalList, sortField, sortDirection );
00573 }
00574 
00575 Journal::List CalendarLocal::rawJournalsForDate( const QDate &date )
00576 {
00577   Journal::List journalList;
00578   Journal *j;
00579 
00580   QString dateStr = date.toString();
00581   QMultiHash<QString, Journal *>::iterator it = d->mJournalsForDate.find( dateStr );
00582 
00583   while ( it != d->mJournalsForDate.end() && it.key() == dateStr ) {
00584     j = it.value();
00585     journalList.append( j );
00586     ++it;
00587   }
00588   return journalList;
00589 }

KCal Library

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

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • kabc
  • kblog
  • kcal
  • kimap
  • kioslave
  •   imap4
  •   mbox
  • kldap
  • kmime
  • kpimidentities
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.5.5
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal