phonebookengines/contactsmodel/cntplsql/src/cviewcontactmanager.cpp
changeset 0 e686773b3f54
child 8 5586b4d2ec3e
equal deleted inserted replaced
-1:000000000000 0:e686773b3f54
       
     1 // Copyright (c) 2007-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 /**
       
    17  @file
       
    18  @internalComponent
       
    19  @released
       
    20 */
       
    21 
       
    22 #include <cntviewsortplugin.h>
       
    23 #include "cntviewprivate.h"
       
    24 #include "cviewcontactmanager.h"
       
    25 
       
    26 #include <cntviewbase.h>
       
    27 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
       
    28 #include <cntviewsortpluginbase.h>
       
    29 #endif
       
    30 
       
    31 const TInt KContactsArrayGranularity = 100;
       
    32 const TInt KUnsortedArrayGranularity = 16;
       
    33 
       
    34 /**
       
    35 @SYMPatchable
       
    36 @publishedPartner
       
    37 @released
       
    38  
       
    39 Patchable constant for the number of CViewContacts to read into memory 
       
    40 before merging them into a larger sorted list (via a heap sort).
       
    41 When the view contacts are merged, their text fields are released from memory. 
       
    42 The larger the constant the faster a View containing large numbers of items is created. 
       
    43 However, a larger constant will use more RAM for large Views.
       
    44  
       
    45 The constant can be changed at ROM build time using patchdata OBY keyword.
       
    46 */
       
    47 IMPORT_C extern const TInt KNumberOfContactsToReadPerMerge;
       
    48 
       
    49 /**
       
    50 @internalComponent
       
    51 @released
       
    52 
       
    53 Number of Contacts to process per invocation of the Sorter
       
    54 Local Views can't do much whilst sorting, but we want to allow other
       
    55 Active Objects in the thread to run. Use to be 50 for the DBMS version, 75 here to match
       
    56 performance (i.e. should occupy the server for the same amount of time).
       
    57 */    
       
    58 const TInt KNumberOfContactsToReadPerChunk = 75;
       
    59 
       
    60 
       
    61 /** 
       
    62 Private constructor
       
    63 */
       
    64 CViewContactManager::CViewContactManager(CContactLocalView& aLocalView, MLplViewIteratorManager& aLplViewMgr, TContactViewPreferences aViewPreferences, CViewContactSortPlugin* aSortPlugin)
       
    65 : iLocalView(aLocalView),
       
    66   iViewSessionId(KPLViewSessionIdNull),   
       
    67   iViewContacts(NULL), 
       
    68   iUnsortedViewContacts(NULL), 
       
    69   iViewContactsBuffer(NULL), 
       
    70   iSortPluginImpl(aSortPlugin), 
       
    71   iViewPreferences(aViewPreferences),
       
    72   iLplViewItemMgr(aLplViewMgr) 
       
    73     {
       
    74     }
       
    75 
       
    76     
       
    77 /** 
       
    78 Destructor
       
    79 */
       
    80 CViewContactManager::~CViewContactManager()
       
    81     {
       
    82     if(iViewSessionId != KPLViewSessionIdNull)
       
    83         {
       
    84     	iLplViewItemMgr.CloseView(iViewSessionId);
       
    85         }
       
    86 	
       
    87     delete iIdleSorter;
       
    88     
       
    89     if(iViewContacts)
       
    90     	{
       
    91     	iViewContacts->ResetAndDestroy();
       
    92 		delete iViewContacts;	
       
    93     	}	
       
    94 	if (iUnsortedViewContacts)
       
    95 		{
       
    96 		iUnsortedViewContacts->ResetAndDestroy();
       
    97 		delete iUnsortedViewContacts;	
       
    98 		}	
       
    99 	
       
   100 	if(iViewContactsBuffer)
       
   101 		{
       
   102 		iViewContactsBuffer->ResetAndDestroy();
       
   103 		delete iViewContactsBuffer;
       
   104 		}
       
   105 		
       
   106 	//The class doesn't own iSortPluginImpl,so don't release it here.
       
   107     }
       
   108 
       
   109     
       
   110 /** 
       
   111 Static factory constructor. Uses two phase construction and 
       
   112 leaves nothing on the CleanupStack.
       
   113 
       
   114 @return A pointer to the newly created CViewContactManager object.
       
   115 */
       
   116 CViewContactManager* CViewContactManager::NewL(CContactLocalView& aLocalView, MLplPersistenceLayerFactory& aFactory, const CContactTextDef& aTextDef, TContactViewPreferences aViewPreferences, CViewContactSortPlugin* aSortPlugin)
       
   117     {
       
   118     MLplViewIteratorManager& lplViewIteratorManager = aFactory.GetViewIteratorManagerL();
       
   119 	CViewContactManager* self = new(ELeave) CViewContactManager(aLocalView, lplViewIteratorManager, aViewPreferences, aSortPlugin);
       
   120 	CleanupStack::PushL(self);
       
   121 	self->ConstructL(aFactory, aTextDef);
       
   122 	CleanupStack::Pop(self);
       
   123 	return self;
       
   124     }
       
   125 
       
   126     
       
   127 /** 
       
   128 Constructor
       
   129 */
       
   130 void CViewContactManager::ConstructL(MLplPersistenceLayerFactory& aFactory, const CContactTextDef& aTextDef)
       
   131 	{
       
   132 	iViewContacts = new(ELeave) RPointerArray<CViewContact>(KContactsArrayGranularity);
       
   133 	iUnsortedViewContacts = new(ELeave) RPointerArray<CViewContact>(KUnsortedArrayGranularity);
       
   134 	
       
   135 	// Collation method by index 0 stays the same (only changes at a reboot)
       
   136  	iCollationMethod = *Mem::CollationMethodByIndex(0);
       
   137  	iCollationMethod.iFlags |= TCollationMethod::EIgnoreNone;
       
   138 	
       
   139 	iViewSessionId = iLplViewItemMgr.OpenViewL(aTextDef, iViewPreferences);
       
   140 
       
   141     //Create idle thread to prepare sort asynchronisely		
       
   142 	iIdleSorter = CIdleContactSorter::NewL(*this, aFactory, iViewPreferences);	
       
   143 	}
       
   144 
       
   145 
       
   146 /** 
       
   147 Start sorting with stored sort order.
       
   148 */
       
   149 void CViewContactManager::SortL()
       
   150 	{
       
   151 	iIdleSorter->Stop();	
       
   152 	
       
   153 	iLplViewItemMgr.BeginIterateL(iViewSessionId);
       
   154 	ResetSort();
       
   155 	
       
   156 	iIdleSorter->Start();	
       
   157 	}
       
   158 
       
   159 /** 
       
   160 Start sorting with given sort order/text definition.
       
   161 
       
   162 @param aTextDef new text definition would be used for sorting.
       
   163 */
       
   164 void CViewContactManager::SortL(const CContactTextDef& aTextDef)
       
   165 	{
       
   166 	//Stop current sorting.
       
   167 	iIdleSorter->Stop();	
       
   168 	
       
   169 	iLplViewItemMgr.EndIterateL(iViewSessionId);
       
   170 	iLplViewItemMgr.ChangeSortOrderL(iViewSessionId, aTextDef);
       
   171 	
       
   172 	//Restart iterating with changed sort order 
       
   173 	iLplViewItemMgr.BeginIterateL(iViewSessionId);
       
   174 	
       
   175 	ResetSort();
       
   176 	iIdleSorter->Start();	
       
   177 	}
       
   178 
       
   179 	
       
   180 /** 
       
   181 Start current sorting.
       
   182 */
       
   183 void CViewContactManager::StopSortL()
       
   184 	{
       
   185 	//Stop current sorting.
       
   186 	iIdleSorter->Stop();	
       
   187 	
       
   188 	//Call the lpl layer to stop iterating view contacts.
       
   189 	iLplViewItemMgr.EndIterateL(iViewSessionId);
       
   190 	}
       
   191 
       
   192 	
       
   193 /** 
       
   194 Reset contact ids arrays for resort or initial sort, this is called 
       
   195 when database complete restoring data or view is creating(first sort).
       
   196 */
       
   197 void CViewContactManager::ResetSort()
       
   198     {
       
   199 	ASSERT(iViewContacts);
       
   200     iViewContacts->ResetAndDestroy();
       
   201 	
       
   202 	ASSERT(iUnsortedViewContacts);
       
   203     iUnsortedViewContacts->ResetAndDestroy();
       
   204 	
       
   205 	if(iViewContactsBuffer)
       
   206 		{
       
   207 		iViewContactsBuffer->ResetAndDestroy();
       
   208 		delete iViewContactsBuffer;
       
   209 		iViewContactsBuffer = NULL;
       
   210 		}
       
   211     }
       
   212 
       
   213 
       
   214 /** 
       
   215 Implementation of MContactViewSortObserver interface, this is called with:
       
   216 1. TIccViewNotify_IccOnlyLocked: The view is ICCEntryOnly view and ICC store is locked.
       
   217 2. TIccViewNotify_IccUnlocked: The view include ICCEntry and ICC store is unlocked 
       
   218                                (resort is needed)
       
   219 
       
   220 @param  aIccViewNotify flag to show if ICC store is locked or not.
       
   221 @return ETrue if there is still view contact in database and needs idle
       
   222         sorting asynchroniser call back again.
       
   223 
       
   224 @leave KErrNoMemory Out of memory.
       
   225 @leave KErrNotFound The view session cannot be found.
       
   226 */
       
   227 void  CViewContactManager::IccViewNotifyL(TInt aIccViewNotify)
       
   228     {
       
   229     switch(aIccViewNotify)
       
   230         {
       
   231         case TIccViewNotify_IccOnlyLocked:
       
   232             iLocalView.SetState(CContactLocalView::EReady);
       
   233             break;
       
   234         case TIccViewNotify_IccUnlocked:
       
   235             iLocalView.SetState(CContactLocalView::ENotReady);
       
   236         	iLplViewItemMgr.EndIterateL(iViewSessionId);
       
   237             break;
       
   238         }
       
   239     }
       
   240 
       
   241 
       
   242 /** 
       
   243 Implementation of MContactViewSortObserver interface, this is called by
       
   244 the idle sorting asynchroniser repeatly. 
       
   245 
       
   246 @param  aSortErr if there is error occurs in idle sorting asynchroniser.
       
   247 @return ETrue if there is still view contact in database and needs idle
       
   248         sorting asynchroniser call back again.
       
   249 */
       
   250 TBool CViewContactManager::IdleSorterNotifyL(TInt aSortErr)
       
   251 	{
       
   252 	if(aSortErr != KErrNone)
       
   253 		{
       
   254 		TInt err = KErrNone;
       
   255 		TRAP(err, iLplViewItemMgr.EndIterateL(iViewSessionId));
       
   256 		iLocalView.SortComplete(aSortErr);
       
   257 		return EFalse;
       
   258 		}
       
   259 		
       
   260 	if(!iViewContactsBuffer)
       
   261 		{
       
   262 		//Create a temporary buffer for reading view contact objects.
       
   263 		iViewContactsBuffer = new(ELeave) RPointerArray<CViewContact>(KContactsArrayGranularity);
       
   264 		}
       
   265 		
       
   266 	CViewContactManager::TReadState readState = ReadInViewContactsL(*iViewContactsBuffer);
       
   267     
       
   268     if(readState == EReadFullChunk)
       
   269 		{
       
   270 		// Full chunk of view contact items have been read, so request another read.
       
   271 		return ETrue;
       
   272 		}
       
   273 		
       
   274 	//Reach here only when readState is EReadFullForMerge or EReadCompleted
       
   275 	if (iSortPluginImpl)
       
   276 		{
       
   277 		// prepare View Sort plug-in
       
   278 		User::LeaveIfError(iSortPluginImpl->SortStart(CViewContactSortPlugin::ESortStartFull, iViewContactsBuffer->Count()));
       
   279 		}
       
   280 	
       
   281 	// sort the view contacts in buffer
       
   282 	HeapSortL(*iViewContactsBuffer);
       
   283 
       
   284 	if(iViewContacts->Count() > 0)		
       
   285 		{
       
   286 		//There are sorted view objects stored in iViewContacts, merging is needed.
       
   287 		RPointerArray<CViewContact>* mergedArray = MergeL(*iViewContacts, *iViewContactsBuffer);	
       
   288 		
       
   289 		// all view contact objects have been merged into iViewContacts, 
       
   290 		// clean up the buffer array. 
       
   291 		iViewContactsBuffer->Reset();
       
   292 		
       
   293 		iViewContacts->Close();
       
   294 		delete iViewContacts;
       
   295 		iViewContacts = mergedArray;
       
   296 		}
       
   297 	else
       
   298 		{
       
   299 		//It's first time we get a list of sorted view contat objects
       
   300 		iViewContacts->Close();
       
   301 		delete iViewContacts;
       
   302 		iViewContacts = iViewContactsBuffer;	
       
   303 		iViewContactsBuffer = NULL;
       
   304 		}
       
   305 		
       
   306 	if (iSortPluginImpl)
       
   307 		{
       
   308 		iSortPluginImpl->SortCompleted();
       
   309 		}
       
   310 		
       
   311 	if(readState == EReadCompleted)
       
   312 		{
       
   313 		//Sorting is complete.
       
   314 		iLplViewItemMgr.EndIterateL(iViewSessionId);
       
   315 		iLocalView.SortComplete(KErrNone);
       
   316 		return EFalse;
       
   317 		}
       
   318     
       
   319 	return ETrue;
       
   320 	}
       
   321 
       
   322 
       
   323 /** 
       
   324 Fill in the given view contacts buffer by asking underlying persistence layer,
       
   325 and add all unsorted view contacts into unsorted array directly.
       
   326 
       
   327 @param  aViewContacts CViewContact objects array to fill in and sort.
       
   328 @return One of enum in TReadState, see the definition in TReadState for detail
       
   329 */
       
   330 CViewContactManager::TReadState CViewContactManager::ReadInViewContactsL(RPointerArray<CViewContact>& aViewContacts)
       
   331     {
       
   332 	TInt total = aViewContacts.Count();
       
   333 	
       
   334 	// process a chunk of contacts
       
   335 	CViewContact* contact = NULL;
       
   336 	
       
   337 	//Here to use current sorting view preference in iIdleSorter who knows
       
   338 	//if we can access ICCEntry store now, therefore decides if we should read in
       
   339 	//ICCEntry contacts from the database.
       
   340 	TContactViewPreferences sortViewPref = iIdleSorter->SortViewPreferences();
       
   341 	
       
   342 	for(TInt i = 0; i<KNumberOfContactsToReadPerChunk; ++i)
       
   343 		{
       
   344 		contact = iLplViewItemMgr.NextItemL(iViewSessionId, sortViewPref);
       
   345 		if(contact == NULL)
       
   346 			{
       
   347     		return EReadCompleted;
       
   348 			}
       
   349 			
       
   350 		CleanupStack::PushL(contact);
       
   351 		if(IsContactSortable(*contact,iViewPreferences))
       
   352 			{
       
   353 			aViewContacts.AppendL(contact);
       
   354 			CleanupStack::Pop(contact);
       
   355 		    if(++total >= KNumberOfContactsToReadPerMerge)
       
   356 		        {
       
   357 		        return EReadFullForMerge;
       
   358 		        }
       
   359 			}
       
   360 		else if(iViewPreferences & (EUnSortedAtBeginning | EUnSortedAtEnd))
       
   361 			{
       
   362 			// It's an unsortable contact, just append its lightweight object
       
   363 			// to unsortable view contacts list.
       
   364 			contact->ChangeToLightweightObject();
       
   365 			iUnsortedViewContacts->AppendL(contact);
       
   366 			CleanupStack::Pop(contact);
       
   367 			}
       
   368 		else
       
   369 			{
       
   370 			CleanupStack::PopAndDestroy(contact);
       
   371 			}
       
   372 		}
       
   373 		
       
   374 	return EReadFullChunk;
       
   375     }
       
   376 
       
   377 
       
   378 /** 
       
   379 Check if the contact type uid matchs the view preferences.
       
   380 
       
   381 @param  aContactTypeUid contact type uid to check.
       
   382 @param  aTypeToInclude  view preferences have flags to define which contact the view should have.
       
   383 @return ETrue if the uid match or reverse.
       
   384 */
       
   385 TBool CViewContactManager::ContactCorrectType(TUid aContactTypeUid, TContactViewPreferences aTypeToInclude)
       
   386 	{
       
   387 	TBool correctType(EFalse);
       
   388 	if (aContactTypeUid==KUidContactCard || aContactTypeUid==KUidContactOwnCard)
       
   389 		{
       
   390 		// Ignore Unsorted Contacts flags & White Space flag
       
   391 		// catch non- contact views
       
   392 		// Should be EContactsOnly, EContactAndGroups & EICCEntriesAndContacts
       
   393 		if (0 == ((aTypeToInclude & ~(ESingleWhiteSpaceIsEmptyField | EIgnoreUnSorted | EUnSortedAtBeginning | EUnSortedAtEnd))
       
   394 				& (EGroupsOnly | EICCEntriesOnly))) // Ignore 'UnSorted' flags, exclude Groups Only & ICC Only 
       
   395 			{
       
   396 			correctType = ETrue;
       
   397 			}
       
   398 		}
       
   399 	else if (aContactTypeUid == KUidContactGroup)
       
   400 		{
       
   401 		if (aTypeToInclude & (EGroupsOnly | EContactAndGroups))
       
   402 			{
       
   403 			correctType = ETrue;
       
   404 			}
       
   405 		}
       
   406 	else if (aContactTypeUid == KUidContactICCEntry)
       
   407 		{
       
   408 		if (aTypeToInclude & (EICCEntriesOnly | EICCEntriesAndContacts))
       
   409 			{
       
   410 			correctType = ETrue;
       
   411 			}
       
   412 		}
       
   413 	return correctType;
       
   414 	}
       
   415 
       
   416 
       
   417 /** 
       
   418 Heap sort the give view contacts array.
       
   419 
       
   420 @param  aContacts the array of view contacts to be sorted.
       
   421 @leave  leave errors from CContactViewBase::CompareContactsAndIdsL
       
   422 */
       
   423 void CViewContactManager::HeapSortL(RPointerArray<CViewContact>& aContacts)
       
   424 	{
       
   425 	// HeapSort (stolen from RPointerArrayBase)
       
   426 	TInt ss = aContacts.Count();
       
   427 	if ( ss>1 )
       
   428 		{
       
   429 		TInt sh = ss>>1;
       
   430 		FOREVER
       
   431 			{
       
   432 			CViewContact* si;
       
   433 			if (sh != 0)
       
   434 				{
       
   435 				// make heap
       
   436 				--sh;
       
   437 				si = aContacts[sh];
       
   438 				}
       
   439 			else
       
   440 				{
       
   441 				// sort heap
       
   442 				--ss;
       
   443 				si = aContacts[ss];
       
   444 				aContacts[ss] = aContacts[0];
       
   445 				if (ss == 1)
       
   446 					{
       
   447 					aContacts[0] = si;
       
   448 					break;
       
   449 					}
       
   450 				}
       
   451 
       
   452 			// sift down
       
   453 			TInt ii = sh;
       
   454 			TInt jj = sh;
       
   455 			FOREVER
       
   456 				{
       
   457 				jj = (jj+1)<<1;
       
   458 				if ((jj >= ss) || (iLocalView.CompareContactsAndIdsL(*aContacts[jj-1],*aContacts[jj]) > 0))
       
   459 					{
       
   460 					--jj;
       
   461 					}
       
   462 					
       
   463 				if ((jj >= ss) || (iLocalView.CompareContactsAndIdsL(*aContacts[jj],*si) <= 0))
       
   464 					{
       
   465 					break;
       
   466 					}
       
   467 					
       
   468 				aContacts[ii] = aContacts[jj];
       
   469 				ii = jj;
       
   470 				} //FOREVER
       
   471 				
       
   472 			aContacts[ii] = si;
       
   473 			} //FOREVER
       
   474 		} //if (ss > 1)
       
   475 	}
       
   476 
       
   477 
       
   478 /** 
       
   479 Merge two view contacts array into a result array, here we always assume the items in 
       
   480 aRightContacts are fulfilled objects.
       
   481 
       
   482 @param  aLeftContacts  the left array of view contacts to be merged.
       
   483 @param  aRightContacts the right array of view contacts to be merged.
       
   484 @return the final merged array.
       
   485 */
       
   486 RPointerArray<CViewContact>* CViewContactManager::MergeL(RPointerArray<CViewContact>& aLeftContacts, RPointerArray<CViewContact>& aRightContacts)
       
   487     {
       
   488 	TInt indexLeft(0);
       
   489 	TInt indexRight(0);
       
   490 	const TInt KCountLeft = aLeftContacts.Count();
       
   491 	
       
   492 	RPointerArray<CViewContact>* resultContacts = new(ELeave) RPointerArray<CViewContact>(KContactsArrayGranularity);	
       
   493 	CleanupStack::PushL(TCleanupItem(ResetAndDestroyRPointerArrayPointer, resultContacts));
       
   494 	
       
   495     while(indexLeft < KCountLeft && indexRight < aRightContacts.Count())
       
   496 		{
       
   497 		CViewContact* firstLeftContact = static_cast<CViewContact*>(aLeftContacts[indexLeft]);
       
   498 		CViewContact* firstRightContact = static_cast<CViewContact*>(aRightContacts[indexRight]);
       
   499 		
       
   500 		if(firstLeftContact->IsLightweightObject())
       
   501 			{
       
   502 			//The current contact in iViewContact is lightweight object, so we need to load the
       
   503 			//fulfilled view contact to compare.
       
   504 			CViewContact* contact = iLplViewItemMgr.ItemAtL(firstLeftContact->Id(), iViewSessionId);				
       
   505 			if(contact == NULL)
       
   506 				{
       
   507 				//The already sorted contact is not in database!!!
       
   508 				User::Leave(KErrNotFound);
       
   509 				}
       
   510 				
       
   511 			CleanupStack::PushL(contact);    
       
   512 			firstLeftContact->CopyL(*contact);
       
   513 			CleanupStack::PopAndDestroy(contact);
       
   514 			}
       
   515 
       
   516         TInt diff = CompareContactsAndIdsL(*firstLeftContact, *firstRightContact);
       
   517         
       
   518 		if(diff > 0)
       
   519 			{
       
   520 			resultContacts->AppendL(firstRightContact);
       
   521 			firstRightContact->ChangeToLightweightObject();
       
   522 			++indexRight;
       
   523 			}
       
   524 		else
       
   525 			{		
       
   526 			resultContacts->AppendL(firstLeftContact);
       
   527 			firstLeftContact->ChangeToLightweightObject();
       
   528 			++indexLeft;
       
   529 			if(diff == 0)
       
   530 			    {
       
   531 			    aRightContacts.Remove(indexRight);
       
   532 			    delete firstRightContact;
       
   533 			    }
       
   534 			}
       
   535 		}
       
   536 		
       
   537 	while(indexLeft < KCountLeft)
       
   538 		{
       
   539 		CViewContact* firstLeftContact = static_cast<CViewContact*>(aLeftContacts[indexLeft]);
       
   540 		resultContacts->AppendL(firstLeftContact);
       
   541 		++indexLeft;
       
   542 		}
       
   543 	
       
   544 	while(indexRight < aRightContacts.Count())
       
   545 		{
       
   546 		CViewContact* firstRightContact = static_cast<CViewContact*>(aRightContacts[indexRight]);
       
   547 		
       
   548 		//change all the fullfil view objects to lightweight into the merged list.
       
   549 		firstRightContact->ChangeToLightweightObject();
       
   550 		
       
   551 		resultContacts->AppendL(firstRightContact);
       
   552 		++indexRight;
       
   553 		}
       
   554 		
       
   555     CleanupStack::Pop(resultContacts);
       
   556 	
       
   557 	return resultContacts;
       
   558     }
       
   559 
       
   560 
       
   561 /** 
       
   562 Insert a view contact object into existing sorted view contacts array(iViewContacts).
       
   563 
       
   564 @param  aNewContact   the new view contact object to be inserted.
       
   565 @param  aSortByIdOnly if the sorting method is sorting by id only
       
   566 @param  aStart        start searching position in existing view contacts array.
       
   567 @param  aIndex        the index of the view contact after insertion.
       
   568 @leave  KErrNoMemory or leave error from CContactViewBase::CompareContactsAndIdsL
       
   569 */
       
   570 TInt CViewContactManager::InsertViewContactL(const CViewContact* aNewContact, TBool aSortByIdOnly, TInt aStart)
       
   571 	{
       
   572 	TInt maxPos = iViewContacts->Count() - 1;
       
   573 	TInt minPos = aStart;
       
   574 	TInt position = 0;
       
   575     TInt error(KErrNone);
       
   576     
       
   577     //Using binary search to find the sorting position for the new contact.    
       
   578 	if (maxPos >= 0)
       
   579 		{
       
   580     	if (iSortPluginImpl)
       
   581     		{
       
   582     		// prepare View Sort plug-in
       
   583     		User::LeaveIfError(iSortPluginImpl->SortStart(CViewContactSortPlugin::ESortStartInsertOne, 1));
       
   584     		}
       
   585 
       
   586 		position = (minPos + maxPos + 1) / 2;
       
   587 
       
   588 		while (maxPos >= minPos)
       
   589 			{
       
   590 			TInt diff = 0;
       
   591             CViewContact* currContact = static_cast<CViewContact*>((*iViewContacts)[position]);
       
   592             
       
   593 			if (aSortByIdOnly)
       
   594 				{
       
   595 				diff = aNewContact->Id() - currContact->Id();
       
   596 				}
       
   597 			else
       
   598 				{
       
   599 				//The view contacts stored in sortable contact list(iViewContacts) have been changed to
       
   600 				//lightweight objects after sorting has done for memory saving purpose. 
       
   601 				if(currContact->IsLightweightObject())
       
   602 				    {
       
   603 				    //The current contact in iViewContact is lightweight object, so we need to load the
       
   604 				    //full content into the view contact before compare.
       
   605                     CViewContact* contact = iLplViewItemMgr.ItemAtL(currContact->Id(), iViewSessionId);				
       
   606 					if(contact == NULL)
       
   607 						{
       
   608 						//the sorted contact is not in the database!!!
       
   609 						User::Leave(KErrNotFound);
       
   610 						}
       
   611                     
       
   612                     CleanupStack::PushL(contact);    
       
   613     				diff = CompareContactsAndIdsL(*aNewContact, *contact);
       
   614     				CleanupStack::PopAndDestroy(contact);
       
   615 				    }
       
   616 				else
       
   617 				    {
       
   618 				    //It's fulfilled object already, use it to compare directly
       
   619     				diff = CompareContactsAndIdsL(*aNewContact, *currContact);
       
   620 				    }    
       
   621 				}
       
   622 
       
   623 
       
   624 			if (diff == 0)
       
   625 				{
       
   626 				// duplicate Id
       
   627 				error = KErrAlreadyExists;
       
   628 				break;
       
   629 				}
       
   630 				
       
   631 			if (diff < 0)
       
   632 				{
       
   633 				maxPos = position - 1;
       
   634 				}
       
   635 			else // diff > 0
       
   636 				{
       
   637 				minPos = position + 1;
       
   638 				}
       
   639 
       
   640 			position = (minPos + maxPos + 1) / 2;
       
   641 			} //while (maxPos >= minPos)
       
   642 			
       
   643     	if (iSortPluginImpl)
       
   644     		{
       
   645     		iSortPluginImpl->SortCompleted();
       
   646     		}
       
   647 		}
       
   648 
       
   649     User::LeaveIfError(error);
       
   650     
       
   651     //Make the view contact object to be lightweighted before insert to iViewContacts.
       
   652     const_cast<CViewContact*>(aNewContact)->ChangeToLightweightObject();
       
   653 	iViewContacts->InsertL(aNewContact, position);
       
   654 
       
   655 	return position;
       
   656 	}
       
   657 
       
   658 /** 
       
   659 Get a reference of a view contact by given index to existing view contacts array,
       
   660 if the the requested view object is in lightweight(only stored contact item id and
       
   661 contact type) the function will fill the whole content to the object.
       
   662 
       
   663 @param  aIndex  the index to the contact ids array.
       
   664 @leave  KErrNoMemory or KErrNotFound
       
   665 @return the reference to the requested contact view object(always be fulfiled), 
       
   666         the constrains of const is to keep to the same definition of the function 
       
   667 		in local view which calls down to this function.
       
   668 */
       
   669 const CViewContact& CViewContactManager::ContactAtL(TInt aIndex) const
       
   670     {
       
   671 	CViewContact& viewContact = ViewContactAtL(aIndex);
       
   672 	
       
   673 	if(viewContact.IsLightweightObject())
       
   674 		{
       
   675 		CViewContact* contact = iLplViewItemMgr.ItemAtL(viewContact.Id(), iViewSessionId);
       
   676 		if(contact == NULL)
       
   677 			{
       
   678 			User::Leave(KErrNotFound);
       
   679 			}
       
   680 		
       
   681 		CleanupStack::PushL(contact);    
       
   682 		viewContact.CopyL(*contact);
       
   683 		CleanupStack::PopAndDestroy(contact);
       
   684 		}
       
   685 	
       
   686     return viewContact;    	
       
   687     }
       
   688 
       
   689 
       
   690 /** 
       
   691 Get the view contact object by given index to existing view contacts array.
       
   692 
       
   693 @param  aIndex  the index to the contact ids array.
       
   694 @param  aLoadFullContent  if the view contact need to load into full content.
       
   695 @leave  KErrNotFound
       
   696 @return the pointer to the requested contact view object but caller doesn't own the object
       
   697         aLoadFullContent is ETrue if the object was a lightweight object but 
       
   698 		has been loaded into full content in the function.
       
   699 */
       
   700 CViewContact& CViewContactManager::ViewContactAtL(TInt aIndex) const
       
   701     {
       
   702 	const TInt unsortedCount = iUnsortedViewContacts->Count();
       
   703 	const TInt sortedCount = iViewContacts->Count();
       
   704 	
       
   705 	if(aIndex >= (unsortedCount + sortedCount))
       
   706 		{
       
   707 		//Out of Bounds.
       
   708 		User::Leave(KErrNotFound);
       
   709 		}
       
   710 
       
   711 	CViewContact* viewContact = NULL;
       
   712     
       
   713 	if(iViewPreferences & EUnSortedAtBeginning)
       
   714 		{
       
   715 		if(aIndex < unsortedCount)
       
   716 			{
       
   717 			//contact in unsorted array
       
   718 			viewContact = (*iUnsortedViewContacts)[aIndex];
       
   719 			}
       
   720 		else
       
   721 			{
       
   722 			//contact in sorted array
       
   723 			viewContact = (*iViewContacts)[aIndex - unsortedCount];
       
   724 			}
       
   725 		}
       
   726 	else if ((iViewPreferences & EUnSortedAtEnd) && (aIndex>=sortedCount))
       
   727 		{
       
   728 		viewContact = (*iUnsortedViewContacts)[aIndex - sortedCount];
       
   729 		}
       
   730 	else
       
   731 	    {
       
   732 	    viewContact = (*iViewContacts)[aIndex];
       
   733 	    }    
       
   734 	
       
   735 	ASSERT(viewContact != NULL);	
       
   736 	return *viewContact;
       
   737     }
       
   738 
       
   739 
       
   740 /** 
       
   741 Get the contact item id by given index.
       
   742 
       
   743 @param  aIndex  the index to the contact ids array.
       
   744 @leave  KErrNotFound
       
   745 @return the contact item id.
       
   746 */
       
   747 TContactItemId CViewContactManager::AtL(TInt aIndex) const
       
   748     {
       
   749     return ViewContactAtL(aIndex).Id();
       
   750     }
       
   751 
       
   752 
       
   753 /** 
       
   754 Get the number of contacts in the veiw.
       
   755 
       
   756 @return the number of contacts in the veiw.
       
   757 */
       
   758 TInt CViewContactManager::Count() const
       
   759     {
       
   760     ASSERT(iViewContacts);
       
   761     ASSERT(iUnsortedViewContacts);
       
   762     
       
   763 	return iViewContacts->Count() + iUnsortedViewContacts->Count();
       
   764     }
       
   765 
       
   766 
       
   767 /** 
       
   768 Find if the given contact item id is in the view.
       
   769 
       
   770 @param  aContactId The contact item id to be retrieved from database.
       
   771 @return Index of the requested view contact or KErrNotFound.
       
   772 */
       
   773 TInt CViewContactManager::FindL(TContactItemId aContactId) const
       
   774     {
       
   775 	TInt index = KErrNotFound;
       
   776 	CViewContact* contact = CViewContact::NewLC(aContactId);
       
   777 	const TInt unSortedCount = iUnsortedViewContacts->Count();
       
   778 	
       
   779 	// first look in unsorted contacts
       
   780 	if(unSortedCount > 0)
       
   781 		{
       
   782 		// contact may be in the unsorted array
       
   783 		index = iUnsortedViewContacts->Find(contact,TIdentityRelation<CViewContact>(CContactViewBase::IdsMatch));
       
   784 
       
   785 		if ((index != KErrNotFound) && (iViewPreferences & EUnSortedAtEnd))
       
   786 			{
       
   787 			// account for sorted array size
       
   788 			index = index + iViewContacts->Count();
       
   789 			}
       
   790 		}
       
   791 
       
   792 	// if not found try sorted contacts
       
   793 	if (index == KErrNotFound)
       
   794 		{
       
   795 		//contact may be in the sorted array
       
   796 		index = iViewContacts->Find(contact,TIdentityRelation<CViewContact>(CContactViewBase::IdsMatch));
       
   797 
       
   798 		if ((index != KErrNotFound) && (iViewPreferences & EUnSortedAtBeginning))
       
   799 			{
       
   800 			// account for unsorted array size
       
   801 			index = index + unSortedCount;
       
   802 			}
       
   803 		}
       
   804 
       
   805 	CleanupStack::PopAndDestroy(contact);
       
   806 	return index;
       
   807     }
       
   808     
       
   809 
       
   810 /** 
       
   811 Get all fields content of a view contact and separate them with charaters in aSeparators.
       
   812 
       
   813 @param  aIndex     the index of view contact.
       
   814 @param  aSeparator the charactors to split the fields content.
       
   815 @return Buffer of the formated fields content.
       
   816 */
       
   817 HBufC* CViewContactManager::AllFieldsLC(TInt aIndex, const TDesC& aSeparator) const
       
   818     {
       
   819 	TBool ifWasFullObject = EFalse;
       
   820 	
       
   821 	CViewContact& viewContact = ViewContactAtL(aIndex); 
       
   822 	if(viewContact.IsLightweightObject())
       
   823 		{
       
   824 		CViewContact* contact = iLplViewItemMgr.ItemAtL(viewContact.Id(), iViewSessionId);
       
   825 		if(contact == NULL)
       
   826 			{
       
   827 			User::Leave(KErrNotFound);
       
   828 			}
       
   829 		
       
   830 		CleanupStack::PushL(contact);    
       
   831 		viewContact.CopyL(*contact);
       
   832 		CleanupStack::PopAndDestroy(contact);
       
   833 		
       
   834 		ifWasFullObject = ETrue;
       
   835 		}
       
   836 
       
   837 	HBufC* buf = FieldsWithSeparatorLC(viewContact,aSeparator);
       
   838 	
       
   839 	if(ifWasFullObject)
       
   840 		{
       
   841 		//loadFullContent is set in ViewContactAtL if the viewContact was a lightweight object and
       
   842 		//loaded to be full content object in that function. So we need to change it to lightweight
       
   843 		//in order to save more memory.
       
   844 		viewContact.ChangeToLightweightObject();
       
   845 		}
       
   846     return buf;	
       
   847     }
       
   848 
       
   849 
       
   850 /** 
       
   851 Insert a contact into the view.
       
   852 
       
   853 @param  aContactId       the contact item id of the contact to be inserted.
       
   854 @param  aViewPreferences view preference which defines the view.
       
   855 @return Index of inserted contact or KErrNotFound.
       
   856 */
       
   857 TInt CViewContactManager::InsertL(const TContactItemId aContactId, TContactViewPreferences& aViewPreferences)
       
   858     {
       
   859 	if(!iIdleSorter->InsertViewPreferences(aViewPreferences))
       
   860 		{
       
   861 		return KErrNotFound;
       
   862 		}
       
   863 
       
   864 	TInt index = KErrNotFound;
       
   865 	
       
   866 	CViewContact* contact = iLplViewItemMgr.ItemAtL(aContactId, iViewSessionId);
       
   867 	if(contact == NULL)
       
   868 		{
       
   869 		//there is not a contact in database owning the contact id.
       
   870 		return KErrNotFound;
       
   871 		}
       
   872 		
       
   873 	CleanupStack::PushL(contact);
       
   874 	
       
   875 	if(ContactCorrectType(contact->ContactTypeUid(),aViewPreferences))
       
   876 		{
       
   877 		if(IsContactSortable(*contact, iViewPreferences))
       
   878 			{
       
   879 			//Contact has normal fields and can be added to the standard sorted array				
       
   880 			//Insert using Sort Plugin compare method, and get new index
       
   881 			index = InsertViewContactL(contact, EFalse, 0);
       
   882 			if (iViewPreferences & EUnSortedAtBeginning)
       
   883 				{
       
   884 				index += iUnsortedViewContacts->Count();
       
   885 				}
       
   886 			}
       
   887 		else if (iViewPreferences & (EUnSortedAtBeginning | EUnSortedAtEnd))
       
   888 			{
       
   889 			// unsortable contacts go at the end or beginning
       
   890 			// we want this to be stable (e.g. when ICC becomes unlocked)
       
   891 			contact->ChangeToLightweightObject();
       
   892 			iUnsortedViewContacts->AppendL(contact);
       
   893             index = iUnsortedViewContacts->Count() - 1; 
       
   894             			
       
   895 			// calc new index
       
   896 			if (iViewPreferences & EUnSortedAtEnd)
       
   897 				{
       
   898 				index += iViewContacts->Count();
       
   899 				}
       
   900 			}
       
   901 		}
       
   902 		
       
   903     CleanupStack::Pop(contact);
       
   904     
       
   905     if(index == KErrNotFound)
       
   906         {
       
   907         //The contact is not inserted, so delete it.
       
   908         delete contact;
       
   909         }
       
   910         
       
   911 	return index;
       
   912     }
       
   913 
       
   914     
       
   915 /** 
       
   916 Remove a contact from the view.
       
   917 
       
   918 @param  aContactId the contact item id of the contact to be removed.
       
   919 @return Index of removed contact or KErrNotFound.
       
   920 */
       
   921 TInt CViewContactManager::RemoveL(const TContactItemId aContactId)
       
   922     {
       
   923 	TInt index=KErrNotFound;
       
   924 	const TInt unSortedCount=iUnsortedViewContacts->Count();
       
   925 	
       
   926 	CViewContact* contact = CViewContact::NewLC(aContactId);
       
   927 	
       
   928 	// first look in unsorted contacts
       
   929 	if(unSortedCount > 0)
       
   930 		{
       
   931 		// contact may be in the unsorted array
       
   932 		index = iUnsortedViewContacts->Find(contact,TIdentityRelation<CViewContact>(CContactViewBase::IdsMatch));
       
   933 
       
   934 		if ((index != KErrNotFound) && (iViewPreferences & EUnSortedAtEnd))
       
   935 			{
       
   936 			CViewContact* viewContact = (*iUnsortedViewContacts)[index];
       
   937 			iUnsortedViewContacts->Remove(index);
       
   938 			delete viewContact;
       
   939 			
       
   940 			// account for sorted array size
       
   941 			index = index + iViewContacts->Count();
       
   942 			}
       
   943 		}
       
   944 
       
   945 	// if not found try sorted contacts
       
   946 	if (index == KErrNotFound)
       
   947 		{
       
   948 		//contact may be in the sorted array
       
   949 		index = iViewContacts->Find(contact,TIdentityRelation<CViewContact>(CContactViewBase::IdsMatch));
       
   950 
       
   951 		if (index != KErrNotFound)
       
   952 		    {
       
   953 			CViewContact* viewContact = (*iViewContacts)[index];
       
   954 			iViewContacts->Remove(index);
       
   955 			delete viewContact;
       
   956 			
       
   957 		    if (iViewPreferences & EUnSortedAtBeginning)
       
   958     			{
       
   959     			// account for unsorted array size
       
   960     			index = index + unSortedCount;
       
   961     			}
       
   962 		    }
       
   963 		}
       
   964     
       
   965     CleanupStack::PopAndDestroy(contact);    		
       
   966 	return index;
       
   967     }
       
   968 
       
   969 	
       
   970 /**
       
   971 This a delegating method to call IsICCSynchronised in iIdleSorter which is
       
   972 also observing ICC synchronization
       
   973 
       
   974 @return EFalse when iIdleSorter is waiting for ICC cards to be synchronized.
       
   975 */
       
   976 TBool CViewContactManager::IsICCSynchronised() const
       
   977 	{
       
   978 	return iIdleSorter->IsICCSynchronised();
       
   979 	}
       
   980 	
       
   981 	
       
   982 /**
       
   983 Cleanup stack call up to handle RPointerArray.
       
   984 
       
   985 @param aArray Pointer to an RPointerArray<CContactItemField> instance.
       
   986 
       
   987 @return None.
       
   988 */
       
   989 void CViewContactManager::ResetAndDestroyRPointerArrayPointer(TAny *aArray)
       
   990 	{
       
   991 	RPointerArray<CViewContact> *parray = static_cast< RPointerArray<CViewContact> * >(aArray);
       
   992 	parray->Close();			
       
   993 	delete parray;
       
   994 	}
       
   995 	
       
   996 /** 
       
   997 This function determines whether a contact should be added to the normal
       
   998 sorted array (iContacts) or put into the alternative iUnSortedContacts array. 
       
   999 Depending on the view preferences, these "unsorted" contacts are either 
       
  1000 ignored (deleted), or added to the beginning or end of the iContacts 
       
  1001 sorted list by At(), Find() etc... methods.
       
  1002 
       
  1003 @param aContact the view contact object to be checked
       
  1004 @param aViewPreferences view preferences that determine if aContact is sortable.
       
  1005 @return ETrue if the view contact object is sortable.
       
  1006 */
       
  1007 TBool CViewContactManager::IsContactSortable(const CViewContact& aContact, TContactViewPreferences& aViewPreferences) const
       
  1008 	{
       
  1009 	TBool sortableContact=EFalse;
       
  1010 
       
  1011 	// only test contact if it matters
       
  1012 	if(aViewPreferences & (EIgnoreUnSorted | EUnSortedAtBeginning | EUnSortedAtEnd)) //Distinguish Unsorted
       
  1013 		{
       
  1014 		if (iSortPluginImpl)
       
  1015 			{
       
  1016 			// use plugin
       
  1017 			sortableContact = iSortPluginImpl->ViewContactIsSortable(aContact);
       
  1018 			}
       
  1019 		else
       
  1020 			{
       
  1021 			// ask contact itself
       
  1022 			sortableContact = aContact.IsSortable();
       
  1023 			}
       
  1024 		}
       
  1025 	else
       
  1026 		{
       
  1027 		// Sortable
       
  1028 		sortableContact = ETrue;
       
  1029 		}
       
  1030 
       
  1031 	return sortableContact;
       
  1032 	}
       
  1033 
       
  1034 
       
  1035 /** 
       
  1036 Used for view sorting and insersion. In order to give a stable result 
       
  1037 if contact details match, it falls back to comparing contact IDs.
       
  1038 If a contact view sort plugin is loaded it uses its SortCompareViewContactsL() method.
       
  1039 
       
  1040 @param aFirst the first view contact to be compared.
       
  1041 @param aSecond the second view contact to be compared.
       
  1042 @return 0 if two view contacts' id are equal.
       
  1043 */
       
  1044 TInt CViewContactManager::CompareContactsAndIdsL(const CViewContact& aFirst, const CViewContact& aSecond) const
       
  1045 	{
       
  1046 	TInt result(0);
       
  1047 
       
  1048 	if (iSortPluginImpl)
       
  1049 		{
       
  1050 		// use View Sort plugin
       
  1051 		result = iSortPluginImpl->SortCompareViewContactsL(aFirst,aSecond);
       
  1052 		}
       
  1053 	else
       
  1054 		{
       
  1055 		// no View sort plugin loaded
       
  1056 		result = TextCompareFieldsL(aFirst, aSecond);
       
  1057 		}
       
  1058 
       
  1059 	if (result == 0)
       
  1060 		{
       
  1061 		result = aFirst.Id() - aSecond.Id();
       
  1062 		}
       
  1063 
       
  1064 	return result;
       
  1065 	}
       
  1066 
       
  1067 	
       
  1068 /** Collates two contact items' field contents.
       
  1069 
       
  1070 This is done by comparing each contact item on a field by field basis starting 
       
  1071 with the loosest collation level initially, and then progressing to tighter 
       
  1072 collation levels only if the items are considered the same at the looser level. 
       
  1073 This is required so that items differing by case only are sorted correctly. 
       
  1074 If a field isn't present, then the comparison is done using the first field 
       
  1075 that is present.
       
  1076 
       
  1077 Faster than static CompareFieldsL() method as it uses prefetched collation method.
       
  1078 
       
  1079 @param aFirst The first contact item.
       
  1080 @param aSecond The second contact item.
       
  1081 @return A positive value indicates that aFirst's field contents are greater 
       
  1082 than aSecond's (so that aFirst would occur after aSecond in a sort order). 
       
  1083 A negative value indicates that aFirst's field contents are less than aSecond's 
       
  1084 (so that aFirst would occur before aSecond in a sort order). Zero indicates 
       
  1085 that aFirst and aSecond have identical field contents. */
       
  1086 TInt CViewContactManager::TextCompareFieldsL(const CViewContact& aFirst,const CViewContact& aSecond) const
       
  1087 	{
       
  1088 	const TInt KDefaultCollationLevel=3;
       
  1089 	TInt comparison = 0; // result of comparison, Zero = fields are identical
       
  1090 	TInt collationLevel = 0;
       
  1091 
       
  1092 	do
       
  1093 		{
       
  1094 		comparison = CViewContactManager::CompareFieldsWithCollationLevel(aFirst, aSecond, collationLevel, &iCollationMethod);
       
  1095 		++collationLevel;
       
  1096 		}
       
  1097 		while (comparison == 0 && collationLevel <= KDefaultCollationLevel);
       
  1098 
       
  1099 	return comparison;
       
  1100 	}
       
  1101 	
       
  1102 
       
  1103 TInt CViewContactManager::CompareFieldsWithCollationLevel(const CViewContact& aFirst, const CViewContact& aSecond, TInt aCollationLevel, const TCollationMethod* aCollateMethod)
       
  1104 	{
       
  1105 	const TInt KLastField = aFirst.FieldCount() - 1;
       
  1106 
       
  1107 	TInt retval = 0; // result of comparison, Zero = fields are identical
       
  1108 	TInt firstField(-1);
       
  1109 	TInt secondField(-1);
       
  1110 	TPtrC first;
       
  1111 	TPtrC second;
       
  1112 
       
  1113 	for (TInt counter=0; !retval && (counter <= KLastField); ++counter)
       
  1114 		{
       
  1115 		// if the 1st populated field has a greater index than counter, 
       
  1116 		//	that means we'd get the same result from FindFirstPopulatedField.
       
  1117 		//	So, don't bother. Of course we always have to run it at least once.
       
  1118 
       
  1119 		if (firstField < counter)
       
  1120 			{
       
  1121 			first.Set(aFirst.FindFirstPopulatedField(counter, firstField));
       
  1122 			}
       
  1123 
       
  1124 		if (secondField < counter)
       
  1125 			{
       
  1126 			second.Set(aSecond.FindFirstPopulatedField(counter, secondField));
       
  1127 			}
       
  1128 
       
  1129 		// no fields in either item
       
  1130 		if ((firstField < 0) && (secondField < 0))
       
  1131 			{
       
  1132 			break;
       
  1133 			}
       
  1134 
       
  1135 		if (firstField < 0)
       
  1136 			{
       
  1137 			// first item sorts lower
       
  1138 			retval = -1;
       
  1139 			}
       
  1140 		else if (secondField < 0)
       
  1141 			{
       
  1142 			// second item sorts lower
       
  1143 			retval = 1;
       
  1144 			}
       
  1145 		else
       
  1146 			{
       
  1147 			// set counter to the first field populated by either contact
       
  1148 			while ((firstField > counter) && (secondField > counter))
       
  1149 				{
       
  1150 				++counter;
       
  1151 				}
       
  1152 			
       
  1153 			retval = first.CompareC(second, aCollationLevel, aCollateMethod);
       
  1154 			}
       
  1155 		}
       
  1156 
       
  1157 	return retval;
       
  1158 	}
       
  1159 	
       
  1160 
       
  1161 /** Allocates and returns a descriptor filled with the contents of all the fields 
       
  1162 in a contact item.
       
  1163 
       
  1164 The fields are separated by the specified separator.
       
  1165 
       
  1166 @param aContacts An array of contact items.
       
  1167 @param aIndex An index into the specified array.
       
  1168 @param aSeparator The text to use to separate the fields.
       
  1169 @return A pointer to a heap descriptor containing the contents of each of the 
       
  1170 contact item's fields. The field separator is appended to each field except 
       
  1171 the last one. The pointer is left on the cleanup stack. */
       
  1172 HBufC* CViewContactManager::FieldsWithSeparatorLC(const CViewContact& aViewContact,const TDesC& aSeparator) const
       
  1173 	{
       
  1174 	// Calculate the length of the buffer.
       
  1175 	TInt bufLength = 0;
       
  1176 	const TInt separatorLength = aSeparator.Length();
       
  1177 	const TInt numFields = aViewContact.FieldCount();
       
  1178 	
       
  1179 	for (TInt ii = 0; ii < numFields; ++ii)
       
  1180 		{
       
  1181 		bufLength += aViewContact.Field(ii).Length() + separatorLength;
       
  1182 		}
       
  1183 		
       
  1184 	HBufC* buf = HBufC::NewLC(bufLength);
       
  1185 	TPtr bufPtr(buf->Des());
       
  1186 
       
  1187 	// Fill the buffer.
       
  1188 	for (TInt j = 0; j < numFields; ++j)
       
  1189 		{
       
  1190 		bufPtr.Append(aViewContact.Field(j));
       
  1191 
       
  1192 		// Only put a separator in if this isn't the last field.
       
  1193 		if (j != numFields-1)
       
  1194 			{
       
  1195 			bufPtr.Append(aSeparator);
       
  1196 			}
       
  1197 		}
       
  1198 	return buf;
       
  1199 	}