diff -r 000000000000 -r f979ecb2b13e pimappservices/calendar/shared/src/agmrptdef.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pimappservices/calendar/shared/src/agmrptdef.cpp Tue Feb 02 10:12:19 2010 +0200 @@ -0,0 +1,3906 @@ +// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include "agmrptdef.h" + +#include "agmsimpleentry.h" +#include "agmdate.h" +#include "agmutil.h" +#include "agmtlsproxy.h" +#include "agmdebug.h" +#include "agmtzrules.h" + +#include + +const TInt16 KRptLocalOffsetNotSet = KMaxTInt16; + +// --------------------------------------- TAgnRpt ------------------------------- + +TBool TAgnRpt::HourAndMinutesDifferentFromStartTimeL(const TTime& aRptLocalTime) const + { + const TDateTime KRptLocalTestDT = aRptLocalTime.DateTime(); + const TDateTime KRptLocalStartDT = StartTimeAsRptLocalL().DateTime(); + + if (KRptLocalTestDT.Hour() != KRptLocalStartDT.Hour() || + KRptLocalTestDT.Minute() != KRptLocalStartDT.Minute()) + { + // Hour and minute are not the same, it is possible that they are at the same time in UTC but + // due to the 'missing hour' the two local times appear different. + // Compare the UTC times. + + const TDateTime KUtcStartDT = StartTime().UtcL().DateTime(); + const TDateTime KUtcTestDT = ConvertFromRepeatLocalToUtcL(aRptLocalTime).DateTime(); + + if (KUtcStartDT.Hour() != KUtcTestDT.Hour() || + KUtcStartDT.Minute() != KUtcTestDT.Minute()) + { + return ETrue; + } + } + return EFalse; + } + +/** Constructs the repeat object. +The until date is initialised to max time, the repeat interval to 1. +@internalComponent +*/ +TAgnRpt::TAgnRpt(CAgnRptDef& aOwningRptDef) : + iOwningRptDef(aOwningRptDef) + { + ClearAll(); + } + +/** Constructs a new TAgnRpt object from an existing one. + +@internalComponent +@param aRRule The object to be copied. */ +TAgnRpt::TAgnRpt(const TAgnRpt& aRRule, CAgnRptDef& aOwningRptDef) : + iOwningRptDef(aOwningRptDef) + { + ClearAll(); + iUntilTime = aRRule.iUntilTime; + iInterval = aRRule.iInterval; + iCount = aRRule.iCount; + iUntiltimeHasBeenSet = aRRule.iUntiltimeHasBeenSet; + } + +void TAgnRpt::ResetCachedStartTimeOffset() + { + iStartTimeRptLocalOffset = KRptLocalOffsetNotSet; + } + +void TAgnRpt::ResetCachedUntilTimeOffset() + { + iUntilTimeRptLocalOffset = KRptLocalOffsetNotSet; + } + +MAgnCalendarTimeMode::TTimeMode TAgnRpt::TimeMode() const + { + return iOwningRptDef.TimeMode(); + } + +TTime TAgnRpt::ConvertFromRepeatLocalToUtcL(const TTime& aRptLocalDate) const + { + return iOwningRptDef.ConvertFromRepeatLocalToUtcL(aRptLocalDate); + } + +TTime TAgnRpt::ConvertFromUtcToRepeatLocalL(const TTime& aUtcDate) const + { + return iOwningRptDef.ConvertFromUtcToRepeatLocalL(aUtcDate); + } + +TTime TAgnRpt::ConvertFromRepeatLocalToSystemLocalL(const TTime& aRptLocalTime) const + { + // If TimeMode is floating, avoid unnecessary conversion by using aRptLocalTime + if (TimeMode() == MAgnCalendarTimeMode::EFloating) + { + return aRptLocalTime; + } + + const TTime KUtcTime = ConvertFromRepeatLocalToUtcL(aRptLocalTime); + return AgnDateTime::ConvertToLocalTimeL(KUtcTime); + } + +TTime TAgnRpt::ConvertFromSystemLocalToRepeatLocalL(const TTime& aSysLocalTime) const + { + // If TimeMode is floating, avoid unnecessary conversion by using aSysLocalTime + if (TimeMode() == MAgnCalendarTimeMode::EFloating) + { + return aSysLocalTime; + } + + const TTime KUtcTime = AgnDateTime::ConvertToLocalTimeL(aSysLocalTime); + return ConvertFromUtcToRepeatLocalL(KUtcTime); + } + +TTime TAgnRpt::StartTimeAsRptLocalL() const + { + TTime startTimeRptLocal; + GetTimeAsRptLocalL(StartTime(), startTimeRptLocal, iStartTimeRptLocalOffset); + return startTimeRptLocal; + } + +TTime TAgnRpt::UntilTimeAsRptLocalL() const + { + TTime untilTimeRptLocal; + GetTimeAsRptLocalL(UntilTimeL(), untilTimeRptLocal, iUntilTimeRptLocalOffset); + return untilTimeRptLocal; + } + +void TAgnRpt::GetTimeAsRptLocalL(const TAgnCalendarTime& aCalendarTime, TTime& aTimeAsRptLocal, TInt16& aCachedOffset) const + { + if (TimeMode() == MAgnCalendarTimeMode::EFloating) + { + aTimeAsRptLocal = aCalendarTime.LocalL(); // if the entry is floating, system local is the same as rpt local + return; + } + + if (aCachedOffset == KRptLocalOffsetNotSet) + { + aCachedOffset = 0; + TTime rptLocalTime = ConvertFromUtcToRepeatLocalL(aCalendarTime.UtcL()); + TTimeIntervalMinutes mins; + rptLocalTime.MinutesFrom(aCalendarTime.UtcL(), mins); + aCachedOffset = mins.Int(); + } + aTimeAsRptLocal = aCalendarTime.UtcL() + TTimeIntervalMinutes(aCachedOffset); + } + +EXPORT_C const TAgnCalendarTime& TAgnRpt::UntilTimeL() const + { + // if iCount is set, the until time will not be set. + if (iCount > 0) + { + TTime time = FindRptUntilTimeLocalL(iCount); + + if (!iUntiltimeHasBeenSet) + { + if (TimeMode() == MAgnCalendarTimeMode::EFloating) + { + iUntilTime.SetFloatingL(time); + } + else + { + iUntilTime.SetLocalL(time); + } + } + } + + if(iUntilTime.UtcL() > AgnDateTime::MaxDate()) + { + iUntilTime.SetUtcL(AgnDateTime::MaxDate()); + } + + return iUntilTime; + } + +void TAgnRpt::SetUntilTime(const TAgnCalendarTime& aUntilTime) + { + iUntilTime = aUntilTime; + iUntilTimeRptLocalOffset = KRptLocalOffsetNotSet; + iUntiltimeHasBeenSet = ETrue; + } + +const TAgnCalendarTime& TAgnRpt::StartTime() const +/** Gets the start time as a @see TAgnCalendarTime. + +@internalComponent +@return The start time. */ + { + return iOwningRptDef.StartTime(); + } + +void TAgnRpt::ClearAll() +/** Clears all the repeat details. + +The until time is set to max time and the repeat interval to 1. +The cached repeat local time offsets are reset. + +@internalComponent +*/ + { + iUntilTime.SetUtcL(AgnDateTime::MaxDate()); // this can't leave + iStartTimeRptLocalOffset = KRptLocalOffsetNotSet; + iUntilTimeRptLocalOffset = KRptLocalOffsetNotSet; + iInterval = 1; + iCount = -1; + iUntiltimeHasBeenSet = EFalse; + } + + +TInt TAgnRpt::InvariantL() const +/** +Check that the rpt doesn't violate its invariants +@internalComponent +*/ + { + if (Type() < EDaily || Type() > EYearlyByDay) + { + return (EAgmErrBadRepeat); + } + + + if (Interval() <= 0 || !AgnDateTime::IsValidAgendaTTime(iUntilTime.UtcL()) || StartTime() >= iUntilTime) + { + return (EAgmErrBadTime); + } + + return (KErrNone); + } + + + +void TAgnRpt::InternalizeL(RReadStream& aStream) +/** Internalises the repeat definition from a read stream, including type, repeat +details and exception list. + +@internalComponent +@param aStream The stream from which the object should be internalised. */ + { + aStream >> iUntilTime; + iInterval = aStream.ReadUint16L(); + iStartTimeRptLocalOffset = KRptLocalOffsetNotSet; + iUntilTimeRptLocalOffset = KRptLocalOffsetNotSet; + } + + +void TAgnRpt::ExternalizeL(RWriteStream& aStream) const +/** Externalises the repeat definition to a write stream. + +@internalComponent +@param aStream The stream to which the object should be externalised. */ + { + aStream << iUntilTime; + aStream.WriteUint16L(iInterval); + } + +TBool TAgnRpt::operator==(const TAgnRpt& aRRule) const +/** Compares two repeat details objects. + +@internalComponent +@param aRRule The repeat details to compare with this object. +@return True if all properties agree, otherwise False. */ + { + return (iInterval == aRRule.iInterval && UntilTimeL() == aRRule.UntilTimeL()); + } + +TBool TAgnRpt::operator!=(const TAgnRpt& aRRule) const + { + return ( ! (*this == aRRule) ); + } + +TUint TAgnRpt::MapDayToBits(TDay aDay) const +/** + Provides a mapping between the enumeration values of TDay to bit fields +*/ + { + switch(aDay) + { + case EMonday : return (EBit1); + case ETuesday: return (EBit2); + case EWednesday:return (EBit3); + case EThursday: return (EBit4); + case EFriday: return (EBit5); + case ESaturday: return (EBit6); + case ESunday: return (EBit7); + default: + { + _DBGLOG_ENTRY(AgmDebug::DebugLog("TAgnRpt: Panic - EAgmErrInvalidWeekDay");) + DBG_PANIC(EAgmErrInvalidWeekDay); + } + } + return (EBit0); + } + + +TUint TAgnRpt::MapDateToBits(TUint aNum) const +/** + Provides a mapping between the numbers 0 to 30 to bit fields. + 0 = the first day of a month, 30 = the 31st day of the month +*/ + { + if (aNum > 30) + { + _DBGLOG_ENTRY(AgmDebug::DebugLog("TAgnRpt: Panic - EAgmErrInvalidMonthDay");) + DBG_PANIC(EAgmErrInvalidMonthDay); + return (EBit0); + } + + return (1 << aNum); + } + +TTime TAgnRpt::NudgeNextAlignedStartTimeL(const TTime& aRptLocalDate) const + { + TTime startTime = StartTimeAsRptLocalL(); + + // Find the previous aligned start time from aRptLocalDate + TTime alignedDate(startTime + aRptLocalDate.DaysFrom(startTime)); + + const TTime KUtcAlignedDate = ConvertFromRepeatLocalToUtcL(alignedDate); + const TTime KUtcLocalDate = ConvertFromRepeatLocalToUtcL(aRptLocalDate); + + // Don't add a day if aRptLocalDate is already 'aligned start time' + // or if it is before the start of the repeat rule, because DaysFrom + // already returns 'next aligned start time' in that case + if ((aRptLocalDate != alignedDate && aRptLocalDate > startTime) || KUtcLocalDate > KUtcAlignedDate) + { + // Add a day to get the 'next aligned start time' + alignedDate += TTimeIntervalDays(1); + } + + return alignedDate; + } + +TTime TAgnRpt::NudgePreviousAlignedStartTimeL(const TTime& aRptLocalDate) const + { + TTime startTime = StartTimeAsRptLocalL(); + + // Find the previous aligned start time from aRptLocalDate + TTime alignedDate(startTime + aRptLocalDate.DaysFrom(startTime)); + + const TTime KUtcAlignedDate = ConvertFromRepeatLocalToUtcL(alignedDate); + const TTime KUtcLocalDate = ConvertFromRepeatLocalToUtcL(aRptLocalDate); + + if ( (aRptLocalDate != alignedDate && aRptLocalDate < startTime) || KUtcLocalDate < KUtcAlignedDate ) + { + // Subtract a day when aRptLocalDate is before the repeat rule + // start date, because DaysFrom() is a day out in that case + alignedDate -= TTimeIntervalDays(1); + } + + return alignedDate; + } + +EXPORT_C TTime TAgnRpt::FindRptUntilTimeLocalL(TUint aCount) const +/** Calculates the repeat's end date from the specified number of instances. + +If the end date would be after the agenda model's valid date range, it returns +a NULL TTime value. + +@internalComponent +@param aCount The number of instances. +@return The end date (System Local Time). */ + { + TTime end = FindRptUntilTimeRptLocalL(aCount); + return ConvertFromRepeatLocalToSystemLocalL(end); + } + +EXPORT_C TUint16 TAgnRpt::Interval() const +/** Gets the repeat interval. + +@return The interval. */ + { + return (iInterval); + } + +EXPORT_C void TAgnRpt::SetInterval(TUint16 aInterval) +/** Sets the repeat interval. + +This is a number of days for a daily repeat, a number of weeks for a +weekly repeat, etc. + +@param aInterval The interval. */ + { + if (aInterval > 0) + { + iInterval = aInterval; + } + } + +EXPORT_C void TAgnRpt::SetCount(TInt aRepCount) + { + iCount = aRepCount; + iUntiltimeHasBeenSet = EFalse; + } + +EXPORT_C TInt TAgnRpt::Count() const +/* +>0 - Indicate how many occurrences of a repeating rule. + 0 - Repeating forever. Note that it is the default value if there is neither Until time nor Count has been set. +<0 - A Until time has been set but not the count. + +*/ { + return iCount; + } + +// --------------------------------- TAgnDailyRpt ------------------------------ +EXPORT_C TAgnDailyRpt::TAgnDailyRpt(CAgnRptDef& aOwningRptDef) : TAgnRpt(aOwningRptDef) +/** +This is not inline to prevent non-exportable functions causing a linker error in calling code +Constructs a default daily repeat object. +@internalComponent +*/ + { + } + +/** Constructs a new TAgnDailyRpt object from an existing TAgnDailyRpt object. + +@internalComponent +@param aRRule The object to be copied. */ +EXPORT_C TAgnDailyRpt::TAgnDailyRpt(const TAgnDailyRpt& aRRule, CAgnRptDef& aOwningRptDef) : + TAgnRpt(aRRule, aOwningRptDef) + { + } + +TAgnRpt::TType TAgnDailyRpt::Type() const + { + return TAgnRpt::EDaily; + } + +TBool TAgnDailyRpt::IsAlignedUtcL(const TTime& aDate) const +/** + Returns true if aDate (UTC) falls on an instance generated by the repeat algorithm +@internalComponent +*/ + { + // convert aDate from UTC to Repeat Local + TTime rptLocalDate = ConvertFromUtcToRepeatLocalL(aDate); + return IsAlignedRptLocalL(rptLocalDate); + } + +TBool TAgnDailyRpt::IsAlignedRptLocalL(const TTime& aDate) const +/** +Returns true if aDate (Repeat Local) falls on an instance generated by the repeat algorithm +@internalComponent +*/ + { + // see if the day falls on an instance + if ( AgnDateTime::DaysBetweenDates(aDate, StartTimeAsRptLocalL()) % iInterval ) + { + return EFalse; + } + + if (HourAndMinutesDifferentFromStartTimeL(aDate)) + { + return EFalse; + } + + return ETrue; + } + +TUint TAgnDailyRpt::InstanceCountL() const +/** Gets the number of instances generated by the repeat algorithm. + +@internalComponent +@return The number of instances. */ + { + // to avoid unnecessary time conversions, date substractions should be done in + // the time reference in which start and end dates are stored + return 1 + (AgnDateTime::DaysBetweenDates(UntilTimeAsRptLocalL(), StartTimeAsRptLocalL()) / iInterval) ; + } + +TTime TAgnDailyRpt::FindRptUntilTimeRptLocalL(TUint aCount) const + { + // do calculations in repeat local + TUint max = (AgnDateTime::MaxDate().DaysFrom(StartTimeAsRptLocalL()).Int() + 1) / iInterval; + if (aCount > max) + { + return AgnDateTime::MaxDate(); + } + return StartTimeAsRptLocalL() + TTimeIntervalDays(iInterval * (aCount-1)); + } + +TTime TAgnDailyRpt::NudgeNextInstanceUtcL(const TTime& aUtcDate) const +/** +If aUtcDate is already a date generated by the repeat algorithm then that is the date returned, +otherwise the next instance from aUtcDate is returned (in UTC time) +@internalComponent +*/ + { + // aDate-start + // nextDate = start + ( ------------- + 1) * interval + // interval + // (NOTE: (aDate-start)/interval is NOT incremented if the modulus of division is zero ) + + // convert aUtcDate to Repeat Local Time + TTime thisDate = ConvertFromUtcToRepeatLocalL(aUtcDate); + + TTime next = NudgeNextAlignedStartTimeL(thisDate); + + if (IsAlignedRptLocalL(next)) + { + return ConvertFromRepeatLocalToUtcL(next); + } + + thisDate = next; + + // get number of last instance + TInt instanceNumber = AgnDateTime::DaysBetweenDates(thisDate, StartTimeAsRptLocalL()) / iInterval; + // if there isn't an instance on our date, we want the next instance + if (AgnDateTime::DaysBetweenDates(thisDate, StartTimeAsRptLocalL()) % iInterval) + { + ++instanceNumber; + } + + // resolve instance number to days since start + TInt daysFromStartToNextInstance = instanceNumber * iInterval; + + // add to start date + TTime nextDate = StartTimeAsRptLocalL() + TTimeIntervalDays(daysFromStartToNextInstance); + + if (nextDate > AgnDateTime::MaxDate()) + { + return Time::NullTTime(); + } + + // convert from repeat local to UTC and return + return ConvertFromRepeatLocalToUtcL(nextDate); + } + + +TTime TAgnDailyRpt::NudgePreviousInstanceUtcL(const TTime& aUtcDate) const +/** +If aUtcDate is already a date generated by the repeat algorithm then that is the date returned, +otherwise the previous instance is returned. +@internalComponent +*/ + { + + TTime thisDate = ConvertFromUtcToRepeatLocalL(aUtcDate); + + TTime prev = NudgePreviousAlignedStartTimeL(thisDate); + + if (IsAlignedRptLocalL(prev)) + { + return ConvertFromRepeatLocalToUtcL(prev); + } + + thisDate = prev; + + // get number of last instance + TInt instanceNumber = AgnDateTime::DaysBetweenDates(thisDate, StartTimeAsRptLocalL()) / iInterval; + + // resolve instance number to days since start + TInt daysFromStartToPreviousInstance = instanceNumber * iInterval; + + // add to start date + TTime prevDate = StartTimeAsRptLocalL() + TTimeIntervalDays(daysFromStartToPreviousInstance); + + // an instance could have occurred later on our date - get previous instance + if (prevDate > thisDate ) + { + prevDate -= TTimeIntervalDays(iInterval); + } + + if (prevDate < AgnDateTime::MinDate()) + { + return Time::NullTTime(); + } + + return ConvertFromRepeatLocalToUtcL(prevDate); + } + + +// ------------------------------------ TAgnWeeklyRpt-------------------------------- +EXPORT_C TAgnWeeklyRpt::TAgnWeeklyRpt(CAgnRptDef& aOwningRptDef) : + TAgnRpt(aOwningRptDef) +/** Constructs a weekly repeat object. + +The weekly repeat days are all cleared, and the day which is the start of the +week is initialised from the system's locale settings. + +@internalComponent +*/ + { + iWeeklyRptDays = 0; + TLocale locale; + SetFirstDayOfWeek(locale.StartOfWeek()); + } + +EXPORT_C TAgnWeeklyRpt::TAgnWeeklyRpt(const TAgnWeeklyRpt& aRRule, CAgnRptDef& aOwningRptDef) : + TAgnRpt(aRRule, aOwningRptDef) +/** Constructs a new TAgnWeeklyRpt object from an existing TAgnWeeklyRpt object. + +@internalComponent +@param aRRule The object to be copied. */ + { + iWeeklyRptDays = aRRule.iWeeklyRptDays; + iFirstDayOfWeek = aRRule.iFirstDayOfWeek; + } + +TAgnRpt::TType TAgnWeeklyRpt::Type() const + { + return TAgnRpt::EWeekly; + } + +EXPORT_C void TAgnWeeklyRpt::SetDay(TDay aDay) +/** Adds a day - more than one day can be set at a time. + +@internalComponent +@param aDay The day to be added. */ + { + + iWeeklyRptDays |= MapDayToBits(aDay); + } + +EXPORT_C TBool TAgnWeeklyRpt::IsDaySet(TDay aDay) const +/** Tests whether a specified day has been set. + +@internalComponent +@param aDay The day to test. +@return True if the day is set, false if not. */ + { + return (iWeeklyRptDays & (MapDayToBits(aDay))); + } + + +EXPORT_C void TAgnWeeklyRpt::SetFirstDayOfWeek(TDay aDay) +/** +Set the start day of the week + +@internalComponent +*/ + { + iFirstDayOfWeek= static_cast(MapDayToBits(aDay)); + } + +EXPORT_C TDay TAgnWeeklyRpt::FirstDayOfWeek() const +/** Gets the day that is considered to be the first day of the week. + +This is set during construction from the operating system's locale settings. + +@internalComponent +@return The first day of the week. */ + { + switch(iFirstDayOfWeek) + { + case EBit1: return (EMonday); + case EBit2: return (ETuesday); + case EBit3: return (EWednesday); + case EBit4: return (EThursday); + case EBit5: return (EFriday); + case EBit6: return (ESaturday); + case EBit7: return (ESunday); + default: + { + _DBGLOG_ENTRY(AgmDebug::DebugLog("TAgnWeeklyRpt: Panic - EAgmErrInvalidWeekDay");) + DBG_PANIC(EAgmErrInvalidWeekDay); + } + } + return (EMonday); + } + +TInt TAgnWeeklyRpt::InvariantL() const +/** +Check that the rpt doesn't violate its invariants +@internalComponent +*/ + { + if (TAgnRpt::InvariantL()==KErrNone && NumDaysSet() > 0 && + (iFirstDayOfWeek==EBit1|| iFirstDayOfWeek==EBit2 || iFirstDayOfWeek==EBit3|| iFirstDayOfWeek==EBit4 || + iFirstDayOfWeek==EBit5 || iFirstDayOfWeek==EBit6 || iFirstDayOfWeek==EBit7)) + { + return (KErrNone); + } + + return (EAgmErrBadRepeat); + } + +void TAgnWeeklyRpt::InternalizeL(RReadStream& aStream) +/** Internalises the weekly repeat object from a read stream. + +@internalComponent +@param aStream Stream from which the object should be internalised. */ + { + TAgnRpt::InternalizeL(aStream); + aStream >> iWeeklyRptDays; + aStream >> iFirstDayOfWeek; + } + +void TAgnWeeklyRpt::ExternalizeL(RWriteStream& aStream) const +/** Externalises the weekly repeat object to a write stream. + +@internalComponent +@param aStream Stream to which the object should be externalised. */ + { + + TAgnRpt::ExternalizeL(aStream); + aStream << iWeeklyRptDays; + aStream << iFirstDayOfWeek; + } + +TBool TAgnWeeklyRpt::operator==(const TAgnWeeklyRpt& aRRule) const +/** Compares two weekly repeat objects for equality. + +@internalComponent +@param aRRule The instance to be compared. +@return True if all repeat details are equal, otherwise False. */ + { + return (TAgnRpt::operator==(aRRule) && iWeeklyRptDays==aRRule.iWeeklyRptDays); + } + +TUint TAgnWeeklyRpt::InstanceCountL() const +/** Gets the number of instances of the repeat. + +@internalComponent +@return The number of instances. */ + { + TTime startOfFirstWeek = DayAtStartOfWeek(StartTimeAsRptLocalL()); + TUint count = AgnDateTime::DaysBetweenDates(UntilTimeAsRptLocalL(), startOfFirstWeek) / (7 * iInterval); // No of complete weeks + TTime startDate = startOfFirstWeek + TTimeIntervalDays(count * 7 * iInterval); // must check any remaining bit of last week + count*=NumDaysSet(); + while (startDate <= UntilTimeAsRptLocalL()) + { + if (IsAlignedRptLocalL(startDate)) + { + ++count; + } + startDate += TTimeIntervalDays(1); + } + + // remove any instances before the start date + while (startOfFirstWeek < StartTimeAsRptLocalL()) + { + if (IsAlignedRptLocalL(startOfFirstWeek)) + { + count--; + } + startOfFirstWeek += TTimeIntervalDays(1); + } + + return (count); + } + +TTime TAgnWeeklyRpt::FindRptUntilTimeRptLocalL(TUint aCount) const + { + const TInt KDaysInAWeek = 7; + + // we do all calculations using repeat local times + TTimeIntervalDays maxDays = AgnDateTime::MaxDate().DaysFrom(StartTimeAsRptLocalL()); + TInt max = (((maxDays.Int() / KDaysInAWeek) * NumDaysSet()) / iInterval) + 1; + + if (aCount > max) + { + return AgnDateTime::MaxDate(); + } + + TInt instancesPerWeek = NumDaysSet(); // number of instances in each week + TTime end; + if (aCount % instancesPerWeek == 0) + { + end = StartTimeAsRptLocalL() + TTimeIntervalDays(((aCount - 1) / instancesPerWeek) * KDaysInAWeek * iInterval); + } + else + { + end = StartTimeAsRptLocalL() + TTimeIntervalDays((aCount / instancesPerWeek) * KDaysInAWeek * iInterval); + } + + if (end > AgnDateTime::MaxDate()) + { + return (Time::NullTTime()); + } + + TInt remainder = aCount % instancesPerWeek; + TInt numToNudge = remainder ? remainder : instancesPerWeek; + + end=NudgeNextInstanceRptLocalL(end); + for (; numToNudge > 1 && end != Time::NullTTime(); numToNudge--) + { + end += TTimeIntervalDays(1); + end = NudgeNextInstanceRptLocalL(end); + } + return end; + } + +TTime TAgnWeeklyRpt::NudgeNextInstanceUtcL(const TTime& aDate) const +/** +If aDate is already a date generated by the repeat algorithm then that is the date returned, +otherwise the next instance from aDate is returned (in UTC) +*/ + { + + // Convert aDate from UTC to repeat local + TTime next = ConvertFromUtcToRepeatLocalL(aDate); + + next = NudgeNextInstanceRptLocalL(next); + + // convert from repeat local back to UTC and return + return ConvertFromRepeatLocalToUtcL(next); + } + +TTime TAgnWeeklyRpt::NudgeNextInstanceRptLocalL(const TTime& aRptLocalDate) const +/** +Nudges next instance in repeat local time +*/ + { + TTime next = NudgeNextAlignedStartTimeL(aRptLocalDate); + FOREVER + { + if (IsAlignedRptLocalL(next)) + { + break; + } + if (next == AgnDateTime::MaxDate()) + { + return (Time::NullTTime()); + } + next += TTimeIntervalDays(1); + } + return next; + } + +TTime TAgnWeeklyRpt::NudgePreviousInstanceUtcL(const TTime& aDate) const +/** +If aDate is already a date generated by the repeat algorithm then that is the date returned, +otherwise the previous instance is returned. + +The algorithm works by skipping backswards over any unaligned weeks, if the current date +isn't in an aligned week then it is jumped back to take it to the week after the previous aligned +week. Then one day at a time is subtracted and each day checked to see whether it is aligned or not. + +If no aligned day is found after creeping back 7 days, then the week is re-checked to see if it is +still in an aligned week (by recalling this function). +Both received parameter (aDate) and returned value are expressed in UTC +@internalComponent +*/ + { + TTime prev = ConvertFromUtcToRepeatLocalL(aDate); + prev = NudgePreviousInstanceRptLocalL(prev); + return ConvertFromRepeatLocalToUtcL(prev); + } + +TTime TAgnWeeklyRpt::NudgePreviousInstanceRptLocalL(const TTime& aDate) const + { + TTime prev = NudgePreviousAlignedStartTimeL(aDate); + + if (IsAlignedRptLocalL(prev)) + return prev; + + // get the first day of the week from the prev parameter + TDay dayOfWeekADate = prev.DayNoInWeek(); + TTime newDate = prev; + while (dayOfWeekADate != FirstDayOfWeek()) + { + newDate -= TTimeIntervalDays(1); + if (dayOfWeekADate > EMonday) + { + dayOfWeekADate = (TDay)(TInt(dayOfWeekADate) - 1); + } + else + { + dayOfWeekADate = ESunday; + } + } + // get the first day of the week from the StartDate + TDay dayOfWeekStartTime = StartTimeAsRptLocalL().DayNoInWeek(); + TTime newStartTime = StartTimeAsRptLocalL(); + while (dayOfWeekStartTime != FirstDayOfWeek()) + { + newStartTime -= TTimeIntervalDays(1); + if (dayOfWeekStartTime > EMonday) + { + dayOfWeekStartTime = (TDay)(TInt(dayOfWeekStartTime) - 1); + } + else + { + dayOfWeekStartTime = ESunday; + } + } + // check if this week has any instances + TInt weeks = AgnDateTime::DaysBetweenDates(newDate, newStartTime) / 7; // needs to compare the first days in the weeks + if (weeks % iInterval != 0) + { + // if not, jump to the week after the previous instance, then creep back one day at a time + TInt daysAfterStartTime = AgnDateTime::DaysBetweenDates(prev, StartTimeAsRptLocalL()); + TInt weeksSafelyAfterLastInstance = (daysAfterStartTime/7) % iInterval - 1; + if (weeksSafelyAfterLastInstance > 0) + { + prev = prev - TTimeIntervalDays(weeksSafelyAfterLastInstance*7); + } + } + + TInt count = 0; + while (!IsAlignedRptLocalL(prev) && count < 7) + { + prev -= TTimeIntervalDays(1); + ++count; + } + if (count >= 7) + { + prev = NudgePreviousInstanceRptLocalL(prev); // call the 'jump back' code as may no longer be in a week with instances + } + if (prev < AgnDateTime::MinDate()) + { + return (Time::NullTTime()); + } + if (prev > AgnDateTime::MaxDate()) + { + return (Time::NullTTime()); + } + return prev; + } + + +TUint TAgnWeeklyRpt::NumDaysSet() const +/** Gets the number of repeat days in the week which are set. + +@internalComponent +@return The number of days. */ + { + + TUint count=0; + for (TUint ii = 1;ii <= 0x40; ii <<= 1) + { + count += !!(iWeeklyRptDays & ii); + } + return (count); + } + +TBool TAgnWeeklyRpt::IsAlignedUtcL(const TTime& aDate) const +/** +Returns true if aDate falls on an instance generated by the repeat algorithm +(ignores repeat start/end dates) +*/ + { + + TTime localDate = ConvertFromUtcToRepeatLocalL(aDate); + + return IsAlignedRptLocalL(localDate); + } + +TBool TAgnWeeklyRpt::IsAlignedRptLocalL(const TTime& aDate) const + { + if (!IsDateInValidWeekRptLocalL(aDate)) + return (EFalse); + + // if it's in a valid week check if that day is set + if (!IsDaySet(aDate.DayNoInWeek())) + { + return EFalse; + } + + if (HourAndMinutesDifferentFromStartTimeL(aDate)) + { + return EFalse; + } + + return ETrue; + } + +TInt TAgnWeeklyRpt::IsDateInValidWeekRptLocalL(const TTime& aDate) const +// aDate is in Repeat Local Time +// +// Determine if aDate falls in a valid week i.e. one aligned according to the interval. +// +// For positive weeks the algorithm is its valid if ((week no -1) % interval)==0 +// Week numbers: 1 2 3 4 5 6 7 8 +// interval of 1 V V V V V V V V (5 - 1) % 1 == 0 so valid +// interval of 2 V V V V (5 - 1) % 2 == 0 so valid +// interval of 3 V V V (5 - 1) % 3 == 1 so invalid etc. +// +// But for negative weeks the algorithm is its valid if ((week no)% interval)==0 +// i.e. +// week no -4 -3 -2 -1 1 2 3 4 5 +// interval of 3 V V V (-3 % 3) == 0 so valid +// + { + + TInt weekNum=WeekNumRptLocalL(aDate); + if (weekNum > 0) // in a positive week i.e. aDate >= the start of the first week + return ((weekNum-1) % iInterval == 0); + else + return ((weekNum) % iInterval == 0); // aDate < the start of the first week + } + + +TInt TAgnWeeklyRpt::WeekNumRptLocalL(const TTime& aDate) const +// First calculate the week number i.e. +// December January +// 29 30 31 1 2 3 4 5 6 7 8 9 10 +// T F S S M T W T F S S M T +// X +// | 1st week | 2nd week +// +// If X is the start date of the repeat and the first day of the week is a saturday then +// sunday the 8th is in week number ((8 - (-1)) / 7) + 1 i.e the 2nd week +// Note that -1 represents 31st of december as it is 1 less than whatever the internal +// representation of 1st Jan is. + + { + TTime startOf1stWeek=DayAtStartOfWeek(StartTimeAsRptLocalL()); + TInt weekNo; + if (aDate >= startOf1stWeek) + weekNo=(AgnDateTime::DaysBetweenDates(aDate, startOf1stWeek)/7)+1; + else + weekNo=((AgnDateTime::DaysBetweenDates(aDate, startOf1stWeek)+1)/7)-1; // i.e. december the30th above is in week -1 + + return (weekNo); + } + + +TTime TAgnWeeklyRpt::DayAtStartOfWeek(const TTime& aDay) const +// +// Returns the day at the start of the week containing aDay +// +// i.e. M T W T F S S M T W T F S S +// 46 47 48 49 50 51 52 53 54 55 56 57 58 59 +// If aDay is 53 (Monday) and the start of the week is a monday then 53 is returned +// If aDay is 53 but the start of the week is a Wednesday then 48 is returned + { + + TTime dayAtWeekStart= aDay - TTimeIntervalDays(aDay.DayNoInWeek()) + TTimeIntervalDays(FirstDayOfWeek()); + if (dayAtWeekStart < 0) + dayAtWeekStart = 0; + else if (dayAtWeekStart > aDay) + dayAtWeekStart = dayAtWeekStart - TTimeIntervalDays(7); + return(dayAtWeekStart); + } + + + + +// ------------------------------ TAgnMonthlyRpt ---------------------------- + +TAgnMonthlyRpt::TAgnMonthlyRpt(CAgnRptDef& aOwningRptDef) : + TAgnRpt(aOwningRptDef) + { + } + +TAgnMonthlyRpt::TAgnMonthlyRpt(const TAgnRpt& aRRule, CAgnRptDef& aOwningRptDef) : + TAgnRpt(aRRule, aOwningRptDef) + { + } + +TUint TAgnMonthlyRpt::InstanceCountL() const +/** Calculates the number of instances generated by the repeat algorithm. + +@internalComponent +@return The number of instances. */ + { + + if (NumInstancesPerMonth()==0) + return (0); + + TUint count=0; + TTime nextDate = NudgeNextInstanceRptLocalL(StartTimeAsRptLocalL()); + while (nextDate <= UntilTimeAsRptLocalL() && nextDate >= AgnDateTime::MinDate() && nextDate <= AgnDateTime::MaxDate() ) + { + nextDate += TTimeIntervalDays(1); + nextDate = NudgeNextInstanceRptLocalL(nextDate); + ++count; + } + return (count); + } + +TTime TAgnMonthlyRpt::FindRptUntilTimeRptLocalL(TUint aCount) const + { + TTimeIntervalMonths monthsFrom = AgnDateTime::MaxDate().MonthsFrom(StartTimeAsRptLocalL()); + TInt numInstancesPerMonth = NumInstancesPerMonth(); + TUint max = (((monthsFrom.Int() + 1) * numInstancesPerMonth) / iInterval) + 1; + + if (aCount > max) + { + return AgnDateTime::MaxDate(); + } + TInt rem = aCount; + + TTime end=StartTimeAsRptLocalL(); + if (IsAlignedRptLocalL(end)) + rem--; + while (rem) + { + end += TTimeIntervalDays(1); + if (end > AgnDateTime::MaxDate()) + return (Time::NullTTime()); + end=NudgeNextInstanceRptLocalL(end); + rem--; + } + return end; + } + +TBool TAgnMonthlyRpt::DateFallsInAlignedMonthL(const TDateTime& aDate) const +/** +Returns ETrue if aDate (Repeat Local Time) falls within a month generated by the the repeat algorithm for +the monthly repeat types. +@internalComponent +*/ + { + + TDateTime start = StartTimeAsRptLocalL().DateTime(); + if (((aDate.Month() + (12 * aDate.Year())) - + (start.Month() + (12 * start.Year()))) % iInterval) + { + return (EFalse); + } + return (ETrue); + } + + +void TAgnMonthlyRpt::NudgeNextMonthL(TTime& aDate) const +/** +Finds start of next valid month; doesnt change day if it is in valid month +In this case you dont want to risk returning a result prior to aDate +@internalComponent +*/ + { + + TDateTime next = aDate.DateTime(); + TDateTime start = StartTimeAsRptLocalL().DateTime(); + + TTimeIntervalMonths monthsSince = (next.Month() - start.Month()) + 12 * (next.Year() - start.Year()); // no months since repeat started + TTimeIntervalMonths nextValidMonth = ((monthsSince.Int()+Interval()-1)/Interval())*Interval(); + if (nextValidMonth > monthsSince) + { + AgnDateTime::AddTo(next,TTimeIntervalMonths(nextValidMonth.Int() - monthsSince.Int())); + next.SetDay(0); // set to start of month + aDate = TTime(next); + if (aDate > AgnDateTime::MaxDate()) + aDate = Time::NullTTime(); + } + } + +void TAgnMonthlyRpt::NudgePreviousMonthL(TTime& aDate) const +/** +Finds previous valid month; doesnt change day if it is in valid month +In this case you dont want to risk returning a result after aDate +@internalComponent +*/ + { + TDateTime prev = aDate.DateTime(); + TDateTime start = StartTimeAsRptLocalL().DateTime(); + TTimeIntervalMonths monthNo=prev.Month() - start.Month() + 12 * (prev.Year() - start.Year()); + TTimeIntervalMonths monthsSince=(monthNo.Int()/Interval())*Interval(); + + if (monthsSince.Int() < Abs(monthNo.Int()) || Abs(monthNo.Int() - monthsSince.Int()) == 11) + { + AgnDateTime::AddTo(prev,TTimeIntervalMonths(monthsSince.Int()-monthNo.Int())); + prev.SetDay(Time::DaysInMonth(prev.Year(),prev.Month())-1); // move to end of month + aDate = TTime(prev); + if (aDate < AgnDateTime::MinDate()) + aDate=Time::NullTTime(); + } + } + +TTime TAgnMonthlyRpt::NudgeNextInstanceUtcL(const TTime& aDate) const +/** +If aDate is already a date generated by the repeat algorithm then that is the date returned, +otherwise the next instance from aDate is returned +@internalComponent +*/ + { + TTime next = ConvertFromUtcToRepeatLocalL(aDate); + next = NudgeNextInstanceRptLocalL(next); + return ConvertFromRepeatLocalToUtcL(next); + } + +TTime TAgnMonthlyRpt::NudgeNextInstanceRptLocalL(const TTime& aDate) const +/** +If aDate is already a date generated by the repeat algorithm then that is the date returned, +otherwise the next instance from aDate is returned +@internalComponent +*/ + { + + TTime next = NudgeNextAlignedStartTimeL(aDate); + + if ( ! DateFallsInAlignedMonthL(next.DateTime()) || ! IsAlignedRptLocalL(next)) + { + NudgeNextMonthL(next); + if (next == Time::NullTTime()) + { + return (Time::NullTTime()); + } + while ( ! IsAlignedRptLocalL(next) ) + { + TTimeIntervalDays numDaysToNextInstance = NumDaysToNextInstanceFrom(next); + if (numDaysToNextInstance.Int()) + { + next = next + TTimeIntervalDays(numDaysToNextInstance.Int()); + } + else + // jump to the 1st day of the next month + { + TDateTime d1 = next.DateTime(); + TInt day = d1.Day(); + TInt daysInMonth = Time::DaysInMonth(d1.Year(),d1.Month()); + next = next + TTimeIntervalDays(daysInMonth - day); + } + TDateTime d2 = next.DateTime(); + if (d2.Day() == 0) // i.e. the 1st of the month + { + AgnDateTime::AddTo(d2,TTimeIntervalMonths(Interval()-1)); + next = TTime(d2); + } + if (next > AgnDateTime::MaxDate()) + { + return (Time::NullTTime()); + } + } + } + return next; + } + +TTime TAgnMonthlyRpt::NudgePreviousInstanceUtcL(const TTime& aDate) const +// +// If aDate is already a date generated by the repeat algorithm then that is the date returned, +// otherwise the previous instance is returned (UTC) +// + { + TTime prev = ConvertFromUtcToRepeatLocalL(aDate); + prev = NudgePreviousInstanceRptLocalL(prev); + return ConvertFromRepeatLocalToUtcL(prev); + } + +TTime TAgnMonthlyRpt::NudgePreviousInstanceRptLocalL(const TTime& aDate) const +// +// If aDate is already a date generated by the repeat algorithm then that is the date returned, +// otherwise the previous instance is returned (Repeat Local Time) +// + { + TTime prev = NudgePreviousAlignedStartTimeL(aDate); + if (!(IsAlignedRptLocalL(prev))) + { + if (Interval() > 1) + { + NudgePreviousMonthL(prev); + if (prev==Time::NullTTime()) + return (Time::NullTTime()); + if (IsAlignedRptLocalL(prev)) + return prev; + } + do + { + TDateTime prevTDateTime=prev.DateTime(); + if (prevTDateTime.Day()==0 && Interval() > 1) + { + AgnDateTime::AddTo(prevTDateTime,TTimeIntervalMonths(1-Interval())); + prev = TTime(prevTDateTime); + } + if (prev == AgnDateTime::MinDate()) + return (Time::NullTTime()); + prev -= TTimeIntervalDays(1); + } + while (!(IsAlignedRptLocalL(prev))); + } + return (prev); + } + + +// ------------------------------------- TAgnMonthlyByDaysRpt ------------------------- +EXPORT_C TAgnMonthlyByDaysRpt::TAgnMonthlyByDaysRpt(CAgnRptDef& aOwningRptDef) : + TAgnMonthlyRpt(aOwningRptDef) +/** Constructs a monthly by days repeat object. + +The repeat days are all cleared. + +@internalComponent +*/ + { + ClearAllDays(); + } + +EXPORT_C TAgnMonthlyByDaysRpt::TAgnMonthlyByDaysRpt(const TAgnMonthlyByDaysRpt& aRRule, CAgnRptDef& aOwningRptDef) : + TAgnMonthlyRpt(aRRule, aOwningRptDef) +/** Constructs a new TAgnMonthlyByDaysRpt object from an existing one. + +@internalComponent +@param aRRule The object to be copied. */ + { + for (TInt i = 0; i < KMonthlyByDaysArraySize; ++i) + { + iMonthlyRptDays[i] = aRRule.iMonthlyRptDays[i]; + } + } + +TAgnRpt::TType TAgnMonthlyByDaysRpt::Type() const + { + return TAgnRpt::EMonthlyByDays; + } + +void TAgnMonthlyByDaysRpt::ClearAllDays() +/** Clears all the monthly repeat days. + +@internalComponent +*/ + { + + iMonthlyRptDays[EFirst]=0; + iMonthlyRptDays[ESecond]=0; + iMonthlyRptDays[EThird]=0; + iMonthlyRptDays[EFourth]=0; + iMonthlyRptDays[ELast]=0; + } + +EXPORT_C void TAgnMonthlyByDaysRpt::SetDay(TDay aDay,TWeekInMonth aWeek) +/** Adds a day in the specified week to the repeat object. + +@internalComponent +@param aDay The day to be added. +@param aWeek The week in the month for the day to be added. */ + { + + __ASSERT_DEBUG(aWeek == EFirst || aWeek == ESecond || aWeek == EThird || aWeek == EFourth || aWeek == ELast, + Panic(EAgmErrInvalidWeekNumber)); + + iMonthlyRptDays[aWeek] |= MapDayToBits(aDay); + } + + +EXPORT_C TBool TAgnMonthlyByDaysRpt::IsDaySet(TDay aDay,TWeekInMonth aWeek) const +/** Tests whether a day is set as a repeat in the given week. + +@internalComponent +@param aDay The day to be tested for. +@param aWeek The week in the month. +@return True if set, False if not set. */ + { + + __ASSERT_DEBUG(aWeek == EFirst || aWeek == ESecond || aWeek == EThird || aWeek == EFourth || aWeek == ELast, + Panic(EAgmErrInvalidWeekNumber)); + + return (iMonthlyRptDays[aWeek]&(MapDayToBits(aDay))); + } + + +TInt TAgnMonthlyByDaysRpt::NumDaysSet() const +/** Gets the number of repeat days in the month. + +@internalComponent +@return The number of days set. */ + { + + TInt total = 0; + for (TUint i = EMonday; i <= ESunday; ++i) + { + for (TUint j = EFirst; j <= ELast; ++j) + { + if (IsDaySet(static_cast(i), static_cast(j))) + { + ++total; + } + } + } + + return (total); + } + + +TInt TAgnMonthlyByDaysRpt::NumInstancesPerMonth() const + { + return (NumDaysSet()); + } + +TInt TAgnMonthlyByDaysRpt::InvariantL() const +// +// Check that the rpt doesn't violate its invariants +// + { + + if (TAgnRpt::InvariantL()==KErrNone && NumDaysSet() > 0) + return (KErrNone); + + return (EAgmErrBadRepeat); + } + + + +void TAgnMonthlyByDaysRpt::InternalizeL(RReadStream& aStream) +/** Internalises the monthly by days repeat object from a read stream. + +@internalComponent +@param aStream Stream from which the object should be internalised. */ + { + + TAgnRpt::InternalizeL(aStream); + aStream >> iMonthlyRptDays[0]; + aStream >> iMonthlyRptDays[1]; + aStream >> iMonthlyRptDays[2]; + aStream >> iMonthlyRptDays[3]; + aStream >> iMonthlyRptDays[4]; + } + +void TAgnMonthlyByDaysRpt::ExternalizeL(RWriteStream& aStream) const +/** Externalises the monthly by days repeat object to a write stream. + +@internalComponent +@param aStream Stream to which the object should be externalised. */ + { + + TAgnRpt::ExternalizeL(aStream); + aStream << iMonthlyRptDays[0]; + aStream << iMonthlyRptDays[1]; + aStream << iMonthlyRptDays[2]; + aStream << iMonthlyRptDays[3]; + aStream << iMonthlyRptDays[4]; + } + +TBool TAgnMonthlyByDaysRpt::operator==(const TAgnMonthlyByDaysRpt& aRRule) const +/** Compares two monthly by day repeat objects for equality. + +@internalComponent +@param aRRule The object to be compared. +@return True if all repeat details agree, otherwise False. */ + { + + return (TAgnRpt::operator==(aRRule) + && iMonthlyRptDays[0]==aRRule.iMonthlyRptDays[0] + && iMonthlyRptDays[1]==aRRule.iMonthlyRptDays[1] + && iMonthlyRptDays[2]==aRRule.iMonthlyRptDays[2] + && iMonthlyRptDays[3]==aRRule.iMonthlyRptDays[3] + && iMonthlyRptDays[4]==aRRule.iMonthlyRptDays[4]); + } + +TBool TAgnMonthlyByDaysRpt::IsAlignedUtcL(const TTime& aDate) const + { + TTime localDate = ConvertFromUtcToRepeatLocalL(aDate); + return IsAlignedRptLocalL(localDate); + } + +TBool TAgnMonthlyByDaysRpt::IsAlignedRptLocalL(const TTime& aDate) const +// +// Returns true if aDate falls on an instance generated by the repeat algorithm +// (ignores repeat start/end dates) +// + { + + TDateTime dateTime=aDate.DateTime(); + + TInt weekNo=dateTime.Day()/7; + TDay day = aDate.DayNoInWeek(); + + // First check the first 4 weeks + if (weekNo < 4 && IsDaySet(day,(TWeekInMonth)weekNo)) + return (ETrue); + + // Now check if aDate is in the last week of the month + if ((dateTime.Day() >= Time::DaysInMonth(dateTime.Year(),dateTime.Month()) - 7) && (IsDaySet(day,ELast))) + { + if (HourAndMinutesDifferentFromStartTimeL(aDate)) + { + return EFalse; + } + + return (ETrue); + } + + return (EFalse); + } + + +TTimeIntervalDays TAgnMonthlyByDaysRpt::NumDaysToNextInstanceFrom(const TTime& aDay) const +// +// Calculates the number of days between aDay and the *next* day which is set, if there is no +// next day before the end of the month then 0 is returned. +// The calculation proceeds by first determining which week of the month aDay+1 is in and then +// checking the remainder of the days of that week, if an instance cannot be found then all days of +// any of the remaining first 4 weeks are checked, if an instance still hasn't been found than the last +// week is checked - this requires skipping backwards as the 4th and last weeks overlap and may coincide +// exactly in the case ofFebruary in a non-leap year. Further explanations of this are given later on +// nearer to the code. +// i.e. suppose aDay is Sunday of the 2nd week and the 1st day of the week is a Friday and +// there are 31 days in the month: +// F S S M T W T F S S M T W T F S S M T W T F S S M T W T F S S +// S <---4th week-> +// <--last week---> +// We start by checking in the 2nd week from Monday onwards until thursday is reached. If an instance +// hasn't been found then we move on to the 3rd week, checking from a Friday onwards until Thursday, +// if an instance hasn't been found the process is repeated with the 4th week. If an instance still hasn't +// been found then we must check the last week which means jumping backwards to what is effectively monday +// of the 4th week. + + { + + static const TInt startDayOfMonthFactor[8] = {EMonday,ESunday,ESaturday,EFriday,EThursday,EWednesday,ETuesday}; + + TInt nextDayFromTheParam = (aDay.DayNoInWeek() + 1) % 7; // checking is exclusive of aDay + TDateTime dateTime = aDay.DateTime(); + if (dateTime.Day() + 1 == Time::DaysInMonth(dateTime.Year(),dateTime.Month())) + return (0); // we're on the last day of the month + + TDateTime temp(dateTime); + temp.SetDay(0); + TTime temp2(temp); + TDay dayAtStartOfMonth = temp2.DayNoInWeek(); + + + // find out what week we're in: + TInt weekNo = (dateTime.Day() + 1) / 7; + + TInt numDaysToNextInstance = 1; + TInt currentDay = nextDayFromTheParam; + TInt numDaysInWeekToCheck; + TInt lowestNumDaysToNextInstanceSoFar = 0; + // the current week we're in may need partial checking + if (weekNo < 4) + { + numDaysInWeekToCheck = 7 - ((currentDay + startDayOfMonthFactor[dayAtStartOfMonth]) % 7); + for (; numDaysInWeekToCheck > 0; --numDaysInWeekToCheck) + { + if (IsDaySet((TDay)currentDay,(TWeekInMonth)weekNo)) + { + if (weekNo == 3) // the 4th week - don't return as this may be bettered by the last week - see later explanation + { + if (!lowestNumDaysToNextInstanceSoFar) + lowestNumDaysToNextInstanceSoFar = numDaysToNextInstance; + goto doincrement; + } + else + return (numDaysToNextInstance); + } +doincrement: + ++numDaysToNextInstance; + if (currentDay == (TInt)ESunday) + currentDay = (TInt)EMonday; + else + ++currentDay; + } + } + ++weekNo; + + // while subsequent weeks need full checking + currentDay = dayAtStartOfMonth; + for (numDaysInWeekToCheck = 7; weekNo < 4;) + { + if (IsDaySet((TDay)currentDay,TWeekInMonth(weekNo))) + { + if (weekNo == 3) // the 4th week - don't return as this may be bettered by the last week - see later explanation + { + if (!lowestNumDaysToNextInstanceSoFar) + lowestNumDaysToNextInstanceSoFar = numDaysToNextInstance; + goto increment; + } + else + return (numDaysToNextInstance); + } + else +increment: + { + ++numDaysToNextInstance; + if (currentDay == (TInt)ESunday) + currentDay = (TInt)EMonday; + else + ++currentDay; + if (numDaysInWeekToCheck == 1) + { + numDaysInWeekToCheck = 7; + ++weekNo; + } + else + --numDaysInWeekToCheck; + } + } + + + // if the 1st four weeks have been checked and nothing has been found or if + // we were in the last week to begin with then check the last week + + // As an example consider the end of January 1996 with Thursday of the last week being set ... + // 22 23 24 25 26 27 28 29 30 31 + // M T W T F S S M T W + // <------4th week------> + // <-------last week-----> + // + // So the 25th of Jan is an instance, suppose we have just checked the 4th week and + // having found no instances are currently positioned on the 29th. We now need to go + // back and check the last week, hence we need to jump to the 24th and check from there + // onwards until we find the 25th - consequently the numDaysToNextInstance needs decrementing + // 5 i.e the difference between 29 and 24. + // A complication arises if the search started from i.e. the 27th because in this case if + // we jump all the way back to the 24th to start the search it would wrongly flag the 25 + // as being the *next* instance from where the search starts from - this needs to be taken + // into consideration so that when we are jumping backwards from the 29th we only jump back + // as far as the 27 and hence just check the last 5 days in the last week and not all 7 of them + // + // Consider the following for another complication - in this case the 4th and last weeks coincide + // (this complication isn't limited to this case though) + // days set in 4th week: | | | + // F S S M T W T + // days set in last week: | | | + // In this case, if checking is from Saturday onwards then when the 4th week is being checked it will + // find Wednesday as the next occurrence - but the *next* occurrence is Saturday (of the last week). So + // Wednesday needs to be remembered in case it can't be bettered upon + + TInt daysInMonth = Time::DaysInMonth(dateTime.Year(),dateTime.Month()); + TInt dayNumOfTheParam = dateTime.Day() + 1; + TInt dayNumOf1stDayOfLastWeek = daysInMonth - 7; + TInt diffBetween1stDayOfLastWeekAndParam = 0; + if (dayNumOf1stDayOfLastWeek <= dayNumOfTheParam) + diffBetween1stDayOfLastWeekAndParam = dayNumOfTheParam - dayNumOf1stDayOfLastWeek; + + numDaysToNextInstance -= (7 - (daysInMonth - 28)); + numDaysToNextInstance += diffBetween1stDayOfLastWeekAndParam; + currentDay = ((TInt)dayAtStartOfMonth + daysInMonth - 7 + diffBetween1stDayOfLastWeekAndParam) % 7; // first day of last week is... + numDaysInWeekToCheck = 7 - diffBetween1stDayOfLastWeekAndParam; + while (numDaysInWeekToCheck > 0) + { + if (IsDaySet((TDay)currentDay,ELast)) + { + if (lowestNumDaysToNextInstanceSoFar && lowestNumDaysToNextInstanceSoFar < numDaysToNextInstance) + numDaysToNextInstance = lowestNumDaysToNextInstanceSoFar; + return (numDaysToNextInstance); + } + + if (currentDay == (TInt)ESunday) + currentDay = (TInt)EMonday; + else + ++currentDay; + --numDaysInWeekToCheck; + ++numDaysToNextInstance; + } + + return (lowestNumDaysToNextInstanceSoFar); + } + +/* + * Produces the week to check from a specified TTime (Repeat Local). + * + * @param "const TTime& aTime" + * The date to check + * @return "TWeekInMonth" + * The Week to check. If this week is EFourth, you should also check + * the last week ( ELast ). + */ +TAgnRpt::TWeekInMonth TAgnMonthlyByDaysRpt::GetWeekToCheckRptLocal(const TTime& aTime) const + { + return static_cast( aTime.DayNoInMonth() / 7 ); + } + +TBool TAgnMonthlyByDaysRpt::CheckLastWeekRptLocal(const TTime& aTime) const + { + TInt endOfMonth = aTime.DaysInMonth(); + TInt currentDay = aTime.DayNoInMonth(); + TInt startOfLastWeek = endOfMonth - 7; + return ( currentDay >= startOfLastWeek ); + } + + +/* + * Returns true, if the specified TTime is a day with an event on it. + * + * @param "const TTime& aTime" + * The date to check (Repeat Local) + * @return "TBool" + * ETrue if an event occurs on this date + * EFalse if not. + */ +TBool TAgnMonthlyByDaysRpt::EventOnDateRptLocal( const TTime& aTime ) const + { + TAgnRpt::TWeekInMonth weekInMonth = GetWeekToCheckRptLocal( aTime ); + TDay dayOfWeek = aTime.DayNoInWeek(); + TBool retval = EFalse; + + retval = IsDaySet( dayOfWeek, weekInMonth ); + + if (!retval && weekInMonth == TAgnRpt::EFourth && CheckLastWeekRptLocal(aTime)) + { + retval = IsDaySet( dayOfWeek, TAgnRpt::ELast ); + } + + return retval; + } + + +/* + * Find the last event on the specified month. + * + * + * @return "TTime" + * The date of the last event (Repeat Local). + * + */ +TTime TAgnMonthlyByDaysRpt::FindLastEventOnSpecifiedMonthRptLocal(const TTime& aTime) const + { + TTime dateCounter = aTime; + TTime retval = aTime; + TDateTime dateTime; + const TInt KEndDayOfMonth = aTime.DaysInMonth(); // last day of month,.. + const TInt KStartDayInMonth = aTime.DayNoInMonth(); // curent starting day in month + TInt counter = 0; + + for (counter = KEndDayOfMonth; counter > KStartDayInMonth; counter--) + { + dateTime = dateCounter.DateTime(); + dateTime.SetDay( counter ); + dateCounter = dateTime; + if ( EventOnDateRptLocal( dateCounter ) ) + { + retval = dateCounter; + break; + } + } + + return retval; + } + +// ------------------------------- TAgnMonthlyByDatesRpt ------------------------------------------------------ + +EXPORT_C TAgnMonthlyByDatesRpt::TAgnMonthlyByDatesRpt(CAgnRptDef& aOwningRptDef) : + TAgnMonthlyRpt(aOwningRptDef) +/** Constructs a monthly repeat by dates object. + +All monthly repeat dates are cleared. + +@internalComponent +*/ + { + iMonthlyRptDates = 0; + } + +EXPORT_C TAgnMonthlyByDatesRpt::TAgnMonthlyByDatesRpt(const TAgnMonthlyByDatesRpt& aRRule, CAgnRptDef& aOwningRptDef) : + TAgnMonthlyRpt(aRRule, aOwningRptDef) +/** Constructs a new TAgnMonthlyByDatesRpt object from an existing one. + +@internalComponent +@param aRRule The object to be copied. */ + { + iMonthlyRptDates = aRRule.iMonthlyRptDates; + } + +TAgnRpt::TType TAgnMonthlyByDatesRpt::Type() const + { + return TAgnRpt::EMonthlyByDates; + } + +EXPORT_C void TAgnMonthlyByDatesRpt::SetDate(TUint aDateInMonth) +/** Sets the date specified. + +@internalComponent +@param aDateInMonth The date to be added, (between 0 and 30 inclusive). */ + { + + iMonthlyRptDates |= MapDateToBits(aDateInMonth); + } + +EXPORT_C TBool TAgnMonthlyByDatesRpt::IsDateSet(TUint aDateInMonth) const +/** Tests whether the supplied date is set. + +@internalComponent +@param aDateInMonth The date to be tested for (between 0 and 30 inclusive). +@return True if set, False if not set. */ + { + + return (iMonthlyRptDates & (MapDateToBits(aDateInMonth))); + } + + +TInt TAgnMonthlyByDatesRpt::NumDatesSet() const +/** Gets the number of repeat dates in the month which are set. + +@internalComponent +@return The number of dates set. */ + { + TInt count = 0; + for (TUint i = 0; i <= 30; ++i) // check each date in a month + { + if (IsDateSet(i)) + { + ++count; + } + } + + return (count); + } + +TInt TAgnMonthlyByDatesRpt::NumInstancesPerMonth() const + { + return (NumDatesSet()); + } + +TInt TAgnMonthlyByDatesRpt::InvariantL() const +// +// Check that the rpt doesn't violate its invariants +// + { + if (TAgnRpt::InvariantL()==KErrNone && NumDatesSet() > 0) + return (KErrNone); + + return (EAgmErrBadRepeat); + } + + + +void TAgnMonthlyByDatesRpt::InternalizeL(RReadStream& aStream) +/** Internalises the monthly by date repeat object from a read stream. + +@internalComponent +@param aStream Stream from which the object should be internalised. */ + { + + TAgnRpt::InternalizeL(aStream); + aStream >> iMonthlyRptDates; + } + +void TAgnMonthlyByDatesRpt::ExternalizeL(RWriteStream& aStream) const +/** Externalises the monthly by date repeat object to a write stream. + +@internalComponent +@param aStream Stream to which the object should be externalised. */ + { + + TAgnRpt::ExternalizeL(aStream); + aStream << iMonthlyRptDates; + } + +TBool TAgnMonthlyByDatesRpt::operator==(const TAgnMonthlyByDatesRpt& aRRule) const +/** Compares two monthly by date repeat objects for equality. + +@internalComponent +@param aRRule The object to be compared. +@return True if all repeat details agree, otherwise False. */ + { + + return (TAgnRpt::operator==(aRRule) && iMonthlyRptDates==aRRule.iMonthlyRptDates); + } + +TBool TAgnMonthlyByDatesRpt::IsAlignedUtcL(const TTime& aDate) const +// +// Returns true is aDate (UTC) falls on a date generated by the repeat algorithm +// (ignores repeat start/end dates) +// + { + TTime localDate = ConvertFromUtcToRepeatLocalL(aDate); + return IsAlignedRptLocalL(localDate); + } + +TBool TAgnMonthlyByDatesRpt::IsAlignedRptLocalL(const TTime& aDate) const +// +// Returns true is aDate (Repeat Local Time) falls on a date generated by the repeat algorithm +// (ignores repeat start/end dates) +// + { + TDateTime date = aDate.DateTime(); + + TUint dayBit = MapDateToBits(date.Day()); + // If the date being checked is, for example, the 30th April and the repeat + // is set to repeat on the 31st of the month then this is still an aligned + // date so the high order bits in dayBit need setting to catch this i.e. + // if 30th april = 0001000... then this needs setting to 11110000 + if (date.Day() == Time::DaysInMonth(date.Year(),date.Month())-1) + { + dayBit =~ (dayBit-1); + } + + if ( ! (dayBit & iMonthlyRptDates)) + { + return EFalse; + } + + if (HourAndMinutesDifferentFromStartTimeL(aDate)) + { + return EFalse; + } + + return ETrue; + } + + +TTimeIntervalDays TAgnMonthlyByDatesRpt::NumDaysToNextInstanceFrom(const TTime& aDate) const +// +// Calculates the number of days between aDate and the *next* date which is set i.e. if +// the date in aDate is the 2nd of the month, and if the repeat is set to repeat on the +// 5th and 10th of the month then 3 is returned. If there is no subsequent date set then +// 0 is returned. +// + { + // Assumes aDate is expressed in Repeat Local Time + + TDateTime dateTime = aDate.DateTime(); + TUint daysInMonth = Time::DaysInMonth(dateTime.Year(),dateTime.Month()); + TUint dayInMonth = dateTime.Day() + 1; + for (TInt num=1; dayInMonth < 31;++dayInMonth) + { + if (IsDateSet(dayInMonth)) + return (num); + if (dayInMonth < daysInMonth-1) + // If the date being checked is, for example, the 30th April and the repeat + // is set to repeat on the 31st of the month then the number to return is the + // difference between 30 and aDate not 31 and aDate - hence num should not be + // incremented in this case + ++num; + } + return (0); + } + + +/* + * Find the last event on the first month if the rule begins. + * + * + * @return "TTime" (Repeat Local) + * The date of the last event. + * + */ +TTime TAgnMonthlyByDatesRpt::FindLastEventOnSpecifiedMonthRptLocal(const TTime& aTime) const + { + const TInt KEndDayOfMonth = aTime.DaysInMonth() - 1; // zero initialised + TTime retval = aTime; + TInt counter = 0; + TDateTime lastDay; + + for (counter = KEndDayOfMonth; counter >= 0; counter--) + { + if ( IsDateSet( counter ) ) + { + lastDay = retval.DateTime(); + lastDay.SetDay( counter ); + retval = lastDay; + break; + } + } + + return retval; + } + +// ------------------------------ TAgnYearlyByDateRpt ---------------------------- +EXPORT_C TAgnYearlyByDateRpt::TAgnYearlyByDateRpt(CAgnRptDef& aOwningRptDef) : + TAgnRpt(aOwningRptDef) +/** +This is not inline to prevent non-exportable functions causing a linker error in calling code + +@internalComponent +*/ + {} + +EXPORT_C TAgnYearlyByDateRpt::TAgnYearlyByDateRpt(const TAgnYearlyByDateRpt& aRRule, CAgnRptDef& aOwningRptDef) : + TAgnRpt(aRRule, aOwningRptDef) +/** Constructs a new TAgnYearlyByDateRpt object from an existing one. + +@internalComponent +@param aRRule The object to be copied. */ + {} + +TAgnRpt::TType TAgnYearlyByDateRpt::Type() const + { + return TAgnRpt::EYearlyByDate; + } + +TUint TAgnYearlyByDateRpt::InstanceCountL() const +/** Gets the number of instances generated by the repeat algorithm. + +@internalComponent +@return The number of instances. */ + { + // Years from start to end divided by the interval + // Add one for the first year: if start and end are in the same year, + // we must return 1. + return ( 1 + UntilTimeAsRptLocalL().YearsFrom(StartTimeAsRptLocalL()).Int()/iInterval ); + } + +TBool TAgnYearlyByDateRpt::IsAlignedRptLocalL(const TTime& aDate) const +// +// Returns true if aDate (Repeat Local Time) falls on an instance generated by the repeat algorithm +// (ignores repeat start/end dates) +// + { + // All date and time comparisons must be done in Repeat Local + + if (StartTimeAsRptLocalL() == aDate) + return (ETrue); + TDateTime startDateTime = StartTimeAsRptLocalL().DateTime(); + TDateTime thisDateTime = aDate.DateTime(); + if ( (thisDateTime.Year()-startDateTime.Year() ) % iInterval) + return (EFalse); + if (startDateTime.Month()!=thisDateTime.Month()) + return (EFalse); + if (startDateTime.Day()!=thisDateTime.Day()) + { + // finally check for 28/29th February + if (startDateTime.Month()!=EFebruary) + return (EFalse); + if (startDateTime.Day()!=28) + return (EFalse); + if (thisDateTime.Day()!=Time::DaysInMonth(thisDateTime.Year(),thisDateTime.Month())-1) + return (EFalse); + } + + if (HourAndMinutesDifferentFromStartTimeL(aDate)) + { + return EFalse; + } + + return ETrue; + } + +TBool TAgnYearlyByDateRpt::IsAlignedUtcL(const TTime& aUtcDate) const +// +// Returns true if aDate (UTC) falls on an instance generated by the repeat algorithm +// (ignores repeat start/end dates) +// + { + // convert aDate from UTC to Repeat Local + TTime rptLocalDate = ConvertFromUtcToRepeatLocalL(aUtcDate); + return IsAlignedRptLocalL(rptLocalDate); + } + +TTime TAgnYearlyByDateRpt::FindRptUntilTimeRptLocalL(TUint aCount) const + { + TTime end = StartTimeAsRptLocalL(); + TUint max = (AgnDateTime::MaxDate().YearsFrom(end).Int() + 1) / iInterval; + if (aCount > max) + { + end = AgnDateTime::MaxDate(); + } + else + { + end += TTimeIntervalYears((aCount - 1) * iInterval); + } + return end; + } + +TTime TAgnYearlyByDateRpt::NudgeNextInstanceUtcL(const TTime& aDate) const +// +// If aDate (UTC) is already a date generated by the repeat algorithm then that is the date returned, +// otherwise the next instance from aDate is returned +// + { + TTime rptLocalDate = ConvertFromUtcToRepeatLocalL(aDate); + rptLocalDate = NudgeNextInstanceRptLocalL(rptLocalDate); + return ConvertFromRepeatLocalToUtcL(rptLocalDate); + } + +TTime TAgnYearlyByDateRpt::NudgeNextInstanceRptLocalL(const TTime& aDate) const +// +// If aDate (Repeat Local Time) is already a date generated by the repeat algorithm then that is the date returned, +// otherwise the next instance from aDate is returned +// + { + TTime next = NudgeNextAlignedStartTimeL(aDate); + + if (IsAlignedRptLocalL(next)) + return (next); + + TDateTime thisTDateTime=next.DateTime(); + TDateTime startTDateTime=StartTimeAsRptLocalL().DateTime(); + + TTimeIntervalYears years=AgnDateTime::YearsFrom(startTDateTime,thisTDateTime); + // Add a year, since the next interval is at least one year away + // This fixes the 'yearly repeating entries on a leap year don't appear + // on the 29th Feb' bug + years = (years.Int() +1); + years=((years.Int()+Interval()-1)/Interval())*Interval(); + AgnDateTime::AddTo(startTDateTime,years); + + if (AgnDateTime::IsLessThan(startTDateTime,thisTDateTime)) + AgnDateTime::AddTo(startTDateTime,TTimeIntervalYears(Interval())); + + TTime date = TTime(startTDateTime); + if ( date > AgnDateTime::MaxDate()) + { + return (Time::NullTTime()); + } + + return date; + } + +TTime TAgnYearlyByDateRpt::NudgePreviousInstanceUtcL(const TTime& aDate) const +// +// If aDate (UTC) is already a date generated by the repeat algorithm then that is the date returned, +// otherwise the previous instance is returned +// + { + TTime rptLocalDate = ConvertFromUtcToRepeatLocalL(aDate); + rptLocalDate = NudgePreviousInstanceRptLocalL(rptLocalDate); + return ConvertFromRepeatLocalToUtcL(rptLocalDate); + } + +TTime TAgnYearlyByDateRpt::NudgePreviousInstanceRptLocalL(const TTime& aDate) const +// +// If aDate (Repeat Local Time) is already a date generated by the repeat algorithm then that is the date returned, +// otherwise the previous instance is returned +// + { + TTime prev = NudgePreviousAlignedStartTimeL(aDate); + + if (IsAlignedRptLocalL(prev)) + return (prev); + + TDateTime thisTDateTime = prev.DateTime(); + TDateTime startTDateTime = StartTimeAsRptLocalL().DateTime(); + + TTimeIntervalYears years=AgnDateTime::YearsFrom(startTDateTime,thisTDateTime); + + if (years.Int()>=(TInt)Interval()) + { + years=(years.Int()/Interval())*Interval(); + AgnDateTime::AddTo(startTDateTime,years); + } + + TTime date = TTime(startTDateTime); + if (date < AgnDateTime::MinDate()) + { + return (Time::NullTTime()); + } + + return date; + } + + +// ------------------------------ TAgnYearlyByDayRpt ---------------------------- +EXPORT_C TAgnYearlyByDayRpt::TAgnYearlyByDayRpt(CAgnRptDef& aOwningRptDef) : + TAgnRpt(aOwningRptDef) +/** +This is not inline to prevent non-exportable functions causing a linker error in calling code + +@internalComponent +*/ + { + iWeekInMonth = static_cast(0); + iDay = static_cast(0); + } + +EXPORT_C TAgnYearlyByDayRpt::TAgnYearlyByDayRpt(const TAgnYearlyByDayRpt& aRRule, CAgnRptDef& aOwningRptDef) : + TAgnRpt(aRRule, aOwningRptDef) +/** Constructs a new TAgnYearlyByDayRpt object from an existing one. + +@internalComponent +@param aRRule The object to be copied. */ + { + iWeekInMonth = aRRule.iWeekInMonth; + iDay = aRRule.iDay; + } + +TAgnRpt::TType TAgnYearlyByDayRpt::Type() const + { + return TAgnRpt::EYearlyByDay; + } + +TUint TAgnYearlyByDayRpt::InstanceCountL() const +/** Gets the number of yearly repeat instances. + +@internalComponent +@return The number of instances. */ + { + + TTime UntilTime = UntilTimeAsRptLocalL(); + TTime strtDate= StartTimeAsRptLocalL(); + for (TInt count = 1; count <= 7; ++count) + { + if (UntilTime.DayNoInWeek()==iDay) + break; + else + UntilTime -= TTimeIntervalDays(1); + } + + return 1 + ( (UntilTime.DateTime().Year() - strtDate.DateTime().Year()) /Interval()); + } + +TBool TAgnYearlyByDayRpt::IsAlignedUtcL(const TTime& aDate) const +// +// Returns true if aDate (UTC) falls on an instance generated by the repeat algorithm +// (ignores repeat start/end dates) +// + { + TTime rptLocalDate = ConvertFromUtcToRepeatLocalL(aDate); + return IsAlignedRptLocalL(rptLocalDate); + } + +TBool TAgnYearlyByDayRpt::IsAlignedRptLocalL(const TTime& aDate) const +// +// Returns true if aDate (Repeat Local Time) falls on an instance generated by the repeat algorithm +// (ignores repeat start/end dates) +// + { + + if (StartTimeAsRptLocalL() == aDate) + return (ETrue); + + TDateTime startDateTime = StartTimeAsRptLocalL().DateTime(); + TDateTime thisDateTime = aDate.DateTime(); + if ((thisDateTime.Year()-startDateTime.Year())%Interval()) + return (EFalse); + + if (startDateTime.Month()!=thisDateTime.Month()) + return (EFalse); + + if (aDate.DayNoInWeek()!=iDay) + return (EFalse); + + TInt dayInMonth = aDate.DayNoInMonth(); + switch (iWeekInMonth) + { + case EFirst: + { + if (dayInMonth > 6) + return (EFalse); + break; + } + case ESecond: + { + if (dayInMonth < 7 || dayInMonth > 13) + return (EFalse); + break; + } + case EThird: + { + if (dayInMonth < 14 || dayInMonth > 20) + return (EFalse); + break; + } + case EFourth: + { + if (dayInMonth < 21 || dayInMonth > 27) + return (EFalse); + break; + } + case ELast: + { + if (dayInMonth < aDate.DaysInMonth() - 7) + return (EFalse); + break; + } + default: + { + _DBGLOG_ENTRY(AgmDebug::DebugLog("TAgnYearlyByDayRpt: Panic - EAgmErrInvalidWeekNumber");) + DBG_PANIC(EAgmErrInvalidWeekNumber); + } + } + + if (HourAndMinutesDifferentFromStartTimeL(aDate)) + { + return EFalse; + } + + return (ETrue); + } + +TTime TAgnYearlyByDayRpt::FindRptUntilTimeRptLocalL(TUint aCount) const + { + // do all calculations in Repeat Local times, and convert to UTC before returning + + TUint max = AgnDateTime::MaxDate().YearsFrom(StartTimeAsRptLocalL()).Int(); + + TUint count = aCount > max ? max : aCount; + + TTime end=StartTimeAsRptLocalL(); + end+=TTimeIntervalYears((count-1)*Interval()); + + TDateTime dt = end.DateTime(); + TInt firstDay = GetFirstDayInWeekRptLocal(iWeekInMonth,dt.Month(),dt.Year()); + dt.SetDay(firstDay); + end = dt; + SetDateAccordingToDayRptLocal(end,iDay,iWeekInMonth); + + return end; + } + +TTime TAgnYearlyByDayRpt::NudgeNextInstanceUtcL(const TTime& aDate) const +// +// If aDate (UTC) is already a date generated by the repeat algorithm then that is the date returned, +// otherwise the next instance from aDate is returned. +// Complication: +// Suppose an entry starts on the 29 th of a month in year X +// 29 X .... 27 28 Y ..... 26 Z +// I I a I +// if aDate is 28th Y then because 26 Z is less than a year from a the calculation will be in +// error unless a is advanced to compensate. +// + { + TTime rptLocalDate = ConvertFromUtcToRepeatLocalL(aDate); + rptLocalDate = NudgeNextInstanceRptLocalL(rptLocalDate); + return ConvertFromRepeatLocalToUtcL(rptLocalDate); + } + +TTime TAgnYearlyByDayRpt::NudgeNextInstanceRptLocalL(TTime aDate) const +// +// If aDate (Repeat Local Time) is already a date generated by the repeat algorithm then that is the date returned, +// otherwise the next instance from aDate is returned. +// Complication: +// Suppose an entry starts on the 29 th of a month in year X +// 29 X .... 27 28 Y ..... 26 Z +// I I a I +// if aDate is 28th Y then because 26 Z is less than a year from a the calculation will be in +// error unless a is advanced to compensate. +// + { + TTime ttime = NudgeNextAlignedStartTimeL(aDate); + + for (TInt count = 1; count <= 7; ++count) + { + if (ttime.DayNoInWeek()==iDay) + break; + else + ttime += TTimeIntervalDays(1); + } + + if (ttime > AgnDateTime::MaxDate()) + return (Time::NullTTime()); + + aDate = ttime; + if (IsAlignedRptLocalL(aDate)) + return (aDate); + + TDateTime thisTDateTime = aDate.DateTime(); + TDateTime startTDateTime = StartTimeAsRptLocalL().DateTime(); + + TTimeIntervalYears years=AgnDateTime::YearsFrom(startTDateTime,thisTDateTime); + years=((years.Int()+Interval()-1)/Interval())*Interval(); + AgnDateTime::AddTo(startTDateTime,years); + + if (AgnDateTime::IsLessThan(startTDateTime,thisTDateTime)) + AgnDateTime::AddTo(startTDateTime,TTimeIntervalYears(Interval())); + + TInt firstDay = GetFirstDayInWeekRptLocal(iWeekInMonth,startTDateTime.Month(),startTDateTime.Year()); + startTDateTime.SetDay(firstDay); + ttime = startTDateTime; + SetDateAccordingToDayRptLocal(ttime,iDay,iWeekInMonth); + + if (ttime > AgnDateTime::MaxDate()) + return (Time::NullTTime()); + + return ttime; + } + +TTime TAgnYearlyByDayRpt::NudgePreviousInstanceUtcL(const TTime& aDate) const +// +// If aDate (UTC) is already a date generated by the repeat algorithm then that is the date returned, +// otherwise the previous instance is returned +// +// Complication: +// Suppose the repeat starts on the 1st of January year X and an instance is on 5th January year Y +// 1 X ........................1 2 3 4 5 6 7 8 Y +// s a b I d +// Now if bis choosen as the point to nudge from there is no problem, but suppose b is the date +// to nudge from then if the number of years between b and s is calculated the it will be 1 too many +// because a is more than 365 day after s (assuming Y = X + 1). So if aDate is b then it needs to be +// reduced to < a to find the correct previous instance. + { + TTime rptLocalDate = ConvertFromUtcToRepeatLocalL(aDate); + rptLocalDate = NudgePreviousInstanceRptLocalL(rptLocalDate); + return ConvertFromRepeatLocalToUtcL(rptLocalDate); + } + +TTime TAgnYearlyByDayRpt::NudgePreviousInstanceRptLocalL(TTime aDate) const +// +// If aDate (Repeat Local Time) is already a date generated by the repeat algorithm then that is the date returned, +// otherwise the previous instance is returned +// +// Complication: +// Suppose the repeat starts on the 1st of January year X and an instance is on 5th January year Y +// 1 X ........................1 2 3 4 5 6 7 8 Y +// s a b I d +// Now if bis choosen as the point to nudge from there is no problem, but suppose b is the date +// to nudge from then if the number of years between b and s is calculated the it will be 1 too many +// because a is more than 365 day after s (assuming Y = X + 1). So if aDate is b then it needs to be +// reduced to < a to find the correct previous instance. + + { + + TTime ttime = NudgePreviousAlignedStartTimeL(aDate); + for (TInt count = 1; count <= 7; ++count) + { + if (ttime.DayNoInWeek()==iDay) + break; + else + ttime -= TTimeIntervalDays(1); + } + + aDate = ttime; + if (IsAlignedRptLocalL(aDate)) + return (aDate); + + TDateTime thisTDateTime = aDate.DateTime(); + TDateTime startTDateTime = StartTimeAsRptLocalL().DateTime(); + + TTimeIntervalYears years=AgnDateTime::YearsFrom(startTDateTime,thisTDateTime); + + if (years.Int()>=(TInt)Interval()) + { + years=(years.Int()/Interval())*Interval(); + AgnDateTime::AddTo(startTDateTime,years); + } + + TInt firstDay = GetFirstDayInWeekRptLocal(iWeekInMonth,startTDateTime.Month(),startTDateTime.Year()); + startTDateTime.SetDay(firstDay); + ttime = startTDateTime; + SetDateAccordingToDayRptLocal(ttime,iDay,iWeekInMonth); + + if (ttime < AgnDateTime::MinDate()) + return (Time::NullTTime()); + + return ttime; + } + + +TInt TAgnYearlyByDayRpt::GetFirstDayInWeekRptLocal(TWeekInMonth aWeekInMonth,TMonth aMonth, TInt aYear) const +// +// Return the day number for the first day in the week aWeekInMonth +// + { + + TInt day=0; + switch (aWeekInMonth) + { + case EFirst: day= 0; break; + case ESecond: day= 7; break; + case EThird: day= 14; break; + case EFourth: day= 21; break; + case ELast: day= Time::DaysInMonth(aYear,aMonth) - 1; break; + default: + { + _DBGLOG_ENTRY(AgmDebug::DebugLog("TAgnYearlyByDayRpt: Panic - EAgmErrInvalidWeekNumber");) + DBG_PANIC(EAgmErrInvalidWeekNumber); + } + } + return (day); + } + +void TAgnYearlyByDayRpt::SetDateAccordingToDayRptLocal(TTime& aDate,TDay aDay,TWeekInMonth aWeekInMonth) const +// +// Adjust aDate (Repeat Local Time) until its day of the week (i.e. tuesday) corresponds with aDay +// + { + + for(TInt count = 1; count <= 7; ++count) + { + if (aDate.DayNoInWeek()==aDay) + break; + else + { + if (aWeekInMonth == ELast) + aDate -= TTimeIntervalDays(1); + else + aDate += TTimeIntervalDays(1); + } + } + } + + +EXPORT_C TTime TAgnYearlyByDayRpt::FindStartDayL(TDay aDay,TWeekInMonth aWeek,TMonth aMonth,TInt aYear) +/** Sets the repeat's start date using the details specified. These details are assumed to refer +to the time zone where the repeating activity takes place. + +@internalComponent +@param aDay The start day. +@param aWeek The start week in the month. +@param aMonth The start month. +@param aYear The start year. */ + { + + iWeekInMonth = aWeek; + iDay = aDay; + TInt dayInMonth=GetFirstDayInWeekRptLocal(aWeek,aMonth,aYear); + TDateTime startDT = StartTimeAsRptLocalL().DateTime(); + TTime date(TDateTime(aYear,aMonth,dayInMonth,startDT.Hour(),startDT.Minute(),startDT.Second(),startDT.MicroSecond())); + SetDateAccordingToDayRptLocal(date,aDay,aWeek); + return date; + } + +EXPORT_C void TAgnYearlyByDayRpt::GetStartDayL(TDay& aDay,TWeekInMonth& aWeek,TMonth& aMonth,TInt& aYear) const +/** Gets the start day, week, month and year for the current start date. These details refer +to the time zone where the repeating entry takes place, not the time zone where the user is. + +@internalComponent +@param aDay On return, the start day. +@param aWeek On return, the week in the month of the start date. +@param aMonth On return, the month of the start date. +@param aYear On return, the year of the start date. */ + { + + TTime date = StartTimeAsRptLocalL(); // Repeat Local + aDay = date.DayNoInWeek(); + aWeek = iWeekInMonth; + TDateTime dateTime = date.DateTime(); + aMonth = dateTime.Month(); + aYear = dateTime.Year(); + } + + +void TAgnYearlyByDayRpt::InternalizeL(RReadStream& aStream) +/** Internalises the yearly by day repeat object from a read stream. + +@internalComponent +@param aStream Stream from which the object should be internalised. */ + { + TAgnRpt::InternalizeL(aStream); + iWeekInMonth = TWeekInMonth(aStream.ReadUint8L()); + + iDay = TDay(aStream.ReadUint8L()); + } + +void TAgnYearlyByDayRpt::ExternalizeL(RWriteStream& aStream) const +/** Externalises the yearly by day repeat object to a write stream. + +@internalComponent +@param aStream Stream to which the object should be externalised. */ + { + TAgnRpt::ExternalizeL(aStream); + aStream.WriteUint8L(iWeekInMonth); + aStream.WriteUint8L(iDay); + } + + +TInt TAgnYearlyByDayRpt::InvariantL() const +// +// Check that the rpt doesn't violate its invariants +// + { + + + if (TAgnRpt::InvariantL()==KErrNone && (iWeekInMonth == EFirst || iWeekInMonth == ESecond + || iWeekInMonth == EThird || iWeekInMonth == EFourth || iWeekInMonth == ELast) && + (iDay == EMonday || iDay == ETuesday || iDay == EWednesday || iDay == EThursday || + iDay == EFriday || iDay == ESaturday || iDay == ESunday)) + return (KErrNone); + + return (EAgmErrBadRepeat); + } + + +// --------------------------------------- CAgnRptDef ------------------------------- + +CAgnRptDef::CAgnRptDef(const CAgnSimpleEntry& aOwningEntry) : + iOwningEntry(aOwningEntry) + { + } + +/** Gets the first instance of the repeat as a TAgnCalendarTime. +This is either the first sporadic date or the start of the repeat rule, whichever is earlier. + +@return The first instance of the repeat. +@internalComponent +*/ +EXPORT_C const TAgnCalendarTime& CAgnRptDef::FirstInstanceL() const + { + if (!HasRepeatRule() && !HasSporadicDates()) + { + User::Leave(KErrCorrupt); + } + + if (HasRepeatRule() && !HasSporadicDates()) + { + return StartTime(); + } + else if (!HasRepeatRule() && HasSporadicDates()) + { + return (*iSporadicDates)[0]; + } + + // has both rule and rdates + const TAgnCalendarTime& KRuleFirstDate = StartTime(); + const TAgnCalendarTime& KRdateFirstDate = (*iSporadicDates)[0]; + + return KRuleFirstDate < KRdateFirstDate ? KRuleFirstDate : KRdateFirstDate; + } + +/** Gets the last instance of the repeat as a TAgnCalendarTime. +This is either the last sporadic date or the end of the repeat rule, whichever is latest. + +@return The last instance of the repeat. +@internalComponent +*/ +EXPORT_C const TAgnCalendarTime& CAgnRptDef::LastInstanceL() const + { + if (!HasRepeatRule() && !HasSporadicDates()) + { + User::Leave(KErrCorrupt); + } + + if (HasRepeatRule() && !HasSporadicDates()) + { + return iRRule->UntilTimeL(); + } + else if (!HasRepeatRule() && HasSporadicDates()) + { + return (*iSporadicDates)[iSporadicDates->Count() - 1]; + } + + // has both rule and rdates + const TAgnCalendarTime& KRuleLastDate = iRRule->UntilTimeL(); + const TAgnCalendarTime& KRdateLastDate = (*iSporadicDates)[iSporadicDates->Count() - 1]; + return KRuleLastDate > KRdateLastDate ? KRuleLastDate : KRdateLastDate; + } + +EXPORT_C void CAgnRptDef::SetRRuleL(const TAgnRpt& aRRule) + { + CreateRptObjectL(aRRule); + } + +/** Create a Repeat Rule of the appropriate repeat rule type operator. +@param aRRule Repeat details. */ +void CAgnRptDef::CreateRptObjectL(const TAgnRpt& aRRule) + { + delete iRRule; + iRRule = NULL; + + switch (aRRule.Type()) + { + case TAgnRpt::EDaily: + iRRule = new (ELeave) TAgnDailyRpt( static_cast(aRRule), *this ); + break; + + case TAgnRpt::EWeekly: + iRRule = new (ELeave) TAgnWeeklyRpt( static_cast(aRRule), *this ); + break; + + case TAgnRpt::EMonthlyByDays: + iRRule = new (ELeave) TAgnMonthlyByDaysRpt( static_cast(aRRule), *this ); + break; + + case TAgnRpt::EMonthlyByDates: + iRRule = new (ELeave) TAgnMonthlyByDatesRpt( static_cast(aRRule), *this ); + break; + + case TAgnRpt::EYearlyByDate: + iRRule = new (ELeave) TAgnYearlyByDateRpt( static_cast(aRRule), *this ); + break; + + case TAgnRpt::EYearlyByDay: + iRRule = new (ELeave) TAgnYearlyByDayRpt( static_cast(aRRule), *this ); + break; + + default: + { + _DBGLOG_ENTRY(AgmDebug::DebugLog("CAgnRptDef: Panic - EAgmErrInvalidRptType");) + DBG_PANIC(EAgmErrInvalidRptType); + break; + } + } + } + +void CAgnRptDef::CreateRptObjectL(TAgnRpt::TType aType) +// +// Creates an object of the appropriate repeat rule type +// operator. +// + { + delete iRRule; + iRRule = NULL; + + switch (aType) + { + case TAgnRpt::EDaily: + iRRule = new (ELeave) TAgnDailyRpt(*this); + break; + + case TAgnRpt::EWeekly: + iRRule = new (ELeave) TAgnWeeklyRpt(*this); + break; + + case TAgnRpt::EMonthlyByDays: + iRRule = new (ELeave) TAgnMonthlyByDaysRpt(*this); + break; + + case TAgnRpt::EMonthlyByDates: + iRRule = new (ELeave) TAgnMonthlyByDatesRpt(*this); + break; + + case TAgnRpt::EYearlyByDate: + iRRule = new (ELeave) TAgnYearlyByDateRpt(*this); + break; + + case TAgnRpt::EYearlyByDay: + iRRule = new (ELeave) TAgnYearlyByDayRpt(*this); + break; + + default: + { + _DBGLOG_ENTRY(AgmDebug::DebugLog("CAgnRptDef: Panic - EAgmErrInvalidRptType");) + DBG_PANIC(EAgmErrInvalidRptType); + break; + } + } + + } + +EXPORT_C CAgnRptDef* CAgnRptDef::NewL(const CAgnSimpleEntry& aOwningEntry) +/** Allocates and constructs a repeat definition. + +@internalComponent +@return Pointer to the created repeat definition. */ + { + return new (ELeave) CAgnRptDef(aOwningEntry); + } + +EXPORT_C CAgnRptDef::~CAgnRptDef() +/** Frees all resources owned by the repeat definition, prior to +its destruction. + +@internalComponent +*/ + { + delete iRRule; + delete iTimeZone; + + ClearTimeArray(iSporadicDates); + ClearTimeArray(iExceptions); + } + +EXPORT_C void CAgnRptDef::AddExceptionL(const TAgnCalendarTime& aException) +/** Adds an exception to the list of exceptions (first creating the exception list +if necessary). + +@internalComponent +@param aException The exception to add to the list. */ + { + TAgnCalendarTime exceptionToAdd = aException; + + // MS Outlook exports exception dates without time information, i.e. time is reset to midnight. + // Need to nudge to see if a date occurs on that day. + if (!IsAnInstanceL(aException.LocalL())) + { + TTime exDateUtc = aException.UtcL(); + TTime actualInstanceTimeUtc; + if (NudgeNextInstanceUtcL(exDateUtc, actualInstanceTimeUtc)) + { + TTime exDateRepeatLocal = ConvertFromUtcToRepeatLocalL(exDateUtc); + TTime actualInstanceTimeRepeatLocal = ConvertFromUtcToRepeatLocalL(actualInstanceTimeUtc); + + // Only change exception date if nudged date is the same date in repeat local time + if (AgnDateTime::DaysBetweenDates(actualInstanceTimeRepeatLocal, exDateRepeatLocal) == 0) + { + if (aException.TimeMode() != MAgnCalendarTimeMode::EFloating) + { + exceptionToAdd.SetUtcL(actualInstanceTimeUtc); + } + else + { + exceptionToAdd.SetFloatingL(actualInstanceTimeRepeatLocal); + } + } + } + } + + if (IsAnInstanceL(exceptionToAdd.LocalL())) + { + EnsureTimeArrayExistsL(iExceptions); + TAgnCalendarTime::InsertInOrderL(*iExceptions, exceptionToAdd); + } + } + +EXPORT_C void CAgnRptDef::PruneExceptionsL() +/** Removes any exceptions which do not occur on instances +@internalComponent +*/ + { + if (iExceptions) + { + // iterate through exceptions in reverse order so that removing exceptions doesn't upset the order + for (TInt i = iExceptions->Count() - 1; i >= 0; --i) + { + const TAgnCalendarTime& KException = (*iExceptions)[i]; + if ( ! IsAnInstanceL(KException.LocalL())) + { + iExceptions->Remove(i); + } + } + if (iExceptions->Count() == 0) + { + iExceptions->Close(); + delete iExceptions; + iExceptions = NULL; + } + } + } + +EXPORT_C TBool CAgnRptDef::FindException(const TAgnCalendarTime& aException) const +/** Tests whether aException is in the exceptions list. + +@internalComponent +@param aException The exception. +@return ETrue = present, otherwise EFalse. */ + { + + if (iExceptions) + { + if (iExceptions->Find(aException) != KErrNotFound) + { + return ETrue; + } + } + return EFalse; + } + +EXPORT_C void CAgnRptDef::ClearTimeArray(RArray*& aTimeArray) + { + if (aTimeArray) + { + aTimeArray->Reset(); + delete aTimeArray; + aTimeArray = NULL; + } + } + +EXPORT_C void CAgnRptDef::RemoveAllExceptions() +/** Removes all the exceptions from the exception list. + +@internalComponent +*/ + { + ClearTimeArray(iExceptions); + } + +void CAgnRptDef::CopyTimeArrayL(const RArray* aSource, RArray*& aDestination) + { + ClearTimeArray(aDestination); + + if (aSource) + { + EnsureTimeArrayExistsL(aDestination); + + const TInt KNumTimes = aSource->Count(); + for (TInt i = 0; i < KNumTimes; ++i) + { + TAgnCalendarTime::InsertInOrderL(*aDestination, (*aSource)[i]); + } + } + } + +void CAgnRptDef::EnsureTimeArrayExistsL(RArray*& aTimeArray) + { + if ( ! aTimeArray) + { + aTimeArray = new (ELeave) RArray; + } + } + +EXPORT_C void CAgnRptDef::AddSporadicDateL(const TAgnCalendarTime& aSporadicDate) +/** Adds a sporadic date to the list of sporadic dates (first creating the sporadic date list +if necessary). + +@internalComponent +@param aSporadicDate The sporadic date to add to the list. */ + { + EnsureTimeArrayExistsL(iSporadicDates); + TAgnCalendarTime::InsertInOrderL(*iSporadicDates, aSporadicDate); + } + +TInt CAgnRptDef::FindSporadicDate(const TAgnCalendarTime& aSporadicDate) const +/** Tests whether aSporadicDate is in the sporadic dates list, using the sporadic date +as the find key. + +@internalComponent +@param aSporadicDate The sporadic dates. +@return ETrue = present, otherwise EFalse. */ + { + if (iSporadicDates) + { + return iSporadicDates->Find(aSporadicDate); + } + return KErrNotFound; + } + +void CAgnRptDef::RemoveSporadicDate(const TAgnCalendarTime& aSporadicDate) +/** Removes a sporadic date from the sporadic date list. + +If it is the last sporadic date in the list, the list is deleted. + +@internalComponent +@param aSporadicDate The sporadic date to be removed. +@return ETrue if the sporadic date was found and removed, otherwise EFalse. */ + { + + if (iSporadicDates) + { + TInt pos = FindSporadicDate(aSporadicDate); + if (pos != KErrNotFound) + { + iSporadicDates->Remove(pos); + if (iSporadicDates->Count() == 0) + { + ClearTimeArray(iSporadicDates); + } + } + } + } + +EXPORT_C void CAgnRptDef::RemoveAllSporadicDates() +/** Removes all the sporadic dates from the sporadic date list. + +@internalComponent +*/ + { + ClearTimeArray(iSporadicDates); + } + +EXPORT_C void CAgnRptDef::CopyL(const CAgnRptDef& aRptDef) +/** Copies the contents of a repeat definition into this object. + +@internalComponent +@param aRRule Pointer to the item to be copied. */ + { + if (aRptDef.HasRepeatRule()) + { + CreateRptObjectL(*aRptDef.iRRule); + } + + CopyTimeArrayL(aRptDef.iExceptions, iExceptions); + CopyTimeArrayL(aRptDef.iSporadicDates, iSporadicDates); + + if (aRptDef.iTimeZone != NULL) + { + if(iTimeZone == NULL) + { + iTimeZone = aRptDef.iTimeZone->CloneL(); + } + else + { + iTimeZone->CopyL(*aRptDef.iTimeZone); + } + TimeZoneChangedL(); + } + else + { + ResetTimeZone(); + } + } + +void CAgnRptDef::ResetTimeZone() + { + delete iTimeZone; + iTimeZone = NULL; + + if (iRRule) + { + iRRule->ResetCachedStartTimeOffset(); + iRRule->ResetCachedUntilTimeOffset(); + } + } + +TBool CAgnRptDef::operator==(const CAgnRptDef& aRptDef) const +/** Compares two repeat definitions for equality. + +This compares all repeat details, the repeat type and the exception list. + +@internalComponent +@param aRRule The repeat definition. +@return True if complete definitions agree, otherwise False. */ + { + + if (HasRepeatRule() && !aRptDef.HasRepeatRule() || !HasRepeatRule() && aRptDef.HasRepeatRule()) + { + return EFalse; + } + + if (aRptDef.HasRepeatRule()) + { + if (Type() != aRptDef.Type()) + { + return EFalse; + } + + switch (Type()) + { + case TAgnRpt::EDaily: + { + const TAgnDailyRpt* d1 = static_cast(RRule()); + const TAgnDailyRpt* d2 = static_cast(aRptDef.RRule()); + if (!(*d1 == *d2)) return EFalse; + } + break; + case TAgnRpt::EWeekly: + { + const TAgnWeeklyRpt* w1 = static_cast(RRule()); + const TAgnWeeklyRpt* w2 = static_cast(aRptDef.RRule()); + if (!(*w1 == *w2)) return EFalse; + } + break; + case TAgnRpt::EMonthlyByDays: + { + const TAgnMonthlyByDaysRpt* mp1 = static_cast(RRule()); + const TAgnMonthlyByDaysRpt* mp2 = static_cast(aRptDef.RRule()); + if (!(*mp1 == *mp2)) return EFalse; + } + break; + case TAgnRpt::EMonthlyByDates: + { + const TAgnMonthlyByDatesRpt* md1 = static_cast(RRule()); + const TAgnMonthlyByDatesRpt* md2 = static_cast(aRptDef.RRule()); + if (!(*md1 == *md2)) return EFalse; + } + break; + case TAgnRpt::EYearlyByDay: + { + const TAgnYearlyByDayRpt* yp1 = static_cast(RRule()); + const TAgnYearlyByDayRpt* yp2 = static_cast(aRptDef.RRule()); + if (!(*yp1 == *yp2)) return EFalse; + } + break; + case TAgnRpt::EYearlyByDate: + { + const TAgnYearlyByDateRpt* yd1 = static_cast(RRule()); + const TAgnYearlyByDateRpt* yd2 = static_cast(aRptDef.RRule()); + if (!(*yd1 == *yd2)) return EFalse; + } + break; + } + } + + if ( ! TAgnCalendarTime::CompareTimeArrays(Exceptions(), aRptDef.Exceptions()) ) + { + return EFalse; + } + + if ( ! TAgnCalendarTime::CompareTimeArrays(SporadicDateList(), aRptDef.SporadicDateList()) ) + { + return EFalse; + } + + return ETrue; + } + +TInt CAgnRptDef::InvariantL() const +/** +Check that the rpt doesn't violate its invariants +@internalComponent +*/ + { + // accept as valid if iRRule has not yet been set + if (iRRule == NULL) + { + return KErrNone; + } + + if (iRRule->InvariantL()==KErrNone) + { + return (KErrNone); + } + + return (EAgmErrBadRepeat); + } + + + +EXPORT_C void CAgnRptDef::ExternalizeL(RWriteStream& aStream, TBool aToBuffer) +/** Externalises the repeat definition to a write stream. + +@internalComponent +@param aStream Stream to which the object should be externalised. */ + { + __ASSERT_ALWAYS(InvariantL()==KErrNone, User::Leave(EAgmErrBadRepeat)); + + // Repeat Rule + if (HasRepeatRule()) + { + aStream.WriteUint8L(ETrue); + aStream.WriteUint8L(Type()); + aStream << *iRRule; + } + else + { + aStream.WriteUint8L(EFalse); + } + + // Exceptions + if (iExceptions) + { + aStream.WriteUint8L(ETrue); + TAgnCalendarTime::ExternalizeTimeArrayL(*iExceptions, aStream); + } + else + { + aStream.WriteUint8L(EFalse); + } + + // Sporadic Dates + if (iSporadicDates) + { + aStream.WriteUint8L(ETrue); + TAgnCalendarTime::ExternalizeTimeArrayL(*iSporadicDates, aStream); + } + else + { + aStream.WriteUint8L(EFalse); + } + + if (TimeMode() == MAgnCalendarTimeMode::EFloating) + {// no timezone rule for floating time mode + aStream.WriteUint8L(EFalse); + } + else + { + if (iTimeZone == NULL) + { // Set time Zone for fixed time mode + SetTimeZoneL(); + } + + aStream.WriteUint8L(ETrue); + if(aToBuffer) + { + iTimeZone->WriteToBufferL(aStream); + } + else + { + iTimeZone->ExternalizeL(aStream); + } + } + } + +void CAgnRptDef::InternalizeRepeatRuleL(RReadStream& aStream) + { + TBool hasRepeatRule = aStream.ReadUint8L(); + + // Repeat Rule + if (hasRepeatRule) + { + TAgnRpt::TType type = static_cast(aStream.ReadUint8L()); + + if (type < TAgnRpt::EDaily || type > TAgnRpt::EYearlyByDay) + { + User::Leave(KErrCorrupt); + } + + CreateRptObjectL(type); + aStream >> *iRRule; + } + } + +void CAgnRptDef::InternalizeExceptionsL(RReadStream& aStream) + { + ClearTimeArray(iExceptions); + + if (aStream.ReadUint8L()) + { + EnsureTimeArrayExistsL(iExceptions); + TAgnCalendarTime::InternalizeTimeArrayL(*iExceptions, aStream); + } + } + +void CAgnRptDef::InternalizeSporadicDatesL(RReadStream& aStream) + { + ClearTimeArray(iSporadicDates); + + if (aStream.ReadUint8L()) + { + EnsureTimeArrayExistsL(iSporadicDates); + TAgnCalendarTime::InternalizeTimeArrayL(*iSporadicDates, aStream); + } + } + +void CAgnRptDef::InternalizeTimeZoneL(RReadStream& aStream, TBool aFromBuffer) + { + // Time Zone + TBool hasTimeZone = aStream.ReadUint8L(); + ResetTimeZone(); + + if(hasTimeZone) + { + iTimeZone = CAgnTzRules::NewL(aStream, aFromBuffer); + TimeZoneChangedL(); + } + } + +EXPORT_C void CAgnRptDef::InternalizeL(RReadStream& aStream, TBool aFromBuffer) +/** Internalises the repeat definition from a read stream, including type, repeat +details and exception list. + +@internalComponent +@param aStream Stream from which the object should be internalised. */ + { + InternalizeRepeatRuleL(aStream); + InternalizeExceptionsL(aStream); + InternalizeSporadicDatesL(aStream); + InternalizeTimeZoneL(aStream, aFromBuffer); + + __ASSERT_ALWAYS(InvariantL()==KErrNone, User::Leave(KErrCorrupt)); + } + + +EXPORT_C TUint CAgnRptDef::InstanceCountL() const +/** Gets the number of repeat instances generated by the repeat algorithm, including +excepted instances. + +@internalComponent +@return The number of repeat instances. */ + { + TInt total((0)); + + if (HasRepeatRule()) + { + total = iRRule->InstanceCountL(); + } + else + { + total = 1;//count DtStart if there is no Repeat Rule + } + + if (HasSporadicDates()) + { + total = total + iSporadicDates->Count(); + } + + return total; + } + + +EXPORT_C TBool CAgnRptDef::IsAnUnexceptedInstanceL(const TTime& aDate) const +/** Tests whether aDate falls on an instance generated from the repeat algorithm or a sporadic date +which is not excepted. + +@internalComponent +@param aDate The system local date to be checked, expressed as Current System Local Time +@return True = the date falls on a non excepted instance, otherwise False. */ + { + // IsAnInstanceL() is exported, so it takes System Local Times. + if (!IsAnInstanceL(aDate)) + { + return EFalse; + } + // FindException() is exported, so it takes System Local Times.// + TAgnCalendarTime exceptionToFind; + if (TimeMode() == MAgnCalendarTimeMode::EFloating) + { + exceptionToFind.SetFloatingL(aDate); + } + else + { + exceptionToFind.SetLocalL(aDate); + } + if (FindException(exceptionToFind)) + { + return EFalse; + } + + return ETrue; + } + + +EXPORT_C TBool CAgnRptDef::IsAnInstanceL(const TTime& aDate) const +/** Tests whether aDate (System local time) falls on an instance generated from the repeat algorithm or on a sporadic date +including excepted items. + +Note: this function is not intended to be called by a view. + +@internalComponent +@param aDate The date to be checked, expressed as System Local Time +@return True = date falls on an instance, otherwise False. */ + { + return IsASporadicDateInstanceL(aDate) || IsARepeatRuleDateInstanceL(aDate) || (aDate == StartTime().LocalL()); + } + +EXPORT_C TBool CAgnRptDef::NudgeNextInstanceL(const TTime& aLocalDate, TTime& aLocalNext, TBool aCheckUnexcepted) const +/** Tests whether there is another repeat instance date after aDate (System local time), including excepted +instances and Sporadic Dates. + +If there is, it returns ETrue and sets aNext to it. If not, it returns +EFalse and sets aNext to the last valid instance date. If aDate is a valid +instance, then aNext is set to it, not the next instance. + +For example: + +If repeat instances fall on 10th Jan and 20th Jan, then if aDate = 10th Jan, +this function returns ETrue and sets aNext to 10th Jan. If aDate = 11th to 19th Jan, +it returns ETrue and sets aNext to 20th Jan. If aDate = 21st Jan, it returns EFalse +and sets aNext to 20th Jan. + +This function can leave. + +@internalComponent +@param aDate The date, expressed as System Local Time +@param aNext On return contains the date (in System Local Time) of the next instance if there is one, +or if not, the last valid instance date +@return True if there is a next instance, otherwise False. */ + { + TTime utcDate = AgnDateTime::ConvertToUtcTimeL(aLocalDate) + TTimeIntervalMicroSeconds(1); + + TBool retVal = NudgeInstanceForwardsUtcL(utcDate, aLocalNext, aCheckUnexcepted); + + if (retVal) + { + aLocalNext = AgnDateTime::ConvertToLocalTimeL(aLocalNext); + } + + return retVal; + } + +TBool CAgnRptDef::NudgeInstanceForwardsUtcL(const TTime& aUtcDate, TTime& aUtcNext, TBool aCheckExcepted) const + { + TBool retValue((EFalse)); + + // If there is a Rpt Rule and No Sporadic Dates + if (iRRule && !HasSporadicDates()) + { + retValue = NudgeNextRepeatInstanceUtcL(aUtcDate, aUtcNext, aCheckExcepted); + } + // else if there are Sporadic Dates and no Rpt Rule + else if (!iRRule && HasSporadicDates()) + { + retValue = NudgeNextSporadicInstanceUtcL(aUtcDate, aUtcNext, aCheckExcepted); + const TAgnCalendarTime& KFirstInstanceUtc = StartTime(); + if (aUtcDate <= KFirstInstanceUtc.UtcL() && + (KFirstInstanceUtc.UtcL() < aUtcNext || retValue == EFalse)) + { + if ( ! FindException(KFirstInstanceUtc)) + { + aUtcNext = KFirstInstanceUtc.UtcL(); + retValue = ETrue; + } + } + } + else if (iRRule && HasSporadicDates()) // there are both Sporadic Dates and a Rule + { + TTime rptNext; + TBool rptHasNext = NudgeNextRepeatInstanceUtcL(aUtcDate, rptNext, aCheckExcepted); + + TTime sporadicNext; + TBool sporadicHasNext = NudgeNextSporadicInstanceUtcL(aUtcDate, sporadicNext, aCheckExcepted); + + if (sporadicHasNext && !rptHasNext) + { + aUtcNext = sporadicNext; + retValue = ETrue; + } + else if (!sporadicHasNext && rptHasNext) + { + aUtcNext = rptNext; + retValue = ETrue; + } + else if (sporadicHasNext && rptHasNext) // both have a next instance. Return the valid date closest to aDate + { + aUtcNext = sporadicNext < rptNext ? sporadicNext : rptNext; + retValue = ETrue; + } + else // neither has a next instance return EFalse + { + retValue = EFalse; + } + } + return retValue; + } + + +TBool CAgnRptDef::NudgeNextRepeatInstanceUtcL(const TTime& aUtcDate, TTime& aUtcNext, TBool aConsiderExceptions) const + { + if (aUtcDate > iRRule->UntilTimeL().UtcL()) + { + return (EFalse); + } + + return aConsiderExceptions ? NudgeNextUnexceptedRepeatInstanceUtcL(aUtcDate, aUtcNext) : NudgeNextRepeatInstanceToNextValidInstanceUtcL(aUtcDate, aUtcNext); + } + + +TBool CAgnRptDef::NudgeNextRepeatInstanceToNextValidInstanceUtcL(const TTime& aUtcDate, TTime& aUtcNext) const + { + if (aUtcDate < StartTime().UtcL()) + { + aUtcNext = iRRule->NudgeNextInstanceUtcL(StartTime().UtcL()); + } + else + { + aUtcNext = iRRule->NudgeNextInstanceUtcL(aUtcDate); + } + + // if this is a valid instance that is the same as the one passed to the repeat rule's nudge + if (aUtcNext != Time::NullTTime() && aUtcNext < aUtcDate) + { + return EFalse; + } + + return aUtcNext != Time::NullTTime() && aUtcNext <= iRRule->UntilTimeL().UtcL() && aUtcNext >= StartTime().UtcL(); + } + + +TBool CAgnRptDef::NudgePreviousRepeatInstanceToPreviousValidInstanceUtcL(const TTime& aUtcDate, TTime& aUtcPrev) const + { + TTime dateUtc = aUtcDate; + if (aUtcDate > iRRule->UntilTimeL().UtcL()) + { + dateUtc = iRRule->UntilTimeL().UtcL(); + } + + aUtcPrev = iRRule->NudgePreviousInstanceUtcL(dateUtc); + + // if this is a valid instance, check that this is previous (time-wise) + if (aUtcPrev != Time::NullTTime() && aUtcPrev > aUtcDate) + { + return EFalse; + } + + return aUtcPrev != Time::NullTTime() && aUtcPrev <= iRRule->UntilTimeL().UtcL() && aUtcPrev >= StartTime().UtcL(); + } + +TBool CAgnRptDef::NudgeNextUnexceptedRepeatInstanceUtcL(const TTime& aUtcDate, TTime& aUtcNext) const + { + TTime currentDate = aUtcDate; + if (currentDate < StartTime().UtcL()) + { + currentDate = StartTime().UtcL(); + } + + TTime tmpLocalTime; + TTime next = aUtcNext; + FOREVER + { + if (!NudgeNextRepeatInstanceToNextValidInstanceUtcL(currentDate, next)) + { + return EFalse; + } + + TAgnCalendarTime candidateException; + if (TimeMode() == MAgnCalendarTimeMode::EFloating) + { + candidateException.SetFloatingL(AgnDateTime::ConvertToLocalTimeL(next)); + } + else + { + candidateException.SetUtcL(next); + } + if (FindException(candidateException)) + { + tmpLocalTime = AgnDateTime::ConvertToLocalTimeL(currentDate); + tmpLocalTime += static_cast(1); + currentDate = AgnDateTime::ConvertToUtcTimeL(tmpLocalTime); + } + else + { + aUtcNext = next; + return ETrue; + } + } + } + + +// aCheckExcepted indicates that sporadic dates that have exceptions are not to be considered as candidates +TBool CAgnRptDef::NudgeNextSporadicInstanceUtcL(const TTime& aUtcDate, TTime& aUtcNext, TBool aCheckExcepted) const + { + TAgnCalendarTime utcDate; + utcDate.SetUtcL(aUtcDate); + TBool retVal((EFalse)); + TBool moreCandidates((ETrue)); + TInt bestMatchPos((KErrNotFound)); + TInt pos((iSporadicDates->Count() - 1)); + + while (moreCandidates && pos >= 0) + { + // if the date is less than the sporadic array[pos] date + moreCandidates = (utcDate <= (*iSporadicDates)[pos--]); + + // if the sporadic array[pos] date is later than the KDate and if we are checking exceptions it is not excepted + const TAgnCalendarTime& KExceptionToFind = (*iSporadicDates)[pos + 1]; + if (moreCandidates && !(aCheckExcepted && FindException(KExceptionToFind))) + { + bestMatchPos = pos + 1; + } + } + + if (bestMatchPos != KErrNotFound) + { + retVal = ETrue; + aUtcNext = (*iSporadicDates)[bestMatchPos].UtcL(); + } + + return retVal; + } + + +EXPORT_C TBool CAgnRptDef::NudgePreviousUnexceptedInstanceL(const TTime& aLocalDate, TTime& aLocalPrev) const +/** Tests whether there is a repeat instance or sporadic date before aDate. + +If there is, it returns ETrue and sets aNext to it. If not, it returns EFalse +and sets aNext to the last valid instance date. If aDate is a valid instance, +then aNext is set to it, not the next instance. + +This function can leave. + +For example: + +If repeat instances fall on 10th Jan and 20th Jan, then if aDate = 20th Jan, +it returns ETrue and sets aNext to 20th Jan. If aDate = 11th to 19th Jan, it +returns ETrue and sets aNext to 10th Jan. If aDate = 9th Jan, it returns EFalse +and sets aNext to 10th Jan. + +@internalComponent +@param aDate The date (System Local Time). +@param aPrev On return contains the date (System Local Time) of the previous instance if there +is one, otherwise the first valid instance date. +@return True if there is a previous instance, otherwise false. */ + { + TTime utcDate = AgnDateTime::ConvertToUtcTimeL(aLocalDate) - TTimeIntervalMicroSeconds(1); + + TBool retVal = NudgeInstanceBackwardsUtcL(utcDate, aLocalPrev, ETrue); + + if (retVal) + { + aLocalPrev = AgnDateTime::ConvertToLocalTimeL(aLocalPrev); + } + + return retVal; + } + + +TBool CAgnRptDef::NudgeInstanceBackwardsUtcL(const TTime& aUtcDate, TTime& aUtcPrev, TBool aCheckExcepted) const + { + TBool retValue((EFalse)); + // If there is a Rpt Rule and No Sporadic Dates + if (iRRule && !HasSporadicDates()) + { + retValue = NudgePreviousRepeatInstanceUtcL(aUtcDate, aUtcPrev, aCheckExcepted); + } + // else if there are Sporadic Dates and no Rpt Rule + else if (!iRRule && HasSporadicDates()) + { + retValue = NudgePreviousSporadicInstanceUtcL(aUtcDate, aUtcPrev, aCheckExcepted); + const TAgnCalendarTime& KFirstInstanceUtc = StartTime(); + if (aUtcDate >= KFirstInstanceUtc.UtcL() && + (KFirstInstanceUtc.UtcL() > aUtcPrev || retValue == EFalse)) + { + if (! FindException(KFirstInstanceUtc)) + { + aUtcPrev = KFirstInstanceUtc.UtcL(); + retValue = ETrue; + } + } + } + else if (iRRule && HasSporadicDates()) + { + // there are both Sporadic Dates and a Rule + TTime rptPrevUtc; + TBool rptHasPrev = NudgePreviousRepeatInstanceUtcL(aUtcDate, rptPrevUtc, aCheckExcepted); + + TTime sporadicPrevUtc; + TBool sporadicHasPrev = NudgePreviousSporadicInstanceUtcL(aUtcDate, sporadicPrevUtc, aCheckExcepted); + + if (sporadicHasPrev && !rptHasPrev) + { + aUtcPrev = sporadicPrevUtc; + retValue = ETrue; + } + else if (!sporadicHasPrev && rptHasPrev) + { + aUtcPrev = rptPrevUtc; + retValue = ETrue; + } + else if (sporadicHasPrev && rptHasPrev) // both have a next instance. Return the valid date closest to aDate + { + aUtcPrev = sporadicPrevUtc > rptPrevUtc ? sporadicPrevUtc : rptPrevUtc; + retValue = ETrue; + } + else // neither have a next instance (under some circumstances repeat rules do not produce aNext. + // It is beleived that this is not used by the caller if this function returns EFalse + { + retValue = EFalse; + } + } + return retValue; + } + +TBool CAgnRptDef::NudgePreviousSporadicInstanceUtcL(const TTime& aUtcDate, TTime& aUtcPrev, TBool aCheckExcepted) const + { + TAgnCalendarTime utcTime; + utcTime.SetUtcL(aUtcDate); + const TInt KCount = iSporadicDates->Count(); + TBool retVal((EFalse)); + TBool moreCandidates((ETrue)); + TInt bestMatchPos((KErrNotFound)); + TInt pos((0)); + + while (moreCandidates && KCount > pos) + { + // if the date is more than the sporadic array[pos] date + moreCandidates = (utcTime >= (*iSporadicDates)[pos++]); + + // if the sporadic array[pos] date is less than the KDate and if we are checking exceptions and it is not excepted + const TAgnCalendarTime& KExceptionToFind = (*iSporadicDates)[pos - 1]; + if (moreCandidates && !(aCheckExcepted && FindException(KExceptionToFind))) + { + bestMatchPos = pos - 1; + } + } + + if (bestMatchPos != KErrNotFound) + { + retVal = ETrue; + aUtcPrev = (*iSporadicDates)[bestMatchPos].UtcL(); + } + + return retVal; + } + + +TBool CAgnRptDef::NudgePreviousRepeatInstanceUtcL(const TTime& aUtcDate, TTime& aUtcPrev, TBool aCheckExcepted) const + { + if (aUtcDate < StartTime().UtcL()) + { + return EFalse; + } + + return aCheckExcepted ? NudgePreviousUnexceptedRepeatInstanceUtcL(aUtcDate, aUtcPrev) : NudgePreviousRepeatInstanceToPreviousValidInstanceUtcL(aUtcDate, aUtcPrev); + } + + +TBool CAgnRptDef::NudgePreviousUnexceptedRepeatInstanceUtcL(const TTime& aUtcDate, TTime& aUtcPrev) const + { + TTime fromUtc = aUtcDate; + TTime prev = aUtcPrev; + if (fromUtc > iRRule->UntilTimeL().UtcL()) + { + fromUtc = iRRule->UntilTimeL().UtcL(); + } + TTime tmpLocalTime; + FOREVER + { + if (!NudgePreviousRepeatInstanceToPreviousValidInstanceUtcL(fromUtc, prev)) + { + return EFalse; + } + + TAgnCalendarTime candidateException; + if (TimeMode() == MAgnCalendarTimeMode::EFloating) + { + candidateException.SetFloatingL(AgnDateTime::ConvertToLocalTimeL(prev)); + } + else + { + candidateException.SetUtcL(prev); + } + if ( ! FindException(candidateException)) + { + aUtcPrev = prev; + return ETrue; + } + else + { + tmpLocalTime = AgnDateTime::ConvertToLocalTimeL(fromUtc); + tmpLocalTime -= static_cast(1); + fromUtc = AgnDateTime::ConvertToUtcTimeL(tmpLocalTime); + } + } + } + +EXPORT_C TBool CAgnRptDef::NudgeNextInstanceUtcL(const TTime& aDayUtc, TTime& aNextUtc) const +/** +@internalComponent +*/ + { + TTime utcNext; + TBool retVal = NudgeInstanceForwardsUtcL(aDayUtc, utcNext, EFalse); + if (retVal) + { + aNextUtc = utcNext; + } + return retVal; + } + +EXPORT_C TBool CAgnRptDef::NudgePreviousInstanceUtcL(const TTime& aDayUtc, TTime& aPrevUtc) const +/** +@internalComponent +*/ + { + TTime utcPrev; + TBool retVal = NudgeInstanceBackwardsUtcL(aDayUtc, utcPrev, EFalse); + if (retVal) + { + aPrevUtc = utcPrev; + } + return retVal; + } + +CAgnTlsProxy* CAgnRptDef::TimeZoneAccessor() + { + // The client session for the agenda server creates and stores the time + // zone accessor (which contains a session to the TZ server) in TLS. As + // long as this is called from the same trhead that created the session + // we can use the TZ server contained in the TZ accessor stored in TLS. + CAgnTlsProxy* timeZoneAccessor = static_cast(Dll::Tls()); + return timeZoneAccessor; + } + +EXPORT_C void CAgnRptDef::SetTimeZoneL(const CTzRules& aTimeZone) +/** Sets the time zone to aTimeZone + +@internalComponent +@param aTimeZone The time zone in which the repeat entry times are expressed. It contains a +collection of time zone rules. */ + { + __ASSERT_DEBUG(TimeMode() != MAgnCalendarTimeMode::EFloating, User::Leave(KErrNotSupported)); + ResetTimeZone(); + iTimeZone = CAgnTzRules::NewL(aTimeZone); + TimeZoneChangedL(); + } + +/** +* Sets the time zone to the current system time zone. Leaves with KErrGeneral +* if the time zone server could not be accessed. +*/ +EXPORT_C void CAgnRptDef::SetTimeZoneL() +/** +@internalComponent +*/ + { + __ASSERT_DEBUG(TimeMode() != MAgnCalendarTimeMode::EFloating, User::Leave(KErrNotSupported)); + ResetTimeZone(); + iTimeZone = CAgnTzRules::NewL(); + TimeZoneChangedL(); + } + +void CAgnRptDef::TimeZoneChangedL() + { + if (iRRule) + { + iRRule->ResetCachedStartTimeOffset(); + iRRule->ResetCachedUntilTimeOffset(); + } + } + +EXPORT_C CTzRules* CAgnRptDef::CloneTzRulesL() +/** Gets a copy of the time zone rules that apply to the repeat definition. + +@internalComponent +*/ + { + if (iTimeZone) + { + return iTimeZone->CloneTzRulesL(); + } + return NULL; + } + +TBool CAgnRptDef::IsARepeatRuleDateInstanceL(const TTime& aLocalDate) const + { + if (!HasRepeatRule()) + { + return EFalse; + } + + if (aLocalDate < StartTime().LocalL() || aLocalDate > iRRule->UntilTimeL().LocalL()) + { + return EFalse; + } + + + // convert aDate to UTC before passing it TAgnRpt::IsAlignedUtcL() + TTime utcDate = AgnDateTime::ConvertToUtcTimeL(aLocalDate); + return iRRule->IsAlignedUtcL(utcDate); + } + + +EXPORT_C TAgnRpt::TType CAgnRptDef::Type() const +/** Gets the repeat definition's type, as set by SetDaily(), SetWeekly() etc. + +@internalComponent +@return The repeat definition's type. */ + { + if (iRRule) + { + return iRRule->Type(); + } + return TAgnRpt::EDaily; + } + +TBool CAgnRptDef::IsASporadicDateInstanceL(const TTime& aLocalDate) const + { + if (!HasSporadicDates()) + { + return EFalse; + } + + TAgnCalendarTime instanceDate; + if (TimeMode() == MAgnCalendarTimeMode::EFloating) + { + instanceDate.SetFloatingL(aLocalDate); + } + else + { + instanceDate.SetLocalL(aLocalDate); + } + return (FindSporadicDate(instanceDate) != KErrNotFound); + } + +/** Returns ETrue if there is at least one sporadic date + +@internalComponent +@return if there is at least one sporadic date */ +TBool CAgnRptDef::HasSporadicDates() const + { + return (iSporadicDates && iSporadicDates->Count() != 0); + } + +/** Returns ETrue if there is a repeat rule + +@internalComponent +@return if there is a repeat rule */ +TBool CAgnRptDef::HasRepeatRule() const + { + return (iRRule != NULL); + } + +/** Clear the Repeat Rule only, leaving sporadic dates and exception dates intact +@internalComponent +*/ +void CAgnRptDef::ClearRRule() + { + delete iRRule; + iRRule = NULL; + } + +void CAgnRptDef::StartTimeChanged() + { + if (iRRule) + { + iRRule->ResetCachedStartTimeOffset(); + } + } + +const CTzRules* CAgnRptDef::TzRules() const + { + if(iTimeZone) + { + return iTimeZone->TzRules(); + } + + return NULL; + } + +EXPORT_C TTime CAgnRptDef::ConvertFromRepeatLocalToUtcL(const TTime& aRptLocalDate) const + { + if (TimeMode() != MAgnCalendarTimeMode::EFloating && TzRules()) + { + TTime utcDate = aRptLocalDate; + TzRules()->ConvertToUtcL(utcDate); + return utcDate; + } + + return AgnDateTime::ConvertToUtcTimeL(aRptLocalDate); + } + +EXPORT_C TTime CAgnRptDef::ConvertFromUtcToRepeatLocalL(const TTime& aUtcDate) const + { + if (TimeMode() != MAgnCalendarTimeMode::EFloating && TzRules()) + { + TTime rptLocalDate = aUtcDate; + TzRules()->ConvertToLocalL(rptLocalDate); + return rptLocalDate; + } + + return AgnDateTime::ConvertToLocalTimeL(aUtcDate); + } + +MAgnCalendarTimeMode::TTimeMode CAgnRptDef::TimeMode() const + { + return iOwningEntry.TimeMode(); + } + +EXPORT_C const TAgnRpt* CAgnRptDef::RRule() const +/** Gets a pointer to the repeat details. +@return Pointer to the repeat details +@internalComponent +*/ + { + return iRRule; + } + +EXPORT_C const RArray* CAgnRptDef::Exceptions() const +/** Gets a pointer to the repeat definition's exception list. +@return Pointer to the exception list. +@internalComponent +*/ + { + return iExceptions; + } + +EXPORT_C const RArray* CAgnRptDef::SporadicDateList() const +/** Gets a pointer to the repeat definition's sporadic date list. +@return Pointer to the sporadic date list. +@internalComponent +*/ + { + return iSporadicDates; + } + +const TAgnCalendarTime& CAgnRptDef::StartTime() const +/** Gets the start date expressed as Current System Local Time. +@internalComponent +@return The start date expressed as Current System Local Time. +*/ + { + return iOwningEntry.EntryTime(); + } + +EXPORT_C void CAgnRptDef::SetUntilTime(const TAgnCalendarTime& aUntilTime) + { + __ASSERT_ALWAYS(iRRule, Panic(EAgmErrNoRepeatRule)); + iRRule->SetUntilTime(aUntilTime); + } + +EXPORT_C void CAgnRptDef::SetInterval(TUint16 aInterval) + { + __ASSERT_ALWAYS(iRRule, Panic(EAgmErrNoRepeatRule)); + iRRule->SetInterval(aInterval); + } + +EXPORT_C CAgnTzRules* CAgnRptDef::AgnTzRules() const + { + return iTimeZone; + }