diff -r 000000000000 -r f979ecb2b13e pimappservices/calendar/server/src/agsextractor.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pimappservices/calendar/server/src/agsextractor.cpp Tue Feb 02 10:12:19 2010 +0200 @@ -0,0 +1,562 @@ +// 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 "agsextractor.h" + +#include "agmsimpleentry.h" +#include "agsentrymodel.h" +#include "agmrptdef.h" +#include "agmutil.h" +#include "agssortinstance.h" +#include "agsindex.h" +#include "agssort.h" + +// This represents the number of instances that have been found by a next or previous instance +// call that could, when sorted into order, appear before the search from instance +TInt gPossibleInstancesOutsideRange(0); + +// ----------------------------CAgnInstanceExtractor------------------------ +CAgnInstanceExtractor::CAgnInstanceExtractor(TAgnIterator* aIterator, CAgnEntryModel& aEntryModel) + :iEntryModel(aEntryModel), iIterator(aIterator) + { + __ASSERT_ALWAYS(aIterator, Panic(EAgmErrNullPointer)); + } + +CAgnInstanceExtractor::~CAgnInstanceExtractor() + { + delete iIterator; + } + +#ifdef SYMBIAN_SKIPPED_CALENDAR_ALARMS +/** Determines whether to continue the Find Instances search. +@param aAlarmedInstanceSearch Whether this is an alarmed instance search +@param aSearchRangeEndLocal The local time of the end of the search range +@internalComponent +*/ +TBool CAgnInstanceExtractor::ContinueSearchL(const TBool aAlarmInstanceSearch, const TTime& aSearchRangeEndLocal) const + { + TBool ret(ETrue); + if (aAlarmInstanceSearch) + { + ret = !iIterator->AtEnd(); + } + else + { + ret = !iIterator->AtEnd() + && ( (iIterator->CurrentElement().ValidFromTimeLocalL() == Time::NullTTime()) + || iIterator->CurrentElement().ValidFromTimeLocalL() <= aSearchRangeEndLocal); + } + return ret; + } + +/** Inserts an instance into an instance list. +@param aAlarmInstanceSearch Whether this is an alarmed instance search +@param aInstances The instance is inserted into this list +@param aInstance The instance to insert +@param aFindInstanceParams Defines the search range +@internalComponent +*/ +void CAgnInstanceExtractor::InsertInstanceL(const TBool aAlarmInstanceSearch, + CArrayFix& aInstances, + TAgnSortInstance& aInstance, + const TFindInstanceParams& aFindInstanceParams) const + { + if (aAlarmInstanceSearch) + { + if (aInstance.CheckAlarmTimeWithinL(aFindInstanceParams)) + { + TAgnAlarmSortKey sortKey; // Only needed for function call below + aInstances.InsertIsqAllowDuplicatesL(aInstance, sortKey); + } + } + else + { + if (aInstance.CheckStartAndEndDateOverlap(aFindInstanceParams)) + { + aInstances.AppendL(aInstance); + } + } + } +#endif + +/** Finds all instances in a time range that match the filter requirements + +@param aInstances The instance list to append instances to +@param aSearchParams The filter requirements for the instance search + +@internalComponent +*/ +void CAgnInstanceExtractor::FindInstancesL(CArrayFix& aInstances, const TFindInstanceParams& aSearchParams) + { + TTime searchRangeStartLocal(aSearchParams.iRangeStart.LocalL()); + TTime searchRangeEndLocal(aSearchParams.iRangeEnd.LocalL()); + + TTime startTime(searchRangeStartLocal); + +#ifdef SYMBIAN_SKIPPED_CALENDAR_ALARMS + TBool alarmInstanceSearch(EFalse); + alarmInstanceSearch = aSearchParams.iFilter.IsAlarmedInstanceSearch(); + if (alarmInstanceSearch) + { + iIterator->StartL(); + } + else + { + TTime startTime(searchRangeStartLocal); + iIterator->GotoL(startTime); + } + + TFindInstanceParams findInstanceParams(aSearchParams); + + for (; ContinueSearchL(alarmInstanceSearch, searchRangeEndLocal); iIterator->NextL()) + { + const CAgnSimpleEntry& KSimpleEntry(iIterator->CurrentElement()); + + if (alarmInstanceSearch) + { + searchRangeStartLocal = aSearchParams.iRangeStart.LocalL() + KSimpleEntry.AlarmOffset(); + searchRangeEndLocal = aSearchParams.iRangeEnd.LocalL() + KSimpleEntry.AlarmOffset(); + findInstanceParams.iRangeStart.SetLocalL(searchRangeStartLocal); + findInstanceParams.iRangeEnd.SetLocalL(searchRangeEndLocal); + } + + if(iEntryModel.MatchFullEntryL(KSimpleEntry.EntryId(), aSearchParams)) + { + const CAgnRptDef* KRptDef(KSimpleEntry.RptDef()); + if (KRptDef) + { + TTime instanceTime; + if (Filter()->RptNextInstanceOnly()) + { + // if this flag is set we only want the next instance after the start time + if (KRptDef->NudgeNextInstanceL(searchRangeStartLocal, instanceTime, ETrue) && instanceTime <= searchRangeEndLocal) + { + TAgnSortInstance instance(KSimpleEntry); + instance.SetL(instanceTime, UndatedTodoTime()); + InsertInstanceL(alarmInstanceSearch, aInstances, instance, findInstanceParams); + } + } + else + { + // nudge backwards from the end of the search range + TTime fromTime(AgnDateTime::ConvertToLocalTimeL(KSimpleEntry.DurationPlusL(AgnDateTime::ConvertToUtcTimeL(searchRangeEndLocal)) + TTimeIntervalMicroSeconds(1))); + while (KRptDef->NudgePreviousUnexceptedInstanceL(fromTime, instanceTime) + && (KSimpleEntry.DurationPlusL(instanceTime) >= searchRangeStartLocal) ) + { + TAgnSortInstance instance(KSimpleEntry); + instance.SetL(instanceTime, UndatedTodoTime()); + InsertInstanceL(alarmInstanceSearch, aInstances, instance, findInstanceParams); + fromTime = instanceTime; + } + } + } + else + { + // It is a non-repeating entry + TAgnSortInstance instance(KSimpleEntry); + instance.SetL(KSimpleEntry.EntryTime().LocalL(), UndatedTodoTime()); + InsertInstanceL(alarmInstanceSearch, aInstances, instance, findInstanceParams); + } + } + } + +#else + for (iIterator->GotoL(startTime); !iIterator->AtEnd() && ( (iIterator->CurrentElement().ValidFromTimeLocalL() == Time::NullTTime()) || iIterator->CurrentElement().ValidFromTimeLocalL() <= searchRangeEndLocal) ; iIterator->NextL()) + { + const CAgnSimpleEntry& KSimpleEntry(iIterator->CurrentElement()); + if(iEntryModel.MatchFullEntryL(KSimpleEntry.EntryId(), aSearchParams)) + { + const CAgnRptDef* KRptDef(KSimpleEntry.RptDef()); + if (KRptDef) + { + TTime instanceTime; + if (Filter()->RptNextInstanceOnly()) + { + // if this flag is set we only want the next instance after the start time + if (KRptDef->NudgeNextInstanceL(searchRangeStartLocal, instanceTime, ETrue) && instanceTime <= searchRangeEndLocal) + { + TAgnSortInstance instance(KSimpleEntry); + instance.SetL(instanceTime, UndatedTodoTime()); + if (instance.CheckStartAndEndDateOverlap(aSearchParams)) + { + aInstances.AppendL(instance); + } + } + } + else + { + // nudge backwards from the end of the search range + TTime fromTime(AgnDateTime::ConvertToLocalTimeL(KSimpleEntry.DurationPlusL(AgnDateTime::ConvertToUtcTimeL(searchRangeEndLocal)) + TTimeIntervalMicroSeconds(1))); + while (KRptDef->NudgePreviousUnexceptedInstanceL(fromTime, instanceTime) + && (KSimpleEntry.DurationPlusL(instanceTime) >= searchRangeStartLocal) ) + { + TAgnSortInstance instance(KSimpleEntry); + instance.SetL(instanceTime, UndatedTodoTime()); + if (instance.CheckStartAndEndDateOverlap(aSearchParams)) + { + aInstances.AppendL(instance); + } + fromTime = instanceTime; + } + } + } + else + { + // It is a non-repeating entry + TAgnSortInstance instance(KSimpleEntry); + instance.SetL(KSimpleEntry.EntryTime().LocalL(), UndatedTodoTime()); + if (instance.CheckStartAndEndDateOverlap(aSearchParams)) + { + aInstances.AppendL(instance); + } + } + } + } +#endif + } + + +// ----------------------------TAgnInstanceExtractor---------------------------- + +/** Instance extractor for all entry types + +@internalComponent +*/ +TAgnInstanceExtractor::TAgnInstanceExtractor(CAgnSimpleEntryTable& aEntryInfoTable) + :iSimpleEntryTable(&aEntryInfoTable) + { + } + +/** Instances are obtained from each index selected by the filter by mean of an extractor. + +The instances are returned in the order defined by TAgnDaySortKey + +@internalComponent +*/ +void TAgnInstanceExtractor::FindInstancesL(CArrayFix& aInstances, const TFindInstanceParams& aSearchParams) + { + + RArray indexList; + CleanupClosePushL(indexList); + + // Get the indexes of interest as per filter + // + iSimpleEntryTable->GetFilteredIndexListL(indexList, aSearchParams.iFilter); + + // Extract instances from each index (both floating and fixed time modes). + // Instances are extracted from each index of interest using a "extractor". + // The extractor is initialized with the particular index when "GetExtractor" is called. + // + const TInt KIndexCount = indexList.Count(); + for (TInt i = 0; i < KIndexCount; ++i) + { + iSimpleEntryTable->GetExtractor(indexList[i], MAgnCalendarTimeMode::EFloating, aSearchParams.iFilter, aSearchParams.iUndatedTodoTimeLocal)->FindInstancesL(aInstances, aSearchParams); + iSimpleEntryTable->GetExtractor(indexList[i], MAgnCalendarTimeMode::EFixedUtc, aSearchParams.iFilter, aSearchParams.iUndatedTodoTimeLocal)->FindInstancesL(aInstances, aSearchParams); + } + + CleanupStack::PopAndDestroy(&indexList); // Close() + } + +void TAgnInstanceExtractor::NextPossibleInstancesL(CArrayFix& aInstances, const TFindInstanceParams& aSearchParams) + { + RArray indexList; + CleanupClosePushL(indexList); + + // Get the indices of interest as per filter + iSimpleEntryTable->GetFilteredIndexListL(indexList, aSearchParams.iFilter); + + gPossibleInstancesOutsideRange = 0; + + const TInt KIndexCount = indexList.Count(); + for (TInt ii = 0; ii < KIndexCount; ++ii) + { + iSimpleEntryTable->GetExtractor(indexList[ii], MAgnCalendarTimeMode::EFloating, aSearchParams.iFilter, aSearchParams.iUndatedTodoTimeLocal)->NextInstancesL(aInstances, aSearchParams); + iSimpleEntryTable->GetExtractor(indexList[ii], MAgnCalendarTimeMode::EFixedUtc, aSearchParams.iFilter, aSearchParams.iUndatedTodoTimeLocal)->NextInstancesL(aInstances, aSearchParams); + } + CleanupStack::PopAndDestroy(&indexList); // Close() + } + +void TAgnInstanceExtractor::PreviousPossibleInstancesL(CArrayFix& aInstances, const TFindInstanceParams& aSearchParams) + { + RArray indexList; + CleanupClosePushL(indexList); + + // Get the indices of interest as per filter + iSimpleEntryTable->GetFilteredIndexListL(indexList, aSearchParams.iFilter); + + gPossibleInstancesOutsideRange = 0; + + const TInt KIndexCount = indexList.Count(); + for (TInt ii = 0 ; ii < KIndexCount ; ++ii) + { + iSimpleEntryTable->GetExtractor(indexList[ii], MAgnCalendarTimeMode::EFloating, aSearchParams.iFilter, aSearchParams.iUndatedTodoTimeLocal)->PreviousInstancesL(aInstances, aSearchParams); + iSimpleEntryTable->GetExtractor(indexList[ii], MAgnCalendarTimeMode::EFixedUtc, aSearchParams.iFilter, aSearchParams.iUndatedTodoTimeLocal)->PreviousInstancesL(aInstances, aSearchParams); + } + CleanupStack::PopAndDestroy(&indexList); // Close() + } +void CAgnInstanceExtractor::NextInstancesL(CArrayFix& aInstances, const TFindInstanceParams& aSearchParams) + { + const TTime KSearchFromTimeLocal(aSearchParams.iInstance.iId.Date().IsSet() ? aSearchParams.iInstance.iId.Date().LocalL() : aSearchParams.iUndatedTodoTimeLocal); + const TTime KSearchRangeEndLocal(aSearchParams.iRangeEnd.LocalL()); + + TTime searchFromTimeLocal(KSearchFromTimeLocal); + TTime lastMatchedTimeLocal(KSearchFromTimeLocal); + + TAgnDaySortKey sortKey(AgnDateTime::MaxDate(), UndatedTodoTime()); + + // This time is used so that we do not add instances to the list that are after + // the Nth one that has been found because we know that we will not need them + TTime NthInstanceTimeLocal(AgnDateTime::MaxDate()); + + TInt numInstancesFound(0); + + for (iIterator->GotoL(searchFromTimeLocal) ; !iIterator->AtEnd() && (iIterator->CurrentElement().ValidFromTimeLocalL() <= KSearchRangeEndLocal) && (iIterator->CurrentElement().ValidFromTimeLocalL() <= NthInstanceTimeLocal) ; iIterator->NextL()) + { + if ( aInstances.Count() > (aSearchParams.iNumInstances + gPossibleInstancesOutsideRange) ) + { + // We don't need instances after aSearchParams.iNumInstances + NthInstanceTimeLocal = aInstances.At(aSearchParams.iNumInstances + gPossibleInstancesOutsideRange).InstanceDate(); + } + + const CAgnSimpleEntry& KSimpleEntry(iIterator->CurrentElement()); + + if (iEntryModel.MatchFullEntryL(KSimpleEntry.EntryId(), aSearchParams)) + { + // find out where this instance is in the list + + if (KSimpleEntry.RptDef()) + { + // nudge backwards to find instances that over lap into the start of the range + // add a microsecond to the search from time so that we find instances that start exactly on the start range + TTime fromTime = AgnDateTime::ConvertToLocalTimeL(AgnDateTime::ConvertToUtcTimeL(KSearchFromTimeLocal) + TTimeIntervalMicroSeconds(1)); + TTime instanceTime; + + while (KSimpleEntry.RptDef()->NudgePreviousUnexceptedInstanceL(fromTime, instanceTime)) + { + TAgnSortInstance instance(KSimpleEntry); + instance.SetL(instanceTime, UndatedTodoTime()); + + if (instance.CheckStartAndEndDateOverlap(aSearchParams)) + { + aInstances.InsertIsqAllowDuplicatesL(instance, sortKey); + + // it is possible that this instance appears before + // the starting instance when sorted into order + ++gPossibleInstancesOutsideRange; + + if (!aSearchParams.iInstance.iId.IsNullId()) + { + // We are searching from a particular instance + // so one nudge backwards is good enough to get the search from instance + break; + } + } + else + { + // There are no more instances in the repeat that overlap into the start of the search range + break; + } + + fromTime = instanceTime; + } + + // Try to get the next n number of instances from the repeat rule + numInstancesFound = 0; + fromTime = KSearchFromTimeLocal; + while ( KSimpleEntry.RptDef()->NudgeNextInstanceL(fromTime, instanceTime, ETrue) + && aSearchParams.iNumInstances >= ++numInstancesFound + && KSimpleEntry.DurationMinusL(instanceTime) <= KSearchRangeEndLocal + && KSimpleEntry.DurationMinusL(instanceTime) <= NthInstanceTimeLocal ) + { + TAgnSortInstance instance(KSimpleEntry); + instance.SetL(instanceTime, UndatedTodoTime()); + + if (instance.CheckStartAndEndDateOverlap(aSearchParams)) + { + aInstances.InsertIsqAllowDuplicatesL(instance, sortKey); + } + + fromTime = instanceTime; + } + } + else + { + // It is a non-repeating entry + + TAgnSortInstance instance(KSimpleEntry); + instance.SetL(KSimpleEntry.EntryTime().LocalL(), UndatedTodoTime()); + + if ( lastMatchedTimeLocal > KSearchFromTimeLocal ) + { + // We now have any instances that are the same as the search from time + + if (++numInstancesFound > aSearchParams.iNumInstances) + { + // We now have the number of requested instances + + if (iIterator->CurrentKey() > lastMatchedTimeLocal) + { + // Break when all the instances that are at + // the same time as the last instance have been found + break; + } + } + } + + // Add the instance to the list + if (instance.CheckStartAndEndDateOverlap(aSearchParams)) + { + aInstances.InsertIsqAllowDuplicatesL(instance, sortKey); + lastMatchedTimeLocal = instance.InstanceDate(); + + if (lastMatchedTimeLocal == KSearchFromTimeLocal) + { + // it is possible that this instance appears before + // the starting instance when sorted into order + ++gPossibleInstancesOutsideRange; + } + } + } + } + } + } + +/** Finds the previous n number of instance that match the filter requirements + +The filter includes the time to search from and the search time range. + +@param aInstances The instance list to append instances to +@param aSearchParams The filter requirements for the instance search. This includes how many instances to find. + +@internalComponent +*/ +void CAgnInstanceExtractor::PreviousInstancesL(CArrayFix& aInstances, const TFindInstanceParams& aSearchParams) + { + const TTime KSearchFromTimeLocal(aSearchParams.iInstance.iId.Date().IsSet() ? aSearchParams.iInstance.iId.Date().LocalL() : aSearchParams.iUndatedTodoTimeLocal); + const TTime KSearchRangeStartLocal(aSearchParams.iRangeStart.LocalL()); + + TTime searchFromTime(KSearchFromTimeLocal); + TTime lastMatchedTime(KSearchFromTimeLocal); + + TAgnDaySortKey sortKey(AgnDateTime::MaxDate(), UndatedTodoTime()); + + // This time is used so that we do not add instances to the list that are after + // the Nth one that has been found because we know that we will not need them + TTime NthInstanceTime(AgnDateTime::MinDate()); + + TInt numInstancesFound(0); + + for (iIterator->GotoLessOrEqualL(searchFromTime) ; !iIterator->AtStart() ; iIterator->PreviousL()) + { + if ( aInstances.Count() > (aSearchParams.iNumInstances + gPossibleInstancesOutsideRange) ) + { + // We don't need instances after aSearchParams.iNumInstances + NthInstanceTime = aInstances.At( aInstances.Count() - 1 - (aSearchParams.iNumInstances + gPossibleInstancesOutsideRange) ).InstanceDate(); + } + + const CAgnSimpleEntry& KSimpleEntry(iIterator->CurrentElement()); + + if(iEntryModel.MatchFullEntryL(KSimpleEntry.EntryId(), aSearchParams)) + { + if (KSimpleEntry.RptDef()) + { + // find instances that overlap into the end of the range + TTime fromTime = AgnDateTime::ConvertToLocalTimeL(AgnDateTime::ConvertToUtcTimeL(KSearchFromTimeLocal) - TTimeIntervalMicroSeconds(1)); + TTime instanceTime; + + while (KSimpleEntry.RptDef()->NudgeNextInstanceL(fromTime, instanceTime, ETrue)) + { + // get instances that are the same as the start time + TAgnSortInstance instance(KSimpleEntry); + instance.SetL(instanceTime, UndatedTodoTime()); + if (instance.CheckStartAndEndDateOverlap(aSearchParams)) + { + aInstances.InsertIsqAllowDuplicatesL(instance, sortKey); + + ++gPossibleInstancesOutsideRange; + + if (!aSearchParams.iInstance.iId.IsNullId()) + { + // We are searching from a particular instance + // so one nudge forwards is good enough to get the search from instance + break; + } + } + else + { + break; + } + + fromTime = instanceTime; + } + + // find n number of instances in the past + numInstancesFound = 0; + fromTime = KSearchFromTimeLocal; + + while (KSimpleEntry.RptDef()->NudgePreviousUnexceptedInstanceL(fromTime, instanceTime) + && ++numInstancesFound <= aSearchParams.iNumInstances + && iIterator->CurrentElement().DurationPlusL(instanceTime) >= KSearchRangeStartLocal + && iIterator->CurrentElement().DurationPlusL(instanceTime) >= NthInstanceTime) + { + // get previous n number of instances before the start time + TAgnSortInstance instance(KSimpleEntry); + instance.SetL(instanceTime, UndatedTodoTime()); + + if (instance.CheckStartAndEndDateOverlap(aSearchParams)) + { + aInstances.InsertIsqAllowDuplicatesL(instance, sortKey); + } + + fromTime = instanceTime; + } + } + else + { + // This is a non-repeating entry + + TAgnSortInstance instance(KSimpleEntry); + instance.SetL(KSimpleEntry.EntryTime().LocalL(), UndatedTodoTime()); + + if (lastMatchedTime > KSearchFromTimeLocal) + { + // We now have all instances that are the same as the end time + if (++numInstancesFound > aSearchParams.iNumInstances) + { + if (lastMatchedTime > instance.InstanceDate()) + { + // We now have all instances that are the same as + // the nth instances before the end time + break; + } + } + } + + // Add the instance to the list + if (instance.CheckStartAndEndDateOverlap(aSearchParams)) + { + aInstances.InsertIsqAllowDuplicatesL(instance, sortKey); + lastMatchedTime = instance.InstanceDate(); + + if (lastMatchedTime == KSearchFromTimeLocal) + { + ++gPossibleInstancesOutsideRange; + } + } + } + } + } + } +