phonebookengines_old/contactsmodel/cntview/LocalView.cpp
changeset 40 b46a585f6909
equal deleted inserted replaced
37:fd64c38c277d 40:b46a585f6909
       
     1 // Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <phbksync.h>
       
    17 #include "CNTSTD.H"
       
    18 #include <cntviewbase.h>
       
    19 #include <cntitem.h>
       
    20 #include "cntviewprivate.h"
       
    21 #include <cntviewsortplugin.h>
       
    22 #include "persistencelayer.h"
       
    23 #include "cviewiterator.h"
       
    24 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
       
    25 #include <cntviewsortpluginbase.h>
       
    26 #endif
       
    27 //uncomment to test
       
    28 //#define __PROFILE_SORT__
       
    29 
       
    30 //uncomment for commonly required debug printing
       
    31 //#define __VERBOSE_DEBUG__
       
    32 
       
    33 extern void DebugLogNotification(const TDesC& aMethod, const TContactDbObserverEvent &aEvent);
       
    34 
       
    35 //
       
    36 // CContactLocalView.
       
    37 //
       
    38 
       
    39 // CIdle Callback function's return values: 0 - finished, 1 - call again
       
    40 // (CIdle is used to Insert & Sort contacts one at a time into the view)
       
    41 
       
    42 const TInt	KSortFinished = 0;
       
    43 const TInt	KSortCallAgain = 1;
       
    44 
       
    45 // Tunable constants
       
    46 // These seem to be useful values for memory allocations with RPointerArray
       
    47 const TInt	KContactsArrayGranularity = 100;
       
    48 const TInt	KUnsortedArrayGranularity = 16;
       
    49 // Number of Contacts to process per invocation of the Sorter
       
    50 // Local Views can't do much whilst sorting, but we want to allow other
       
    51 // Active Objects in the thread to run.
       
    52 const TInt	KNumberOfContactsPerChunk = 50;
       
    53 
       
    54 CContactLocalView::CContactLocalView(const CContactDatabase& aDb,TContactViewPreferences aContactTypes, MLplPersistenceLayerFactory* aFactory) 
       
    55 : CContactViewBase(aDb), 
       
    56 iFactory(aFactory),
       
    57 iContacts(KContactsArrayGranularity), 
       
    58 iUnSortedContacts(KUnsortedArrayGranularity),
       
    59 iViewPreferences(aContactTypes)
       
    60 /**
       
    61 @internalComponent
       
    62 */
       
    63 	{
       
    64 	}
       
    65 
       
    66 EXPORT_C CContactLocalView::CContactLocalView(const CContactDatabase& aDb,TContactViewPreferences aContactTypes) 
       
    67 : CContactViewBase(aDb), iContacts(KContactsArrayGranularity), iUnSortedContacts(KUnsortedArrayGranularity),
       
    68 iViewPreferences(aContactTypes)
       
    69 /** Protected C++ constructor.
       
    70 
       
    71 Called by NewL().
       
    72 
       
    73 @param aDb The underlying database that contains the contact items.
       
    74 @param aContactTypes Specifies which types of contact items should be included 
       
    75 in the view and the behaviour for items that do not have content in any of 
       
    76 the fields specified in the sort order. */
       
    77 	{
       
    78 	}
       
    79 
       
    80 EXPORT_C CContactLocalView::~CContactLocalView()
       
    81 /** Destructor.
       
    82 
       
    83 Deletes all resources owned by the object, and removes itself as the contact 
       
    84 database observer. */
       
    85 	{
       
    86 #ifdef CONTACTS_API_PROFILING
       
    87 	TContactsApiProfile::CntViewMethodLog(TContactsApiProfile::ECntVwClassLocalView, TContactsApiProfile::ECntViewDestructor);
       
    88 #endif
       
    89 	delete iTextDef;
       
    90 	delete iAsyncSorter;
       
    91 	iContacts.ResetAndDestroy();
       
    92 	iUnSortedContacts.ResetAndDestroy();
       
    93 	iOutstandingEvents.Close();
       
    94 	iSortOrder.Close();
       
    95 
       
    96 	if (&iDb != NULL)
       
    97 		{
       
    98         const_cast<CContactDatabase&>(iDb).RemoveObserver(*this);
       
    99 		}
       
   100 	delete iViewIterator;
       
   101 	}
       
   102 
       
   103 EXPORT_C CContactLocalView* CContactLocalView::NewL(MContactViewObserver& aObserver,const CContactDatabase& aDb,
       
   104 													const RContactViewSortOrder& aSortOrder,TContactViewPreferences aContactTypes)
       
   105 /** Allocates and constructs the local view object.
       
   106 
       
   107 The view is sorted according to the sort order and view preferences specified, 
       
   108 using a low priority idle time active object. The specified view observer 
       
   109 is notified when the view is sorted and ready for use.
       
   110 
       
   111 @param aObserver An observer that receives notifications when this view is 
       
   112 ready for use and when changes take place in it. The observer receives a TContactViewEvent::EReady 
       
   113 event when the view is ready. Any attempt to use the view before this notification will Leave with KErrNotReady
       
   114 @param aDb The underlying database that contains the contact items. The view 
       
   115 observes the database, so that it handles change events sent from the database.
       
   116 @param aSortOrder Specifies the fields to use to sort the items in the view.
       
   117 @param aContactTypes Specifies which types of contact items should be included 
       
   118 in the view and the behaviour for items that do not have content in any of 
       
   119 the fields specified in the sort order.
       
   120 @return The newly constructed local view object. */
       
   121 	{
       
   122 #ifdef CONTACTS_API_PROFILING
       
   123 	TContactsApiProfile::CntViewMethodLog(TContactsApiProfile::ECntVwClassLocalView, TContactsApiProfile::ECntViewApiNewL, aSortOrder, aContactTypes);
       
   124 #endif
       
   125 	CContactLocalView* self=new(ELeave) CContactLocalView(aDb,aContactTypes);
       
   126 	CleanupStack::PushL(self);
       
   127 	self->ConstructL(aObserver,aSortOrder);
       
   128 	CleanupStack::Pop(self); 
       
   129 	return self;
       
   130 	}
       
   131 
       
   132 EXPORT_C void CContactLocalView::ConstructL(MContactViewObserver& aObserver,const RContactViewSortOrder& aSortOrder)
       
   133 /** Protected second phase constructor.
       
   134 
       
   135 The view is sorted according to the sort order and view preferences specified, 
       
   136 using a low priority idle time active object. The specified view observer 
       
   137 is notified when the view is sorted and ready for use.
       
   138 
       
   139 Called by NewL().
       
   140 
       
   141 @param aObserver An observer that receives notifications when this view is 
       
   142 ready for use and when changes take place in it. The observer receives a TContactViewEvent::EReady 
       
   143 event when the view is ready. Any attempt to use the view before this notification will Leave with KErrNotReady.
       
   144 @param aSortOrder Specifies the fields to use to sort the items in the view. */
       
   145 	{
       
   146 	// call new ConstructL
       
   147 	ConstructL(aObserver, aSortOrder, EFalse, KNullDesC8);
       
   148 	}
       
   149 
       
   150 EXPORT_C CContactLocalView* CContactLocalView::NewL(MContactViewObserver& aObserver,const CContactDatabase& aDb,
       
   151 													const RContactViewSortOrder& aSortOrder,TContactViewPreferences aContactTypes,
       
   152 													const TDesC8& aSortPluginName)
       
   153 /** Allocates and constructs the local view object.
       
   154 
       
   155 The view is sorted according to the sort order and view preferences specified, 
       
   156 using a low priority idle time active object. The specified view observer 
       
   157 is notified when the view is sorted and ready for use.
       
   158 
       
   159 @param aObserver An observer that receives notifications when this view is 
       
   160 ready for use and when changes take place in it. The observer receives a TContactViewEvent::EReady 
       
   161 event when the view is ready. Any attempt to use the view before this notification will Leave with KErrNotReady
       
   162 @param aDb The underlying database that contains the contact items. The view 
       
   163 observes the database, so that it handles change events sent from the database.
       
   164 @param aSortOrder Specifies the fields to use to sort the items in the view.
       
   165 @param aContactTypes Specifies which types of contact items should be included 
       
   166 in the view and the behaviour for items that do not have content in any of 
       
   167 the fields specified in the sort order.
       
   168 @param aSortPluginName Specifies a plug-in that will be used to compare view contacts
       
   169 when the the view is sorted. This name is used by ECOM to select the plugin, and is matched
       
   170 with the "default_data" of all ECOM plugins that support the required interface.
       
   171 @return The newly constructed local view object. */
       
   172 	{
       
   173 #ifdef CONTACTS_API_PROFILING
       
   174 	TContactsApiProfile::CntViewMethodLog(TContactsApiProfile::ECntVwClassLocalView, TContactsApiProfile::ECntViewApiNewL, aSortOrder, aContactTypes, aSortPluginName);
       
   175 #endif
       
   176 	CContactLocalView* self=new(ELeave) CContactLocalView(aDb,aContactTypes);
       
   177 	CleanupStack::PushL(self);
       
   178 	self->ConstructL(aObserver, aSortOrder, ETrue, aSortPluginName);
       
   179 	CleanupStack::Pop(self); 
       
   180 	return self;
       
   181 	}
       
   182 
       
   183 /** CContactLocalView contructor, used in the server
       
   184 @internalTechnology 
       
   185  */
       
   186 EXPORT_C CContactLocalView* CContactLocalView::NewL(MContactViewObserver& aObserver,const CContactDatabase& aDb,const RContactViewSortOrder& aSortOrder,TContactViewPreferences aContactTypes,
       
   187 		MLplPersistenceLayerFactory* aFactory,const TDesC8& aSortPluginName)
       
   188 	{
       
   189 	CContactLocalView* self=new(ELeave) CContactLocalView(aDb,aContactTypes,aFactory);
       
   190 	CleanupStack::PushL(self);
       
   191 	self->ConstructL(aObserver, aSortOrder, ETrue, aSortPluginName);
       
   192 	CleanupStack::Pop(self); 
       
   193 	return self;
       
   194 	}
       
   195 
       
   196 void CContactLocalView::ConstructL(MContactViewObserver& aObserver,const RContactViewSortOrder& aSortOrder,
       
   197 								   TBool aUseNamedPlugin, const TDesC8& aSortPluginName)
       
   198 /** Protected second phase constructor.
       
   199 
       
   200 The view is sorted according to the sort order and view preferences specified, 
       
   201 using a low priority idle time active object. The specified view observer 
       
   202 is notified when the view is sorted and ready for use.
       
   203 
       
   204 Called by NewL().
       
   205 
       
   206 @internalComponent
       
   207 @param aObserver An observer that receives notifications when this view is 
       
   208 ready for use and when changes take place in it. The observer receives a TContactViewEvent::EReady 
       
   209 event when the view is ready. Any attempt to use the view before this notification will Leave with KErrNotReady.
       
   210 @param aSortOrder Specifies the fields to use to sort the items in the view. 
       
   211 @param aUseNamedPlugin A flag indicates whether the aSortPluginName parameter is valid.
       
   212 @param aSortPluginName Specifies a plug-in that will be used to compare view contacts
       
   213 when the the view is sorted. This name is used by ECOM to select the plugin, and is matched
       
   214 with the "default_data" of all ECOM plugins that support the required interface.
       
   215 */
       
   216 	{
       
   217 	CContactViewBase::ConstructL();
       
   218 	if(iFactory == NULL)
       
   219 		{
       
   220 		iFactory = const_cast<CContactDatabase&>(iDb).FactoryL();
       
   221 		}
       
   222 	iAsyncSorter = CIdleContactSorter::NewL(*this, *iFactory);
       
   223 
       
   224 	OpenL(aObserver);
       
   225 	if (aUseNamedPlugin)
       
   226 		{
       
   227 		// find and load Sort plug-in
       
   228 		if (aSortPluginName.Length())
       
   229 			{
       
   230 			TUid sortPluginUid = FindSortPluginImplL (aSortPluginName);
       
   231 			LoadViewSortPluginL(sortPluginUid, iViewPreferences);
       
   232 			}
       
   233 		}
       
   234 	else
       
   235 		{
       
   236 		// find and load default Sort plug-in (if any)
       
   237 		TUid sortPluginUid = FindDefaultViewSortPluginImplL();
       
   238 		if (sortPluginUid != KNullUid)
       
   239 			{
       
   240 			LoadViewSortPluginL(sortPluginUid, iViewPreferences);
       
   241 			}
       
   242 		}
       
   243 	// initialise for sort, and start if the database is ready
       
   244 	InitialiseSortL(aSortOrder, EFalse);
       
   245 	if (&iDb != NULL)
       
   246 		{
       
   247         const_cast<CContactDatabase&>(iDb).AddObserverL(*this);
       
   248 		}
       
   249 	}
       
   250 
       
   251 
       
   252 EXPORT_C const RContactViewSortOrder& CContactLocalView::SortOrder() const
       
   253 /** Gets the sort order, as set during construction.
       
   254 
       
   255 @return The sort order. */
       
   256 	{
       
   257 #ifdef CONTACTS_API_PROFILING
       
   258 	TContactsApiProfile::CntViewMethodLog(TContactsApiProfile::ECntVwClassLocalView, TContactsApiProfile::ECntViewApiSortOrder);
       
   259 #endif
       
   260 	return iSortOrder;
       
   261 	}
       
   262 
       
   263 TContactItemId CContactLocalView::AtL(TInt aIndex) const
       
   264 /** Returns the ID of the contact item at a specified index into the view.
       
   265 
       
   266 @param aIndex An index into the view.
       
   267 @leave KErrNotFound The index is out of bounds.
       
   268 @return The ID of the contact item at the specified index.
       
   269 @leave KErrNotReady The view is not ready for use.  */
       
   270 	{
       
   271 #ifdef CONTACTS_API_PROFILING
       
   272 	TContactsApiProfile::CntViewMethodLog(TContactsApiProfile::ECntVwClassLocalView, TContactsApiProfile::ECntViewApiAtL, aIndex);
       
   273 #endif
       
   274 	const CViewContact& contact = ContactAtL(aIndex);
       
   275 	return contact.Id();
       
   276 	}
       
   277 
       
   278 const CViewContact& CContactLocalView::ContactAtL(TInt aIndex) const
       
   279 /** Returns the contact item at a specified index into the view.
       
   280 
       
   281 @param aIndex An index into the view.
       
   282 @leave KErrNotFound The index is out of bounds.
       
   283 @leave KErrNotReady The view is not ready for use.
       
   284 @return The contact item at the specified index. */
       
   285 	{
       
   286 #ifdef CONTACTS_API_PROFILING
       
   287 	TContactsApiProfile::CntViewMethodLog(TContactsApiProfile::ECntVwClassLocalView, TContactsApiProfile::ECntViewApiContactAtL, aIndex);
       
   288 #endif
       
   289 	// state cannot be EInitializing or ENotReady
       
   290 	if( iState != EReady )
       
   291 		{
       
   292 		User::Leave(KErrNotReady);
       
   293 		}
       
   294 
       
   295 	TInt offsetIndex=aIndex;
       
   296 	const TInt unsortedCount=iUnSortedContacts.Count();
       
   297 	const TInt sortedCount=iContacts.Count();
       
   298 	if(offsetIndex >= (unsortedCount+sortedCount))
       
   299 		{
       
   300 		//Out of Bounds.
       
   301 		User::Leave(KErrNotFound);
       
   302 		}
       
   303 
       
   304 	if(unsortedCount>0)
       
   305 		{
       
   306 		if(iViewPreferences & EUnSortedAtBeginning)
       
   307 			{
       
   308 			if(aIndex<unsortedCount)
       
   309 				{
       
   310 				//contact in unsorted array
       
   311 				return *iUnSortedContacts[aIndex];
       
   312 				}
       
   313 			else
       
   314 				{
       
   315 				//contact in sorted array
       
   316 				offsetIndex-=unsortedCount;
       
   317 				}
       
   318 			}
       
   319 		else if ((iViewPreferences & EUnSortedAtEnd) && (aIndex>=sortedCount))
       
   320 			{
       
   321 			offsetIndex-=sortedCount;
       
   322 			return *iUnSortedContacts[offsetIndex];
       
   323 			}
       
   324 
       
   325 		}
       
   326 	return *iContacts[offsetIndex];
       
   327 	}
       
   328 
       
   329 TInt CContactLocalView::CountL() const
       
   330 /** Gets the total number of contact items in the view.
       
   331 
       
   332 @return The number of contact items in the view. This includes both sorted 
       
   333 and unsorted items.
       
   334 @leave KErrNotReady The view is not ready for use. */
       
   335 	{
       
   336 #ifdef CONTACTS_API_PROFILING
       
   337 	TContactsApiProfile::CntViewMethodLog(TContactsApiProfile::ECntVwClassLocalView, TContactsApiProfile::ECntViewApiCountL);
       
   338 #endif
       
   339 	// state cannot be EInitializing or ENotReady
       
   340 	if( iState != EReady )
       
   341 		{
       
   342 		User::Leave(KErrNotReady);
       
   343 		}
       
   344 	
       
   345 	TInt count(iUnSortedContacts.Count());
       
   346 	count+=iContacts.Count();
       
   347 	return count;
       
   348 	}
       
   349 
       
   350 TInt CContactLocalView::FindL(TContactItemId aId) const
       
   351 /** Searches for a contact item in the view with the specified ID.
       
   352 
       
   353 @param aId The ID of the contact item to search for.
       
   354 @return If found, the index into the view of the matching item. Otherwise, 
       
   355 KErrNotFound.
       
   356 @leave KErrNotReady The view is not ready for use.  */
       
   357 	{
       
   358 #ifdef CONTACTS_API_PROFILING
       
   359 	TContactsApiProfile::CntViewMethodLog(TContactsApiProfile::ECntVwClassLocalView, TContactsApiProfile::ECntViewApiFindL, aId);
       
   360 #endif
       
   361 	// state cannot be EInitializing or ENotReady
       
   362 	if( iState != EReady )
       
   363 		{
       
   364 		User::Leave(KErrNotReady);
       
   365 		}
       
   366 
       
   367 	TInt index=KErrNotFound;
       
   368 	CViewContact* contact = CViewContact::NewLC(aId);
       
   369 	const TInt unSortedCount=iUnSortedContacts.Count();
       
   370 	// first look in unsorted contacts
       
   371 	if(unSortedCount > 0)
       
   372 		{
       
   373 		// contact may be in the unsorted array
       
   374 		index = iUnSortedContacts.Find(contact,TIdentityRelation<CViewContact>(IdsMatch));
       
   375 
       
   376 		if ((index != KErrNotFound) && (iViewPreferences & EUnSortedAtEnd))
       
   377 			{
       
   378 			// account for sorted array size
       
   379 			index = index + iContacts.Count();
       
   380 			}
       
   381 		}
       
   382 
       
   383 	// if not found try sorted contacts
       
   384 	if (index == KErrNotFound)
       
   385 		{
       
   386 		//contact may be in the sorted array
       
   387 		index = iContacts.Find(contact,TIdentityRelation<CViewContact>(IdsMatch));
       
   388 
       
   389 		if ((index != KErrNotFound) && (iViewPreferences & EUnSortedAtBeginning))
       
   390 			{
       
   391 			// account for unsorted array size
       
   392 			index = index + unSortedCount;
       
   393 			}
       
   394 		}
       
   395 
       
   396 	CleanupStack::PopAndDestroy(contact);
       
   397 	return index;
       
   398 	}
       
   399 
       
   400 HBufC* CContactLocalView::AllFieldsLC(TInt aIndex,const TDesC& aSeparator) const
       
   401 /** Gets a descriptor containing the contents of all fields specified in the view's 
       
   402 sort order for an item in the view.
       
   403 
       
   404 The field separator is used to separate the contents of each field. It is 
       
   405 not appended to the last field.
       
   406 
       
   407 @param aIndex The index of the contact item into the view.
       
   408 @param aSeparator The string to use to separate the fields.
       
   409 @return Pointer to the contact item descriptor. */
       
   410 	{
       
   411 #ifdef CONTACTS_API_PROFILING
       
   412 	TContactsApiProfile::CntViewMethodLog(TContactsApiProfile::ECntVwClassLocalView, TContactsApiProfile::ECntViewApiAllFieldsLC, aIndex);
       
   413 #endif
       
   414 
       
   415 	if( iState != EReady )
       
   416 		{
       
   417 		User::Leave(KErrNotReady);
       
   418 		}
       
   419 
       
   420 	TInt offsetIndex=aIndex;
       
   421 	const TInt unSortedCount=iUnSortedContacts.Count();
       
   422 	if(unSortedCount>0)
       
   423 		{
       
   424 		if(iViewPreferences & EUnSortedAtBeginning)
       
   425 			{
       
   426 			if(aIndex<unSortedCount)
       
   427 				{
       
   428 				//contact in unsorted array
       
   429 				return FieldsWithSeparatorLC(iUnSortedContacts,aIndex,aSeparator);
       
   430 				}
       
   431 			else
       
   432 				{
       
   433 				//contact in sorted array
       
   434 				offsetIndex-=unSortedCount;
       
   435 				}
       
   436 			}
       
   437 		else if(iViewPreferences & EUnSortedAtEnd)
       
   438 			{
       
   439 			const TInt sortedCount=iContacts.Count();
       
   440 			if(aIndex>=sortedCount)
       
   441 				{
       
   442 				offsetIndex-=sortedCount;
       
   443 				return FieldsWithSeparatorLC(iUnSortedContacts,offsetIndex,aSeparator);
       
   444 				}
       
   445 			}
       
   446 		}
       
   447 	return FieldsWithSeparatorLC(iContacts,offsetIndex,aSeparator);
       
   448 	}
       
   449 
       
   450 EXPORT_C void CContactLocalView::SortL(const RContactViewSortOrder& aSortOrder)
       
   451 /** Sorts the view using the specified sort order, using a low priority idle time 
       
   452 active object.
       
   453 
       
   454 This function is called during view construction and on receipt of certain 
       
   455 change events from the underlying database.
       
   456 
       
   457 @param aSortOrder Specifies the fields to use to sort the items in the view. */
       
   458 	{
       
   459 #ifdef CONTACTS_API_PROFILING
       
   460 	TContactsApiProfile::CntViewMethodLog(TContactsApiProfile::ECntVwClassLocalView, TContactsApiProfile::ECntViewApiSortL);
       
   461 #endif
       
   462 	// re-initialise sort, and try to start it
       
   463 	InitialiseSortL(aSortOrder, ETrue);
       
   464 	}
       
   465 
       
   466 
       
   467 /*
       
   468  Start first sort of view, or restart after SortL() API has changed the order.
       
   469  */
       
   470 void CContactLocalView::InitialiseSortL(const RContactViewSortOrder& aSortOrder, TBool aChangingSortOrder)
       
   471 	{
       
   472 	if (aChangingSortOrder)
       
   473 		{
       
   474 		if (&iDb != NULL)
       
   475 			{
       
   476 			if (!iDb.DatabaseReadyL())
       
   477 				{
       
   478 				User::Leave(KErrNotReady);
       
   479 				}
       
   480 			}
       
   481 		}
       
   482 
       
   483 	// copy new sort order
       
   484 	TRAPD(sortStartError, iSortOrder.CopyL(aSortOrder));
       
   485 	
       
   486 	if (sortStartError)
       
   487 		{
       
   488 		// ensure Db Recover (close then open tables) cannot push view to EReady
       
   489 		iExtension->iError = sortStartError;
       
   490 		User::Leave(sortStartError);
       
   491 		}
       
   492 
       
   493 	// New sort order for Sort Plugin
       
   494 	CViewContactSortPlugin* sortPluginImpl = SortPluginImpl();
       
   495 	if (sortPluginImpl)
       
   496 		{
       
   497 		sortPluginImpl->SetSortOrderL(aSortOrder);
       
   498 		}
       
   499 
       
   500 	// View can Sort only if database is 'ready'.
       
   501 	if (&iDb != NULL)
       
   502 		{
       
   503 		if (!iDb.DatabaseReadyL())
       
   504 			{
       
   505 			return;
       
   506 			}
       
   507 		}
       
   508 
       
   509 	// database is ready for reading - so start the Sort
       
   510 	SortL();
       
   511 	}
       
   512 
       
   513 
       
   514 /**
       
   515 Safe resort of view after Recover, Backup/Restore, etc...
       
   516 
       
   517 @internalComponent
       
   518 @released
       
   519 */
       
   520 void CContactLocalView::SafeResort()
       
   521 	{
       
   522 	TInt sortError(KErrNone);
       
   523 	
       
   524 	// Database tables are closed across backup or restore so we may need to
       
   525 	// re-open view iterator here.
       
   526 	if (iViewIterator == NULL)
       
   527 		{
       
   528 		const TContactViewPreferences viewPrefs = iAsyncSorter->SortViewPreferences();
       
   529 		TRAP(sortError,
       
   530 			if(iFactory == NULL)
       
   531 				{
       
   532 				iFactory = const_cast<CContactDatabase&>(iDb).FactoryL();
       
   533 				}
       
   534 			MLplViewIteratorManager& manager = iFactory->GetViewIteratorManagerL();
       
   535 			iViewIterator = new (ELeave) CViewIterator(manager,*iTextDef,viewPrefs);
       
   536 			) // TRAP
       
   537 		}
       
   538 
       
   539 	if (!sortError)
       
   540 		{
       
   541 		TRAP(sortError, SortL());
       
   542 		}
       
   543 
       
   544 	// notify any error
       
   545 	if (sortError)
       
   546 		{
       
   547 		NotifySortError(sortError);
       
   548 		}
       
   549 	}
       
   550 
       
   551 
       
   552 /**
       
   553 @internalComponent
       
   554 @released
       
   555 */
       
   556 void CContactLocalView::SortL()
       
   557 	{
       
   558 	// Initialisation for each explicitly requested sort
       
   559 	// Construct a text def to read out the required fields from the db.
       
   560 	CContactTextDef* textDef=CContactTextDef::NewLC();
       
   561 	TInt sortOrderCount=iSortOrder.Count();
       
   562 
       
   563 	for (TInt sortIndex=0;sortIndex<sortOrderCount;sortIndex++)
       
   564 		{
       
   565 		textDef->AppendL(TContactTextDefItem(iSortOrder[sortIndex]));
       
   566 		}
       
   567 	CleanupStack::Pop(); // textDef.
       
   568 	delete iTextDef;
       
   569 	iTextDef=textDef;
       
   570 
       
   571 	// NB ResetSortL() requires iTextDef to be initialised
       
   572 
       
   573 	// initialisation for each pass (of the insert sort) through the db
       
   574 	// (2 passes may be required if the SIM card starts locked and is then unlocked)
       
   575 	// (such a 2nd pass is kicked off by CIdleContactSorter)
       
   576 	ResetSortL();
       
   577 
       
   578 	// Delete existing sort if present.
       
   579 	iAsyncSorter->Stop();
       
   580 
       
   581 	iContacts.ResetAndDestroy();
       
   582 	iUnSortedContacts.ResetAndDestroy();
       
   583 
       
   584 #ifdef __PROFILE_SORT__
       
   585 	RDebug::Print(_L("[CNTMODEL] CntModel View, , %u, %u, Starting sort\n"), 
       
   586 		static_cast<TUint>(RProcess().Id()), 
       
   587 		static_cast<TUint>(RThread().Id()));
       
   588 
       
   589 	// 3 timers: 1st for read/Append; 2nd for Sort, 3rd for Compare
       
   590 	RDebug::ProfileReset(1,3);
       
   591 	RDebug::ProfileStart(1);
       
   592 #endif
       
   593 
       
   594 	// reset sort error
       
   595 	iExtension->iError = KErrNone;
       
   596 
       
   597 	// Kick off idler.
       
   598 	iAsyncSorter->Start();
       
   599 	}
       
   600 
       
   601 void CContactLocalView::ResetSortL()
       
   602 /**
       
   603  * Setup for a fresh pass through the Contacts database table
       
   604  *
       
   605  * (Code was in SortL)
       
   606  */
       
   607 	{
       
   608 	delete iViewIterator;
       
   609 	iViewIterator = NULL;
       
   610 	}
       
   611 
       
   612 EXPORT_C TInt CContactLocalView::InsertL(TContactItemId aId)
       
   613 /** Inserts a contact item into the view, maintaining the view's sort order.
       
   614 
       
   615 For the item to be inserted, it must exist in the underlying database, and 
       
   616 it must be of the correct type according to the view preferences.
       
   617 
       
   618 This function is called when a contact item or group is added to or changed 
       
   619 in the underlying database.
       
   620 
       
   621 @param aId The ID of a contact item that exists in the underlying database.
       
   622 @return The index at which the item was inserted into the view, or KErrNotFound 
       
   623 if the contact item was not found in the underlying database, or it already 
       
   624 exists in the view. */
       
   625 	{
       
   626 	TInt index=KErrNotFound;
       
   627 #if defined(__VERBOSE_DEBUG__)
       
   628 	RDebug::Print(_L("[CNTMODEL] CContactLocalView{ViewPrefs = 0x%08X}::InsertL into view Contact Id %i\r\n"), 
       
   629 		iViewPreferences, aId);
       
   630 #endif
       
   631 	TContactViewPreferences view = iViewPreferences;
       
   632 	if(!iAsyncSorter->InsertViewPreferences(view))
       
   633 		{
       
   634 		return KErrNotFound;
       
   635 		}
       
   636 	if(iFactory == NULL)
       
   637 		{
       
   638 		iFactory = const_cast<CContactDatabase&>(iDb).FactoryL();
       
   639 		}
       
   640 	MLplViewIteratorManager& manager = iFactory->GetViewIteratorManagerL();
       
   641 	CViewIterator* iter = new (ELeave) CViewIterator(manager,*iTextDef,view);
       
   642 	CleanupStack::PushL(iter);
       
   643 	CViewContact* contact = iter->ItemAtL(aId);
       
   644 	CleanupStack::PopAndDestroy(iter);	
       
   645 	if(contact != NULL && ContactCorrectType(contact->ContactTypeUid(),view))
       
   646 		{
       
   647 		CleanupStack::PushL(contact);
       
   648 		if(IsContactSortable(*contact, iViewPreferences))
       
   649 			{
       
   650 			//Contact has normal fields and can be added to the standard sorted array				
       
   651 #if defined(__VERBOSE_DEBUG__)
       
   652 				RDebug::Print(_L("[CNTMODEL] > > > > > View Insert into RPointerArray [Count = %i]\r\n"), iContacts.Count());
       
   653 #endif
       
   654 				
       
   655 			// Insert using Sort Plugin compare method, and get new index
       
   656 			User::LeaveIfError(InsertContactInView(iContacts, contact, EFalse, &index));
       
   657 			CleanupStack::Pop(contact);
       
   658 			if (iViewPreferences & EUnSortedAtBeginning)
       
   659 				{
       
   660 				index += iUnSortedContacts.Count();
       
   661 				}
       
   662 			}
       
   663 		else if (iViewPreferences & (EUnSortedAtBeginning | EUnSortedAtEnd))
       
   664 			{
       
   665 			// unsortable contacts go at the end or beginning
       
   666 			// we want this to be stable (e.g. when ICC becomes unlocked)
       
   667 			User::LeaveIfError(InsertContactInView(iUnSortedContacts, contact, ETrue, &index));
       
   668 			CleanupStack::Pop(contact);
       
   669 			// calc new index
       
   670 			if (iViewPreferences & EUnSortedAtEnd)
       
   671 				{
       
   672 				index += iContacts.Count();
       
   673 				}
       
   674 			}
       
   675 		else // EIgnoreUnSorted
       
   676 			{
       
   677 			CleanupStack::PopAndDestroy(contact);
       
   678 			}
       
   679 		}
       
   680 	else if(contact)
       
   681 		{
       
   682 		delete contact;
       
   683 		}
       
   684 
       
   685 	return index;
       
   686 	}
       
   687 
       
   688 EXPORT_C TInt CContactLocalView::RemoveL(TContactItemId aId)
       
   689 /** Removes a contact item from the view.
       
   690 
       
   691 This function is called when a contact item or group is deleted from or changed 
       
   692 in the underlying database.
       
   693 
       
   694 @param aId The ID of the contact item to remove from the view.
       
   695 @return The index of the removed item into the view's list of sorted or unsorted 
       
   696 contact items, or KErrNotFound if the item was not found in the view. */
       
   697 	{
       
   698 	CViewContact* contact = CViewContact::NewLC(aId);
       
   699 	TInt index=KErrNotFound;
       
   700 	index=iContacts.Find(contact,TIdentityRelation<CViewContact>(IdsMatch));
       
   701 	if (index!=KErrNotFound)
       
   702 		{
       
   703 		CViewContact* temp= iContacts[index];
       
   704 		iContacts.Remove(index);
       
   705 		delete temp;
       
   706 		if (iViewPreferences & EUnSortedAtBeginning)
       
   707 			{
       
   708 			index+=iUnSortedContacts.Count();
       
   709 			}
       
   710 		}
       
   711 	else
       
   712 		{
       
   713 		if(iUnSortedContacts.Count()>0)
       
   714 			{
       
   715 			index=iUnSortedContacts.Find(contact,TIdentityRelation<CViewContact>(IdsMatch));
       
   716 			if (index!=KErrNotFound)
       
   717 				{
       
   718 				CViewContact* temp= iUnSortedContacts[index];
       
   719 				iUnSortedContacts.Remove(index);
       
   720 				delete temp;
       
   721 				if (iViewPreferences & EUnSortedAtEnd)
       
   722 					{	
       
   723 					index+=iContacts.Count();
       
   724 					}
       
   725 				// NB - If EIgnoreUnsorted, then this clause would not be running,
       
   726 				// as the contact would never be added to the view.
       
   727 				}
       
   728 			}
       
   729 		}
       
   730 	CleanupStack::PopAndDestroy(contact);
       
   731 	return index;
       
   732 	}
       
   733 
       
   734 EXPORT_C void CContactLocalView::CContactLocalView_Reserved_1()
       
   735 	{
       
   736 	}
       
   737 
       
   738 EXPORT_C void CContactLocalView::CContactLocalView_Reserved_2()
       
   739 	{
       
   740 	}
       
   741 
       
   742 void CContactLocalView::HandleDatabaseEventL(TContactDbObserverEvent aEvent)
       
   743 	{
       
   744 	// handle Backup / Restore notifications before checking View State
       
   745 	switch (aEvent.iType)
       
   746 		{
       
   747 		case EContactDbObserverEventBackupBeginning:
       
   748 		case EContactDbObserverEventRestoreBeginning:
       
   749 #if defined(__VERBOSE_DEBUG__)
       
   750 			RDebug::Print(_L("[CNTMODEL] CContactLocalView{ViewPrefs = 0x%08X}::HandleDatabaseEventL -> Backup/Restore Beginning, state = %i\r\n"), 
       
   751 				iViewPreferences, iState);
       
   752 #endif
       
   753 			if (iState == EReady)
       
   754 				{
       
   755 				SetState(ENotReady);
       
   756 				}
       
   757 			else
       
   758 				{
       
   759 				// stop sorting
       
   760 				iAsyncSorter->Stop();
       
   761 				}
       
   762 			ResetSortL();
       
   763 			return;
       
   764 
       
   765 		case EContactDbObserverEventBackupRestoreCompleted:
       
   766 #if defined(__VERBOSE_DEBUG__)
       
   767 			RDebug::Print(_L("[CNTMODEL] CContactLocalView{ViewPrefs = 0x%08X}::HandleDatabaseEventL -> Backup/Restore Completed, state = %i, old sort error %i\r\n"), 
       
   768 				iViewPreferences, iState, iExtension->iError);
       
   769 #endif
       
   770 			if (iState == ENotReady && iExtension->iError == KErrNone)
       
   771 				{
       
   772 				// view was ready before tables were closed
       
   773 				SetState(EReady);
       
   774 				}
       
   775 			else // view was Initializing (sorting) before tables were closed
       
   776 				{
       
   777 				// re-read database and sort
       
   778 				SafeResort();
       
   779 				}
       
   780 			return;
       
   781 
       
   782 		default:
       
   783 			// other events dealt with below
       
   784 			break;
       
   785 		}
       
   786 
       
   787 
       
   788 	if (iState!=EReady)
       
   789 		{
       
   790         // The tables have been closed so the the sort must be cancelled.
       
   791 		if (aEvent.iType == EContactDbObserverEventTablesClosed)
       
   792 			{
       
   793 	    	iAsyncSorter->Stop();
       
   794 			}
       
   795 
       
   796 		if (iAsyncSorter->QueueViewEvents())
       
   797 			{
       
   798        			
       
   799 #if defined(__VERBOSE_DEBUG__)
       
   800 			DebugLogNotification(_L("[CNTMODEL] . . . . . Queueing Database Event "), aEvent);
       
   801 #endif
       
   802 			iOutstandingEvents.AppendL(aEvent);
       
   803 			// The view state is set to ENotReady when a recovery takes place, and also when the tables
       
   804 			// are closed, so set ready here.
       
   805 			if (iState==ENotReady && (aEvent.iType==EContactDbObserverEventRecover || aEvent.iType==EContactDbObserverEventTablesOpened))
       
   806 				{
       
   807 				SetState(EReady);
       
   808 				}
       
   809 			// view was Initializing (sorting) before recovery or compression started!	
       
   810 			if (iState==EInitializing && (aEvent.iType==EContactDbObserverEventRecover || aEvent.iType==EContactDbObserverEventCompress))
       
   811 				{
       
   812 				// re-read database and sort
       
   813 				SafeResort();
       
   814 				}
       
   815 			}		
       
   816 			
       
   817 			
       
   818 #if defined(__VERBOSE_DEBUG__)
       
   819 		else
       
   820 			{
       
   821 			DebugLogNotification(_L("[CNTMODEL] . . . . . Discarding Database Event "), aEvent);
       
   822 			}
       
   823 #endif
       
   824 		}
       
   825 	else
       
   826 		{
       
   827 		TContactViewEvent event;
       
   828 		event.iInt = KErrNone;
       
   829 		switch(aEvent.iType)
       
   830 			{
       
   831 			case EContactDbObserverEventGroupChanged:
       
   832 				{
       
   833 				//Groups are a special case the base view may not contain the group
       
   834 				//but a sub view may be such a group and need to know its changed
       
   835 				//Local views can contain groups so this case carries on to the next so no break;
       
   836 				event.iEventType=TContactViewEvent::EGroupChanged;
       
   837 				event.iContactId=aEvent.iContactId;
       
   838 				NotifyObservers(event);
       
   839 				}
       
   840 			case EContactDbObserverEventContactChanged:
       
   841 			case EContactDbObserverEventOwnCardChanged:
       
   842 				{// Remove from old position, and notify.
       
   843 				TRAPD(err,event.iInt=RemoveL(aEvent.iContactId));
       
   844 
       
   845                 if (err == KErrNone && event.iInt != KErrNotFound)
       
   846                     {
       
   847 				    event.iEventType=TContactViewEvent::EItemRemoved;
       
   848 				    event.iContactId=aEvent.iContactId;
       
   849 				    NotifyObservers(event);
       
   850 					}
       
   851 				
       
   852 				// Insert at new position, and notify.
       
   853 				event.iInt=InsertL(aEvent.iContactId);
       
   854                 if (event.iInt != KErrNotFound)
       
   855 					{
       
   856 				    event.iEventType=TContactViewEvent::EItemAdded;
       
   857 				    event.iContactId=aEvent.iContactId;
       
   858 				    NotifyObservers(event);
       
   859                     }
       
   860 				break;
       
   861 				}
       
   862 			case EContactDbObserverEventContactAdded:
       
   863 			case EContactDbObserverEventGroupAdded:
       
   864 #if defined(__VERBOSE_DEBUG__)
       
   865 			DebugLogNotification(_L("[CNTMODEL] DatabaseEvent -> Contact/Group Added"), aEvent);
       
   866 #endif
       
   867 				event.iInt=InsertL(aEvent.iContactId);
       
   868 				if (event.iInt != KErrNotFound)
       
   869 					{
       
   870 					event.iEventType=TContactViewEvent::EItemAdded;
       
   871 					event.iContactId=aEvent.iContactId;
       
   872 					NotifyObservers(event);
       
   873 					}
       
   874 				break;
       
   875 			case EContactDbObserverEventContactDeleted:
       
   876 				if(aEvent.iContactId == KNullContactId)// KNullContactId indicates a bulk delete 
       
   877 					{
       
   878 					SetState(EInitializing); // Use initializing state to avoid ESortOrderChanged event being sent to observers.
       
   879 					SafeResort();
       
   880 					}
       
   881 				else
       
   882 					{
       
   883 					event.iInt=RemoveL(aEvent.iContactId);
       
   884 					if (event.iInt != KErrNotFound)
       
   885 						{
       
   886 						event.iEventType=TContactViewEvent::EItemRemoved;
       
   887 						event.iContactId=aEvent.iContactId;
       
   888 						NotifyObservers(event);
       
   889 						}
       
   890 					}
       
   891 				break;
       
   892 			case EContactDbObserverEventGroupDeleted:
       
   893 			case EContactDbObserverEventOwnCardDeleted:
       
   894 				event.iInt=RemoveL(aEvent.iContactId);
       
   895 				if (event.iInt != KErrNotFound)
       
   896 					{
       
   897 					event.iEventType=TContactViewEvent::EItemRemoved;
       
   898 					event.iContactId=aEvent.iContactId;
       
   899 					NotifyObservers(event);
       
   900 					}
       
   901 				break;
       
   902 			case EContactDbObserverEventUnknownChanges:
       
   903 			case EContactDbObserverEventCurrentDatabaseChanged:
       
   904 				SetState(EInitializing); // Use initializing state to avoid ESortOrderChanged event being sent to observers.
       
   905 				SafeResort();
       
   906 				break;
       
   907 			case EContactDbObserverEventSortOrderChanged: // event is not currently used
       
   908 				SetState(ENotReady);
       
   909 				SafeResort();
       
   910 				break;
       
   911 			case EContactDbObserverEventTablesClosed:
       
   912 				if (iState == EReady)
       
   913 					{
       
   914 					SetState(ENotReady);
       
   915 					}
       
   916 				break;
       
   917 			case EContactDbObserverEventTablesOpened:
       
   918 				// re-read database and sort
       
   919 				SafeResort();
       
   920 				break;
       
   921 
       
   922 			case EContactDbObserverEventNull:
       
   923 			case EContactDbObserverEventUnused:
       
   924 			case EContactDbObserverEventRecover:
       
   925 			case EContactDbObserverEventCompress:
       
   926 			case EContactDbObserverEventRollback:
       
   927 			case EContactDbObserverEventTemplateChanged:
       
   928 			case EContactDbObserverEventTemplateDeleted:
       
   929 			case EContactDbObserverEventTemplateAdded:
       
   930 			case EContactDbObserverEventCurrentItemDeleted:
       
   931 			case EContactDbObserverEventCurrentItemChanged:				
       
   932 			case EContactDbObserverEventPreferredTemplateChanged:
       
   933 			case EContactDbObserverEventSpeedDialsChanged:
       
   934 			case EContactDbObserverEventRestoreBadDatabase:
       
   935 				break;
       
   936 
       
   937 			// these events should not come here, but be dealt with at the top of HandleDatabaseEventL
       
   938 			case EContactDbObserverEventBackupBeginning:
       
   939 			case EContactDbObserverEventRestoreBeginning:
       
   940 			case EContactDbObserverEventBackupRestoreCompleted:
       
   941 				break;
       
   942 				
       
   943 			default:
       
   944 				ASSERT(EFalse);
       
   945 			}
       
   946 		}
       
   947 	}
       
   948 
       
   949 TInt CContactLocalView::SortCallBack()
       
   950 	{
       
   951 	TInt ret=KErrNotFound;
       
   952 	TRAPD(err, ret = DoReadIncrementL());
       
   953 
       
   954 #if defined(__VERBOSE_DEBUG__)
       
   955 	if (err)
       
   956 		{
       
   957 		RDebug::Print(_L("[CNTMODEL] CContactLocalView{ViewPrefs = 0x%08X} . . . DoReadIncrementL ERROR %i\r\n"),
       
   958 			iViewPreferences, err);
       
   959 		}
       
   960 	else
       
   961 		{
       
   962 		RDebug::Print(_L("[CNTMODEL] CContactLocalView{ViewPrefs = 0x%08X} . . . DoReadIncrementL returned %i\r\n"),
       
   963 			iViewPreferences, ret);
       
   964 		}
       
   965 #endif
       
   966 
       
   967 	if(err!=KErrNone)
       
   968 		{
       
   969 		ret=err;
       
   970 		}
       
   971 	if (ret<0)
       
   972 		{
       
   973 		// There was an error, so notify observers and stop any further callbacks.
       
   974 		NotifySortError(ret);
       
   975 		return KSortFinished;
       
   976 		}
       
   977 	if (ret==0)
       
   978 		{
       
   979 		//Read Has Finished.
       
   980 #ifdef __PROFILE_SORT__
       
   981 		RDebug::ProfileEnd(1);
       
   982 
       
   983 		RDebug::ProfileStart(2);
       
   984 #endif
       
   985 
       
   986 		// is there a View Sort ECOM plug-in present?
       
   987 		CViewContactSortPlugin*	sortPluginImpl = SortPluginImpl();
       
   988 
       
   989 		if (sortPluginImpl)
       
   990 			{
       
   991 			// prepare View Sort plug-in
       
   992 			ret = sortPluginImpl->SortStart(CViewContactSortPlugin::ESortStartFull, iContacts.Count());
       
   993 
       
   994 			if (ret < 0)
       
   995 				{
       
   996 				return ret;
       
   997 				}
       
   998 			}
       
   999 
       
  1000 		// customised array sort implementation
       
  1001 		TRAP(err, ContactsArraySortL());
       
  1002 
       
  1003 		//Sort Has Finished.
       
  1004 		if (sortPluginImpl)
       
  1005 			{
       
  1006 			sortPluginImpl->SortCompleted();
       
  1007 			}
       
  1008 
       
  1009 
       
  1010 #ifdef __PROFILE_SORT__
       
  1011 
       
  1012 		RDebug::ProfileEnd(2);
       
  1013 		TProfile profile[3];
       
  1014 		RDebug::ProfileResult(profile,1,3);
       
  1015 
       
  1016 		RDebug::Print(_L("[CNTMODEL] CntModel View, , %u, %u, Finished sort total, %u us\n"), 
       
  1017 			static_cast<TUint>(RProcess().Id()), static_cast<TUint>(RThread().Id()),
       
  1018 			profile[1].iTime + profile[0].iTime);
       
  1019 
       
  1020 		RDebug::Print(_L("[CNTMODEL] CntModel View, , , , Data Read time, %u us\n"), profile[0].iTime);
       
  1021 		RDebug::Print(_L("[CNTMODEL] CntModel View, , , , Data Sort time, %u us\n"), profile[1].iTime);
       
  1022 		RDebug::Print(_L("[CNTMODEL] CntModel View, , , , Compare time, %u us\n"), profile[2].iTime);
       
  1023 
       
  1024 #endif
       
  1025 
       
  1026 		// sort finished, change state, allow for 2nd pass for ICC entries
       
  1027 		TInt result = iAsyncSorter->SortComplete();
       
  1028 
       
  1029 		if (iState != EInitializing)
       
  1030 			{
       
  1031 			//The view has just been re-sorted notifiy observers ESortOrderChanged
       
  1032 			iState = EReady;
       
  1033 			NotifyObservers(TContactViewEvent(TContactViewEvent::ESortOrderChanged));
       
  1034 			HandleOutstandingEvents();
       
  1035 			return result;
       
  1036 			}
       
  1037 		// Sorted for the first time, notifiy ready
       
  1038 		SetState(EReady);
       
  1039 		return result;
       
  1040 		}
       
  1041 	// There's more reading to be done, so request another callback.
       
  1042 	return KSortCallAgain;
       
  1043 	}
       
  1044 
       
  1045 TInt CContactLocalView::DoReadIncrementL()
       
  1046 	{
       
  1047 #if defined(__VERBOSE_DEBUG__)
       
  1048 	RDebug::Print(_L("[CNTMODEL] CContactLocalView{ViewPrefs = 0x%08X}::DoReadIncrement()"), iViewPreferences);
       
  1049 #endif
       
  1050 
       
  1051 	// what contacts are we adding to the View?
       
  1052 	const TContactViewPreferences viewPrefs = iAsyncSorter->SortViewPreferences();
       
  1053 
       
  1054 	if(iViewIterator == NULL)
       
  1055 		{
       
  1056 		if(iFactory == NULL)
       
  1057 			{
       
  1058 			iFactory = const_cast<CContactDatabase&>(iDb).FactoryL();
       
  1059 			}
       
  1060 		MLplViewIteratorManager& manager = iFactory->GetViewIteratorManagerL();
       
  1061 		iViewIterator = new (ELeave) CViewIterator(manager,*iTextDef,viewPrefs);
       
  1062 		iViewIterator->GoFirstL();
       
  1063 		}
       
  1064 	TInt i(0);
       
  1065 	// process a chunk of contacts
       
  1066 	CViewContact* contact;
       
  1067 	for(;i<KNumberOfContactsPerChunk;++i)
       
  1068 		{
       
  1069 		contact = iViewIterator->NextItemL();
       
  1070 		if(contact == NULL)
       
  1071 			{
       
  1072 			break; // No more contacts so quick exit
       
  1073 			}
       
  1074 		else if(!ContactCorrectType(contact->ContactTypeUid(),viewPrefs))
       
  1075 			{
       
  1076 			delete contact;
       
  1077 			}
       
  1078 		else
       
  1079 			{
       
  1080 			CleanupStack::PushL(contact);
       
  1081 			if(IsContactSortable(*contact,iViewPreferences))
       
  1082 				{
       
  1083 				iContacts.AppendL(contact);
       
  1084 				CleanupStack::Pop(contact);
       
  1085 				}
       
  1086 			else if(iViewPreferences & (EUnSortedAtBeginning | EUnSortedAtEnd))
       
  1087 				{
       
  1088 				// unsortable contacts go at the end or beginning
       
  1089 				iUnSortedContacts.AppendL(contact);
       
  1090 				CleanupStack::Pop(contact);
       
  1091 				}
       
  1092 			else
       
  1093 				{
       
  1094 				CleanupStack::PopAndDestroy(contact);
       
  1095 				}
       
  1096 			}	
       
  1097 		}
       
  1098 	if(i== KNumberOfContactsPerChunk)
       
  1099 		{
       
  1100 		// Loop did not break so more contacts
       
  1101 		return ETrue;
       
  1102 		}
       
  1103 	else
       
  1104 		{
       
  1105 		// Loop break so no more contacts
       
  1106 		return EFalse;
       
  1107 		}
       
  1108 	}
       
  1109 
       
  1110 void CContactLocalView::ContactsArraySortL()
       
  1111 	{
       
  1112 
       
  1113 	// HeapSort (stolen from RPointerArrayBase)
       
  1114 	TInt ss = iContacts.Count();
       
  1115 	if (ss>1)
       
  1116 		{
       
  1117 		TInt sh = ss>>1;
       
  1118 		FOREVER
       
  1119 			{
       
  1120 			CViewContact* si;
       
  1121 			if (sh!=0)
       
  1122 				{
       
  1123 				// make heap
       
  1124 				--sh;
       
  1125 				si = iContacts[sh];
       
  1126 				}
       
  1127 			else
       
  1128 				{
       
  1129 				// sort heap
       
  1130 				--ss;
       
  1131 				si = iContacts[ss];
       
  1132 				iContacts[ss] = iContacts[0];
       
  1133 				if (ss==1)
       
  1134 					{
       
  1135 					iContacts[0] = si;
       
  1136 					break;
       
  1137 					}
       
  1138 				}
       
  1139 
       
  1140 			// sift down
       
  1141 			TInt ii = sh;
       
  1142 			TInt jj = sh;
       
  1143 			FOREVER
       
  1144 				{
       
  1145 				jj = (jj+1)<<1;
       
  1146 				if (jj>=ss || CompareContactsAndIdsL(*iContacts[jj-1],*iContacts[jj])>0 )
       
  1147 					--jj;
       
  1148 				if (jj>=ss || CompareContactsAndIdsL(*iContacts[jj],*si)<=0 )
       
  1149 					break;
       
  1150 				iContacts[ii] = iContacts[jj];
       
  1151 				ii = jj;
       
  1152 				}
       
  1153 			iContacts[ii]=si;
       
  1154 			}
       
  1155 		}
       
  1156 
       
  1157 	}
       
  1158 
       
  1159 
       
  1160 /**
       
  1161 @internalComponent
       
  1162 */
       
  1163 void CContactLocalView::SetState(TState aState)
       
  1164 	{
       
  1165 	switch (iState)
       
  1166 		{
       
  1167 		case EInitializing:
       
  1168 		case ENotReady:
       
  1169 			ASSERT(aState==EReady);
       
  1170 			iState=EReady;
       
  1171 			NotifyObservers(TContactViewEvent(TContactViewEvent::EReady));
       
  1172 			HandleOutstandingEvents();
       
  1173 			break;
       
  1174 		case EReady:
       
  1175 			ASSERT(aState==ENotReady || aState==EInitializing);
       
  1176 			// ensure sort error is reset
       
  1177 			iExtension->iError = KErrNone;
       
  1178 			iState=aState;
       
  1179 			NotifyObservers(TContactViewEvent(TContactViewEvent::EUnavailable));
       
  1180 			break;
       
  1181 		default:
       
  1182 			ASSERT(EFalse);
       
  1183 		}
       
  1184 	}
       
  1185 
       
  1186 
       
  1187 void CContactLocalView::HandleOutstandingEventL()
       
  1188 	{
       
  1189 	TContactDbObserverEvent event = iOutstandingEvents[0];
       
  1190 	iOutstandingEvents.Remove(0);
       
  1191 	HandleDatabaseEventL(event);
       
  1192 	}
       
  1193 
       
  1194 void CContactLocalView::HandleOutstandingEvents()
       
  1195 	{
       
  1196 	while (iOutstandingEvents.Count() > 0)
       
  1197 		{
       
  1198 		// loop through as many events as possible in the one Trap harness
       
  1199 		TRAP_IGNORE(HandleOutstandingEventL());
       
  1200 		// if HandleDatabaseEventL left we must remove the event
       
  1201 		}
       
  1202 	}
       
  1203 
       
  1204 TContactViewPreferences CContactLocalView::ContactViewPreferences()
       
  1205 /** Gets the view preferences, as set during construction.
       
  1206 
       
  1207 @return The view preferences. */
       
  1208 	{
       
  1209 	return iViewPreferences;
       
  1210 	}
       
  1211 
       
  1212 const RContactViewSortOrder& CContactLocalView::SortOrderL() const
       
  1213 /** Gets the sort order, as set during construction.
       
  1214 
       
  1215 This function cannot leave.
       
  1216 
       
  1217 @return The sort order. */
       
  1218 	{
       
  1219 	return iSortOrder;
       
  1220 	}
       
  1221 
       
  1222 /*
       
  1223  * Notify observers that view construction failed.
       
  1224  * The error is stored so that if another client tries to open the view
       
  1225  * they will receive the same error.
       
  1226  * @param aError Leave code from CIdleContactSorter::RunL
       
  1227  */
       
  1228 void CContactLocalView::NotifySortError(TInt aError)
       
  1229 	{
       
  1230 	iExtension->iError = aError;
       
  1231 	NotifyObservers(TContactViewEvent(TContactViewEvent::ESortError, aError));
       
  1232 	}
       
  1233 
       
  1234 /*
       
  1235  * This is a reserved virtual exported function that is used for BC proofing 
       
  1236  * against present and future additions of new exported virtual functions.
       
  1237  @return Any return values of the helper methods called from this function or NULL.
       
  1238 */
       
  1239 EXPORT_C TAny* CContactLocalView::CContactViewBase_Reserved_1(TFunction aFunction,TAny* aParams)
       
  1240 	{
       
  1241 	return CContactViewBase::CContactViewBase_Reserved_1(aFunction,aParams);
       
  1242 	}
       
  1243 
       
  1244 
       
  1245 /*
       
  1246  * Factory constructor.
       
  1247  * @since 7.0
       
  1248  * @param aView Reference to CContactLocalView object
       
  1249  */
       
  1250 CIdleContactSorter* CIdleContactSorter::NewL(CContactLocalView& aView, MLplPersistenceLayerFactory& aFactory)
       
  1251 	{
       
  1252 	CIdleContactSorter* self = new (ELeave) CIdleContactSorter(aView, aFactory);
       
  1253 	CleanupStack::PushL(self);
       
  1254 	self->ConstructL();
       
  1255 	CleanupStack::Pop(self);
       
  1256 	return self;
       
  1257 	}
       
  1258 
       
  1259 /* Destructor */
       
  1260 CIdleContactSorter::~CIdleContactSorter()
       
  1261 	{
       
  1262 	Cancel();
       
  1263 
       
  1264 	if (iPhbkSyncWatcher)
       
  1265 		{
       
  1266 		iPhbkSyncWatcher->RemovePhbkObserver(*this);
       
  1267 		ReleasePhbkSyncWatcher();
       
  1268 		}
       
  1269 	}
       
  1270 
       
  1271 /* Cancel any active requests to the phonebook synchroniser */
       
  1272 void CIdleContactSorter::DoCancel()
       
  1273 	{
       
  1274 	// Nothing to do.
       
  1275 	}
       
  1276 
       
  1277 /** 
       
  1278  * Uses a simple state machine, initial iSortState is set by Start() to either
       
  1279  * EInsertSortFinal or EWaitingForInitialICCReady
       
  1280  *
       
  1281  * Either Insert Sort all or part of the requested view.
       
  1282  * (CIdle::RunL calls back to the Insert Sort code.)
       
  1283  *    State
       
  1284  *    EInsertContactsOnlyIccLocked		  insert Contacts only (in a mixed view)
       
  1285  *        goes to EContactsReadyWaitICCUnlock
       
  1286  *    EInsertSortFinal                    insert all Contacts & ICC entries, or
       
  1287  *        goes to ESortDone               add ICC entries to mixed view
       
  1288  *                                        (iSortView specifies which)
       
  1289  * Or wait for Phonebook Synchroniser to either finish or fail
       
  1290  *    (failure other than SIM Locked causes a Sort Error) 
       
  1291  *    State
       
  1292  *    EWaitingForInitialICCReady          the view has nothing in: Phonebook
       
  1293  *        goes to EInsertSortFinal        Synchronised allows full view to be available;
       
  1294  *        or EInsertContactsOnlyIccLocked SIM Locked allows a view without ICC entries to 
       
  1295  *                                        accessible
       
  1296  *    EContactsReadyWaitICCUnlock         SIM was previously found to be locked, if/when
       
  1297  *        goes to EInsertSortFinal        Phonebook Synchroniser completes we can merge in
       
  1298  *                                        requested ICC entries
       
  1299  *
       
  1300  * The check whether the phonebook synchroniser is in a cache-valid state:-
       
  1301  *
       
  1302  * This check is done by making a async request to be completed when the 
       
  1303  * phbksync cache state has changed, checking the current cache state and 
       
  1304  * if the cache is valid already cancelling the request.
       
  1305  * (The cancelled request will complete, causing RunL to run again.)
       
  1306  * If there was a phbksync error check the error code, if it is not due to the
       
  1307  * SIM card being locked then Leave.
       
  1308  */
       
  1309 void CIdleContactSorter::RunL()
       
  1310 	{
       
  1311 #if defined(__VERBOSE_DEBUG__)
       
  1312 	RDebug::Print(_L("[CNTMODEL] CIdleContactSorter{RequestedView = 0x%08X, SortView = 0x%08X}::RunL()\r\n"),
       
  1313 		iRequestedView, iSortView);
       
  1314 	TSorterState oldSortState = iSortState;		// for debug messages only
       
  1315 #endif
       
  1316 
       
  1317 	User::LeaveIfError(iStatus.Int());
       
  1318 
       
  1319 	// either sort or wait for ICC ready / phonebook synch state change
       
  1320 	switch (iSortState)
       
  1321 		{
       
  1322 		// states that are sorting all or part of view
       
  1323 	case EInsertSortFinal:				// full insert sort or Phonebook Synched so add ICC entries
       
  1324 	case EInsertContactsOnlyIccLocked:	// insert Contacts for now, then wait for SIM to be unlocked
       
  1325 		// do slice of full / Contacts only /ICC only insert sort
       
  1326 		if (iView.SortCallBack() == KSortCallAgain)
       
  1327 			{ // CAsyncOneShot::Call()
       
  1328 			Call();
       
  1329 			}
       
  1330 		break;
       
  1331 
       
  1332 		// states that are waiting for a phonebook sync event
       
  1333 	case EWaitingForInitialICCReady:	// ICC entries in view, waiting for Phonebook Synch state change
       
  1334 		// ICC entries are included in view:
       
  1335 		if (iPhbkSyncWatcher->PhonebooksReady() > 0)
       
  1336 			{
       
  1337 			// ICC sync complete - can immediately sort everything
       
  1338 			ChangeSortState(EInsertSortFinal);
       
  1339 			}
       
  1340 		else if (iPhbkSyncWatcher->PhonebooksWaiting() > 0)
       
  1341 			{
       
  1342 			// SIM card is locked and, this is the first time we've seen this
       
  1343 
       
  1344 			// Insert Contacts (if wanted) into View now
       
  1345 			// Afterwards we will wait again for SIM to unlock & Phonebook Synch to complete
       
  1346 			if(iRequestedView & EICCEntriesAndContacts)
       
  1347 				{
       
  1348 				// insert/sort view, but without the requested ICC entries
       
  1349 				iSortView = static_cast<TContactViewPreferences>(iSortView & ~EICCEntriesAndContacts);
       
  1350 				ChangeSortState(EInsertContactsOnlyIccLocked);
       
  1351 				}
       
  1352 			else 
       
  1353 				{
       
  1354 				// only ICC entries were wanted in the first place
       
  1355 				// so make the (empty) View Ready
       
  1356 				const_cast<CContactLocalView&>(iView).SetState(CContactLocalView::EReady);
       
  1357 				// now wait for SIM to unlock & Phonebook Synch to complete
       
  1358 				ChangeSortState(EContactsReadyWaitICCUnlock);
       
  1359 				}
       
  1360 			}
       
  1361 		else
       
  1362 			{
       
  1363 			// synchronisation finished with an error?
       
  1364 			User::LeaveIfError(iPhbkSyncWatcher->PhonebookSyncError());
       
  1365 			}
       
  1366 
       
  1367 		// otherwise wait for a Phonebook Synch event
       
  1368 		break;
       
  1369 
       
  1370 	case EContactsReadyWaitICCUnlock:	// when SIM is unlocked add ICC Entries to this view
       
  1371 		// ICC entries are included in view:
       
  1372 		if (iPhbkSyncWatcher->PhonebooksReady() > 0)
       
  1373 			{
       
  1374 			// ICC sync complete - can sort everything
       
  1375 			ChangeSortState(EInsertSortFinal);
       
  1376 
       
  1377 			// add requested ICC entries into the sorted view
       
  1378 			iSortView = STATIC_CAST(TContactViewPreferences, (iSortView & ~EContactsOnly) | EICCEntriesOnly);
       
  1379 			const_cast<CContactLocalView&>(iView).SetState(CContactLocalView::ENotReady);
       
  1380 
       
  1381 			// another pass through contacts database is needed
       
  1382 			// ResetSortL should not Leave (especially as it must have worked previously)
       
  1383 			const_cast<CContactLocalView&>(iView).ResetSortL();
       
  1384 			}	
       
  1385 
       
  1386 		// otherwise wait for a Phonebook Synch event
       
  1387 		break;
       
  1388 
       
  1389 	case ESortAllDone: // shouldn't have come back here
       
  1390 	default:
       
  1391 		Panic(ECntPanicViewSorterStateMachine);
       
  1392 		break;
       
  1393 		}
       
  1394 
       
  1395 #if defined(__VERBOSE_DEBUG__)
       
  1396 	if (oldSortState != iSortState)
       
  1397 		{
       
  1398 		switch (iSortState)
       
  1399 			{
       
  1400 			case EInsertSortFinal:
       
  1401 				RDebug::Print(_L("[CNTMODEL] {RequestedView = 0x%08X} * * * new Sort State = EInsertSortFinal, SortView = 0x%08X\r\n"),
       
  1402 					iRequestedView, iSortView);
       
  1403 				break;
       
  1404 			case EInsertContactsOnlyIccLocked:
       
  1405 				RDebug::Print(_L("[CNTMODEL] {RequestedView = 0x%08X} * * * new Sort State = EInsertContactsOnlyIccLocked, SortView = 0x%08X\r\n"),
       
  1406 					iRequestedView, iSortView);
       
  1407 				break;
       
  1408 			case EWaitingForInitialICCReady:
       
  1409 				RDebug::Print(_L("[CNTMODEL] {RequestedView = 0x%08X} * * * new Sort State = EWaitingForInitialICCReady\r\n"),
       
  1410 					iRequestedView);
       
  1411 				break;
       
  1412 			case EContactsReadyWaitICCUnlock:
       
  1413 				RDebug::Print(_L("[CNTMODEL] {RequestedView = 0x%08X} * * * new Sort State = EContactsReadyWaitICCUnlock, SortView = 0x%08X\r\n"),
       
  1414 					iRequestedView, iSortView);
       
  1415 				break;
       
  1416 			case ESortAllDone:
       
  1417 				RDebug::Print(_L("[CNTMODEL] {RequestedView = 0x%08X} * * * new Sort State = ESortAllDone\r\n"), iRequestedView);
       
  1418 				break;
       
  1419 			}
       
  1420 		}
       
  1421 	RDebug::Print(_L("[CNTMODEL] [Unsorted Contacts = %i, Sorted Contacts = %i, IsActive = %i]\r\n"),
       
  1422 		const_cast<CContactLocalView&>(iView).iUnSortedContacts.Count(),
       
  1423 		const_cast<CContactLocalView&>(iView).iContacts.Count(),
       
  1424 		IsActive());
       
  1425 #endif
       
  1426 
       
  1427 	}
       
  1428 
       
  1429 
       
  1430 void CIdleContactSorter::ChangeSortState(TSorterState aNewSortState)
       
  1431 	{
       
  1432 #if defined(__VERBOSE_DEBUG__)
       
  1433 	RDebug::Print(_L("[CNTMODEL] CIdleContactSorter{RequestedView = 0x%08X, SortView = 0x%08X}::ChangeSortState(%i)\r\n"),
       
  1434 		iRequestedView, iSortView, static_cast<TInt>(aNewSortState));
       
  1435 #endif
       
  1436 	// new state
       
  1437 	iSortState = aNewSortState;
       
  1438 	// make the active object to run, CAsyncOneShot::Call()
       
  1439 	Call();
       
  1440 	}
       
  1441 
       
  1442 
       
  1443 /* 
       
  1444  * Handle any leave during CIdleContactSorter::RunL. 
       
  1445  * The local view is informed of that the view construction failed.
       
  1446  * It will broadcast an ESortError view event to all clients of this view.
       
  1447  * 
       
  1448  * @param aError Leave code from RunL
       
  1449  */
       
  1450 TInt CIdleContactSorter::RunError(TInt aError)
       
  1451 	{
       
  1452 #if defined(__VERBOSE_DEBUG__)
       
  1453 	RDebug::Print(_L("[CNTMODEL] CIdleContactSorter{RequestedView = 0x%08X, SortView = 0x%08X}::RunError(error = %i)\r\n"),
       
  1454 		iRequestedView, iSortView, aError);
       
  1455 #endif
       
  1456 	if ((aError != KErrCancel) && (iSortState != ESortAllDone))
       
  1457 		{
       
  1458 		const_cast<CContactLocalView&>(iView).NotifySortError(aError);
       
  1459 		iSortState = ESortAllDone;
       
  1460 		}
       
  1461 	return KErrNone;
       
  1462 	}
       
  1463 
       
  1464 
       
  1465 TInt CIdleContactSorter::SortComplete()
       
  1466 /**
       
  1467  * Sort or partial sort completed, decide if there is more to do:
       
  1468  * EInsertSortFinal -> ESortAllDone
       
  1469  * EInsertContactsOnlyIccLocked -> EContactsReadyWaitICCUnlock (wait for SIM to become unlocked)
       
  1470  *
       
  1471  * return KSortCallAgain if there is more work to do, KSortFinished otherwise
       
  1472  */
       
  1473 	{
       
  1474 	if(iSortState == EInsertContactsOnlyIccLocked)
       
  1475 		{
       
  1476 		// we are now waiting for phbksync, so that we can add ICC entries
       
  1477 		iSortState = EContactsReadyWaitICCUnlock;
       
  1478 #if defined(__VERBOSE_DEBUG__)
       
  1479 		RDebug::Print(_L("[CNTMODEL] * * * * * SortComplete: New Sort State = EContactsReadyWaitICCUnlock\r\n"));
       
  1480 #endif
       
  1481 		// CIdleContactSorter has more to do
       
  1482 		return KSortCallAgain;
       
  1483 		}
       
  1484 
       
  1485 	// CIdleContactSorter all done
       
  1486 	iSortState = ESortAllDone;
       
  1487 #if defined(__VERBOSE_DEBUG__)
       
  1488 	RDebug::Print(_L("[CNTMODEL] * * * * * SortComplete: New Sort State = ESortAllDone\r\n"));
       
  1489 #endif
       
  1490 	return KSortFinished;
       
  1491 	}
       
  1492 
       
  1493 /*
       
  1494  Initialise Idle Contact Sorter for a new sort
       
  1495 
       
  1496  Re-init iSortView - the view filter for the Insert Sort
       
  1497  Decide the initial iSortState for RunL:
       
  1498    Contacts only view -> EInsertSortFinal
       
  1499    ICC entries included -> EWaitingForInitialICCReady
       
  1500  */
       
  1501  void CIdleContactSorter::Start()
       
  1502 	{
       
  1503 	// initially we will try to insert sort everything requested
       
  1504 	iSortView = iRequestedView;
       
  1505 
       
  1506 	if (iPhbkSyncWatcher)
       
  1507 		{
       
  1508 		// ICC entries included in view, must wait for Phonebook Synch
       
  1509 		iSortState = EWaitingForInitialICCReady;
       
  1510 		}
       
  1511 	else
       
  1512 		{
       
  1513 		// Only Contacts wanted in view, we can Sort straight away
       
  1514 		iSortState = EInsertSortFinal;
       
  1515 		}
       
  1516 
       
  1517 #if defined(__VERBOSE_DEBUG__)
       
  1518 	RDebug::Print(
       
  1519 		(iSortState == EInsertSortFinal) ? 
       
  1520 			_L("[CNTMODEL] CIdleContactSorter{RequestedView = 0x%08X}::Start() Sort State = EInsertSortFinal\r\n") :
       
  1521 			_L("[CNTMODEL] CIdleContactSorter{RequestedView = 0x%08X}::Start() Sort State = EWaitingForInitialICCReady\r\n"),
       
  1522 		iRequestedView);
       
  1523 #endif
       
  1524 
       
  1525 	// set Active for the first time, CAsyncOneShot::Call()
       
  1526 	Call();
       
  1527 	}
       
  1528 
       
  1529 
       
  1530 /*
       
  1531  Stop any sort that is already in progress
       
  1532  */
       
  1533 void CIdleContactSorter::Stop()
       
  1534 	{
       
  1535 	if (iSortState != ESortAllDone)
       
  1536  		{
       
  1537 		// stop sorting
       
  1538 		iSortState = ESortAllDone;
       
  1539 		Cancel();
       
  1540  		}
       
  1541 	}
       
  1542 
       
  1543 
       
  1544 /* 
       
  1545  * Second phase construction.
       
  1546  * Copy the View's requested preferences, get link to ICC phonebook watcher
       
  1547  */
       
  1548 void CIdleContactSorter::ConstructL()
       
  1549 	{
       
  1550 	iRequestedView = CONST_CAST(CContactLocalView&,iView).ContactViewPreferences();
       
  1551 
       
  1552 	// is ICC phonebook sync expected?
       
  1553 	if (iRequestedView & (EICCEntriesOnly | EICCEntriesAndContacts))
       
  1554 		{
       
  1555 		iPhbkSyncWatcher = GetPhbkSyncWatcherL();
       
  1556 
       
  1557 		// observe ICC sync events
       
  1558 		iPhbkSyncWatcher->AddPhbkObserverL(*this);
       
  1559 		}
       
  1560 	}
       
  1561 
       
  1562  /*
       
  1563  Utility method to return a reference to the ICC synchroniser watcher.
       
  1564  Always returns a pointer to the real phonebook synchroniser plugin.
       
  1565  It is assumed that Phonebook synchronising server never creates the view,
       
  1566  so the deadlock in not possible and the dummy plugin is not required.
       
  1567 
       
  1568  @internalTechnology
       
  1569  @leave KErrNotSupported if contact synchroniser plug-in cannot be found
       
  1570  @leave KErrNoMemory if not enough memory
       
  1571  @return Pointer to CContactPhbkSyncWatcher instance.
       
  1572  */
       
  1573 CContactPhbkSyncWatcher* CIdleContactSorter::GetPhbkSyncWatcherL()
       
  1574 	{
       
  1575 	if (!iPhbkSyncWatcher)
       
  1576 		{
       
  1577 		iPhbkSyncWatcher = CContactPhbkSyncWatcher::NewL(iFactory.GetContactSynchroniserL(KMaxTUint32)); //Always use the Contact Synchroniser
       
  1578 		}
       
  1579 	return iPhbkSyncWatcher;
       
  1580 	}
       
  1581 
       
  1582 
       
  1583 void CIdleContactSorter::ReleasePhbkSyncWatcher()
       
  1584 	{
       
  1585 	if (iPhbkSyncWatcher)
       
  1586 		{
       
  1587 		if (iPhbkSyncWatcher->ObserverCount() == 0)
       
  1588 			{
       
  1589 			delete iPhbkSyncWatcher;
       
  1590 			iPhbkSyncWatcher = NULL;
       
  1591 			}
       
  1592 		}
       
  1593 	}
       
  1594 
       
  1595 
       
  1596 /* Constructor */
       
  1597   CIdleContactSorter::CIdleContactSorter(CContactLocalView& aView, MLplPersistenceLayerFactory& aFactory) 
       
  1598   : CAsyncOneShot(CActive::EPriorityLow), iView(aView), iFactory(aFactory)
       
  1599 	{
       
  1600 	}
       
  1601 
       
  1602 /* 
       
  1603  * Determines whether view events should be queued.
       
  1604  *
       
  1605  * View events are only queued when the ICC has been synchronised. This prevents
       
  1606  * duplicate contacts in an ICC view because add events are not queued until the 
       
  1607  * SIM is fully synchronised. 
       
  1608  * 
       
  1609  * See LUD-5EBHZF "ICC contacts view broadcasts add item events after view is 
       
  1610  * ready" for more detail.
       
  1611  * 
       
  1612  * @return ETrue, if view events should be queued. EFalse, otherwise
       
  1613  */
       
  1614 TBool CIdleContactSorter::QueueViewEvents() const
       
  1615 	{
       
  1616 	// Initial wait for phonebook synch (i.e. waiting for ICC ready or locked) ?
       
  1617 	if(iSortState == EWaitingForInitialICCReady)
       
  1618 		{
       
  1619 		return EFalse;
       
  1620 		}
       
  1621 	return ETrue;
       
  1622 	}
       
  1623 
       
  1624 TContactViewPreferences CIdleContactSorter::SortViewPreferences() const
       
  1625 /**
       
  1626  * Current View Preferences for insert sort in to View
       
  1627  *
       
  1628  * May be a subset of the requested View.
       
  1629  * If the SIM card is locked this will initially be a View without ICC entries.
       
  1630  * If the SIM becomes unlocked a second pass then picks out ICC entries only.
       
  1631  *
       
  1632  */
       
  1633 	{
       
  1634 	return iSortView;
       
  1635 	}
       
  1636 
       
  1637 
       
  1638 TBool CIdleContactSorter::InsertViewPreferences(TContactViewPreferences &aInsertView) const
       
  1639 /**
       
  1640  * Modifies View Preferences for inserting into View
       
  1641  *
       
  1642  * May be a subset of the requested View:
       
  1643  * If a Mixed (Contacts & ICC view) is requested and the Phonebook Synch has NOT
       
  1644  * completed then only Contacts entries are added to the view. When the PhoneBook Synch 
       
  1645  * completes all ICC entries will at the same time.
       
  1646  *
       
  1647  */
       
  1648 	{
       
  1649 	TBool okayToInsert = ETrue;
       
  1650 
       
  1651 	switch (iSortState)
       
  1652 		{
       
  1653 	case EInsertSortFinal:				// full insert sort or Phonebook Synched so add ICC entries
       
  1654 	case ESortAllDone:
       
  1655 		// view is finished or finishing, can Insert any contact
       
  1656 		break;
       
  1657 
       
  1658 	case EInsertContactsOnlyIccLocked:	// insert Contacts for now, then wait for SIM to be unlocked
       
  1659 		// only Contacts can be inserted now, no ICC entries
       
  1660 		aInsertView = iSortView;
       
  1661 		break;
       
  1662 
       
  1663 	case EWaitingForInitialICCReady:	// ICC entries in view, waiting for Phonebook Synch state change
       
  1664 		// Waiting for initial ICC Synch result, insert nothing
       
  1665 		okayToInsert = EFalse;
       
  1666 		break;
       
  1667 
       
  1668 	case EContactsReadyWaitICCUnlock:	// when SIM is unlocked add ICC Entries to this view
       
  1669 		if (aInsertView & EICCEntriesOnly)
       
  1670 			{
       
  1671 			okayToInsert = EFalse;		// can't insert ICC entries yet
       
  1672 			}
       
  1673 		else
       
  1674 			{
       
  1675 			aInsertView = iSortView;	// only Insert Contacts
       
  1676 			}
       
  1677 		break;
       
  1678 		}
       
  1679 
       
  1680 	return okayToInsert;
       
  1681 	}
       
  1682 
       
  1683 TBool CContactLocalView::ContactCorrectType(TUid aType,TContactViewPreferences aTypeToInclude)
       
  1684 	{
       
  1685 	TBool correctType(EFalse);
       
  1686 	if (aType==KUidContactCard || aType==KUidContactOwnCard)
       
  1687 		{
       
  1688 		// Ignore Unsorted Contacts flags & White Space flag
       
  1689 		// catch non- contact views
       
  1690 		// Should be EContactsOnly, EContactAndGroups & EICCEntriesAndContacts
       
  1691 		if (0 == ((aTypeToInclude & ~(ESingleWhiteSpaceIsEmptyField | EIgnoreUnSorted | EUnSortedAtBeginning | EUnSortedAtEnd))
       
  1692 				& (EGroupsOnly | EICCEntriesOnly))) // Ignore 'UnSorted' flags, exclude Groups Only & ICC Only 
       
  1693 			{
       
  1694 			correctType = ETrue;
       
  1695 			}
       
  1696 		}
       
  1697 	else if (aType==KUidContactGroup)
       
  1698 		{
       
  1699 		if (aTypeToInclude & (EGroupsOnly | EContactAndGroups))
       
  1700 			{
       
  1701 			correctType = ETrue;
       
  1702 			}
       
  1703 		}
       
  1704 	else if (aType == KUidContactICCEntry)
       
  1705 		{
       
  1706 		if (aTypeToInclude & (EICCEntriesOnly | EICCEntriesAndContacts))
       
  1707 			{
       
  1708 			correctType = ETrue;
       
  1709 			}
       
  1710 		}
       
  1711 	return correctType;
       
  1712 	}
       
  1713 
       
  1714 
       
  1715 void CIdleContactSorter::ContactPhbkSyncEventHandler(TPhonebookState aPhbkState)
       
  1716 	{
       
  1717 #if defined(__VERBOSE_DEBUG__)
       
  1718 	RDebug::Print(_L("[CNTMODEL] CIdleContactSorter{RequestedView = 0x%08X, SortView = 0x%08X}::ContactPhbkSyncEventHandler\r\n"),
       
  1719 		iRequestedView, iSortView);
       
  1720 #endif
       
  1721 	switch (aPhbkState)
       
  1722 		{
       
  1723 		case EIccPhbkNotSynchronised:
       
  1724 			/* Initial state, or ICC card has 'gone away' (e.g. ICC is resetting). */
       
  1725 			// no action - may want to act on this in future
       
  1726 			break;
       
  1727 
       
  1728 		case EIccPhbkSynchronised:	// ICC Phonebook has completed synchronisation.
       
  1729 
       
  1730 		case EIccWaitForPhbkToBeReady:	// Sync failed due to ICC being locked or not ready.
       
  1731 
       
  1732 		case EIccPhbkSyncError:		//	Sync with Phbk Server failed.
       
  1733 
       
  1734 #if defined(__VERBOSE_DEBUG__)
       
  1735 			RDebug::Print(aPhbkState == EIccPhbkSynchronised ? _L("[CNTMODEL]     state = ICC phonebook synchronised)\r\n") :
       
  1736 				aPhbkState == EIccWaitForPhbkToBeReady ? _L("    state = ICC phonebook Locked)\r\n") :
       
  1737 				 _L("    state = ICC phonebook Sync Error)\r\n"));
       
  1738 #endif
       
  1739 			// in a sorting state where we care?
       
  1740 			if ((iSortState == EWaitingForInitialICCReady) || (iSortState == EContactsReadyWaitICCUnlock))
       
  1741 				{
       
  1742 				// let state machine in RunL() deal with the event
       
  1743 				if (!IsActive())
       
  1744 					{ // CAsyncOneShot::Call()
       
  1745 					Call();
       
  1746 					}
       
  1747 				}
       
  1748 			break;
       
  1749 		}
       
  1750 	}
       
  1751 
       
  1752