diff --git a/kcal/CMakeLists.txt b/kcal/CMakeLists.txt index a68b4c94e..541eac141 100644 --- a/kcal/CMakeLists.txt +++ b/kcal/CMakeLists.txt @@ -1,182 +1,184 @@ project(kcal) set(LIBICAL_MIN_VERSION "0.42") find_package(Libical) macro_log_feature(LIBICAL_FOUND "libical" "Reference implementation of the iCalendar data type and serialization format" "http://sourceforge.net/projects/freeassociation" TRUE ${LIBICAL_MIN_VERSION} "Required for the critical PIM kcal library.") add_definitions(-DKDE_DEFAULT_DEBUG_AREA=5800) include (ConfigureChecks.cmake) if(KDE4_BUILD_TESTS) add_definitions(-DCOMPILING_TESTS) endif(KDE4_BUILD_TESTS) include_directories( ${LIBICAL_INCLUDE_DIRS} ${LIBICAL_INCLUDE_DIRS}/libical ${CMAKE_CURRENT_SOURCE_DIR}/versit ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/kabc ${CMAKE_BINARY_DIR}/kabc ${KDE4_INCLUDE_DIR} ) set(libversit_SRCS ${CMAKE_SOURCE_DIR}/kcal/versit/vcc.c ${CMAKE_SOURCE_DIR}/kcal/versit/vobject.c ) ########### next target ############### set(kcal_LIB_SRCS ${libversit_SRCS} incidencebase.cpp incidence.cpp journal.cpp todo.cpp event.cpp freebusy.cpp freebusyperiod.cpp attendee.cpp attachment.cpp recurrencerule.cpp recurrence.cpp alarm.cpp customproperties.cpp calendar.cpp calendarlocal.cpp calformat.cpp vcalformat.cpp icalformat.cpp icalformat_p.cpp incidenceformatter.cpp vcaldrag.cpp icaldrag.cpp exceptions.cpp scheduler.cpp imipscheduler.cpp dummyscheduler.cpp calfilter.cpp person.cpp period.cpp duration.cpp dndfactory.cpp calstorage.cpp filestorage.cpp compat.cpp resourcecalendar.cpp resourcelocal.cpp resourcelocalconfig.cpp resourcelocaldir.cpp resourcelocaldirconfig.cpp resourcecached.cpp resourcecachedconfig.cpp calendarresources.cpp qtopiaformat.cpp htmlexport.cpp calendarnull.cpp freebusyurlstore.cpp confirmsavedialog.cpp icaltimezones.cpp kresult.cpp assignmentvisitor.cpp + comparisonvisitor.cpp ) kde4_add_kcfg_files(kcal_LIB_SRCS htmlexportsettings.kcfgc ) kde4_add_library(kcal SHARED ${kcal_LIB_SRCS}) target_link_libraries(kcal ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS} ${QT_QTXML_LIBRARY} kresources kabc kpimutils ${LIBICAL_LIBRARIES}) target_link_libraries(kcal LINK_INTERFACE_LIBRARIES kresources kabc) set_target_properties(kcal PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION}) install(TARGETS kcal EXPORT kdepimlibsLibraryTargets ${INSTALL_TARGETS_DEFAULT_ARGS}) ########### next target ############### set(kcal_local_PART_SRCS resourcelocal_plugin.cpp ) kde4_add_plugin(kcal_local ${kcal_local_PART_SRCS}) target_link_libraries(kcal_local ${QT_QTGUI_LIBRARY} ${KDE4_KDECORE_LIBS} kcal kresources ) install(TARGETS kcal_local DESTINATION ${PLUGIN_INSTALL_DIR}) ########### next target ############### set(kcal_localdir_PART_SRCS resourcelocaldir_plugin.cpp ) kde4_add_plugin(kcal_localdir ${kcal_localdir_PART_SRCS}) target_link_libraries(kcal_localdir ${QT_QTGUI_LIBRARY} ${KDE4_KDECORE_LIBS} kcal kresources) install(TARGETS kcal_localdir DESTINATION ${PLUGIN_INSTALL_DIR}) add_subdirectory( tests ) ########### install files ############### install( FILES local.desktop localdir.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kresources/kcal) install( FILES alarm.h assignmentvisitor.h attachment.h attendee.h calendar.h calendarlocal.h calendarnull.h calendarresources.h calfilter.h calformat.h calstorage.h + comparisonvisitor.h confirmsavedialog.h customproperties.h dndfactory.h duration.h event.h exceptions.h filestorage.h freebusy.h freebusycache.h freebusyperiod.h freebusyurlstore.h ${CMAKE_CURRENT_BINARY_DIR}/htmlexportsettings.h htmlexport.h icaldrag.h icalformat.h icaltimezones.h imipscheduler.h incidencebase.h incidence.h incidenceformatter.h journal.h kcal_export.h kcalversion.h listbase.h period.h person.h qtopiaformat.h recurrencerule.h recurrence.h resourcecached.h resourcecachedconfig.h resourcecalendar.h resourcelocalconfig.h resourcelocaldirconfig.h resourcelocaldir.h resourcelocal.h scheduler.h sortablelist.h todo.h vcaldrag.h vcalformat.h kresult.h DESTINATION ${INCLUDE_INSTALL_DIR}/kcal COMPONENT Devel) install( FILES kcal_manager.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kresources) diff --git a/kcal/comparisonvisitor.cpp b/kcal/comparisonvisitor.cpp new file mode 100644 index 000000000..9ca985edd --- /dev/null +++ b/kcal/comparisonvisitor.cpp @@ -0,0 +1,108 @@ +/* + Copyright 2009 Ingo Klöcker + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "comparisonvisitor.h" + +#include "event.h" +#include "freebusy.h" +#include "journal.h" +#include "todo.h" + +using namespace KCal; + +class ComparisonVisitor::Private +{ + public: + Private() : mReference( 0 ) {} + + public: + const IncidenceBase *mReference; +}; + +ComparisonVisitor::ComparisonVisitor() : d( new Private() ) +{ +} + +ComparisonVisitor::~ComparisonVisitor() +{ + delete d; +} + +bool ComparisonVisitor::compare( IncidenceBase* incidence, const IncidenceBase* reference ) +{ + d->mReference = reference; + + const bool result = incidence ? incidence->accept( *this ) : reference == 0; + + d->mReference = 0; + + return result; +} + +bool ComparisonVisitor::visit( Event* event ) +{ + Q_ASSERT( event != 0 ); + + const Event *refEvent = dynamic_cast( d->mReference ); + if ( refEvent ) { + return *event == *refEvent; + } else { + // refEvent is no Event and thus cannot be equal to event + return false; + } +} + +bool ComparisonVisitor::visit( Todo* todo ) +{ + Q_ASSERT( todo != 0 ); + + const Todo *refTodo = dynamic_cast( d->mReference ); + if ( refTodo ) { + return *todo == *refTodo; + } else { + // refTodo is no Todo and thus cannot be equal to todo + return false; + } +} + +bool ComparisonVisitor::visit( Journal* journal ) +{ + Q_ASSERT( journal != 0 ); + + const Journal *refJournal = dynamic_cast( d->mReference ); + if ( refJournal ) { + return *journal == *refJournal; + } else { + // refJournal is no Journal and thus cannot be equal to journal + return false; + } +} + +bool ComparisonVisitor::visit( FreeBusy* freebusy ) +{ + Q_ASSERT( freebusy != 0 ); + + const FreeBusy *refFreeBusy = dynamic_cast( d->mReference ); + if ( refFreeBusy ) { + return *freebusy == *refFreeBusy; + } else { + // refFreeBusy is no FreeBusy and thus cannot be equal to freebusy + return false; + } +} diff --git a/kcal/comparisonvisitor.h b/kcal/comparisonvisitor.h new file mode 100644 index 000000000..f55406ca2 --- /dev/null +++ b/kcal/comparisonvisitor.h @@ -0,0 +1,128 @@ +/* + Copyright 2009 Ingo Klöcker + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#ifndef KCAL_COMPARISONVISITOR_H +#define KCAL_COMPARISONVISITOR_H + +#include "kcal_export.h" + +#include "incidencebase.h" + +namespace KCal { + +/** + Helper for type correct comparison of incidences via pointers. + + This class provides a way of correctly comparing one incidence to another, + given two IncidenceBase derived pointers. It effectively provides a virtual + comparison method which first type checks the two pointers to ensure they + reference the same incidence type, before performing the comparison. + + Usage example: + @code + KCal::Incidence *incidence; // assume this is set somewhere else + KCal::Incidence *referenceIncidence; // assume this is set somewhere else + + KCal::ComparisonVisitor visitor; + + // compare + if ( visitor.compare( incidence, referenceIncidence ) ) { + // incidence and referenceIncidence point to identical incidences + } + @endcode + + @author Ingo Klöcker + + @since 4.3 + */ +class KCAL_EXPORT ComparisonVisitor : public IncidenceBase::Visitor +{ + public: + /** + Creates a visitor instance. + */ + ComparisonVisitor(); + + /** + Destroys the instance. + */ + virtual ~ComparisonVisitor(); + + /** + Compares the incidence referenced by @p incidence to the incidence + referenced by @p reference. Returns true, if the incidence referenced + by @p incidence is identical to the incidence referenced by @p reference. + Also returns true, if @p incidence and @p reference are both @c 0. + + Basically it is a virtual equivalent of + @code + *incidence == *reference + @endcode + + @param incidence pointer to the incidence to compare with the reference incidence + @param reference pointer to the reference incidence + + @return @c true if the two incidences are identical or both @c 0 + */ + bool compare( IncidenceBase *incidence, const IncidenceBase *reference ); + + /** + Compares the event referenced by @p event to the incidence passed to + compare(). + + @return @c true if the event is identical to the reference incidence + */ + virtual bool visit( Event *event ); + + /** + Compares the todo referenced by @p todo to the incidence passed to + compare(). + + @return @c true if the todo is identical to the reference incidence + */ + virtual bool visit( Todo *todo ); + + /** + Compares the journal referenced by @p journal to the incidence passed to + compare(). + + @return @c true if the journal is identical to the reference incidence + */ + virtual bool visit( Journal *journal ); + + /** + Compares the freebusy object referenced by @p freebusy to the incidence passed to + compare(). + + @return @c true if the freebusy object is identical to the reference incidence + */ + virtual bool visit( FreeBusy *freebusy ); + + private: + //@cond PRIVATE + class Private; + Private *const d; + //@endcond + + Q_DISABLE_COPY( ComparisonVisitor ) +}; + +} + +#endif // KCAL_COMPARISONVISITOR_H diff --git a/kcal/customproperties.h b/kcal/customproperties.h index 9e46a8a7c..55c4e449d 100644 --- a/kcal/customproperties.h +++ b/kcal/customproperties.h @@ -1,171 +1,175 @@ /* This file is part of the kcal library. Copyright (c) 2002,2006 David Jarvie This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** @file This file is part of the API for handling calendar data and defines the CustomProperties class. @author David Jarvie \ */ #ifndef KCAL_CUSTOMPROPERTIES_H #define KCAL_CUSTOMPROPERTIES_H #include "kcal_export.h" #include #include #include namespace KCal { /** @brief A class to manage custom calendar properties. This class represents custom calendar properties. It is used as a base class for classes which represent calendar components. A custom property name written by the kcal library has the form X-KDE-APP-KEY where APP represents the application name, and KEY distinguishes individual properties for the application. In keeping with RFC2445, property names must be composed only of the characters A-Z, a-z, 0-9 and '-'. */ class KCAL_EXPORT CustomProperties { public: /** Constructs an empty custom properties instance. */ CustomProperties(); /** Copy constructor. @param other is the one to copy. */ CustomProperties( const CustomProperties &other ); /** Destructor. */ virtual ~CustomProperties(); /** Compare this with @p properties for equality. @param properties is the one to compare. + + @warning The comparison is not polymorphic. */ - bool operator==( const CustomProperties &properties ) const; + bool operator==( const CustomProperties &properties ) const; // KDE5: make protected to prevent accidental usage /** Create or modify a custom calendar property. @param app Application name as it appears in the custom property name. @param key Property identifier specific to the application. @param value The property's value. A call with a value of QString() will be ignored. @see removeCustomProperty(). */ void setCustomProperty( const QByteArray &app, const QByteArray &key, const QString &value ); /** Delete a custom calendar property. @param app Application name as it appears in the custom property name. @param key Property identifier specific to the application. @see setCustomProperty(). */ void removeCustomProperty( const QByteArray &app, const QByteArray &key ); /** Return the value of a custom calendar property. @param app Application name as it appears in the custom property name. @param key Property identifier specific to the application. @return Property value, or QString() if (and only if) the property does not exist. */ QString customProperty( const QByteArray &app, const QByteArray &key ) const; /** Create or modify a non-KDE or non-standard custom calendar property. @param name Full property name @param value The property's value. A call with a value of QString() will be ignored. @see removeNonKDECustomProperty(). */ void setNonKDECustomProperty( const QByteArray &name, const QString &value ); /** Delete a non-KDE or non-standard custom calendar property. @param name Full property name @see setNonKDECustomProperty(). */ void removeNonKDECustomProperty( const QByteArray &name ); /** Return the value of a non-KDE or non-standard custom calendar property. @param name Full property name @return Property value, or QString() if (and only if) the property does not exist. */ QString nonKDECustomProperty( const QByteArray &name ) const; /** Initialise the alarm's custom calendar properties to the specified key/value pairs. @param properties is a QMap of property key/value pairs. @see customProperties(). */ void setCustomProperties( const QMap &properties ); /** Returns all custom calendar property key/value pairs. @see setCustomProperties(). */ QMap customProperties() const; /** Assignment operator. + + @warning The assignment is not polymorphic. */ - CustomProperties &operator=( const CustomProperties &other ); + CustomProperties &operator=( const CustomProperties &other ); // KDE5: make protected to prevent accidental usage protected: /** Called when a custom property has been changed. The default implementation does nothing: override in derived classes to perform change processing. */ virtual void customPropertyUpdated() {} private: //@cond PRIVATE class Private; Private *const d; //@endcond }; } #endif diff --git a/kcal/event.cpp b/kcal/event.cpp index 4a1e90ae7..a7021a1ff 100644 --- a/kcal/event.cpp +++ b/kcal/event.cpp @@ -1,277 +1,277 @@ /* This file is part of the kcal library. Copyright (c) 2001 Cornelius Schumacher This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** @file This file is part of the API for handling calendar data and defines the Event class. @brief This class provides an Event in the sense of RFC2445. @author Cornelius Schumacher \ */ #include "event.h" #include "incidenceformatter.h" #include #include #include #include using namespace KCal; /** Private class that helps to provide binary compatibility between releases. @internal */ //@cond PRIVATE class KCal::Event::Private { public: Private() : mHasEndDate( false ), mTransparency( Opaque ) {} Private( const KCal::Event::Private &other ) : mDtEnd( other.mDtEnd ), mHasEndDate( other.mHasEndDate ), mTransparency( other.mTransparency ) {} KDateTime mDtEnd; bool mHasEndDate; Transparency mTransparency; }; //@endcond Event::Event() : d( new KCal::Event::Private ) { } Event::Event( const Event &other ) : Incidence( other ), d( new KCal::Event::Private( *other.d ) ) { } Event::~Event() { delete d; } Event *Event::clone() { return new Event( *this ); } Event &Event::operator=( const Event &other ) { // check for self assignment if ( &other == this ) { return *this; } Incidence::operator=( other ); *d = *other.d; return *this; } bool Event::operator==( const Event &event ) const { return - static_cast( *this ) == static_cast( event ) && + Incidence::operator==( event ) && dtEnd() == event.dtEnd() && hasEndDate() == event.hasEndDate() && transparency() == event.transparency(); } QByteArray Event::type() const { return "Event"; } void Event::setDtEnd( const KDateTime &dtEnd ) { if ( mReadOnly ) { return; } d->mDtEnd = dtEnd; setHasEndDate( true ); setHasDuration( false ); updated(); } KDateTime Event::dtEnd() const { if ( hasEndDate() ) { return d->mDtEnd; } if ( hasDuration() ) { if ( allDay() ) { // For all day events, dtEnd is always inclusive KDateTime end = duration().end( dtStart() ).addDays( -1 ); return end >= dtStart() ? end : dtStart(); } else { return duration().end( dtStart() ); } } // It is valid for a VEVENT to be without a DTEND. See RFC2445, Sect4.6.1. // Be careful to use Event::dateEnd() as appropriate due to this possibility. return dtStart(); } QDate Event::dateEnd() const { KDateTime end = dtEnd().toTimeSpec( dtStart() ); if ( allDay() ) { return end.date(); } else { return end.addSecs(-1).date(); } } QString Event::dtEndTimeStr( bool shortfmt, const KDateTime::Spec &spec ) const { if ( spec.isValid() ) { QString timeZone; if ( spec.timeZone() != KSystemTimeZones::local() ) { timeZone = ' ' + spec.timeZone().name(); } return KGlobal::locale()->formatTime( dtEnd().toTimeSpec( spec ).time(), !shortfmt ) + timeZone; } else { return KGlobal::locale()->formatTime( dtEnd().time(), !shortfmt ); } } QString Event::dtEndDateStr( bool shortfmt, const KDateTime::Spec &spec ) const { if ( spec.isValid() ) { QString timeZone; if ( spec.timeZone() != KSystemTimeZones::local() ) { timeZone = ' ' + spec.timeZone().name(); } return KGlobal::locale()->formatDate( dtEnd().toTimeSpec( spec ).date(), ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ) + timeZone; } else { return KGlobal::locale()->formatDate( dtEnd().date(), ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ); } } QString Event::dtEndStr( bool shortfmt, const KDateTime::Spec &spec ) const { if ( allDay() ) { return IncidenceFormatter::dateToString( dtEnd(), shortfmt, spec ); } if ( spec.isValid() ) { QString timeZone; if ( spec.timeZone() != KSystemTimeZones::local() ) { timeZone = ' ' + spec.timeZone().name(); } return KGlobal::locale()->formatDateTime( dtEnd().toTimeSpec( spec ).dateTime(), ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ) + timeZone; } else { return KGlobal::locale()->formatDateTime( dtEnd().dateTime(), ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ); } } void Event::setHasEndDate( bool b ) { d->mHasEndDate = b; } bool Event::hasEndDate() const { return d->mHasEndDate; } bool Event::isMultiDay( const KDateTime::Spec &spec ) const { // End date is non inclusive, so subtract 1 second... KDateTime start, end; if ( spec.isValid() ) { start = dtStart().toTimeSpec( spec ); end = dtEnd().toTimeSpec( spec ); } else { start = dtStart(); end = dtEnd(); } if ( !allDay() ) { end = end.addSecs( -1 ); } bool multi = ( start.date() != end.date() && start <= end ); return multi; } void Event::shiftTimes( const KDateTime::Spec &oldSpec, const KDateTime::Spec &newSpec ) { Incidence::shiftTimes( oldSpec, newSpec ); if ( hasEndDate() ) { d->mDtEnd = d->mDtEnd.toTimeSpec( oldSpec ); d->mDtEnd.setTimeSpec( newSpec ); } } void Event::setTransparency( Event::Transparency transparency ) { if ( mReadOnly ) { return; } d->mTransparency = transparency; updated(); } Event::Transparency Event::transparency() const { return d->mTransparency; } void Event::setDuration( const Duration &duration ) { setHasEndDate( false ); Incidence::setDuration( duration ); } KDateTime Event::endDateRecurrenceBase() const { return dtEnd(); } diff --git a/kcal/freebusy.cpp b/kcal/freebusy.cpp index 89b568a77..5d64c6758 100644 --- a/kcal/freebusy.cpp +++ b/kcal/freebusy.cpp @@ -1,364 +1,364 @@ /* This file is part of the kcal library. Copyright (c) 2001 Cornelius Schumacher Copyright (C) 2004 Reinhold Kainhofer This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** @file This file is part of the API for handling calendar data and defines the FreeBusy class. @brief Provides information about the free/busy time of a calendar user. @author Cornelius Schumacher \ @author Reinhold Kainhofer \ */ #include "freebusy.h" #include "calendar.h" #include "event.h" #include #include using namespace KCal; //@cond PRIVATE class KCal::FreeBusy::Private { public: Private() : mCalendar( 0 ) {} Private( const KCal::FreeBusy::Private &other ) { init( other ); } Private( const FreeBusyPeriod::List &busyPeriods ) : mBusyPeriods( busyPeriods ), mCalendar( 0 ) {} void init( const KCal::FreeBusy::Private &other ); KDateTime mDtEnd; // end datetime FreeBusyPeriod::List mBusyPeriods;// list of periods Calendar *mCalendar; // associated calendar, not owned by this instance //This is used for creating a freebusy object for the current user bool addLocalPeriod( FreeBusy *fb, const KDateTime &start, const KDateTime &end ); }; void KCal::FreeBusy::Private::init( const KCal::FreeBusy::Private &other ) { mDtEnd = other.mDtEnd; mBusyPeriods = other.mBusyPeriods; mCalendar = other.mCalendar; } //@endcond FreeBusy::FreeBusy() : d( new KCal::FreeBusy::Private() ) { } FreeBusy::FreeBusy( const FreeBusy &other ) : IncidenceBase( other ), d( new KCal::FreeBusy::Private( *other.d ) ) { } FreeBusy::FreeBusy( const KDateTime &start, const KDateTime &end ) : d( new KCal::FreeBusy::Private() ) { setDtStart( start ); setDtEnd( end ); } FreeBusy::FreeBusy( Calendar *calendar, const KDateTime &start, const KDateTime &end ) : d( new KCal::FreeBusy::Private() ) { kDebug(); d->mCalendar = calendar; setDtStart( start ); setDtEnd( end ); // Get all the events in the calendar Event::List eventList = d->mCalendar->rawEvents( start.date(), end.date() ); int extraDays, i, x, duration; duration = start.daysTo( end ); QDate day; KDateTime tmpStart; KDateTime tmpEnd; // Loops through every event in the calendar Event::List::ConstIterator it; for ( it = eventList.constBegin(); it != eventList.constEnd(); ++it ) { Event *event = *it; // The code below can not handle all-dayevents. Fixing this resulted // in a lot of duplicated code. Instead, make a copy of the event and // set the period to the full day(s). This trick works for recurring, // multiday, and single day all-day events. Event *allDayEvent = 0; if ( event->allDay() ) { // addDay event. Do the hack kDebug() << "All-day event"; allDayEvent = new Event( *event ); // Set the start and end times to be on midnight KDateTime st = allDayEvent->dtStart(); st.setTime( QTime( 0, 0 ) ); KDateTime nd = allDayEvent->dtEnd(); nd.setTime( QTime( 23, 59, 59, 999 ) ); allDayEvent->setAllDay( false ); allDayEvent->setDtStart( st ); allDayEvent->setDtEnd( nd ); kDebug() << "Use:" << st.toString() << "to" << nd.toString(); // Finally, use this event for the setting below event = allDayEvent; } // This whole for loop is for recurring events, it loops through // each of the days of the freebusy request // If this event is transparent it shouldn't be in the freebusy list. if ( event->transparency() == Event::Transparent ) { continue; } for ( i = 0; i <= duration; ++i ) { day = start.addDays(i).date(); tmpStart.setDate( day ); tmpEnd.setDate( day ); if ( event->recurs() ) { if ( event->isMultiDay() ) { // FIXME: This doesn't work for sub-daily recurrences or recurrences with // a different time than the original event. extraDays = event->dtStart().daysTo( event->dtEnd() ); for ( x = 0; x <= extraDays; ++x ) { if ( event->recursOn( day.addDays(-x), start.timeSpec() ) ) { tmpStart.setDate( day.addDays(-x) ); tmpStart.setTime( event->dtStart().time() ); tmpEnd = event->duration().end( tmpStart ); d->addLocalPeriod( this, tmpStart, tmpEnd ); break; } } } else { if ( event->recursOn( day, start.timeSpec() ) ) { tmpStart.setTime( event->dtStart().time() ); tmpEnd.setTime( event->dtEnd().time() ); d->addLocalPeriod ( this, tmpStart, tmpEnd ); } } } } // Non-recurring events d->addLocalPeriod( this, event->dtStart(), event->dtEnd() ); // Clean up delete allDayEvent; } sortList(); } FreeBusy::FreeBusy( const Period::List &busyPeriods ) : d( new KCal::FreeBusy::Private() ) { addPeriods(busyPeriods); } FreeBusy::FreeBusy( const FreeBusyPeriod::List &busyPeriods ) : d( new KCal::FreeBusy::Private( busyPeriods ) ) { } FreeBusy::~FreeBusy() { delete d; } QByteArray FreeBusy::type() const { return "FreeBusy"; } void FreeBusy::setDtStart( const KDateTime &start ) { IncidenceBase::setDtStart( start.toUtc() ); updated(); } void FreeBusy::setDtEnd( const KDateTime &end ) { d->mDtEnd = end; } KDateTime FreeBusy::dtEnd() const { return d->mDtEnd; } Period::List FreeBusy::busyPeriods() const { Period::List res; foreach ( const FreeBusyPeriod &p, d->mBusyPeriods ) { res << p; } return res; } FreeBusyPeriod::List FreeBusy::fullBusyPeriods() const { return d->mBusyPeriods; } void FreeBusy::sortList() { qSort( d->mBusyPeriods ); return; } void FreeBusy::addPeriods( const Period::List &list ) { foreach ( const Period &p, list ) { d->mBusyPeriods << FreeBusyPeriod( p ); } sortList(); } void FreeBusy::addPeriods( const FreeBusyPeriod::List &list ) { d->mBusyPeriods += list; sortList(); } void FreeBusy::addPeriod( const KDateTime &start, const KDateTime &end ) { d->mBusyPeriods.append( FreeBusyPeriod( start, end ) ); sortList(); } void FreeBusy::addPeriod( const KDateTime &start, const Duration &duration ) { d->mBusyPeriods.append( FreeBusyPeriod( start, duration ) ); sortList(); } void FreeBusy::merge( FreeBusy *freeBusy ) { if ( freeBusy->dtStart() < dtStart() ) { setDtStart( freeBusy->dtStart() ); } if ( freeBusy->dtEnd() > dtEnd() ) { setDtEnd( freeBusy->dtEnd() ); } Period::List periods = freeBusy->busyPeriods(); Period::List::ConstIterator it; for ( it = periods.constBegin(); it != periods.constEnd(); ++it ) { addPeriod( (*it).start(), (*it).end() ); } } void FreeBusy::shiftTimes( const KDateTime::Spec &oldSpec, const KDateTime::Spec &newSpec ) { if ( oldSpec.isValid() && newSpec.isValid() && oldSpec != newSpec ) { IncidenceBase::shiftTimes( oldSpec, newSpec ); d->mDtEnd = d->mDtEnd.toTimeSpec( oldSpec ); d->mDtEnd.setTimeSpec( newSpec ); foreach ( FreeBusyPeriod p, d->mBusyPeriods ) { //krazy:exclude=foreach p.shiftTimes( oldSpec, newSpec ); } } } FreeBusy &FreeBusy::operator=( const FreeBusy &other ) { // check for self assignment if ( &other == this ) { return *this; } IncidenceBase::operator=( other ); d->init( *other.d ); return *this; } bool FreeBusy::operator==( const FreeBusy &freebusy ) const { return - static_cast( *this ) == static_cast( freebusy ) && + IncidenceBase::operator==( freebusy ) && dtEnd() == freebusy.dtEnd() && d->mCalendar == freebusy.d->mCalendar && d->mBusyPeriods == freebusy.d->mBusyPeriods; } //@cond PRIVATE bool FreeBusy::Private::addLocalPeriod( FreeBusy *fb, const KDateTime &eventStart, const KDateTime &eventEnd ) { KDateTime tmpStart; KDateTime tmpEnd; //Check to see if the start *or* end of the event is //between the start and end of the freebusy dates. KDateTime start = fb->dtStart(); if ( !( ( ( start.secsTo(eventStart) >= 0 ) && ( eventStart.secsTo(mDtEnd) >= 0 ) ) || ( ( start.secsTo(eventEnd) >= 0 ) && ( eventEnd.secsTo(mDtEnd) >= 0 ) ) ) ) { return false; } if ( eventStart.secsTo( start ) >= 0 ) { tmpStart = start; } else { tmpStart = eventStart; } if ( eventEnd.secsTo( mDtEnd ) <= 0 ) { tmpEnd = mDtEnd; } else { tmpEnd = eventEnd; } FreeBusyPeriod p( tmpStart, tmpEnd ); mBusyPeriods.append( p ); return true; } //@endcond diff --git a/kcal/incidence.h b/kcal/incidence.h index 2c85a0595..f891a21be 100644 --- a/kcal/incidence.h +++ b/kcal/incidence.h @@ -1,811 +1,824 @@ /* This file is part of the kcal library. Copyright (c) 2001-2003 Cornelius Schumacher Copyright (C) 2003-2004 Reinhold Kainhofer This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** @file This file is part of the API for handling calendar data and defines the Incidence class. @author Cornelius Schumacher \ @author Reinhold Kainhofer \ */ #ifndef INCIDENCE_H #define INCIDENCE_H #include "kcal_export.h" #include "incidencebase.h" #include "alarm.h" #include "attachment.h" #include "recurrence.h" #include namespace KCal { /** @brief Provides the abstract base class common to non-FreeBusy (Events, To-dos, Journals) calendar components known as incidences. Several properties are not allowed for VFREEBUSY objects (see rfc:2445), so they are not in IncidenceBase. The hierarchy is: IncidenceBase - - FreeBusy - - Incidence - - Event - - Todo - - Journal + + FreeBusy + + Incidence + + Event + + Todo + + Journal So IncidenceBase contains all properties that are common to all classes, and Incidence contains all additional properties that are common to Events, Todos and Journals, but are not allowed for FreeBusy entries. */ class KCAL_EXPORT Incidence //krazy:exclude=dpointer since nested class templates confuse krazy : public IncidenceBase, public Recurrence::RecurrenceObserver { public: /** Template for a class that implements a visitor for adding an Incidence to a resource supporting addEvent(), addTodo() and addJournal() calls. */ //@cond PRIVATE template class AddVisitor : public IncidenceBase::Visitor { public: AddVisitor( T *r ) : mResource( r ) {} bool visit( Event *e ) { return mResource->addEvent( e ); } bool visit( Todo *t ) { return mResource->addTodo( t ); } bool visit( Journal *j ) { return mResource->addJournal( j ); } bool visit( FreeBusy * ) { return false; } private: T *mResource; }; //@endcond /** Template for a class that implements a visitor for deleting an Incidence from a resource supporting deleteEvent(), deleteTodo() and deleteJournal() calls. */ //@cond PRIVATE template class DeleteVisitor : public IncidenceBase::Visitor { public: DeleteVisitor( T *r ) : mResource( r ) {} bool visit( Event *e ) { mResource->deleteEvent( e ); return true; } bool visit( Todo *t ) { mResource->deleteTodo( t ); return true; } bool visit( Journal *j ) { mResource->deleteJournal( j ); return true; } bool visit( FreeBusy * ) { return false; } private: T *mResource; }; //@endcond /** The different types of overall incidence status or confirmation. The meaning is specific to the incidence type in context. */ enum Status { StatusNone, /**< No status */ StatusTentative, /**< event is tentative */ StatusConfirmed, /**< event is definite */ StatusCompleted, /**< to-do completed */ StatusNeedsAction, /**< to-do needs action */ StatusCanceled, /**< event or to-do canceled; journal removed */ StatusInProcess, /**< to-do in process */ StatusDraft, /**< journal is draft */ StatusFinal, /**< journal is final */ StatusX /**< a non-standard status string */ }; /** The different types of incidence access classifications. */ enum Secrecy { SecrecyPublic=0, /**< Not secret (default) */ SecrecyPrivate=1, /**< Secret to the owner */ SecrecyConfidential=2 /**< Secret to the owner and some others */ }; /** List of incidences. */ typedef ListBase List; /** Constructs an empty incidence.* */ Incidence(); /** Copy constructor. @param other is the incidence to copy. */ Incidence( const Incidence &other ); /** Destroys an incidence. */ ~Incidence(); /** Returns an exact copy of this incidence. The returned object is owned by the caller. */ virtual Incidence *clone() = 0; /** Set readonly state of incidence. @param readonly If true, the incidence is set to readonly, if false the incidence is set to readwrite. */ void setReadOnly( bool readonly ); /** @copydoc IncidenceBase::setAllDay(). */ void setAllDay( bool allDay ); /** Recreate event. The event is made a new unique event, but already stored event information is preserved. Sets uniquie id, creation date, last modification date and revision number. */ void recreate(); /** Sets the incidence creation date/time. It is stored as a UTC date/time. @param dt is the creation date/time. @see created(). */ void setCreated( const KDateTime &dt ); /** Returns the incidence creation date/time. @see setCreated(). */ KDateTime created() const; /** Sets the number of revisions this incidence has seen. @param rev is the incidence revision number. @see revision(). */ void setRevision( int rev ); /** Returns the number of revisions this incidence has seen. @see setRevision(). */ int revision() const; /** Sets the incidence starting date/time. @param dt is the starting date/time. @see IncidenceBase::dtStart(). */ virtual void setDtStart( const KDateTime &dt ); /** Returns the incidence ending date/time. @see IncidenceBase::dtStart(). */ virtual KDateTime dtEnd() const; /** @copydoc IncidenceBase::shiftTimes() */ virtual void shiftTimes( const KDateTime::Spec &oldSpec, const KDateTime::Spec &newSpec ); /** Sets the incidence description. @param description is the incidence description string. @param isRich if true indicates the description string contains richtext. @see description(). */ void setDescription( const QString &description, bool isRich ); /** Sets the incidence description and tries to guess if the description is rich text. @param description is the incidence description string. @see description(). @since 4.1 */ void setDescription( const QString &description ); /** Returns the incidence description. @see setDescription(). @see richDescription(). */ QString description() const; /** Returns the incidence description in rich text format. @see setDescription(). @see description(). @since 4.1 */ QString richDescription() const; /** Returns true if incidence description contains RichText; false otherwise. @see setDescription(), description(). */ bool descriptionIsRich() const; /** Sets the incidence summary. @param summary is the incidence summary string. @param isRich if true indicates the summary string contains richtext. @see summary(). */ void setSummary( const QString &summary, bool isRich ); /** Sets the incidence summary and tries to guess if the summary is richtext.. @param summary is the incidence summary string. @see summary(). @since 4.1 */ void setSummary( const QString &summary ); /** Returns the incidence summary. @see setSummary(). @see richSummary(). */ QString summary() const; /** Returns the incidence summary in rich text format. @see setSummary(). @see summary(). @since 4.1 */ QString richSummary() const; /** Returns true if incidence summary contains RichText; false otherwise. @see setSummary(), summary(). */ bool summaryIsRich() const; /** Sets the incidence location. Do _not_ use with journals. @param location is the incidence location string. @param isRich if true indicates the location string contains richtext. @see location(). */ void setLocation( const QString &location, bool isRich ); /** Sets the incidence location and tries to guess if the location is richtext. Do _not_ use with journals. @param location is the incidence location string. @param isRich if true indicates the location string contains richtext. @see location(). @since 4.1 */ void setLocation( const QString &location ); /** Returns the incidence location. Do _not_ use with journals. @see setLocation(). @see richLocation(). */ QString location() const; /** Returns the incidence location in rich text format. @see setLocation(). @see location(). @since 4.1 */ QString richLocation() const; /** Returns true if incidence location contains RichText; false otherwise. @see setLocation(), location(). */ bool locationIsRich() const; /** Sets the incidence category list. @param categories is a list of category strings. @see setCategories( const QString &), categories(). */ void setCategories( const QStringList &categories ); /** Sets the incidence category list based on a comma delimited string. @param catStr is a QString containing a list of categories which are delimited by a comma character. @see setCategories( const QStringList &), categories(). */ void setCategories( const QString &catStr ); /** Returns the incidence categories as a list of strings. @see setCategories( const QStringList &), setCategories( Const QString &). */ QStringList categories() const; /** Returns the incidence categories as a comma separated string. @see categories(). */ QString categoriesStr() const; /** Relates another incidence to this one, by UID. This function should only be used when constructing a calendar before the related incidence exists. @param uid is a QString containing a UID for another incidence. @see relatedToUid(), setRelatedTo(). */ void setRelatedToUid( const QString &uid ); /** Returns a UID string for the incidence that is related to this one. This function should only be used when constructing a calendar before the related incidence exists. @see setRelatedToUid(), relatedTo(). */ QString relatedToUid() const; /** Relates another incidence to this one. This function should only be used when constructing a calendar before the related incidence exists. @param incidence is a pointer to another incidence object. @see relatedTo(), setRelatedToUid(). */ void setRelatedTo( Incidence *incidence ); /** Returns a pointer for the incidence that is related to this one. This function should only be used when constructing a calendar before the related incidence exists. @see setRelatedTo(), relatedToUid(). */ Incidence *relatedTo() const; /** Returns a list of all incidences related to this one. @see addRelation, removeRelation(). */ Incidence::List relations() const; /** Adds an incidence that is related to this one. @param incidence is a pointer to an Incidence object. @see removeRelation(), relations(). */ void addRelation( Incidence *incidence ); /** Removes an incidence that is related to this one. @param incidence is a pointer to an Incidence object. @see addRelation(), relations(). */ void removeRelation( Incidence *incidence ); // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // %%%%% Recurrence-related methods // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /** Returns the recurrence rule associated with this incidence. If there is none, returns an appropriate (non-0) object. */ Recurrence *recurrence() const; /** Removes all recurrence and exception rules and dates. */ void clearRecurrence(); /** @copydoc Recurrence::recurs() */ bool recurs() const; /** @copydoc Recurrence::recurrenceType() */ ushort recurrenceType() const; /** @copydoc Recurrence::recursOn() */ virtual bool recursOn( const QDate &date, const KDateTime::Spec &timeSpec ) const; /** @copydoc Recurrence::recursAt() */ bool recursAt( const KDateTime &dt ) 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). @param date the date when the incidence should occur @param timeSpec time specification for @p date. @return the start date/time of all occurrences that overlap with the given date; an empty list if the incidence does not overlap with the date at all. */ virtual QList startDateTimesForDate( const QDate &date, const KDateTime::Spec &timeSpec = KDateTime::LocalZone ) const; /** Calculates the start date/time for all recurrences that happen at the given time. @param datetime the date/time when the incidence should occur. @return the start date/time of all occurrences that overlap with the given date/time; an empty list if the incidence does not happen at the given time at all. */ virtual QList startDateTimesForDateTime( const KDateTime &datetime ) const; /** Returns the end date/time of the incidence occurrence if it starts at specified date/time. @param startDt is the specified starting date/time. @return the corresponding end date/time for the occurrence; or the start date/time if the end date/time is invalid; or the end date/time if the start date/time is invalid. */ virtual KDateTime endDateForStart( const KDateTime &startDt ) const; // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // %%%%% Attachment-related methods // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /** Adds an attachment to the incidence. @param attachment is a pointer to a valid Attachment object. @see deleteAttachment(). */ void addAttachment( Attachment *attachment ); /** Removes the specified attachment from the incidence. Additionally, the memory used by the attachment is freed. @param attachment is a pointer to a valid Attachment object. @see addAttachment(), deleteAttachments(). */ void deleteAttachment( Attachment *attachment ); /** Removes all attachments of the specified MIME type from the incidence. The memory used by all the removed attachments is freed. @param mime is a QString containing the MIME type. @see deleteAttachment(). */ void deleteAttachments( const QString &mime ); /** Returns a list of all incidence attachments. @see attachments( const QString &). */ Attachment::List attachments() const; /** Returns a list of all incidence attachments with the specified MIME type. @param mime is a QString containing the MIME type. @see attachments(). */ Attachment::List attachments( const QString &mime ) const; /** Removes all attachments and frees the memory used by them. @see deleteAttachment( Attachment *), deleteAttachments( const QString &). */ void clearAttachments(); // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // %%%%% Secrecy and Status methods // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /** Sets the incidence #Secrecy. @param secrecy is the incidence #Secrecy to set. @see secrecy(), secrecyStr(). */ void setSecrecy( Secrecy secrecy ); /** Returns the incidence #Secrecy. @see setSecrecy(), secrecyStr(). */ Secrecy secrecy() const; /** Returns the incidence #Secrecy as translated string. @see secrecy(). */ QString secrecyStr() const; /** Returns a list of all available #Secrecy types as a list of translated strings. @see secrecyName(). */ static QStringList secrecyList(); /** Returns the translated string form of a specified #Secrecy. @param secrecy is a #Secrecy type. @see secrecyList(). */ static QString secrecyName( Secrecy secrecy ); /** Sets the incidence status to a standard #Status value. Note that StatusX cannot be specified. @param status is the incidence #Status to set. @see status(), setCustomStatus(). */ void setStatus( Status status ); /** Sets the incidence #Status to a non-standard status value. @param status is a non-standard status string. If empty, the incidence #Status will be set to StatusNone. @see setStatus(), status(). */ void setCustomStatus( const QString &status ); /** Returns the incidence #Status. @see setStatus(), setCustomStatus(), statusStr(). */ Status status() const; /** Returns the incidence #Status as translated string. @see status(). */ QString statusStr() const; /** Returns the translated string form of a specified #Status. @param status is a #Status type. */ static QString statusName( Status status ); // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // %%%%% Other methods // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /** Sets a list of incidence resources. (Note: resources in this context means items used by the incidence such as money, fuel, hours, etc). @param resources is a list of resource strings. @see resources(). */ void setResources( const QStringList &resources ); /** Returns the incidence resources as a list of strings. @see setResources(). */ QStringList resources() const; /** Sets the incidences priority. The priority must be an integer value between 0 and 9, where 0 is undefined, 1 is the highest, and 9 is the lowest priority (decreasing order). @param priority is the incidence priority to set. @see priority(). */ void setPriority( int priority ); /** Returns the incidence priority. @see setPriority(). */ int priority() const; // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // %%%%% Alarm-related methods // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /** Returns a list of all incidence alarms. */ const Alarm::List &alarms() const; /** Create a new incidence alarm. */ Alarm *newAlarm(); /** Adds an alarm to the incidence. @param alarm is a pointer to a valid Alarm object. @see removeAlarm(). */ void addAlarm( Alarm *alarm ); /** Removes the specified alarm from the incidence. @param alarm is a pointer to a valid Alarm object. @see addAlarm(). */ void removeAlarm( Alarm *alarm ); /** Removes all alarms. @see removeAlarm(). */ void clearAlarms(); /** Returns true if any of the incidence alarms are enabled; false otherwise. */ bool isAlarmEnabled() const; // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // %%%%% Other methods // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /** Set the incidence scheduling ID. Do _not_ use with journals. This is used for accepted invitations as the place to store the UID of the invitation. It is later used again if updates to the invitation comes in. If we did not set a new UID on incidences from invitations, we can end up with more than one resource having events with the same UID, if you have access to other peoples resources. @param sid is a QString containing the scheduling ID. @see schedulingID(). */ void setSchedulingID( const QString &sid ); /** Returns the incidence scheduling ID. Do _not_ use with journals. If a scheduling ID is not set, then return the incidence UID. @see setSchedulingID(). */ QString schedulingID() const; /** Observer interface for the recurrence class. If the recurrence is changed, this method will be called for the incidence the recurrence object belongs to. @param recurrence is a pointer to a valid Recurrence object. */ virtual void recurrenceUpdated( Recurrence *recurrence ); /** Assignment operator. + + @warning Not polymorphic. Use AssignmentVisitor for correct + assignment of an instance of type IncidenceBase to another + instance of type Incidence. + + @param other is the Incidence to assign. + + @see AssignmentVisitor */ - Incidence &operator=( const Incidence &other ); + Incidence &operator=( const Incidence &other ); // KDE5: make protected to prevent accidental usage /** - Compare this with @p incidence for equality. + Compares this with Incidence @p ib for equality. + + @warning Not polymorphic. Use ComparisonVisitor for correct + comparison of two instances of type Incidence. + + @param incidence is the Incidence to compare. - @param incidence is the incidence to compare. + @see ComparisonVisitor */ - bool operator==( const Incidence &incidence ) const; + bool operator==( const Incidence &incidence ) const; // KDE5: make protected to prevent accidental usage protected: /** Returns the end date/time of the base incidence (e.g. due date/time for to-dos, end date/time for events). This method must be reimplemented by derived classes. */ virtual KDateTime endDateRecurrenceBase() const { return dtStart(); } private: void init( const Incidence &other ); //@cond PRIVATE class Private; Private *const d; //@endcond }; } #endif diff --git a/kcal/incidencebase.h b/kcal/incidencebase.h index b8d930fb0..433c44f00 100644 --- a/kcal/incidencebase.h +++ b/kcal/incidencebase.h @@ -1,568 +1,581 @@ /* This file is part of the kcal library. Copyright (c) 2001-2003 Cornelius Schumacher Copyright (c) 2003-2004 Reinhold Kainhofer Copyright (c) 2005 Rafal Rzepecki This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** @file This file is part of the API for handling calendar data and defines the IncidenceBase class. @author Cornelius Schumacher \ @author Reinhold Kainhofer \ @author Rafal Rzepecki \ @glossary @anchor incidence @b incidence: General term for a calendar component. Examples are events, to-dos, and journals. @glossary @anchor event @b event: An @ref incidence that has a start and end time, typically representing some occurrence of social or personal importance. May be recurring. Examples are appointments, meetings, or holidays. @glossary @anchor to-do @b to-do: An @ref incidence that has an optional start time and an optional due time typically representing some undertaking to be performed. May be recurring. Examples are "fix the bug" or "pay the bills". @glossary @anchor todo @b todo: See @ref to-do. @glossary @anchor journal @b journal: An @ref incidence with a start date that represents a diary or daily record of one's activities. May @b not be recurring. */ #ifndef KCAL_INCIDENCEBASE_H #define KCAL_INCIDENCEBASE_H #include "attendee.h" #include "customproperties.h" #include "duration.h" #include "sortablelist.h" #include #include #include class KUrl; namespace KCal { /** List of dates */ typedef SortableList DateList; /** List of times */ typedef SortableList DateTimeList; class Event; class Todo; class Journal; class FreeBusy; /** @brief An abstract class that provides a common base for all calendar incidence classes. define: organizer (person) define: uid (same as the attendee uid?) Several properties are not allowed for VFREEBUSY objects (see rfc:2445), so they are not in IncidenceBase. The hierarchy is: IncidenceBase - - FreeBusy - - Incidence - - Event - - Todo - - Journal + + FreeBusy + + Incidence + + Event + + Todo + + Journal So IncidenceBase contains all properties that are common to all classes, and Incidence contains all additional properties that are common to Events, Todos and Journals, but are not allowed for FreeBusy entries. */ class KCAL_EXPORT IncidenceBase : public CustomProperties { public: /** This class provides the interface for a visitor of calendar components. It serves as base class for concrete visitors, which implement certain actions on calendar components. It allows to add functions, which operate on the concrete types of calendar components, without changing the calendar component classes. */ class KCAL_EXPORT Visitor //krazy:exclude=dpointer { public: /** Destruct Incidence::Visitor */ virtual ~Visitor() {} /** Reimplement this function in your concrete subclass of IncidenceBase::Visitor to perform actions on an Event object. @param event is a pointer to a valid Event object. */ virtual bool visit( Event *event ); /** Reimplement this function in your concrete subclass of IncidenceBase::Visitor to perform actions on a Todo object. @param todo is a pointer to a valid Todo object. */ virtual bool visit( Todo *todo ); /** Reimplement this function in your concrete subclass of IncidenceBase::Visitor to perform actions on an Journal object. @param journal is a pointer to a valid Journal object. */ virtual bool visit( Journal *journal ); /** Reimplement this function in your concrete subclass of IncidenceBase::Visitor to perform actions on a FreeBusy object. @param freebusy is a pointer to a valid FreeBusy object. */ virtual bool visit( FreeBusy *freebusy ); protected: /** Constructor is protected to prevent direct creation of visitor base class. */ Visitor() {} }; /** The IncidenceObserver class. */ class IncidenceObserver { public: /** Destroys the IncidenceObserver. */ virtual ~IncidenceObserver() {} /** The IncidenceObserver interface. @param incidenceBase is a pointer to an IncidenceBase object. */ virtual void incidenceUpdated( IncidenceBase *incidenceBase ) = 0; }; /** Constructs an empty IncidenceBase. */ IncidenceBase(); /** Constructs an IncidenceBase as a copy of another IncidenceBase object. @param ib is the IncidenceBase to copy. */ IncidenceBase( const IncidenceBase &ib ); /** Destroys the IncidenceBase. */ virtual ~IncidenceBase(); /** Assignment operator. + + @warning Not polymorphic. Use AssignmentVisitor for correct + assignment of an instance of type IncidenceBase to another + instance of type IncidenceBase. + @param other is the IncidenceBase to assign. + + @see AssignmentVisitor */ - IncidenceBase &operator=( const IncidenceBase &other ); + IncidenceBase &operator=( const IncidenceBase &other ); // KDE5: make protected to prevent accidental usage /** Compares this with IncidenceBase @p ib for equality. + + @warning Not polymorphic. Use ComparisonVisitor for correct + comparison of two instances of type IncidenceBase. + @param ib is the IncidenceBase to compare. + + @see ComparisonVisitor */ - bool operator==( const IncidenceBase &ib ) const; + bool operator==( const IncidenceBase &ib ) const; // KDE5: make protected to prevent accidental usage /** Accept IncidenceVisitor. A class taking part in the visitor mechanism has to provide this implementation:
         bool accept(Visitor &v) { return v.visit(this); }
       
@param v is a reference to a Visitor object. */ virtual bool accept( Visitor &v ) { Q_UNUSED( v ); return false; } /** Prints the type of Incidence as a string. */ virtual QByteArray type() const = 0; /** Sets the unique id for the incidence to @p uid. @param uid is the string containing the incidence @ref uid. @see uid() */ void setUid( const QString &uid ); /** Returns the unique id (@ref uid) for the incidence. @see setUid() */ QString uid() const; /** Returns the uri for the incidence, of form urn:x-ical:\ */ KUrl uri() const; /** Sets the time the incidence was last modified to @p lm. It is stored as a UTC date/time. @param lm is the KDateTime when the incidence was last modified. @see lastModified() */ void setLastModified( const KDateTime &lm ); /** Returns the time the incidence was last modified. @see setLastModified() */ KDateTime lastModified() const; /** Sets the organizer for the incidence. @param organizer is a Person to use as the incidence @ref organizer. @see organizer(), setOrganizer(const QString &) */ void setOrganizer( const Person &organizer ); /** Sets the incidence organizer to any string @p organizer. @param organizer is a string to use as the incidence @ref organizer. @see organizer(), setOrganizer(const Person &) */ void setOrganizer( const QString &organizer ); /** Returns the Person associated with this incidence. @see setOrganizer(const QString &), setOrganizer(const Person &) */ Person organizer() const; /** Sets readonly status. @param readOnly if set, the incidence is read-only; else the incidence can be modified. @see isReadOnly(). */ virtual void setReadOnly( bool readOnly ); /** Returns true the object is read-only; false otherwise. @see setReadOnly() */ bool isReadOnly() const { return mReadOnly; } /** Sets the incidence's starting date/time with a KDateTime. The incidence's all-day status is set according to whether @p dtStart is a date/time (not all-day) or date-only (all-day). @param dtStart is the incidence start date/time. @see dtStart(). */ virtual void setDtStart( const KDateTime &dtStart ); /** Returns an incidence's starting date/time as a KDateTime. @see setDtStart(). */ virtual KDateTime dtStart() const; /** Returns an incidence's starting time as a string formatted according to the user's locale settings. @param shortfmt If set to true, use short date format, if set to false use long format. @param spec If set, return the time in the given spec, else use the incidence's current spec. @deprecated use IncidenceFormatter::timeToString() */ virtual KDE_DEPRECATED QString dtStartTimeStr( bool shortfmt = true, const KDateTime::Spec &spec = KDateTime::Spec() ) const; /** Returns an incidence's starting date as a string formatted according to the user's locale settings. @param shortfmt If set to true, use short date format, if set to false use long format. @param spec If set, return the date in the given spec, else use the incidence's current spec. @deprecated use IncidenceFormatter::dateToString() */ virtual KDE_DEPRECATED QString dtStartDateStr( bool shortfmt = true, const KDateTime::Spec &spec = KDateTime::Spec() ) const; /** Returns an incidence's starting date and time as a string formatted according to the user's locale settings. @param shortfmt If set to true, use short date format, if set to false use long format. @param spec If set, return the date and time in the given spec, else use the incidence's current spec. @deprecated use IncidenceFormatter::dateTimeToString() */ virtual KDE_DEPRECATED QString dtStartStr( bool shortfmt = true, const KDateTime::Spec &spec = KDateTime::Spec() ) const; /** Sets the incidence duration. @param duration the incidence duration @see duration() */ virtual void setDuration( const Duration &duration ); /** Returns the length of the incidence duration. @see setDuration() */ Duration duration() const; /** Sets if the incidence has a duration. @param hasDuration true if the incidence has a duration; false otherwise. @see hasDuration() */ void setHasDuration( bool hasDuration ); /** Returns true if the incidence has a duration; false otherwise. @see setHasDuration() */ bool hasDuration() const; /** Returns true or false depending on whether the incidence is all-day. i.e. has a date but no time attached to it. @see setAllDay() */ bool allDay() const; /** Sets whether the incidence is all-day, i.e. has a date but no time attached to it. @param allDay sets whether the incidence is all-day. @see allDay() */ void setAllDay( bool allDay ); /** Shift the times of the incidence so that they appear at the same clock time as before but in a new time zone. The shift is done from a viewing time zone rather than from the actual incidence time zone. For example, shifting an incidence whose start time is 09:00 America/New York, using an old viewing time zone (@p oldSpec) of Europe/London, to a new time zone (@p newSpec) of Europe/Paris, will result in the time being shifted from 14:00 (which is the London time of the incidence start) to 14:00 Paris time. @param oldSpec the time specification which provides the clock times @param newSpec the new time specification */ virtual void shiftTimes( const KDateTime::Spec &oldSpec, const KDateTime::Spec &newSpec ); /** Adds a comment to thieincidence. Does not add a linefeed character; simply appends the text as specified. @param comment is the QString containing the comment to add. @see removeComment(). */ void addComment( const QString &comment ); /** Removes a comment from the incidence. Removes the first comment whose string is an exact match for the specified string in @p comment. @param comment is the QString containing the comment to remove. @return true if match found, false otherwise. @see addComment(). */ bool removeComment( const QString &comment ); /** Deletes all incidence comments. */ void clearComments(); /** Returns all incidence comments as a list of strings. */ QStringList comments() const; /** Add Attendee to this incidence. IncidenceBase takes ownership of the Attendee object. @param attendee a pointer to the attendee to add @param doUpdate If true the Observers are notified, if false they are not. */ void addAttendee( Attendee *attendee, bool doUpdate = true ); /** Removes all attendees from the incidence. */ void clearAttendees(); /** Returns a list of incidence attendees. */ const Attendee::List &attendees() const; /** Returns the number of incidence attendees. */ int attendeeCount() const; /** Returns the attendee with the specified email address. @param email is a QString containing an email address of the form "FirstName LastName ". @see attendeeByMails(), attendeesByUid(). */ Attendee *attendeeByMail( const QString &email ) const; /** Returns the first incidence attendee with one of the specified email addresses. @param emails is a list of QStrings containing email addresses of the form "FirstName LastName ". @param email is a QString containing a single email address to search in addition to the list specified in @p emails. @see attendeeByMail(), attendeesByUid(). */ Attendee *attendeeByMails( const QStringList &emails, const QString &email = QString() ) const; /** Returns the incidence attendee with the specified attendee @acronym UID. @param uid is a QString containing an attendee @acronym UID. @see attendeeByMail(), attendeeByMails(). */ Attendee *attendeeByUid( const QString &uid ) const; /** Register observer. The observer is notified when the observed object changes. @param observer is a pointer to an IncidenceObserver object that will be watching this incidence. @see unRegisterObserver() */ void registerObserver( IncidenceObserver *observer ); /** Unregister observer. It isn't notified anymore about changes. @param observer is a pointer to an IncidenceObserver object that will be watching this incidence. @see registerObserver(). */ void unRegisterObserver( IncidenceObserver *observer ); /** Call this to notify the observers after the IncidenceBase object has changed. */ void updated(); /** Call this when a group of updates is going to be made. This suppresses change notifications until endUpdates() is called, at which point updated() will automatically be called. */ void startUpdates(); /** Call this when a group of updates is complete, to notify observers that the instance has changed. This should be called in conjunction with startUpdates(). */ void endUpdates(); protected: /** @copydoc CustomProperties::customPropertyUpdated() */ virtual void customPropertyUpdated(); /** Identifies a read-only incidence. */ bool mReadOnly; private: //@cond PRIVATE class Private; Private *const d; //@endcond }; } #endif diff --git a/kcal/journal.cpp b/kcal/journal.cpp index b43fd8f5e..ed6386c45 100644 --- a/kcal/journal.cpp +++ b/kcal/journal.cpp @@ -1,70 +1,70 @@ /* This file is part of the kcal library. Copyright (c) 2001 Cornelius Schumacher This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** @file This file is part of the API for handling calendar data and defines the Journal class. @brief Provides a Journal in the sense of RFC2445. @author Cornelius Schumacher \ */ #include "journal.h" using namespace KCal; Journal::Journal() : d( 0 ) { } Journal::~Journal() { } QByteArray Journal::type() const { return "Journal"; } Journal *Journal::clone() { return new Journal( *this ); } Journal &Journal::operator=( const Journal &other ) { // check for self assignment if ( &other == this ) { return *this; } Incidence::operator=( other ); return *this; } bool Journal::operator==( const Journal &journal ) const { return - static_cast( *this ) == static_cast( journal ); + Incidence::operator==( journal ); } diff --git a/kcal/todo.cpp b/kcal/todo.cpp index 492815a3c..603d319bf 100644 --- a/kcal/todo.cpp +++ b/kcal/todo.cpp @@ -1,550 +1,550 @@ /* This file is part of the kcal library. Copyright (c) 2001-2003 Cornelius Schumacher This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** @file This file is part of the API for handling calendar data and defines the Todo class. @brief Provides a To-do in the sense of RFC2445. @author Cornelius Schumacher \ */ #include "todo.h" #include "incidenceformatter.h" #include #include #include #include using namespace KCal; /** Private class that helps to provide binary compatibility between releases. @internal */ //@cond PRIVATE class KCal::Todo::Private { public: Private() : mPercentComplete( 0 ), mHasDueDate( false ), mHasStartDate( false ), mHasCompletedDate( false ) {} Private( const KCal::Todo::Private &other ) { init( other ); } void init( const KCal::Todo::Private &other ); KDateTime mDtDue; // to-do due date (if there is one) // ALSO the first occurrence of a recurring to-do KDateTime mDtRecurrence; // next occurrence (for recurring to-dos) KDateTime mCompleted; // to-do completion date (if it has been completed) int mPercentComplete; // to-do percent complete [0,100] bool mHasDueDate; // true if the to-do has a due date bool mHasStartDate; // true if the to-do has a starting date bool mHasCompletedDate; // true if the to-do has a completion date /** Returns true if the todo got a new date, else false will be returned. */ bool recurTodo( Todo *todo ); }; void KCal::Todo::Private::init( const KCal::Todo::Private &other ) { mDtDue = other.mDtDue; mDtRecurrence = other.mDtRecurrence; mCompleted = other.mCompleted; mPercentComplete = other.mPercentComplete; mHasDueDate = other.mHasDueDate; mHasStartDate = other.mHasStartDate; mHasCompletedDate = other.mHasCompletedDate; } //@endcond Todo::Todo() : d( new KCal::Todo::Private ) { } Todo::Todo( const Todo &other ) : Incidence( other ), d( new KCal::Todo::Private( *other.d ) ) { } Todo::~Todo() { delete d; } Todo *Todo::clone() { return new Todo( *this ); } Todo &Todo::operator=( const Todo &other ) { // check for self assignment if ( &other == this ) { return *this; } Incidence::operator=( other ); d->init( *other.d ); return *this; } bool Todo::operator==( const Todo &todo ) const { return - static_cast( *this ) == static_cast( todo ) && + Incidence::operator==( todo ) && dtDue() == todo.dtDue() && hasDueDate() == todo.hasDueDate() && hasStartDate() == todo.hasStartDate() && completed() == todo.completed() && hasCompletedDate() == todo.hasCompletedDate() && percentComplete() == todo.percentComplete(); } QByteArray Todo::type() const { return "Todo"; } void Todo::setDtDue( const KDateTime &dtDue, bool first ) { //int diffsecs = d->mDtDue.secsTo(dtDue); /*if (mReadOnly) return; const Alarm::List& alarms = alarms(); for (Alarm *alarm = alarms.first(); alarm; alarm = alarms.next()) { if (alarm->enabled()) { alarm->setTime(alarm->time().addSecs(diffsecs)); } }*/ if ( recurs() && !first ) { d->mDtRecurrence = dtDue; } else { d->mDtDue = dtDue; // TODO: This doesn't seem right... recurrence()->setStartDateTime( dtDue ); recurrence()->setAllDay( allDay() ); } if ( recurs() && dtDue < recurrence()->startDateTime() ) { setDtStart( dtDue ); } /*const Alarm::List& alarms = alarms(); for (Alarm *alarm = alarms.first(); alarm; alarm = alarms.next()) alarm->setAlarmStart(d->mDtDue);*/ updated(); } KDateTime Todo::dtDue( bool first ) const { if ( !hasDueDate() ) { return KDateTime(); } if ( recurs() && !first && d->mDtRecurrence.isValid() ) { return d->mDtRecurrence; } return d->mDtDue; } QString Todo::dtDueTimeStr( bool shortfmt, const KDateTime::Spec &spec ) const { if ( spec.isValid() ) { QString timeZone; if ( spec.timeZone() != KSystemTimeZones::local() ) { timeZone = ' ' + spec.timeZone().name(); } return KGlobal::locale()->formatTime( dtDue( !recurs() ).toTimeSpec( spec ).time(), !shortfmt ) + timeZone; } else { return KGlobal::locale()->formatTime( dtDue( !recurs() ).time(), !shortfmt ); } } QString Todo::dtDueDateStr( bool shortfmt, const KDateTime::Spec &spec ) const { if ( spec.isValid() ) { QString timeZone; if ( spec.timeZone() != KSystemTimeZones::local() ) { timeZone = ' ' + spec.timeZone().name(); } return KGlobal::locale()->formatDate( dtDue( !recurs() ).toTimeSpec( spec ).date(), ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ) + timeZone; } else { return KGlobal::locale()->formatDate( dtDue( !recurs() ).date(), ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ); } } QString Todo::dtDueStr( bool shortfmt, const KDateTime::Spec &spec ) const { if ( allDay() ) { return IncidenceFormatter::dateToString( dtDue(), shortfmt, spec ); } if ( spec.isValid() ) { QString timeZone; if ( spec.timeZone() != KSystemTimeZones::local() ) { timeZone = ' ' + spec.timeZone().name(); } return KGlobal::locale()->formatDateTime( dtDue( !recurs() ).toTimeSpec( spec ).dateTime(), ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ) + timeZone; } else { return KGlobal::locale()->formatDateTime( dtDue( !recurs() ).dateTime(), ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ); } } bool Todo::hasDueDate() const { return d->mHasDueDate; } void Todo::setHasDueDate( bool f ) { if ( mReadOnly ) { return; } d->mHasDueDate = f; updated(); } bool Todo::hasStartDate() const { return d->mHasStartDate; } void Todo::setHasStartDate( bool f ) { if ( mReadOnly ) { return; } if ( recurs() && !f ) { if ( !comments().filter( "NoStartDate" ).count() ) { addComment( "NoStartDate" ); //TODO: --> custom flag? } } else { QString s( "NoStartDate" ); removeComment( s ); } d->mHasStartDate = f; updated(); } KDateTime Todo::dtStart() const { return dtStart( false ); } KDateTime Todo::dtStart( bool first ) const { if ( !hasStartDate() ) { return KDateTime(); } if ( recurs() && !first ) { return d->mDtRecurrence.addDays( dtDue( true ).daysTo( IncidenceBase::dtStart() ) ); } else { return IncidenceBase::dtStart(); } } void Todo::setDtStart( const KDateTime &dtStart ) { // TODO: This doesn't seem right (rfc 2445/6 says, recurrence is calculated from the dtstart...) if ( recurs() ) { recurrence()->setStartDateTime( d->mDtDue ); recurrence()->setAllDay( allDay() ); } IncidenceBase::setDtStart( dtStart ); } QString Todo::dtStartTimeStr( bool shortfmt, bool first, const KDateTime::Spec &spec ) const { if ( spec.isValid() ) { QString timeZone; if ( spec.timeZone() != KSystemTimeZones::local() ) { timeZone = ' ' + spec.timeZone().name(); } return KGlobal::locale()->formatTime( dtStart( first ).toTimeSpec( spec ).time(), !shortfmt ) + timeZone; } else { return KGlobal::locale()->formatTime( dtStart( first ).time(), !shortfmt ); } } QString Todo::dtStartTimeStr( bool shortfmt, const KDateTime::Spec &spec ) const { return IncidenceFormatter::timeToString( dtStart(), shortfmt, spec ); } QString Todo::dtStartDateStr( bool shortfmt, bool first, const KDateTime::Spec &spec ) const { if ( spec.isValid() ) { QString timeZone; if ( spec.timeZone() != KSystemTimeZones::local() ) { timeZone = ' ' + spec.timeZone().name(); } return KGlobal::locale()->formatDate( dtStart( first ).toTimeSpec( spec ).date(), ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ) + timeZone; } else { return KGlobal::locale()->formatDate( dtStart( first ).date(), ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ); } } QString Todo::dtStartDateStr( bool shortfmt, const KDateTime::Spec &spec ) const { return IncidenceFormatter::dateToString( dtStart(), shortfmt, spec ); } QString Todo::dtStartStr( bool shortfmt, bool first, const KDateTime::Spec &spec ) const { if ( allDay() ) { return IncidenceFormatter::dateToString( dtStart(), shortfmt, spec ); } if ( spec.isValid() ) { QString timeZone; if ( spec.timeZone() != KSystemTimeZones::local() ) { timeZone = ' ' + spec.timeZone().name(); } return KGlobal::locale()->formatDateTime( dtStart( first ).toTimeSpec( spec ).dateTime(), ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ) + timeZone; } else { return KGlobal::locale()->formatDateTime( dtStart( first ).dateTime(), ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ); } } QString Todo::dtStartStr( bool shortfmt, const KDateTime::Spec &spec ) const { if ( allDay() ) { return IncidenceFormatter::dateToString( dtStart(), shortfmt, spec ); } if ( spec.isValid() ) { QString timeZone; if ( spec.timeZone() != KSystemTimeZones::local() ) { timeZone = ' ' + spec.timeZone().name(); } return KGlobal::locale()->formatDateTime( dtStart().toTimeSpec( spec ).dateTime(), ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ) + timeZone; } else { return KGlobal::locale()->formatDateTime( dtStart().dateTime(), ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ); } } bool Todo::isCompleted() const { if ( d->mPercentComplete == 100 ) { return true; } else { return false; } } void Todo::setCompleted( bool completed ) { if ( completed ) { d->mPercentComplete = 100; } else { d->mPercentComplete = 0; d->mHasCompletedDate = false; d->mCompleted = KDateTime(); } updated(); } KDateTime Todo::completed() const { if ( hasCompletedDate() ) { return d->mCompleted; } else { return KDateTime(); } } QString Todo::completedStr( bool shortfmt ) const { return KGlobal::locale()->formatDateTime( d->mCompleted.dateTime(), ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ); } void Todo::setCompleted( const KDateTime &completed ) { if ( !d->recurTodo( this ) ) { d->mHasCompletedDate = true; d->mPercentComplete = 100; d->mCompleted = completed.toUtc(); } updated(); } bool Todo::hasCompletedDate() const { return d->mHasCompletedDate; } int Todo::percentComplete() const { return d->mPercentComplete; } void Todo::setPercentComplete( int percent ) { //TODO: (?) assert percent between 0 and 100, inclusive d->mPercentComplete = percent; if ( percent != 100 ) { d->mHasCompletedDate = false; } updated(); } void Todo::shiftTimes( const KDateTime::Spec &oldSpec, const KDateTime::Spec &newSpec ) { Incidence::shiftTimes( oldSpec, newSpec ); d->mDtDue = d->mDtDue.toTimeSpec( oldSpec ); d->mDtDue.setTimeSpec( newSpec ); if ( recurs() ) { d->mDtRecurrence = d->mDtRecurrence.toTimeSpec( oldSpec ); d->mDtRecurrence.setTimeSpec( newSpec ); } if ( d->mHasCompletedDate ) { d->mCompleted = d->mCompleted.toTimeSpec( oldSpec ); d->mCompleted.setTimeSpec( newSpec ); } } void Todo::setDtRecurrence( const KDateTime &dt ) { d->mDtRecurrence = dt; } KDateTime Todo::dtRecurrence() const { return d->mDtRecurrence.isValid() ? d->mDtRecurrence : d->mDtDue; } bool Todo::recursOn( const QDate &date, const KDateTime::Spec &timeSpec ) const { QDate today = QDate::currentDate(); return Incidence::recursOn( date, timeSpec ) && !( date < today && d->mDtRecurrence.date() < today && d->mDtRecurrence > recurrence()->startDateTime() ); } bool Todo::isOverdue() const { if ( !dtDue().isValid() ) { return false; // if it's never due, it can't be overdue } bool inPast = allDay() ? dtDue().date() < QDate::currentDate() : dtDue() < KDateTime::currentUtcDateTime(); return inPast && !isCompleted(); } KDateTime Todo::endDateRecurrenceBase() const { return dtDue(); } //@cond PRIVATE bool Todo::Private::recurTodo( Todo *todo ) { if ( todo->recurs() ) { Recurrence *r = todo->recurrence(); KDateTime endDateTime = r->endDateTime(); KDateTime nextDate = r->getNextDateTime( todo->dtDue() ); if ( ( r->duration() == -1 || ( nextDate.isValid() && endDateTime.isValid() && nextDate <= endDateTime ) ) ) { while ( !todo->recursAt( nextDate ) || nextDate <= KDateTime::currentUtcDateTime() ) { if ( !nextDate.isValid() || ( nextDate > endDateTime && r->duration() != -1 ) ) { return false; } nextDate = r->getNextDateTime( nextDate ); } todo->setDtDue( nextDate ); todo->setCompleted( false ); todo->setRevision( todo->revision() + 1 ); return true; } } return false; } //@endcond