Build, if that was not necessary blame cartman who told me "sure" :-D
[kdepim.git] / libkcal / calendar.cpp
blob77b13e33cee8adb3aa0023f08647774717a7c558
1 /*
2 This file is part of libkcal.
4 Copyright (c) 1998 Preston Brown
5 Copyright (c) 2000-2004 Cornelius Schumacher <schumacher@kde.org>
6 Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
18 You should have received a copy of the GNU Library General Public License
19 along with this library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.
24 #include <stdlib.h>
26 #include <kdebug.h>
27 #include <klocale.h>
29 #include "exceptions.h"
30 #include "calfilter.h"
32 #include "calendar.h"
34 using namespace KCal;
36 Calendar::Calendar()
38 mTimeZoneId = QString::fromLatin1( "UTC" );
39 mLocalTime = false;
41 init();
44 Calendar::Calendar( const QString &timeZoneId )
46 mTimeZoneId = timeZoneId;
47 mLocalTime = false;
49 init();
52 void Calendar::init()
54 mNewObserver = false;
55 mObserversEnabled = true;
57 mModified = false;
59 // Setup default filter, which does nothing
60 mDefaultFilter = new CalFilter;
61 mFilter = mDefaultFilter;
62 mFilter->setEnabled(false);
64 // initialize random numbers. This is a hack, and not
65 // even that good of one at that.
66 // srandom(time(0));
68 // user information...
69 setOwner( Person( i18n("Unknown Name"), i18n("unknown@nowhere") ) );
71 #if 0
72 tmpStr = KOPrefs::instance()->mTimeZone;
73 // kdDebug(5800) << "Calendar::Calendar(): TimeZone: " << tmpStr << endl;
74 int dstSetting = KOPrefs::instance()->mDaylightSavings;
75 extern long int timezone;
76 struct tm *now;
77 time_t curtime;
78 curtime = time(0);
79 now = localtime(&curtime);
80 int hourOff = - ((timezone / 60) / 60);
81 if (now->tm_isdst)
82 hourOff += 1;
83 QString tzStr;
84 tzStr.sprintf("%.2d%.2d",
85 hourOff,
86 abs((timezone / 60) % 60));
88 // if no time zone was in the config file, write what we just discovered.
89 if (tmpStr.isEmpty()) {
90 // KOPrefs::instance()->mTimeZone = tzStr;
91 } else {
92 tzStr = tmpStr;
95 // if daylight savings has changed since last load time, we need
96 // to rewrite these settings to the config file.
97 if ((now->tm_isdst && !dstSetting) ||
98 (!now->tm_isdst && dstSetting)) {
99 KOPrefs::instance()->mTimeZone = tzStr;
100 KOPrefs::instance()->mDaylightSavings = now->tm_isdst;
103 setTimeZone(tzStr);
104 #endif
106 // KOPrefs::instance()->writeConfig();
109 Calendar::~Calendar()
111 delete mDefaultFilter;
114 const Person &Calendar::getOwner() const
116 return mOwner;
119 void Calendar::setOwner( const Person &owner )
121 mOwner = owner;
123 setModified( true );
126 void Calendar::setTimeZoneId(const QString &id)
128 mTimeZoneId = id;
129 mLocalTime = false;
131 setModified( true );
132 doSetTimeZoneId( id );
135 QString Calendar::timeZoneId() const
137 return mTimeZoneId;
140 void Calendar::setLocalTime()
142 mLocalTime = true;
143 mTimeZone = 0;
144 mTimeZoneId = "";
146 setModified( true );
149 bool Calendar::isLocalTime() const
151 return mLocalTime;
154 void Calendar::setFilter(CalFilter *filter)
156 if ( filter ) {
157 mFilter = filter;
158 } else {
159 mFilter = mDefaultFilter;
163 CalFilter *Calendar::filter()
165 return mFilter;
168 QStringList Calendar::incidenceCategories()
170 Incidence::List rawInc( rawIncidences() );
171 QStringList categories, thisCats;
172 // TODO: For now just iterate over all incidences. In the future,
173 // the list of categories should be built when reading the file.
174 for ( Incidence::List::ConstIterator i = rawInc.constBegin(); i != rawInc.constEnd(); ++i ) {
175 thisCats = (*i)->categories();
176 for ( QStringList::ConstIterator si = thisCats.constBegin(); si != thisCats.constEnd(); ++si ) {
177 if ( categories.find( *si ) == categories.end() ) {
178 categories.append( *si );
182 return categories;
185 Incidence::List Calendar::incidences( const QDate &qdt )
187 return mergeIncidenceList( events( qdt ), todos( qdt ), journals( qdt ) );
190 Incidence::List Calendar::incidences()
192 return mergeIncidenceList( events(), todos(), journals() );
195 Incidence::List Calendar::rawIncidences()
197 return mergeIncidenceList( rawEvents(), rawTodos(), rawJournals() );
200 Event::List Calendar::sortEvents( Event::List *eventList,
201 EventSortField sortField,
202 SortDirection sortDirection ) {
204 Event::List eventListSorted;
205 Event::List tempList, t;
206 Event::List alphaList;
207 Event::List::Iterator sortIt;
208 Event::List::Iterator eit;
210 // Notice we alphabetically presort Summaries first.
211 // We do this so comparison "ties" stay in a nice order.
213 switch( sortField ) {
214 case EventSortUnsorted:
215 eventListSorted = *eventList;
216 break;
218 case EventSortStartDate:
219 alphaList = sortEvents( eventList, EventSortSummary, sortDirection );
220 for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
221 sortIt = eventListSorted.begin();
222 if ( sortDirection == SortDirectionAscending ) {
223 while ( sortIt != eventListSorted.end() &&
224 (*eit)->dtStart() >= (*sortIt)->dtStart() ) {
225 ++sortIt;
227 } else {
228 while ( sortIt != eventListSorted.end() &&
229 (*eit)->dtStart() < (*sortIt)->dtStart() ) {
230 ++sortIt;
233 eventListSorted.insert( sortIt, *eit );
235 break;
237 case EventSortEndDate:
238 alphaList = sortEvents( eventList, EventSortSummary, sortDirection );
239 for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
240 if ( (*eit)->hasEndDate() ) {
241 sortIt = eventListSorted.begin();
242 if ( sortDirection == SortDirectionAscending ) {
243 while ( sortIt != eventListSorted.end() &&
244 (*eit)->dtEnd() >= (*sortIt)->dtEnd() ) {
245 ++sortIt;
247 } else {
248 while ( sortIt != eventListSorted.end() &&
249 (*eit)->dtEnd() < (*sortIt)->dtEnd() ) {
250 ++sortIt;
253 } else {
254 // Keep a list of the Events without End DateTimes
255 tempList.append( *eit );
257 eventListSorted.insert( sortIt, *eit );
259 if ( sortDirection == SortDirectionAscending ) {
260 // Append the list of Events without End DateTimes
261 eventListSorted += tempList;
262 } else {
263 // Prepend the list of Events without End DateTimes
264 tempList += eventListSorted;
265 eventListSorted = tempList;
267 break;
269 case EventSortSummary:
270 for ( eit = eventList->begin(); eit != eventList->end(); ++eit ) {
271 sortIt = eventListSorted.begin();
272 if ( sortDirection == SortDirectionAscending ) {
273 while ( sortIt != eventListSorted.end() &&
274 (*eit)->summary() >= (*sortIt)->summary() ) {
275 ++sortIt;
277 } else {
278 while ( sortIt != eventListSorted.end() &&
279 (*eit)->summary() < (*sortIt)->summary() ) {
280 ++sortIt;
283 eventListSorted.insert( sortIt, *eit );
285 break;
288 return eventListSorted;
292 Event::List Calendar::events( const QDate &date, bool sorted )
294 Event::List el = rawEventsForDate( date, sorted );
295 mFilter->apply(&el);
296 return el;
299 Event::List Calendar::events( const QDateTime &qdt )
301 Event::List el = rawEventsForDate(qdt);
302 mFilter->apply(&el);
303 return el;
306 Event::List Calendar::events( const QDate &start, const QDate &end,
307 bool inclusive)
309 Event::List el = rawEvents(start,end,inclusive);
310 mFilter->apply(&el);
311 return el;
314 Event::List Calendar::events( EventSortField sortField, SortDirection sortDirection )
316 Event::List el = rawEvents( sortField, sortDirection );
317 mFilter->apply(&el);
318 return el;
321 bool Calendar::addIncidence(Incidence *i)
323 Incidence::AddVisitor<Calendar> v(this);
325 return i->accept(v);
328 bool Calendar::deleteIncidence( Incidence *i )
330 if ( beginChange( i ) ) {
331 Incidence::DeleteVisitor<Calendar> v( this );
332 bool result = i->accept( v );
333 endChange( i );
334 return result;
335 } else
336 return false;
339 Incidence *Calendar::dissociateOccurrence( Incidence *incidence, QDate date,
340 bool single )
342 if ( !incidence || !incidence->doesRecur() ) return 0;
344 Incidence *newInc = incidence->clone();
345 newInc->recreate();
346 newInc->setRelatedTo( incidence );
347 Recurrence *recur = newInc->recurrence();
348 if ( single ) {
349 recur->unsetRecurs();
350 } else {
351 // Adjust the recurrence for the future incidences. In particular
352 // adjust the "end after n occurences" rules! "No end date" and "end by ..."
353 // don't need to be modified.
354 int duration = recur->duration();
355 if ( duration > 0 ) {
356 int doneduration = recur->durationTo( date.addDays(-1) );
357 if ( doneduration >= duration ) {
358 kdDebug(5850) << "The dissociated event already occured more often that it was supposed to ever occur. ERROR!" << endl;
359 recur->unsetRecurs();
360 } else {
361 recur->setDuration( duration - doneduration );
365 // Adjust the date of the incidence
366 if ( incidence->type() == "Event" ) {
367 Event *ev = static_cast<Event *>( newInc );
368 QDateTime start( ev->dtStart() );
369 int daysTo = start.date().daysTo( date );
370 ev->setDtStart( start.addDays( daysTo ) );
371 ev->setDtEnd( ev->dtEnd().addDays( daysTo ) );
372 } else if ( incidence->type() == "Todo" ) {
373 Todo *td = static_cast<Todo *>( newInc );
374 bool haveOffset = false;
375 int daysTo = 0;
376 if ( td->hasDueDate() ) {
377 QDateTime due( td->dtDue() );
378 daysTo = due.date().daysTo( date ) ;
379 td->setDtDue( due.addDays( daysTo ), true );
380 haveOffset = true;
382 if ( td->hasStartDate() ) {
383 QDateTime start( td->dtStart() );
384 if ( !haveOffset ) daysTo = start.date().daysTo( date );
385 td->setDtStart( start.addDays( daysTo ) );
386 haveOffset = true;
389 if ( addIncidence( newInc ) ) {
390 if (single) {
391 incidence->addExDate( date );
392 } else {
393 recur = incidence->recurrence();
394 if ( recur ) {
395 // Make sure the recurrence of the past events ends at the corresponding day
396 recur->setEndDate( date.addDays(-1) );
399 } else {
400 delete newInc;
401 return 0;
403 return newInc;
406 Incidence *Calendar::incidence( const QString& uid )
408 Incidence *i = event( uid );
409 if ( i ) return i;
410 i = todo( uid );
411 if ( i ) return i;
412 i = journal( uid );
413 return i;
416 Incidence *Calendar::incidenceFromSchedulingID( const QString &UID )
418 Incidence::List incidences = rawIncidences();
419 Incidence::List::iterator it = incidences.begin();
420 for ( ; it != incidences.end(); ++it )
421 if ( (*it)->schedulingID() == UID )
422 // Touchdown, and the crowd goes wild
423 return *it;
424 // Not found
425 return 0;
428 Todo::List Calendar::sortTodos( Todo::List *todoList,
429 TodoSortField sortField,
430 SortDirection sortDirection )
432 Todo::List todoListSorted;
433 Todo::List tempList, t;
434 Todo::List alphaList;
435 Todo::List::Iterator sortIt;
436 Todo::List::Iterator eit;
438 // Notice we alphabetically presort Summaries first.
439 // We do this so comparison "ties" stay in a nice order.
441 // Note that Todos may not have Start DateTimes nor due DateTimes.
443 switch( sortField ) {
444 case TodoSortUnsorted:
445 todoListSorted = *todoList;
446 break;
448 case TodoSortStartDate:
449 alphaList = sortTodos( todoList, TodoSortSummary, sortDirection );
450 for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
451 if ( (*eit)->hasStartDate() ) {
452 sortIt = todoListSorted.begin();
453 if ( sortDirection == SortDirectionAscending ) {
454 while ( sortIt != todoListSorted.end() &&
455 (*eit)->dtStart() >= (*sortIt)->dtStart() ) {
456 ++sortIt;
458 } else {
459 while ( sortIt != todoListSorted.end() &&
460 (*eit)->dtStart() < (*sortIt)->dtStart() ) {
461 ++sortIt;
464 todoListSorted.insert( sortIt, *eit );
465 } else {
466 // Keep a list of the Todos without Start DateTimes
467 tempList.append( *eit );
470 if ( sortDirection == SortDirectionAscending ) {
471 // Append the list of Todos without Start DateTimes
472 todoListSorted += tempList;
473 } else {
474 // Prepend the list of Todos without Start DateTimes
475 tempList += todoListSorted;
476 todoListSorted = tempList;
478 break;
480 case TodoSortDueDate:
481 alphaList = sortTodos( todoList, TodoSortSummary, sortDirection );
482 for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
483 if ( (*eit)->hasDueDate() ) {
484 sortIt = todoListSorted.begin();
485 if ( sortDirection == SortDirectionAscending ) {
486 while ( sortIt != todoListSorted.end() &&
487 (*eit)->dtDue() >= (*sortIt)->dtDue() ) {
488 ++sortIt;
490 } else {
491 while ( sortIt != todoListSorted.end() &&
492 (*eit)->dtDue() < (*sortIt)->dtDue() ) {
493 ++sortIt;
496 todoListSorted.insert( sortIt, *eit );
497 } else {
498 // Keep a list of the Todos without Due DateTimes
499 tempList.append( *eit );
502 if ( sortDirection == SortDirectionAscending ) {
503 // Append the list of Todos without Due DateTimes
504 todoListSorted += tempList;
505 } else {
506 // Prepend the list of Todos without Due DateTimes
507 tempList += todoListSorted;
508 todoListSorted = tempList;
510 break;
512 case TodoSortPriority:
513 alphaList = sortTodos( todoList, TodoSortSummary, sortDirection );
514 for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
515 sortIt = todoListSorted.begin();
516 if ( sortDirection == SortDirectionAscending ) {
517 while ( sortIt != todoListSorted.end() &&
518 (*eit)->priority() >= (*sortIt)->priority() ) {
519 ++sortIt;
521 } else {
522 while ( sortIt != todoListSorted.end() &&
523 (*eit)->priority() < (*sortIt)->priority() ) {
524 ++sortIt;
527 todoListSorted.insert( sortIt, *eit );
529 break;
531 case TodoSortPercentComplete:
532 alphaList = sortTodos( todoList, TodoSortSummary, sortDirection );
533 for ( eit = alphaList.begin(); eit != alphaList.end(); ++eit ) {
534 sortIt = todoListSorted.begin();
535 if ( sortDirection == SortDirectionAscending ) {
536 while ( sortIt != todoListSorted.end() &&
537 (*eit)->percentComplete() >= (*sortIt)->percentComplete() ) {
538 ++sortIt;
540 } else {
541 while ( sortIt != todoListSorted.end() &&
542 (*eit)->percentComplete() < (*sortIt)->percentComplete() ) {
543 ++sortIt;
546 todoListSorted.insert( sortIt, *eit );
548 break;
550 case TodoSortSummary:
551 for ( eit = todoList->begin(); eit != todoList->end(); ++eit ) {
552 sortIt = todoListSorted.begin();
553 if ( sortDirection == SortDirectionAscending ) {
554 while ( sortIt != todoListSorted.end() &&
555 (*eit)->summary() >= (*sortIt)->summary() ) {
556 ++sortIt;
558 } else {
559 while ( sortIt != todoListSorted.end() &&
560 (*eit)->summary() < (*sortIt)->summary() ) {
561 ++sortIt;
564 todoListSorted.insert( sortIt, *eit );
566 break;
569 return todoListSorted;
572 Todo::List Calendar::todos( TodoSortField sortField, SortDirection sortDirection )
574 Todo::List tl = rawTodos( sortField, sortDirection );
575 mFilter->apply( &tl );
576 return tl;
579 Todo::List Calendar::todos( const QDate &date )
581 Todo::List el = rawTodosForDate( date );
582 mFilter->apply(&el);
583 return el;
586 Journal::List Calendar::sortJournals( Journal::List *journalList,
587 JournalSortField sortField,
588 SortDirection sortDirection )
590 Journal::List journalListSorted;
591 Journal::List::Iterator sortIt;
592 Journal::List::Iterator eit;
594 switch( sortField ) {
595 case JournalSortUnsorted:
596 journalListSorted = *journalList;
597 break;
599 case JournalSortDate:
600 for ( eit = journalList->begin(); eit != journalList->end(); ++eit ) {
601 sortIt = journalListSorted.begin();
602 if ( sortDirection == SortDirectionAscending ) {
603 while ( sortIt != journalListSorted.end() &&
604 (*eit)->dtStart() >= (*sortIt)->dtStart() ) {
605 ++sortIt;
607 } else {
608 while ( sortIt != journalListSorted.end() &&
609 (*eit)->dtStart() < (*sortIt)->dtStart() ) {
610 ++sortIt;
613 journalListSorted.insert( sortIt, *eit );
615 break;
617 case JournalSortSummary:
618 for ( eit = journalList->begin(); eit != journalList->end(); ++eit ) {
619 sortIt = journalListSorted.begin();
620 if ( sortDirection == SortDirectionAscending ) {
621 while ( sortIt != journalListSorted.end() &&
622 (*eit)->summary() >= (*sortIt)->summary() ) {
623 ++sortIt;
625 } else {
626 while ( sortIt != journalListSorted.end() &&
627 (*eit)->summary() < (*sortIt)->summary() ) {
628 ++sortIt;
631 journalListSorted.insert( sortIt, *eit );
633 break;
636 return journalListSorted;
639 Journal::List Calendar::journals( JournalSortField sortField, SortDirection sortDirection )
641 Journal::List jl = rawJournals( sortField, sortDirection );
642 mFilter->apply( &jl );
643 return jl;
646 Journal::List Calendar::journals( const QDate &date )
648 Journal::List el = rawJournalsForDate( date );
649 mFilter->apply(&el);
650 return el;
653 // When this is called, the todo have already been added to the calendar.
654 // This method is only about linking related todos
655 void Calendar::setupRelations( Incidence *forincidence )
657 QString uid = forincidence->uid();
659 // First, go over the list of orphans and see if this is their parent
660 while( Incidence* i = mOrphans[ uid ] ) {
661 mOrphans.remove( uid );
662 i->setRelatedTo( forincidence );
663 forincidence->addRelation( i );
664 mOrphanUids.remove( i->uid() );
667 // Now see about this incidences parent
668 if( !forincidence->relatedTo() && !forincidence->relatedToUid().isEmpty() ) {
669 // This incidence has a uid it is related to, but is not registered to it yet
670 // Try to find it
671 Incidence* parent = incidence( forincidence->relatedToUid() );
672 if( parent ) {
673 // Found it
674 forincidence->setRelatedTo( parent );
675 parent->addRelation( forincidence );
676 } else {
677 // Not found, put this in the mOrphans list
678 mOrphans.insert( forincidence->relatedToUid(), forincidence );
679 mOrphanUids.insert( forincidence->uid(), forincidence );
684 // If a task with subtasks is deleted, move it's subtasks to the orphans list
685 void Calendar::removeRelations( Incidence *incidence )
687 if( !incidence ) {
688 kdDebug(5800) << "Warning: Calendar::removeRelations( 0 )!\n";
689 return;
692 QString uid = incidence->uid();
694 Incidence::List relations = incidence->relations();
695 Incidence::List::ConstIterator it;
696 for( it = relations.begin(); it != relations.end(); ++it ) {
697 Incidence *i = *it;
698 if( !mOrphanUids.find( i->uid() ) ) {
699 mOrphans.insert( uid, i );
700 mOrphanUids.insert( i->uid(), i );
701 i->setRelatedTo( 0 );
702 i->setRelatedToUid( uid );
706 // If this incidence is related to something else, tell that about it
707 if( incidence->relatedTo() )
708 incidence->relatedTo()->removeRelation( incidence );
710 // Remove this one from the orphans list
711 if( mOrphanUids.remove( uid ) )
712 // This incidence is located in the orphans list - it should be removed
713 if( !( incidence->relatedTo() != 0 && mOrphans.remove( incidence->relatedTo()->uid() ) ) ) {
714 // Removing wasn't that easy
715 for( QDictIterator<Incidence> it( mOrphans ); it.current(); ++it ) {
716 if( it.current()->uid() == uid ) {
717 mOrphans.remove( it.currentKey() );
718 break;
724 void Calendar::registerObserver( Observer *observer )
726 if( !mObservers.contains( observer ) ) mObservers.append( observer );
727 mNewObserver = true;
730 void Calendar::unregisterObserver( Observer *observer )
732 mObservers.remove( observer );
735 void Calendar::setModified( bool modified )
737 if ( modified != mModified || mNewObserver ) {
738 mNewObserver = false;
739 Observer *observer;
740 for( observer = mObservers.first(); observer;
741 observer = mObservers.next() ) {
742 observer->calendarModified( modified, this );
744 mModified = modified;
748 void Calendar::incidenceUpdated( IncidenceBase *incidence )
750 // kdDebug(5800) << "CalendarResources::incidenceUpdated( IncidenceBase * ): Not yet implemented\n";
751 incidence->setSyncStatus( Event::SYNCMOD );
752 incidence->setLastModified( QDateTime::currentDateTime() );
753 // we should probably update the revision number here,
754 // or internally in the Event itself when certain things change.
755 // need to verify with ical documentation.
757 // The static_cast is ok as the CalendarLocal only observes Incidence objects
758 notifyIncidenceChanged( static_cast<Incidence *>( incidence ) );
760 setModified( true );
763 void Calendar::notifyIncidenceAdded( Incidence *i )
765 if ( !mObserversEnabled ) return;
767 Observer *observer;
768 for( observer = mObservers.first(); observer;
769 observer = mObservers.next() ) {
770 observer->calendarIncidenceAdded( i );
774 void Calendar::notifyIncidenceChanged( Incidence *i )
776 if ( !mObserversEnabled ) return;
778 Observer *observer;
779 for( observer = mObservers.first(); observer;
780 observer = mObservers.next() ) {
781 observer->calendarIncidenceChanged( i );
785 void Calendar::notifyIncidenceDeleted( Incidence *i )
787 if ( !mObserversEnabled ) return;
789 Observer *observer;
790 for( observer = mObservers.first(); observer;
791 observer = mObservers.next() ) {
792 observer->calendarIncidenceDeleted( i );
796 void Calendar::setLoadedProductId( const QString &id )
798 mLoadedProductId = id;
801 QString Calendar::loadedProductId()
803 return mLoadedProductId;
806 Incidence::List Calendar::mergeIncidenceList( const Event::List &e,
807 const Todo::List &t,
808 const Journal::List &j )
810 Incidence::List incidences;
812 Event::List::ConstIterator it1;
813 for( it1 = e.begin(); it1 != e.end(); ++it1 ) incidences.append( *it1 );
815 Todo::List::ConstIterator it2;
816 for( it2 = t.begin(); it2 != t.end(); ++it2 ) incidences.append( *it2 );
818 Journal::List::ConstIterator it3;
819 for( it3 = j.begin(); it3 != j.end(); ++it3 ) incidences.append( *it3 );
821 return incidences;
824 bool Calendar::beginChange( Incidence * )
826 return true;
829 bool Calendar::endChange( Incidence * )
831 return true;
834 void Calendar::setObserversEnabled( bool enabled )
836 mObserversEnabled = enabled;
839 #include "calendar.moc"