pimappservices/calendar/server/src/agsasyncdelete.cpp
changeset 0 f979ecb2b13e
child 12 38571fd2a704
child 45 b6db4fd4947b
equal deleted inserted replaced
-1:000000000000 0:f979ecb2b13e
       
     1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include "agsasyncdelete.h"
       
    17 
       
    18 #include "agsfilemanager.h"
       
    19 #include "agmentry.h"
       
    20 #include "agsentrymodel.h"
       
    21 #include "agmrptdef.h"
       
    22 #include "agmutil.h"
       
    23 #include "agssess.h"
       
    24 #include "agmdebug.h"
       
    25 
       
    26 const TUint KTidyCallbackRate = 24;
       
    27 const TInt KTidyArrayGranularity = 16;
       
    28 
       
    29 /**
       
    30 Used to sort a list of TAgnEntryIds by their stream id component - used when tidying
       
    31 */
       
    32 TInt CCalAsyncDelete::TStreamIdKey::Compare(TInt aLeft,TInt aRight) const
       
    33 	{
       
    34 	TUint32 left = static_cast<TAgnEntryId*>(At(aLeft))->StreamId().Value();
       
    35 	TUint32 right = static_cast<TAgnEntryId*>(At(aRight))->StreamId().Value();
       
    36 	TInt r = -1;
       
    37 	if (left == right)
       
    38 		{
       
    39 		r=0;
       
    40 		}
       
    41 	else if (left > right)
       
    42 		{
       
    43 		r=1;
       
    44 		}
       
    45 	return (r);
       
    46 	}
       
    47 
       
    48 CCalAsyncDelete::CCalAsyncDelete(CAgnEntryModel& aModel, TAgnChangeFilter& aChangeFilter, CAgnSimpleEntryTable& aEntryTable)
       
    49 	:iModel(aModel), iChangeFilter(aChangeFilter), iEntryTable(aEntryTable)
       
    50 	{
       
    51 	}
       
    52 
       
    53 void CCalAsyncDelete::ConstructL()
       
    54 	{
       
    55 	iAlreadyTidied = new(ELeave)CArrayFixFlat<TAgnEntryId>(KTidyArrayGranularity);
       
    56 	iTidyDeleteArray = new(ELeave)CArrayFixFlat<TAgnEntryId>(KTidyArrayGranularity);
       
    57 	}
       
    58 
       
    59 CCalAsyncDelete* CCalAsyncDelete::NewL(CAgnEntryModel& aModel, TAgnChangeFilter& aChangeFilter, CAgnSimpleEntryTable& aEntryTable)
       
    60 	{
       
    61 	CCalAsyncDelete* self = new(ELeave) CCalAsyncDelete(aModel, aChangeFilter, aEntryTable);
       
    62 	CleanupStack::PushL(self);
       
    63 	self->ConstructL();
       
    64 	CleanupStack::Pop(self);
       
    65 	return self;
       
    66 	}
       
    67 
       
    68 CCalAsyncDelete::~CCalAsyncDelete()
       
    69 	{
       
    70 	delete iTidyIter;
       
    71 	delete iAlreadyTidied;
       
    72 	delete iTidyDeleteArray;
       
    73 	}
       
    74 
       
    75 /**
       
    76 Determines if an instance of an entry falls within the tidy range.
       
    77 */
       
    78 TBool CCalAsyncDelete::IsEntryValidToTidyL(const CAgnSimpleEntry& aSimpleEntry)
       
    79 	{
       
    80 	// non-repeating entries must fall in the time range because otherwise the entry iterator wouldn't find them
       
    81 	if (aSimpleEntry.RptDef())
       
    82 		{
       
    83 		TTime instance;
       
    84 		if ( ! aSimpleEntry.RptDef()->NudgeNextInstanceL(iTidyStartDate, instance, ETrue))
       
    85 		    {
       
    86             // If the parent is repeating but all its instances are excepted it doesn't mean 
       
    87             // that it cannot be deleted. It can if its time range is falling 
       
    88             // within the time filter, meaning the parent is safe to tidy as 
       
    89             // the child entries are already in the tidy up list.
       
    90             if (aSimpleEntry.RptDef()->FirstInstanceL().LocalL() < iTidyStartDate || 
       
    91                 aSimpleEntry.RptDef()->LastInstanceL().LocalL() > iTidyEndDate)
       
    92                 {
       
    93                 return (EFalse);
       
    94                 }
       
    95             else
       
    96                 {
       
    97                 return (ETrue);
       
    98                 }
       
    99             }
       
   100 		
       
   101         if (instance < iTidyStartDate || instance > iTidyEndDate)
       
   102             {
       
   103             return (EFalse);
       
   104             }
       
   105         }
       
   106     return (ETrue);
       
   107     }
       
   108 
       
   109 
       
   110 /**
       
   111 Calculate the number of entries to be tidied (so the percentage tidied so far
       
   112 can be determined) and create and required objects.
       
   113 @capability WriteUserData
       
   114 @capability ReadUserData
       
   115 */
       
   116 TBool CCalAsyncDelete::SetUpDeleteL(const TAgnFilter& aFilter, const TTime& aTodaysDate, const TTime& aStartDate, const TTime& aEndDate)
       
   117 	{
       
   118 	iTidyStartDate = aStartDate;
       
   119 	iTidyEndDate = aEndDate;
       
   120 	iTidyDate = iTidyStartDate;
       
   121 
       
   122 	#if defined (__CAL_ASYNC_LOGGING__) || (__CAL_VERBOSE_LOGGING__)
       
   123 		{
       
   124 		TBuf<KMinTTimeStrLength> tidyEndDateTimeBuf;
       
   125 		AgmDebug::TTimeStrL(iTidyEndDate, tidyEndDateTimeBuf);
       
   126 		TBuf<KMinTTimeStrLength> tidyStartDateTimeBuf;
       
   127 		AgmDebug::TTimeStrL(iTidyStartDate, tidyStartDateTimeBuf);
       
   128 		AgmDebug::DebugLog("Async Delete: Range From %S To %S", &tidyStartDateTimeBuf, &tidyEndDateTimeBuf);
       
   129 		}
       
   130 	#endif
       
   131 		
       
   132 	iNumEntriesToProcess = 0;
       
   133 	delete iTidyIter;
       
   134 	iTidyIter = NULL;
       
   135 	
       
   136 	iTidyIter = new(ELeave) TAgnEntryDateIterator(iEntryTable, aTodaysDate, aFilter);
       
   137 	
       
   138 	for (iTidyIter->GotoL(iTidyStartDate); !iTidyIter->AtEnd() && iTidyIter->CurrentKey() <= iTidyEndDate; iTidyIter->NextL())
       
   139 		{
       
   140 		if (IsEntryValidToTidyL(iTidyIter->CurrentElement()))
       
   141 			{
       
   142 			++iNumEntriesToProcess;
       
   143 			}
       
   144 		}
       
   145 	
       
   146 	if (!iNumEntriesToProcess)
       
   147 		{ // there are no entries to tidy that match the date/filter criteria
       
   148 		return (EFalse); 
       
   149 		}
       
   150 
       
   151 	iNumEntriesProcessed = 0;
       
   152 	return (ETrue);
       
   153 	}
       
   154 
       
   155 TBool CCalAsyncDelete::CheckDateIteratorEnd() const
       
   156 	{
       
   157 	return ( ! iTidyIter->AtEnd() && iTidyIter->CurrentKey() <= iTidyEndDate);
       
   158 	}
       
   159 
       
   160 /**
       
   161 Tidy the agenda model and return the progress as a percentage of the number of entries tidied so far.
       
   162 Returns 0 when the tidy has completed.
       
   163 The callback frequency and percentage completed are based on the number of entries tidied so far out
       
   164 of the total number of entreis that match the tidy filter and date range. But as the iterator may be
       
   165 position half-way through the entries for a day when a callback is due to be made then its necessary
       
   166 to continue processing till the end of that day before the callback is made - this is so that next time
       
   167 round the same entries aren't processed twice.
       
   168 
       
   169 @capability WriteUserData
       
   170 @capability ReadUserData
       
   171 */
       
   172 TInt CCalAsyncDelete::DoDeleteStepL()
       
   173 	{
       
   174 	iTidyIter->GotoL(iTidyDate);	
       
   175 
       
   176 	TInt pos = 0;
       
   177 	TKeyArrayFix alreadyTidiedKey(0, ECmpTUint32);
       
   178 	while(CheckDateIteratorEnd())
       
   179 		{
       
   180 		const CAgnSimpleEntry& simpleEntry = iTidyIter->CurrentElement();
       
   181 
       
   182 		if (IsEntryValidToTidyL(simpleEntry))
       
   183 			{
       
   184 			TBool alreadyTidied = EFalse;
       
   185 			
       
   186 			// If the entry is repeating or if it spans more than one instant then the iterator may return the
       
   187 			// same entry more than once (due to the fact that the call backs interrupt the sequence and the
       
   188 			// iterator is reset on each chunk of processing) so add then to an array to prevent this
       
   189 			if ( simpleEntry.RptDef() || simpleEntry.StartTime() != simpleEntry.EndTime())
       
   190 				{
       
   191 				if (iAlreadyTidied->Find(simpleEntry.EntryId(), alreadyTidiedKey, pos) == 0)
       
   192 					{
       
   193 					alreadyTidied = ETrue;
       
   194 					}
       
   195 				else
       
   196 					{
       
   197 					iAlreadyTidied->AppendL(simpleEntry.EntryId());
       
   198 					}
       
   199 				}
       
   200 			
       
   201 			if ( ! alreadyTidied)
       
   202 				{
       
   203 				TidyEntryL(simpleEntry);
       
   204 				
       
   205 				if ((++iNumEntriesProcessed % KTidyCallbackRate)==0)
       
   206 					{
       
   207 					DeleteTidiedEntriesL();
       
   208 					
       
   209 					TInt percentage = (iNumEntriesProcessed * KAgnPercentageComplete) / iNumEntriesToProcess;
       
   210 					return (percentage < 1 ? 1 : percentage);
       
   211 					}
       
   212 
       
   213 				__ASSERT_DEBUG(iNumEntriesProcessed <= iNumEntriesToProcess, Panic(EAgmErrCorruptDelete));
       
   214 				}
       
   215 			}
       
   216 
       
   217 		iTidyIter->NextL();	
       
   218 		}
       
   219 	
       
   220 	DeleteTidiedEntriesL();
       
   221 	return KAgnPercentageComplete;
       
   222 	}
       
   223 
       
   224 /**
       
   225 Delete entries whose id's have been placed in iTidyDeleteArray during the tidying process
       
   226 @capability WriteUserData
       
   227 @capability ReadUserData
       
   228 */
       
   229 void CCalAsyncDelete::DeleteTidiedEntriesL()
       
   230 	{
       
   231 	if (iTidyDeleteArray && iTidyDeleteArray->Count())
       
   232 		{
       
   233 		// sort the entries in the tidy array by their entry ID (and therefore by their stream)
       
   234 		// this ensures entries in the same stream will be deleted together
       
   235 		TStreamIdKey key;
       
   236 		iTidyDeleteArray->Sort(key);
       
   237 		
       
   238 		const TInt KDeleteArrayCount = iTidyDeleteArray->Count();
       
   239 		for (TInt ii = 0; ii < KDeleteArrayCount; ++ii)
       
   240 			{
       
   241 			CAgnEntry* entry = iModel.FetchEntryL((*iTidyDeleteArray)[ii]);
       
   242 			if (entry)
       
   243 				{
       
   244 				CleanupStack::PushL(entry);
       
   245 				iModel.DeleteEntryL(*entry, ETrue, NULL);
       
   246 				CleanupStack::PopAndDestroy(entry);
       
   247 				}
       
   248 			}
       
   249 			
       
   250 		iTidyDeleteArray->Reset();
       
   251 		iModel.FlushL();
       
   252 		}
       
   253 	}
       
   254 
       
   255 /**
       
   256 Tidies (i.e. deletes) the entry identified by aSimpleEntry from the agenda if its eligible according to 
       
   257 its dates. 
       
   258 If it is non-repeating then for it to be tidied its instance date must fall within iTidyStartDate and
       
   259 iTidyEndDate. 
       
   260 If it is repeating then both its repeat start and until dates must fall within the range. 
       
   261 If it is an undated todo then it would not have been selected by the iterator if today does not fall within the tidy
       
   262 range hence it can be added without further checks.
       
   263 */
       
   264 void CCalAsyncDelete::TidyEntryL(const CAgnSimpleEntry& aSimpleEntry)
       
   265 	{
       
   266 	CAgnEntry* entry = iModel.FetchEntryL(aSimpleEntry.EntryId());
       
   267 	if (entry == NULL)
       
   268 		{
       
   269 		// already deleted
       
   270 		return;
       
   271 		}
       
   272 	
       
   273 	CleanupStack::PushL(entry);
       
   274 	
       
   275 	TBool todelete = EFalse;
       
   276 	if(entry->GsDataType() == CGsData::EParent)
       
   277 		{
       
   278 		// Only parents need to be tidied
       
   279 		todelete = FallInTimeRangeL(aSimpleEntry);
       
   280 		// If this Entry is a parent and it has children
       
   281 		if (todelete)
       
   282 			{
       
   283 			//Find out whether all children fall in the time range to tidy
       
   284 			const RArray<TGsChildRefData>& KChildIds = entry->ChildIds();
       
   285 		   
       
   286 			const TInt KCount = KChildIds.Count();
       
   287 			// Check each child to see if they are all fall in the date range
       
   288 			for (TInt i = 0; i < KCount && todelete; ++i)
       
   289 				{
       
   290 				const CAgnSimpleEntry* KChildEntry = iModel.GetSimpleEntryFromIndexes(KChildIds[i].ChildId());
       
   291 				todelete = FallInTimeRangeL(*KChildEntry);
       
   292 				}
       
   293 			}
       
   294 
       
   295 	#if defined (__CAL_ENTRY_LOGGING__) || (__CAL_VERBOSE_LOGGING__)
       
   296 		if(todelete)
       
   297 			{
       
   298 			AgmDebug::DebugLog("TidyEntryL: Async - Tidying - Deleting an entry");
       
   299 			AgmDebug::DebugLogEntryL(*entry,EDumpEntryIDs);
       
   300 			}
       
   301 	#endif
       
   302 		}
       
   303 	CleanupStack::PopAndDestroy(entry);
       
   304 	
       
   305 	if(todelete)
       
   306 		{
       
   307 		iTidyDeleteArray->AppendL(aSimpleEntry.EntryId());
       
   308 		if(aSimpleEntry.Type() == CCalEntry::ETodo)
       
   309 			{
       
   310 			iChangeFilter.SetPubSubChange(TAgnChangeFilter::ETodoChanged);
       
   311 			}
       
   312 		else
       
   313 			{
       
   314 			iChangeFilter.SetPubSubChange(TAgnChangeFilter::EEventChanged);
       
   315 			}
       
   316 		}
       
   317 	}
       
   318 
       
   319 TBool CCalAsyncDelete::FallInTimeRangeL(const CAgnSimpleEntry& aSimpleEntry)
       
   320 	{
       
   321 	if (aSimpleEntry.RptDef())
       
   322 		{ 
       
   323 		TTime firstUnexceptedInstanceDate;
       
   324 		TTime lastUnexceptedInstanceDate;
       
   325 		if(!aSimpleEntry.RptDef()->NudgeNextInstanceL(aSimpleEntry.RptDef()->FirstInstanceL().LocalL(), firstUnexceptedInstanceDate, ETrue))
       
   326 			{
       
   327 			firstUnexceptedInstanceDate = aSimpleEntry.RptDef()->FirstInstanceL().LocalL(); //we don't want the last date - we want the first date
       
   328 			}
       
   329 		if(!aSimpleEntry.RptDef()->NudgePreviousUnexceptedInstanceL(aSimpleEntry.RptDef()->LastInstanceL().LocalL(), lastUnexceptedInstanceDate))
       
   330 			{
       
   331 			lastUnexceptedInstanceDate = aSimpleEntry.RptDef()->LastInstanceL().LocalL(); // we don't want the first date - we want the last date
       
   332 			}
       
   333 		if ((firstUnexceptedInstanceDate >= iTidyStartDate) && (lastUnexceptedInstanceDate <= iTidyEndDate))
       
   334 
       
   335 			{
       
   336 			return ETrue;
       
   337 			}
       
   338 		}
       
   339 	else
       
   340 		{
       
   341 		if (aSimpleEntry.Type()==CCalEntry::ETodo)
       
   342 			{
       
   343 			// check due date only for Todos
       
   344 			if (aSimpleEntry.EndTime().LocalL() <= iTidyEndDate && aSimpleEntry.EndTime().LocalL() >= iTidyStartDate)
       
   345 				{
       
   346 				return ETrue;
       
   347 				}
       
   348 			}
       
   349 		else
       
   350 			{
       
   351 			if (aSimpleEntry.EndTime().LocalL() <= iTidyEndDate && aSimpleEntry.StartTime().LocalL() >= iTidyStartDate)
       
   352 				{
       
   353 				return ETrue;
       
   354 				}
       
   355 			}
       
   356 		}
       
   357 
       
   358 	return EFalse;
       
   359 	}