libkcal

calendar.cpp

Go to the documentation of this file.
00001 /*
00002     This file is part of libkcal.
00003 
00004     Copyright (c) 1998 Preston Brown <pbrown@kde.org>
00005     Copyright (c) 2000-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 */
00031 #include <stdlib.h>
00032 
00033 #include <kdebug.h>
00034 #include <klocale.h>
00035 
00036 #include "exceptions.h"
00037 #include "calfilter.h"
00038 
00039 #include "calendar.h"
00040 
00041 using namespace KCal;
00042 
00043 Calendar::Calendar( const QString &timeZoneId )
00044 {
00045   mTimeZoneId = timeZoneId;
00046   mLocalTime = false;
00047 
00048   init();
00049 }
00050 
00051 void Calendar::init()
00052 {
00053   mNewObserver = false;
00054   mObserversEnabled = true;
00055 
00056   mModified = false;
00057 
00058   // Setup default filter, which does nothing
00059   mDefaultFilter = new CalFilter;
00060   mFilter = mDefaultFilter;
00061   mFilter->setEnabled( false );
00062 
00063   // user information...
00064   setOwner( Person( i18n( "Unknown Name" ), i18n( "unknown@nowhere" ) ) );
00065 }
00066 
00067 Calendar::~Calendar()
00068 {
00069   delete mDefaultFilter;
00070 }
00071 
00072 const Person &Calendar::getOwner() const
00073 {
00074   return mOwner;
00075 }
00076 
00077 void Calendar::setOwner( const Person &owner )
00078 {
00079   mOwner = owner;
00080 
00081   setModified( true );
00082 }
00083 
00084 void Calendar::setTimeZoneId( const QString &timeZoneId )
00085 {
00086   mTimeZoneId = timeZoneId;
00087   mLocalTime = false;
00088 
00089   setModified( true );
00090   doSetTimeZoneId( timeZoneId );
00091 }
00092 
00093 QString Calendar::timeZoneId() const
00094 {
00095   return mTimeZoneId;
00096 }
00097 
00098 void Calendar::setLocalTime()
00099 {
00100   mLocalTime = true;
00101   mTimeZoneId = "";
00102 
00103   setModified( true );
00104 }
00105 
00106 bool Calendar::isLocalTime() const
00107 {
00108   return mLocalTime;
00109 }
00110 
00111 void Calendar::setFilter( CalFilter *filter )
00112 {
00113   if ( filter ) {
00114     mFilter = filter;
00115   } else {
00116     mFilter = mDefaultFilter;
00117   }
00118 }
00119 
00120 CalFilter *Calendar::filter()
00121 {
00122   return mFilter;
00123 }
00124 
00125 QStringList Calendar::categories()
00126 {
00127   Incidence::List rawInc( rawIncidences() );
00128   QStringList cats, thisCats;
00129   // @TODO: For now just iterate over all incidences. In the future,
00130   // the list of categories should be built when reading the file.
00131   for ( Incidence::List::ConstIterator i = rawInc.constBegin();
00132         i != rawInc.constEnd(); ++i ) {
00133     thisCats = (*i)->categories();
00134     for ( QStringList::ConstIterator si = thisCats.constBegin();
00135           si != thisCats.constEnd(); ++si ) {
00136       if ( cats.find( *si ) == cats.end() ) {
00137         cats.append( *si );
00138       }
00139     }
00140   }
00141   return cats;
00142 }
00143 
00144 Incidence::List Calendar::incidences( const QDate &date )
00145 {
00146   return mergeIncidenceList( events( date ), todos( date ), journals( date ) );
00147 }
00148 
00149 Incidence::List Calendar::incidences()
00150 {
00151   return mergeIncidenceList( events(), todos(), journals() );
00152 }
00153 
00154 Incidence::List Calendar::rawIncidences()
00155 {
00156   return mergeIncidenceList( rawEvents(), rawTodos(), rawJournals() );
00157 }
00158 
00159 Event::List Calendar::sortEvents( Event::List *eventList,
00160                                   EventSortField sortField,
00161                                   SortDirection sortDirection )
00162 {
00163   Event::List eventListSorted;
00164   Event::List tempList, t;
00165   Event::List alphaList;
00166   Event::List::Iterator sortIt;
00167   Event::List::Iterator eit;
00168 
00169   // Notice we alphabetically presort Summaries first.
00170   // We do this so comparison "ties" stay in a nice order.
00171 
00172   switch( sortField ) {
00173   case EventSortUnsorted:
00174     eventListSorted = *eventList;
00175     break;
00176 
00177   case EventSortStartDate:
00178     alphaList = sortEvents( eventList, EventSortSummary, sortDirection );
00179     for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00180       sortIt = eventListSorted.begin();
00181       if ( sortDirection == SortDirectionAscending ) {
00182         while ( sortIt != eventListSorted.end() &&
00183                 (*eit)->dtStart() >= (*sortIt)->dtStart() ) {
00184           ++sortIt;
00185         }
00186       } else {
00187         while ( sortIt != eventListSorted.end() &&
00188                 (*eit)->dtStart() < (*sortIt)->dtStart() ) {
00189           ++sortIt;
00190         }
00191       }
00192       eventListSorted.insert( sortIt, *eit );
00193     }
00194     break;
00195 
00196   case EventSortEndDate:
00197     alphaList = sortEvents( eventList, EventSortSummary, sortDirection );
00198     for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00199       if ( (*eit)->hasEndDate() ) {
00200         sortIt = eventListSorted.begin();
00201         if ( sortDirection == SortDirectionAscending ) {
00202           while ( sortIt != eventListSorted.end() &&
00203                   (*eit)->dtEnd() >= (*sortIt)->dtEnd() ) {
00204             ++sortIt;
00205           }
00206         } else {
00207           while ( sortIt != eventListSorted.end() &&
00208                   (*eit)->dtEnd() < (*sortIt)->dtEnd() ) {
00209             ++sortIt;
00210           }
00211         }
00212       } else {
00213         // Keep a list of the Events without End DateTimes
00214         tempList.append( *eit );
00215       }
00216       eventListSorted.insert( sortIt, *eit );
00217     }
00218     if ( sortDirection == SortDirectionAscending ) {
00219       // Append the list of Events without End DateTimes
00220       eventListSorted += tempList;
00221     } else {
00222       // Prepend the list of Events without End DateTimes
00223       tempList += eventListSorted;
00224       eventListSorted = tempList;
00225     }
00226     break;
00227 
00228   case EventSortSummary:
00229     for ( eit = eventList->begin(); eit != eventList->end(); ++eit ) {
00230       sortIt = eventListSorted.begin();
00231       if ( sortDirection == SortDirectionAscending ) {
00232         while ( sortIt != eventListSorted.end() &&
00233                 (*eit)->summary() >= (*sortIt)->summary() ) {
00234           ++sortIt;
00235         }
00236       } else {
00237         while ( sortIt != eventListSorted.end() &&
00238                 (*eit)->summary() < (*sortIt)->summary() ) {
00239           ++sortIt;
00240         }
00241       }
00242       eventListSorted.insert( sortIt, *eit );
00243     }
00244     break;
00245   }
00246 
00247   return eventListSorted;
00248 
00249 }
00250 
00251 Event::List Calendar::events( const QDate &date,
00252                               EventSortField sortField,
00253                               SortDirection sortDirection )
00254 {
00255   Event::List el = rawEventsForDate( date, sortField, sortDirection );
00256   mFilter->apply( &el );
00257   return el;
00258 }
00259 
00260 Event::List Calendar::events( const QDateTime &qdt )
00261 {
00262   Event::List el = rawEventsForDate( qdt );
00263   mFilter->apply( &el );
00264   return el;
00265 }
00266 
00267 Event::List Calendar::events( const QDate &start, const QDate &end,
00268                               bool inclusive)
00269 {
00270   Event::List el = rawEvents( start, end, inclusive );
00271   mFilter->apply( &el );
00272   return el;
00273 }
00274 
00275 Event::List Calendar::events( EventSortField sortField,
00276                               SortDirection sortDirection )
00277 {
00278   Event::List el = rawEvents( sortField, sortDirection );
00279   mFilter->apply( &el );
00280   return el;
00281 }
00282 
00283 bool Calendar::addIncidence( Incidence *incidence )
00284 {
00285   Incidence::AddVisitor<Calendar> v( this );
00286 
00287   return incidence->accept(v);
00288 }
00289 
00290 bool Calendar::deleteIncidence( Incidence *incidence )
00291 {
00292   if ( beginChange( incidence ) ) {
00293     Incidence::DeleteVisitor<Calendar> v( this );
00294     bool result = incidence->accept( v );
00295     endChange( incidence );
00296     return result;
00297   } else
00298     return false;
00299 }
00300 
00304 Incidence *Calendar::dissociateOccurrence( Incidence *incidence, QDate date,
00305                                            bool single )
00306 {
00307   if ( !incidence || !incidence->doesRecur() )
00308     return 0;
00309 
00310   Incidence *newInc = incidence->clone();
00311   newInc->recreate();
00312   newInc->setRelatedTo( incidence );
00313   Recurrence *recur = newInc->recurrence();
00314   if ( single ) {
00315     recur->clear();
00316   } else {
00317     // Adjust the recurrence for the future incidences. In particular
00318     // adjust the "end after n occurrences" rules! "No end date" and "end by ..."
00319     // don't need to be modified.
00320     int duration = recur->duration();
00321     if ( duration > 0 ) {
00322       int doneduration = recur->durationTo( date.addDays(-1) );
00323       if ( doneduration >= duration ) {
00324         kdDebug(5850) << "The dissociated event already occurred more often "
00325                       << "than it was supposed to ever occur. ERROR!" << endl;
00326         recur->clear();
00327       } else {
00328         recur->setDuration( duration - doneduration );
00329       }
00330     }
00331   }
00332   // Adjust the date of the incidence
00333   if ( incidence->type() == "Event" ) {
00334     Event *ev = static_cast<Event *>( newInc );
00335     QDateTime start( ev->dtStart() );
00336     int daysTo = start.date().daysTo( date );
00337     ev->setDtStart( start.addDays( daysTo ) );
00338     ev->setDtEnd( ev->dtEnd().addDays( daysTo ) );
00339   } else if ( incidence->type() == "Todo" ) {
00340     Todo *td = static_cast<Todo *>( newInc );
00341     bool haveOffset = false;
00342     int daysTo = 0;
00343     if ( td->hasDueDate() ) {
00344       QDateTime due( td->dtDue() );
00345       daysTo = due.date().daysTo( date );
00346       td->setDtDue( due.addDays( daysTo ), true );
00347       haveOffset = true;
00348     }
00349     if ( td->hasStartDate() ) {
00350       QDateTime start( td->dtStart() );
00351       if ( !haveOffset )
00352         daysTo = start.date().daysTo( date );
00353       td->setDtStart( start.addDays( daysTo ) );
00354       haveOffset = true;
00355     }
00356   }
00357   recur = incidence->recurrence();
00358   if ( recur ) {
00359     if ( single ) {
00360       recur->addExDate( date );
00361     } else {
00362       // Make sure the recurrence of the past events ends
00363       // at the corresponding day
00364       recur->setEndDate( date.addDays(-1) );
00365     }
00366   }
00367   return newInc;
00368 }
00369 
00370 Incidence *Calendar::incidence( const QString &uid )
00371 {
00372   Incidence *i = event( uid );
00373   if ( i )
00374     return i;
00375   i = todo( uid );
00376   if ( i )
00377     return i;
00378   i = journal( uid );
00379   return i;
00380 }
00381 
00382 Incidence::List Calendar::incidencesFromSchedulingID( const QString &UID )
00383 {
00384   Incidence::List result;
00385   Incidence::List incidences = rawIncidences();
00386   Incidence::List::iterator it = incidences.begin();
00387   for ( ; it != incidences.end(); ++it )
00388     if ( (*it)->schedulingID() == UID )
00389       result.append( *it );
00390   return result;
00391 }
00392 
00393 Incidence *Calendar::incidenceFromSchedulingID( const QString &UID )
00394 {
00395   Incidence::List incidences = rawIncidences();
00396   Incidence::List::iterator it = incidences.begin();
00397   for ( ; it != incidences.end(); ++it )
00398     if ( (*it)->schedulingID() == UID )
00399       // Touchdown, and the crowd goes wild
00400       return *it;
00401   // Not found
00402   return 0;
00403 }
00404 
00405 Todo::List Calendar::sortTodos( Todo::List *todoList,
00406                                 TodoSortField sortField,
00407                                 SortDirection sortDirection )
00408 {
00409   Todo::List todoListSorted;
00410   Todo::List tempList, t;
00411   Todo::List alphaList;
00412   Todo::List::Iterator sortIt;
00413   Todo::List::Iterator eit;
00414 
00415   // Notice we alphabetically presort Summaries first.
00416   // We do this so comparison "ties" stay in a nice order.
00417 
00418   // Note that Todos may not have Start DateTimes nor due DateTimes.
00419 
00420   switch( sortField ) {
00421   case TodoSortUnsorted:
00422     todoListSorted = *todoList;
00423     break;
00424 
00425   case TodoSortStartDate:
00426     alphaList = sortTodos( todoList, TodoSortSummary, sortDirection );
00427     for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00428       if ( (*eit)->hasStartDate() ) {
00429         sortIt = todoListSorted.begin();
00430         if ( sortDirection == SortDirectionAscending ) {
00431           while ( sortIt != todoListSorted.end() &&
00432                   (*eit)->dtStart() >= (*sortIt)->dtStart() ) {
00433             ++sortIt;
00434           }
00435         } else {
00436           while ( sortIt != todoListSorted.end() &&
00437                   (*eit)->dtStart() < (*sortIt)->dtStart() ) {
00438             ++sortIt;
00439           }
00440         }
00441         todoListSorted.insert( sortIt, *eit );
00442       } else {
00443         // Keep a list of the Todos without Start DateTimes
00444         tempList.append( *eit );
00445       }
00446     }
00447     if ( sortDirection == SortDirectionAscending ) {
00448       // Append the list of Todos without Start DateTimes
00449       todoListSorted += tempList;
00450     } else {
00451       // Prepend the list of Todos without Start DateTimes
00452       tempList += todoListSorted;
00453       todoListSorted = tempList;
00454     }
00455     break;
00456 
00457   case TodoSortDueDate:
00458     alphaList = sortTodos( todoList, TodoSortSummary, sortDirection );
00459     for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00460       if ( (*eit)->hasDueDate() ) {
00461         sortIt = todoListSorted.begin();
00462         if ( sortDirection == SortDirectionAscending ) {
00463           while ( sortIt != todoListSorted.end() &&
00464                   (*eit)->dtDue() >= (*sortIt)->dtDue() ) {
00465             ++sortIt;
00466           }
00467         } else {
00468           while ( sortIt != todoListSorted.end() &&
00469                   (*eit)->dtDue() < (*sortIt)->dtDue() ) {
00470             ++sortIt;
00471           }
00472         }
00473         todoListSorted.insert( sortIt, *eit );
00474       } else {
00475         // Keep a list of the Todos without Due DateTimes
00476         tempList.append( *eit );
00477       }
00478     }
00479     if ( sortDirection == SortDirectionAscending ) {
00480       // Append the list of Todos without Due DateTimes
00481       todoListSorted += tempList;
00482     } else {
00483       // Prepend the list of Todos without Due DateTimes
00484       tempList += todoListSorted;
00485       todoListSorted = tempList;
00486     }
00487     break;
00488 
00489   case TodoSortPriority:
00490     alphaList = sortTodos( todoList, TodoSortSummary, sortDirection );
00491     for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00492       sortIt = todoListSorted.begin();
00493       if ( sortDirection == SortDirectionAscending ) {
00494         while ( sortIt != todoListSorted.end() &&
00495                 (*eit)->priority() >= (*sortIt)->priority() ) {
00496           ++sortIt;
00497         }
00498       } else {
00499         while ( sortIt != todoListSorted.end() &&
00500                 (*eit)->priority() < (*sortIt)->priority() ) {
00501           ++sortIt;
00502         }
00503       }
00504       todoListSorted.insert( sortIt, *eit );
00505     }
00506     break;
00507 
00508   case TodoSortPercentComplete:
00509     alphaList = sortTodos( todoList, TodoSortSummary, sortDirection );
00510     for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00511       sortIt = todoListSorted.begin();
00512       if ( sortDirection == SortDirectionAscending ) {
00513         while ( sortIt != todoListSorted.end() &&
00514                 (*eit)->percentComplete() >= (*sortIt)->percentComplete() ) {
00515           ++sortIt;
00516         }
00517       } else {
00518         while ( sortIt != todoListSorted.end() &&
00519                 (*eit)->percentComplete() < (*sortIt)->percentComplete() ) {
00520           ++sortIt;
00521         }
00522       }
00523       todoListSorted.insert( sortIt, *eit );
00524     }
00525     break;
00526 
00527   case TodoSortSummary:
00528     for ( eit = todoList->begin(); eit != todoList->end(); ++eit ) {
00529       sortIt = todoListSorted.begin();
00530       if ( sortDirection == SortDirectionAscending ) {
00531         while ( sortIt != todoListSorted.end() &&
00532                 (*eit)->summary() >= (*sortIt)->summary() ) {
00533           ++sortIt;
00534         }
00535       } else {
00536         while ( sortIt != todoListSorted.end() &&
00537                 (*eit)->summary() < (*sortIt)->summary() ) {
00538           ++sortIt;
00539         }
00540       }
00541       todoListSorted.insert( sortIt, *eit );
00542     }
00543     break;
00544   }
00545 
00546   return todoListSorted;
00547 }
00548 
00549 Todo::List Calendar::todos( TodoSortField sortField,
00550                             SortDirection sortDirection )
00551 {
00552   Todo::List tl = rawTodos( sortField, sortDirection );
00553   mFilter->apply( &tl );
00554   return tl;
00555 }
00556 
00557 Todo::List Calendar::todos( const QDate &date )
00558 {
00559   Todo::List el = rawTodosForDate( date );
00560   mFilter->apply( &el );
00561   return el;
00562 }
00563 
00564 Journal::List Calendar::sortJournals( Journal::List *journalList,
00565                                       JournalSortField sortField,
00566                                       SortDirection sortDirection )
00567 {
00568   Journal::List journalListSorted;
00569   Journal::List::Iterator sortIt;
00570   Journal::List::Iterator eit;
00571 
00572   switch( sortField ) {
00573   case JournalSortUnsorted:
00574     journalListSorted = *journalList;
00575     break;
00576 
00577   case JournalSortDate:
00578     for ( eit = journalList->begin(); eit != journalList->end(); ++eit ) {
00579       sortIt = journalListSorted.begin();
00580       if ( sortDirection == SortDirectionAscending ) {
00581         while ( sortIt != journalListSorted.end() &&
00582                 (*eit)->dtStart() >= (*sortIt)->dtStart() ) {
00583           ++sortIt;
00584         }
00585       } else {
00586         while ( sortIt != journalListSorted.end() &&
00587                 (*eit)->dtStart() < (*sortIt)->dtStart() ) {
00588           ++sortIt;
00589         }
00590       }
00591       journalListSorted.insert( sortIt, *eit );
00592     }
00593     break;
00594 
00595   case JournalSortSummary:
00596     for ( eit = journalList->begin(); eit != journalList->end(); ++eit ) {
00597       sortIt = journalListSorted.begin();
00598       if ( sortDirection == SortDirectionAscending ) {
00599         while ( sortIt != journalListSorted.end() &&
00600                 (*eit)->summary() >= (*sortIt)->summary() ) {
00601           ++sortIt;
00602         }
00603       } else {
00604         while ( sortIt != journalListSorted.end() &&
00605                 (*eit)->summary() < (*sortIt)->summary() ) {
00606           ++sortIt;
00607         }
00608       }
00609       journalListSorted.insert( sortIt, *eit );
00610     }
00611     break;
00612   }
00613 
00614   return journalListSorted;
00615 }
00616 
00617 Journal::List Calendar::journals( JournalSortField sortField,
00618                                   SortDirection sortDirection )
00619 {
00620   Journal::List jl = rawJournals( sortField, sortDirection );
00621   mFilter->apply( &jl );
00622   return jl;
00623 }
00624 
00625 Journal::List Calendar::journals( const QDate &date )
00626 {
00627   Journal::List el = rawJournalsForDate( date );
00628   mFilter->apply( &el );
00629   return el;
00630 }
00631 
00632 // When this is called, the todo have already been added to the calendar.
00633 // This method is only about linking related todos
00634 void Calendar::setupRelations( Incidence *forincidence )
00635 {
00636   if ( !forincidence ) return;
00637 // kdDebug(5850) << "Calendar::setupRelations for incidence " << forincidence << " with UID " << forincidence->uid() << ", summary: " << forincidence->summary() << endl;
00638   QString uid = forincidence->uid();
00639 
00640   // First, go over the list of orphans and see if this is their parent
00641   while ( Incidence* i = mOrphans[ uid ] ) {
00642     mOrphans.remove( uid );
00643     i->setRelatedTo( forincidence );
00644     forincidence->addRelation( i );
00645     mOrphanUids.remove( i->uid() );
00646   }
00647 
00648   // Now see about this incidences parent
00649   if ( !forincidence->relatedTo() && !forincidence->relatedToUid().isEmpty() ) {
00650     // This incidence has a uid it is related to but is not registered to it yet
00651     // Try to find it
00652     Incidence* parent = incidence( forincidence->relatedToUid() );
00653     if ( parent ) {
00654       // Found it
00655       forincidence->setRelatedTo( parent );
00656       parent->addRelation( forincidence );
00657     } else {
00658       // Not found, put this in the mOrphans list
00659       // Note that the mOrphans dict might have several entries with the same key! That are
00660       // multiple children that wait for the parent incidence to be inserted.
00661       mOrphans.insert( forincidence->relatedToUid(), forincidence );
00662       mOrphanUids.insert( forincidence->uid(), forincidence );
00663     }
00664   }
00665 }
00666 
00667 // If a task with subtasks is deleted, move it's subtasks to the orphans list
00668 void Calendar::removeRelations( Incidence *incidence )
00669 {
00670   if( !incidence ) {
00671     kdDebug(5800) << "Warning: Calendar::removeRelations( 0 )!\n";
00672     return;
00673   }
00674 
00675 // kdDebug(5850) << "Calendar::removeRelations for incidence " << forincidence << " with UID " << forincidence->uid() << ", summary: " << forincidence->summary() << endl;
00676   QString uid = incidence->uid();
00677 
00678   Incidence::List relations = incidence->relations();
00679   Incidence::List::ConstIterator it;
00680   for ( it = relations.begin(); it != relations.end(); ++it ) {
00681     Incidence *i = *it;
00682     if ( !mOrphanUids.find( i->uid() ) ) {
00683       mOrphans.insert( uid, i );
00684       mOrphanUids.insert( i->uid(), i );
00685       i->setRelatedTo( 0 );
00686       i->setRelatedToUid( uid );
00687     }
00688   }
00689 
00690   // If this incidence is related to something else, tell that about it
00691   if ( incidence->relatedTo() )
00692     incidence->relatedTo()->removeRelation( incidence );
00693 
00694   // Remove this one from the orphans list
00695   if ( mOrphanUids.remove( uid ) ) {
00696     // This incidence is located in the orphans list - it should be removed
00697     // Since the mOrphans dict might contain the same key (with different
00698     // child incidence pointers!) multiple times, take care that we remove
00699     // the correct one. So we need to remove all items with the given
00700     // parent UID, and readd those that are not for this item. Also, there
00701     // might be other entries with differnet UID that point to this
00702     // incidence (this might happen when the relatedTo of the item is
00703     // changed before its parent is inserted. This might happen with
00704     // groupware servers....). Remove them, too
00705     QStringList relatedToUids;
00706     // First get the list of all keys in the mOrphans list that point to the removed item
00707     relatedToUids << incidence->relatedToUid();
00708     for ( QDictIterator<Incidence> it( mOrphans ); it.current(); ++it ) {
00709       if ( it.current()->uid() == uid ) {
00710         relatedToUids << it.currentKey();
00711       }
00712     }
00713 
00714     // now go through all uids that have one entry that point to the incidence
00715     for ( QStringList::Iterator uidit = relatedToUids.begin();
00716           uidit != relatedToUids.end(); ++uidit ) {
00717       Incidence::List tempList;
00718       // Remove all to get access to the remaining entries
00719       while( Incidence* i = mOrphans[ *uidit ] ) {
00720         mOrphans.remove( *uidit );
00721         if ( i != incidence ) tempList.append( i );
00722       }
00723       // Readd those that point to a different orphan incidence
00724       for ( Incidence::List::Iterator incit = tempList.begin();
00725             incit != tempList.end(); ++incit ) {
00726         mOrphans.insert( *uidit, *incit );
00727       }
00728     }
00729   }
00730 }
00731 
00732 void Calendar::registerObserver( Observer *observer )
00733 {
00734   if( !mObservers.contains( observer ) )
00735     mObservers.append( observer );
00736   mNewObserver = true;
00737 }
00738 
00739 void Calendar::unregisterObserver( Observer *observer )
00740 {
00741   mObservers.remove( observer );
00742 }
00743 
00744 void Calendar::setModified( bool modified )
00745 {
00746   if ( modified != mModified || mNewObserver ) {
00747     mNewObserver = false;
00748     Observer *observer;
00749     for ( observer = mObservers.first(); observer;
00750           observer = mObservers.next() ) {
00751       observer->calendarModified( modified, this );
00752     }
00753     mModified = modified;
00754   }
00755 }
00756 
00757 void Calendar::incidenceUpdated( IncidenceBase *incidence )
00758 {
00759   incidence->setSyncStatus( Event::SYNCMOD );
00760   incidence->setLastModified( QDateTime::currentDateTime() );
00761   // we should probably update the revision number here,
00762   // or internally in the Event itself when certain things change.
00763   // need to verify with ical documentation.
00764 
00765   // The static_cast is ok as the CalendarLocal only observes Incidence objects
00766   notifyIncidenceChanged( static_cast<Incidence *>( incidence ) );
00767 
00768   setModified( true );
00769 }
00770 
00771 void Calendar::notifyIncidenceAdded( Incidence *i )
00772 {
00773   if ( !mObserversEnabled )
00774     return;
00775 
00776   Observer *observer;
00777   for ( observer = mObservers.first(); observer;
00778         observer = mObservers.next() ) {
00779     observer->calendarIncidenceAdded( i );
00780   }
00781 }
00782 
00783 void Calendar::notifyIncidenceChanged( Incidence *i )
00784 {
00785   if ( !mObserversEnabled )
00786     return;
00787 
00788   Observer *observer;
00789   for ( observer = mObservers.first(); observer;
00790         observer = mObservers.next() ) {
00791     observer->calendarIncidenceChanged( i );
00792   }
00793 }
00794 
00795 void Calendar::notifyIncidenceDeleted( Incidence *i )
00796 {
00797   if ( !mObserversEnabled )
00798     return;
00799 
00800   Observer *observer;
00801   for ( observer = mObservers.first(); observer;
00802         observer = mObservers.next() ) {
00803     observer->calendarIncidenceDeleted( i );
00804   }
00805 }
00806 
00807 void Calendar::customPropertyUpdated()
00808 {
00809   setModified( true );
00810 }
00811 
00812 void Calendar::setProductId( const QString &productId )
00813 {
00814   mProductId = productId;
00815 }
00816 
00817 QString Calendar::productId()
00818 {
00819   return mProductId;
00820 }
00821 
00822 Incidence::List Calendar::mergeIncidenceList( const Event::List &events,
00823                                               const Todo::List &todos,
00824                                               const Journal::List &journals )
00825 {
00826   Incidence::List incidences;
00827 
00828   Event::List::ConstIterator it1;
00829   for ( it1 = events.begin(); it1 != events.end(); ++it1 )
00830     incidences.append( *it1 );
00831 
00832   Todo::List::ConstIterator it2;
00833   for ( it2 = todos.begin(); it2 != todos.end(); ++it2 )
00834     incidences.append( *it2 );
00835 
00836   Journal::List::ConstIterator it3;
00837   for ( it3 = journals.begin(); it3 != journals.end(); ++it3 )
00838     incidences.append( *it3 );
00839 
00840   return incidences;
00841 }
00842 
00843 bool Calendar::beginChange( Incidence * )
00844 {
00845   return true;
00846 }
00847 
00848 bool Calendar::endChange( Incidence * )
00849 {
00850   return true;
00851 }
00852 
00853 void Calendar::setObserversEnabled( bool enabled )
00854 {
00855   mObserversEnabled = enabled;
00856 }
00857 
00858 #include "calendar.moc"