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

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
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.5.7
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