diff options
Diffstat (limited to 'libkcal')
-rw-r--r-- | libkcal/calendar.cpp | 19 | ||||
-rw-r--r-- | libkcal/calendarlocal.cpp | 61 | ||||
-rw-r--r-- | libkcal/calendarlocal.h | 12 | ||||
-rw-r--r-- | libkcal/icalformat.cpp | 44 | ||||
-rw-r--r-- | libkcal/icalformat.h | 7 | ||||
-rw-r--r-- | libkcal/icalformatimpl.cpp | 128 | ||||
-rw-r--r-- | libkcal/incidence.cpp | 106 | ||||
-rw-r--r-- | libkcal/incidence.h | 76 |
8 files changed, 429 insertions, 24 deletions
diff --git a/libkcal/calendar.cpp b/libkcal/calendar.cpp index 3d57e7546..0be3dffcd 100644 --- a/libkcal/calendar.cpp +++ b/libkcal/calendar.cpp @@ -290,6 +290,25 @@ bool Calendar::addIncidence( Incidence *incidence ) bool Calendar::deleteIncidence( Incidence *incidence ) { if ( beginChange( incidence ) ) { + if (incidence->hasRecurrenceID()) { + // Delete this event's UID from the parent's list of children + Incidence *parentIncidence; + IncidenceList il = incidence->childIncidences(); + IncidenceListIterator it; + it = il.begin(); + parentIncidence = this->incidence(*it); + parentIncidence->deleteChildIncidence(incidence->uid()); + } + else { + // Delete all children as well + IncidenceList il = incidence->childIncidences(); + IncidenceListIterator it; + for ( it = il.begin(); it != il.end(); ++it ) { + deleteIncidence( this->incidence(*it) ); + // Avoid a crash, reset the iterator every time the list is modified + it = il.begin(); + } + } Incidence::DeleteVisitor<Calendar> v( this ); bool result = incidence->accept( v ); endChange( incidence ); diff --git a/libkcal/calendarlocal.cpp b/libkcal/calendarlocal.cpp index 39c48ae4b..716fa5e98 100644 --- a/libkcal/calendarlocal.cpp +++ b/libkcal/calendarlocal.cpp @@ -126,6 +126,10 @@ bool CalendarLocal::deleteEvent( Event *event ) setModified( true ); notifyIncidenceDeleted( event ); mDeletedIncidences.append( event ); + // Delete child events + if (!event->hasRecurrenceID()) { + deleteChildEvents(event); + } return true; } else { kdWarning() << "CalendarLocal::deleteEvent(): Event not found." << endl; @@ -133,6 +137,21 @@ bool CalendarLocal::deleteEvent( Event *event ) } } +bool CalendarLocal::deleteChildEvents( Event *event ) +{ + EventDictIterator it( mEvents ); + for( ; it.current(); ++it ) { + Event *e = *it; + if (e->uid() == event->uid()) { + if ( e->hasRecurrenceID() ) { + deleteEvent(( e )); + } + } + } + + return true; +} + void CalendarLocal::deleteAllEvents() { // kdDebug(5800) << "CalendarLocal::deleteAllEvents" << endl; @@ -178,6 +197,10 @@ bool CalendarLocal::deleteTodo( Todo *todo ) setModified( true ); notifyIncidenceDeleted( todo ); mDeletedIncidences.append( todo ); + // Delete child todos + if (!todo->hasRecurrenceID()) { + deleteChildTodos(todo); + } return true; } else { kdWarning() << "CalendarLocal::deleteTodo(): Todo not found." << endl; @@ -185,6 +208,21 @@ bool CalendarLocal::deleteTodo( Todo *todo ) } } +bool CalendarLocal::deleteChildTodos( Todo *todo ) +{ + Todo::List::ConstIterator it; + for( it = mTodoList.begin(); it != mTodoList.end(); ++it ) { + Todo *t = *it; + if (t->uid() == todo->uid()) { + if ( t->hasRecurrenceID() ) { + deleteTodo(( t )); + } + } + } + + return true; +} + void CalendarLocal::deleteAllTodos() { // kdDebug(5800) << "CalendarLocal::deleteAllTodos()\n"; @@ -392,13 +430,13 @@ Event::List CalendarLocal::rawEventsForDate( const TQDate &qd, int extraDays = event->dtStart().date().daysTo( event->dtEnd().date() ); int i; for ( i = 0; i <= extraDays; i++ ) { - if ( event->recursOn( qd.addDays( -i ) ) ) { + if ( event->recursOn( qd.addDays( -i ), this ) ) { eventList.append( event ); break; } } } else { - if ( event->recursOn( qd ) ) + if ( event->recursOn( qd, this ) ) eventList.append( event ); } } else { @@ -527,6 +565,10 @@ bool CalendarLocal::deleteJournal( Journal *journal ) setModified( true ); notifyIncidenceDeleted( journal ); mDeletedIncidences.append( journal ); + // Delete child journals + if (!journal->hasRecurrenceID()) { + deleteChildJournals(journal); + } return true; } else { kdWarning() << "CalendarLocal::deleteJournal(): Journal not found." << endl; @@ -534,6 +576,21 @@ bool CalendarLocal::deleteJournal( Journal *journal ) } } +bool CalendarLocal::deleteChildJournals( Journal *journal ) +{ + Journal::List::ConstIterator it; + for( it = mJournalList.begin(); it != mJournalList.end(); ++it ) { + Journal *j = *it; + if (j->uid() == journal->uid()) { + if ( j->hasRecurrenceID() ) { + deleteJournal(( j )); + } + } + } + + return true; +} + void CalendarLocal::deleteAllJournals() { Journal::List::ConstIterator it; diff --git a/libkcal/calendarlocal.h b/libkcal/calendarlocal.h index b76eb5ab4..7326a2343 100644 --- a/libkcal/calendarlocal.h +++ b/libkcal/calendarlocal.h @@ -89,6 +89,10 @@ class LIBKCAL_EXPORT CalendarLocal : public Calendar */ bool deleteEvent( Event *event ); /** + Deletes a child event from this calendar. + */ + bool deleteChildEvents( Event *event ); + /** Deletes all events from this calendar. */ void deleteAllEvents(); @@ -111,6 +115,10 @@ class LIBKCAL_EXPORT CalendarLocal : public Calendar */ bool deleteTodo( Todo * ); /** + Deletes a child todo from this calendar. + */ + bool deleteChildTodos( Todo *todo ); + /** Deletes all todos from this calendar. */ void deleteAllTodos(); @@ -137,6 +145,10 @@ class LIBKCAL_EXPORT CalendarLocal : public Calendar */ bool deleteJournal( Journal * ); /** + Delete a child journal from this calendar. + */ + bool deleteChildJournals( Journal *journal ); + /** Deletes all journals from this calendar. */ void deleteAllJournals(); diff --git a/libkcal/icalformat.cpp b/libkcal/icalformat.cpp index 4fae0eaf2..c6a245c80 100644 --- a/libkcal/icalformat.cpp +++ b/libkcal/icalformat.cpp @@ -293,6 +293,50 @@ TQString ICalFormat::toString( Incidence *incidence ) return text; } +TQString ICalFormat::toString( Incidence *incidence, Calendar *calendar ) +{ + icalcomponent *component; + TQString text = ""; + + // See if there are any parent or child events that must be added to the string + if ( incidence->hasRecurrenceID() ) { + // Get the parent + IncidenceList il = incidence->childIncidences(); + IncidenceListIterator it; + it = il.begin(); + Incidence *parentIncidence; + parentIncidence = calendar->incidence(*it); + il = parentIncidence->childIncidences(); + if (il.count() > 0) { + for ( it = il.begin(); it != il.end(); ++it ) { + component = mImpl->writeIncidence( calendar->incidence(*it) ); + text = text + TQString::fromUtf8( icalcomponent_as_ical_string( component ) ); + icalcomponent_free( component ); + } + } + component = mImpl->writeIncidence( parentIncidence ); + text = text + TQString::fromUtf8( icalcomponent_as_ical_string( component ) ); + icalcomponent_free( component ); + } + else { + // This incidence is a potential parent + IncidenceList il = incidence->childIncidences(); + if (il.count() > 0) { + IncidenceListIterator it; + for ( it = il.begin(); it != il.end(); ++it ) { + component = mImpl->writeIncidence( calendar->incidence(*it) ); + text = text + TQString::fromUtf8( icalcomponent_as_ical_string( component ) ); + icalcomponent_free( component ); + } + } + component = mImpl->writeIncidence( incidence ); + text = text + TQString::fromUtf8( icalcomponent_as_ical_string( component ) ); + icalcomponent_free( component ); + } + + return text; +} + TQString ICalFormat::toString( RecurrenceRule *recurrence ) { icalproperty *property; diff --git a/libkcal/icalformat.h b/libkcal/icalformat.h index c35da5eb1..425e80d54 100644 --- a/libkcal/icalformat.h +++ b/libkcal/icalformat.h @@ -87,6 +87,13 @@ class LIBKCAL_EXPORT ICalFormat : public CalFormat */ TQString toString( Incidence * ); /** + Return incidence as iCalendar formatted text. + This function includes all RECURRENCE-ID related incidences. + @return TQString of iCalendar formatted text. + @since 3.5.12 + */ + TQString toString( Incidence *, Calendar * ); + /** Return recurrence rule as iCalendar formatted text. */ TQString toString( RecurrenceRule * ); diff --git a/libkcal/icalformatimpl.cpp b/libkcal/icalformatimpl.cpp index a52ec304c..a1655409f 100644 --- a/libkcal/icalformatimpl.cpp +++ b/libkcal/icalformatimpl.cpp @@ -314,10 +314,24 @@ void ICalFormatImpl::writeIncidence(icalcomponent *parent,Incidence *incidence) icalcomponent_add_property(parent,p); } - if ( incidence->schedulingID() != incidence->uid() ) + TQString modifiedUid; + if ( incidence->hasRecurrenceID() ) { + // Recurring incidences are special; they must match their parent's UID + // Each child has the parent set as the first item in the list + // So, get and set the UID... + IncidenceList il = incidence->childIncidences(); + IncidenceListIterator it; + it = il.begin(); + modifiedUid = (*it); + } + else { + modifiedUid = incidence->uid(); + } + + if ( incidence->schedulingID() != modifiedUid ) // We need to store the UID in here. The rawSchedulingID will // go into the iCal UID component - incidence->setCustomProperty( "LIBKCAL", "ID", incidence->uid() ); + incidence->setCustomProperty( "LIBKCAL", "ID", modifiedUid ); else incidence->removeCustomProperty( "LIBKCAL", "ID" ); @@ -330,9 +344,15 @@ void ICalFormatImpl::writeIncidence(icalcomponent *parent,Incidence *incidence) // unique id // If the scheduling ID is different from the real UID, the real // one is stored on X-REALID above - if ( !incidence->schedulingID().isEmpty() ) { - icalcomponent_add_property(parent,icalproperty_new_uid( - incidence->schedulingID().utf8())); + if ( incidence->hasRecurrenceID() ) { + // Recurring incidences are special; they must match their parent's UID + icalcomponent_add_property(parent,icalproperty_new_uid(modifiedUid.utf8())); + } + else { + if ( !incidence->schedulingID().isEmpty() ) { + icalcomponent_add_property(parent,icalproperty_new_uid( + incidence->schedulingID().utf8())); + } } // revision @@ -426,6 +446,11 @@ void ICalFormatImpl::writeIncidence(icalcomponent *parent,Incidence *incidence) incidence->relatedToUid().utf8())); } + // recurrenceid + if ( incidence->hasRecurrenceID() ) { + icalcomponent_add_property(parent, icalproperty_new_recurrenceid( writeICalDateTime( incidence->recurrenceID() ) )); + } + // kdDebug(5800) << "Write recurrence for '" << incidence->summary() << "' (" << incidence->uid() // << ")" << endl; @@ -1359,10 +1384,21 @@ void ICalFormatImpl::readIncidence(icalcomponent *parent, icaltimezone *tz, Inci categories.append(TQString::fromUtf8(text)); break; + case ICAL_RECURRENCEID_PROPERTY: // recurrenceID + icaltime = icalproperty_get_recurrenceid(p); + incidence->setRecurrenceID( readICalDateTime( p, icaltime ) ); + incidence->setHasRecurrenceID( true ); + break; + case ICAL_RRULE_PROPERTY: readRecurrenceRule( p, incidence ); break; +// case ICAL_CONTACT_PROPERTY: +// incidenceBase->addContact( +// QString::fromUtf8( icalproperty_get_contact( p ) ) ); +// break; + case ICAL_RDATE_PROPERTY: { icaldatetimeperiodtype rd = icalproperty_get_rdate( p ); if ( icaltime_is_valid_time( rd.time ) ) { @@ -2031,11 +2067,29 @@ bool ICalFormatImpl::populate( Calendar *cal, icalcomponent *calendar) // kdDebug(5800) << "----Todo found" << endl; Todo *todo = readTodo(c); if (todo) { - if (!cal->todo(todo->uid())) { - cal->addTodo(todo); - } else { - delete todo; - mTodosRelate.remove( todo ); + if (todo->hasRecurrenceID()) { + TQString originalUid = todo->uid(); + todo->setUid(originalUid + QString("-recur-%1").arg(todo->recurrenceID().toTime_t())); + if (!cal->todo(todo->uid())) { + cal->addTodo(todo); + if (!cal->event(originalUid)) { + printf("FIXME! [WARNING] Parent for child event does not yet exist!\n\r"); + } + else { + // Add this todo to its parent + cal->todo(originalUid)->addChildIncidence(todo->uid()); + // And the parent to the child + todo->addChildIncidence(cal->todo(originalUid)->uid()); + } + } + } + else { + if (!cal->todo(todo->uid())) { + cal->addTodo(todo); + } else { + delete todo; + mTodosRelate.remove( todo ); + } } } c = icalcomponent_get_next_component(calendar,ICAL_VTODO_COMPONENT); @@ -2047,11 +2101,29 @@ bool ICalFormatImpl::populate( Calendar *cal, icalcomponent *calendar) // kdDebug(5800) << "----Event found" << endl; Event *event = readEvent(c, ctz); if (event) { - if (!cal->event(event->uid())) { - cal->addEvent(event); - } else { - delete event; - mEventsRelate.remove( event ); + if (event->hasRecurrenceID()) { + TQString originalUid = event->uid(); + event->setUid(originalUid + QString("-recur-%1").arg(event->recurrenceID().toTime_t())); + if (!cal->event(event->uid())) { + cal->addEvent(event); + if (!cal->event(originalUid)) { + printf("FIXME! [WARNING] Parent for child event does not yet exist!\n\r"); + } + else { + // Add this event to its parent + cal->event(originalUid)->addChildIncidence(event->uid()); + // And the parent to the child + event->addChildIncidence(cal->event(originalUid)->uid()); + } + } + } + else { + if (!cal->event(event->uid())) { + cal->addEvent(event); + } else { + delete event; + mEventsRelate.remove( event ); + } } } c = icalcomponent_get_next_component(calendar,ICAL_VEVENT_COMPONENT); @@ -2063,10 +2135,28 @@ bool ICalFormatImpl::populate( Calendar *cal, icalcomponent *calendar) // kdDebug(5800) << "----Journal found" << endl; Journal *journal = readJournal(c); if (journal) { - if (!cal->journal(journal->uid())) { - cal->addJournal(journal); - } else { - delete journal; + if (journal->hasRecurrenceID()) { + TQString originalUid = journal->uid(); + journal->setUid(originalUid + QString("-recur-%1").arg(journal->recurrenceID().toTime_t())); + if (!cal->journal(journal->uid())) { + cal->addJournal(journal); + if (!cal->event(originalUid)) { + printf("FIXME! [WARNING] Parent for child event does not yet exist!\n\r"); + } + else { + // Add this journal to its parent + cal->journal(originalUid)->addChildIncidence(journal->uid()); + // And the parent to the child + journal->addChildIncidence(cal->journal(originalUid)->uid()); + } + } + } + else { + if (!cal->journal(journal->uid())) { + cal->addJournal(journal); + } else { + delete journal; + } } } c = icalcomponent_get_next_component(calendar,ICAL_VJOURNAL_COMPONENT); diff --git a/libkcal/incidence.cpp b/libkcal/incidence.cpp index 94995b12c..79de6723d 100644 --- a/libkcal/incidence.cpp +++ b/libkcal/incidence.cpp @@ -27,13 +27,15 @@ #include "calformat.h" #include "incidence.h" +#include "calendar.h" using namespace KCal; Incidence::Incidence() : IncidenceBase(), mRelatedTo(0), mStatus(StatusNone), mSecrecy(SecrecyPublic), - mPriority(0), mRecurrence(0) + mPriority(0), mRecurrence(0), + mHasRecurrenceID( false ), mChildRecurrenceEvents() { recreate(); @@ -59,6 +61,9 @@ Incidence::Incidence( const Incidence &i ) : IncidenceBase( i ),Recurrence::Obse mSecrecy = i.mSecrecy; mPriority = i.mPriority; mLocation = i.mLocation; + mRecurrenceID = i.mRecurrenceID; + mHasRecurrenceID = i.mHasRecurrenceID; + mChildRecurrenceEvents = i.mChildRecurrenceEvents; // Alarms and Attachments are stored in ListBase<...>, which is a TQValueList<...*>. // We need to really duplicate the objects stored therein, otherwise deleting @@ -124,6 +129,9 @@ Incidence& Incidence::operator=( const Incidence &i ) mSecrecy = i.mSecrecy; mPriority = i.mPriority; mLocation = i.mLocation; + mRecurrenceID = i.mRecurrenceID; + mHasRecurrenceID = i.mHasRecurrenceID; + mChildRecurrenceEvents = i.mChildRecurrenceEvents; mAlarms.clearAll(); Alarm::List::ConstIterator it; @@ -413,12 +421,58 @@ bool Incidence::doesRecur() const bool Incidence::recursOn(const TQDate &qd) const { - return ( mRecurrence && mRecurrence->recursOn(qd) ); + bool doesRecur = false; + doesRecur = mRecurrence && mRecurrence->recursOn(qd); + + return doesRecur; } bool Incidence::recursAt(const TQDateTime &qdt) const { - return ( mRecurrence && mRecurrence->recursAt(qdt) ); + bool doesRecur = false; + doesRecur = mRecurrence && mRecurrence->recursAt(qdt); + + return doesRecur; +} + +bool Incidence::recursOn(const TQDate &qd, Calendar *cal) const +{ + bool doesRecur = false; + doesRecur = mRecurrence && mRecurrence->recursOn(qd); + + // Make sure that this instance has not been moved through a RECURRENCE-ID statement + if (hasRecurrenceID() == false) { + IncidenceList il = childIncidences(); + IncidenceListIterator it; + for ( it = il.begin(); it != il.end(); ++it ) { + QDateTime modifiedDt = cal->incidence(*it)->recurrenceID(); + modifiedDt.setTime(QTime()); + if (QDateTime(qd) == modifiedDt) { + doesRecur = false; + } + } + } + + return doesRecur; +} + +bool Incidence::recursAt(const TQDateTime &qdt, Calendar *cal) const +{ + bool doesRecur = false; + doesRecur = mRecurrence && mRecurrence->recursAt(qdt); + + // Make sure that this instance has not been moved through a RECURRENCE-ID statement + if (hasRecurrenceID() == false) { + IncidenceList il = childIncidences(); + IncidenceListIterator it; + for ( it = il.begin(); it != il.end(); ++it ) { + if (qdt == cal->incidence(*it)->recurrenceID()) { + doesRecur = false; + } + } + } + + return doesRecur; } /** @@ -836,6 +890,52 @@ TQString Incidence::schedulingID() const return mSchedulingID; } +bool Incidence::hasRecurrenceID() const +{ + return mHasRecurrenceID; +} + +void Incidence::setHasRecurrenceID( bool hasRecurrenceID ) +{ + if ( mReadOnly ) { + return; + } + + mHasRecurrenceID = hasRecurrenceID; + updated(); +} + +TQDateTime Incidence::recurrenceID() const +{ + return mRecurrenceID; +} + +void Incidence::setRecurrenceID( const TQDateTime &recurrenceID ) +{ + if ( mReadOnly ) { + return; + } + +// update(); + mRecurrenceID = recurrenceID; + updated(); +} + +void Incidence::addChildIncidence( TQString childIncidence ) +{ + mChildRecurrenceEvents.append(childIncidence); +} + +void Incidence::deleteChildIncidence( TQString childIncidence ) +{ + mChildRecurrenceEvents.remove(childIncidence); +} + +IncidenceList Incidence::childIncidences() const +{ + return mChildRecurrenceEvents; +} + /** Observer interface for the recurrence class. If the recurrence is changed, this method will be called for the incidence the recurrence object belongs to. */ diff --git a/libkcal/incidence.h b/libkcal/incidence.h index 268b2cede..477b758c6 100644 --- a/libkcal/incidence.h +++ b/libkcal/incidence.h @@ -36,6 +36,10 @@ namespace KCal { +class Calendar; + +typedef QStringList IncidenceList; +typedef QStringList::iterator IncidenceListIterator; /** This class provides the base class common to all calendar components. @@ -249,6 +253,21 @@ class LIBKCAL_EXPORT Incidence : public IncidenceBase, public Recurrence::Observ bool recursAt( const TQDateTime &qdt ) const; /** + Returns true if the date specified is one on which the incidence will + recur. + This function takes RECURRENCE-ID parameters into account + @param cal the calendar owning the incidence + */ + virtual bool recursOn( const TQDate &qd, Calendar *cal ) const; + /** + Returns true if the date/time specified is one on which the incidence will + recur. + This function takes RECURRENCE-ID parameters into account + @param cal the calendar owning the incidence + */ + bool recursAt( const TQDateTime &qdt, Calendar *cal ) const; + + /** Calculates the start date/time for all recurrences that happen at some time on the given date (might start before that date, but end on or after the given date). @@ -378,6 +397,58 @@ class LIBKCAL_EXPORT Incidence : public IncidenceBase, public Recurrence::Observ */ int priority() const; + /** + Returns true if the incidence has recurrenceID, otherwise return false. + @see setHasRecurrenceID(), setRecurrenceID(TQDateTime) + @since 3.5.12 + */ + bool hasRecurrenceID() const; + + /** + Sets if the incidence has recurrenceID. + @param hasRecurrenceID true if incidence has recurrenceID, otherwise false + @see hasRecurrenceID(), recurrenceID() + @since 3.5.12 + */ + void setHasRecurrenceID( bool hasRecurrenceID ); + + /** + Set the incidences recurrenceID. + @param recurrenceID is the incidence recurrenceID to set + @see recurrenceID(). + @since 3.5.12 + */ + void setRecurrenceID( const TQDateTime &recurrenceID ); + + /** + Returns the incidence recurrenceID. + @return incidences recurrenceID value + @see setRecurrenceID(). + @since 3.5.12 + */ + TQDateTime recurrenceID() const; + + /** + Attach a child incidence to a parent incidence. + @param childIncidence is the child incidence to add + @since 3.5.12 + */ + void addChildIncidence( TQString childIncidence ); + + /** + Detach a child incidence from its parent incidence. + @param childIncidence is the child incidence to remove + @since 3.5.12 + */ + void deleteChildIncidence( TQString childIncidence ); + + /** + Returns an EventList of all child incidences. + @return EventList of all child incidences. + @since 3.5.12 + */ + IncidenceList childIncidences() const; + // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // %%%%% Alarm-related methods @@ -477,6 +548,11 @@ class LIBKCAL_EXPORT Incidence : public IncidenceBase, public Recurrence::Observ // Scheduling ID - used only to identify between scheduling mails TQString mSchedulingID; + TQDateTime mRecurrenceID; // recurrenceID + bool mHasRecurrenceID; // if incidence has recurrenceID + + IncidenceList mChildRecurrenceEvents; + class Private; Private *d; }; |