00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00038 #include "calendar.h"
00039 #include "exceptions.h"
00040 #include "calfilter.h"
00041 #include "icaltimezones.h"
00042 #include <kdebug.h>
00043 #include <klocale.h>
00044
00045 extern "C" {
00046 #include <icaltimezone.h>
00047 }
00048
00049 using namespace KCal;
00050
00055
00056 class KCal::Calendar::Private
00057 {
00058 public:
00059 Private()
00060 : mTimeZones( new ICalTimeZones ),
00061 mModified( false ),
00062 mNewObserver( false ),
00063 mObserversEnabled( true ),
00064 mDefaultFilter( new CalFilter )
00065 {
00066
00067 mFilter = mDefaultFilter;
00068 mFilter->setEnabled( false );
00069
00070
00071 mOwner.setName( i18n( "Unknown Name" ) );
00072 mOwner.setEmail( i18n( "unknown@nowhere" ) );
00073 }
00074
00075 ~Private()
00076 {
00077 delete mTimeZones;
00078 if ( mFilter != mDefaultFilter ) {
00079 delete mFilter;
00080 }
00081 delete mDefaultFilter;
00082 }
00083 KDateTime::Spec timeZoneIdSpec( const QString &timeZoneId, bool view );
00084
00085 QString mProductId;
00086 Person mOwner;
00087 ICalTimeZones *mTimeZones;
00088 ICalTimeZone mBuiltInTimeZone;
00089 ICalTimeZone mBuiltInViewTimeZone;
00090 KDateTime::Spec mTimeSpec;
00091 mutable KDateTime::Spec mViewTimeSpec;
00092 bool mModified;
00093 bool mNewObserver;
00094 bool mObserversEnabled;
00095 QList<CalendarObserver*> mObservers;
00096
00097 CalFilter *mDefaultFilter;
00098 CalFilter *mFilter;
00099
00100
00101 QMultiHash<QString, Incidence*> mOrphans;
00102 QMultiHash<QString, Incidence*> mOrphanUids;
00103 };
00104
00105
00106 Calendar::Calendar( const KDateTime::Spec &timeSpec )
00107 : d( new KCal::Calendar::Private )
00108 {
00109 d->mTimeSpec = timeSpec;
00110 d->mViewTimeSpec = timeSpec;
00111 }
00112
00113 Calendar::Calendar( const QString &timeZoneId )
00114 : d( new KCal::Calendar::Private )
00115 {
00116 setTimeZoneId( timeZoneId );
00117 }
00118
00119 Calendar::~Calendar()
00120 {
00121 delete d;
00122 }
00123
00124 Person Calendar::owner() const
00125 {
00126 return d->mOwner;
00127 }
00128
00129 void Calendar::setOwner( const Person &owner )
00130 {
00131 d->mOwner = owner;
00132
00133 setModified( true );
00134 }
00135
00136 void Calendar::setTimeSpec( const KDateTime::Spec &timeSpec )
00137 {
00138 d->mTimeSpec = timeSpec;
00139 d->mBuiltInTimeZone = ICalTimeZone();
00140 setViewTimeSpec( timeSpec );
00141
00142 doSetTimeSpec( d->mTimeSpec );
00143 }
00144
00145 KDateTime::Spec Calendar::timeSpec() const
00146 {
00147 return d->mTimeSpec;
00148 }
00149
00150 void Calendar::setTimeZoneId( const QString &timeZoneId )
00151 {
00152 d->mTimeSpec = d->timeZoneIdSpec( timeZoneId, false );
00153 d->mViewTimeSpec = d->mTimeSpec;
00154 d->mBuiltInViewTimeZone = d->mBuiltInTimeZone;
00155
00156 doSetTimeSpec( d->mTimeSpec );
00157 }
00158
00159
00160 KDateTime::Spec Calendar::Private::timeZoneIdSpec( const QString &timeZoneId,
00161 bool view )
00162 {
00163 if ( view ) {
00164 mBuiltInViewTimeZone = ICalTimeZone();
00165 } else {
00166 mBuiltInTimeZone = ICalTimeZone();
00167 }
00168 if ( timeZoneId == QLatin1String( "UTC" ) ) {
00169 return KDateTime::UTC;
00170 }
00171 ICalTimeZone tz = mTimeZones->zone( timeZoneId );
00172 if ( !tz.isValid() ) {
00173 ICalTimeZoneSource tzsrc;
00174 tz = tzsrc.parse( icaltimezone_get_builtin_timezone( timeZoneId.toLatin1() ) );
00175 if ( view ) {
00176 mBuiltInViewTimeZone = tz;
00177 } else {
00178 mBuiltInTimeZone = tz;
00179 }
00180 }
00181 if ( tz.isValid() ) {
00182 return tz;
00183 } else {
00184 return KDateTime::ClockTime;
00185 }
00186 }
00187
00188
00189 QString Calendar::timeZoneId() const
00190 {
00191 KTimeZone tz = d->mTimeSpec.timeZone();
00192 return tz.isValid() ? tz.name() : QString();
00193 }
00194
00195 void Calendar::setViewTimeSpec( const KDateTime::Spec &timeSpec ) const
00196 {
00197 d->mViewTimeSpec = timeSpec;
00198 d->mBuiltInViewTimeZone = ICalTimeZone();
00199 }
00200
00201 void Calendar::setViewTimeZoneId( const QString &timeZoneId ) const
00202 {
00203 d->mViewTimeSpec = d->timeZoneIdSpec( timeZoneId, true );
00204 }
00205
00206 KDateTime::Spec Calendar::viewTimeSpec() const
00207 {
00208 return d->mViewTimeSpec;
00209 }
00210
00211 QString Calendar::viewTimeZoneId() const
00212 {
00213 KTimeZone tz = d->mViewTimeSpec.timeZone();
00214 return tz.isValid() ? tz.name() : QString();
00215 }
00216
00217 ICalTimeZones *Calendar::timeZones() const
00218 {
00219 return d->mTimeZones;
00220 }
00221
00222 void Calendar::shiftTimes( const KDateTime::Spec &oldSpec,
00223 const KDateTime::Spec &newSpec )
00224 {
00225 setTimeSpec( newSpec );
00226
00227 int i, end;
00228 Event::List ev = events();
00229 for ( i = 0, end = ev.count(); i < end; ++i ) {
00230 ev[i]->shiftTimes( oldSpec, newSpec );
00231 }
00232
00233 Todo::List to = todos();
00234 for ( i = 0, end = to.count(); i < end; ++i ) {
00235 to[i]->shiftTimes( oldSpec, newSpec );
00236 }
00237
00238 Journal::List jo = journals();
00239 for ( i = 0, end = jo.count(); i < end; ++i ) {
00240 jo[i]->shiftTimes( oldSpec, newSpec );
00241 }
00242 }
00243
00244 void Calendar::setFilter( CalFilter *filter )
00245 {
00246 if ( filter ) {
00247 d->mFilter = filter;
00248 } else {
00249 d->mFilter = d->mDefaultFilter;
00250 }
00251 }
00252
00253 CalFilter *Calendar::filter()
00254 {
00255 return d->mFilter;
00256 }
00257
00258 QStringList Calendar::categories()
00259 {
00260 Incidence::List rawInc( rawIncidences() );
00261 QStringList cats, thisCats;
00262
00263
00264 for ( Incidence::List::ConstIterator i = rawInc.constBegin();
00265 i != rawInc.constEnd(); ++i ) {
00266 thisCats = (*i)->categories();
00267 for ( QStringList::ConstIterator si = thisCats.constBegin();
00268 si != thisCats.constEnd(); ++si ) {
00269 if ( !cats.contains( *si ) ) {
00270 cats.append( *si );
00271 }
00272 }
00273 }
00274 return cats;
00275 }
00276
00277 Incidence::List Calendar::incidences( const QDate &date )
00278 {
00279 return mergeIncidenceList( events( date ), todos( date ), journals( date ) );
00280 }
00281
00282 Incidence::List Calendar::incidences()
00283 {
00284 return mergeIncidenceList( events(), todos(), journals() );
00285 }
00286
00287 Incidence::List Calendar::rawIncidences()
00288 {
00289 return mergeIncidenceList( rawEvents(), rawTodos(), rawJournals() );
00290 }
00291
00292 Event::List Calendar::sortEvents( Event::List *eventList,
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
00303
00304
00305 switch( sortField ) {
00306 case EventSortUnsorted:
00307 eventListSorted = *eventList;
00308 break;
00309
00310 case EventSortStartDate:
00311 alphaList = sortEvents( eventList, EventSortSummary, sortDirection );
00312 for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00313 if ( (*eit)->dtStart().isDateOnly() ) {
00314 tempList.append( *eit );
00315 continue;
00316 }
00317 sortIt = eventListSorted.begin();
00318 if ( sortDirection == SortDirectionAscending ) {
00319 while ( sortIt != eventListSorted.end() &&
00320 (*eit)->dtStart() >= (*sortIt)->dtStart() ) {
00321 ++sortIt;
00322 }
00323 } else {
00324 while ( sortIt != eventListSorted.end() &&
00325 (*eit)->dtStart() < (*sortIt)->dtStart() ) {
00326 ++sortIt;
00327 }
00328 }
00329 eventListSorted.insert( sortIt, *eit );
00330 }
00331 if ( sortDirection == SortDirectionAscending ) {
00332
00333 tempList += eventListSorted;
00334 eventListSorted = tempList;
00335 } else {
00336
00337 eventListSorted += tempList;
00338 }
00339 break;
00340
00341 case EventSortEndDate:
00342 alphaList = sortEvents( eventList, EventSortSummary, sortDirection );
00343 for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00344 if ( (*eit)->hasEndDate() ) {
00345 sortIt = eventListSorted.begin();
00346 if ( sortDirection == SortDirectionAscending ) {
00347 while ( sortIt != eventListSorted.end() &&
00348 (*eit)->dtEnd() >= (*sortIt)->dtEnd() ) {
00349 ++sortIt;
00350 }
00351 } else {
00352 while ( sortIt != eventListSorted.end() &&
00353 (*eit)->dtEnd() < (*sortIt)->dtEnd() ) {
00354 ++sortIt;
00355 }
00356 }
00357 } else {
00358
00359 tempList.append( *eit );
00360 }
00361 eventListSorted.insert( sortIt, *eit );
00362 }
00363 if ( sortDirection == SortDirectionAscending ) {
00364
00365 eventListSorted += tempList;
00366 } else {
00367
00368 tempList += eventListSorted;
00369 eventListSorted = tempList;
00370 }
00371 break;
00372
00373 case EventSortSummary:
00374 for ( eit = eventList->begin(); eit != eventList->end(); ++eit ) {
00375 sortIt = eventListSorted.begin();
00376 if ( sortDirection == SortDirectionAscending ) {
00377 while ( sortIt != eventListSorted.end() &&
00378 (*eit)->summary() >= (*sortIt)->summary() ) {
00379 ++sortIt;
00380 }
00381 } else {
00382 while ( sortIt != eventListSorted.end() &&
00383 (*eit)->summary() < (*sortIt)->summary() ) {
00384 ++sortIt;
00385 }
00386 }
00387 eventListSorted.insert( sortIt, *eit );
00388 }
00389 break;
00390 }
00391
00392 return eventListSorted;
00393 }
00394
00395 Event::List Calendar::sortEventsForDate( Event::List *eventList,
00396 const QDate &date,
00397 const KDateTime::Spec &timeSpec,
00398 EventSortField sortField,
00399 SortDirection sortDirection )
00400 {
00401 Event::List eventListSorted;
00402 Event::List tempList;
00403 Event::List alphaList;
00404 Event::List::Iterator sortIt;
00405 Event::List::Iterator eit;
00406
00407 switch( sortField ) {
00408 case EventSortStartDate:
00409 alphaList = sortEvents( eventList, EventSortSummary, sortDirection );
00410 for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00411 if ( (*eit)->allDay() ) {
00412 tempList.append( *eit );
00413 continue;
00414 }
00415 sortIt = eventListSorted.begin();
00416 if ( sortDirection == SortDirectionAscending ) {
00417 while ( sortIt != eventListSorted.end() ) {
00418 if ( !(*eit)->recurs() ) {
00419 if ( (*eit)->dtStart().time() >= (*sortIt)->dtStart().time() ) {
00420 ++sortIt;
00421 } else {
00422 break;
00423 }
00424 } else {
00425 if ( (*eit)->recursOn( date, timeSpec ) ) {
00426 if ( (*eit)->dtStart().time() >= (*sortIt)->dtStart().time() ) {
00427 ++sortIt;
00428 } else {
00429 break;
00430 }
00431 } else {
00432 ++sortIt;
00433 }
00434 }
00435 }
00436 } else {
00437 while ( sortIt != eventListSorted.end() ) {
00438 if ( !(*eit)->recurs() ) {
00439 if ( (*eit)->dtStart().time() < (*sortIt)->dtStart().time() ) {
00440 ++sortIt;
00441 } else {
00442 break;
00443 }
00444 } else {
00445 if ( (*eit)->recursOn( date, timeSpec ) ) {
00446 if ( (*eit)->dtStart().time() < (*sortIt)->dtStart().time() ) {
00447 ++sortIt;
00448 } else {
00449 break;
00450 }
00451 } else {
00452 ++sortIt;
00453 }
00454 }
00455 }
00456 }
00457 eventListSorted.insert( sortIt, *eit );
00458 }
00459 if ( sortDirection == SortDirectionAscending ) {
00460
00461 tempList += eventListSorted;
00462 eventListSorted = tempList;
00463 } else {
00464
00465 eventListSorted += tempList;
00466 }
00467 break;
00468
00469 case EventSortEndDate:
00470 alphaList = sortEvents( eventList, EventSortSummary, sortDirection );
00471 for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00472 if ( (*eit)->hasEndDate() ) {
00473 sortIt = eventListSorted.begin();
00474 if ( sortDirection == SortDirectionAscending ) {
00475 while ( sortIt != eventListSorted.end() ) {
00476 if ( !(*eit)->recurs() ) {
00477 if ( (*eit)->dtEnd().time() >= (*sortIt)->dtEnd().time() ) {
00478 ++sortIt;
00479 } else {
00480 break;
00481 }
00482 } else {
00483 if ( (*eit)->recursOn( date, timeSpec ) ) {
00484 if ( (*eit)->dtEnd().time() >= (*sortIt)->dtEnd().time() ) {
00485 ++sortIt;
00486 } else {
00487 break;
00488 }
00489 } else {
00490 ++sortIt;
00491 }
00492 }
00493 }
00494 } else {
00495 while ( sortIt != eventListSorted.end() ) {
00496 if ( !(*eit)->recurs() ) {
00497 if ( (*eit)->dtEnd().time() < (*sortIt)->dtEnd().time() ) {
00498 ++sortIt;
00499 } else {
00500 break;
00501 }
00502 } else {
00503 if ( (*eit)->recursOn( date, timeSpec ) ) {
00504 if ( (*eit)->dtEnd().time() < (*sortIt)->dtEnd().time() ) {
00505 ++sortIt;
00506 } else {
00507 break;
00508 }
00509 } else {
00510 ++sortIt;
00511 }
00512 }
00513 }
00514 }
00515 } else {
00516
00517 tempList.append( *eit );
00518 }
00519 eventListSorted.insert( sortIt, *eit );
00520 }
00521 if ( sortDirection == SortDirectionAscending ) {
00522
00523 tempList += eventListSorted;
00524 eventListSorted = tempList;
00525 } else {
00526
00527 eventListSorted += tempList;
00528 }
00529 break;
00530
00531 default:
00532 eventListSorted = sortEvents( eventList, sortField, sortDirection );
00533 break;
00534 }
00535
00536 return eventListSorted;
00537 }
00538
00539 Event::List Calendar::events( const QDate &date,
00540 const KDateTime::Spec &timeSpec,
00541 EventSortField sortField,
00542 SortDirection sortDirection )
00543 {
00544 Event::List el = rawEventsForDate( date, timeSpec, sortField, sortDirection );
00545 d->mFilter->apply( &el );
00546 return el;
00547 }
00548
00549 Event::List Calendar::events( const KDateTime &dt )
00550 {
00551 Event::List el = rawEventsForDate( dt );
00552 d->mFilter->apply( &el );
00553 return el;
00554 }
00555
00556 Event::List Calendar::events( const QDate &start, const QDate &end,
00557 const KDateTime::Spec &timeSpec,
00558 bool inclusive )
00559 {
00560 Event::List el = rawEvents( start, end, timeSpec, inclusive );
00561 d->mFilter->apply( &el );
00562 return el;
00563 }
00564
00565 Event::List Calendar::events( EventSortField sortField,
00566 SortDirection sortDirection )
00567 {
00568 Event::List el = rawEvents( sortField, sortDirection );
00569 d->mFilter->apply( &el );
00570 return el;
00571 }
00572
00573 bool Calendar::addIncidence( Incidence *incidence )
00574 {
00575 Incidence::AddVisitor<Calendar> v( this );
00576
00577 return incidence->accept( v );
00578 }
00579
00580 bool Calendar::deleteIncidence( Incidence *incidence )
00581 {
00582 if ( beginChange( incidence ) ) {
00583 Incidence::DeleteVisitor<Calendar> v( this );
00584 bool result = incidence->accept( v );
00585 endChange( incidence );
00586 return result;
00587 } else {
00588 return false;
00589 }
00590 }
00591
00592
00593
00594
00595 Incidence *Calendar::dissociateOccurrence( Incidence *incidence,
00596 const QDate &date,
00597 const KDateTime::Spec &spec,
00598 bool single )
00599 {
00600 if ( !incidence || !incidence->recurs() ) {
00601 return 0;
00602 }
00603
00604 Incidence *newInc = incidence->clone();
00605 newInc->recreate();
00606
00607
00608
00609
00610
00611 Recurrence *recur = newInc->recurrence();
00612 if ( single ) {
00613 recur->clear();
00614 } else {
00615
00616
00617
00618 int duration = recur->duration();
00619 if ( duration > 0 ) {
00620 int doneduration = recur->durationTo( date.addDays( -1 ) );
00621 if ( doneduration >= duration ) {
00622 kDebug() << "The dissociated event already occurred more often"
00623 << "than it was supposed to ever occur. ERROR!";
00624 recur->clear();
00625 } else {
00626 recur->setDuration( duration - doneduration );
00627 }
00628 }
00629 }
00630
00631 if ( incidence->type() == "Event" ) {
00632 Event *ev = static_cast<Event *>( newInc );
00633 KDateTime start( ev->dtStart() );
00634 int daysTo = start.toTimeSpec( spec ).date().daysTo( date );
00635 ev->setDtStart( start.addDays( daysTo ) );
00636 ev->setDtEnd( ev->dtEnd().addDays( daysTo ) );
00637 } else if ( incidence->type() == "Todo" ) {
00638 Todo *td = static_cast<Todo *>( newInc );
00639 bool haveOffset = false;
00640 int daysTo = 0;
00641 if ( td->hasDueDate() ) {
00642 KDateTime due( td->dtDue() );
00643 daysTo = due.toTimeSpec( spec ).date().daysTo( date );
00644 td->setDtDue( due.addDays( daysTo ), true );
00645 haveOffset = true;
00646 }
00647 if ( td->hasStartDate() ) {
00648 KDateTime start( td->dtStart() );
00649 if ( !haveOffset ) {
00650 daysTo = start.toTimeSpec( spec ).date().daysTo( date );
00651 }
00652 td->setDtStart( start.addDays( daysTo ) );
00653 haveOffset = true;
00654 }
00655 }
00656 recur = incidence->recurrence();
00657 if ( recur ) {
00658 if ( single ) {
00659 recur->addExDate( date );
00660 } else {
00661
00662
00663 recur->setEndDate( date.addDays(-1) );
00664 }
00665 }
00666 return newInc;
00667 }
00668
00669 Incidence *Calendar::incidence( const QString &uid )
00670 {
00671 Incidence *i = event( uid );
00672 if ( i ) {
00673 return i;
00674 }
00675
00676 i = todo( uid );
00677 if ( i ) {
00678 return i;
00679 }
00680
00681 i = journal( uid );
00682 return i;
00683 }
00684
00685 Incidence::List Calendar::incidencesFromSchedulingID( const QString &sid )
00686 {
00687 Incidence::List result;
00688 const Incidence::List incidences = rawIncidences();
00689 Incidence::List::const_iterator it = incidences.begin();
00690 for ( ; it != incidences.end(); ++it ) {
00691 if ( (*it)->schedulingID() == sid ) {
00692 result.append( *it );
00693 }
00694 }
00695 return result;
00696 }
00697
00698 Incidence *Calendar::incidenceFromSchedulingID( const QString &UID )
00699 {
00700 const Incidence::List incidences = rawIncidences();
00701 Incidence::List::const_iterator it = incidences.begin();
00702 for ( ; it != incidences.end(); ++it ) {
00703 if ( (*it)->schedulingID() == UID ) {
00704
00705 return *it;
00706 }
00707 }
00708
00709 return 0;
00710 }
00711
00712 Todo::List Calendar::sortTodos( Todo::List *todoList,
00713 TodoSortField sortField,
00714 SortDirection sortDirection )
00715 {
00716 Todo::List todoListSorted;
00717 Todo::List tempList, t;
00718 Todo::List alphaList;
00719 Todo::List::Iterator sortIt;
00720 Todo::List::Iterator eit;
00721
00722
00723
00724
00725
00726
00727 switch( sortField ) {
00728 case TodoSortUnsorted:
00729 todoListSorted = *todoList;
00730 break;
00731
00732 case TodoSortStartDate:
00733 alphaList = sortTodos( todoList, TodoSortSummary, sortDirection );
00734 for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00735 if ( (*eit)->hasStartDate() ) {
00736 sortIt = todoListSorted.begin();
00737 if ( sortDirection == SortDirectionAscending ) {
00738 while ( sortIt != todoListSorted.end() &&
00739 (*eit)->dtStart() >= (*sortIt)->dtStart() ) {
00740 ++sortIt;
00741 }
00742 } else {
00743 while ( sortIt != todoListSorted.end() &&
00744 (*eit)->dtStart() < (*sortIt)->dtStart() ) {
00745 ++sortIt;
00746 }
00747 }
00748 todoListSorted.insert( sortIt, *eit );
00749 } else {
00750
00751 tempList.append( *eit );
00752 }
00753 }
00754 if ( sortDirection == SortDirectionAscending ) {
00755
00756 todoListSorted += tempList;
00757 } else {
00758
00759 tempList += todoListSorted;
00760 todoListSorted = tempList;
00761 }
00762 break;
00763
00764 case TodoSortDueDate:
00765 alphaList = sortTodos( todoList, TodoSortSummary, sortDirection );
00766 for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00767 if ( (*eit)->hasDueDate() ) {
00768 sortIt = todoListSorted.begin();
00769 if ( sortDirection == SortDirectionAscending ) {
00770 while ( sortIt != todoListSorted.end() &&
00771 (*eit)->dtDue() >= (*sortIt)->dtDue() ) {
00772 ++sortIt;
00773 }
00774 } else {
00775 while ( sortIt != todoListSorted.end() &&
00776 (*eit)->dtDue() < (*sortIt)->dtDue() ) {
00777 ++sortIt;
00778 }
00779 }
00780 todoListSorted.insert( sortIt, *eit );
00781 } else {
00782
00783 tempList.append( *eit );
00784 }
00785 }
00786 if ( sortDirection == SortDirectionAscending ) {
00787
00788 todoListSorted += tempList;
00789 } else {
00790
00791 tempList += todoListSorted;
00792 todoListSorted = tempList;
00793 }
00794 break;
00795
00796 case TodoSortPriority:
00797 alphaList = sortTodos( todoList, TodoSortSummary, sortDirection );
00798 for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00799 sortIt = todoListSorted.begin();
00800 if ( sortDirection == SortDirectionAscending ) {
00801 while ( sortIt != todoListSorted.end() &&
00802 (*eit)->priority() >= (*sortIt)->priority() ) {
00803 ++sortIt;
00804 }
00805 } else {
00806 while ( sortIt != todoListSorted.end() &&
00807 (*eit)->priority() < (*sortIt)->priority() ) {
00808 ++sortIt;
00809 }
00810 }
00811 todoListSorted.insert( sortIt, *eit );
00812 }
00813 break;
00814
00815 case TodoSortPercentComplete:
00816 alphaList = sortTodos( todoList, TodoSortSummary, sortDirection );
00817 for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00818 sortIt = todoListSorted.begin();
00819 if ( sortDirection == SortDirectionAscending ) {
00820 while ( sortIt != todoListSorted.end() &&
00821 (*eit)->percentComplete() >= (*sortIt)->percentComplete() ) {
00822 ++sortIt;
00823 }
00824 } else {
00825 while ( sortIt != todoListSorted.end() &&
00826 (*eit)->percentComplete() < (*sortIt)->percentComplete() ) {
00827 ++sortIt;
00828 }
00829 }
00830 todoListSorted.insert( sortIt, *eit );
00831 }
00832 break;
00833
00834 case TodoSortSummary:
00835 for ( eit = todoList->begin(); eit != todoList->end(); ++eit ) {
00836 sortIt = todoListSorted.begin();
00837 if ( sortDirection == SortDirectionAscending ) {
00838 while ( sortIt != todoListSorted.end() &&
00839 (*eit)->summary() >= (*sortIt)->summary() ) {
00840 ++sortIt;
00841 }
00842 } else {
00843 while ( sortIt != todoListSorted.end() &&
00844 (*eit)->summary() < (*sortIt)->summary() ) {
00845 ++sortIt;
00846 }
00847 }
00848 todoListSorted.insert( sortIt, *eit );
00849 }
00850 break;
00851 }
00852
00853 return todoListSorted;
00854 }
00855
00856 Todo::List Calendar::todos( TodoSortField sortField,
00857 SortDirection sortDirection )
00858 {
00859 Todo::List tl = rawTodos( sortField, sortDirection );
00860 d->mFilter->apply( &tl );
00861 return tl;
00862 }
00863
00864 Todo::List Calendar::todos( const QDate &date )
00865 {
00866 Todo::List el = rawTodosForDate( date );
00867 d->mFilter->apply( &el );
00868 return el;
00869 }
00870
00871 Journal::List Calendar::sortJournals( Journal::List *journalList,
00872 JournalSortField sortField,
00873 SortDirection sortDirection )
00874 {
00875 Journal::List journalListSorted;
00876 Journal::List::Iterator sortIt;
00877 Journal::List::Iterator eit;
00878
00879 switch( sortField ) {
00880 case JournalSortUnsorted:
00881 journalListSorted = *journalList;
00882 break;
00883
00884 case JournalSortDate:
00885 for ( eit = journalList->begin(); eit != journalList->end(); ++eit ) {
00886 sortIt = journalListSorted.begin();
00887 if ( sortDirection == SortDirectionAscending ) {
00888 while ( sortIt != journalListSorted.end() &&
00889 (*eit)->dtStart() >= (*sortIt)->dtStart() ) {
00890 ++sortIt;
00891 }
00892 } else {
00893 while ( sortIt != journalListSorted.end() &&
00894 (*eit)->dtStart() < (*sortIt)->dtStart() ) {
00895 ++sortIt;
00896 }
00897 }
00898 journalListSorted.insert( sortIt, *eit );
00899 }
00900 break;
00901
00902 case JournalSortSummary:
00903 for ( eit = journalList->begin(); eit != journalList->end(); ++eit ) {
00904 sortIt = journalListSorted.begin();
00905 if ( sortDirection == SortDirectionAscending ) {
00906 while ( sortIt != journalListSorted.end() &&
00907 (*eit)->summary() >= (*sortIt)->summary() ) {
00908 ++sortIt;
00909 }
00910 } else {
00911 while ( sortIt != journalListSorted.end() &&
00912 (*eit)->summary() < (*sortIt)->summary() ) {
00913 ++sortIt;
00914 }
00915 }
00916 journalListSorted.insert( sortIt, *eit );
00917 }
00918 break;
00919 }
00920
00921 return journalListSorted;
00922 }
00923
00924 Journal::List Calendar::journals( JournalSortField sortField,
00925 SortDirection sortDirection )
00926 {
00927 Journal::List jl = rawJournals( sortField, sortDirection );
00928 d->mFilter->apply( &jl );
00929 return jl;
00930 }
00931
00932 Journal::List Calendar::journals( const QDate &date )
00933 {
00934 Journal::List el = rawJournalsForDate( date );
00935 d->mFilter->apply( &el );
00936 return el;
00937 }
00938
00939 void Calendar::beginBatchAdding()
00940 {
00941 emit batchAddingBegins();
00942 }
00943
00944 void Calendar::endBatchAdding()
00945 {
00946 emit batchAddingEnds();
00947 }
00948
00949
00950
00951 void Calendar::setupRelations( Incidence *forincidence )
00952 {
00953 if ( !forincidence ) {
00954 return;
00955 }
00956
00957 QString uid = forincidence->uid();
00958
00959
00960 QList<Incidence*> l = d->mOrphans.values( uid );
00961 d->mOrphans.remove( uid );
00962 for ( int i = 0, end = l.count(); i < end; ++i ) {
00963 l[i]->setRelatedTo( forincidence );
00964 forincidence->addRelation( l[i] );
00965 d->mOrphanUids.remove( l[i]->uid() );
00966 }
00967
00968
00969 if ( !forincidence->relatedTo() && !forincidence->relatedToUid().isEmpty() ) {
00970
00971
00972 Incidence *parent = incidence( forincidence->relatedToUid() );
00973 if ( parent ) {
00974
00975
00976
00977 if ( isAncestorOf( forincidence, parent ) ) {
00978 forincidence->setRelatedToUid( QString() );
00979 kWarning() << "hierarchy loop beetween " << forincidence->uid() << " and " << parent->uid();
00980 } else {
00981 forincidence->setRelatedTo( parent );
00982 parent->addRelation( forincidence );
00983 }
00984
00985 } else {
00986
00987
00988
00989
00990 d->mOrphans.insert( forincidence->relatedToUid(), forincidence );
00991 d->mOrphanUids.insert( forincidence->uid(), forincidence );
00992 }
00993 }
00994 }
00995
00996
00997 void Calendar::removeRelations( Incidence *incidence )
00998 {
00999 if ( !incidence ) {
01000 kDebug() << "Warning: incidence is 0";
01001 return;
01002 }
01003
01004 QString uid = incidence->uid();
01005 foreach ( Incidence *i, incidence->relations() ) {
01006 if ( !d->mOrphanUids.contains( i->uid() ) ) {
01007 d->mOrphans.insert( uid, i );
01008 d->mOrphanUids.insert( i->uid(), i );
01009 i->setRelatedTo( 0 );
01010 i->setRelatedToUid( uid );
01011 }
01012 }
01013
01014
01015 if ( incidence->relatedTo() ) {
01016 incidence->relatedTo()->removeRelation( incidence );
01017 }
01018
01019
01020 if ( d->mOrphanUids.remove( uid ) ) {
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030 QStringList relatedToUids;
01031
01032
01033
01034 relatedToUids << incidence->relatedToUid();
01035 for ( QMultiHash<QString, Incidence*>::Iterator it = d->mOrphans.begin();
01036 it != d->mOrphans.end(); ++it ) {
01037 if ( it.value()->uid() == uid ) {
01038 relatedToUids << it.key();
01039 }
01040 }
01041
01042
01043 for ( QStringList::const_iterator uidit = relatedToUids.constBegin();
01044 uidit != relatedToUids.constEnd(); ++uidit ) {
01045 Incidence::List tempList;
01046
01047 QList<Incidence*> l = d->mOrphans.values( *uidit );
01048 d->mOrphans.remove( *uidit );
01049 foreach ( Incidence *i, l ) {
01050 if ( i != incidence ) {
01051 tempList.append( i );
01052 }
01053 }
01054
01055 for ( Incidence::List::Iterator incit = tempList.begin();
01056 incit != tempList.end(); ++incit ) {
01057 d->mOrphans.insert( *uidit, *incit );
01058 }
01059 }
01060 }
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072 incidence->setRelatedTo( 0 );
01073 }
01074
01075 bool Calendar::isAncestorOf( Incidence *ancestor, Incidence *incidence )
01076 {
01077 if ( !incidence || incidence->relatedToUid().isEmpty() ) {
01078 return false;
01079 } else if ( incidence->relatedToUid() == ancestor->uid() ) {
01080 return true;
01081 } else {
01082 return isAncestorOf( ancestor, this->incidence( incidence->relatedToUid() ) );
01083 }
01084 }
01085
01086 void Calendar::CalendarObserver::calendarModified( bool modified, Calendar *calendar )
01087 {
01088 Q_UNUSED( modified );
01089 Q_UNUSED( calendar );
01090 }
01091
01092 void Calendar::CalendarObserver::calendarIncidenceAdded( Incidence *incidence )
01093 {
01094 Q_UNUSED( incidence );
01095 }
01096
01097 void Calendar::CalendarObserver::calendarIncidenceChanged( Incidence *incidence )
01098 {
01099 Q_UNUSED( incidence );
01100 }
01101
01102 void Calendar::CalendarObserver::calendarIncidenceDeleted( Incidence *incidence )
01103 {
01104 Q_UNUSED( incidence );
01105 }
01106
01107 void Calendar::registerObserver( CalendarObserver *observer )
01108 {
01109 if ( !d->mObservers.contains( observer ) ) {
01110 d->mObservers.append( observer );
01111 }
01112 d->mNewObserver = true;
01113 }
01114
01115 void Calendar::unregisterObserver( CalendarObserver *observer )
01116 {
01117 d->mObservers.removeAll( observer );
01118 }
01119
01120 bool Calendar::isSaving()
01121 {
01122 return false;
01123 }
01124
01125 void Calendar::setModified( bool modified )
01126 {
01127 if ( modified != d->mModified || d->mNewObserver ) {
01128 d->mNewObserver = false;
01129 foreach ( CalendarObserver *observer, d->mObservers ) {
01130 observer->calendarModified( modified, this );
01131 }
01132 d->mModified = modified;
01133 }
01134 }
01135
01136 bool Calendar::isModified() const
01137 {
01138 return d->mModified;
01139 }
01140
01141 void Calendar::incidenceUpdated( IncidenceBase *incidence )
01142 {
01143 incidence->setLastModified( KDateTime::currentUtcDateTime() );
01144
01145
01146
01147
01148
01149 notifyIncidenceChanged( static_cast<Incidence *>( incidence ) );
01150
01151 setModified( true );
01152 }
01153
01154 void Calendar::doSetTimeSpec( const KDateTime::Spec &timeSpec )
01155 {
01156 Q_UNUSED( timeSpec );
01157 }
01158
01159 void Calendar::notifyIncidenceAdded( Incidence *i )
01160 {
01161 if ( !d->mObserversEnabled ) {
01162 return;
01163 }
01164
01165 foreach ( CalendarObserver *observer, d->mObservers ) {
01166 observer->calendarIncidenceAdded( i );
01167 }
01168 }
01169
01170 void Calendar::notifyIncidenceChanged( Incidence *i )
01171 {
01172 if ( !d->mObserversEnabled ) {
01173 return;
01174 }
01175
01176 foreach ( CalendarObserver *observer, d->mObservers ) {
01177 observer->calendarIncidenceChanged( i );
01178 }
01179 }
01180
01181 void Calendar::notifyIncidenceDeleted( Incidence *i )
01182 {
01183 if ( !d->mObserversEnabled ) {
01184 return;
01185 }
01186
01187 foreach ( CalendarObserver *observer, d->mObservers ) {
01188 observer->calendarIncidenceDeleted( i );
01189 }
01190 }
01191
01192 void Calendar::customPropertyUpdated()
01193 {
01194 setModified( true );
01195 }
01196
01197 void Calendar::setProductId( const QString &id )
01198 {
01199 d->mProductId = id;
01200 }
01201
01202 QString Calendar::productId() const
01203 {
01204 return d->mProductId;
01205 }
01206
01207 Incidence::List Calendar::mergeIncidenceList( const Event::List &events,
01208 const Todo::List &todos,
01209 const Journal::List &journals )
01210 {
01211 Incidence::List incidences;
01212
01213 int i, end;
01214 for ( i = 0, end = events.count(); i < end; ++i ) {
01215 incidences.append( events[i] );
01216 }
01217
01218 for ( i = 0, end = todos.count(); i < end; ++i ) {
01219 incidences.append( todos[i] );
01220 }
01221
01222 for ( i = 0, end = journals.count(); i < end; ++i ) {
01223 incidences.append( journals[i] );
01224 }
01225
01226 return incidences;
01227 }
01228
01229 bool Calendar::beginChange( Incidence *incidence )
01230 {
01231 Q_UNUSED( incidence );
01232 return true;
01233 }
01234
01235 bool Calendar::endChange( Incidence *incidence )
01236 {
01237 Q_UNUSED( incidence );
01238 return true;
01239 }
01240
01241 void Calendar::setObserversEnabled( bool enabled )
01242 {
01243 d->mObserversEnabled = enabled;
01244 }
01245
01246 void Calendar::appendAlarms( Alarm::List &alarms, Incidence *incidence,
01247 const KDateTime &from, const KDateTime &to )
01248 {
01249 KDateTime preTime = from.addSecs(-1);
01250
01251 Alarm::List alarmlist = incidence->alarms();
01252 for ( int i = 0, iend = alarmlist.count(); i < iend; ++i ) {
01253 if ( alarmlist[i]->enabled() ) {
01254 KDateTime dt = alarmlist[i]->nextRepetition( preTime );
01255 if ( dt.isValid() && dt <= to ) {
01256 kDebug() << incidence->summary() << "':" << dt.toString();
01257 alarms.append( alarmlist[i] );
01258 }
01259 }
01260 }
01261 }
01262
01263 void Calendar::appendRecurringAlarms( Alarm::List &alarms,
01264 Incidence *incidence,
01265 const KDateTime &from,
01266 const KDateTime &to )
01267 {
01268 KDateTime dt;
01269 Duration endOffset( 0 );
01270 bool endOffsetValid = false;
01271 Duration period( from, to );
01272
01273 Event *e = static_cast<Event *>( incidence );
01274 Todo *t = static_cast<Todo *>( incidence );
01275
01276 Alarm::List alarmlist = incidence->alarms();
01277 for ( int i = 0, iend = alarmlist.count(); i < iend; ++i ) {
01278 Alarm *a = alarmlist[i];
01279 if ( a->enabled() ) {
01280 if ( a->hasTime() ) {
01281
01282 dt = a->nextRepetition( from.addSecs( -1 ) );
01283 if ( !dt.isValid() || dt > to ) {
01284 continue;
01285 }
01286 } else {
01287
01288
01289
01290 Duration offset( 0 );
01291 if ( a->hasStartOffset() ) {
01292 offset = a->startOffset();
01293 } else if ( a->hasEndOffset() ) {
01294 offset = a->endOffset();
01295 if ( !endOffsetValid ) {
01296 if ( incidence->type() == "Event" ) {
01297 endOffset = Duration( e->dtStart(), e->dtEnd() );
01298 endOffsetValid = true;
01299 } else if ( incidence->type() == "Todo" &&
01300 t->hasStartDate() && t->hasDueDate() ) {
01301 endOffset = Duration( t->dtStart(), t->dtEnd() );
01302 endOffsetValid = true;
01303 }
01304 }
01305 }
01306
01307
01308 KDateTime alarmStart;
01309 if ( incidence->type() == "Event" ) {
01310 alarmStart =
01311 offset.end( a->hasEndOffset() ? e->dtEnd() : e->dtStart() );
01312 } else if ( incidence->type() == "Todo" ) {
01313 alarmStart =
01314 offset.end( a->hasEndOffset() ? t->dtDue() : t->dtStart() );
01315 }
01316
01317 if ( alarmStart.isValid() && alarmStart > to ) {
01318 continue;
01319 }
01320
01321 KDateTime baseStart;
01322 if ( incidence->type() == "Event" ) {
01323 baseStart = e->dtStart();
01324 } else if ( incidence->type() == "Todo" ) {
01325 baseStart = t->dtDue();
01326 }
01327 if ( alarmStart.isValid() && from > alarmStart ) {
01328 alarmStart = from;
01329 baseStart = (-offset).end( (-endOffset).end( alarmStart ) );
01330 }
01331
01332
01333
01334
01335 dt = incidence->recurrence()->getNextDateTime( baseStart.addSecs( -1 ) );
01336 if ( !dt.isValid() ||
01337 ( dt = endOffset.end( offset.end( dt ) ) ) > to )
01338 {
01339
01340 if ( !a->repeatCount() ) {
01341 continue;
01342 }
01343
01344
01345
01346 bool found = false;
01347 Duration alarmDuration = a->duration();
01348 for ( KDateTime base = baseStart;
01349 ( dt = incidence->recurrence()->getPreviousDateTime( base ) ).isValid();
01350 base = dt ) {
01351 if ( a->duration().end( dt ) < base ) {
01352 break;
01353 }
01354
01355
01356
01357
01358 int snooze = a->snoozeTime().value();
01359 if ( a->snoozeTime().isDaily() ) {
01360 Duration toFromDuration( dt, base );
01361 int toFrom = toFromDuration.asDays();
01362 if ( a->snoozeTime().end( from ) <= to ||
01363 ( toFromDuration.isDaily() && toFrom % snooze == 0 ) ||
01364 ( toFrom / snooze + 1 ) * snooze <= toFrom + period.asDays() ) {
01365 found = true;
01366 #ifndef NDEBUG
01367
01368 dt = offset.end( dt ).addDays( ( ( toFrom - 1 ) / snooze + 1 ) * snooze );
01369 #endif
01370 break;
01371 }
01372 } else {
01373 int toFrom = dt.secsTo( base );
01374 if ( period.asSeconds() >= snooze ||
01375 toFrom % snooze == 0 ||
01376 ( toFrom / snooze + 1 ) * snooze <= toFrom + period.asSeconds() )
01377 {
01378 found = true;
01379 #ifndef NDEBUG
01380
01381 dt = offset.end( dt ).addSecs( ( ( toFrom - 1 ) / snooze + 1 ) * snooze );
01382 #endif
01383 break;
01384 }
01385 }
01386 }
01387 if ( !found ) {
01388 continue;
01389 }
01390 }
01391 }
01392 kDebug() << incidence->summary() << "':" << dt.toString();
01393 alarms.append( a );
01394 }
01395 }
01396 }
01397
01398 #include "calendar.moc"