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