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 <tdelocale.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       if (it != il.end()) {
00483         parentIncidence = this->incidence(*it);
00484         parentIncidence->deleteChildIncidence(incidence->uid());
00485       }
00486     }
00487     else {
00488       // Delete all children as well
00489       IncidenceList il = incidence->childIncidences();
00490       IncidenceListIterator it;
00491       for ( it = il.begin(); it != il.end(); ++it ) {
00492         deleteIncidence( this->incidence(*it) );
00493         // Avoid a crash, reset the iterator every time the list is modified
00494         it = il.begin();
00495       }
00496     }
00497     Incidence::DeleteVisitor<Calendar> v( this );
00498     bool result = incidence->accept( v );
00499     endChange( incidence );
00500     return result;
00501   } else
00502     return false;
00503 }
00504 
00508 Incidence *Calendar::dissociateOccurrence( Incidence *incidence, TQDate date,
00509                                            bool single )
00510 {
00511   if ( !incidence || !incidence->doesRecur() )
00512     return 0;
00513 
00514   Incidence *newInc = incidence->clone();
00515   newInc->recreate();
00516   newInc->setHasRecurrenceID(false);
00517 //  newInc->setRecurrenceID(TQString());
00518   newInc->setRelatedTo( incidence );
00519   Recurrence *recur = newInc->recurrence();
00520   if ( single ) {
00521     recur->clear();
00522   } else {
00523     // Adjust the recurrence for the future incidences. In particular
00524     // adjust the "end after n occurrences" rules! "No end date" and "end by ..."
00525     // don't need to be modified.
00526     int duration = recur->duration();
00527     if ( duration > 0 ) {
00528       int doneduration = recur->durationTo( date.addDays(-1) );
00529       if ( doneduration >= duration ) {
00530         kdDebug(5850) << "The dissociated event already occurred more often "
00531                       << "than it was supposed to ever occur. ERROR!" << endl;
00532         recur->clear();
00533       } else {
00534         recur->setDuration( duration - doneduration );
00535       }
00536     }
00537   }
00538   // Adjust the date of the incidence
00539   if ( incidence->type() == "Event" ) {
00540     Event *ev = static_cast<Event *>( newInc );
00541     TQDateTime start( ev->dtStart() );
00542     int daysTo = start.date().daysTo( date );
00543     ev->setDtStart( start.addDays( daysTo ) );
00544     ev->setDtEnd( ev->dtEnd().addDays( daysTo ) );
00545   } else if ( incidence->type() == "Todo" ) {
00546     Todo *td = static_cast<Todo *>( newInc );
00547     bool haveOffset = false;
00548     int daysTo = 0;
00549     if ( td->hasDueDate() ) {
00550       TQDateTime due( td->dtDue() );
00551       daysTo = due.date().daysTo( date );
00552       td->setDtDue( due.addDays( daysTo ), true );
00553       haveOffset = true;
00554     }
00555     if ( td->hasStartDate() ) {
00556       TQDateTime start( td->dtStart() );
00557       if ( !haveOffset )
00558         daysTo = start.date().daysTo( date );
00559       td->setDtStart( start.addDays( daysTo ) );
00560       haveOffset = true;
00561     }
00562   }
00563   recur = incidence->recurrence();
00564   if ( recur ) {
00565     if ( single ) {
00566       recur->addExDate( date );
00567     } else {
00568       // Make sure the recurrence of the past events ends
00569       // at the corresponding day
00570       recur->setEndDate( date.addDays(-1) );
00571     }
00572   }
00573   return newInc;
00574 }
00575 
00576 Incidence *Calendar::incidence( const TQString &uid )
00577 {
00578   Incidence *i = event( uid );
00579   if ( i )
00580     return i;
00581   i = todo( uid );
00582   if ( i )
00583     return i;
00584   i = journal( uid );
00585   return i;
00586 }
00587 
00588 Incidence::List Calendar::incidencesFromSchedulingID( const TQString &UID )
00589 {
00590   Incidence::List result;
00591   Incidence::List incidences = rawIncidences();
00592   Incidence::List::iterator it = incidences.begin();
00593   for ( ; it != incidences.end(); ++it )
00594     if ( (*it)->schedulingID() == UID )
00595       result.append( *it );
00596   return result;
00597 }
00598 
00599 Incidence *Calendar::incidenceFromSchedulingID( const TQString &UID )
00600 {
00601   Incidence::List incidences = rawIncidences();
00602   Incidence::List::iterator it = incidences.begin();
00603   for ( ; it != incidences.end(); ++it )
00604     if ( (*it)->schedulingID() == UID )
00605       // Touchdown, and the crowd goes wild
00606       return *it;
00607   // Not found
00608   return 0;
00609 }
00610 
00611 Todo::List Calendar::sortTodos( Todo::List *todoList,
00612                                 TodoSortField sortField,
00613                                 SortDirection sortDirection )
00614 {
00615   Todo::List todoListSorted;
00616   Todo::List tempList, t;
00617   Todo::List alphaList;
00618   Todo::List::Iterator sortIt;
00619   Todo::List::Iterator eit;
00620 
00621   // Notice we alphabetically presort Summaries first.
00622   // We do this so comparison "ties" stay in a nice order.
00623 
00624   // Note that Todos may not have Start DateTimes nor due DateTimes.
00625 
00626   switch( sortField ) {
00627   case TodoSortUnsorted:
00628     todoListSorted = *todoList;
00629     break;
00630 
00631   case TodoSortStartDate:
00632     alphaList = sortTodos( todoList, TodoSortSummary, sortDirection );
00633     for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00634       if ( (*eit)->hasStartDate() ) {
00635         sortIt = todoListSorted.begin();
00636         if ( sortDirection == SortDirectionAscending ) {
00637           while ( sortIt != todoListSorted.end() &&
00638                   (*eit)->dtStart() >= (*sortIt)->dtStart() ) {
00639             ++sortIt;
00640           }
00641         } else {
00642           while ( sortIt != todoListSorted.end() &&
00643                   (*eit)->dtStart() < (*sortIt)->dtStart() ) {
00644             ++sortIt;
00645           }
00646         }
00647         todoListSorted.insert( sortIt, *eit );
00648       } else {
00649         // Keep a list of the Todos without Start DateTimes
00650         tempList.append( *eit );
00651       }
00652     }
00653     if ( sortDirection == SortDirectionAscending ) {
00654       // Append the list of Todos without Start DateTimes
00655       todoListSorted += tempList;
00656     } else {
00657       // Prepend the list of Todos without Start DateTimes
00658       tempList += todoListSorted;
00659       todoListSorted = tempList;
00660     }
00661     break;
00662 
00663   case TodoSortDueDate:
00664     alphaList = sortTodos( todoList, TodoSortSummary, sortDirection );
00665     for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00666       if ( (*eit)->hasDueDate() ) {
00667         sortIt = todoListSorted.begin();
00668         if ( sortDirection == SortDirectionAscending ) {
00669           while ( sortIt != todoListSorted.end() &&
00670                   (*eit)->dtDue() >= (*sortIt)->dtDue() ) {
00671             ++sortIt;
00672           }
00673         } else {
00674           while ( sortIt != todoListSorted.end() &&
00675                   (*eit)->dtDue() < (*sortIt)->dtDue() ) {
00676             ++sortIt;
00677           }
00678         }
00679         todoListSorted.insert( sortIt, *eit );
00680       } else {
00681         // Keep a list of the Todos without Due DateTimes
00682         tempList.append( *eit );
00683       }
00684     }
00685     if ( sortDirection == SortDirectionAscending ) {
00686       // Append the list of Todos without Due DateTimes
00687       todoListSorted += tempList;
00688     } else {
00689       // Prepend the list of Todos without Due DateTimes
00690       tempList += todoListSorted;
00691       todoListSorted = tempList;
00692     }
00693     break;
00694 
00695   case TodoSortPriority:
00696     alphaList = sortTodos( todoList, TodoSortSummary, sortDirection );
00697     for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00698       sortIt = todoListSorted.begin();
00699       if ( sortDirection == SortDirectionAscending ) {
00700         while ( sortIt != todoListSorted.end() &&
00701                 (*eit)->priority() >= (*sortIt)->priority() ) {
00702           ++sortIt;
00703         }
00704       } else {
00705         while ( sortIt != todoListSorted.end() &&
00706                 (*eit)->priority() < (*sortIt)->priority() ) {
00707           ++sortIt;
00708         }
00709       }
00710       todoListSorted.insert( sortIt, *eit );
00711     }
00712     break;
00713 
00714   case TodoSortPercentComplete:
00715     alphaList = sortTodos( todoList, TodoSortSummary, sortDirection );
00716     for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00717       sortIt = todoListSorted.begin();
00718       if ( sortDirection == SortDirectionAscending ) {
00719         while ( sortIt != todoListSorted.end() &&
00720                 (*eit)->percentComplete() >= (*sortIt)->percentComplete() ) {
00721           ++sortIt;
00722         }
00723       } else {
00724         while ( sortIt != todoListSorted.end() &&
00725                 (*eit)->percentComplete() < (*sortIt)->percentComplete() ) {
00726           ++sortIt;
00727         }
00728       }
00729       todoListSorted.insert( sortIt, *eit );
00730     }
00731     break;
00732 
00733   case TodoSortSummary:
00734     for ( eit = todoList->begin(); eit != todoList->end(); ++eit ) {
00735       sortIt = todoListSorted.begin();
00736       if ( sortDirection == SortDirectionAscending ) {
00737         while ( sortIt != todoListSorted.end() &&
00738                 (*eit)->summary() >= (*sortIt)->summary() ) {
00739           ++sortIt;
00740         }
00741       } else {
00742         while ( sortIt != todoListSorted.end() &&
00743                 (*eit)->summary() < (*sortIt)->summary() ) {
00744           ++sortIt;
00745         }
00746       }
00747       todoListSorted.insert( sortIt, *eit );
00748     }
00749     break;
00750   }
00751 
00752   return todoListSorted;
00753 }
00754 
00755 Todo::List Calendar::todos( TodoSortField sortField,
00756                             SortDirection sortDirection )
00757 {
00758   Todo::List tl = rawTodos( sortField, sortDirection );
00759   mFilter->apply( &tl );
00760   return tl;
00761 }
00762 
00763 Todo::List Calendar::todos( const TQDate &date )
00764 {
00765   Todo::List el = rawTodosForDate( date );
00766   mFilter->apply( &el );
00767   return el;
00768 }
00769 
00770 Journal::List Calendar::sortJournals( Journal::List *journalList,
00771                                       JournalSortField sortField,
00772                                       SortDirection sortDirection )
00773 {
00774   Journal::List journalListSorted;
00775   Journal::List::Iterator sortIt;
00776   Journal::List::Iterator eit;
00777 
00778   switch( sortField ) {
00779   case JournalSortUnsorted:
00780     journalListSorted = *journalList;
00781     break;
00782 
00783   case JournalSortDate:
00784     for ( eit = journalList->begin(); eit != journalList->end(); ++eit ) {
00785       sortIt = journalListSorted.begin();
00786       if ( sortDirection == SortDirectionAscending ) {
00787         while ( sortIt != journalListSorted.end() &&
00788                 (*eit)->dtStart() >= (*sortIt)->dtStart() ) {
00789           ++sortIt;
00790         }
00791       } else {
00792         while ( sortIt != journalListSorted.end() &&
00793                 (*eit)->dtStart() < (*sortIt)->dtStart() ) {
00794           ++sortIt;
00795         }
00796       }
00797       journalListSorted.insert( sortIt, *eit );
00798     }
00799     break;
00800 
00801   case JournalSortSummary:
00802     for ( eit = journalList->begin(); eit != journalList->end(); ++eit ) {
00803       sortIt = journalListSorted.begin();
00804       if ( sortDirection == SortDirectionAscending ) {
00805         while ( sortIt != journalListSorted.end() &&
00806                 (*eit)->summary() >= (*sortIt)->summary() ) {
00807           ++sortIt;
00808         }
00809       } else {
00810         while ( sortIt != journalListSorted.end() &&
00811                 (*eit)->summary() < (*sortIt)->summary() ) {
00812           ++sortIt;
00813         }
00814       }
00815       journalListSorted.insert( sortIt, *eit );
00816     }
00817     break;
00818   }
00819 
00820   return journalListSorted;
00821 }
00822 
00823 Journal::List Calendar::journals( JournalSortField sortField,
00824                                   SortDirection sortDirection )
00825 {
00826   Journal::List jl = rawJournals( sortField, sortDirection );
00827   mFilter->apply( &jl );
00828   return jl;
00829 }
00830 
00831 Journal::List Calendar::journals( const TQDate &date )
00832 {
00833   Journal::List el = rawJournalsForDate( date );
00834   mFilter->apply( &el );
00835   return el;
00836 }
00837 
00838 // When this is called, the todo have already been added to the calendar.
00839 // This method is only about linking related todos
00840 void Calendar::setupRelations( Incidence *forincidence )
00841 {
00842   if ( !forincidence ) return;
00843 // kdDebug(5850) << "Calendar::setupRelations for incidence " << forincidence << " with UID " << forincidence->uid() << ", summary: " << forincidence->summary() << endl;
00844   TQString uid = forincidence->uid();
00845 
00846   // First, go over the list of orphans and see if this is their parent
00847   while ( Incidence* i = mOrphans[ uid ] ) {
00848     mOrphans.remove( uid );
00849     i->setRelatedTo( forincidence );
00850     forincidence->addRelation( i );
00851     mOrphanUids.remove( i->uid() );
00852   }
00853 
00854   // Now see about this incidences parent
00855   if ( !forincidence->relatedTo() && !forincidence->relatedToUid().isEmpty() ) {
00856     // This incidence has a uid it is related to but is not registered to it yet
00857     // Try to find it
00858     Incidence* parent = incidence( forincidence->relatedToUid() );
00859     if ( parent ) {
00860       // Found it
00861       forincidence->setRelatedTo( parent );
00862       parent->addRelation( forincidence );
00863     } else {
00864       // Not found, put this in the mOrphans list
00865       // Note that the mOrphans dict might have several entries with the same key! That are
00866       // multiple children that wait for the parent incidence to be inserted.
00867       mOrphans.insert( forincidence->relatedToUid(), forincidence );
00868       mOrphanUids.insert( forincidence->uid(), forincidence );
00869     }
00870   }
00871 }
00872 
00873 // If a task with subtasks is deleted, move it's subtasks to the orphans list
00874 void Calendar::removeRelations( Incidence *incidence )
00875 {
00876   if( !incidence ) {
00877     kdDebug(5800) << "Warning: Calendar::removeRelations( 0 )!\n";
00878     return;
00879   }
00880 
00881 // kdDebug(5850) << "Calendar::removeRelations for incidence " << forincidence << " with UID " << forincidence->uid() << ", summary: " << forincidence->summary() << endl;
00882   TQString uid = incidence->uid();
00883 
00884   Incidence::List relations = incidence->relations();
00885   Incidence::List::ConstIterator it;
00886   for ( it = relations.begin(); it != relations.end(); ++it ) {
00887     Incidence *i = *it;
00888     if ( !mOrphanUids.find( i->uid() ) ) {
00889       mOrphans.insert( uid, i );
00890       mOrphanUids.insert( i->uid(), i );
00891       i->setRelatedTo( 0 );
00892       i->setRelatedToUid( uid );
00893     }
00894   }
00895 
00896   // If this incidence is related to something else, tell that about it
00897   if ( incidence->relatedTo() )
00898     incidence->relatedTo()->removeRelation( incidence );
00899 
00900   // Remove this one from the orphans list
00901   if ( mOrphanUids.remove( uid ) ) {
00902     // This incidence is located in the orphans list - it should be removed
00903     // Since the mOrphans dict might contain the same key (with different
00904     // child incidence pointers!) multiple times, take care that we remove
00905     // the correct one. So we need to remove all items with the given
00906     // parent UID, and readd those that are not for this item. Also, there
00907     // might be other entries with differnet UID that point to this
00908     // incidence (this might happen when the relatedTo of the item is
00909     // changed before its parent is inserted. This might happen with
00910     // groupware servers....). Remove them, too
00911     TQStringList relatedToUids;
00912     // First get the list of all keys in the mOrphans list that point to the removed item
00913     relatedToUids << incidence->relatedToUid();
00914     for ( TQDictIterator<Incidence> it( mOrphans ); it.current(); ++it ) {
00915       if ( it.current()->uid() == uid ) {
00916         relatedToUids << it.currentKey();
00917       }
00918     }
00919 
00920     // now go through all uids that have one entry that point to the incidence
00921     for ( TQStringList::Iterator uidit = relatedToUids.begin();
00922           uidit != relatedToUids.end(); ++uidit ) {
00923       Incidence::List tempList;
00924       // Remove all to get access to the remaining entries
00925       while( Incidence* i = mOrphans[ *uidit ] ) {
00926         mOrphans.remove( *uidit );
00927         if ( i != incidence ) tempList.append( i );
00928       }
00929       // Readd those that point to a different orphan incidence
00930       for ( Incidence::List::Iterator incit = tempList.begin();
00931             incit != tempList.end(); ++incit ) {
00932         mOrphans.insert( *uidit, *incit );
00933       }
00934     }
00935   }
00936 }
00937 
00938 void Calendar::registerObserver( Observer *observer )
00939 {
00940   if( !mObservers.contains( observer ) )
00941     mObservers.append( observer );
00942   mNewObserver = true;
00943 }
00944 
00945 void Calendar::unregisterObserver( Observer *observer )
00946 {
00947   mObservers.remove( observer );
00948 }
00949 
00950 void Calendar::setModified( bool modified )
00951 {
00952   if ( modified != mModified || mNewObserver ) {
00953     mNewObserver = false;
00954     Observer *observer;
00955     for ( observer = mObservers.first(); observer;
00956           observer = mObservers.next() ) {
00957       observer->calendarModified( modified, this );
00958     }
00959     mModified = modified;
00960   }
00961 }
00962 
00963 void Calendar::incidenceUpdated( IncidenceBase *incidence )
00964 {
00965   incidence->setSyncStatus( Event::SYNCMOD );
00966   incidence->setLastModified( TQDateTime::currentDateTime() );
00967   // we should probably update the revision number here,
00968   // or internally in the Event itself when certain things change.
00969   // need to verify with ical documentation.
00970 
00971   // The static_cast is ok as the CalendarLocal only observes Incidence objects
00972   notifyIncidenceChanged( static_cast<Incidence *>( incidence ) );
00973 
00974   setModified( true );
00975 }
00976 
00977 void Calendar::notifyIncidenceAdded( Incidence *i )
00978 {
00979   if ( !mObserversEnabled )
00980     return;
00981 
00982   Observer *observer;
00983   for ( observer = mObservers.first(); observer;
00984         observer = mObservers.next() ) {
00985     observer->calendarIncidenceAdded( i );
00986   }
00987 }
00988 
00989 void Calendar::notifyIncidenceChanged( Incidence *i )
00990 {
00991   if ( !mObserversEnabled )
00992     return;
00993 
00994   Observer *observer;
00995   for ( observer = mObservers.first(); observer;
00996         observer = mObservers.next() ) {
00997     observer->calendarIncidenceChanged( i );
00998   }
00999 }
01000 
01001 void Calendar::notifyIncidenceDeleted( Incidence *i )
01002 {
01003   if ( !mObserversEnabled )
01004     return;
01005 
01006   Observer *observer;
01007   for ( observer = mObservers.first(); observer;
01008         observer = mObservers.next() ) {
01009     observer->calendarIncidenceDeleted( i );
01010   }
01011 }
01012 
01013 void Calendar::customPropertyUpdated()
01014 {
01015   setModified( true );
01016 }
01017 
01018 void Calendar::setProductId( const TQString &productId )
01019 {
01020   mProductId = productId;
01021 }
01022 
01023 TQString Calendar::productId()
01024 {
01025   return mProductId;
01026 }
01027 
01028 Incidence::List Calendar::mergeIncidenceList( const Event::List &events,
01029                                               const Todo::List &todos,
01030                                               const Journal::List &journals )
01031 {
01032   Incidence::List incidences;
01033 
01034   Event::List::ConstIterator it1;
01035   for ( it1 = events.begin(); it1 != events.end(); ++it1 )
01036     incidences.append( *it1 );
01037 
01038   Todo::List::ConstIterator it2;
01039   for ( it2 = todos.begin(); it2 != todos.end(); ++it2 )
01040     incidences.append( *it2 );
01041 
01042   Journal::List::ConstIterator it3;
01043   for ( it3 = journals.begin(); it3 != journals.end(); ++it3 )
01044     incidences.append( *it3 );
01045 
01046   return incidences;
01047 }
01048 
01049 bool Calendar::beginChange( Incidence * )
01050 {
01051   return true;
01052 }
01053 
01054 bool Calendar::endChange( Incidence * )
01055 {
01056   return true;
01057 }
01058 
01059 void Calendar::setObserversEnabled( bool enabled )
01060 {
01061   mObserversEnabled = enabled;
01062 }
01063 
01064 #include "calendar.moc"