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

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
  •   contact
  •   kmime
  • kabc
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.7.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