libkcal

calendar.cpp
Go to the documentation of this file.
1 /*
2  This file is part of libkcal.
3 
4  Copyright (c) 1998 Preston Brown <pbrown@kde.org>
5  Copyright (c) 2000-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 */
31 #include <stdlib.h>
32 
33 #include <kdebug.h>
34 #include <klocale.h>
35 
36 #include "exceptions.h"
37 #include "calfilter.h"
38 
39 #include "calendar.h"
40 
41 using namespace KCal;
42 
43 Calendar::Calendar( const TQString &timeZoneId )
44 {
45  mTimeZoneId = timeZoneId;
46  mLocalTime = false;
47 
48  init();
49 }
50 
51 void Calendar::init()
52 {
53  mException = 0;
54  mNewObserver = false;
55  mObserversEnabled = true;
56 
57  mModified = false;
58 
59  // Setup default filter, which does nothing
60  mDefaultFilter = new CalFilter;
61  mFilter = mDefaultFilter;
62  mFilter->setEnabled( false );
63 
64  // user information...
65  setOwner( Person( i18n( "Unknown Name" ), i18n( "unknown@nowhere" ) ) );
66 }
67 
69 {
71  delete mDefaultFilter;
72 }
73 
75 {
76  delete mException;
77  mException = 0;
78 }
79 
81 {
82  return mException;
83 }
84 
86 {
87  delete mException;
88  mException = e;
89 }
90 
91 const Person &Calendar::getOwner() const
92 {
93  return mOwner;
94 }
95 
96 void Calendar::setOwner( const Person &owner )
97 {
98  mOwner = owner;
99 
100  setModified( true );
101 }
102 
103 void Calendar::setTimeZoneId( const TQString &timeZoneId )
104 {
105  mTimeZoneId = timeZoneId;
106  mLocalTime = false;
107 
108  setModified( true );
109  doSetTimeZoneId( timeZoneId );
110 }
111 
112 TQString Calendar::timeZoneId() const
113 {
114  return mTimeZoneId;
115 }
116 
118 {
119  mLocalTime = true;
120  mTimeZoneId = "";
121 
122  setModified( true );
123 }
124 
126 {
127  return mLocalTime;
128 }
129 
131 {
132  if ( filter ) {
133  mFilter = filter;
134  } else {
135  mFilter = mDefaultFilter;
136  }
137 }
138 
140 {
141  return mFilter;
142 }
143 
145 {
146  emit batchAddingBegins();
147 }
148 
150 {
151  emit batchAddingEnds();
152 }
153 
154 TQStringList Calendar::categories()
155 {
156  Incidence::List rawInc( rawIncidences() );
157  TQStringList cats, thisCats;
158  // @TODO: For now just iterate over all incidences. In the future,
159  // the list of categories should be built when reading the file.
160  for ( Incidence::List::ConstIterator i = rawInc.constBegin();
161  i != rawInc.constEnd(); ++i ) {
162  thisCats = (*i)->categories();
163  for ( TQStringList::ConstIterator si = thisCats.constBegin();
164  si != thisCats.constEnd(); ++si ) {
165  if ( cats.find( *si ) == cats.end() ) {
166  cats.append( *si );
167  }
168  }
169  }
170  return cats;
171 }
172 
174 {
175  return mergeIncidenceList( events( date ), todos( date ), journals( date ) );
176 }
177 
179 {
180  return mergeIncidenceList( events(), todos(), journals() );
181 }
182 
184 {
186 }
187 
189  EventSortField sortField,
190  SortDirection sortDirection )
191 {
192  Event::List eventListSorted;
193  Event::List tempList;
194  Event::List alphaList;
195  Event::List::Iterator sortIt;
196  Event::List::Iterator eit;
197 
198  // Notice we alphabetically presort Summaries first.
199  // We do this so comparison "ties" stay in a nice order.
200 
201  switch( sortField ) {
202  case EventSortUnsorted:
203  eventListSorted = *eventList;
204  break;
205 
206  case EventSortStartDate:
207  alphaList = sortEvents( eventList, EventSortSummary, sortDirection );
208  for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
209  if ( (*eit)->doesFloat() ) {
210  tempList.append( *eit );
211  continue;
212  }
213  sortIt = eventListSorted.begin();
214  if ( sortDirection == SortDirectionAscending ) {
215  while ( sortIt != eventListSorted.end() &&
216  (*eit)->dtStart() >= (*sortIt)->dtStart() ) {
217  ++sortIt;
218  }
219  } else {
220  while ( sortIt != eventListSorted.end() &&
221  (*eit)->dtStart() < (*sortIt)->dtStart() ) {
222  ++sortIt;
223  }
224  }
225  eventListSorted.insert( sortIt, *eit );
226  }
227  if ( sortDirection == SortDirectionAscending ) {
228  // Prepend the list of all-day Events
229  tempList += eventListSorted;
230  eventListSorted = tempList;
231  } else {
232  // Append the list of all-day Events
233  eventListSorted += tempList;
234  }
235  break;
236 
237  case EventSortEndDate:
238  alphaList = sortEvents( eventList, EventSortSummary, sortDirection );
239  for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
240  if ( (*eit)->hasEndDate() ) {
241  sortIt = eventListSorted.begin();
242  if ( sortDirection == SortDirectionAscending ) {
243  while ( sortIt != eventListSorted.end() &&
244  (*eit)->dtEnd() >= (*sortIt)->dtEnd() ) {
245  ++sortIt;
246  }
247  } else {
248  while ( sortIt != eventListSorted.end() &&
249  (*eit)->dtEnd() < (*sortIt)->dtEnd() ) {
250  ++sortIt;
251  }
252  }
253  } else {
254  // Keep a list of the Events without End DateTimes
255  tempList.append( *eit );
256  }
257  eventListSorted.insert( sortIt, *eit );
258  }
259  if ( sortDirection == SortDirectionAscending ) {
260  // Append the list of Events without End DateTimes
261  eventListSorted += tempList;
262  } else {
263  // Prepend the list of Events without End DateTimes
264  tempList += eventListSorted;
265  eventListSorted = tempList;
266  }
267  break;
268 
269  case EventSortSummary:
270  for ( eit = eventList->begin(); eit != eventList->end(); ++eit ) {
271  sortIt = eventListSorted.begin();
272  if ( sortDirection == SortDirectionAscending ) {
273  while ( sortIt != eventListSorted.end() &&
274  (*eit)->summary() >= (*sortIt)->summary() ) {
275  ++sortIt;
276  }
277  } else {
278  while ( sortIt != eventListSorted.end() &&
279  (*eit)->summary() < (*sortIt)->summary() ) {
280  ++sortIt;
281  }
282  }
283  eventListSorted.insert( sortIt, *eit );
284  }
285  break;
286  }
287 
288  return eventListSorted;
289 }
290 
292  const TQDate &date,
293  EventSortField sortField,
294  SortDirection sortDirection )
295 {
296  Event::List eventListSorted;
297  Event::List tempList;
298  Event::List alphaList;
299  Event::List::Iterator sortIt;
300  Event::List::Iterator eit;
301 
302  switch( sortField ) {
303  case EventSortStartDate:
304  alphaList = sortEvents( eventList, EventSortSummary, sortDirection );
305  for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
306  if ( (*eit)->doesFloat() ) {
307  tempList.append( *eit );
308  continue;
309  }
310  sortIt = eventListSorted.begin();
311  if ( sortDirection == SortDirectionAscending ) {
312  while ( sortIt != eventListSorted.end() ) {
313  if ( !(*eit)->doesRecur() ) {
314  if ( (*eit)->dtStart().time() >= (*sortIt)->dtStart().time() ) {
315  ++sortIt;
316  } else {
317  break;
318  }
319  } else {
320  if ( (*eit)->recursOn( date ) ) {
321  if ( (*eit)->dtStart().time() >= (*sortIt)->dtStart().time() ) {
322  ++sortIt;
323  } else {
324  break;
325  }
326  } else {
327  ++sortIt;
328  }
329  }
330  }
331  } else { // descending
332  while ( sortIt != eventListSorted.end() ) {
333  if ( !(*eit)->doesRecur() ) {
334  if ( (*eit)->dtStart().time() < (*sortIt)->dtStart().time() ) {
335  ++sortIt;
336  } else {
337  break;
338  }
339  } else {
340  if ( (*eit)->recursOn( date ) ) {
341  if ( (*eit)->dtStart().time() < (*sortIt)->dtStart().time() ) {
342  ++sortIt;
343  } else {
344  break;
345  }
346  } else {
347  ++sortIt;
348  }
349  }
350  }
351  }
352  eventListSorted.insert( sortIt, *eit );
353  }
354  if ( sortDirection == SortDirectionAscending ) {
355  // Prepend the list of all-day Events
356  tempList += eventListSorted;
357  eventListSorted = tempList;
358  } else {
359  // Append the list of all-day Events
360  eventListSorted += tempList;
361  }
362  break;
363 
364  case EventSortEndDate:
365  alphaList = sortEvents( eventList, EventSortSummary, sortDirection );
366  for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
367  if ( (*eit)->hasEndDate() ) {
368  sortIt = eventListSorted.begin();
369  if ( sortDirection == SortDirectionAscending ) {
370  while ( sortIt != eventListSorted.end() ) {
371  if ( !(*eit)->doesRecur() ) {
372  if ( (*eit)->dtEnd().time() >= (*sortIt)->dtEnd().time() ) {
373  ++sortIt;
374  } else {
375  break;
376  }
377  } else {
378  if ( (*eit)->recursOn( date ) ) {
379  if ( (*eit)->dtEnd().time() >= (*sortIt)->dtEnd().time() ) {
380  ++sortIt;
381  } else {
382  break;
383  }
384  } else {
385  ++sortIt;
386  }
387  }
388  }
389  } else { // descending
390  while ( sortIt != eventListSorted.end() ) {
391  if ( !(*eit)->doesRecur() ) {
392  if ( (*eit)->dtEnd().time() < (*sortIt)->dtEnd().time() ) {
393  ++sortIt;
394  } else {
395  break;
396  }
397  } else {
398  if ( (*eit)->recursOn( date ) ) {
399  if ( (*eit)->dtEnd().time() < (*sortIt)->dtEnd().time() ) {
400  ++sortIt;
401  } else {
402  break;
403  }
404  } else {
405  ++sortIt;
406  }
407  }
408  }
409  }
410  } else {
411  // Keep a list of the Events without End DateTimes
412  tempList.append( *eit );
413  }
414  eventListSorted.insert( sortIt, *eit );
415  }
416  if ( sortDirection == SortDirectionAscending ) {
417  // Prepend the list of Events without End DateTimes
418  tempList += eventListSorted;
419  eventListSorted = tempList;
420  } else {
421  // Append the list of Events without End DateTimes
422  eventListSorted += tempList;
423  }
424  break;
425 
426  default:
427  eventListSorted = sortEvents( eventList, sortField, sortDirection );
428  break;
429  }
430 
431  return eventListSorted;
432 }
433 
434 Event::List Calendar::events( const TQDate &date,
435  EventSortField sortField,
436  SortDirection sortDirection )
437 {
438  Event::List el = rawEventsForDate( date, sortField, sortDirection );
439  mFilter->apply( &el );
440  return el;
441 }
442 
443 Event::List Calendar::events( const TQDateTime &qdt )
444 {
445  Event::List el = rawEventsForDate( qdt );
446  mFilter->apply( &el );
447  return el;
448 }
449 
450 Event::List Calendar::events( const TQDate &start, const TQDate &end,
451  bool inclusive)
452 {
453  Event::List el = rawEvents( start, end, inclusive );
454  mFilter->apply( &el );
455  return el;
456 }
457 
459  SortDirection sortDirection )
460 {
461  Event::List el = rawEvents( sortField, sortDirection );
462  mFilter->apply( &el );
463  return el;
464 }
465 
467 {
469 
470  return incidence->accept(v);
471 }
472 
474 {
475  if ( beginChange( incidence ) ) {
476  if (incidence->hasRecurrenceID()) {
477  // Delete this event's UID from the parent's list of children
478  Incidence *parentIncidence;
479  IncidenceList il = incidence->childIncidences();
480  IncidenceListIterator it;
481  it = il.begin();
482  parentIncidence = this->incidence(*it);
483  parentIncidence->deleteChildIncidence(incidence->uid());
484  }
485  else {
486  // Delete all children as well
487  IncidenceList il = incidence->childIncidences();
488  IncidenceListIterator it;
489  for ( it = il.begin(); it != il.end(); ++it ) {
490  deleteIncidence( this->incidence(*it) );
491  // Avoid a crash, reset the iterator every time the list is modified
492  it = il.begin();
493  }
494  }
496  bool result = incidence->accept( v );
497  endChange( incidence );
498  return result;
499  } else
500  return false;
501 }
502 
507  bool single )
508 {
509  if ( !incidence || !incidence->doesRecur() )
510  return 0;
511 
512  Incidence *newInc = incidence->clone();
513  newInc->recreate();
514  newInc->setHasRecurrenceID(false);
515 // newInc->setRecurrenceID(TQString());
516  newInc->setRelatedTo( incidence );
517  Recurrence *recur = newInc->recurrence();
518  if ( single ) {
519  recur->clear();
520  } else {
521  // Adjust the recurrence for the future incidences. In particular
522  // adjust the "end after n occurrences" rules! "No end date" and "end by ..."
523  // don't need to be modified.
524  int duration = recur->duration();
525  if ( duration > 0 ) {
526  int doneduration = recur->durationTo( date.addDays(-1) );
527  if ( doneduration >= duration ) {
528  kdDebug(5850) << "The dissociated event already occurred more often "
529  << "than it was supposed to ever occur. ERROR!" << endl;
530  recur->clear();
531  } else {
532  recur->setDuration( duration - doneduration );
533  }
534  }
535  }
536  // Adjust the date of the incidence
537  if ( incidence->type() == "Event" ) {
538  Event *ev = static_cast<Event *>( newInc );
539  TQDateTime start( ev->dtStart() );
540  int daysTo = start.date().daysTo( date );
541  ev->setDtStart( start.addDays( daysTo ) );
542  ev->setDtEnd( ev->dtEnd().addDays( daysTo ) );
543  } else if ( incidence->type() == "Todo" ) {
544  Todo *td = static_cast<Todo *>( newInc );
545  bool haveOffset = false;
546  int daysTo = 0;
547  if ( td->hasDueDate() ) {
548  TQDateTime due( td->dtDue() );
549  daysTo = due.date().daysTo( date );
550  td->setDtDue( due.addDays( daysTo ), true );
551  haveOffset = true;
552  }
553  if ( td->hasStartDate() ) {
554  TQDateTime start( td->dtStart() );
555  if ( !haveOffset )
556  daysTo = start.date().daysTo( date );
557  td->setDtStart( start.addDays( daysTo ) );
558  haveOffset = true;
559  }
560  }
561  recur = incidence->recurrence();
562  if ( recur ) {
563  if ( single ) {
564  recur->addExDate( date );
565  } else {
566  // Make sure the recurrence of the past events ends
567  // at the corresponding day
568  recur->setEndDate( date.addDays(-1) );
569  }
570  }
571  return newInc;
572 }
573 
574 Incidence *Calendar::incidence( const TQString &uid )
575 {
576  Incidence *i = event( uid );
577  if ( i )
578  return i;
579  i = todo( uid );
580  if ( i )
581  return i;
582  i = journal( uid );
583  return i;
584 }
585 
587 {
588  Incidence::List result;
590  Incidence::List::iterator it = incidences.begin();
591  for ( ; it != incidences.end(); ++it )
592  if ( (*it)->schedulingID() == UID )
593  result.append( *it );
594  return result;
595 }
596 
598 {
600  Incidence::List::iterator it = incidences.begin();
601  for ( ; it != incidences.end(); ++it )
602  if ( (*it)->schedulingID() == UID )
603  // Touchdown, and the crowd goes wild
604  return *it;
605  // Not found
606  return 0;
607 }
608 
610  TodoSortField sortField,
611  SortDirection sortDirection )
612 {
613  Todo::List todoListSorted;
614  Todo::List tempList, t;
615  Todo::List alphaList;
616  Todo::List::Iterator sortIt;
617  Todo::List::Iterator eit;
618 
619  // Notice we alphabetically presort Summaries first.
620  // We do this so comparison "ties" stay in a nice order.
621 
622  // Note that Todos may not have Start DateTimes nor due DateTimes.
623 
624  switch( sortField ) {
625  case TodoSortUnsorted:
626  todoListSorted = *todoList;
627  break;
628 
629  case TodoSortStartDate:
630  alphaList = sortTodos( todoList, TodoSortSummary, sortDirection );
631  for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
632  if ( (*eit)->hasStartDate() ) {
633  sortIt = todoListSorted.begin();
634  if ( sortDirection == SortDirectionAscending ) {
635  while ( sortIt != todoListSorted.end() &&
636  (*eit)->dtStart() >= (*sortIt)->dtStart() ) {
637  ++sortIt;
638  }
639  } else {
640  while ( sortIt != todoListSorted.end() &&
641  (*eit)->dtStart() < (*sortIt)->dtStart() ) {
642  ++sortIt;
643  }
644  }
645  todoListSorted.insert( sortIt, *eit );
646  } else {
647  // Keep a list of the Todos without Start DateTimes
648  tempList.append( *eit );
649  }
650  }
651  if ( sortDirection == SortDirectionAscending ) {
652  // Append the list of Todos without Start DateTimes
653  todoListSorted += tempList;
654  } else {
655  // Prepend the list of Todos without Start DateTimes
656  tempList += todoListSorted;
657  todoListSorted = tempList;
658  }
659  break;
660 
661  case TodoSortDueDate:
662  alphaList = sortTodos( todoList, TodoSortSummary, sortDirection );
663  for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
664  if ( (*eit)->hasDueDate() ) {
665  sortIt = todoListSorted.begin();
666  if ( sortDirection == SortDirectionAscending ) {
667  while ( sortIt != todoListSorted.end() &&
668  (*eit)->dtDue() >= (*sortIt)->dtDue() ) {
669  ++sortIt;
670  }
671  } else {
672  while ( sortIt != todoListSorted.end() &&
673  (*eit)->dtDue() < (*sortIt)->dtDue() ) {
674  ++sortIt;
675  }
676  }
677  todoListSorted.insert( sortIt, *eit );
678  } else {
679  // Keep a list of the Todos without Due DateTimes
680  tempList.append( *eit );
681  }
682  }
683  if ( sortDirection == SortDirectionAscending ) {
684  // Append the list of Todos without Due DateTimes
685  todoListSorted += tempList;
686  } else {
687  // Prepend the list of Todos without Due DateTimes
688  tempList += todoListSorted;
689  todoListSorted = tempList;
690  }
691  break;
692 
693  case TodoSortPriority:
694  alphaList = sortTodos( todoList, TodoSortSummary, sortDirection );
695  for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
696  sortIt = todoListSorted.begin();
697  if ( sortDirection == SortDirectionAscending ) {
698  while ( sortIt != todoListSorted.end() &&
699  (*eit)->priority() >= (*sortIt)->priority() ) {
700  ++sortIt;
701  }
702  } else {
703  while ( sortIt != todoListSorted.end() &&
704  (*eit)->priority() < (*sortIt)->priority() ) {
705  ++sortIt;
706  }
707  }
708  todoListSorted.insert( sortIt, *eit );
709  }
710  break;
711 
713  alphaList = sortTodos( todoList, TodoSortSummary, sortDirection );
714  for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
715  sortIt = todoListSorted.begin();
716  if ( sortDirection == SortDirectionAscending ) {
717  while ( sortIt != todoListSorted.end() &&
718  (*eit)->percentComplete() >= (*sortIt)->percentComplete() ) {
719  ++sortIt;
720  }
721  } else {
722  while ( sortIt != todoListSorted.end() &&
723  (*eit)->percentComplete() < (*sortIt)->percentComplete() ) {
724  ++sortIt;
725  }
726  }
727  todoListSorted.insert( sortIt, *eit );
728  }
729  break;
730 
731  case TodoSortSummary:
732  for ( eit = todoList->begin(); eit != todoList->end(); ++eit ) {
733  sortIt = todoListSorted.begin();
734  if ( sortDirection == SortDirectionAscending ) {
735  while ( sortIt != todoListSorted.end() &&
736  (*eit)->summary() >= (*sortIt)->summary() ) {
737  ++sortIt;
738  }
739  } else {
740  while ( sortIt != todoListSorted.end() &&
741  (*eit)->summary() < (*sortIt)->summary() ) {
742  ++sortIt;
743  }
744  }
745  todoListSorted.insert( sortIt, *eit );
746  }
747  break;
748  }
749 
750  return todoListSorted;
751 }
752 
754  SortDirection sortDirection )
755 {
756  Todo::List tl = rawTodos( sortField, sortDirection );
757  mFilter->apply( &tl );
758  return tl;
759 }
760 
761 Todo::List Calendar::todos( const TQDate &date )
762 {
763  Todo::List el = rawTodosForDate( date );
764  mFilter->apply( &el );
765  return el;
766 }
767 
769  JournalSortField sortField,
770  SortDirection sortDirection )
771 {
772  Journal::List journalListSorted;
773  Journal::List::Iterator sortIt;
774  Journal::List::Iterator eit;
775 
776  switch( sortField ) {
777  case JournalSortUnsorted:
778  journalListSorted = *journalList;
779  break;
780 
781  case JournalSortDate:
782  for ( eit = journalList->begin(); eit != journalList->end(); ++eit ) {
783  sortIt = journalListSorted.begin();
784  if ( sortDirection == SortDirectionAscending ) {
785  while ( sortIt != journalListSorted.end() &&
786  (*eit)->dtStart() >= (*sortIt)->dtStart() ) {
787  ++sortIt;
788  }
789  } else {
790  while ( sortIt != journalListSorted.end() &&
791  (*eit)->dtStart() < (*sortIt)->dtStart() ) {
792  ++sortIt;
793  }
794  }
795  journalListSorted.insert( sortIt, *eit );
796  }
797  break;
798 
799  case JournalSortSummary:
800  for ( eit = journalList->begin(); eit != journalList->end(); ++eit ) {
801  sortIt = journalListSorted.begin();
802  if ( sortDirection == SortDirectionAscending ) {
803  while ( sortIt != journalListSorted.end() &&
804  (*eit)->summary() >= (*sortIt)->summary() ) {
805  ++sortIt;
806  }
807  } else {
808  while ( sortIt != journalListSorted.end() &&
809  (*eit)->summary() < (*sortIt)->summary() ) {
810  ++sortIt;
811  }
812  }
813  journalListSorted.insert( sortIt, *eit );
814  }
815  break;
816  }
817 
818  return journalListSorted;
819 }
820 
822  SortDirection sortDirection )
823 {
824  Journal::List jl = rawJournals( sortField, sortDirection );
825  mFilter->apply( &jl );
826  return jl;
827 }
828 
829 Journal::List Calendar::journals( const TQDate &date )
830 {
831  Journal::List el = rawJournalsForDate( date );
832  mFilter->apply( &el );
833  return el;
834 }
835 
836 // When this is called, the todo have already been added to the calendar.
837 // This method is only about linking related todos
838 void Calendar::setupRelations( Incidence *forincidence )
839 {
840  if ( !forincidence ) return;
841 // kdDebug(5850) << "Calendar::setupRelations for incidence " << forincidence << " with UID " << forincidence->uid() << ", summary: " << forincidence->summary() << endl;
842  TQString uid = forincidence->uid();
843 
844  // First, go over the list of orphans and see if this is their parent
845  while ( Incidence* i = mOrphans[ uid ] ) {
846  mOrphans.remove( uid );
847  i->setRelatedTo( forincidence );
848  forincidence->addRelation( i );
849  mOrphanUids.remove( i->uid() );
850  }
851 
852  // Now see about this incidences parent
853  if ( !forincidence->relatedTo() && !forincidence->relatedToUid().isEmpty() ) {
854  // This incidence has a uid it is related to but is not registered to it yet
855  // Try to find it
856  Incidence* parent = incidence( forincidence->relatedToUid() );
857  if ( parent ) {
858  // Found it
859  forincidence->setRelatedTo( parent );
860  parent->addRelation( forincidence );
861  } else {
862  // Not found, put this in the mOrphans list
863  // Note that the mOrphans dict might have several entries with the same key! That are
864  // multiple children that wait for the parent incidence to be inserted.
865  mOrphans.insert( forincidence->relatedToUid(), forincidence );
866  mOrphanUids.insert( forincidence->uid(), forincidence );
867  }
868  }
869 }
870 
871 // If a task with subtasks is deleted, move it's subtasks to the orphans list
873 {
874  if( !incidence ) {
875  kdDebug(5800) << "Warning: Calendar::removeRelations( 0 )!\n";
876  return;
877  }
878 
879 // kdDebug(5850) << "Calendar::removeRelations for incidence " << forincidence << " with UID " << forincidence->uid() << ", summary: " << forincidence->summary() << endl;
880  TQString uid = incidence->uid();
881 
882  Incidence::List relations = incidence->relations();
883  Incidence::List::ConstIterator it;
884  for ( it = relations.begin(); it != relations.end(); ++it ) {
885  Incidence *i = *it;
886  if ( !mOrphanUids.find( i->uid() ) ) {
887  mOrphans.insert( uid, i );
888  mOrphanUids.insert( i->uid(), i );
889  i->setRelatedTo( 0 );
890  i->setRelatedToUid( uid );
891  }
892  }
893 
894  // If this incidence is related to something else, tell that about it
895  if ( incidence->relatedTo() )
896  incidence->relatedTo()->removeRelation( incidence );
897 
898  // Remove this one from the orphans list
899  if ( mOrphanUids.remove( uid ) ) {
900  // This incidence is located in the orphans list - it should be removed
901  // Since the mOrphans dict might contain the same key (with different
902  // child incidence pointers!) multiple times, take care that we remove
903  // the correct one. So we need to remove all items with the given
904  // parent UID, and readd those that are not for this item. Also, there
905  // might be other entries with differnet UID that point to this
906  // incidence (this might happen when the relatedTo of the item is
907  // changed before its parent is inserted. This might happen with
908  // groupware servers....). Remove them, too
909  TQStringList relatedToUids;
910  // First get the list of all keys in the mOrphans list that point to the removed item
911  relatedToUids << incidence->relatedToUid();
912  for ( TQDictIterator<Incidence> it( mOrphans ); it.current(); ++it ) {
913  if ( it.current()->uid() == uid ) {
914  relatedToUids << it.currentKey();
915  }
916  }
917 
918  // now go through all uids that have one entry that point to the incidence
919  for ( TQStringList::Iterator uidit = relatedToUids.begin();
920  uidit != relatedToUids.end(); ++uidit ) {
921  Incidence::List tempList;
922  // Remove all to get access to the remaining entries
923  while( Incidence* i = mOrphans[ *uidit ] ) {
924  mOrphans.remove( *uidit );
925  if ( i != incidence ) tempList.append( i );
926  }
927  // Readd those that point to a different orphan incidence
928  for ( Incidence::List::Iterator incit = tempList.begin();
929  incit != tempList.end(); ++incit ) {
930  mOrphans.insert( *uidit, *incit );
931  }
932  }
933  }
934 }
935 
937 {
938  if( !mObservers.contains( observer ) )
939  mObservers.append( observer );
940  mNewObserver = true;
941 }
942 
944 {
945  mObservers.remove( observer );
946 }
947 
948 void Calendar::setModified( bool modified )
949 {
950  if ( modified != mModified || mNewObserver ) {
951  mNewObserver = false;
952  Observer *observer;
953  for ( observer = mObservers.first(); observer;
954  observer = mObservers.next() ) {
955  observer->calendarModified( modified, this );
956  }
957  mModified = modified;
958  }
959 }
960 
962 {
963  incidence->setSyncStatus( Event::SYNCMOD );
964  incidence->setLastModified( TQDateTime::currentDateTime() );
965  // we should probably update the revision number here,
966  // or internally in the Event itself when certain things change.
967  // need to verify with ical documentation.
968 
969  // The static_cast is ok as the CalendarLocal only observes Incidence objects
970  notifyIncidenceChanged( static_cast<Incidence *>( incidence ) );
971 
972  setModified( true );
973 }
974 
976 {
977  if ( !mObserversEnabled )
978  return;
979 
980  Observer *observer;
981  for ( observer = mObservers.first(); observer;
982  observer = mObservers.next() ) {
983  observer->calendarIncidenceAdded( i );
984  }
985 }
986 
988 {
989  if ( !mObserversEnabled )
990  return;
991 
992  Observer *observer;
993  for ( observer = mObservers.first(); observer;
994  observer = mObservers.next() ) {
995  observer->calendarIncidenceChanged( i );
996  }
997 }
998 
1000 {
1001  if ( !mObserversEnabled )
1002  return;
1003 
1004  Observer *observer;
1005  for ( observer = mObservers.first(); observer;
1006  observer = mObservers.next() ) {
1007  observer->calendarIncidenceDeleted( i );
1008  }
1009 }
1010 
1012 {
1013  setModified( true );
1014 }
1015 
1016 void Calendar::setProductId( const TQString &productId )
1017 {
1018  mProductId = productId;
1019 }
1020 
1022 {
1023  return mProductId;
1024 }
1025 
1027  const Todo::List &todos,
1028  const Journal::List &journals )
1029 {
1031 
1032  Event::List::ConstIterator it1;
1033  for ( it1 = events.begin(); it1 != events.end(); ++it1 )
1034  incidences.append( *it1 );
1035 
1036  Todo::List::ConstIterator it2;
1037  for ( it2 = todos.begin(); it2 != todos.end(); ++it2 )
1038  incidences.append( *it2 );
1039 
1040  Journal::List::ConstIterator it3;
1041  for ( it3 = journals.begin(); it3 != journals.end(); ++it3 )
1042  incidences.append( *it3 );
1043 
1044  return incidences;
1045 }
1046 
1048 {
1049  return true;
1050 }
1051 
1053 {
1054  return true;
1055 }
1056 
1057 void Calendar::setObserversEnabled( bool enabled )
1058 {
1059  mObserversEnabled = enabled;
1060 }
1061 
1062 #include "calendar.moc"