• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.10.5 API Reference
  • KDE Home
  • Contact Us
 

KCal Library

  • kcal
calendarlocal.cpp
Go to the documentation of this file.
1 /*
2  This file is part of the kcal library.
3 
4  Copyright (c) 1998 Preston Brown <pbrown@kde.org>
5  Copyright (c) 2001,2003,2004 Cornelius Schumacher <schumacher@kde.org>
6  Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
7 
8  This library is free software; you can redistribute it and/or
9  modify it under the terms of the GNU Library General Public
10  License as published by the Free Software Foundation; either
11  version 2 of the License, or (at your option) any later version.
12 
13  This library is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  Library General Public License for more details.
17 
18  You should have received a copy of the GNU Library General Public License
19  along with this library; see the file COPYING.LIB. If not, write to
20  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  Boston, MA 02110-1301, USA.
22 */
35 #include "calendarlocal.h"
36 
37 #include "incidence.h"
38 #include "event.h"
39 #include "todo.h"
40 #include "journal.h"
41 #include "filestorage.h"
42 #include <QtCore/QDate>
43 #include <QtCore/QHash>
44 #include <QtCore/QMultiHash>
45 #include <QtCore/QString>
46 
47 #include <kdebug.h>
48 #include <kdatetime.h>
49 #include <klocale.h>
50 #include <kmessagebox.h>
51 
52 using namespace KCal;
53 
58 //@cond PRIVATE
59 class KCal::CalendarLocal::Private
60 {
61  public:
62  Private() : mFormat(0) {}
63  QString mFileName; // filename where calendar is stored
64  CalFormat *mFormat; // calendar format
65 
66  QHash<QString, Event *>mEvents; // hash on uids of all Events
67  QMultiHash<QString, Event *>mEventsForDate;// on start dates of non-recurring, single-day Events
68  QHash<QString, Todo *>mTodos; // hash on uids of all Todos
69  QMultiHash<QString, Todo*>mTodosForDate;// on due dates for all Todos
70  QHash<QString, Journal *>mJournals; // hash on uids of all Journals
71  QMultiHash<QString, Journal *>mJournalsForDate; // on dates of all Journals
72 
73  void insertEvent( Event *event );
74  void insertTodo( Todo *todo );
75  void insertJournal( Journal *journal );
76 };
77 
78 // helper
79 namespace {
80 template <typename T>
81 void removeIncidenceFromMultiHashByUID( QMultiHash< QString, T >& container,
82  const QString &key,
83  const QString &uid )
84 {
85  const QList<T> values = container.values( key );
86  QListIterator<T> it(values);
87  while ( it.hasNext() ) {
88  T const inc = it.next();
89  if ( inc->uid() == uid ) {
90  container.remove( key, inc );
91  }
92  }
93 }
94 }
95 //@endcond
96 
97 CalendarLocal::CalendarLocal( const KDateTime::Spec &timeSpec )
98  : Calendar( timeSpec ),
99  d( new KCal::CalendarLocal::Private )
100 {
101 }
102 
103 CalendarLocal::CalendarLocal( const QString &timeZoneId )
104  : Calendar( timeZoneId ),
105  d( new KCal::CalendarLocal::Private )
106 {
107 }
108 
109 CalendarLocal::~CalendarLocal()
110 {
111  close();
112  delete d;
113 }
114 
115 bool CalendarLocal::load( const QString &fileName, CalFormat *format )
116 {
117  d->mFileName = fileName;
118  FileStorage storage( this, fileName, format );
119  return storage.load();
120 }
121 
122 bool CalendarLocal::reload()
123 {
124  const QString filename = d->mFileName;
125  save();
126  close();
127  d->mFileName = filename;
128  FileStorage storage( this, d->mFileName );
129  return storage.load();
130 }
131 
132 bool CalendarLocal::save()
133 {
134  if ( d->mFileName.isEmpty() ) {
135  return false;
136  }
137 
138  if ( isModified() ) {
139  FileStorage storage( this, d->mFileName, d->mFormat );
140  return storage.save();
141  } else {
142  return true;
143  }
144 }
145 
146 bool CalendarLocal::save( const QString &fileName, CalFormat *format )
147 {
148  // Save only if the calendar is either modified, or saved to a
149  // different file than it was loaded from
150  if ( d->mFileName != fileName || isModified() ) {
151  FileStorage storage( this, fileName, format );
152  return storage.save();
153  } else {
154  return true;
155  }
156 }
157 
158 void CalendarLocal::close()
159 {
160  setObserversEnabled( false );
161  d->mFileName.clear();
162 
163  deleteAllEvents();
164  deleteAllTodos();
165  deleteAllJournals();
166 
167  setModified( false );
168 
169  setObserversEnabled( true );
170 }
171 
172 bool CalendarLocal::addEvent( Event *event )
173 {
174  d->insertEvent( event );
175 
176  event->registerObserver( this );
177 
178  setModified( true );
179 
180  notifyIncidenceAdded( event );
181 
182  return true;
183 }
184 
185 bool CalendarLocal::deleteEvent( Event *event )
186 {
187  const QString uid = event->uid();
188  if ( d->mEvents.remove( uid ) ) {
189  setModified( true );
190  notifyIncidenceDeleted( event );
191  if ( !event->recurs() ) {
192  removeIncidenceFromMultiHashByUID<Event *>(
193  d->mEventsForDate, event->dtStart().date().toString(), event->uid() );
194  }
195  return true;
196  } else {
197  kWarning() << "Event not found.";
198  return false;
199  }
200 }
201 
202 void CalendarLocal::deleteAllEvents()
203 {
204  QHashIterator<QString, Event *>i( d->mEvents );
205  while ( i.hasNext() ) {
206  i.next();
207  notifyIncidenceDeleted( i.value() );
208  // suppress update notifications for the relation removal triggered
209  // by the following deletions
210  i.value()->startUpdates();
211  }
212  qDeleteAll( d->mEvents );
213  d->mEvents.clear();
214  d->mEventsForDate.clear();
215 }
216 
217 Event *CalendarLocal::event( const QString &uid )
218 {
219  return d->mEvents.value( uid );
220 }
221 
222 bool CalendarLocal::addTodo( Todo *todo )
223 {
224  d->insertTodo( todo );
225 
226  todo->registerObserver( this );
227 
228  // Set up sub-to-do relations
229  setupRelations( todo );
230 
231  setModified( true );
232 
233  notifyIncidenceAdded( todo );
234 
235  return true;
236 }
237 
238 //@cond PRIVATE
239 void CalendarLocal::Private::insertTodo( Todo *todo )
240 {
241  QString uid = todo->uid();
242  if ( !mTodos.contains( uid ) ) {
243  mTodos.insert( uid, todo );
244  if ( todo->hasDueDate() ) {
245  mTodosForDate.insert( todo->dtDue().date().toString(), todo );
246  }
247 
248  } else {
249 #ifndef NDEBUG
250  // if we already have an to-do with this UID, it must be the same to-do,
251  // otherwise something's really broken
252  Q_ASSERT( mTodos.value( uid ) == todo );
253 #endif
254  }
255 }
256 //@endcond
257 
258 bool CalendarLocal::deleteTodo( Todo *todo )
259 {
260  // Handle orphaned children
261  removeRelations( todo );
262 
263  if ( d->mTodos.remove( todo->uid() ) ) {
264  setModified( true );
265  notifyIncidenceDeleted( todo );
266  if ( todo->hasDueDate() ) {
267  removeIncidenceFromMultiHashByUID<Todo *>(
268  d->mTodosForDate, todo->dtDue().date().toString(), todo->uid() );
269  }
270  return true;
271  } else {
272  kWarning() << "Todo not found.";
273  return false;
274  }
275 }
276 
277 void CalendarLocal::deleteAllTodos()
278 {
279  QHashIterator<QString, Todo *>i( d->mTodos );
280  while ( i.hasNext() ) {
281  i.next();
282  notifyIncidenceDeleted( i.value() );
283  // suppress update notifications for the relation removal triggered
284  // by the following deletions
285  i.value()->startUpdates();
286  }
287  qDeleteAll( d->mTodos );
288  d->mTodos.clear();
289  d->mTodosForDate.clear();
290 }
291 
292 Todo *CalendarLocal::todo( const QString &uid )
293 {
294  return d->mTodos.value( uid );
295 }
296 
297 Todo::List CalendarLocal::rawTodos( TodoSortField sortField,
298  SortDirection sortDirection )
299 {
300  Todo::List todoList;
301  QHashIterator<QString, Todo *>i( d->mTodos );
302  while ( i.hasNext() ) {
303  i.next();
304  todoList.append( i.value() );
305  }
306  return sortTodos( &todoList, sortField, sortDirection );
307 }
308 
309 Todo::List CalendarLocal::rawTodosForDate( const QDate &date )
310 {
311  Todo::List todoList;
312  Todo *t;
313 
314  QString dateStr = date.toString();
315  QMultiHash<QString, Todo *>::const_iterator it = d->mTodosForDate.constFind( dateStr );
316  while ( it != d->mTodosForDate.constEnd() && it.key() == dateStr ) {
317  t = it.value();
318  todoList.append( t );
319  ++it;
320  }
321  return todoList;
322 }
323 
324 Alarm::List CalendarLocal::alarmsTo( const KDateTime &to )
325 {
326  return alarms( KDateTime( QDate( 1900, 1, 1 ) ), to );
327 }
328 
329 Alarm::List CalendarLocal::alarms( const KDateTime &from, const KDateTime &to )
330 {
331  Alarm::List alarmList;
332  QHashIterator<QString, Event *>ie( d->mEvents );
333  Event *e;
334  while ( ie.hasNext() ) {
335  ie.next();
336  e = ie.value();
337  if ( e->recurs() ) {
338  appendRecurringAlarms( alarmList, e, from, to );
339  } else {
340  appendAlarms( alarmList, e, from, to );
341  }
342  }
343 
344  QHashIterator<QString, Todo *>it( d->mTodos );
345  Todo *t;
346  while ( it.hasNext() ) {
347  it.next();
348  t = it.value();
349  if ( !t->isCompleted() ) {
350  if ( t->recurs() ) {
351  appendRecurringAlarms( alarmList, t, from, to );
352  } else {
353  appendAlarms( alarmList, t, from, to );
354  }
355  }
356  }
357 
358  return alarmList;
359 }
360 
361 //@cond PRIVATE
362 void CalendarLocal::Private::insertEvent( Event *event )
363 {
364  QString uid = event->uid();
365  if ( !mEvents.contains( uid ) ) {
366  mEvents.insert( uid, event );
367  if ( !event->recurs() && !event->isMultiDay() ) {
368  mEventsForDate.insert( event->dtStart().date().toString(), event );
369  }
370  } else {
371 #ifdef NDEBUG
372  // if we already have an event with this UID, it must be the same event,
373  // otherwise something's really broken
374  Q_ASSERT( mEvents.value( uid ) == event );
375 #endif
376  }
377 }
378 //@endcond
379 
380 void CalendarLocal::incidenceUpdated( IncidenceBase *incidence )
381 {
382  KDateTime nowUTC = KDateTime::currentUtcDateTime();
383  incidence->setLastModified( nowUTC );
384  // we should probably update the revision number here,
385  // or internally in the Event itself when certain things change.
386  // need to verify with ical documentation.
387 
388  if ( incidence->type() == "Event" ) {
389  Event *event = static_cast<Event*>( incidence );
390  removeIncidenceFromMultiHashByUID<Event *>(
391  d->mEventsForDate, event->dtStart().date().toString(), event->uid() );
392  if ( !event->recurs() && !event->isMultiDay() ) {
393  d->mEventsForDate.insert( event->dtStart().date().toString(), event );
394  }
395  } else if ( incidence->type() == "Todo" ) {
396  Todo *todo = static_cast<Todo*>( incidence );
397  removeIncidenceFromMultiHashByUID<Todo *>(
398  d->mTodosForDate, todo->dtDue().date().toString(), todo->uid() );
399  if ( todo->hasDueDate() ) {
400  d->mTodosForDate.insert( todo->dtDue().date().toString(), todo );
401  }
402  } else if ( incidence->type() == "Journal" ) {
403  Journal *journal = static_cast<Journal*>( incidence );
404  removeIncidenceFromMultiHashByUID<Journal *>(
405  d->mJournalsForDate, journal->dtStart().date().toString(), journal->uid() );
406  d->mJournalsForDate.insert( journal->dtStart().date().toString(), journal );
407  } else {
408  Q_ASSERT( false );
409  }
410 
411  // The static_cast is ok as the CalendarLocal only observes Incidence objects
412  notifyIncidenceChanged( static_cast<Incidence *>( incidence ) );
413 
414  setModified( true );
415 }
416 
417 Event::List CalendarLocal::rawEventsForDate( const QDate &date,
418  const KDateTime::Spec &timespec,
419  EventSortField sortField,
420  SortDirection sortDirection )
421 {
422  Event::List eventList;
423  Event *ev;
424 
425  // Find the hash for the specified date
426  QString dateStr = date.toString();
427  QMultiHash<QString, Event *>::const_iterator it = d->mEventsForDate.constFind( dateStr );
428  // Iterate over all non-recurring, single-day events that start on this date
429  KDateTime::Spec ts = timespec.isValid() ? timespec : timeSpec();
430  KDateTime kdt( date, ts );
431  while ( it != d->mEventsForDate.constEnd() && it.key() == dateStr ) {
432  ev = it.value();
433  KDateTime end( ev->dtEnd().toTimeSpec( ev->dtStart() ) );
434  if ( ev->allDay() ) {
435  end.setDateOnly( true );
436  } else {
437  end = end.addSecs( -1 );
438  }
439  if ( end >= kdt ) {
440  eventList.append( ev );
441  }
442  ++it;
443  }
444 
445  // Iterate over all events. Look for recurring events that occur on this date
446  QHashIterator<QString, Event *>i( d->mEvents );
447  while ( i.hasNext() ) {
448  i.next();
449  ev = i.value();
450  if ( ev->recurs() ) {
451  if ( ev->isMultiDay() ) {
452  int extraDays = ev->dtStart().date().daysTo( ev->dtEnd().date() );
453  for ( int i = 0; i <= extraDays; ++i ) {
454  if ( ev->recursOn( date.addDays( -i ), ts ) ) {
455  eventList.append( ev );
456  break;
457  }
458  }
459  } else {
460  if ( ev->recursOn( date, ts ) ) {
461  eventList.append( ev );
462  }
463  }
464  } else {
465  if ( ev->isMultiDay() ) {
466  if ( ev->dtStart().date() <= date && ev->dtEnd().date() >= date ) {
467  eventList.append( ev );
468  }
469  }
470  }
471  }
472 
473  return sortEventsForDate( &eventList, date, timespec, sortField, sortDirection );
474 }
475 
476 Event::List CalendarLocal::rawEvents( const QDate &start, const QDate &end,
477  const KDateTime::Spec &timespec, bool inclusive )
478 {
479  Event::List eventList;
480  KDateTime::Spec ts = timespec.isValid() ? timespec : timeSpec();
481  KDateTime st( start, ts );
482  KDateTime nd( end, ts );
483  KDateTime yesterStart = st.addDays( -1 );
484 
485  // Get non-recurring events
486  QHashIterator<QString, Event *>i( d->mEvents );
487  Event *event;
488  while ( i.hasNext() ) {
489  i.next();
490  event = i.value();
491  KDateTime rStart = event->dtStart();
492  if ( nd < rStart ) {
493  continue;
494  }
495  if ( inclusive && rStart < st ) {
496  continue;
497  }
498 
499  if ( !event->recurs() ) { // non-recurring events
500  KDateTime rEnd = event->dtEnd();
501  if ( rEnd < st ) {
502  continue;
503  }
504  if ( inclusive && nd < rEnd ) {
505  continue;
506  }
507  } else { // recurring events
508  switch( event->recurrence()->duration() ) {
509  case -1: // infinite
510  if ( inclusive ) {
511  continue;
512  }
513  break;
514  case 0: // end date given
515  default: // count given
516  KDateTime rEnd( event->recurrence()->endDate(), ts );
517  if ( !rEnd.isValid() ) {
518  continue;
519  }
520  if ( rEnd < st ) {
521  continue;
522  }
523  if ( inclusive && nd < rEnd ) {
524  continue;
525  }
526  break;
527  } // switch(duration)
528  } //if(recurs)
529 
530  eventList.append( event );
531  }
532 
533  return eventList;
534 }
535 
536 Event::List CalendarLocal::rawEventsForDate( const KDateTime &kdt )
537 {
538  return rawEventsForDate( kdt.date(), kdt.timeSpec() );
539 }
540 
541 Event::List CalendarLocal::rawEvents( EventSortField sortField,
542  SortDirection sortDirection )
543 {
544  Event::List eventList;
545  QHashIterator<QString, Event *>i( d->mEvents );
546  while ( i.hasNext() ) {
547  i.next();
548  eventList.append( i.value() );
549  }
550  return sortEvents( &eventList, sortField, sortDirection );
551 }
552 
553 bool CalendarLocal::addJournal( Journal *journal )
554 {
555  d->insertJournal( journal );
556 
557  journal->registerObserver( this );
558 
559  setModified( true );
560 
561  notifyIncidenceAdded( journal );
562 
563  return true;
564 }
565 
566 //@cond PRIVATE
567 void CalendarLocal::Private::insertJournal( Journal *journal )
568 {
569  QString uid = journal->uid();
570  if ( !mJournals.contains( uid ) ) {
571  mJournals.insert( uid, journal );
572  mJournalsForDate.insert( journal->dtStart().date().toString(), journal );
573  } else {
574 #ifndef NDEBUG
575  // if we already have an journal with this UID, it must be the same journal,
576  // otherwise something's really broken
577  Q_ASSERT( mJournals.value( uid ) == journal );
578 #endif
579  }
580 }
581 //@endcond
582 
583 bool CalendarLocal::deleteJournal( Journal *journal )
584 {
585  if ( d->mJournals.remove( journal->uid() ) ) {
586  setModified( true );
587  notifyIncidenceDeleted( journal );
588  removeIncidenceFromMultiHashByUID<Journal *>(
589  d->mJournalsForDate, journal->dtStart().date().toString(), journal->uid() );
590  return true;
591  } else {
592  kWarning() << "Journal not found.";
593  return false;
594  }
595 }
596 
597 void CalendarLocal::deleteAllJournals()
598 {
599  QHashIterator<QString, Journal *>i( d->mJournals );
600  while ( i.hasNext() ) {
601  i.next();
602  notifyIncidenceDeleted( i.value() );
603  // suppress update notifications for the relation removal triggered
604  // by the following deletions
605  i.value()->startUpdates();
606  }
607  qDeleteAll( d->mJournals );
608  d->mJournals.clear();
609  d->mJournalsForDate.clear();
610 }
611 
612 Journal *CalendarLocal::journal( const QString &uid )
613 {
614  return d->mJournals.value( uid );
615 }
616 
617 Journal::List CalendarLocal::rawJournals( JournalSortField sortField,
618  SortDirection sortDirection )
619 {
620  Journal::List journalList;
621  QHashIterator<QString, Journal *>i( d->mJournals );
622  while ( i.hasNext() ) {
623  i.next();
624  journalList.append( i.value() );
625  }
626  return sortJournals( &journalList, sortField, sortDirection );
627 }
628 
629 Journal::List CalendarLocal::rawJournalsForDate( const QDate &date )
630 {
631  Journal::List journalList;
632  Journal *j;
633 
634  QString dateStr = date.toString();
635  QMultiHash<QString, Journal *>::const_iterator it = d->mJournalsForDate.constFind( dateStr );
636 
637  while ( it != d->mJournalsForDate.constEnd() && it.key() == dateStr ) {
638  j = it.value();
639  journalList.append( j );
640  ++it;
641  }
642  return journalList;
643 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Sat Jul 13 2013 01:29:13 by doxygen 1.8.3.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KCal Library

Skip menu "KCal Library"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Related Pages

kdepimlibs-4.10.5 API Reference

Skip menu "kdepimlibs-4.10.5 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal