KCalCore Library
calendar.cpp
Go to the documentation of this file.
00001 /* 00002 This file is part of the kcalcore library. 00003 00004 Copyright (c) 1998 Preston Brown <pbrown@kde.org> 00005 Copyright (c) 2000-2004 Cornelius Schumacher <schumacher@kde.org> 00006 Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com> 00007 Copyright (c) 2006 David Jarvie <software@astrojar.org.uk> 00008 00009 This library is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU Library General Public 00011 License as published by the Free Software Foundation; either 00012 version 2 of the License, or (at your option) any later version. 00013 00014 This library is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 Library General Public License for more details. 00018 00019 You should have received a copy of the GNU Library General Public License 00020 along with this library; see the file COPYING.LIB. If not, write to 00021 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00022 Boston, MA 02110-1301, USA. 00023 */ 00037 #include "calendar.h" 00038 #include "calfilter.h" 00039 #include "icaltimezones.h" 00040 #include "sorting.h" 00041 #include "visitor.h" 00042 00043 #include <KDebug> 00044 00045 extern "C" { 00046 #include <icaltimezone.h> 00047 } 00048 00049 #include <algorithm> // for std::remove() 00050 00051 using namespace KCalCore; 00052 00057 //@cond PRIVATE 00058 class KCalCore::Calendar::Private 00059 { 00060 public: 00061 Private() 00062 : mTimeZones( new ICalTimeZones ), 00063 mModified( false ), 00064 mNewObserver( false ), 00065 mObserversEnabled( true ), 00066 mDefaultFilter( new CalFilter ), 00067 batchAddingInProgress( false ) 00068 { 00069 // Setup default filter, which does nothing 00070 mFilter = mDefaultFilter; 00071 mFilter->setEnabled( false ); 00072 00073 mOwner = Person::Ptr( new Person() ); 00074 mOwner->setName( "Unknown Name" ); 00075 mOwner->setEmail( "unknown@nowhere" ); 00076 } 00077 00078 ~Private() 00079 { 00080 delete mTimeZones; 00081 mTimeZones = 0; 00082 if ( mFilter != mDefaultFilter ) { 00083 delete mFilter; 00084 } 00085 delete mDefaultFilter; 00086 } 00087 KDateTime::Spec timeZoneIdSpec( const QString &timeZoneId, bool view ); 00088 00089 QString mProductId; 00090 Person::Ptr mOwner; 00091 ICalTimeZones *mTimeZones; // collection of time zones used in this calendar 00092 ICalTimeZone mBuiltInTimeZone; // cached time zone lookup 00093 ICalTimeZone mBuiltInViewTimeZone; // cached viewing time zone lookup 00094 KDateTime::Spec mTimeSpec; 00095 mutable KDateTime::Spec mViewTimeSpec; 00096 bool mModified; 00097 bool mNewObserver; 00098 bool mObserversEnabled; 00099 QList<CalendarObserver*> mObservers; 00100 00101 CalFilter *mDefaultFilter; 00102 CalFilter *mFilter; 00103 00104 // These lists are used to put together related To-dos 00105 QMultiHash<QString, Incidence::Ptr> mOrphans; 00106 QMultiHash<QString, Incidence::Ptr> mOrphanUids; 00107 00108 // Lists for associating incidences to notebooks 00109 QMultiHash<QString, Incidence::Ptr >mNotebookIncidences; 00110 QHash<QString, QString>mUidToNotebook; 00111 QHash<QString, bool>mNotebooks; // name to visibility 00112 QHash<Incidence::Ptr, bool>mIncidenceVisibility; // incidence -> visibility 00113 QString mDefaultNotebook; // uid of default notebook 00114 QMap<QString, Incidence::List > mIncidenceRelations; 00115 bool batchAddingInProgress; 00116 00117 }; 00118 00122 template <typename K, typename V> 00123 QVector<V> values( const QMultiHash<K,V> &c ) 00124 { 00125 QVector<V> v; 00126 v.reserve( c.size() ); 00127 for ( typename QMultiHash<K,V>::const_iterator it = c.begin(), end = c.end(); it != end; ++it ) { 00128 v.push_back( it.value() ); 00129 } 00130 return v; 00131 } 00132 00133 template <typename K, typename V> 00134 QVector<V> values( const QMultiHash<K,V> &c, const K &x ) 00135 { 00136 QVector<V> v; 00137 typename QMultiHash<K,V>::const_iterator it = c.find( x ); 00138 while ( it != c.end() && it.key() == x ) { 00139 v.push_back( it.value() ); 00140 ++it; 00141 } 00142 return v; 00143 } 00144 00149 template<class T> 00150 class AddVisitor : public Visitor 00151 { 00152 public: 00153 AddVisitor( T *r ) : mResource( r ) {} 00154 00155 bool visit( Event::Ptr e ) 00156 { 00157 return mResource->addEvent( e ); 00158 } 00159 bool visit( Todo::Ptr t ) 00160 { 00161 return mResource->addTodo( t ); 00162 } 00163 bool visit( Journal::Ptr j ) 00164 { 00165 return mResource->addJournal( j ); 00166 } 00167 bool visit( FreeBusy::Ptr ) 00168 { 00169 return false; 00170 } 00171 00172 private: 00173 T *mResource; 00174 }; 00175 00181 template<class T> 00182 class DeleteVisitor : public Visitor 00183 { 00184 public: 00185 DeleteVisitor( T *r ) : mResource( r ) {} 00186 00187 bool visit( Event::Ptr e ) 00188 { 00189 mResource->deleteEvent( e ); 00190 return true; 00191 } 00192 bool visit( Todo::Ptr t ) 00193 { 00194 mResource->deleteTodo( t ); 00195 return true; 00196 } 00197 bool visit( Journal::Ptr j ) 00198 { 00199 mResource->deleteJournal( j ); 00200 return true; 00201 } 00202 bool visit( FreeBusy::Ptr ) 00203 { 00204 return false; 00205 } 00206 00207 private: 00208 T *mResource; 00209 }; 00210 //@endcond 00211 00212 Calendar::Calendar( const KDateTime::Spec &timeSpec ) 00213 : d( new KCalCore::Calendar::Private ) 00214 { 00215 d->mTimeSpec = timeSpec; 00216 d->mViewTimeSpec = timeSpec; 00217 } 00218 00219 Calendar::Calendar( const QString &timeZoneId ) 00220 : d( new KCalCore::Calendar::Private ) 00221 { 00222 setTimeZoneId( timeZoneId ); 00223 } 00224 00225 Calendar::~Calendar() 00226 { 00227 delete d; 00228 } 00229 00230 Person::Ptr Calendar::owner() const 00231 { 00232 return d->mOwner; 00233 } 00234 00235 void Calendar::setOwner( const Person::Ptr &owner ) 00236 { 00237 Q_ASSERT( owner ); 00238 d->mOwner = owner; 00239 setModified( true ); 00240 } 00241 00242 void Calendar::setTimeSpec( const KDateTime::Spec &timeSpec ) 00243 { 00244 d->mTimeSpec = timeSpec; 00245 d->mBuiltInTimeZone = ICalTimeZone(); 00246 setViewTimeSpec( timeSpec ); 00247 00248 doSetTimeSpec( d->mTimeSpec ); 00249 } 00250 00251 KDateTime::Spec Calendar::timeSpec() const 00252 { 00253 return d->mTimeSpec; 00254 } 00255 00256 void Calendar::setTimeZoneId( const QString &timeZoneId ) 00257 { 00258 d->mTimeSpec = d->timeZoneIdSpec( timeZoneId, false ); 00259 d->mViewTimeSpec = d->mTimeSpec; 00260 d->mBuiltInViewTimeZone = d->mBuiltInTimeZone; 00261 00262 doSetTimeSpec( d->mTimeSpec ); 00263 } 00264 00265 //@cond PRIVATE 00266 KDateTime::Spec Calendar::Private::timeZoneIdSpec( const QString &timeZoneId, 00267 bool view ) 00268 { 00269 if ( view ) { 00270 mBuiltInViewTimeZone = ICalTimeZone(); 00271 } else { 00272 mBuiltInTimeZone = ICalTimeZone(); 00273 } 00274 if ( timeZoneId == QLatin1String( "UTC" ) ) { 00275 return KDateTime::UTC; 00276 } 00277 ICalTimeZone tz = mTimeZones->zone( timeZoneId ); 00278 if ( !tz.isValid() ) { 00279 ICalTimeZoneSource tzsrc; 00280 tz = tzsrc.parse( icaltimezone_get_builtin_timezone( timeZoneId.toLatin1() ) ); 00281 if ( view ) { 00282 mBuiltInViewTimeZone = tz; 00283 } else { 00284 mBuiltInTimeZone = tz; 00285 } 00286 } 00287 if ( tz.isValid() ) { 00288 return tz; 00289 } else { 00290 return KDateTime::ClockTime; 00291 } 00292 } 00293 //@endcond 00294 00295 QString Calendar::timeZoneId() const 00296 { 00297 KTimeZone tz = d->mTimeSpec.timeZone(); 00298 return tz.isValid() ? tz.name() : QString(); 00299 } 00300 00301 void Calendar::setViewTimeSpec( const KDateTime::Spec &timeSpec ) const 00302 { 00303 d->mViewTimeSpec = timeSpec; 00304 d->mBuiltInViewTimeZone = ICalTimeZone(); 00305 } 00306 00307 void Calendar::setViewTimeZoneId( const QString &timeZoneId ) const 00308 { 00309 d->mViewTimeSpec = d->timeZoneIdSpec( timeZoneId, true ); 00310 } 00311 00312 KDateTime::Spec Calendar::viewTimeSpec() const 00313 { 00314 return d->mViewTimeSpec; 00315 } 00316 00317 QString Calendar::viewTimeZoneId() const 00318 { 00319 KTimeZone tz = d->mViewTimeSpec.timeZone(); 00320 return tz.isValid() ? tz.name() : QString(); 00321 } 00322 00323 ICalTimeZones *Calendar::timeZones() const 00324 { 00325 return d->mTimeZones; 00326 } 00327 00328 void Calendar::setTimeZones( ICalTimeZones *zones ) 00329 { 00330 if ( !zones ) { 00331 return; 00332 } 00333 00334 if ( d->mTimeZones && ( d->mTimeZones != zones ) ) { 00335 delete d->mTimeZones; 00336 d->mTimeZones = 0; 00337 } 00338 d->mTimeZones = zones; 00339 } 00340 00341 void Calendar::shiftTimes( const KDateTime::Spec &oldSpec, const KDateTime::Spec &newSpec ) 00342 { 00343 setTimeSpec( newSpec ); 00344 00345 int i, end; 00346 Event::List ev = events(); 00347 for ( i = 0, end = ev.count(); i < end; ++i ) { 00348 ev[i]->shiftTimes( oldSpec, newSpec ); 00349 } 00350 00351 Todo::List to = todos(); 00352 for ( i = 0, end = to.count(); i < end; ++i ) { 00353 to[i]->shiftTimes( oldSpec, newSpec ); 00354 } 00355 00356 Journal::List jo = journals(); 00357 for ( i = 0, end = jo.count(); i < end; ++i ) { 00358 jo[i]->shiftTimes( oldSpec, newSpec ); 00359 } 00360 } 00361 00362 void Calendar::setFilter( CalFilter *filter ) 00363 { 00364 if ( filter ) { 00365 d->mFilter = filter; 00366 } else { 00367 d->mFilter = d->mDefaultFilter; 00368 } 00369 } 00370 00371 CalFilter *Calendar::filter() const 00372 { 00373 return d->mFilter; 00374 } 00375 00376 QStringList Calendar::categories() const 00377 { 00378 Incidence::List rawInc( rawIncidences() ); 00379 QStringList cats, thisCats; 00380 // @TODO: For now just iterate over all incidences. In the future, 00381 // the list of categories should be built when reading the file. 00382 for ( Incidence::List::ConstIterator i = rawInc.constBegin(); 00383 i != rawInc.constEnd(); ++i ) { 00384 thisCats = (*i)->categories(); 00385 for ( QStringList::ConstIterator si = thisCats.constBegin(); 00386 si != thisCats.constEnd(); ++si ) { 00387 if ( !cats.contains( *si ) ) { 00388 cats.append( *si ); 00389 } 00390 } 00391 } 00392 return cats; 00393 } 00394 00395 Incidence::List Calendar::incidences( const QDate &date ) const 00396 { 00397 return mergeIncidenceList( events( date ), todos( date ), journals( date ) ); 00398 } 00399 00400 Incidence::List Calendar::incidences() const 00401 { 00402 return mergeIncidenceList( events(), todos(), journals() ); 00403 } 00404 00405 Incidence::List Calendar::rawIncidences() const 00406 { 00407 return mergeIncidenceList( rawEvents(), rawTodos(), rawJournals() ); 00408 } 00409 00410 Incidence::List Calendar::instances( const Incidence::Ptr &incidence ) const 00411 { 00412 if ( incidence ) { 00413 Event::List elist; 00414 Todo::List tlist; 00415 Journal::List jlist; 00416 00417 if ( incidence->type() == Incidence::TypeEvent ) { 00418 elist = eventInstances( incidence ); 00419 } else if ( incidence->type() == Incidence::TypeTodo ) { 00420 tlist = todoInstances( incidence ); 00421 } else if ( incidence->type() == Incidence::TypeJournal ) { 00422 jlist = journalInstances( incidence ); 00423 } 00424 return mergeIncidenceList( elist, tlist, jlist ); 00425 } else { 00426 return Incidence::List(); 00427 } 00428 } 00429 00430 Incidence::List Calendar::duplicates( const Incidence::Ptr &incidence ) 00431 { 00432 if ( incidence ) { 00433 Incidence::List list; 00434 Incidence::List vals = values( d->mNotebookIncidences ); 00435 Incidence::List::const_iterator it; 00436 for ( it = vals.constBegin(); it != vals.constEnd(); ++it ) { 00437 if ( ( ( incidence->dtStart() == (*it)->dtStart() ) || 00438 ( !incidence->dtStart().isValid() && !(*it)->dtStart().isValid() ) ) && 00439 ( incidence->summary() == (*it)->summary() ) ) { 00440 list.append( *it ); 00441 } 00442 } 00443 return list; 00444 } else { 00445 return Incidence::List(); 00446 } 00447 } 00448 00449 bool Calendar::addNotebook( const QString ¬ebook, bool isVisible ) 00450 { 00451 if ( d->mNotebooks.contains( notebook ) ) { 00452 return false; 00453 } else { 00454 d->mNotebooks.insert( notebook, isVisible ); 00455 return true; 00456 } 00457 } 00458 00459 bool Calendar::updateNotebook( const QString ¬ebook, bool isVisible ) 00460 { 00461 if ( !d->mNotebooks.contains( notebook ) ) { 00462 return false; 00463 } else { 00464 d->mNotebooks.insert( notebook, isVisible ); 00465 return true; 00466 } 00467 } 00468 00469 bool Calendar::deleteNotebook( const QString ¬ebook ) 00470 { 00471 if ( !d->mNotebooks.contains( notebook ) ) { 00472 return false; 00473 } else { 00474 return d->mNotebooks.remove( notebook ); 00475 } 00476 } 00477 00478 bool Calendar::setDefaultNotebook( const QString ¬ebook ) 00479 { 00480 if ( !d->mNotebooks.contains( notebook ) ) { 00481 return false; 00482 } else { 00483 d->mDefaultNotebook = notebook; 00484 return true; 00485 } 00486 } 00487 00488 QString Calendar::defaultNotebook() const 00489 { 00490 return d->mDefaultNotebook; 00491 } 00492 00493 bool Calendar::hasValidNotebook( const QString ¬ebook ) const 00494 { 00495 return d->mNotebooks.contains( notebook ); 00496 } 00497 00498 bool Calendar::isVisible( const Incidence::Ptr &incidence ) const 00499 { 00500 if ( d->mIncidenceVisibility.contains( incidence ) ) { 00501 return d->mIncidenceVisibility[incidence]; 00502 } 00503 const QString nuid = notebook( incidence ); 00504 bool rv; 00505 if ( d->mNotebooks.contains( nuid ) ) { 00506 rv = d->mNotebooks.value( nuid ); 00507 } else { 00508 // NOTE returns true also for nonexisting notebooks for compatibility 00509 rv = true; 00510 } 00511 d->mIncidenceVisibility[incidence] = rv; 00512 return rv; 00513 } 00514 00515 void Calendar::clearNotebookAssociations() 00516 { 00517 d->mNotebookIncidences.clear(); 00518 d->mUidToNotebook.clear(); 00519 d->mIncidenceVisibility.clear(); 00520 } 00521 00522 bool Calendar::setNotebook( const Incidence::Ptr &inc, const QString ¬ebook ) 00523 { 00524 if ( !inc ) { 00525 return false; 00526 } 00527 00528 if ( !notebook.isEmpty() && 00529 !incidence( inc->uid(), inc->recurrenceId() ) ) { 00530 kWarning() << "cannot set notebook until incidence has been added"; 00531 return false; 00532 } 00533 00534 if ( d->mUidToNotebook.contains( inc->uid() ) ) { 00535 QString old = d->mUidToNotebook.value( inc->uid() ); 00536 if ( !old.isEmpty() && notebook != old ) { 00537 if ( inc->hasRecurrenceId() ) { 00538 kWarning() << "cannot set notebook for child incidences"; 00539 return false; 00540 } 00541 // Move all possible children also. 00542 Incidence::List list = instances( inc ); 00543 Incidence::List::Iterator it; 00544 for ( it = list.begin(); it != list.end(); ++it ) { 00545 d->mNotebookIncidences.remove( old, *it ); 00546 d->mNotebookIncidences.insert( notebook, *it ); 00547 } 00548 notifyIncidenceChanged( inc ); // for removing from old notebook 00549 // don not remove from mUidToNotebook to keep deleted incidences 00550 d->mNotebookIncidences.remove( old, inc ); 00551 } 00552 } 00553 if ( !notebook.isEmpty() ) { 00554 d->mUidToNotebook.insert( inc->uid(), notebook ); 00555 d->mNotebookIncidences.insert( notebook, inc ); 00556 kDebug() << "setting notebook" << notebook << "for" << inc->uid(); 00557 notifyIncidenceChanged( inc ); // for inserting into new notebook 00558 } 00559 00560 return true; 00561 } 00562 00563 QString Calendar::notebook( const Incidence::Ptr &incidence ) const 00564 { 00565 if ( incidence ) { 00566 return d->mUidToNotebook.value( incidence->uid() ); 00567 } else { 00568 return QString(); 00569 } 00570 } 00571 00572 QString Calendar::notebook( const QString &uid ) const 00573 { 00574 return d->mUidToNotebook.value( uid ); 00575 } 00576 00577 QStringList Calendar::notebooks() const 00578 { 00579 return d->mNotebookIncidences.uniqueKeys(); 00580 } 00581 00582 Incidence::List Calendar::incidences( const QString ¬ebook ) const 00583 { 00584 if ( notebook.isEmpty() ) { 00585 return values( d->mNotebookIncidences ); 00586 } else { 00587 return values( d->mNotebookIncidences, notebook ); 00588 } 00589 } 00590 00592 Event::List Calendar::sortEvents( const Event::List &eventList, 00593 EventSortField sortField, 00594 SortDirection sortDirection ) 00595 { 00596 00597 if ( eventList.isEmpty() ) { 00598 return Event::List(); 00599 } 00600 00601 Event::List eventListSorted; 00602 00603 // Notice we alphabetically presort Summaries first. 00604 // We do this so comparison "ties" stay in a nice order. 00605 eventListSorted = eventList; 00606 switch( sortField ) { 00607 case EventSortUnsorted: 00608 break; 00609 00610 case EventSortStartDate: 00611 if ( sortDirection == SortDirectionAscending ) { 00612 qSort( eventListSorted.begin(), eventListSorted.end(), Events::startDateLessThan ); 00613 } else { 00614 qSort( eventListSorted.begin(), eventListSorted.end(), Events::startDateMoreThan ); 00615 } 00616 break; 00617 00618 case EventSortEndDate: 00619 if ( sortDirection == SortDirectionAscending ) { 00620 qSort( eventListSorted.begin(), eventListSorted.end(), Events::endDateLessThan ); 00621 } else { 00622 qSort( eventListSorted.begin(), eventListSorted.end(), Events::endDateMoreThan ); 00623 } 00624 break; 00625 00626 case EventSortSummary: 00627 if ( sortDirection == SortDirectionAscending ) { 00628 qSort( eventListSorted.begin(), eventListSorted.end(), Events::summaryLessThan ); 00629 } else { 00630 qSort( eventListSorted.begin(), eventListSorted.end(), Events::summaryMoreThan ); 00631 } 00632 break; 00633 } 00634 00635 return eventListSorted; 00636 00637 } 00638 00639 Event::List Calendar::events( const QDate &date, 00640 const KDateTime::Spec &timeSpec, 00641 EventSortField sortField, 00642 SortDirection sortDirection ) const 00643 { 00644 Event::List el = rawEventsForDate( date, timeSpec, sortField, sortDirection ); 00645 d->mFilter->apply( &el ); 00646 return el; 00647 } 00648 00649 Event::List Calendar::events( const KDateTime &dt ) const 00650 { 00651 Event::List el = rawEventsForDate( dt ); 00652 d->mFilter->apply( &el ); 00653 return el; 00654 } 00655 00656 Event::List Calendar::events( const QDate &start, const QDate &end, 00657 const KDateTime::Spec &timeSpec, 00658 bool inclusive ) const 00659 { 00660 Event::List el = rawEvents( start, end, timeSpec, inclusive ); 00661 d->mFilter->apply( &el ); 00662 return el; 00663 } 00664 00665 Event::List Calendar::events( EventSortField sortField, 00666 SortDirection sortDirection ) const 00667 { 00668 Event::List el = rawEvents( sortField, sortDirection ); 00669 d->mFilter->apply( &el ); 00670 return el; 00671 } 00672 00673 bool Calendar::addIncidence( const Incidence::Ptr &incidence ) 00674 { 00675 if ( !incidence ) { 00676 return false; 00677 } 00678 00679 AddVisitor<Calendar> v( this ); 00680 return incidence->accept( v, incidence ); 00681 } 00682 00683 bool Calendar::deleteIncidence( const Incidence::Ptr &incidence ) 00684 { 00685 if ( !incidence ) { 00686 return false; 00687 } 00688 00689 if ( beginChange( incidence ) ) { 00690 DeleteVisitor<Calendar> v( this ); 00691 const bool result = incidence->accept( v, incidence ); 00692 endChange( incidence ); 00693 return result; 00694 } else { 00695 return false; 00696 } 00697 } 00698 00699 // Dissociate a single occurrence or all future occurrences from a recurring 00700 // sequence. The new incidence is returned, but not automatically inserted 00701 // into the calendar, which is left to the calling application. 00702 Incidence::Ptr Calendar::dissociateOccurrence( const Incidence::Ptr &incidence, 00703 const QDate &date, 00704 const KDateTime::Spec &spec, 00705 bool single ) 00706 { 00707 if ( !incidence || !incidence->recurs() ) { 00708 return Incidence::Ptr(); 00709 } 00710 00711 Incidence::Ptr newInc( incidence->clone() ); 00712 newInc->recreate(); 00713 // Do not call setRelatedTo() when dissociating recurring to-dos, otherwise the new to-do 00714 // will appear as a child. Originally, we planned to set a relation with reltype SIBLING 00715 // when dissociating to-dos, but currently kcalcore only supports reltype PARENT. 00716 // We can uncomment the following line when we support the PARENT reltype. 00717 //newInc->setRelatedTo( incidence ); 00718 Recurrence *recur = newInc->recurrence(); 00719 if ( single ) { 00720 recur->clear(); 00721 } else { 00722 // Adjust the recurrence for the future incidences. In particular adjust 00723 // the "end after n occurrences" rules! "No end date" and "end by ..." 00724 // don't need to be modified. 00725 int duration = recur->duration(); 00726 if ( duration > 0 ) { 00727 int doneduration = recur->durationTo( date.addDays( -1 ) ); 00728 if ( doneduration >= duration ) { 00729 kDebug() << "The dissociated event already occurred more often" 00730 << "than it was supposed to ever occur. ERROR!"; 00731 recur->clear(); 00732 } else { 00733 recur->setDuration( duration - doneduration ); 00734 } 00735 } 00736 } 00737 // Adjust the date of the incidence 00738 if ( incidence->type() == Incidence::TypeEvent ) { 00739 Event::Ptr ev = newInc.staticCast<Event>(); 00740 KDateTime start( ev->dtStart() ); 00741 int daysTo = start.toTimeSpec( spec ).date().daysTo( date ); 00742 ev->setDtStart( start.addDays( daysTo ) ); 00743 ev->setDtEnd( ev->dtEnd().addDays( daysTo ) ); 00744 } else if ( incidence->type() == Incidence::TypeTodo ) { 00745 Todo::Ptr td = newInc.staticCast<Todo>(); 00746 bool haveOffset = false; 00747 int daysTo = 0; 00748 if ( td->hasDueDate() ) { 00749 KDateTime due( td->dtDue() ); 00750 daysTo = due.toTimeSpec( spec ).date().daysTo( date ); 00751 td->setDtDue( due.addDays( daysTo ), true ); 00752 haveOffset = true; 00753 } 00754 if ( td->hasStartDate() ) { 00755 KDateTime start( td->dtStart() ); 00756 if ( !haveOffset ) { 00757 daysTo = start.toTimeSpec( spec ).date().daysTo( date ); 00758 } 00759 td->setDtStart( start.addDays( daysTo ) ); 00760 haveOffset = true; 00761 } 00762 } 00763 recur = incidence->recurrence(); 00764 if ( recur ) { 00765 if ( single ) { 00766 recur->addExDate( date ); 00767 } else { 00768 // Make sure the recurrence of the past events ends 00769 // at the corresponding day 00770 recur->setEndDate( date.addDays(-1) ); 00771 } 00772 } 00773 return newInc; 00774 } 00775 00776 Incidence::Ptr Calendar::incidence( const QString &uid, 00777 const KDateTime &recurrenceId ) const 00778 { 00779 Incidence::Ptr i = event( uid, recurrenceId ); 00780 if ( i ) { 00781 return i; 00782 } 00783 00784 i = todo( uid, recurrenceId ); 00785 if ( i ) { 00786 return i; 00787 } 00788 00789 i = journal( uid, recurrenceId ); 00790 return i; 00791 } 00792 00793 Incidence::Ptr Calendar::deleted( const QString &uid, const KDateTime &recurrenceId ) const 00794 { 00795 Incidence::Ptr i = deletedEvent( uid, recurrenceId ); 00796 if ( i ) { 00797 return i; 00798 } 00799 00800 i = deletedTodo( uid, recurrenceId ); 00801 if ( i ) { 00802 return i; 00803 } 00804 00805 i = deletedJournal( uid, recurrenceId ); 00806 return i; 00807 } 00808 00809 Incidence::List Calendar::incidencesFromSchedulingID( const QString &sid ) const 00810 { 00811 Incidence::List result; 00812 const Incidence::List incidences = rawIncidences(); 00813 Incidence::List::const_iterator it = incidences.begin(); 00814 for ( ; it != incidences.end(); ++it ) { 00815 if ( (*it)->schedulingID() == sid ) { 00816 result.append( *it ); 00817 } 00818 } 00819 return result; 00820 } 00821 00822 Incidence::Ptr Calendar::incidenceFromSchedulingID( const QString &uid ) const 00823 { 00824 const Incidence::List incidences = rawIncidences(); 00825 Incidence::List::const_iterator it = incidences.begin(); 00826 for ( ; it != incidences.end(); ++it ) { 00827 if ( (*it)->schedulingID() == uid ) { 00828 // Touchdown, and the crowd goes wild 00829 return *it; 00830 } 00831 } 00832 // Not found 00833 return Incidence::Ptr(); 00834 } 00835 00837 Todo::List Calendar::sortTodos( const Todo::List &todoList, 00838 TodoSortField sortField, 00839 SortDirection sortDirection ) 00840 { 00841 if ( todoList.isEmpty() ) { 00842 return Todo::List(); 00843 } 00844 00845 Todo::List todoListSorted; 00846 00847 // Notice we alphabetically presort Summaries first. 00848 // We do this so comparison "ties" stay in a nice order. 00849 00850 // Note that To-dos may not have Start DateTimes nor due DateTimes. 00851 00852 todoListSorted = todoList; 00853 switch( sortField ) { 00854 case TodoSortUnsorted: 00855 break; 00856 00857 case TodoSortStartDate: 00858 if ( sortDirection == SortDirectionAscending ) { 00859 qSort( todoListSorted.begin(), todoListSorted.end(), Todos::startDateLessThan ); 00860 } else { 00861 qSort( todoListSorted.begin(), todoListSorted.end(), Todos::startDateMoreThan ); 00862 } 00863 break; 00864 00865 case TodoSortDueDate: 00866 if ( sortDirection == SortDirectionAscending ) { 00867 qSort( todoListSorted.begin(), todoListSorted.end(), Todos::dueDateLessThan ); 00868 } else { 00869 qSort( todoListSorted.begin(), todoListSorted.end(), Todos::dueDateMoreThan ); 00870 } 00871 break; 00872 00873 case TodoSortPriority: 00874 if ( sortDirection == SortDirectionAscending ) { 00875 qSort( todoListSorted.begin(), todoListSorted.end(), Todos::priorityLessThan ); 00876 } else { 00877 qSort( todoListSorted.begin(), todoListSorted.end(), Todos::priorityMoreThan ); 00878 } 00879 break; 00880 00881 case TodoSortPercentComplete: 00882 if ( sortDirection == SortDirectionAscending ) { 00883 qSort( todoListSorted.begin(), todoListSorted.end(), Todos::percentLessThan ); 00884 } else { 00885 qSort( todoListSorted.begin(), todoListSorted.end(), Todos::percentMoreThan ); 00886 } 00887 break; 00888 00889 case TodoSortSummary: 00890 if ( sortDirection == SortDirectionAscending ) { 00891 qSort( todoListSorted.begin(), todoListSorted.end(), Todos::summaryLessThan ); 00892 } else { 00893 qSort( todoListSorted.begin(), todoListSorted.end(), Todos::summaryMoreThan ); 00894 } 00895 break; 00896 00897 case TodoSortCreated: 00898 if ( sortDirection == SortDirectionAscending ) { 00899 qSort( todoListSorted.begin(), todoListSorted.end(), Todos::createdLessThan ); 00900 } else { 00901 qSort( todoListSorted.begin(), todoListSorted.end(), Todos::createdMoreThan ); 00902 } 00903 break; 00904 } 00905 00906 return todoListSorted; 00907 } 00908 00909 Todo::List Calendar::todos( TodoSortField sortField, 00910 SortDirection sortDirection ) const 00911 { 00912 Todo::List tl = rawTodos( sortField, sortDirection ); 00913 d->mFilter->apply( &tl ); 00914 return tl; 00915 } 00916 00917 Todo::List Calendar::todos( const QDate &date ) const 00918 { 00919 Todo::List el = rawTodosForDate( date ); 00920 d->mFilter->apply( &el ); 00921 return el; 00922 } 00923 00924 Todo::List Calendar::todos( const QDate &start, const QDate &end, 00925 const KDateTime::Spec ×pec, bool inclusive ) const 00926 { 00927 Todo::List tl = rawTodos( start, end, timespec, inclusive ); 00928 d->mFilter->apply( &tl ); 00929 return tl; 00930 } 00931 00933 Journal::List Calendar::sortJournals( const Journal::List &journalList, 00934 JournalSortField sortField, 00935 SortDirection sortDirection ) 00936 { 00937 if ( journalList.isEmpty() ) { 00938 return Journal::List(); 00939 } 00940 00941 Journal::List journalListSorted = journalList; 00942 00943 switch( sortField ) { 00944 case JournalSortUnsorted: 00945 break; 00946 00947 case JournalSortDate: 00948 if ( sortDirection == SortDirectionAscending ) { 00949 qSort( journalListSorted.begin(), journalListSorted.end(), Journals::dateLessThan ); 00950 } else { 00951 qSort( journalListSorted.begin(), journalListSorted.end(), Journals::dateMoreThan ); 00952 } 00953 break; 00954 00955 case JournalSortSummary: 00956 if ( sortDirection == SortDirectionAscending ) { 00957 qSort( journalListSorted.begin(), journalListSorted.end(), Journals::summaryLessThan ); 00958 } else { 00959 qSort( journalListSorted.begin(), journalListSorted.end(), Journals::summaryMoreThan ); 00960 } 00961 break; 00962 } 00963 00964 return journalListSorted; 00965 } 00966 00967 Journal::List Calendar::journals( JournalSortField sortField, 00968 SortDirection sortDirection ) const 00969 { 00970 Journal::List jl = rawJournals( sortField, sortDirection ); 00971 d->mFilter->apply( &jl ); 00972 return jl; 00973 } 00974 00975 Journal::List Calendar::journals( const QDate &date ) const 00976 { 00977 Journal::List el = rawJournalsForDate( date ); 00978 d->mFilter->apply( &el ); 00979 return el; 00980 } 00981 00982 // When this is called, the to-dos have already been added to the calendar. 00983 // This method is only about linking related to-dos. 00984 void Calendar::setupRelations( const Incidence::Ptr &forincidence ) 00985 { 00986 if ( !forincidence ) { 00987 return; 00988 } 00989 00990 const QString uid = forincidence->uid(); 00991 00992 // First, go over the list of orphans and see if this is their parent 00993 Incidence::List l = values( d->mOrphans, uid ); 00994 d->mOrphans.remove( uid ); 00995 for ( int i = 0, end = l.count(); i < end; ++i ) { 00996 d->mIncidenceRelations[uid].append( l[i] ); 00997 d->mOrphanUids.remove( l[i]->uid() ); 00998 } 00999 01000 // Now see about this incidences parent 01001 if ( forincidence->relatedTo().isEmpty() && !forincidence->relatedTo().isEmpty() ) { 01002 // Incidence has a uid it is related to but is not registered to it yet. 01003 // Try to find it 01004 Incidence::Ptr parent = incidence( forincidence->relatedTo() ); 01005 if ( parent ) { 01006 // Found it 01007 01008 // look for hierarchy loops 01009 if ( isAncestorOf( forincidence, parent ) ) { 01010 forincidence->setRelatedTo( QString() ); 01011 kWarning() << "hierarchy loop beetween " << forincidence->uid() << " and " << parent->uid(); 01012 } else { 01013 d->mIncidenceRelations[parent->uid()].append( forincidence ); 01014 } 01015 } else { 01016 // Not found, put this in the mOrphans list 01017 // Note that the mOrphans dict might contain multiple entries with the 01018 // same key! which are multiple children that wait for the parent 01019 // incidence to be inserted. 01020 d->mOrphans.insert( forincidence->relatedTo(), forincidence ); 01021 d->mOrphanUids.insert( forincidence->uid(), forincidence ); 01022 } 01023 } 01024 } 01025 01026 // If a to-do with sub-to-dos is deleted, move it's sub-to-dos to the orphan list 01027 void Calendar::removeRelations( const Incidence::Ptr &incidence ) 01028 { 01029 if ( !incidence ) { 01030 kDebug() << "Warning: incidence is 0"; 01031 return; 01032 } 01033 01034 const QString uid = incidence->uid(); 01035 01036 foreach ( Incidence::Ptr i, d->mIncidenceRelations[uid] ) { 01037 if ( !d->mOrphanUids.contains( i->uid() ) ) { 01038 d->mOrphans.insert( uid, i ); 01039 d->mOrphanUids.insert( i->uid(), i ); 01040 i->setRelatedTo( uid ); 01041 } 01042 } 01043 01044 const QString parentUid = incidence->relatedTo(); 01045 01046 // If this incidence is related to something else, tell that about it 01047 if ( !parentUid.isEmpty() ) { 01048 d->mIncidenceRelations[parentUid].erase( 01049 std::remove( d->mIncidenceRelations[parentUid].begin(), 01050 d->mIncidenceRelations[parentUid].end(), incidence ), 01051 d->mIncidenceRelations[parentUid].end() ); 01052 } 01053 01054 // Remove this one from the orphans list 01055 if ( d->mOrphanUids.remove( uid ) ) { 01056 // This incidence is located in the orphans list - it should be removed 01057 // Since the mOrphans dict might contain the same key (with different 01058 // child incidence pointers!) multiple times, take care that we remove 01059 // the correct one. So we need to remove all items with the given 01060 // parent UID, and readd those that are not for this item. Also, there 01061 // might be other entries with differnet UID that point to this 01062 // incidence (this might happen when the relatedTo of the item is 01063 // changed before its parent is inserted. This might happen with 01064 // groupware servers....). Remove them, too 01065 QStringList relatedToUids; 01066 01067 // First, create a list of all keys in the mOrphans list which point 01068 // to the removed item 01069 relatedToUids << incidence->relatedTo(); 01070 for ( QMultiHash<QString, Incidence::Ptr>::Iterator it = d->mOrphans.begin(); 01071 it != d->mOrphans.end(); ++it ) { 01072 if ( it.value()->uid() == uid ) { 01073 relatedToUids << it.key(); 01074 } 01075 } 01076 01077 // now go through all uids that have one entry that point to the incidence 01078 for ( QStringList::const_iterator uidit = relatedToUids.constBegin(); 01079 uidit != relatedToUids.constEnd(); ++uidit ) { 01080 Incidence::List tempList; 01081 // Remove all to get access to the remaining entries 01082 QList<Incidence::Ptr> l = d->mOrphans.values( *uidit ); 01083 d->mOrphans.remove( *uidit ); 01084 foreach ( Incidence::Ptr i, l ) { 01085 if ( i != incidence ) { 01086 tempList.append( i ); 01087 } 01088 } 01089 // Readd those that point to a different orphan incidence 01090 for ( Incidence::List::Iterator incit = tempList.begin(); 01091 incit != tempList.end(); ++incit ) { 01092 d->mOrphans.insert( *uidit, *incit ); 01093 } 01094 } 01095 } 01096 01097 // Make sure the deleted incidence doesn't relate to a non-deleted incidence, 01098 // since that would cause trouble in MemoryCalendar::close(), as the deleted 01099 // incidences are destroyed after the non-deleted incidences. The destructor 01100 // of the deleted incidences would then try to access the already destroyed 01101 // non-deleted incidence, which would segfault. 01102 // 01103 // So in short: Make sure dead incidences don't point to alive incidences 01104 // via the relation. 01105 // 01106 // This crash is tested in MemoryCalendarTest::testRelationsCrash(). 01107 // incidence->setRelatedTo( Incidence::Ptr() ); 01108 } 01109 01110 bool Calendar::isAncestorOf( const Incidence::Ptr &ancestor, 01111 const Incidence::Ptr &incidence ) const 01112 { 01113 if ( !incidence || incidence->relatedTo().isEmpty() ) { 01114 return false; 01115 } else if ( incidence->relatedTo() == ancestor->uid() ) { 01116 return true; 01117 } else { 01118 return isAncestorOf( ancestor, this->incidence( incidence->relatedTo() ) ); 01119 } 01120 } 01121 01122 Incidence::List Calendar::relations( const QString &uid ) const 01123 { 01124 return d->mIncidenceRelations[uid]; 01125 } 01126 01127 Calendar::CalendarObserver::~CalendarObserver() 01128 { 01129 } 01130 01131 void Calendar::CalendarObserver::calendarModified( bool modified, Calendar *calendar ) 01132 { 01133 Q_UNUSED( modified ); 01134 Q_UNUSED( calendar ); 01135 } 01136 01137 void Calendar::CalendarObserver::calendarIncidenceAdded( const Incidence::Ptr &incidence ) 01138 { 01139 Q_UNUSED( incidence ); 01140 } 01141 01142 void Calendar::CalendarObserver::calendarIncidenceChanged( const Incidence::Ptr &incidence ) 01143 { 01144 Q_UNUSED( incidence ); 01145 } 01146 01147 void Calendar::CalendarObserver::calendarIncidenceDeleted( const Incidence::Ptr &incidence ) 01148 { 01149 Q_UNUSED( incidence ); 01150 } 01151 01152 void 01153 Calendar::CalendarObserver::calendarIncidenceAdditionCanceled( const Incidence::Ptr &incidence ) 01154 { 01155 Q_UNUSED( incidence ); 01156 } 01157 01158 void Calendar::registerObserver( CalendarObserver *observer ) 01159 { 01160 if ( !observer ) { 01161 return; 01162 } 01163 01164 if ( !d->mObservers.contains( observer ) ) { 01165 d->mObservers.append( observer ); 01166 } else { 01167 d->mNewObserver = true; 01168 } 01169 } 01170 01171 void Calendar::unregisterObserver( CalendarObserver *observer ) 01172 { 01173 if ( !observer ) { 01174 return; 01175 } else { 01176 d->mObservers.removeAll( observer ); 01177 } 01178 } 01179 01180 bool Calendar::isSaving() const 01181 { 01182 return false; 01183 } 01184 01185 void Calendar::setModified( bool modified ) 01186 { 01187 if ( modified != d->mModified || d->mNewObserver ) { 01188 d->mNewObserver = false; 01189 foreach ( CalendarObserver *observer, d->mObservers ) { 01190 observer->calendarModified( modified, this ); 01191 } 01192 d->mModified = modified; 01193 } 01194 } 01195 01196 bool Calendar::isModified() const 01197 { 01198 return d->mModified; 01199 } 01200 01201 bool Calendar::save() 01202 { 01203 return true; 01204 } 01205 01206 bool Calendar::reload() 01207 { 01208 return true; 01209 } 01210 01211 void Calendar::incidenceUpdated( const QString &uid, const KDateTime &recurrenceId ) 01212 { 01213 01214 Incidence::Ptr inc = incidence( uid, recurrenceId ); 01215 01216 if ( !inc ) { 01217 return; 01218 } 01219 01220 inc->setLastModified( KDateTime::currentUtcDateTime() ); 01221 // we should probably update the revision number here, 01222 // or internally in the Event itself when certain things change. 01223 // need to verify with ical documentation. 01224 01225 notifyIncidenceChanged( inc ); 01226 01227 setModified( true ); 01228 } 01229 01230 void Calendar::doSetTimeSpec( const KDateTime::Spec &timeSpec ) 01231 { 01232 Q_UNUSED( timeSpec ); 01233 } 01234 01235 void Calendar::notifyIncidenceAdded( const Incidence::Ptr &incidence ) 01236 { 01237 if ( !incidence ) { 01238 return; 01239 } 01240 01241 if ( !d->mObserversEnabled ) { 01242 return; 01243 } 01244 01245 foreach ( CalendarObserver *observer, d->mObservers ) { 01246 observer->calendarIncidenceAdded( incidence ); 01247 } 01248 } 01249 01250 void Calendar::notifyIncidenceChanged( const Incidence::Ptr &incidence ) 01251 { 01252 if ( !incidence ) { 01253 return; 01254 } 01255 01256 if ( !d->mObserversEnabled ) { 01257 return; 01258 } 01259 01260 foreach ( CalendarObserver *observer, d->mObservers ) { 01261 observer->calendarIncidenceChanged( incidence ); 01262 } 01263 } 01264 01265 void Calendar::notifyIncidenceDeleted( const Incidence::Ptr &incidence ) 01266 { 01267 if ( !incidence ) { 01268 return; 01269 } 01270 01271 if ( !d->mObserversEnabled ) { 01272 return; 01273 } 01274 01275 foreach ( CalendarObserver *observer, d->mObservers ) { 01276 observer->calendarIncidenceDeleted( incidence ); 01277 } 01278 } 01279 01280 void Calendar::notifyIncidenceAdditionCanceled( const Incidence::Ptr &incidence ) 01281 { 01282 if ( !incidence ) { 01283 return; 01284 } 01285 01286 if ( !d->mObserversEnabled ) { 01287 return; 01288 } 01289 01290 foreach ( CalendarObserver *observer, d->mObservers ) { 01291 observer->calendarIncidenceAdditionCanceled( incidence ); 01292 } 01293 } 01294 01295 void Calendar::customPropertyUpdated() 01296 { 01297 setModified( true ); 01298 } 01299 01300 void Calendar::setProductId( const QString &id ) 01301 { 01302 d->mProductId = id; 01303 } 01304 01305 QString Calendar::productId() const 01306 { 01307 return d->mProductId; 01308 } 01309 01311 Incidence::List Calendar::mergeIncidenceList( const Event::List &events, 01312 const Todo::List &todos, 01313 const Journal::List &journals ) 01314 { 01315 Incidence::List incidences; 01316 01317 int i, end; 01318 for ( i = 0, end = events.count(); i < end; ++i ) { 01319 incidences.append( events[i] ); 01320 } 01321 01322 for ( i = 0, end = todos.count(); i < end; ++i ) { 01323 incidences.append( todos[i] ); 01324 } 01325 01326 for ( i = 0, end = journals.count(); i < end; ++i ) { 01327 incidences.append( journals[i] ); 01328 } 01329 01330 return incidences; 01331 } 01332 01333 bool Calendar::beginChange( const Incidence::Ptr &incidence ) 01334 { 01335 Q_UNUSED( incidence ); 01336 return true; 01337 } 01338 01339 bool Calendar::endChange( const Incidence::Ptr &incidence ) 01340 { 01341 Q_UNUSED( incidence ); 01342 return true; 01343 } 01344 01345 void Calendar::setObserversEnabled( bool enabled ) 01346 { 01347 d->mObserversEnabled = enabled; 01348 } 01349 01350 void Calendar::appendAlarms( Alarm::List &alarms, const Incidence::Ptr &incidence, 01351 const KDateTime &from, const KDateTime &to ) const 01352 { 01353 KDateTime preTime = from.addSecs(-1); 01354 01355 Alarm::List alarmlist = incidence->alarms(); 01356 for ( int i = 0, iend = alarmlist.count(); i < iend; ++i ) { 01357 if ( alarmlist[i]->enabled() ) { 01358 KDateTime dt = alarmlist[i]->nextRepetition( preTime ); 01359 if ( dt.isValid() && dt <= to ) { 01360 kDebug() << incidence->summary() << "':" << dt.toString(); 01361 alarms.append( alarmlist[i] ); 01362 } 01363 } 01364 } 01365 } 01366 01367 void Calendar::appendRecurringAlarms( Alarm::List &alarms, 01368 const Incidence::Ptr &incidence, 01369 const KDateTime &from, 01370 const KDateTime &to ) const 01371 { 01372 KDateTime dt; 01373 bool endOffsetValid = false; 01374 Duration endOffset( 0 ); 01375 Duration period( from, to ); 01376 01377 Alarm::List alarmlist = incidence->alarms(); 01378 for ( int i = 0, iend = alarmlist.count(); i < iend; ++i ) { 01379 Alarm::Ptr a = alarmlist[i]; 01380 if ( a->enabled() ) { 01381 if ( a->hasTime() ) { 01382 // The alarm time is defined as an absolute date/time 01383 dt = a->nextRepetition( from.addSecs(-1) ); 01384 if ( !dt.isValid() || dt > to ) { 01385 continue; 01386 } 01387 } else { 01388 // Alarm time is defined by an offset from the event start or end time. 01389 // Find the offset from the event start time, which is also used as the 01390 // offset from the recurrence time. 01391 Duration offset( 0 ); 01392 if ( a->hasStartOffset() ) { 01393 offset = a->startOffset(); 01394 } else if ( a->hasEndOffset() ) { 01395 offset = a->endOffset(); 01396 if ( !endOffsetValid ) { 01397 endOffset = Duration( incidence->dtStart(), 01398 incidence->dateTime( Incidence::RoleAlarmEndOffset ) ); 01399 endOffsetValid = true; 01400 } 01401 } 01402 01403 // Find the incidence's earliest alarm 01404 KDateTime alarmStart = 01405 offset.end( a->hasEndOffset() ? incidence->dateTime( Incidence::RoleAlarmEndOffset ) : 01406 incidence->dtStart() ); 01407 // KDateTime alarmStart = incidence->dtStart().addSecs( offset ); 01408 if ( alarmStart > to ) { 01409 continue; 01410 } 01411 KDateTime baseStart = incidence->dtStart(); 01412 if ( from > alarmStart ) { 01413 alarmStart = from; // don't look earlier than the earliest alarm 01414 baseStart = (-offset).end( (-endOffset).end( alarmStart ) ); 01415 } 01416 01417 // Adjust the 'alarmStart' date/time and find the next recurrence at or after it. 01418 // Treate the two offsets separately in case one is daily and the other not. 01419 dt = incidence->recurrence()->getNextDateTime( baseStart.addSecs(-1) ); 01420 if ( !dt.isValid() || 01421 ( dt = endOffset.end( offset.end( dt ) ) ) > to ) // adjust 'dt' to get the alarm time 01422 { 01423 // The next recurrence is too late. 01424 if ( !a->repeatCount() ) { 01425 continue; 01426 } 01427 01428 // The alarm has repetitions, so check whether repetitions of previous 01429 // recurrences fall within the time period. 01430 bool found = false; 01431 Duration alarmDuration = a->duration(); 01432 for ( KDateTime base = baseStart; 01433 ( dt = incidence->recurrence()->getPreviousDateTime( base ) ).isValid(); 01434 base = dt ) { 01435 if ( a->duration().end( dt ) < base ) { 01436 break; // this recurrence's last repetition is too early, so give up 01437 } 01438 01439 // The last repetition of this recurrence is at or after 'alarmStart' time. 01440 // Check if a repetition occurs between 'alarmStart' and 'to'. 01441 int snooze = a->snoozeTime().value(); // in seconds or days 01442 if ( a->snoozeTime().isDaily() ) { 01443 Duration toFromDuration( dt, base ); 01444 int toFrom = toFromDuration.asDays(); 01445 if ( a->snoozeTime().end( from ) <= to || 01446 ( toFromDuration.isDaily() && toFrom % snooze == 0 ) || 01447 ( toFrom / snooze + 1 ) * snooze <= toFrom + period.asDays() ) { 01448 found = true; 01449 #ifndef NDEBUG 01450 // for debug output 01451 dt = offset.end( dt ).addDays( ( ( toFrom - 1 ) / snooze + 1 ) * snooze ); 01452 #endif 01453 break; 01454 } 01455 } else { 01456 int toFrom = dt.secsTo( base ); 01457 if ( period.asSeconds() >= snooze || 01458 toFrom % snooze == 0 || 01459 ( toFrom / snooze + 1 ) * snooze <= toFrom + period.asSeconds() ) 01460 { 01461 found = true; 01462 #ifndef NDEBUG 01463 // for debug output 01464 dt = offset.end( dt ).addSecs( ( ( toFrom - 1 ) / snooze + 1 ) * snooze ); 01465 #endif 01466 break; 01467 } 01468 } 01469 } 01470 if ( !found ) { 01471 continue; 01472 } 01473 } 01474 } 01475 kDebug() << incidence->summary() << "':" << dt.toString(); 01476 alarms.append( a ); 01477 } 01478 } 01479 } 01480 01481 void Calendar::startBatchAdding() 01482 { 01483 d->batchAddingInProgress = true; 01484 } 01485 01486 void Calendar::endBatchAdding() 01487 { 01488 d->batchAddingInProgress = false; 01489 } 01490 01491 bool Calendar::batchAdding() const 01492 { 01493 return d->batchAddingInProgress; 01494 } 01495 01496 void Calendar::virtual_hook( int id, void *data ) 01497 { 01498 Q_UNUSED( id ); 01499 Q_UNUSED( data ); 01500 Q_ASSERT( false ); 01501 } 01502 01503 #include "calendar.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon Aug 27 2012 22:07:48 by doxygen 1.7.5 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon Aug 27 2012 22:07:48 by doxygen 1.7.5 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.