diff --git a/kcal/event.cpp b/kcal/event.cpp index 78c57a5a3..d20adb3b5 100644 --- a/kcal/event.cpp +++ b/kcal/event.cpp @@ -1,273 +1,273 @@ /* 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 #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 ) { Incidence::operator=( other ); *d = *other.d; return *this; } bool Event::operator==( const Event &event ) const { return static_cast( *this ) == static_cast( 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 ) + return KGlobal::locale()->formatTime( dtEnd().toTimeSpec( spec ).time(), !shortfmt ) + timeZone; } else { - return KGlobal::locale()->formatTime( dtEnd().time(), shortfmt ); + 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 dtEndDateStr( 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/incidencebase.cpp b/kcal/incidencebase.cpp index e37a4ea92..33bd6ea59 100644 --- a/kcal/incidencebase.cpp +++ b/kcal/incidencebase.cpp @@ -1,526 +1,526 @@ /* This file is part of the kcal library. Copyright (c) 2001,2004 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 IncidenceBase class. @brief An abstract base class that provides a common base for all calendar incidence classes. @author Cornelius Schumacher \ @author Reinhold Kainhofer \ */ #include "incidencebase.h" #include "calformat.h" #include #include #include #include #include #include using namespace KCal; /** Private class that helps to provide binary compatibility between releases. @internal */ //@cond PRIVATE class KCal::IncidenceBase::Private { public: Private() : mUpdateGroupLevel( 0 ), mUpdatedPending( false ), mAllDay( true ), mHasDuration( false ) { mAttendees.setAutoDelete( true ); } Private( const Private &other ) : mUpdateGroupLevel( 0 ), mUpdatedPending( false ), mAllDay( true ), mHasDuration( false ) { mAttendees.setAutoDelete( true ); init( other ); } void init( const Private &other ); KDateTime mLastModified; // incidence last modified date KDateTime mDtStart; // incidence start time Person mOrganizer; // incidence person (owner) QString mUid; // incidence unique id Duration mDuration; // incidence duration int mUpdateGroupLevel; // if non-zero, suppresses update() calls bool mUpdatedPending; // true if an update has occurred since startUpdates() bool mAllDay; // true if the incidence is all-day bool mHasDuration; // true if the incidence has a duration Attendee::List mAttendees; // list of incidence attendees QStringList mComments; // list of incidence comments QList mObservers; // list of incidence observers }; void IncidenceBase::Private::init( const Private &other ) { mLastModified = other.mLastModified; mDtStart = other.mDtStart; mOrganizer = other.mOrganizer; mUid = other.mUid; mDuration = other.mDuration; mAllDay = other.mAllDay; mHasDuration = other.mHasDuration; mComments = other.mComments; mAttendees.clearAll(); Attendee::List::ConstIterator it; for ( it = other.mAttendees.begin(); it != other.mAttendees.end(); ++it ) { mAttendees.append( new Attendee( *(*it) ) ); } } //@endcond IncidenceBase::IncidenceBase() : d( new KCal::IncidenceBase::Private ) { mReadOnly = false; setUid( CalFormat::createUniqueId() ); } IncidenceBase::IncidenceBase( const IncidenceBase &i ) : CustomProperties( i ), d( new KCal::IncidenceBase::Private( *i.d ) ) { mReadOnly = i.mReadOnly; } IncidenceBase::~IncidenceBase() { delete d; } IncidenceBase &IncidenceBase::operator=( const IncidenceBase &other ) { CustomProperties::operator=( other ); d->init( *other.d ); mReadOnly = other.mReadOnly; return *this; } bool IncidenceBase::operator==( const IncidenceBase &i2 ) const { if ( attendees().count() != i2.attendees().count() ) { return false; // no need to check further } Attendee::List al1 = attendees(); Attendee::List al2 = i2.attendees(); Attendee::List::ConstIterator a1 = al1.constBegin(); Attendee::List::ConstIterator a2 = al2.constBegin(); //TODO Does the order of attendees in the list really matter? //Please delete this comment if you know it's ok, kthx for ( ; a1 != al1.constEnd() && a2 != al2.constEnd(); ++a1, ++a2 ) { if ( !( **a1 == **a2 ) ) { return false; } } if ( !CustomProperties::operator == (i2) ) { return false; } return dtStart() == i2.dtStart() && organizer() == i2.organizer() && uid() == i2.uid() && // Don't compare lastModified, otherwise the operator is not // of much use. We are not comparing for identity, after all. allDay() == i2.allDay() && duration() == i2.duration() && hasDuration() == i2.hasDuration(); // no need to compare mObserver } void IncidenceBase::setUid( const QString &uid ) { d->mUid = uid; updated(); } QString IncidenceBase::uid() const { return d->mUid; } void IncidenceBase::setLastModified( const KDateTime &lm ) { // DON'T! updated() because we call this from // Calendar::updateEvent(). // Convert to UTC and remove milliseconds part. KDateTime current = lm.toUtc(); QTime t = current.time(); t.setHMS( t.hour(), t.minute(), t.second(), 0 ); current.setTime( t ); d->mLastModified = current; } KDateTime IncidenceBase::lastModified() const { return d->mLastModified; } void IncidenceBase::setOrganizer( const Person &o ) { // we don't check for readonly here, because it is // possible that by setting the organizer we are changing // the event's readonly status... d->mOrganizer = o; updated(); } void IncidenceBase::setOrganizer( const QString &o ) { QString mail( o ); if ( mail.startsWith( QLatin1String( "MAILTO:" ), Qt::CaseInsensitive ) ) { mail = mail.remove( 0, 7 ); } // split the string into full name plus email. const Person organizer = Person::fromFullName( mail ); setOrganizer( organizer ); } Person IncidenceBase::organizer() const { return d->mOrganizer; } void IncidenceBase::setReadOnly( bool readOnly ) { mReadOnly = readOnly; } void IncidenceBase::setDtStart( const KDateTime &dtStart ) { // if ( mReadOnly ) return; d->mDtStart = dtStart; d->mAllDay = dtStart.isDateOnly(); updated(); } KDateTime IncidenceBase::dtStart() const { return d->mDtStart; } QString IncidenceBase::dtStartTimeStr( 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( dtStart().toTimeSpec( spec ).time(), shortfmt ) + return KGlobal::locale()->formatTime( dtStart().toTimeSpec( spec ).time(), !shortfmt ) + timeZone; } else { - return KGlobal::locale()->formatTime( dtStart().time(), shortfmt ); + return KGlobal::locale()->formatTime( dtStart().time(), !shortfmt ); } } QString IncidenceBase::dtStartDateStr( 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( dtStart().toTimeSpec( spec ).date(), ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ) + timeZone; } else { return KGlobal::locale()->formatDate( dtStart().date(), ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ); } } QString IncidenceBase::dtStartStr( bool shortfmt, const KDateTime::Spec &spec ) const { if ( allDay() ) { return dtStartDateStr( 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 IncidenceBase::allDay() const { return d->mAllDay; } void IncidenceBase::setAllDay( bool f ) { if ( mReadOnly || f == d->mAllDay ) { return; } d->mAllDay = f; updated(); } void IncidenceBase::shiftTimes( const KDateTime::Spec &oldSpec, const KDateTime::Spec &newSpec ) { d->mDtStart = d->mDtStart.toTimeSpec( oldSpec ); d->mDtStart.setTimeSpec( newSpec ); updated(); } void IncidenceBase::addComment( const QString &comment ) { d->mComments += comment; } bool IncidenceBase::removeComment( const QString &comment ) { bool found = false; QStringList::Iterator i; for ( i = d->mComments.begin(); !found && i != d->mComments.end(); ++i ) { if ( (*i) == comment ) { found = true; d->mComments.erase( i ); } } return found; } void IncidenceBase::clearComments() { d->mComments.clear(); } QStringList IncidenceBase::comments() const { return d->mComments; } void IncidenceBase::addAttendee( Attendee *a, bool doupdate ) { if ( !a || mReadOnly ) { return; } if ( a->name().left(7).toUpper() == "MAILTO:" ) { a->setName( a->name().remove( 0, 7 ) ); } d->mAttendees.append( a ); if ( doupdate ) { updated(); } } const Attendee::List &IncidenceBase::attendees() const { return d->mAttendees; } int IncidenceBase::attendeeCount() const { return d->mAttendees.count(); } void IncidenceBase::clearAttendees() { if ( mReadOnly ) { return; } qDeleteAll( d->mAttendees ); d->mAttendees.clear(); } Attendee *IncidenceBase::attendeeByMail( const QString &email ) const { Attendee::List::ConstIterator it; for ( it = d->mAttendees.constBegin(); it != d->mAttendees.constEnd(); ++it ) { if ( (*it)->email() == email ) { return *it; } } return 0; } Attendee *IncidenceBase::attendeeByMails( const QStringList &emails, const QString &email ) const { QStringList mails = emails; if ( !email.isEmpty() ) { mails.append( email ); } Attendee::List::ConstIterator itA; for ( itA = d->mAttendees.constBegin(); itA != d->mAttendees.constEnd(); ++itA ) { for ( QStringList::const_iterator it = mails.constBegin(); it != mails.constEnd(); ++it ) { if ( (*itA)->email() == (*it) ) { return *itA; } } } return 0; } Attendee *IncidenceBase::attendeeByUid( const QString &uid ) const { Attendee::List::ConstIterator it; for ( it = d->mAttendees.constBegin(); it != d->mAttendees.constEnd(); ++it ) { if ( (*it)->uid() == uid ) { return *it; } } return 0; } void IncidenceBase::setDuration( const Duration &duration ) { d->mDuration = duration; setHasDuration( true ); updated(); } Duration IncidenceBase::duration() const { return d->mDuration; } void IncidenceBase::setHasDuration( bool hasDuration ) { d->mHasDuration = hasDuration; } bool IncidenceBase::hasDuration() const { return d->mHasDuration; } void IncidenceBase::registerObserver( IncidenceBase::IncidenceObserver *observer ) { if ( !d->mObservers.contains( observer ) ) { d->mObservers.append( observer ); } } void IncidenceBase::unRegisterObserver( IncidenceBase::IncidenceObserver *observer ) { d->mObservers.removeAll( observer ); } void IncidenceBase::updated() { if ( d->mUpdateGroupLevel ) { d->mUpdatedPending = true; } else { foreach ( IncidenceObserver *o, d->mObservers ) { o->incidenceUpdated( this ); } } } void IncidenceBase::startUpdates() { ++d->mUpdateGroupLevel; } void IncidenceBase::endUpdates() { if ( d->mUpdateGroupLevel > 0 ) { if ( --d->mUpdateGroupLevel == 0 && d->mUpdatedPending ) { d->mUpdatedPending = false; updated(); } } } void IncidenceBase::customPropertyUpdated() { updated(); } KUrl IncidenceBase::uri() const { return KUrl( QString( "urn:x-ical:" ) + uid() ); } bool IncidenceBase::Visitor::visit( Event *event ) { Q_UNUSED( event ); return false; } bool IncidenceBase::Visitor::visit( Todo *todo ) { Q_UNUSED( todo ); return false; } bool IncidenceBase::Visitor::visit( Journal *journal ) { Q_UNUSED( journal ); return false; } bool IncidenceBase::Visitor::visit( FreeBusy *freebusy ) { Q_UNUSED( freebusy ); return false; } diff --git a/kcal/todo.cpp b/kcal/todo.cpp index d6c8b874c..eb4162f48 100644 --- a/kcal/todo.cpp +++ b/kcal/todo.cpp @@ -1,528 +1,528 @@ /* 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 #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 ) { Incidence::operator=( other ); d->init( *other.d ); return *this; } bool Todo::operator==( const Todo &todo ) const { return static_cast( *this ) == static_cast( 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 ); } //kDebug() << "setDtDue says date is" << d->mDtDue.toString(); /*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 ) + return KGlobal::locale()->formatTime( dtDue( !recurs() ).toTimeSpec( spec ).time(), !shortfmt ) + timeZone; } else { - return KGlobal::locale()->formatTime( dtDue( !recurs() ).time(), shortfmt ); + 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 dtDueDateStr( 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( first ).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 ) + return KGlobal::locale()->formatTime( dtStart( first ).toTimeSpec( spec ).time(), !shortfmt ) + timeZone; } else { - return KGlobal::locale()->formatTime( dtStart( first ).time(), shortfmt ); + return KGlobal::locale()->formatTime( dtStart( first ).time(), !shortfmt ); } } QString Todo::dtStartTimeStr( bool shortfmt, const KDateTime::Spec &spec ) const { return Incidence::dtStartTimeStr( 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 Incidence::dtStartDateStr( shortfmt, spec ); } QString Todo::dtStartStr( bool shortfmt, bool first, const KDateTime::Spec &spec ) const { if ( allDay() ) { return dtStartDateStr( 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 { return Incidence::dtStartStr( shortfmt, spec ); } 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 ) { return false; } nextDate = r->getNextDateTime( nextDate ); } todo->setDtDue( nextDate ); todo->setCompleted( false ); todo->setRevision( todo->revision() + 1 ); return true; } } return false; } //@endcond