• Skip to content
  • Skip to link menu
KDE 4.1 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 
00082 // helper
00083 namespace {
00084 template <typename T>
00085 void removeIncidenceFromMultiHashByUID( QMultiHash< QString, T >& container,
00086                                         const QString& key,
00087                                         const QString& uid )
00088 {
00089   const QList<T> values = container.values( key );
00090   QListIterator<T> it(values);
00091   while ( it.hasNext() ) {
00092     T const inc = it.next();
00093     if ( inc->uid() == uid )
00094       container.remove( key, inc );
00095   }
00096 }
00097 }
00098 //@endcond
00099 
00100 CalendarLocal::CalendarLocal( const KDateTime::Spec &timeSpec )
00101   : Calendar( timeSpec ),
00102     d( new KCal::CalendarLocal::Private )
00103 {
00104 }
00105 
00106 CalendarLocal::CalendarLocal( const QString &timeZoneId )
00107   : Calendar( timeZoneId ),
00108     d( new KCal::CalendarLocal::Private )
00109 {
00110 }
00111 
00112 CalendarLocal::~CalendarLocal()
00113 {
00114   close();
00115   delete d;
00116 }
00117 
00118 bool CalendarLocal::load( const QString &fileName, CalFormat *format )
00119 {
00120   d->mFileName = fileName;
00121   FileStorage storage( this, fileName, format );
00122   return storage.load();
00123 }
00124 
00125 bool CalendarLocal::reload()
00126 {
00127   const QString filename = d->mFileName;
00128   save();
00129   close();
00130   d->mFileName = filename;
00131   FileStorage storage( this, d->mFileName );
00132   return storage.load();
00133 }
00134 
00135 bool CalendarLocal::save()
00136 {
00137   if ( d->mFileName.isEmpty() ) {
00138     return false;
00139   }
00140 
00141   if ( isModified() ) {
00142     FileStorage storage( this, d->mFileName, d->mFormat );
00143     return storage.save();
00144   } else {
00145     return true;
00146   }
00147 }
00148 
00149 bool CalendarLocal::save( const QString &fileName, CalFormat *format )
00150 {
00151   // Save only if the calendar is either modified, or saved to a
00152   // different file than it was loaded from
00153   if ( d->mFileName != fileName || isModified() ) {
00154     FileStorage storage( this, fileName, format );
00155     return storage.save();
00156   } else {
00157     return true;
00158   }
00159 }
00160 
00161 void CalendarLocal::close()
00162 {
00163   setObserversEnabled( false );
00164   d->mFileName.clear();
00165 
00166   deleteAllEvents();
00167   deleteAllTodos();
00168   deleteAllJournals();
00169 
00170   d->mDeletedIncidences.clearAll();
00171   setModified( false );
00172 
00173   setObserversEnabled( true );
00174 }
00175 
00176 bool CalendarLocal::addEvent( Event *event )
00177 {
00178   d->insertEvent( event );
00179 
00180   event->registerObserver( this );
00181 
00182   setModified( true );
00183 
00184   notifyIncidenceAdded( event );
00185 
00186   return true;
00187 }
00188 
00189 bool CalendarLocal::deleteEvent( Event *event )
00190 {
00191   const QString uid = event->uid();
00192   if ( d->mEvents.remove( uid ) ) {
00193     setModified( true );
00194     notifyIncidenceDeleted( event );
00195     d->mDeletedIncidences.append( event );
00196     if ( !event->recurs() ) {
00197       removeIncidenceFromMultiHashByUID<Event*>( d->mEventsForDate, event->dtStart().date().toString(), event->uid() );
00198     }
00199     return true;
00200   } else {
00201     kWarning() << "CalendarLocal::deleteEvent(): Event not found.";
00202     return false;
00203   }
00204 }
00205 
00206 void CalendarLocal::deleteAllEvents()
00207 {
00208   QHashIterator<QString, Event *>i( d->mEvents );
00209   while ( i.hasNext() ) {
00210     i.next();
00211     notifyIncidenceDeleted( i.value() );
00212   }
00213   qDeleteAll( d->mEvents );
00214   d->mEvents.clear();
00215   d->mEventsForDate.clear();
00216 }
00217 
00218 Event *CalendarLocal::event( const QString &uid )
00219 {
00220   return d->mEvents.value( uid );
00221 }
00222 
00223 bool CalendarLocal::addTodo( Todo *todo )
00224 {
00225   d->insertTodo( todo );
00226 
00227   todo->registerObserver( this );
00228 
00229   // Set up sub-to-do relations
00230   setupRelations( todo );
00231 
00232   setModified( true );
00233 
00234   notifyIncidenceAdded( todo );
00235 
00236   return true;
00237 }
00238 
00239 //@cond PRIVATE
00240 void CalendarLocal::Private::insertTodo( Todo *todo )
00241 {
00242   QString uid = todo->uid();
00243   if ( !mTodos.contains( uid ) ) {
00244     mTodos.insert( uid, todo );
00245     if ( todo->hasDueDate() ) {
00246       mTodosForDate.insert( todo->dtDue().date().toString(), todo );
00247     }
00248 
00249   } else {
00250 #ifndef NDEBUG
00251     // if we already have an to-do with this UID, it must be the same to-do,
00252     // otherwise something's really broken
00253     Q_ASSERT( mTodos.value( uid ) == todo );
00254 #endif
00255   }
00256 }
00257 //@endcond
00258 
00259 bool CalendarLocal::deleteTodo( Todo *todo )
00260 {
00261   // Handle orphaned children
00262   removeRelations( todo );
00263 
00264   if ( d->mTodos.remove( todo->uid() ) ) {
00265     setModified( true );
00266     notifyIncidenceDeleted( todo );
00267     d->mDeletedIncidences.append( todo );
00268     if ( todo->hasDueDate() ) {
00269       removeIncidenceFromMultiHashByUID( d->mTodosForDate, todo->dtDue().date().toString(), todo->uid() );
00270     }
00271     return true;
00272   } else {
00273     kWarning() << "CalendarLocal::deleteTodo(): Todo not found.";
00274     return false;
00275   }
00276 }
00277 
00278 void CalendarLocal::deleteAllTodos()
00279 {
00280   QHashIterator<QString, Todo *>i( d->mTodos );
00281   while ( i.hasNext() ) {
00282     i.next();
00283     notifyIncidenceDeleted( i.value() );
00284   }
00285   qDeleteAll( d->mTodos );
00286   d->mTodos.clear();
00287   d->mTodosForDate.clear();
00288 }
00289 
00290 Todo *CalendarLocal::todo( const QString &uid )
00291 {
00292   return d->mTodos.value( uid );
00293 }
00294 
00295 Todo::List CalendarLocal::rawTodos( TodoSortField sortField,
00296                                     SortDirection sortDirection )
00297 {
00298   Todo::List todoList;
00299   QHashIterator<QString, Todo *>i( d->mTodos );
00300   while ( i.hasNext() ) {
00301     i.next();
00302     todoList.append( i.value() );
00303   }
00304   return sortTodos( &todoList, sortField, sortDirection );
00305 }
00306 
00307 Todo::List CalendarLocal::rawTodosForDate( const QDate &date )
00308 {
00309   Todo::List todoList;
00310   Todo *t;
00311 
00312   QString dateStr = date.toString();
00313   QMultiHash<QString, Todo *>::iterator it = d->mTodosForDate.find( dateStr );
00314   while ( it != d->mTodosForDate.end() && it.key() == dateStr ) {
00315     t = it.value();
00316     todoList.append( t );
00317     ++it;
00318   }
00319   return todoList;
00320 }
00321 
00322 Alarm::List CalendarLocal::alarmsTo( const KDateTime &to )
00323 {
00324   return alarms( KDateTime( QDate( 1900, 1, 1 ) ), to );
00325 }
00326 
00327 Alarm::List CalendarLocal::alarms( const KDateTime &from, const KDateTime &to )
00328 {
00329   Alarm::List alarmList;
00330   QHashIterator<QString, Event *>ie( d->mEvents );
00331   Event *e;
00332   while ( ie.hasNext() ) {
00333     ie.next();
00334     e = ie.value();
00335     if ( e->recurs() ) {
00336       appendRecurringAlarms( alarmList, e, from, to );
00337     } else {
00338       appendAlarms( alarmList, e, from, to );
00339     }
00340   }
00341 
00342   QHashIterator<QString, Todo *>it( d->mTodos );
00343   Todo *t;
00344   while ( it.hasNext() ) {
00345     it.next();
00346     t = it.value();
00347     if (! t->isCompleted() ) {
00348       appendAlarms( alarmList, t, from, to );
00349     }
00350   }
00351 
00352   return alarmList;
00353 }
00354 
00355 //@cond PRIVATE
00356 void CalendarLocal::Private::insertEvent( Event *event )
00357 {
00358   QString uid = event->uid();
00359   if ( !mEvents.contains( uid ) ) {
00360     mEvents.insert( uid, event );
00361     if ( !event->recurs() ) {
00362       mEventsForDate.insert( event->dtStart().date().toString(), event );
00363     }
00364   } else {
00365 #ifdef NDEBUG
00366     // if we already have an event with this UID, it must be the same event,
00367     // otherwise something's really broken
00368     Q_ASSERT( mEvents.value( uid ) == event );
00369 #endif
00370   }
00371 }
00372 //@endcond
00373 
00374 void CalendarLocal::incidenceUpdated( IncidenceBase *incidence )
00375 {
00376   KDateTime nowUTC = KDateTime::currentUtcDateTime();
00377   incidence->setLastModified( nowUTC );
00378   // we should probably update the revision number here,
00379   // or internally in the Event itself when certain things change.
00380   // need to verify with ical documentation.
00381 
00382   // The static_cast is ok as the CalendarLocal only observes Incidence objects
00383   notifyIncidenceChanged( static_cast<Incidence *>( incidence ) );
00384 
00385   setModified( true );
00386 }
00387 
00388 Event::List CalendarLocal::rawEventsForDate( const QDate &date,
00389                                              const KDateTime::Spec &timespec,
00390                                              EventSortField sortField,
00391                                              SortDirection sortDirection )
00392 {
00393   Event::List eventList;
00394   Event *ev;
00395 
00396   // Find the hash for the specified date
00397   QString dateStr = date.toString();
00398   QMultiHash<QString, Event *>::iterator it = d->mEventsForDate.find( dateStr );
00399   // Iterate over all non-recurring events that start on this date
00400   KDateTime::Spec ts = timespec.isValid() ? timespec : timeSpec();
00401   KDateTime kdt( date, ts );
00402   while ( it != d->mEventsForDate.end() && it.key() == dateStr ) {
00403     ev = it.value();
00404     KDateTime end( ev->dtEnd().toTimeSpec( ev->dtStart() ) );
00405     if ( ev->allDay() ) {
00406       end.setDateOnly( true );
00407     } else {
00408       end = end.addSecs(-1);
00409     }
00410     if ( end >= kdt ) {
00411       eventList.append( ev );
00412     }
00413     ++it;
00414   }
00415 
00416   // Iterate over all events. Look for recurring events that occur on this date
00417   QHashIterator<QString, Event *>i( d->mEvents );
00418   while ( i.hasNext() ) {
00419     i.next();
00420     ev = i.value();
00421     if ( ev->recurs() ) {
00422       if ( ev->isMultiDay() ) {
00423         int extraDays = ev->dtStart().date().daysTo( ev->dtEnd().date() );
00424         int i;
00425         for ( i = 0; i <= extraDays; i++ ) {
00426           if ( ev->recursOn( date.addDays( -i ), ts ) ) {
00427             eventList.append( ev );
00428             break;
00429           }
00430         }
00431       } else {
00432         if ( ev->recursOn( date, ts ) ) {
00433           eventList.append( ev );
00434         }
00435       }
00436     }
00437   }
00438 
00439   return sortEvents( &eventList, sortField, sortDirection );
00440 }
00441 
00442 Event::List CalendarLocal::rawEvents( const QDate &start, const QDate &end,
00443                                       const KDateTime::Spec &timespec, bool inclusive )
00444 {
00445   Event::List eventList;
00446   KDateTime::Spec ts = timespec.isValid() ? timespec : timeSpec();
00447   KDateTime st( start, ts );
00448   KDateTime nd( end, ts );
00449   KDateTime yesterStart = st.addDays( -1 );
00450 
00451   // Get non-recurring events
00452   QHashIterator<QString, Event *>i( d->mEvents );
00453   Event *event;
00454   while ( i.hasNext() ) {
00455     i.next();
00456     event = i.value();
00457     KDateTime rStart = event->dtStart();
00458     if ( nd < rStart ) {
00459       continue;
00460     }
00461     if ( inclusive && rStart < st ) {
00462       continue;
00463     }
00464 
00465     if ( !event->recurs() ) { // non-recurring events
00466       KDateTime rEnd = event->dtEnd();
00467       if ( rEnd < st ) {
00468         continue;
00469       }
00470       if ( inclusive && nd < rEnd ) {
00471         continue;
00472       }
00473     } else { // recurring events
00474       switch( event->recurrence()->duration() ) {
00475       case -1: // infinite
00476         if ( inclusive ) {
00477           continue;
00478         }
00479         break;
00480       case 0: // end date given
00481       default: // count given
00482         KDateTime rEnd( event->recurrence()->endDate(), ts );
00483         if ( !rEnd.isValid() ) {
00484           continue;
00485         }
00486         if ( rEnd < st ) {
00487           continue;
00488         }
00489         if ( inclusive && nd < rEnd ) {
00490           continue;
00491         }
00492         break;
00493       } // switch(duration)
00494     } //if(recurs)
00495 
00496     eventList.append( event );
00497   }
00498 
00499   return eventList;
00500 }
00501 
00502 Event::List CalendarLocal::rawEventsForDate( const KDateTime &kdt )
00503 {
00504   return rawEventsForDate( kdt.date(), kdt.timeSpec() );
00505 }
00506 
00507 Event::List CalendarLocal::rawEvents( EventSortField sortField,
00508                                       SortDirection sortDirection )
00509 {
00510   Event::List eventList;
00511   QHashIterator<QString, Event *>i( d->mEvents );
00512   while ( i.hasNext() ) {
00513     i.next();
00514     eventList.append( i.value() );
00515   }
00516   return sortEvents( &eventList, sortField, sortDirection );
00517 }
00518 
00519 bool CalendarLocal::addJournal( Journal *journal )
00520 {
00521   d->insertJournal( journal );
00522 
00523   journal->registerObserver( this );
00524 
00525   setModified( true );
00526 
00527   notifyIncidenceAdded( journal );
00528 
00529   return true;
00530 }
00531 
00532 //@cond PRIVATE
00533 void CalendarLocal::Private::insertJournal( Journal *journal )
00534 {
00535   QString uid = journal->uid();
00536   if ( !mJournals.contains( uid ) ) {
00537     mJournals.insert( uid, journal );
00538     mJournalsForDate.insert( journal->dtStart().date().toString(), journal );
00539   } else {
00540 #ifndef NDEBUG
00541     // if we already have an journal with this UID, it must be the same journal,
00542     // otherwise something's really broken
00543     Q_ASSERT( mJournals.value( uid ) == journal );
00544 #endif
00545   }
00546 }
00547 //@endcond
00548 
00549 bool CalendarLocal::deleteJournal( Journal *journal )
00550 {
00551   if ( d->mJournals.remove( journal->uid() ) ) {
00552     setModified( true );
00553     notifyIncidenceDeleted( journal );
00554     d->mDeletedIncidences.append( journal );
00555     removeIncidenceFromMultiHashByUID<Journal*>( d->mJournalsForDate, journal->dtStart().date().toString(), journal->uid() );
00556     return true;
00557   } else {
00558     kWarning() << "CalendarLocal::deleteJournal(): Journal not found.";
00559     return false;
00560   }
00561 }
00562 
00563 void CalendarLocal::deleteAllJournals()
00564 {
00565   QHashIterator<QString, Journal *>i( d->mJournals );
00566   while ( i.hasNext() ) {
00567     i.next();
00568     notifyIncidenceDeleted( i.value() );
00569   }
00570   qDeleteAll( d->mJournals );
00571   d->mJournals.clear();
00572   d->mJournalsForDate.clear();
00573 }
00574 
00575 Journal *CalendarLocal::journal( const QString &uid )
00576 {
00577   return d->mJournals.value( uid );
00578 }
00579 
00580 Journal::List CalendarLocal::rawJournals( JournalSortField sortField,
00581                                           SortDirection sortDirection )
00582 {
00583   Journal::List journalList;
00584   QHashIterator<QString, Journal *>i( d->mJournals );
00585   while ( i.hasNext() ) {
00586     i.next();
00587     journalList.append( i.value() );
00588   }
00589   return sortJournals( &journalList, sortField, sortDirection );
00590 }
00591 
00592 Journal::List CalendarLocal::rawJournalsForDate( const QDate &date )
00593 {
00594   Journal::List journalList;
00595   Journal *j;
00596 
00597   QString dateStr = date.toString();
00598   QMultiHash<QString, Journal *>::iterator it = d->mJournalsForDate.find( dateStr );
00599 
00600   while ( it != d->mJournalsForDate.end() && it.key() == dateStr ) {
00601     j = it.value();
00602     journalList.append( j );
00603     ++it;
00604   }
00605   return journalList;
00606 }

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"
  • akonadi
  • 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.6
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