• 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 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   }
00215   qDeleteAll( d->mEvents );
00216   d->mEvents.clear();
00217   d->mEventsForDate.clear();
00218 }
00219 
00220 Event *CalendarLocal::event( const QString &uid )
00221 {
00222   return d->mEvents.value( uid );
00223 }
00224 
00225 bool CalendarLocal::addTodo( Todo *todo )
00226 {
00227   d->insertTodo( todo );
00228 
00229   todo->registerObserver( this );
00230 
00231   // Set up sub-to-do relations
00232   setupRelations( todo );
00233 
00234   setModified( true );
00235 
00236   notifyIncidenceAdded( todo );
00237 
00238   return true;
00239 }
00240 
00241 //@cond PRIVATE
00242 void CalendarLocal::Private::insertTodo( Todo *todo )
00243 {
00244   QString uid = todo->uid();
00245   if ( !mTodos.contains( uid ) ) {
00246     mTodos.insert( uid, todo );
00247     if ( todo->hasDueDate() ) {
00248       mTodosForDate.insert( todo->dtDue().date().toString(), todo );
00249     }
00250 
00251   } else {
00252 #ifndef NDEBUG
00253     // if we already have an to-do with this UID, it must be the same to-do,
00254     // otherwise something's really broken
00255     Q_ASSERT( mTodos.value( uid ) == todo );
00256 #endif
00257   }
00258 }
00259 //@endcond
00260 
00261 bool CalendarLocal::deleteTodo( Todo *todo )
00262 {
00263   // Handle orphaned children
00264   removeRelations( todo );
00265 
00266   if ( d->mTodos.remove( todo->uid() ) ) {
00267     setModified( true );
00268     notifyIncidenceDeleted( todo );
00269     d->mDeletedIncidences.append( todo );
00270     if ( todo->hasDueDate() ) {
00271       removeIncidenceFromMultiHashByUID<Todo *>(
00272         d->mTodosForDate, todo->dtDue().date().toString(), todo->uid() );
00273     }
00274     return true;
00275   } else {
00276     kWarning() << "CalendarLocal::deleteTodo(): Todo not found.";
00277     return false;
00278   }
00279 }
00280 
00281 void CalendarLocal::deleteAllTodos()
00282 {
00283   QHashIterator<QString, Todo *>i( d->mTodos );
00284   while ( i.hasNext() ) {
00285     i.next();
00286     notifyIncidenceDeleted( i.value() );
00287   }
00288   qDeleteAll( d->mTodos );
00289   d->mTodos.clear();
00290   d->mTodosForDate.clear();
00291 }
00292 
00293 Todo *CalendarLocal::todo( const QString &uid )
00294 {
00295   return d->mTodos.value( uid );
00296 }
00297 
00298 Todo::List CalendarLocal::rawTodos( TodoSortField sortField,
00299                                     SortDirection sortDirection )
00300 {
00301   Todo::List todoList;
00302   QHashIterator<QString, Todo *>i( d->mTodos );
00303   while ( i.hasNext() ) {
00304     i.next();
00305     todoList.append( i.value() );
00306   }
00307   return sortTodos( &todoList, sortField, sortDirection );
00308 }
00309 
00310 Todo::List CalendarLocal::rawTodosForDate( const QDate &date )
00311 {
00312   Todo::List todoList;
00313   Todo *t;
00314 
00315   QString dateStr = date.toString();
00316   QMultiHash<QString, Todo *>::iterator it = d->mTodosForDate.find( dateStr );
00317   while ( it != d->mTodosForDate.end() && it.key() == dateStr ) {
00318     t = it.value();
00319     todoList.append( t );
00320     ++it;
00321   }
00322   return todoList;
00323 }
00324 
00325 Alarm::List CalendarLocal::alarmsTo( const KDateTime &to )
00326 {
00327   return alarms( KDateTime( QDate( 1900, 1, 1 ) ), to );
00328 }
00329 
00330 Alarm::List CalendarLocal::alarms( const KDateTime &from, const KDateTime &to )
00331 {
00332   Alarm::List alarmList;
00333   QHashIterator<QString, Event *>ie( d->mEvents );
00334   Event *e;
00335   while ( ie.hasNext() ) {
00336     ie.next();
00337     e = ie.value();
00338     if ( e->recurs() ) {
00339       appendRecurringAlarms( alarmList, e, from, to );
00340     } else {
00341       appendAlarms( alarmList, e, from, to );
00342     }
00343   }
00344 
00345   QHashIterator<QString, Todo *>it( d->mTodos );
00346   Todo *t;
00347   while ( it.hasNext() ) {
00348     it.next();
00349     t = it.value();
00350     if (! t->isCompleted() ) {
00351       appendAlarms( alarmList, t, from, to );
00352     }
00353   }
00354 
00355   return alarmList;
00356 }
00357 
00358 //@cond PRIVATE
00359 void CalendarLocal::Private::insertEvent( Event *event )
00360 {
00361   QString uid = event->uid();
00362   if ( !mEvents.contains( uid ) ) {
00363     mEvents.insert( uid, event );
00364     if ( !event->recurs() && !event->isMultiDay() ) {
00365       mEventsForDate.insert( event->dtStart().date().toString(), event );
00366     }
00367   } else {
00368 #ifdef NDEBUG
00369     // if we already have an event with this UID, it must be the same event,
00370     // otherwise something's really broken
00371     Q_ASSERT( mEvents.value( uid ) == event );
00372 #endif
00373   }
00374 }
00375 //@endcond
00376 
00377 void CalendarLocal::incidenceUpdated( IncidenceBase *incidence )
00378 {
00379   KDateTime nowUTC = KDateTime::currentUtcDateTime();
00380   incidence->setLastModified( nowUTC );
00381   // we should probably update the revision number here,
00382   // or internally in the Event itself when certain things change.
00383   // need to verify with ical documentation.
00384 
00385   // The static_cast is ok as the CalendarLocal only observes Incidence objects
00386   notifyIncidenceChanged( static_cast<Incidence *>( incidence ) );
00387 
00388   setModified( true );
00389 }
00390 
00391 Event::List CalendarLocal::rawEventsForDate( const QDate &date,
00392                                              const KDateTime::Spec &timespec,
00393                                              EventSortField sortField,
00394                                              SortDirection sortDirection )
00395 {
00396   Event::List eventList;
00397   Event *ev;
00398 
00399   // Find the hash for the specified date
00400   QString dateStr = date.toString();
00401   QMultiHash<QString, Event *>::iterator it = d->mEventsForDate.find( dateStr );
00402   // Iterate over all non-recurring, single-day events that start on this date
00403   KDateTime::Spec ts = timespec.isValid() ? timespec : timeSpec();
00404   KDateTime kdt( date, ts );
00405   while ( it != d->mEventsForDate.end() && it.key() == dateStr ) {
00406     ev = it.value();
00407     KDateTime end( ev->dtEnd().toTimeSpec( ev->dtStart() ) );
00408     if ( ev->allDay() ) {
00409       end.setDateOnly( true );
00410     } else {
00411       end = end.addSecs( -1 );
00412     }
00413     if ( end >= kdt ) {
00414       eventList.append( ev );
00415     }
00416     ++it;
00417   }
00418 
00419   // Iterate over all events. Look for recurring events that occur on this date
00420   QHashIterator<QString, Event *>i( d->mEvents );
00421   while ( i.hasNext() ) {
00422     i.next();
00423     ev = i.value();
00424     if ( ev->recurs() ) {
00425       if ( ev->isMultiDay() ) {
00426         int extraDays = ev->dtStart().date().daysTo( ev->dtEnd().date() );
00427         for ( int i = 0; i <= extraDays; i++ ) {
00428           if ( ev->recursOn( date.addDays( -i ), ts ) ) {
00429             eventList.append( ev );
00430             break;
00431           }
00432         }
00433       } else {
00434         if ( ev->recursOn( date, ts ) ) {
00435           eventList.append( ev );
00436         }
00437       }
00438     } else {
00439       if ( ev->isMultiDay() ) {
00440         if ( ev->dtStart().date() <= date && ev->dtEnd().date() >= date ) {
00441           eventList.append( ev );
00442         }
00443       }
00444     }
00445   }
00446 
00447   return sortEvents( &eventList, sortField, sortDirection );
00448 }
00449 
00450 Event::List CalendarLocal::rawEvents( const QDate &start, const QDate &end,
00451                                       const KDateTime::Spec &timespec, bool inclusive )
00452 {
00453   Event::List eventList;
00454   KDateTime::Spec ts = timespec.isValid() ? timespec : timeSpec();
00455   KDateTime st( start, ts );
00456   KDateTime nd( end, ts );
00457   KDateTime yesterStart = st.addDays( -1 );
00458 
00459   // Get non-recurring events
00460   QHashIterator<QString, Event *>i( d->mEvents );
00461   Event *event;
00462   while ( i.hasNext() ) {
00463     i.next();
00464     event = i.value();
00465     KDateTime rStart = event->dtStart();
00466     if ( nd < rStart ) {
00467       continue;
00468     }
00469     if ( inclusive && rStart < st ) {
00470       continue;
00471     }
00472 
00473     if ( !event->recurs() ) { // non-recurring events
00474       KDateTime rEnd = event->dtEnd();
00475       if ( rEnd < st ) {
00476         continue;
00477       }
00478       if ( inclusive && nd < rEnd ) {
00479         continue;
00480       }
00481     } else { // recurring events
00482       switch( event->recurrence()->duration() ) {
00483       case -1: // infinite
00484         if ( inclusive ) {
00485           continue;
00486         }
00487         break;
00488       case 0: // end date given
00489       default: // count given
00490         KDateTime rEnd( event->recurrence()->endDate(), ts );
00491         if ( !rEnd.isValid() ) {
00492           continue;
00493         }
00494         if ( rEnd < st ) {
00495           continue;
00496         }
00497         if ( inclusive && nd < rEnd ) {
00498           continue;
00499         }
00500         break;
00501       } // switch(duration)
00502     } //if(recurs)
00503 
00504     eventList.append( event );
00505   }
00506 
00507   return eventList;
00508 }
00509 
00510 Event::List CalendarLocal::rawEventsForDate( const KDateTime &kdt )
00511 {
00512   return rawEventsForDate( kdt.date(), kdt.timeSpec() );
00513 }
00514 
00515 Event::List CalendarLocal::rawEvents( EventSortField sortField,
00516                                       SortDirection sortDirection )
00517 {
00518   Event::List eventList;
00519   QHashIterator<QString, Event *>i( d->mEvents );
00520   while ( i.hasNext() ) {
00521     i.next();
00522     eventList.append( i.value() );
00523   }
00524   return sortEvents( &eventList, sortField, sortDirection );
00525 }
00526 
00527 bool CalendarLocal::addJournal( Journal *journal )
00528 {
00529   d->insertJournal( journal );
00530 
00531   journal->registerObserver( this );
00532 
00533   setModified( true );
00534 
00535   notifyIncidenceAdded( journal );
00536 
00537   return true;
00538 }
00539 
00540 //@cond PRIVATE
00541 void CalendarLocal::Private::insertJournal( Journal *journal )
00542 {
00543   QString uid = journal->uid();
00544   if ( !mJournals.contains( uid ) ) {
00545     mJournals.insert( uid, journal );
00546     mJournalsForDate.insert( journal->dtStart().date().toString(), journal );
00547   } else {
00548 #ifndef NDEBUG
00549     // if we already have an journal with this UID, it must be the same journal,
00550     // otherwise something's really broken
00551     Q_ASSERT( mJournals.value( uid ) == journal );
00552 #endif
00553   }
00554 }
00555 //@endcond
00556 
00557 bool CalendarLocal::deleteJournal( Journal *journal )
00558 {
00559   if ( d->mJournals.remove( journal->uid() ) ) {
00560     setModified( true );
00561     notifyIncidenceDeleted( journal );
00562     d->mDeletedIncidences.append( journal );
00563     removeIncidenceFromMultiHashByUID<Journal *>(
00564       d->mJournalsForDate, journal->dtStart().date().toString(), journal->uid() );
00565     return true;
00566   } else {
00567     kWarning() << "CalendarLocal::deleteJournal(): Journal not found.";
00568     return false;
00569   }
00570 }
00571 
00572 void CalendarLocal::deleteAllJournals()
00573 {
00574   QHashIterator<QString, Journal *>i( d->mJournals );
00575   while ( i.hasNext() ) {
00576     i.next();
00577     notifyIncidenceDeleted( i.value() );
00578   }
00579   qDeleteAll( d->mJournals );
00580   d->mJournals.clear();
00581   d->mJournalsForDate.clear();
00582 }
00583 
00584 Journal *CalendarLocal::journal( const QString &uid )
00585 {
00586   return d->mJournals.value( uid );
00587 }
00588 
00589 Journal::List CalendarLocal::rawJournals( JournalSortField sortField,
00590                                           SortDirection sortDirection )
00591 {
00592   Journal::List journalList;
00593   QHashIterator<QString, Journal *>i( d->mJournals );
00594   while ( i.hasNext() ) {
00595     i.next();
00596     journalList.append( i.value() );
00597   }
00598   return sortJournals( &journalList, sortField, sortDirection );
00599 }
00600 
00601 Journal::List CalendarLocal::rawJournalsForDate( const QDate &date )
00602 {
00603   Journal::List journalList;
00604   Journal *j;
00605 
00606   QString dateStr = date.toString();
00607   QMultiHash<QString, Journal *>::iterator it = d->mJournalsForDate.find( dateStr );
00608 
00609   while ( it != d->mJournalsForDate.end() && it.key() == dateStr ) {
00610     j = it.value();
00611     journalList.append( j );
00612     ++it;
00613   }
00614   return journalList;
00615 }

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.4
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