--- /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 <vtzrules.h>
+
+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<TUint8>(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<TDay>(i), static_cast<TWeekInMonth>(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<TAgnRpt::TWeekInMonth>( 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<TAgnRpt::TWeekInMonth>(0);
+ iDay = static_cast<TDay>(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<const TAgnDailyRpt&>(aRRule), *this );
+ break;
+
+ case TAgnRpt::EWeekly:
+ iRRule = new (ELeave) TAgnWeeklyRpt( static_cast<const TAgnWeeklyRpt&>(aRRule), *this );
+ break;
+
+ case TAgnRpt::EMonthlyByDays:
+ iRRule = new (ELeave) TAgnMonthlyByDaysRpt( static_cast<const TAgnMonthlyByDaysRpt&>(aRRule), *this );
+ break;
+
+ case TAgnRpt::EMonthlyByDates:
+ iRRule = new (ELeave) TAgnMonthlyByDatesRpt( static_cast<const TAgnMonthlyByDatesRpt&>(aRRule), *this );
+ break;
+
+ case TAgnRpt::EYearlyByDate:
+ iRRule = new (ELeave) TAgnYearlyByDateRpt( static_cast<const TAgnYearlyByDateRpt&>(aRRule), *this );
+ break;
+
+ case TAgnRpt::EYearlyByDay:
+ iRRule = new (ELeave) TAgnYearlyByDayRpt( static_cast<const TAgnYearlyByDayRpt&>(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<TAgnCalendarTime>*& 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<TAgnCalendarTime>* aSource, RArray<TAgnCalendarTime>*& 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<TAgnCalendarTime>*& aTimeArray)
+ {
+ if ( ! aTimeArray)
+ {
+ aTimeArray = new (ELeave) RArray<TAgnCalendarTime>;
+ }
+ }
+
+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<const TAgnDailyRpt*>(RRule());
+ const TAgnDailyRpt* d2 = static_cast<const TAgnDailyRpt*>(aRptDef.RRule());
+ if (!(*d1 == *d2)) return EFalse;
+ }
+ break;
+ case TAgnRpt::EWeekly:
+ {
+ const TAgnWeeklyRpt* w1 = static_cast<const TAgnWeeklyRpt*>(RRule());
+ const TAgnWeeklyRpt* w2 = static_cast<const TAgnWeeklyRpt*>(aRptDef.RRule());
+ if (!(*w1 == *w2)) return EFalse;
+ }
+ break;
+ case TAgnRpt::EMonthlyByDays:
+ {
+ const TAgnMonthlyByDaysRpt* mp1 = static_cast<const TAgnMonthlyByDaysRpt*>(RRule());
+ const TAgnMonthlyByDaysRpt* mp2 = static_cast<const TAgnMonthlyByDaysRpt*>(aRptDef.RRule());
+ if (!(*mp1 == *mp2)) return EFalse;
+ }
+ break;
+ case TAgnRpt::EMonthlyByDates:
+ {
+ const TAgnMonthlyByDatesRpt* md1 = static_cast<const TAgnMonthlyByDatesRpt*>(RRule());
+ const TAgnMonthlyByDatesRpt* md2 = static_cast<const TAgnMonthlyByDatesRpt*>(aRptDef.RRule());
+ if (!(*md1 == *md2)) return EFalse;
+ }
+ break;
+ case TAgnRpt::EYearlyByDay:
+ {
+ const TAgnYearlyByDayRpt* yp1 = static_cast<const TAgnYearlyByDayRpt*>(RRule());
+ const TAgnYearlyByDayRpt* yp2 = static_cast<const TAgnYearlyByDayRpt*>(aRptDef.RRule());
+ if (!(*yp1 == *yp2)) return EFalse;
+ }
+ break;
+ case TAgnRpt::EYearlyByDate:
+ {
+ const TAgnYearlyByDateRpt* yd1 = static_cast<const TAgnYearlyByDateRpt*>(RRule());
+ const TAgnYearlyByDateRpt* yd2 = static_cast<const TAgnYearlyByDateRpt*>(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<TAgnRpt::TType>(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<TTimeIntervalDays>(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<TTimeIntervalDays>(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<CAgnTlsProxy*>(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<TAgnCalendarTime>* 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<TAgnCalendarTime>* 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;
+ }