pimappservices/calendar/client/src/calinstanceiteratoruid.cpp
changeset 0 f979ecb2b13e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pimappservices/calendar/client/src/calinstanceiteratoruid.cpp	Tue Feb 02 10:12:19 2010 +0200
@@ -0,0 +1,440 @@
+// Copyright (c) 2007-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 "calinstanceiteratoruid.h"
+#include "calsessionimpl.h"
+#include "calinstance.h"
+#include "calinstanceimpl.h"
+#include "calentryimpl.h"
+#include "calclient.h"
+#include "agmrptdef.h"
+#include "agmentry.h"
+#include "agmsimpleentry.h"
+#include "calcommonimpl.h"
+#include "agmdate.h"
+
+/** Uid instance iterator NewL
+
+@internalComponent
+*/
+CCalInstanceIteratorUid* CCalInstanceIteratorUid::NewL(const CCalInstanceViewImpl& iInstanceViewImpl, const TDesC8& aGuid, const TCalTime& aStartInstance, TUint8 aShortFileId)
+	{
+	CCalInstanceIteratorUid* self = new(ELeave) CCalInstanceIteratorUid(iInstanceViewImpl);
+	CleanupStack::PushL(self);
+	self->ConstructL(aGuid, aStartInstance, aShortFileId);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+/** Uid instance iterator constructor
+
+@internalComponent
+*/
+CCalInstanceIteratorUid::CCalInstanceIteratorUid(const CCalInstanceViewImpl& iInstanceViewImpl)
+:CCalInstanceIterator(iInstanceViewImpl), iCurrentIndex(-1)
+	{
+	}
+
+/** Uid instance iterator ConstructL
+
+Fetches all the related entries to the UID and sets the currently indexed time
+
+@internalComponent
+*/
+void CCalInstanceIteratorUid::ConstructL(const TDesC8& aUid, const TCalTime& aInstanceTime, TCalCollectionId aCollectionId)
+	{
+	// record the time to use for undated todos
+	TTime now;
+	now.HomeTime();
+	iUndatedTodoTime.SetTimeLocalL(now);
+	
+	// Fetch all the entries that relate to the instance
+	RPointerArray<CAgnSimpleEntry> simpleEntries;
+	TCleanSimpleEntryArray cleanSimpleEntryArray(simpleEntries, iInstanceViewImpl.GetServ());
+	CleanupStack::PushL(TCleanupItem(CCalInstanceViewImpl::DestroySimpleEntryArray, &cleanSimpleEntryArray));
+	RArray<TInt> fileIds;
+	iInstanceViewImpl.GetShortFileIdLC(fileIds);//It is in order 
+	iInstanceViewImpl.GetServ().FetchSimpleEntriesByGuidL(aUid, simpleEntries, fileIds);
+	CleanupStack::PopAndDestroy(&fileIds);
+	
+	const TInt KEntryCount(simpleEntries.Count());
+	
+	// There must be entries associated with this UID
+	__ASSERT_ALWAYS(KEntryCount != 0, User::Leave(KErrNotFound));
+	
+	TBool instanceExists(EFalse);
+	
+	for (TInt i(0) ; i < KEntryCount ; ++i)
+		{
+		CCalLiteEntry* liteEntry = CCalLiteEntry::NewL(*simpleEntries[0], iInstanceViewImpl.GetServ());
+		liteEntry->IncrementRefCount();
+		simpleEntries.Remove(0);
+		TInt appendError = iCalLiteEntries.Append(liteEntry);	
+		if (appendError != KErrNone)
+			{
+			liteEntry->DecrementRefCount();
+			User::Leave(appendError);
+			}
+		
+		if (iInstanceViewImpl.IsValidInstanceL(liteEntry->LiteEntry(), aInstanceTime))
+			{//Add the index of the entry which has the same time as aInstanceTime into iEntryWithSameTime
+			if(liteEntry->LiteEntry().CollectionId() == aCollectionId)
+				{
+				instanceExists = ETrue;
+				iCurrentIndexTime = aInstanceTime;
+				iCurrentIndex = iEntryWithSameTime.Count();
+				}
+			iEntryWithSameTime.AppendL(i);
+			}
+		}
+	
+	__ASSERT_ALWAYS(instanceExists, User::Leave(KErrNotFound));
+	CleanupStack::PopAndDestroy(); // simpleEntries
+	}
+
+/** UID instance iterator destructor
+
+@internalComponent
+*/
+CCalInstanceIteratorUid::~CCalInstanceIteratorUid()
+	{
+	// should use CleanArray of LiteEntries 
+	const TInt KEntryCount(iCalLiteEntries.Count());
+	for (TInt i(0) ; i < KEntryCount ; ++i)
+		{
+		iCalLiteEntries[i]->DecrementRefCount(); 
+		}
+	
+	iCalLiteEntries.Close();
+	iEntryWithSameTime.Close();
+	}
+
+TCalTime CCalInstanceIteratorUid::NonRptEntryInstanceTimeL(const CAgnSimpleEntry& aEntry)
+	{	
+	// The entry does not have a repeat rule so it is just a single instance
+	TCalTime entryInstanceTime;
+	if (aEntry.Type() == CCalEntry::ETodo)
+		{
+		TTime completionDate = aEntry.CompletedDateUtc();
+		if (completionDate == Time::NullTTime())
+			{
+			if (!aEntry.EntryTime().IsSet())
+				{
+				entryInstanceTime = iUndatedTodoTime;
+				}
+			else
+				{
+				entryInstanceTime = CalUtils::TAgnCalendarTimeToTCalTimeL(aEntry.EntryTime());
+				}
+			}
+		else
+			{
+			if (aEntry.TimeMode() == MAgnCalendarTimeMode::EFloating)
+				{
+				entryInstanceTime.SetTimeLocalFloatingL(AgnDateTime::ConvertToLocalTimeL(completionDate));
+				}
+			else
+				{
+				entryInstanceTime.SetTimeUtcL(completionDate);
+				}
+			}
+		}
+	else
+		{
+		entryInstanceTime = CalUtils::TAgnCalendarTimeToTCalTimeL(aEntry.EntryTime());
+		}
+	
+	return entryInstanceTime;
+	}
+
+/** Returns the next instance
+
+Loops through all the entries in the cached entry list and finds
+the earliest instance that appears after the current index instance time.
+
+@return The next instance
+
+@internalComponent
+*/
+CCalInstance* CCalInstanceIteratorUid::NextL()
+	{
+	CCalInstance* retInstance = NULL;
+	TInt numSameTimeEntry = iEntryWithSameTime.Count();
+	if(numSameTimeEntry >0 && iCurrentIndex < numSameTimeEntry - 1)
+		{
+		//If there are entries in iEntryWithSameTime, their instance time is same as the iCurrentIndexTime, we should return this instance. 
+		return iInstanceViewImpl.CreateInstanceL(*iCalLiteEntries[iEntryWithSameTime[++iCurrentIndex]], iCurrentIndexTime);
+		}
+	
+	TCalTime bestSoFar;
+	bestSoFar.SetTimeUtcL(TCalTime::MaxTime());
+	TInt thisAgnSimpleEntryIndex(KErrNotFound);
+	
+	const TInt KEntryCount(iCalLiteEntries.Count());
+	TInt i(0);
+	for (; i < KEntryCount ; ++i)
+		{
+		TCalTime entryNextTime;
+		entryNextTime.SetTimeUtcL(TCalTime::MaxTime());
+		
+		CAgnRptDef* thisEntryRptDef = iCalLiteEntries[i]->LiteEntry().RptDef();
+		if (thisEntryRptDef)
+			{
+			TTime entryNextTimeUtc;
+			TBool instanceFound(EFalse);
+			TTime fromTimeUtc(iCurrentIndexTime.TimeUtcL() + TTimeIntervalMicroSeconds(1));
+			
+			do
+				{
+				// keep looping until we find an unexcepted instance or there are no more instances
+				instanceFound = thisEntryRptDef->NudgeNextInstanceUtcL(fromTimeUtc, entryNextTimeUtc);
+				fromTimeUtc = entryNextTimeUtc + TTimeIntervalMicroSeconds(1);
+				}
+			while (instanceFound && !thisEntryRptDef->IsAnUnexceptedInstanceL(AgnDateTime::ConvertToLocalTimeL(entryNextTimeUtc) ) );
+			
+			if (instanceFound)
+				{
+				entryNextTime.SetTimeUtcL(entryNextTimeUtc);
+				}
+			}
+		else
+			{
+			TCalTime entryInstanceTime = NonRptEntryInstanceTimeL(iCalLiteEntries[i]->LiteEntry());
+						
+			if (entryInstanceTime.TimeUtcL() > iCurrentIndexTime.TimeUtcL())
+				{
+				// The entry's instance time is after the current index time
+				// so it is a valid possible next instance
+				entryNextTime = entryInstanceTime;
+				}
+			}
+		
+		if (entryNextTime.TimeUtcL() < bestSoFar.TimeUtcL()) 
+			{
+			// This time is better than best time so far so update the best so far
+			bestSoFar = entryNextTime;
+			thisAgnSimpleEntryIndex = i;
+			iEntryWithSameTime.Reset();
+			iCurrentIndex = -1;
+			}
+		else if (entryNextTime.TimeUtcL() == bestSoFar.TimeUtcL() && entryNextTime.TimeUtcL()!= TCalTime::MaxTime())
+			{
+			//Store the index of the entry which has the instance time as the "bestSoFar" time
+			iEntryWithSameTime.AppendL(i);
+			}
+		}
+	
+	
+	if (bestSoFar.TimeUtcL() != TCalTime::MaxTime())
+		{
+		retInstance = iInstanceViewImpl.CreateInstanceL(*iCalLiteEntries[thisAgnSimpleEntryIndex], bestSoFar);
+		iCurrentIndexTime = bestSoFar;
+		}
+	
+	return retInstance;
+	}
+
+/** Returns the previous instance
+
+Loops through all the entries in the cached entry list and finds
+the latest instance that appears before the current index instance time.
+
+@return The previous instance
+
+@internalComponent
+*/
+CCalInstance* CCalInstanceIteratorUid::PreviousL()
+	{
+	CCalInstance* retInstance = NULL;
+	TInt numOfsameTimeInstance = iEntryWithSameTime.Count();
+	if(numOfsameTimeInstance > 0 && iCurrentIndex >= 1)
+		{
+		// we should return the last instance in the array to make it consistent with NextL which returns the first entry's instance.
+		return iInstanceViewImpl.CreateInstanceL(*iCalLiteEntries[iEntryWithSameTime[--iCurrentIndex]], iCurrentIndexTime);
+		}
+
+	TCalTime bestSoFar;
+	bestSoFar.SetTimeUtcL(TCalTime::MinTime());
+	TInt thisAgnSimpleEntryIndex(KErrNotFound);
+	
+	const TInt KEntryCount(iCalLiteEntries.Count());
+	TInt i(0);
+	for (; i < KEntryCount ; ++i)
+		{
+		TCalTime entryPreviousTime;
+		entryPreviousTime.SetTimeUtcL(TCalTime::MinTime());
+		
+		CAgnRptDef* thisEntryRptDef = iCalLiteEntries[i]->LiteEntry().RptDef();
+		
+		if (thisEntryRptDef)
+			{
+			TTime entryPreviousTimeUtc(iCurrentIndexTime.TimeUtcL());
+			TBool instancefound(EFalse);
+			TTime fromTimeUtc;
+			
+			do
+				{
+				fromTimeUtc = entryPreviousTimeUtc - TTimeIntervalMicroSeconds(1);
+				// keep calling until an unexcepted instance is found or there are no more instances
+				instancefound = thisEntryRptDef->NudgePreviousInstanceUtcL(fromTimeUtc, entryPreviousTimeUtc);
+				}
+			while (instancefound && !thisEntryRptDef->IsAnUnexceptedInstanceL(AgnDateTime::ConvertToLocalTimeL(entryPreviousTimeUtc) ) );
+			
+			if (instancefound)
+				{
+				entryPreviousTime.SetTimeUtcL(entryPreviousTimeUtc);
+				}
+			}
+		else
+			{
+			// The entry does not have a repeat rule so it is just a single instance
+			TCalTime entryInstanceTime = NonRptEntryInstanceTimeL(iCalLiteEntries[i]->LiteEntry());
+			
+			if (entryInstanceTime.TimeUtcL() < iCurrentIndexTime.TimeUtcL())
+				{
+				// The entry's instance time is before the current index time
+				// so it is a valid possible next instance
+				entryPreviousTime = entryInstanceTime;
+				}
+			}
+		
+		if (entryPreviousTime.TimeUtcL() > bestSoFar.TimeUtcL()) 
+			{
+			// This time is better than best time so far so update the best so far
+			bestSoFar = entryPreviousTime;
+			thisAgnSimpleEntryIndex = i;
+			iEntryWithSameTime.Reset();
+			iCurrentIndex = -1;
+			}
+		else if (entryPreviousTime.TimeUtcL() == bestSoFar.TimeUtcL() && entryPreviousTime.TimeUtcL()!= TCalTime::MinTime())
+			{
+			iEntryWithSameTime.AppendL(thisAgnSimpleEntryIndex);
+			thisAgnSimpleEntryIndex = i;
+			}
+		}
+	
+	if (bestSoFar.TimeUtcL() != TCalTime::MinTime())
+		{
+		retInstance = iInstanceViewImpl.CreateInstanceL(*iCalLiteEntries[thisAgnSimpleEntryIndex], bestSoFar);
+		iCurrentIndexTime = bestSoFar;
+		numOfsameTimeInstance = iEntryWithSameTime.Count();
+		if(numOfsameTimeInstance>0)
+			{
+			iCurrentIndex = numOfsameTimeInstance;
+			}
+		}
+		
+	return retInstance;
+	}
+
+/** To check if there are more instance to be returned by NextL().
+
+Calls NextL() to see if if returns another instance, and then sets the current
+indexed instance time back to what it was before the call. 
+
+@return ETrue if there are more instance to be returned by NextL(),
+EFalse if there are no more instance, and EFalse if there is a problem
+calculating if there are more instance to be returned by NextL().
+
+@internalComponent
+*/
+TBool CCalInstanceIteratorUid::HasMore() const
+	{
+	TBool returnValue(EFalse);
+	TRAP_IGNORE(returnValue = HasMoreL());
+	return returnValue;
+	}
+
+TBool CCalInstanceIteratorUid::HasMoreL() const
+	{
+	TBool returnValue(EFalse);
+
+	//Store the current state
+	TCalTime storedCurrentIndex = iCurrentIndexTime;
+	TInt storedArrayIndex = iCurrentIndex;
+	RArray<TInt> storedArray;
+	CleanupClosePushL(storedArray);
+	const TInt count = iEntryWithSameTime.Count();
+	for(TInt ii=0; ii<count;++ii)
+		{
+		storedArray.AppendL(iEntryWithSameTime[ii]);
+		}
+
+	//Find instances
+	CCalInstance* nextInstance = const_cast<CCalInstanceIteratorUid*>(this)->NextL();
+	returnValue = (nextInstance != NULL);
+	delete nextInstance;
+
+	// restore the state
+	const_cast<CCalInstanceIteratorUid*>(this)->iCurrentIndexTime = storedCurrentIndex; 
+	iCurrentIndex = storedArrayIndex;//reset index since it could be moved in NextL
+	iEntryWithSameTime.Reset();
+	const TInt countSortedArray = storedArray.Count();
+	for(TInt ii=0; ii<countSortedArray;++ii)
+		{
+		iEntryWithSameTime.AppendL(storedArray[ii]);
+		}
+
+	CleanupStack::PopAndDestroy(&storedArray);
+
+	return returnValue;
+	}
+
+/** Instance iterator count
+
+Loops through all the entries in the cached entry list and finds each of the instance counts.
+The instance count is the sum of all the entries instances.
+
+@return The sum of the instance counts for all the entries in the cached list. 
+
+@internalComponent
+*/
+TInt CCalInstanceIteratorUid::Count() const
+	{
+	TInt returnInstanceCount(0);
+	const TInt KEntryCount(iCalLiteEntries.Count());
+	for (TInt i(0) ; i < KEntryCount ; ++i)
+		{
+		CAgnRptDef* rptDef = iCalLiteEntries[i]->LiteEntry().RptDef();
+		if (rptDef)
+			{
+			// This gets all the instances generated by the repeat rule
+			TRAPD(error, returnInstanceCount += rptDef->InstanceCountL());
+			if (error)
+				{
+				// an error has occoured whilst calculating the instance count
+				// so quit and retrun the error code
+				returnInstanceCount = error;
+				break;
+				}
+			
+			// Need to take off valid exception dates
+			if (rptDef->Exceptions())
+				{
+				returnInstanceCount -= rptDef->Exceptions()->Count();
+				}
+			}
+		else
+			{
+			// The entry does not have a repeat rule
+			// so it is just a single instance
+			++returnInstanceCount;	
+			}
+		}
+	
+	return returnInstanceCount;
+	}
+
+