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 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 if ( (*eit)->dtStart().isDateOnly() ) {
00311 tempList.append( *eit );
00312 continue;
00313 }
00314 sortIt = eventListSorted.begin();
00315 if ( sortDirection == SortDirectionAscending ) {
00316 while ( sortIt != eventListSorted.end() &&
00317 (*eit)->dtStart() >= (*sortIt)->dtStart() ) {
00318 ++sortIt;
00319 }
00320 } else {
00321 while ( sortIt != eventListSorted.end() &&
00322 (*eit)->dtStart() < (*sortIt)->dtStart() ) {
00323 ++sortIt;
00324 }
00325 }
00326 eventListSorted.insert( sortIt, *eit );
00327 }
00328 if ( sortDirection == SortDirectionAscending ) {
00329
00330 tempList += eventListSorted;
00331 eventListSorted = tempList;
00332 } else {
00333
00334 eventListSorted += tempList;
00335 }
00336 break;
00337
00338 case EventSortEndDate:
00339 alphaList = sortEvents( eventList, EventSortSummary, sortDirection );
00340 for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00341 if ( (*eit)->hasEndDate() ) {
00342 sortIt = eventListSorted.begin();
00343 if ( sortDirection == SortDirectionAscending ) {
00344 while ( sortIt != eventListSorted.end() &&
00345 (*eit)->dtEnd() >= (*sortIt)->dtEnd() ) {
00346 ++sortIt;
00347 }
00348 } else {
00349 while ( sortIt != eventListSorted.end() &&
00350 (*eit)->dtEnd() < (*sortIt)->dtEnd() ) {
00351 ++sortIt;
00352 }
00353 }
00354 } else {
00355
00356 tempList.append( *eit );
00357 }
00358 eventListSorted.insert( sortIt, *eit );
00359 }
00360 if ( sortDirection == SortDirectionAscending ) {
00361
00362 eventListSorted += tempList;
00363 } else {
00364
00365 tempList += eventListSorted;
00366 eventListSorted = tempList;
00367 }
00368 break;
00369
00370 case EventSortSummary:
00371 for ( eit = eventList->begin(); eit != eventList->end(); ++eit ) {
00372 sortIt = eventListSorted.begin();
00373 if ( sortDirection == SortDirectionAscending ) {
00374 while ( sortIt != eventListSorted.end() &&
00375 (*eit)->summary() >= (*sortIt)->summary() ) {
00376 ++sortIt;
00377 }
00378 } else {
00379 while ( sortIt != eventListSorted.end() &&
00380 (*eit)->summary() < (*sortIt)->summary() ) {
00381 ++sortIt;
00382 }
00383 }
00384 eventListSorted.insert( sortIt, *eit );
00385 }
00386 break;
00387 }
00388
00389 return eventListSorted;
00390
00391 }
00392
00393 Event::List Calendar::events( const QDate &date,
00394 const KDateTime::Spec ×pec,
00395 EventSortField sortField,
00396 SortDirection sortDirection )
00397 {
00398 Event::List el = rawEventsForDate( date, timespec, sortField, sortDirection );
00399 d->mFilter->apply( &el );
00400 return el;
00401 }
00402
00403 Event::List Calendar::events( const KDateTime &dt )
00404 {
00405 Event::List el = rawEventsForDate( dt );
00406 d->mFilter->apply( &el );
00407 return el;
00408 }
00409
00410 Event::List Calendar::events( const QDate &start, const QDate &end,
00411 const KDateTime::Spec ×pec,
00412 bool inclusive )
00413 {
00414 Event::List el = rawEvents( start, end, timespec, inclusive );
00415 d->mFilter->apply( &el );
00416 return el;
00417 }
00418
00419 Event::List Calendar::events( EventSortField sortField,
00420 SortDirection sortDirection )
00421 {
00422 Event::List el = rawEvents( sortField, sortDirection );
00423 d->mFilter->apply( &el );
00424 return el;
00425 }
00426
00427 bool Calendar::addIncidence( Incidence *incidence )
00428 {
00429 Incidence::AddVisitor<Calendar> v( this );
00430
00431 return incidence->accept( v );
00432 }
00433
00434 bool Calendar::deleteIncidence( Incidence *incidence )
00435 {
00436 if ( beginChange( incidence ) ) {
00437 Incidence::DeleteVisitor<Calendar> v( this );
00438 bool result = incidence->accept( v );
00439 endChange( incidence );
00440 return result;
00441 } else {
00442 return false;
00443 }
00444 }
00445
00446
00447
00448
00449 Incidence *Calendar::dissociateOccurrence( Incidence *incidence,
00450 const QDate &date,
00451 const KDateTime::Spec &spec,
00452 bool single )
00453 {
00454 if ( !incidence || !incidence->recurs() ) {
00455 return 0;
00456 }
00457
00458 Incidence *newInc = incidence->clone();
00459 newInc->recreate();
00460
00461 Recurrence *recur = newInc->recurrence();
00462 if ( single ) {
00463 recur->clear();
00464 } else {
00465
00466
00467
00468 int duration = recur->duration();
00469 if ( duration > 0 ) {
00470 int doneduration = recur->durationTo( date.addDays( -1 ) );
00471 if ( doneduration >= duration ) {
00472 kDebug() << "The dissociated event already occurred more often"
00473 << "than it was supposed to ever occur. ERROR!";
00474 recur->clear();
00475 } else {
00476 recur->setDuration( duration - doneduration );
00477 }
00478 }
00479 }
00480
00481 if ( incidence->type() == "Event" ) {
00482 Event *ev = static_cast<Event *>( newInc );
00483 KDateTime start( ev->dtStart() );
00484 int daysTo = start.toTimeSpec( spec ).date().daysTo( date );
00485 ev->setDtStart( start.addDays( daysTo ) );
00486 ev->setDtEnd( ev->dtEnd().addDays( daysTo ) );
00487 } else if ( incidence->type() == "Todo" ) {
00488 Todo *td = static_cast<Todo *>( newInc );
00489 bool haveOffset = false;
00490 int daysTo = 0;
00491 if ( td->hasDueDate() ) {
00492 KDateTime due( td->dtDue() );
00493 daysTo = due.toTimeSpec( spec ).date().daysTo( date );
00494 td->setDtDue( due.addDays( daysTo ), true );
00495 haveOffset = true;
00496 }
00497 if ( td->hasStartDate() ) {
00498 KDateTime start( td->dtStart() );
00499 if ( !haveOffset ) {
00500 daysTo = start.toTimeSpec( spec ).date().daysTo( date );
00501 }
00502 td->setDtStart( start.addDays( daysTo ) );
00503 haveOffset = true;
00504 }
00505 }
00506 recur = incidence->recurrence();
00507 if ( recur ) {
00508 if ( single ) {
00509 recur->addExDate( date );
00510 } else {
00511
00512
00513 recur->setEndDate( date.addDays(-1) );
00514 }
00515 }
00516 return newInc;
00517 }
00518
00519 Incidence *Calendar::incidence( const QString &uid )
00520 {
00521 Incidence *i = event( uid );
00522 if ( i ) {
00523 return i;
00524 }
00525
00526 i = todo( uid );
00527 if ( i ) {
00528 return i;
00529 }
00530
00531 i = journal( uid );
00532 return i;
00533 }
00534
00535 Incidence::List Calendar::incidencesFromSchedulingID( const QString &sid )
00536 {
00537 Incidence::List result;
00538 const Incidence::List incidences = rawIncidences();
00539 Incidence::List::const_iterator it = incidences.begin();
00540 for ( ; it != incidences.end(); ++it ) {
00541 if ( (*it)->schedulingID() == sid ) {
00542 result.append( *it );
00543 }
00544 }
00545 return result;
00546 }
00547
00548 Incidence *Calendar::incidenceFromSchedulingID( const QString &UID )
00549 {
00550 const Incidence::List incidences = rawIncidences();
00551 Incidence::List::const_iterator it = incidences.begin();
00552 for ( ; it != incidences.end(); ++it ) {
00553 if ( (*it)->schedulingID() == UID ) {
00554
00555 return *it;
00556 }
00557 }
00558
00559 return 0;
00560 }
00561
00562 Todo::List Calendar::sortTodos( Todo::List *todoList,
00563 TodoSortField sortField,
00564 SortDirection sortDirection )
00565 {
00566 Todo::List todoListSorted;
00567 Todo::List tempList, t;
00568 Todo::List alphaList;
00569 Todo::List::Iterator sortIt;
00570 Todo::List::Iterator eit;
00571
00572
00573
00574
00575
00576
00577 switch( sortField ) {
00578 case TodoSortUnsorted:
00579 todoListSorted = *todoList;
00580 break;
00581
00582 case TodoSortStartDate:
00583 alphaList = sortTodos( todoList, TodoSortSummary, sortDirection );
00584 for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00585 if ( (*eit)->hasStartDate() ) {
00586 sortIt = todoListSorted.begin();
00587 if ( sortDirection == SortDirectionAscending ) {
00588 while ( sortIt != todoListSorted.end() &&
00589 (*eit)->dtStart() >= (*sortIt)->dtStart() ) {
00590 ++sortIt;
00591 }
00592 } else {
00593 while ( sortIt != todoListSorted.end() &&
00594 (*eit)->dtStart() < (*sortIt)->dtStart() ) {
00595 ++sortIt;
00596 }
00597 }
00598 todoListSorted.insert( sortIt, *eit );
00599 } else {
00600
00601 tempList.append( *eit );
00602 }
00603 }
00604 if ( sortDirection == SortDirectionAscending ) {
00605
00606 todoListSorted += tempList;
00607 } else {
00608
00609 tempList += todoListSorted;
00610 todoListSorted = tempList;
00611 }
00612 break;
00613
00614 case TodoSortDueDate:
00615 alphaList = sortTodos( todoList, TodoSortSummary, sortDirection );
00616 for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00617 if ( (*eit)->hasDueDate() ) {
00618 sortIt = todoListSorted.begin();
00619 if ( sortDirection == SortDirectionAscending ) {
00620 while ( sortIt != todoListSorted.end() &&
00621 (*eit)->dtDue() >= (*sortIt)->dtDue() ) {
00622 ++sortIt;
00623 }
00624 } else {
00625 while ( sortIt != todoListSorted.end() &&
00626 (*eit)->dtDue() < (*sortIt)->dtDue() ) {
00627 ++sortIt;
00628 }
00629 }
00630 todoListSorted.insert( sortIt, *eit );
00631 } else {
00632
00633 tempList.append( *eit );
00634 }
00635 }
00636 if ( sortDirection == SortDirectionAscending ) {
00637
00638 todoListSorted += tempList;
00639 } else {
00640
00641 tempList += todoListSorted;
00642 todoListSorted = tempList;
00643 }
00644 break;
00645
00646 case TodoSortPriority:
00647 alphaList = sortTodos( todoList, TodoSortSummary, sortDirection );
00648 for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00649 sortIt = todoListSorted.begin();
00650 if ( sortDirection == SortDirectionAscending ) {
00651 while ( sortIt != todoListSorted.end() &&
00652 (*eit)->priority() >= (*sortIt)->priority() ) {
00653 ++sortIt;
00654 }
00655 } else {
00656 while ( sortIt != todoListSorted.end() &&
00657 (*eit)->priority() < (*sortIt)->priority() ) {
00658 ++sortIt;
00659 }
00660 }
00661 todoListSorted.insert( sortIt, *eit );
00662 }
00663 break;
00664
00665 case TodoSortPercentComplete:
00666 alphaList = sortTodos( todoList, TodoSortSummary, sortDirection );
00667 for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
00668 sortIt = todoListSorted.begin();
00669 if ( sortDirection == SortDirectionAscending ) {
00670 while ( sortIt != todoListSorted.end() &&
00671 (*eit)->percentComplete() >= (*sortIt)->percentComplete() ) {
00672 ++sortIt;
00673 }
00674 } else {
00675 while ( sortIt != todoListSorted.end() &&
00676 (*eit)->percentComplete() < (*sortIt)->percentComplete() ) {
00677 ++sortIt;
00678 }
00679 }
00680 todoListSorted.insert( sortIt, *eit );
00681 }
00682 break;
00683
00684 case TodoSortSummary:
00685 for ( eit = todoList->begin(); eit != todoList->end(); ++eit ) {
00686 sortIt = todoListSorted.begin();
00687 if ( sortDirection == SortDirectionAscending ) {
00688 while ( sortIt != todoListSorted.end() &&
00689 (*eit)->summary() >= (*sortIt)->summary() ) {
00690 ++sortIt;
00691 }
00692 } else {
00693 while ( sortIt != todoListSorted.end() &&
00694 (*eit)->summary() < (*sortIt)->summary() ) {
00695 ++sortIt;
00696 }
00697 }
00698 todoListSorted.insert( sortIt, *eit );
00699 }
00700 break;
00701 }
00702
00703 return todoListSorted;
00704 }
00705
00706 Todo::List Calendar::todos( TodoSortField sortField,
00707 SortDirection sortDirection )
00708 {
00709 Todo::List tl = rawTodos( sortField, sortDirection );
00710 d->mFilter->apply( &tl );
00711 return tl;
00712 }
00713
00714 Todo::List Calendar::todos( const QDate &date )
00715 {
00716 Todo::List el = rawTodosForDate( date );
00717 d->mFilter->apply( &el );
00718 return el;
00719 }
00720
00721 Journal::List Calendar::sortJournals( Journal::List *journalList,
00722 JournalSortField sortField,
00723 SortDirection sortDirection )
00724 {
00725 Journal::List journalListSorted;
00726 Journal::List::Iterator sortIt;
00727 Journal::List::Iterator eit;
00728
00729 switch( sortField ) {
00730 case JournalSortUnsorted:
00731 journalListSorted = *journalList;
00732 break;
00733
00734 case JournalSortDate:
00735 for ( eit = journalList->begin(); eit != journalList->end(); ++eit ) {
00736 sortIt = journalListSorted.begin();
00737 if ( sortDirection == SortDirectionAscending ) {
00738 while ( sortIt != journalListSorted.end() &&
00739 (*eit)->dtStart() >= (*sortIt)->dtStart() ) {
00740 ++sortIt;
00741 }
00742 } else {
00743 while ( sortIt != journalListSorted.end() &&
00744 (*eit)->dtStart() < (*sortIt)->dtStart() ) {
00745 ++sortIt;
00746 }
00747 }
00748 journalListSorted.insert( sortIt, *eit );
00749 }
00750 break;
00751
00752 case JournalSortSummary:
00753 for ( eit = journalList->begin(); eit != journalList->end(); ++eit ) {
00754 sortIt = journalListSorted.begin();
00755 if ( sortDirection == SortDirectionAscending ) {
00756 while ( sortIt != journalListSorted.end() &&
00757 (*eit)->summary() >= (*sortIt)->summary() ) {
00758 ++sortIt;
00759 }
00760 } else {
00761 while ( sortIt != journalListSorted.end() &&
00762 (*eit)->summary() < (*sortIt)->summary() ) {
00763 ++sortIt;
00764 }
00765 }
00766 journalListSorted.insert( sortIt, *eit );
00767 }
00768 break;
00769 }
00770
00771 return journalListSorted;
00772 }
00773
00774 Journal::List Calendar::journals( JournalSortField sortField,
00775 SortDirection sortDirection )
00776 {
00777 Journal::List jl = rawJournals( sortField, sortDirection );
00778 d->mFilter->apply( &jl );
00779 return jl;
00780 }
00781
00782 Journal::List Calendar::journals( const QDate &date )
00783 {
00784 Journal::List el = rawJournalsForDate( date );
00785 d->mFilter->apply( &el );
00786 return el;
00787 }
00788
00789
00790
00791 void Calendar::setupRelations( Incidence *forincidence )
00792 {
00793 if ( !forincidence ) {
00794 return;
00795 }
00796
00797 QString uid = forincidence->uid();
00798
00799
00800 QList<Incidence*> l = d->mOrphans.values( uid );
00801 d->mOrphans.remove( uid );
00802 for ( int i = 0, end = l.count(); i < end; ++i ) {
00803 l[i]->setRelatedTo( forincidence );
00804 forincidence->addRelation( l[i] );
00805 d->mOrphanUids.remove( l[i]->uid() );
00806 }
00807
00808
00809 if ( !forincidence->relatedTo() && !forincidence->relatedToUid().isEmpty() ) {
00810
00811
00812 Incidence *parent = incidence( forincidence->relatedToUid() );
00813 if ( parent ) {
00814
00815 forincidence->setRelatedTo( parent );
00816 parent->addRelation( forincidence );
00817 } else {
00818
00819
00820
00821
00822 d->mOrphans.insert( forincidence->relatedToUid(), forincidence );
00823 d->mOrphanUids.insert( forincidence->uid(), forincidence );
00824 }
00825 }
00826 }
00827
00828
00829 void Calendar::removeRelations( Incidence *incidence )
00830 {
00831 if ( !incidence ) {
00832 kDebug() << "Warning: incidence is 0";
00833 return;
00834 }
00835
00836 QString uid = incidence->uid();
00837 foreach ( Incidence *i, incidence->relations() ) {
00838 if ( !d->mOrphanUids.contains( i->uid() ) ) {
00839 d->mOrphans.insert( uid, i );
00840 d->mOrphanUids.insert( i->uid(), i );
00841 i->setRelatedTo( 0 );
00842 i->setRelatedToUid( uid );
00843 }
00844 }
00845
00846
00847 if ( incidence->relatedTo() ) {
00848 incidence->relatedTo()->removeRelation( incidence );
00849 }
00850
00851
00852 if ( d->mOrphanUids.remove( uid ) ) {
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862 QStringList relatedToUids;
00863
00864
00865
00866 relatedToUids << incidence->relatedToUid();
00867 for ( QMultiHash<QString, Incidence*>::Iterator it = d->mOrphans.begin();
00868 it != d->mOrphans.end(); ++it ) {
00869 if ( it.value()->uid() == uid ) {
00870 relatedToUids << it.key();
00871 }
00872 }
00873
00874
00875 for ( QStringList::const_iterator uidit = relatedToUids.constBegin();
00876 uidit != relatedToUids.constEnd(); ++uidit ) {
00877 Incidence::List tempList;
00878
00879 QList<Incidence*> l = d->mOrphans.values( *uidit );
00880 d->mOrphans.remove( *uidit );
00881 foreach ( Incidence *i, l ) {
00882 if ( i != incidence ) {
00883 tempList.append( i );
00884 }
00885 }
00886
00887 for ( Incidence::List::Iterator incit = tempList.begin();
00888 incit != tempList.end(); ++incit ) {
00889 d->mOrphans.insert( *uidit, *incit );
00890 }
00891 }
00892 }
00893 }
00894
00895 void Calendar::CalendarObserver::calendarModified( bool modified, Calendar *calendar )
00896 {
00897 Q_UNUSED( modified );
00898 Q_UNUSED( calendar );
00899 }
00900
00901 void Calendar::CalendarObserver::calendarIncidenceAdded( Incidence *incidence )
00902 {
00903 Q_UNUSED( incidence );
00904 }
00905
00906 void Calendar::CalendarObserver::calendarIncidenceChanged( Incidence *incidence )
00907 {
00908 Q_UNUSED( incidence );
00909 }
00910
00911 void Calendar::CalendarObserver::calendarIncidenceDeleted( Incidence *incidence )
00912 {
00913 Q_UNUSED( incidence );
00914 }
00915
00916 void Calendar::registerObserver( CalendarObserver *observer )
00917 {
00918 if ( !d->mObservers.contains( observer ) ) {
00919 d->mObservers.append( observer );
00920 }
00921 d->mNewObserver = true;
00922 }
00923
00924 void Calendar::unregisterObserver( CalendarObserver *observer )
00925 {
00926 d->mObservers.removeAll( observer );
00927 }
00928
00929 bool Calendar::isSaving()
00930 {
00931 return false;
00932 }
00933
00934 void Calendar::setModified( bool modified )
00935 {
00936 if ( modified != d->mModified || d->mNewObserver ) {
00937 d->mNewObserver = false;
00938 foreach ( CalendarObserver *observer, d->mObservers ) {
00939 observer->calendarModified( modified, this );
00940 }
00941 d->mModified = modified;
00942 }
00943 }
00944
00945 bool Calendar::isModified() const
00946 {
00947 return d->mModified;
00948 }
00949
00950 void Calendar::incidenceUpdated( IncidenceBase *incidence )
00951 {
00952 incidence->setLastModified( KDateTime::currentUtcDateTime() );
00953
00954
00955
00956
00957
00958 notifyIncidenceChanged( static_cast<Incidence *>( incidence ) );
00959
00960 setModified( true );
00961 }
00962
00963 void Calendar::doSetTimeSpec( const KDateTime::Spec &timeSpec )
00964 {
00965 Q_UNUSED( timeSpec );
00966 }
00967
00968 void Calendar::notifyIncidenceAdded( Incidence *i )
00969 {
00970 if ( !d->mObserversEnabled ) {
00971 return;
00972 }
00973
00974 foreach ( CalendarObserver *observer, d->mObservers ) {
00975 observer->calendarIncidenceAdded( i );
00976 }
00977 }
00978
00979 void Calendar::notifyIncidenceChanged( Incidence *i )
00980 {
00981 if ( !d->mObserversEnabled ) {
00982 return;
00983 }
00984
00985 foreach ( CalendarObserver *observer, d->mObservers ) {
00986 observer->calendarIncidenceChanged( i );
00987 }
00988 }
00989
00990 void Calendar::notifyIncidenceDeleted( Incidence *i )
00991 {
00992 if ( !d->mObserversEnabled ) {
00993 return;
00994 }
00995
00996 foreach ( CalendarObserver *observer, d->mObservers ) {
00997 observer->calendarIncidenceDeleted( i );
00998 }
00999 }
01000
01001 void Calendar::customPropertyUpdated()
01002 {
01003 setModified( true );
01004 }
01005
01006 void Calendar::setProductId( const QString &id )
01007 {
01008 d->mProductId = id;
01009 }
01010
01011 QString Calendar::productId() const
01012 {
01013 return d->mProductId;
01014 }
01015
01016 Incidence::List Calendar::mergeIncidenceList( const Event::List &events,
01017 const Todo::List &todos,
01018 const Journal::List &journals )
01019 {
01020 Incidence::List incidences;
01021
01022 int i, end;
01023 for ( i = 0, end = events.count(); i < end; ++i ) {
01024 incidences.append( events[i] );
01025 }
01026
01027 for ( i = 0, end = todos.count(); i < end; ++i ) {
01028 incidences.append( todos[i] );
01029 }
01030
01031 for ( i = 0, end = journals.count(); i < end; ++i ) {
01032 incidences.append( journals[i] );
01033 }
01034
01035 return incidences;
01036 }
01037
01038 bool Calendar::beginChange( Incidence *incidence )
01039 {
01040 Q_UNUSED( incidence );
01041 return true;
01042 }
01043
01044 bool Calendar::endChange( Incidence *incidence )
01045 {
01046 Q_UNUSED( incidence );
01047 return true;
01048 }
01049
01050 void Calendar::setObserversEnabled( bool enabled )
01051 {
01052 d->mObserversEnabled = enabled;
01053 }
01054
01055 void Calendar::appendAlarms( Alarm::List &alarms, Incidence *incidence,
01056 const KDateTime &from, const KDateTime &to )
01057 {
01058 KDateTime preTime = from.addSecs(-1);
01059
01060 Alarm::List alarmlist = incidence->alarms();
01061 for ( int i = 0, iend = alarmlist.count(); i < iend; ++i ) {
01062 if ( alarmlist[i]->enabled() ) {
01063 KDateTime dt = alarmlist[i]->nextRepetition( preTime );
01064 if ( dt.isValid() && dt <= to ) {
01065 kDebug() << incidence->summary() << "':" << dt.toString();
01066 alarms.append( alarmlist[i] );
01067 }
01068 }
01069 }
01070 }
01071
01072 void Calendar::appendRecurringAlarms( Alarm::List &alarms,
01073 Incidence *incidence,
01074 const KDateTime &from,
01075 const KDateTime &to )
01076 {
01077 KDateTime dt;
01078 bool endOffsetValid = false;
01079 Duration endOffset( 0 );
01080 Duration period( from, to );
01081
01082 Alarm::List alarmlist = incidence->alarms();
01083 for ( int i = 0, iend = alarmlist.count(); i < iend; ++i ) {
01084 Alarm *a = alarmlist[i];
01085 if ( a->enabled() ) {
01086 if ( a->hasTime() ) {
01087
01088 dt = a->nextRepetition( from.addSecs(-1) );
01089 if ( !dt.isValid() || dt > to ) {
01090 continue;
01091 }
01092 } else {
01093
01094
01095
01096 Duration offset( 0 );
01097 if ( a->hasStartOffset() ) {
01098 offset = a->startOffset();
01099 } else if ( a->hasEndOffset() ) {
01100 offset = a->endOffset();
01101 if ( !endOffsetValid ) {
01102 endOffset = Duration( incidence->dtStart(), incidence->dtEnd() );
01103 endOffsetValid = true;
01104 }
01105 }
01106
01107
01108 KDateTime alarmStart =
01109 offset.end( a->hasEndOffset() ? incidence->dtEnd() : incidence->dtStart() );
01110
01111 if ( alarmStart > to ) {
01112 continue;
01113 }
01114 KDateTime baseStart = incidence->dtStart();
01115 if ( from > alarmStart ) {
01116 alarmStart = from;
01117 baseStart = (-offset).end( (-endOffset).end( alarmStart ) );
01118 }
01119
01120
01121
01122 dt = incidence->recurrence()->getNextDateTime( baseStart.addSecs(-1) );
01123 if ( !dt.isValid() ||
01124 ( dt = endOffset.end( offset.end( dt ) ) ) > to )
01125 {
01126
01127 if ( !a->repeatCount() ) {
01128 continue;
01129 }
01130
01131
01132
01133 bool found = false;
01134 Duration alarmDuration = a->duration();
01135 for ( KDateTime base = baseStart;
01136 ( dt = incidence->recurrence()->getPreviousDateTime( base ) ).isValid();
01137 base = dt ) {
01138 if ( a->duration().end( dt ) < base ) {
01139 break;
01140 }
01141
01142
01143
01144 int snooze = a->snoozeTime().value();
01145 if ( a->snoozeTime().isDaily() ) {
01146 Duration toFromDuration( dt, base );
01147 int toFrom = toFromDuration.asDays();
01148 if ( a->snoozeTime().end( from ) <= to ||
01149 ( toFromDuration.isDaily() && toFrom % snooze == 0 ) ||
01150 ( toFrom / snooze + 1 ) * snooze <= toFrom + period.asDays() ) {
01151 found = true;
01152 #ifndef NDEBUG
01153
01154 dt = offset.end( dt ).addDays( ( ( toFrom - 1 ) / snooze + 1 ) * snooze );
01155 #endif
01156 break;
01157 }
01158 } else {
01159 int toFrom = dt.secsTo( base );
01160 if ( period.asSeconds() >= snooze ||
01161 toFrom % snooze == 0 ||
01162 ( toFrom / snooze + 1 ) * snooze <= toFrom + period.asSeconds() )
01163 {
01164 found = true;
01165 #ifndef NDEBUG
01166
01167 dt = offset.end( dt ).addSecs( ( ( toFrom - 1 ) / snooze + 1 ) * snooze );
01168 #endif
01169 break;
01170 }
01171 }
01172 }
01173 if ( !found ) {
01174 continue;
01175 }
01176 }
01177 }
01178 kDebug() << incidence->summary() << "':" << dt.toString();
01179 alarms.append( a );
01180 }
01181 }
01182 }
01183
01184 #include "calendar.moc"