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