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