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