diff --git a/kcal/attendee.cpp b/kcal/attendee.cpp index dff38f584..00270e550 100644 --- a/kcal/attendee.cpp +++ b/kcal/attendee.cpp @@ -1,241 +1,246 @@ /* 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 Attendee class. @brief Represents information related to an attendee of an Calendar Incidence. @author Cornelius Schumacher \ */ #include "attendee.h" #include #include #include using namespace KCal; /** Private class that helps to provide binary compatibility between releases. @internal */ //@cond PRIVATE class KCal::Attendee::Private { public: bool mRSVP; Role mRole; PartStat mStatus; QString mUid; QString mDelegate; QString mDelegator; }; //@endcond Attendee::Attendee( const QString &name, const QString &email, bool rsvp, Attendee::PartStat s, Attendee::Role r, const QString &u ) : d( new KCal::Attendee::Private ) { setName( name ); setEmail( email ); d->mRSVP = rsvp; d->mStatus = s; d->mRole = r; d->mUid = u; } Attendee::Attendee( const Attendee &attendee ) : Person( attendee ), d( new KCal::Attendee::Private( *attendee.d ) ) { } Attendee::~Attendee() { delete d; } bool KCal::Attendee::operator==( const Attendee &attendee ) { return ( Person & )*this == ( const Person & )attendee && d->mRSVP == attendee.d->mRSVP && d->mRole == attendee.d->mRole && d->mStatus == attendee.d->mStatus && d->mUid == attendee.d->mUid && d->mDelegate == attendee.d->mDelegate && d->mDelegator == attendee.d->mDelegator; } Attendee &KCal::Attendee::operator=( const Attendee &attendee ) { + // check for self assignment + if ( &attendee == this ) { + return *this; + } + *d = *attendee.d; setName( attendee.name() ); setEmail( attendee.email() ); return *this; } void Attendee::setRSVP( bool r ) { d->mRSVP = r; } bool Attendee::RSVP() const { return d->mRSVP; } void Attendee::setStatus( Attendee::PartStat s ) { d->mStatus = s; } Attendee::PartStat Attendee::status() const { return d->mStatus; } QString Attendee::statusStr() const { return statusName( d->mStatus ); } QString Attendee::statusName( Attendee::PartStat status ) { switch ( status ) { default: case NeedsAction: return i18nc( "@item event, to-do or journal needs action", "Needs Action" ); break; case Accepted: return i18nc( "@item event, to-do or journal accepted", "Accepted" ); break; case Declined: return i18nc( "@item event, to-do or journal declined", "Declined" ); break; case Tentative: return i18nc( "@item event or to-do tentatively accepted", "Tentative" ); break; case Delegated: return i18nc( "@item event or to-do delegated", "Delegated" ); break; case Completed: return i18nc( "@item to-do completed", "Completed" ); break; case InProcess: return i18nc( "@item to-do in process of being completed", "In Process" ); break; } } QStringList Attendee::statusList() { QStringList list; list << statusName( NeedsAction ); list << statusName( Accepted ); list << statusName( Declined ); list << statusName( Tentative ); list << statusName( Delegated ); list << statusName( Completed ); list << statusName( InProcess ); return list; } void Attendee::setRole( Attendee::Role r ) { d->mRole = r; } Attendee::Role Attendee::role() const { return d->mRole; } QString Attendee::roleStr() const { return roleName( d->mRole ); } void Attendee::setUid( const QString &uid ) { d->mUid = uid; } QString Attendee::uid() const { return d->mUid; } QString Attendee::roleName( Attendee::Role role ) { switch ( role ) { case Chair: return i18nc( "@item chairperson", "Chair" ); break; default: case ReqParticipant: return i18nc( "@item participation is required", "Participant" ); break; case OptParticipant: return i18nc( "@item participation is optional", "Optional Participant" ); break; case NonParticipant: return i18nc( "@item non-participant copied for information", "Observer" ); break; } } QStringList Attendee::roleList() { QStringList list; list << roleName( ReqParticipant ); list << roleName( OptParticipant ); list << roleName( NonParticipant ); list << roleName( Chair ); return list; } void Attendee::setDelegate( const QString &delegate ) { d->mDelegate = delegate; } QString Attendee::delegate() const { return d->mDelegate; } void Attendee::setDelegator( const QString &delegator ) { d->mDelegator = delegator; } QString Attendee::delegator() const { return d->mDelegator; } diff --git a/kcal/customproperties.cpp b/kcal/customproperties.cpp index bd2bfb813..61ebc7641 100644 --- a/kcal/customproperties.cpp +++ b/kcal/customproperties.cpp @@ -1,185 +1,190 @@ /* 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. @brief A class to manage custom calendar properties. @author David Jarvie \ */ #include "customproperties.h" #include #include using namespace KCal; //@cond PRIVATE static bool checkName( const QByteArray &name ); class CustomProperties::Private { public: bool operator==( const Private &other ) const; QMap mProperties; // custom calendar properties }; bool CustomProperties::Private::operator==( const CustomProperties::Private &other ) const { if ( mProperties.count() != other.mProperties.count() ) { return false; } for ( QMap::ConstIterator it = mProperties.begin(); it != mProperties.end(); ++it ) { QMap::ConstIterator itOther = other.mProperties.find( it.key() ); if ( itOther == other.mProperties.end() || itOther.value() != it.value() ) { return false; } } return true; } //@endcond CustomProperties::CustomProperties() : d( new Private ) { } CustomProperties::CustomProperties( const CustomProperties &cp ) : d( new Private( *cp.d ) ) { } CustomProperties &CustomProperties::operator=( const CustomProperties &other ) { + // check for self assignment + if ( &other == this ) { + return *this; + } + *d = *other.d; return *this; } CustomProperties::~CustomProperties() { delete d; } bool CustomProperties::operator==( const CustomProperties &other ) const { return *d == *other.d; } void CustomProperties::setCustomProperty( const QByteArray &app, const QByteArray &key, const QString &value ) { if ( value.isNull() || key.isEmpty() || app.isEmpty() ) { return; } QByteArray property = "X-KDE-" + app + '-' + key; if ( !checkName( property ) ) { return; } d->mProperties[property] = value; customPropertyUpdated(); } void CustomProperties::removeCustomProperty( const QByteArray &app, const QByteArray &key ) { removeNonKDECustomProperty( QByteArray( "X-KDE-" + app + '-' + key ) ); } QString CustomProperties::customProperty( const QByteArray &app, const QByteArray &key ) const { return nonKDECustomProperty( QByteArray( "X-KDE-" + app + '-' + key ) ); } void CustomProperties::setNonKDECustomProperty( const QByteArray &name, const QString &value ) { if ( value.isNull() || !checkName( name ) ) { return; } d->mProperties[name] = value; customPropertyUpdated(); } void CustomProperties::removeNonKDECustomProperty( const QByteArray &name ) { QMap::Iterator it = d->mProperties.find( name ); if ( it != d->mProperties.end() ) { d->mProperties.erase( it ); customPropertyUpdated(); } } QString CustomProperties::nonKDECustomProperty( const QByteArray &name ) const { QMap::ConstIterator it = d->mProperties.constFind( name ); if ( it == d->mProperties.constEnd() ) { return QString(); } return it.value(); } void CustomProperties::setCustomProperties( const QMap &properties ) { bool changed = false; for ( QMap::ConstIterator it = properties.begin(); it != properties.end(); ++it ) { // Validate the property name and convert any null string to empty string if ( checkName( it.key() ) ) { d->mProperties[it.key()] = it.value().isNull() ? QString( "" ) : it.value(); changed = true; } } if ( changed ) { customPropertyUpdated(); } } QMap CustomProperties::customProperties() const { return d->mProperties; } //@cond PRIVATE bool checkName( const QByteArray &name ) { // Check that the property name starts with 'X-' and contains // only the permitted characters const char *n = name; int len = name.length(); if ( len < 2 || n[0] != 'X' || n[1] != '-' ) { return false; } for ( int i = 2; i < len; ++i ) { char ch = n[i]; if ( ( ch >= 'A' && ch <= 'Z' ) || ( ch >= 'a' && ch <= 'z' ) || ( ch >= '0' && ch <= '9' ) || ch == '-' ) { continue; } return false; // invalid character found } return true; } //@endcond diff --git a/kcal/duration.cpp b/kcal/duration.cpp index 25881ab11..487d3fb81 100644 --- a/kcal/duration.cpp +++ b/kcal/duration.cpp @@ -1,204 +1,209 @@ /* This file is part of the kcal library. Copyright (c) 2001 Cornelius Schumacher Copyright (c) 2007 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 Duration class. @brief Represents a span of time measured in seconds. @author Cornelius Schumacher \ @author David Jarvie \ */ #include "duration.h" #include using namespace KCal; /** Private class that helps to provide binary compatibility between releases. @internal */ //@cond PRIVATE class KCal::Duration::Private { public: int seconds() const { return mDaily ? mDuration * 86400 : mDuration; } int mDuration; // number of seconds or days in the duration bool mDaily; // specified in terms of days rather than seconds }; //@endcond Duration::Duration() : d( new KCal::Duration::Private() ) { } Duration::Duration( const KDateTime &start, const KDateTime &end ) : d( new KCal::Duration::Private() ) { if ( start.time() == end.time() && start.timeSpec() == end.timeSpec() ) { d->mDuration = start.daysTo( end ); d->mDaily = true; } else { d->mDuration = start.secsTo( end ); d->mDaily = false; } } Duration::Duration( const KDateTime &start, const KDateTime &end, Type type ) : d( new KCal::Duration::Private() ) { if ( type == Days ) { KDateTime endSt( end.toTimeSpec( start ) ); d->mDuration = start.daysTo( endSt ); if ( d->mDuration ) { // Round down to whole number of days if necessary if ( start < endSt ) { if ( endSt.time() < start.time() ) { --d->mDuration; } } else { if ( endSt.time() > start.time() ) { ++d->mDuration; } } } d->mDaily = true; } else { d->mDuration = start.secsTo( end ); d->mDaily = false; } } Duration::Duration( int duration, Type type ) : d( new KCal::Duration::Private() ) { d->mDuration = duration; d->mDaily = ( type == Days ); } Duration::Duration( const Duration &duration ) : d( new KCal::Duration::Private( *duration.d ) ) { } Duration::~Duration() { delete d; } Duration &Duration::operator=( const Duration &duration ) { + // check for self assignment + if ( &duration == this ) { + return *this; + } + *d = *duration.d; return *this; } Duration::operator bool() const { return d->mDuration; } bool Duration::operator<( const Duration &other ) const { if ( d->mDaily == other.d->mDaily ) { // guard against integer overflow for two daily durations return d->mDuration < other.d->mDuration; } return d->seconds() < other.d->seconds(); } bool Duration::operator==( const Duration &other ) const { return d->mDuration == other.d->mDuration && d->mDaily == other.d->mDaily; } Duration &Duration::operator+=( const Duration &other ) { if ( d->mDaily == other.d->mDaily ) { d->mDuration += other.d->mDuration; } else if ( d->mDaily ) { d->mDuration = d->mDuration * 86400 + other.d->mDuration; d->mDaily = false; } else { d->mDuration += other.d->mDuration + 86400; } return *this; } Duration Duration::operator-() const { return Duration( -d->mDuration, ( d->mDaily ? Days : Seconds ) ); } Duration &Duration::operator-=( const Duration &duration ) { return operator+=( -duration ); } Duration &Duration::operator*=( int value ) { d->mDuration *= value; return *this; } Duration &Duration::operator/=( int value ) { d->mDuration /= value; return *this; } KDateTime Duration::end( const KDateTime &start ) const { return d->mDaily ? start.addDays( d->mDuration ) : start.addSecs( d->mDuration ); } Duration::Type Duration::type() const { return d->mDaily ? Days : Seconds; } bool Duration::isDaily() const { return d->mDaily; } int Duration::asSeconds() const { return d->seconds(); } int Duration::asDays() const { return d->mDaily ? d->mDuration : d->mDuration / 86400; } int Duration::value() const { return d->mDuration; } diff --git a/kcal/event.cpp b/kcal/event.cpp index d20adb3b5..44e5b6efe 100644 --- a/kcal/event.cpp +++ b/kcal/event.cpp @@ -1,273 +1,278 @@ /* 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 ) { + // 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 ) && 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 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/freebusy.cpp b/kcal/freebusy.cpp index 4bd8d1f0d..cfae55244 100644 --- a/kcal/freebusy.cpp +++ b/kcal/freebusy.cpp @@ -1,357 +1,362 @@ /* 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 ) { IncidenceBase::shiftTimes( oldSpec, newSpec ); d->mDtEnd = d->mDtEnd.toTimeSpec( oldSpec ); d->mDtEnd.setTimeSpec( newSpec ); for ( int i = 0, end = d->mBusyPeriods.count(); i < end; ++end ) { d->mBusyPeriods[i].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 ) && 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/freebusyperiod.cpp b/kcal/freebusyperiod.cpp index 6a5433a92..2441ebb1d 100644 --- a/kcal/freebusyperiod.cpp +++ b/kcal/freebusyperiod.cpp @@ -1,105 +1,110 @@ /* This file is part of the kcal library. Copyright (c) 2001 Cornelius Schumacher Copyright (c) 2007 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 FreeBusyPeriod class. @brief Represents a period of time. @author Cornelius Schumacher \ */ #include "freebusyperiod.h" #include #include using namespace KCal; //@cond PRIVATE class KCal::FreeBusyPeriod::Private { public: Private() {} QString mSummary; QString mLocation; }; //@endcond FreeBusyPeriod::FreeBusyPeriod() : Period(), d( new KCal::FreeBusyPeriod::Private() ) { } FreeBusyPeriod::FreeBusyPeriod( const KDateTime &start, const KDateTime &end ) : Period( start, end ), d( new KCal::FreeBusyPeriod::Private() ) { } FreeBusyPeriod::FreeBusyPeriod( const KDateTime &start, const Duration &duration ) : Period( start, duration ), d( new KCal::FreeBusyPeriod::Private() ) { } FreeBusyPeriod::FreeBusyPeriod( const FreeBusyPeriod &period ) : Period( period ), d( new KCal::FreeBusyPeriod::Private( *period.d ) ) { } FreeBusyPeriod::FreeBusyPeriod( const Period &period ) : Period( period ), d( new KCal::FreeBusyPeriod::Private() ) { } FreeBusyPeriod::~FreeBusyPeriod() { delete d; } FreeBusyPeriod &FreeBusyPeriod::operator=( const FreeBusyPeriod &other ) { + // check for self assignment + if ( &other == this ) { + return *this; + } + Period::operator=(other); *d = *other.d; return *this; } QString FreeBusyPeriod::summary() const { return d->mSummary; } void FreeBusyPeriod::setSummary( const QString &summary ) { d->mSummary = summary; } QString FreeBusyPeriod::location() const { return d->mLocation; } void FreeBusyPeriod::setLocation( const QString &location ) { d->mLocation = location; } diff --git a/kcal/incidencebase.cpp b/kcal/incidencebase.cpp index 33bd6ea59..12ac849ee 100644 --- a/kcal/incidencebase.cpp +++ b/kcal/incidencebase.cpp @@ -1,526 +1,531 @@ /* 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 ) { + // check for self assignment + if ( &other == this ) { + return *this; + } + 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 ) + timeZone; } else { 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/journal.cpp b/kcal/journal.cpp index 7dfe936a8..b43fd8f5e 100644 --- a/kcal/journal.cpp +++ b/kcal/journal.cpp @@ -1,65 +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 ); } diff --git a/kcal/period.cpp b/kcal/period.cpp index acb5379cc..25f194951 100644 --- a/kcal/period.cpp +++ b/kcal/period.cpp @@ -1,138 +1,143 @@ /* This file is part of the kcal library. Copyright (c) 2001 Cornelius Schumacher Copyright (c) 2007 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 Period class. @brief Represents a period of time. @author Cornelius Schumacher \ */ #include "period.h" #include #include using namespace KCal; //@cond PRIVATE class KCal::Period::Private { public: Private() : mHasDuration( false ) {} Private( const KDateTime &start, const KDateTime &end, bool hasDuration ) : mStart( start ), mEnd( end ), mHasDuration( hasDuration ) {} KDateTime mStart; // period starting date/time KDateTime mEnd; // period ending date/time bool mHasDuration; // does period have a duration? bool mDailyDuration; // duration is defined as number of days, not seconds }; //@endcond Period::Period() : d( new KCal::Period::Private() ) { } Period::Period( const KDateTime &start, const KDateTime &end ) : d( new KCal::Period::Private( start, end, false ) ) { } Period::Period( const KDateTime &start, const Duration &duration ) : d( new KCal::Period::Private( start, duration.end( start ), true ) ) { d->mDailyDuration = duration.isDaily(); } Period::Period( const Period &period ) : d( new KCal::Period::Private( *period.d ) ) { } Period::~Period() { delete d; } bool Period::operator<( const Period &other ) const { return d->mStart < other.d->mStart; } bool Period::operator==( const Period &other ) const { return d->mStart == other.d->mStart && d->mEnd == other.d->mEnd && d->mHasDuration == other.d->mHasDuration; } Period &Period::operator=( const Period &other ) { + // check for self assignment + if ( &other == this ) { + return *this; + } + *d = *other.d; return *this; } KDateTime Period::start() const { return d->mStart; } KDateTime Period::end() const { return d->mEnd; } Duration Period::duration() const { if ( d->mHasDuration ) { return Duration( d->mStart, d->mEnd, d->mDailyDuration ? Duration::Days : Duration::Seconds ); } else { return Duration( d->mStart, d->mEnd ); } } Duration Period::duration( Duration::Type type ) const { return Duration( d->mStart, d->mEnd, type ); } bool Period::hasDuration() const { return d->mHasDuration; } void Period::shiftTimes( const KDateTime::Spec &oldSpec, const KDateTime::Spec &newSpec ) { d->mStart = d->mStart.toTimeSpec( oldSpec ); d->mStart.setTimeSpec( newSpec ); d->mEnd = d->mEnd.toTimeSpec( oldSpec ); d->mEnd.setTimeSpec( newSpec ); } diff --git a/kcal/person.cpp b/kcal/person.cpp index 06f7c14d6..6d55f5ad4 100644 --- a/kcal/person.cpp +++ b/kcal/person.cpp @@ -1,157 +1,162 @@ /* This file is part of the kcal library. Copyright (c) 2001 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 Person class. @brief Represents a person, by name and email address. @author Cornelius Schumacher \ @author Reinhold Kainhofer \ */ #include "person.h" #include "kpimutils/email.h" #include #include #include using namespace KCal; /** Private class that helps to provide binary compatibility between releases. @internal */ //@cond PRIVATE class KCal::Person::Private { public: QString mName; // person name QString mEmail; // person email address }; //@endcond Person::Person() : d( new KCal::Person::Private ) { } Person::Person( const QString &fullName ) : d( new Private ) { KPIMUtils::extractEmailAddressAndName( fullName, d->mEmail, d->mName ); } Person Person::fromFullName( const QString &fullName ) { QString email, name; KPIMUtils::extractEmailAddressAndName( fullName, email, name ); return Person( name, email ); } Person::Person( const QString &name, const QString &email ) : d( new KCal::Person::Private ) { d->mName = name; d->mEmail = email; } Person::Person( const Person &person ) : d( new KCal::Person::Private( *person.d ) ) { } Person::~Person() { delete d; } bool KCal::Person::operator==( const Person &person ) { return d->mName == person.d->mName && d->mEmail == person.d->mEmail; } Person &KCal::Person::operator=( const Person &person ) { + // check for self assignment + if ( &person == this ) { + return *this; + } + *d = *person.d; return *this; } QString Person::fullName() const { if ( d->mName.isEmpty() ) { return d->mEmail; } else { if ( d->mEmail.isEmpty() ) { return d->mName; } else { // Taken from KABC::Addressee::fullEmail QString name = d->mName; QRegExp needQuotes( "[^ 0-9A-Za-z\\x0080-\\xFFFF]" ); bool weNeedToQuote = name.indexOf( needQuotes ) != -1; if ( weNeedToQuote ) { if ( name[0] != '"' ) { name.prepend( '"' ); } if ( name[ name.length()-1 ] != '"' ) { name.append( '"' ); } } return name + " <" + d->mEmail + '>'; } } } QString Person::name() const { return d->mName; } QString Person::email() const { return d->mEmail; } bool Person::isEmpty() const { return d->mEmail.isEmpty() && d->mName.isEmpty(); } void Person::setName( const QString &name ) { d->mName = name; } void Person::setEmail( const QString &email ) { if ( email.startsWith( QLatin1String( "mailto:" ), Qt::CaseInsensitive ) ) { d->mEmail = email.mid( 7 ); } else { d->mEmail = email; } } diff --git a/kcal/resourcelocal.cpp b/kcal/resourcelocal.cpp index 52f82f500..a666c5c1d 100644 --- a/kcal/resourcelocal.cpp +++ b/kcal/resourcelocal.cpp @@ -1,260 +1,265 @@ /* This file is part of the kcal library. Copyright (c) 1998 Preston Brown 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 ResourceLocal class. @author Preston Brown @author Cornelius Schumacher */ #include "resourcelocal.h" #include "resourcelocal_p.h" #include "resourcelocalconfig.h" #include "vcalformat.h" #include "icalformat.h" #include "calendarlocal.h" #include "exceptions.h" #include "incidence.h" #include "event.h" #include "todo.h" #include "journal.h" #include #include #include #include #include #include #include #include #include #include #include "resourcelocal.moc" using namespace KCal; ResourceLocal::ResourceLocal() : ResourceCached(), d( new ResourceLocal::Private() ) { d->mLock = 0; d->mURL = KUrl(); d->mFormat = new ICalFormat(); init(); } ResourceLocal::ResourceLocal( const KConfigGroup &group ) : ResourceCached( group ), d( new ResourceLocal::Private() ) { d->mLock = 0; QString url = group.readPathEntry( "CalendarURL", QString() ); d->mURL = KUrl( url ); QString format = group.readEntry( "Format" ); if ( format == "ical" ) { d->mFormat = new ICalFormat(); } else if ( format == "vcal" ) { d->mFormat = new VCalFormat(); } else { d->mFormat = new ICalFormat(); } init(); } ResourceLocal::ResourceLocal( const QString &fileName ) : ResourceCached(), d( new ResourceLocal::Private ) { d->mURL = KUrl::fromPath( fileName ); d->mFormat = new ICalFormat(); init(); } void ResourceLocal::writeConfig( KConfigGroup &group ) { kDebug(); ResourceCalendar::writeConfig( group ); group.writePathEntry( "CalendarURL", d->mURL.prettyUrl() ); if ( typeid( *d->mFormat ) == typeid( ICalFormat ) ) { group.writeEntry( "Format", "ical" ); } else if ( typeid( *d->mFormat ) == typeid( VCalFormat ) ) { group.writeEntry( "Format", "vcal" ); } else { kDebug() << "ERROR: Unknown format type"; } } void ResourceLocal::init() { setType( "file" ); setSavePolicy( SaveDelayed ); connect( &d->mDirWatch, SIGNAL( dirty( const QString & ) ), SLOT( reload() ) ); connect( &d->mDirWatch, SIGNAL( created( const QString & ) ), SLOT( reload() ) ); connect( &d->mDirWatch, SIGNAL( deleted( const QString & ) ), SLOT( reload() ) ); d->mLock = new KABC::Lock( d->mURL.path() ); d->mDirWatch.addFile( d->mURL.path() ); d->mDirWatch.startScan(); } ResourceLocal::~ResourceLocal() { d->mDirWatch.stopScan(); close(); delete d->mLock; delete d; } KDateTime ResourceLocal::readLastModified() { QFileInfo fi( d->mURL.path() ); return KDateTime( fi.lastModified() ); // use local time zone } bool ResourceLocal::doLoad( bool syncCache ) { Q_UNUSED( syncCache ); bool success; if ( !KStandardDirs::exists( d->mURL.path() ) ) { kDebug() << "File doesn't exist yet."; // Save the empty calendar, so the calendar file will be created. success = doSave( true ); } else { success = calendar()->load( d->mURL.path() ); if ( success ) { d->mLastModified = readLastModified(); } } return success; } bool ResourceLocal::doSave( bool syncCache ) { Q_UNUSED( syncCache ); bool success = calendar()->save( d->mURL.path() ); kDebug() << "Save of " << d->mURL.path() << "was " << success; d->mLastModified = readLastModified(); return success; } bool ResourceLocal::doSave( bool syncCache, Incidence *incidence ) { return ResourceCached::doSave( syncCache, incidence ); } KABC::Lock *ResourceLocal::lock() { return d->mLock; } bool ResourceLocal::doReload() { kDebug(); if ( !isOpen() ) { kDebug() << "trying to reload from a closed file"; return false; } if ( d->mLastModified == readLastModified() ) { kDebug() << "file not modified since last read."; return false; } calendar()->close(); calendar()->load( d->mURL.path() ); return true; } void ResourceLocal::reload() { if ( doReload() ) { emit resourceChanged( this ); } } void ResourceLocal::dump() const { ResourceCalendar::dump(); kDebug() << " Url:" << d->mURL.url(); } QString ResourceLocal::fileName() const { return d->mURL.path(); } bool ResourceLocal::setFileName( const QString &fileName ) { bool open = isOpen(); if ( open ) { close(); } delete d->mLock; d->mDirWatch.stopScan(); d->mDirWatch.removeFile( d->mURL.path() ); d->mURL = KUrl::fromPath( fileName ); d->mLock = new KABC::Lock( d->mURL.path() ); d->mDirWatch.addFile( d->mURL.path() ); d->mDirWatch.startScan(); return true; } bool ResourceLocal::setValue( const QString &key, const QString &value ) { if ( key == "File" ) { return setFileName( value ); } else { return false; } } bool ResourceLocal::operator==( const ResourceLocal &other ) { return d->mURL == other.d->mURL && d->mLastModified == other.d->mLastModified; } ResourceLocal &ResourceLocal::operator=( const ResourceLocal &other ) { + // check for self assignment + if ( &other == this ) { + return *this; + } + d->mURL = other.d->mURL; d->mLastModified = other.d->mLastModified; return *this; } diff --git a/kcal/todo.cpp b/kcal/todo.cpp index 8e5f89151..16dd1a7db 100644 --- a/kcal/todo.cpp +++ b/kcal/todo.cpp @@ -1,530 +1,535 @@ /* 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 ) { + // 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 ) && 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 ) + 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 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( 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 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 && 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