00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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
00059 class KCal::CalendarLocal::Private
00060 {
00061 public:
00062 Private()
00063 {
00064 mDeletedIncidences.setAutoDelete( true );
00065 }
00066 QString mFileName;
00067 CalFormat *mFormat;
00068
00069 QHash<QString, Event *> mEvents;
00070 QMultiHash<QString, Event *> mEventsForDate;
00071 QHash<QString, Todo *> mTodos;
00072 QMultiHash<QString, Todo*>mTodosForDate;
00073 QHash<QString, Journal *> mJournals;
00074 QMultiHash<QString, Journal *>mJournalsForDate;
00075 Incidence::List mDeletedIncidences;
00076
00077 void insertEvent( Event *event );
00078 void insertTodo( Todo *todo );
00079 void insertJournal( Journal *journal );
00080 };
00081
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
00135
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.clearAll();
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
00213 setupRelations( todo );
00214
00215 setModified( true );
00216
00217 notifyIncidenceAdded( todo );
00218
00219 return true;
00220 }
00221
00222
00223 void CalendarLocal::Private::insertTodo( Todo *todo )
00224 {
00225 QString uid = todo->uid();
00226 if ( !mTodos.contains( uid ) ) {
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
00235
00236 Q_ASSERT( mTodos.value( uid ) == todo );
00237 #endif
00238 }
00239 }
00240
00241
00242 bool CalendarLocal::deleteTodo( Todo *todo )
00243 {
00244
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
00339 void CalendarLocal::Private::insertEvent( Event *event )
00340 {
00341 QString uid = event->uid();
00342 if ( !mEvents.contains( uid ) ) {
00343 mEvents.insert( uid, event );
00344 if ( !event->recurs() ) {
00345 mEventsForDate.insert( event->dtStart().date().toString(), event );
00346 }
00347 } else {
00348 #ifdef NDEBUG
00349
00350
00351 Q_ASSERT( mEvents.value( uid ) == event );
00352 #endif
00353 }
00354 }
00355
00356
00357 void CalendarLocal::incidenceUpdated( IncidenceBase *incidence )
00358 {
00359 KDateTime nowUTC = KDateTime::currentUtcDateTime();
00360 incidence->setLastModified( nowUTC );
00361
00362
00363
00364
00365
00366 notifyIncidenceChanged( static_cast<Incidence *>( incidence ) );
00367
00368 setModified( true );
00369 }
00370
00371 Event::List CalendarLocal::rawEventsForDate( const QDate &date,
00372 const KDateTime::Spec ×pec,
00373 EventSortField sortField,
00374 SortDirection sortDirection )
00375 {
00376 Event::List eventList;
00377 Event *ev;
00378
00379
00380 QString dateStr = date.toString();
00381 QMultiHash<QString, Event *>::iterator it = d->mEventsForDate.find( dateStr );
00382
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
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 ×pec, 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
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() ) {
00449 KDateTime rEnd = event->dtEnd();
00450 if ( rEnd < st ) {
00451 continue;
00452 }
00453 if ( inclusive && nd < rEnd ) {
00454 continue;
00455 }
00456 } else {
00457 switch( event->recurrence()->duration() ) {
00458 case -1:
00459 if ( inclusive ) {
00460 continue;
00461 }
00462 break;
00463 case 0:
00464 default:
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 }
00477 }
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
00516 void CalendarLocal::Private::insertJournal( Journal *journal )
00517 {
00518 QString uid = journal->uid();
00519 if ( !mJournals.contains( uid ) ) {
00520 mJournals.insert( uid, journal );
00521 mJournalsForDate.insert( journal->dtStart().date().toString(), journal );
00522 } else {
00523 #ifndef NDEBUG
00524
00525
00526 Q_ASSERT( mJournals.value( uid ) == journal );
00527 #endif
00528 }
00529 }
00530
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 }