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