--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/predictivesearch/PcsAlgorithm/Algorithm2/src/CPcsAlgorithm2.cpp Wed Sep 01 12:29:52 2010 +0100
@@ -0,0 +1,1668 @@
+/*
+* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: Predictive Contact Search Algorithm 1 main class
+*
+*/
+
+// INCLUDES
+#include <VPbkEng.rsg>
+#include <PtiEngine.h>
+#include <centralrepository.h>
+#include <AknFepInternalCRKeys.h>
+
+#include "CPcsAlgorithm2.h"
+#include "CPcsAlgorithm2Helper.h"
+#include "CPcsAlgorithm2MultiSearchHelper.h"
+#include "CPcsAlgorithm2Utils.h"
+#include "CPcsDebug.h"
+#include "CPcsCache.h"
+#include "CPcsKeyMap.h"
+#include "CPsData.h"
+#include "CWords.h"
+#include "CPsQuery.h"
+#include "CPsDataPluginInterface.h"
+#include "CPcsDefs.h"
+#include "FindUtilChineseECE.h"
+
+
+// ============================== MEMBER FUNCTIONS ============================
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::NewL
+// Two Phase Construction
+// ----------------------------------------------------------------------------
+CPcsAlgorithm2* CPcsAlgorithm2::NewL()
+ {
+ PRINT ( _L("Enter CPcsAlgorithm2::NewL") );
+
+ CPcsAlgorithm2* self = new (ELeave) CPcsAlgorithm2();
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+
+ PRINT ( _L("End CPcsAlgorithm2::NewL") );
+
+ return self;
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::CPcsAlgorithm2
+// Two Phase Construction
+// ----------------------------------------------------------------------------
+CPcsAlgorithm2::CPcsAlgorithm2()
+ {
+ PRINT ( _L("Enter CPcsAlgorithm2::CPcsAlgorithm2") );
+ PRINT ( _L("End CPcsAlgorithm2::CPcsAlgorithm2") );
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::ConstructL
+// Two Phase Construction
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm2::ConstructL()
+ {
+ PRINT ( _L("Enter CPcsAlgorithm2::ConstructL") );
+
+ iCacheStatus = ECachingNotStarted; // Starting status
+ iCacheError = KErrNone; // No error
+ iCacheCount = 0; // No data
+
+ iFindUtilECE = CFindUtilChineseECE::NewL(this);
+
+ iPluginLauncher = CIdle::NewL( CActive::EPriorityStandard );
+
+ // Define cache status property used to inform clients about the caching status.
+ DefinePropertyL( EPsKeyCacheStatus );
+
+ // Define cache error property used to inform client about the errors.
+ DefinePropertyL( EPsKeyCacheError );
+
+ // Define properties for notifying about cache updates
+ DefinePropertyL( EPsKeyContactRemovedCounter );
+ DefinePropertyL( EPsKeyContactModifiedCounter );
+ DefinePropertyL( EPsKeyContactAddedCounter );
+
+ // Initialize key map and pti engine
+ TInt keyMapErr = KErrNone;
+ TRAP( keyMapErr, iKeyMap = CPcsKeyMap::NewL( this ) );
+ if (keyMapErr != KErrNone)
+ {
+ PRINT ( _L("**********************************************."));
+ PRINT1 ( _L("CPcsAlgorithm2::ConstructL() KeyMap construction error. The keymap crashed with error code %d."), keyMapErr );
+ PRINT ( _L("Please check the keypad/language for which keymap got crashed.") );
+ PRINT ( _L("**********************************************."));
+ User::Leave( keyMapErr ); // we can't go on without a key map; constructing cache needs it
+ }
+
+ // Initialize helpers
+ iHelper = CPcsAlgorithm2Helper::NewL(this);
+ iMultiSearchHelper = CPcsAlgorithm2MultiSearchHelper::NewL(this);
+
+ if(!iPluginLauncher->IsActive())
+ {
+ iPluginLauncher->Start(TCallBack(CPcsAlgorithm2::DoLaunchPluginsL, this));
+ }
+
+ PRINT ( _L("End CPcsAlgorithm2::ConstructL") );
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::~CPcsAlgorithm2
+// Destructor
+// ----------------------------------------------------------------------------
+CPcsAlgorithm2::~CPcsAlgorithm2()
+ {
+ PRINT ( _L("Enter CPcsAlgorithm2::~CPcsAlgorithm2") );
+
+ // Clear TLS
+ Dll::SetTls(NULL);
+
+ // Cleanup cache
+ iPcsCache.ResetAndDestroy();
+
+ // Cleanup adapters interface and key handling
+ delete iKeyMap;
+ delete iPsDataPluginInterface;
+
+ // Cleanup helpers
+ delete iHelper;
+ delete iMultiSearchHelper;
+
+ delete iFindUtilECE;
+
+ delete iPluginLauncher;
+
+ PRINT ( _L("End CPcsAlgorithm2::~CPcsAlgorithm2") );
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::DefinePropertyL
+// Define a P&S property with given key under the internal category
+// UID of PCS. Leave if definition fails for any other reason than
+// key already existing.
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm2::DefinePropertyL( TPcsInternalKeyCacheStatus aPsKey )
+ {
+ TInt err = RProperty::Define( KPcsInternalUidCacheStatus,
+ aPsKey,
+ RProperty::EInt );
+ if ( err != KErrAlreadyExists )
+ {
+ User::LeaveIfError(err);
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::RemoveSpacesL
+// Remove leading and trailing spaces of search query
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm2::RemoveSpacesL(CPsQuery& aQuery)
+ {
+ PRINT ( _L("Enter CPcsAlgorithm2::RemoveSpacesL") );
+
+ // Remove all leading " "
+ while ( aQuery.Count() > 0 )
+ {
+ CPsQueryItem& item = aQuery.GetItemAtL(0); // First
+ if ( !item.Character().IsSpace() )
+ {
+ break;
+ }
+ aQuery.Remove(0);
+ }
+
+ // Remove all trailing " "
+ while ( aQuery.Count() > 0 )
+ {
+ CPsQueryItem& item = aQuery.GetItemAtL(aQuery.Count()-1); // Last
+ if ( !item.Character().IsSpace() )
+ {
+ break;
+ }
+ aQuery.Remove(aQuery.Count()-1);
+ }
+
+ PRINT ( _L("End CPcsAlgorithm2::RemoveSpacesL") );
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::ReplaceZeroWithSpaceL
+// Replace first occurance of '0' in a sequence of '0's in ITU-T with space
+// ----------------------------------------------------------------------------
+TBool CPcsAlgorithm2::ReplaceZeroWithSpaceL(CPsQuery& aQuery)
+ {
+ PRINT ( _L("Enter CPcsAlgorithm1::ReplaceZeroWithSpaceL") );
+
+ //PRINTQUERY ( _L("CPcsAlgorithm1::ReplaceZeroWithSpaceL (BEFORE): "), aQuery );
+
+ TBool queryModified = EFalse;
+
+ /* In phones like E52 and E55, where the "0" and the " " characters are on
+ * the same key, the "0"s have to be considered as possible separators.
+ *
+ * In phones like N97 and E72, where the "0" and the " " characters are on
+ * different keys, the "0"s must not be considered as possible separators.
+ */
+
+ // Skip initial "0"s, they are not replaced into spaces
+ TInt skipIndex = 0;
+ while ( (skipIndex < aQuery.Count()) &&
+ (aQuery.GetItemAtL(skipIndex).Character().GetNumericValue() == 0) )
+ {
+ skipIndex++;
+ }
+
+ // Replace remaining "0"s into spaces in case they are entered with a keyboard
+ // that has "0" and " " on the same key.
+ const TInt queryCount = aQuery.Count();
+ for ( TInt index = skipIndex; index < queryCount; index++ )
+ {
+ CPsQueryItem& item = aQuery.GetItemAtL(index);
+
+ if ( iKeyMap->GetSpaceAndZeroOnSameKey( item.Mode() ) &&
+ item.Character().GetNumericValue() == 0 )
+ {
+ item.SetCharacter(KSpace);
+ queryModified = ETrue;
+ }
+ }
+
+ //PRINTQUERY ( _L("CPcsAlgorithm1::ReplaceZeroWithSpaceL (AFTER): "), aQuery );
+
+ PRINT1 ( _L("CPcsAlgorithm1::ReplaceZeroWithSpaceL: Query modified (0=not, 1=yes): %d"), queryModified );
+
+ PRINT ( _L("End CPcsAlgorithm1::ReplaceZeroWithSpaceL") );
+
+ return queryModified;
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::PerformSearchL
+// Search function for cache
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm2::PerformSearchL(const CPsSettings& aSettings,
+ CPsQuery& aQuery,
+ RPointerArray<CPsClientData>& aSearchResults,
+ RPointerArray<CPsPattern>& aSearchSeqs)
+ {
+ PRINT ( _L("Enter CPcsAlgorithm2::PerformSearchL") );
+
+ //__LATENCY_MARK ( _L("CPcsAlgorithm2::PerformSearchL") );
+
+ // Check aSettings
+ RPointerArray<TDesC> searchUris;
+ CleanupResetAndDestroyPushL( searchUris );
+ aSettings.SearchUrisL(searchUris);
+
+ if ( searchUris.Count() <= 0)
+ {
+ PRINT ( _L("searchUris.Count() <= 0, Leave from CPcsAlgorithm1::PerformSearchL") );
+ User::Leave(KErrArgument);
+ }
+ CleanupStack::PopAndDestroy( &searchUris ); // ResetAndDestroy
+
+ // Local arrays to hold the search results
+ RPointerArray<CPsData> tempSearchResults;
+ CleanupClosePushL( tempSearchResults );
+ RPointerArray<CPsData> tempSearchResults1;
+ CleanupClosePushL( tempSearchResults1 );
+
+ // -------------------- Perform the basic search --------------------------
+
+ RemoveSpacesL(aQuery);
+ PRINTQUERY ( _L("CPcsAlgorithm2::PerformSearchL: 1st search query: "), aQuery );
+ DoSearchL(aSettings, aQuery, tempSearchResults, aSearchSeqs);
+
+ // ------------------------------------------------------------------------
+
+ // ---- Perform new search after "0" replacement if query is not empty ----
+ /* Examples:
+ * - If the original search string is "Abc0" then we will search again with "Abc".
+ * - If the original search string is "00" then we will not search again.
+ */
+ TBool queryModified = ReplaceZeroWithSpaceL(aQuery);
+ RemoveSpacesL(aQuery);
+ // Perform query again if query got modified.
+ if (queryModified)
+ {
+ PRINTQUERY ( _L("CPcsAlgorithm2::PerformSearchL: 2nd search query: "), aQuery );
+ DoSearchL(aSettings, aQuery, tempSearchResults1, aSearchSeqs);
+
+
+ // Sort rule
+ TLinearOrder<CPsData> rule(CPcsAlgorithm2Utils::CompareDataBySortOrder);
+
+ // Avoid duplicates and add new results
+ TIdentityRelation<CPsData> identityRule(CPsData::CompareById);
+ const TInt tempSearchResults1Count = tempSearchResults1.Count();
+ if (aSettings.GetSortType() != EAlphabetical)
+ {
+ TInt insertPos = 0;
+ for (TInt i = 0; i < tempSearchResults1Count; i++)
+ {
+ if (tempSearchResults.Find(tempSearchResults1[i],
+ identityRule) == KErrNotFound)
+ {
+ tempSearchResults.Insert(tempSearchResults1[i], insertPos);
+ insertPos++;
+ }
+ }
+ }
+ else
+ {
+ for (TInt i = 0; i < tempSearchResults1Count; i++)
+ {
+ if (tempSearchResults.Find(tempSearchResults1[i],
+ identityRule) == KErrNotFound)
+ {
+ tempSearchResults.InsertInOrderAllowRepeats(tempSearchResults1[i],
+ rule);
+ }
+ }
+ }
+ }
+ // ------------------------------------------------------------------------
+
+ // ---------------------- Write result objects to the stream --------------
+ // Truncate the result set if required
+ TInt maxNumToDisplay = aSettings.MaxResults();
+ TInt resultSetCount = tempSearchResults.Count();
+ TInt numToDisplay = 0;
+ if ( maxNumToDisplay == -1 )
+ {
+ numToDisplay = resultSetCount;
+ }
+ else
+ {
+ numToDisplay = Min( maxNumToDisplay, resultSetCount );
+ }
+
+ // Copy desired number of results from tempSearchResults to the results stream
+ for (TInt i = 0; i < numToDisplay; i++)
+ {
+ aSearchResults.Append(WriteClientDataL(*(tempSearchResults[i])));
+ }
+ // ------------------------------------------------------------------------
+
+ // Cleanup local results array
+ CleanupStack::PopAndDestroy( &tempSearchResults1 ); // Close, don't destroy
+ CleanupStack::PopAndDestroy( &tempSearchResults ); // Close, don't destroy
+
+ // __LATENCY_MARKEND ( _L("CPcsAlgorithm2::PerformSearchL") );
+
+ PRINT ( _L("End CPcsAlgorithm2::PerformSearchL") );
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::SearchInputL
+// Search function for input string
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm2::SearchInputL(CPsQuery& aQuery,
+ TDesC& aData,
+ RPointerArray<TDesC>& aMatchSet,
+ RArray<TPsMatchLocation>& aMatchLocation)
+ {
+ // __LATENCY_MARK ( _L("CPcsAlgorithm2::SearchInputL: ") );
+ PRINT ( _L("Enter CPcsAlgorithm2::SearchInputL") );
+
+ // Print input query for debug
+ PRINTQUERY ( _L("CPcsAlgorithm2::SearchInputL: Search query: "), aQuery );
+
+ // Print received search data
+ PRINT1 ( _L("Search data received = %S"), &aData);
+
+
+ // -------------------- Perform the basic search --------------------------
+
+ RemoveSpacesL(aQuery);
+ DoSearchInputL(aQuery, aData, aMatchSet, aMatchLocation);
+
+ // ------------------------------------------------------------------------
+
+ // ---- Perform new search after "0" replacement if query is not empty ----
+ /* Examples:
+ * - If the original search string is "Abc0" then we will search again with "Abc".
+ * - If the original search string is "00" then we will not search again.
+ */
+ TBool queryModified = ReplaceZeroWithSpaceL(aQuery);
+ RemoveSpacesL(aQuery);
+ // If query got modified and the search query still contains something
+ // perform a multi search again
+ if (queryModified && aQuery.Count() > 0 && aMatchSet.Count() == 0 && aMatchLocation.Count() == 0 )
+ {
+ DoSearchInputL(aQuery, aData, aMatchSet, aMatchLocation);
+ }
+ // ------------------------------------------------------------------------
+
+ // --- Remove overlapping items from aMatchLocation ---
+ TInt i = 0;
+ TBool incrementFirstCursor;
+ while ( i < aMatchLocation.Count() )
+ {
+ incrementFirstCursor = ETrue;
+ TInt j = i+1;
+ while ( j < aMatchLocation.Count() )
+ {
+ if ( CPcsAlgorithm2Utils::MatchesOverlap( aMatchLocation[j], aMatchLocation[i] ) )
+ {
+ // Remove match location item with smallest length if 2 items have same index
+ if ( aMatchLocation[j].length <= aMatchLocation[i].length )
+ {
+ aMatchLocation.Remove(j);
+ continue; // Do not increment j
+ }
+ else
+ {
+ aMatchLocation.Remove(i);
+ incrementFirstCursor = EFalse; // Do not increment i
+ break;
+ }
+ }
+ j++;
+ }
+ if ( incrementFirstCursor )
+ {
+ i++;
+ }
+ }
+
+ // --- Remove from aMatchSet items which no longer have corresponding item in aMatchLocation ---
+ HBufC* dataUpper = HBufC::NewLC(aData.Length());
+ dataUpper->Des().Copy(aData);
+ dataUpper->Des().UpperCase(); // Get uppercase, as aMatchSet is in upper case
+
+ TInt k = 0;
+ while ( k < aMatchSet.Count() )
+ {
+ TBool keepMatch = EFalse;
+ TInt startCursor = -1;
+
+ TInt offsetCursor;
+ while ( KErrNotFound != (offsetCursor = dataUpper->Mid(startCursor + 1).Find(*aMatchSet[k])) )
+ {
+ // startCursor = index of match item *aMatchSet[k] into search string aData
+ startCursor = offsetCursor + startCursor + 1;
+ const TInt matchLocationCount = aMatchLocation.Count();
+ for ( TInt i = 0; i < matchLocationCount; i++ )
+ {
+ // If match item was found in the location list, then keep it
+ if ( (aMatchLocation[i].index == startCursor) &&
+ (aMatchLocation[i].length == aMatchSet[k]->Length()) )
+ {
+ keepMatch = ETrue;
+ break;
+ }
+ }
+ }
+
+ if ( keepMatch )
+ {
+ k++;
+ }
+ else
+ {
+ aMatchSet.Remove(k); // Do not increment k
+ }
+ }
+ CleanupStack::PopAndDestroy( dataUpper );
+ // --- Remove items End ---
+
+ // Sort match set
+ iHelper->SortSearchSeqsL(aMatchSet);
+
+ PRINT ( _L("End CPcsAlgorithm2::SearchInputL") );
+ //__LATENCY_MARKEND ( _L("CPcsAlgorithm2::SearchInputL") );
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::SearchMatchStringL
+// Search function for input string, result also as string
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm2::SearchMatchStringL( CPsQuery& /*aSearchQuery*/,
+ TDesC& /*aSearchData*/,
+ TDes& /*aMatch*/ )
+ {
+ PRINT ( _L("Enter CPcsAlgorithm2::SearchMatchStringL") );
+
+ //__LATENCY_MARK ( _L("CPcsAlgorithm2::SearchMatchStringL") );
+
+ // TODO: Implementation missing
+
+ //__LATENCY_MARKEND ( _L("CPcsAlgorithm2::SearchMatchStringL") );
+
+ PRINT ( _L("End CPcsAlgorithm2::SearchMatchStringL") );
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::DoSearchL
+// Search function helper
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm2::DoSearchL( const CPsSettings& aSettings,
+ CPsQuery& aQuery,
+ RPointerArray<CPsData>& aSearchResults,
+ RPointerArray<CPsPattern>& aSearchSeqs )
+ {
+ PRINT ( _L("Enter CPcsAlgorithm2::DoSearchL") );
+
+ //__LATENCY_MARK ( _L("CPcsAlgorithm2::DoSearchL") );
+
+ // -(0)----------------- Check if group search is required ---------------
+ RArray<TInt> contactsInGroup;
+ CleanupClosePushL( contactsInGroup );
+ RArray<TInt> groupIdArray;
+ CleanupClosePushL( groupIdArray );
+
+ // Create a new settings instance
+ CPsSettings* tempSettings = aSettings.CloneL();
+ CleanupStack::PushL( tempSettings );
+
+ TBool isGroupSearch = IsGroupSearchL(*tempSettings, groupIdArray);
+
+ if (isGroupSearch)
+ {
+ // Replace groups URI with contacts DB URI in new search settings
+ ReplaceGroupsUriL(*tempSettings);
+
+ // List of contacts in this group
+ GetContactsInGroupL(groupIdArray[0], contactsInGroup);
+ }
+
+ // -----------------------------------------------------------------------
+
+
+ // Extract query list.
+ RPointerArray<CPsQuery> queryList = iMultiSearchHelper->MultiQueryL(aQuery);
+ CleanupResetAndDestroyPushL( queryList );
+
+ // (1)-------------------- No query return all contacts -------------------
+ if (queryList.Count() == 0)
+ {
+ GetAllContentsL(*tempSettings, aSearchResults);
+
+ if (isGroupSearch)
+ {
+ FilterSearchResultsForGroupsL(contactsInGroup, aSearchResults);
+ }
+ }
+ // ------------------------------------------------------------------------
+
+ // (2)-------------------- Perform a single query search ------------------
+ else if (queryList.Count() == 1)
+ {
+ CPsQuery* query = queryList[0];
+
+ // Search results
+ iHelper->SearchSingleL(*tempSettings, *query, isGroupSearch,
+ contactsInGroup, aSearchResults, aSearchSeqs);
+ }
+ // ------------------------------------------------------------------------
+
+ // (3)-------------------- Perform a multi query search -------------------
+ else // multiple query
+ {
+ PRINT ( _L("Query received is in multiple. Performing a multi search.") );
+
+ // Search results
+ iMultiSearchHelper->SearchMultiL(*tempSettings, queryList, isGroupSearch,
+ contactsInGroup, aSearchResults, aSearchSeqs);
+ }
+ // -------------------------------------------------------------------------
+
+ // Cleanup
+
+ CleanupStack::PopAndDestroy( &queryList ); // ResetAndDestroy
+ CleanupStack::PopAndDestroy( tempSettings );
+ CleanupStack::PopAndDestroy( &groupIdArray ); // Close
+ CleanupStack::PopAndDestroy( &contactsInGroup ); // Close
+
+ //__LATENCY_MARKEND ( _L("CPcsAlgorithm2::DoSearchL") );
+
+ PRINT ( _L("End CPcsAlgorithm2::DoSearchL") );
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::DoSearchInputL
+// Search function helper
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm2::DoSearchInputL(CPsQuery& aQuery,
+ const TDesC& aData,
+ RPointerArray<TDesC>& aMatchSet,
+ RArray<TPsMatchLocation>& aMatchLocation)
+ {
+
+ //__LATENCY_MARK ( _L("CPcsAlgorithm2::SearchInputL: ") );
+ PRINT ( _L("Enter CPcsAlgorithm2::DoSearchInputL") );
+
+ // Check if any seperator is there in the query
+ RPointerArray<CPsQuery> queryList = iMultiSearchHelper->MultiQueryL(aQuery);
+ CleanupResetAndDestroyPushL( queryList );
+
+ // No query
+ if (queryList.Count() == 0)
+ {
+ PRINT ( _L("Query received is empty") );
+ CleanupStack::PopAndDestroy( &queryList ); // ResetAndDestroy
+ return;
+ }
+
+ // Single query
+ if (queryList.Count() == 1)
+ {
+ iHelper->SearchMatchSeqL(aQuery, aData, aMatchSet, aMatchLocation);
+ }
+
+ if (queryList.Count() > 1) // multiple query
+ {
+ PRINT ( _L("Query received is in multiple. Performing a multi search.") );
+
+ // Search results
+ iMultiSearchHelper->SearchMatchSeqMultiL(queryList,
+ aData,
+ aMatchSet,
+ aMatchLocation);
+ }
+
+ // Delete all the query elements
+ CleanupStack::PopAndDestroy( &queryList ); // ResetAndDestroy
+ PRINT ( _L("End CPcsAlgorithm2::DoSearchInputL") );
+ //__LATENCY_MARKEND ( _L("CPcsAlgorithm2::SearchInputL") );
+
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::AddData
+// Add a data element to the pool
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm2::AddData(TDesC& aDataStore, CPsData* aData)
+ {
+ TInt arrayIndex = GetCacheIndex(aDataStore);
+
+ if (arrayIndex < 0)
+ return;
+
+ CPcsCache* cache = iPcsCache[arrayIndex];
+
+ // Fill the data store index
+ TInt dataStoreIndex = FindStoreUri(aDataStore);
+ if (dataStoreIndex >= 0)
+ {
+ aData->SetUriId(dataStoreIndex);
+ }
+ else
+ {
+ PRINT(_L("CPcsAlgorithm2::AddDataL Unknown data store"));
+ return;
+ }
+ TRAPD(err, cache->AddToCacheL(*aData));
+
+ if (err != KErrNone)
+ {
+ SetCachingError(aDataStore, err);
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::RemoveData
+// Remove a data element from the pool
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm2::RemoveData(TDesC &aDataStore, TInt aItemId)
+ {
+ TInt arrayIndex = GetCacheIndex(aDataStore);
+
+ if (arrayIndex < 0)
+ return;
+
+ CPcsCache* cache = iPcsCache[arrayIndex];
+ TRAPD(err, cache->RemoveFromCacheL(aItemId));
+
+ if (err != KErrNone)
+ {
+ SetCachingError(aDataStore, err);
+ }
+ }
+
+// ---------------------------------------------------------------------
+// CPcsAlgorithm2::RemoveAll
+// Remove all the contacts from a datastore
+// ---------------------------------------------------------------------
+void CPcsAlgorithm2::RemoveAll(TDesC& aDataStore)
+ {
+ TInt dataStoreIndex = GetCacheIndex(aDataStore);
+
+ if (dataStoreIndex < 0)
+ return;
+
+ CPcsCache* cache = iPcsCache[dataStoreIndex];
+ cache->RemoveAllFromCache();
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::GetCacheIndex
+// Return the cache index for a data store
+// ----------------------------------------------------------------------------
+TInt CPcsAlgorithm2::GetCacheIndex(const TDesC& aDataStore)
+ {
+ const TInt pcsCacheCount = iPcsCache.Count();
+ for (int i = 0; i <pcsCacheCount; i++)
+ {
+ CPcsCache* cache = iPcsCache[i];
+
+ if (cache->GetURI().CompareC(aDataStore) == 0)
+ return i;
+ }
+
+ return -1;
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::AddDataStore
+// Adds a new store
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm2::AddDataStore(TDesC& aDataStore)
+ {
+ // Check if the datastore cache already exists
+ TInt index = GetCacheIndex(aDataStore);
+ if (index != -1)
+ {
+ // Already exists
+ return;
+ }
+
+ // Create a new cache
+ CPcsCache* cache = NULL;
+ TRAPD(err, cache = CPcsCache::NewL( this, aDataStore, *iKeyMap, iCacheCount));
+ if (err != KErrNone)
+ {
+ SetCachingError(aDataStore, err);
+ return;
+ }
+
+ // Increment the cachecount
+ iCacheCount++;
+
+ RArray<TInt> dataFields;
+ TRAP(err, iPsDataPluginInterface->GetSupportedDataFieldsL(cache->GetURI(), dataFields));
+ if (err != KErrNone)
+ {
+ SetCachingError(aDataStore, err);
+ return;
+ }
+ cache->SetDataFields(dataFields);
+
+ // Check if sort order is persisted already
+ RArray<TInt> sortOrder;
+ TRAP(err, ReadSortOrderFromCenRepL(*(cache->GetUri()), sortOrder));
+ if (err != KErrNone)
+ {
+ SetCachingError(aDataStore, err);
+ return;
+ }
+
+ if (sortOrder.Count() == 0)
+ {
+ cache->SetSortOrder(dataFields); // Initial sort order
+ }
+ else
+ {
+ cache->SetSortOrder(sortOrder); // Persisted sort order
+ }
+
+ sortOrder.Close();
+ dataFields.Close();
+
+ iPcsCache.Append(cache);
+
+ TRAP(err, iPsDataPluginInterface->RequestForDataL(aDataStore));
+ if (err != KErrNone)
+ {
+ SetCachingError(aDataStore, err);
+ UpdateCachingStatus(aDataStore, ECachingCompleteWithErrors);
+ return;
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::RemoveDataStore
+// Removes an existing data store
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm2::RemoveDataStore(TDesC& aDataStore)
+ {
+
+ for (int i = 0; i < iPcsCache.Count(); i++)
+ {
+ CPcsCache* cache = iPcsCache[i];
+
+ if (cache->GetURI().CompareC(aDataStore) == 0)
+ {
+ delete iPcsCache[i];
+ iPcsCache.Remove(i);
+ iCacheCount--;
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::IsLanguageSupportedL
+// Returns ETrue if this language is supported
+// ----------------------------------------------------------------------------
+TBool CPcsAlgorithm2::IsLanguageSupportedL(TUint32 aLang)
+ {
+ return iKeyMap->IsLanguageSupportedL(aLang);
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::GetUriForIdL
+// Get the URI string for this internal id
+// ----------------------------------------------------------------------------
+const TDesC& CPcsAlgorithm2::GetUriForIdL(TUint8 aUriId)
+ {
+ TBool found = EFalse;
+ TInt i = 0;
+ const TInt pcsCacheCount = iPcsCache.Count();
+ for (i = 0; i < pcsCacheCount; i++)
+ {
+ if (iPcsCache[i]->GetUriId() == aUriId)
+ {
+ found = ETrue;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ User::Leave(KErrNotFound);
+ }
+
+ return *(iPcsCache[i]->GetUri());
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::FindStoreUri
+// Checks if this store exists
+// ----------------------------------------------------------------------------
+TInt CPcsAlgorithm2::FindStoreUri(const TDesC& aDataStore)
+ {
+ const TInt pcsCacheCount = iPcsCache.Count();
+ for ( TInt i = 0; i < pcsCacheCount; i++ )
+ {
+ if ( aDataStore.CompareC(*(iPcsCache[i]->GetUri())) == 0 )
+ {
+ return i;
+ }
+ }
+
+ return KErrNotFound;
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::UpdateCachingStatus
+// Update caching status
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm2::UpdateCachingStatus(TDesC& aDataStore, TInt aStatus)
+{
+ PRINT ( _L("Enter CPcsAlgorithm2::UpdateCachingStatus") );
+ PRINT2 ( _L("CPcsAlgorithm2::UpdateCachingStatus: Request received for URI=%S with status=%d"),
+ &aDataStore, aStatus );
+
+ // Handle data store update events
+ if ( aStatus == ECacheUpdateContactRemoved ||
+ aStatus == ECacheUpdateContactModified ||
+ aStatus == ECacheUpdateContactAdded )
+ {
+ HandleCacheUpdated( static_cast<TCachingStatus>(aStatus) );
+ return;
+ }
+
+ // If not a cache update event, then this event is related to the initial
+ // cache construction.
+
+ // Check if any error occurred and update the cache error
+ if ( aStatus < 0 )
+ {
+ SetCachingError(aDataStore, aStatus);
+ }
+ else
+ {
+ TInt index = FindStoreUri(aDataStore);
+ iPcsCache[index]->UpdateCacheStatus(aStatus);
+ }
+
+ TCachingStatus status = ECachingNotStarted;
+ TUint countNotStarted = 0;
+ TUint countInProgress = 0;
+ TUint countCompleted = 0;
+ TUint countCompletedWithErrors = 0;
+ TInt cacheCount = iPcsCache.Count();
+ for ( TInt i = 0; i < cacheCount; i++ )
+ {
+ PRINT3 ( _L("CPcsAlgorithm2::UpdateCachingStatus: URI[%d]=%S, cache status=%d"),
+ i, &iPcsCache[i]->GetURI(), iPcsCache[i]->GetCacheStatus() );
+
+ switch ( iPcsCache[i]->GetCacheStatus() )
+ {
+ case ECachingNotStarted:
+ {
+ countNotStarted++;
+ break;
+ }
+ case ECachingInProgress:
+ {
+ countInProgress++;
+ break;
+ }
+ case ECachingComplete:
+ {
+ countCompleted++;
+ break;
+ }
+ case ECachingCompleteWithErrors:
+ {
+ countCompletedWithErrors++;
+ break;
+ }
+ default:
+ {
+ // Default completed state
+ countCompleted++;
+ break;
+ }
+ }
+ }
+
+ // Calculate cumulative status according to single caches statuses
+ if ( countCompleted > 0 && ( countCompleted + countNotStarted ) == cacheCount )
+ {
+ // If at least one caching is finished
+ // set status to ECachingComplete or ECachingCompleteWithErrors
+ // according to iCacheError
+ status = ( iCacheError == KErrNone ) ? ECachingComplete : ECachingCompleteWithErrors;
+ }
+ else if ( countInProgress > 0 )
+ {
+ // Else if at least one caching is in progress,
+ // set status to ECachingInProgress
+ status = ECachingInProgress;
+ }
+ else if ( countCompletedWithErrors > 0 )
+ {
+ // Else if at least one caching is completed with errors,
+ //set status to ECachingCompleteWithErrors
+ status = ECachingCompleteWithErrors;
+ }
+ else
+ {
+ // countNotStarted == cacheCount
+ // status is set to default ECachingNotStarted
+ }
+
+ PRINT1 ( _L("CPcsAlgorithm2::UpdateCachingStatus: Cumulative caching status is %d"),
+ status );
+
+ // Check if status changed
+ if ( status != iCacheStatus )
+ {
+ PRINT2 ( _L("CPcsAlgorithm2::UpdateCachingStatus: Cumulative caching changed: %d -> %d"),
+ iCacheStatus, status );
+
+ iCacheStatus = status;
+ RProperty::Set(KPcsInternalUidCacheStatus, EPsKeyCacheStatus, iCacheStatus );
+ }
+
+ PRINT( _L("End CPcsAlgorithm2::UpdateCachingStatus") );
+}
+
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::SetCachingError
+// Updates cachinge error
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm2::SetCachingError(const TDesC& aDataStore, TInt aError)
+ {
+ PRINT2 ( _L("SetCachingError::URI %S ERROR %d"), &aDataStore, aError );
+
+ iCacheError = aError;
+ RProperty::Set( KPcsInternalUidCacheStatus, EPsKeyCacheError, iCacheError );
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::GetAllContentsL
+// Returns all the contents of a store
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm2::GetAllContentsL(const CPsSettings& aSettings,
+ RPointerArray<CPsData>& aResults)
+ {
+ //__LATENCY_MARK ( _L("CPcsAlgorithm2::GetAllContentsL") );
+
+ PRINT ( _L("Enter CPcsAlgorithm2::GetAllContentsL") );
+
+ // To hold array of results from different data stores
+ typedef RPointerArray<CPsData> CPSDATA_R_PTR_ARRAY;
+ RPointerArray<CPSDATA_R_PTR_ARRAY> searchResultsArr;
+ CleanupResetAndDestroyPushL( searchResultsArr );
+ // TODO: Here's still a potential memory leak if a leave happens. The child
+ // arrays of searchResultsArr are not Reset in that case. The CPsData objects
+ // may leak as well. Handling this safely is somewhat complicated because some of
+ // the CPsData objects may already be transferred to ownership of aResults array
+ // at the time the leave happens, and those items must not be deleted.
+
+ // Get the data stores
+ RPointerArray<TDesC> dataStores;
+ CleanupResetAndDestroyPushL( dataStores );
+ aSettings.SearchUrisL(dataStores);
+
+ // Get all contacts for each data store
+ const TInt dataStoresCount = dataStores.Count();
+ for (TInt dsIndex = 0; dsIndex < dataStoresCount; dsIndex++)
+ {
+ RPointerArray<CPsData> *temp = new (ELeave) RPointerArray<CPsData> ();
+ searchResultsArr.Append(temp);
+
+ TInt arrayIndex = GetCacheIndex(*(dataStores[dsIndex]));
+ if (arrayIndex < 0)
+ {
+ continue;
+ }
+
+ CPcsCache* cache = GetCache(arrayIndex);
+
+ cache->GetAllContentsL(*(searchResultsArr[dsIndex]));
+ }
+
+ CleanupStack::PopAndDestroy( &dataStores ); // ResetAndDestroy
+
+ // Merge the results from different data stores
+ CPcsAlgorithm2Utils::FormCompleteSearchResultsL(searchResultsArr, aResults);
+
+ // Cleanup the local arrays
+ const TInt seaerchResultsArrCount = searchResultsArr.Count();
+ for (TInt i = 0; i < seaerchResultsArrCount; i++)
+ {
+ searchResultsArr[i]->Reset();
+ }
+
+ CleanupStack::PopAndDestroy( &searchResultsArr ); // ResetAndDestroy
+
+ PRINT1 ( _L("Number of results = %d"), aResults.Count() );
+
+ PRINT ( _L("End CPcsAlgorithm2::GetAllContentsL") );
+
+ //__LATENCY_MARKEND ( _L("CPcsAlgorithm2::GetAllContentsL") );
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::IsGroupSearchL
+// Checks if a group search is required
+// ----------------------------------------------------------------------------
+TBool CPcsAlgorithm2::IsGroupSearchL(CPsSettings& aSettings,
+ RArray<TInt>& aGroupIdArray)
+ {
+ PRINT ( _L("Enter CPcsAlgorithm2::IsGroupSearchL") );
+
+ // Get the groupIds in the seach settings
+ aSettings.GetGroupIdsL(aGroupIdArray);
+
+ // Get the current URIs defined in settings
+ RPointerArray<TDesC> searchUris;
+ CleanupResetAndDestroyPushL( searchUris );
+ aSettings.SearchUrisL(searchUris);
+
+ if (aGroupIdArray.Count() && (searchUris.Count() > aGroupIdArray.Count()))
+ {
+ // There is an error, either there are more than one groups
+ // or the settings contain a combination of group/non-group Uris
+ aGroupIdArray.Close();
+ User::Leave(KErrArgument);
+ }
+
+ CleanupStack::PopAndDestroy( &searchUris ); // ResetAndDestroy
+
+ PRINT ( _L("End CPcsAlgorithm2::IsGroupSearchL") );
+
+ if (aGroupIdArray.Count() == 1)
+ return ETrue;
+
+ return EFalse;
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::ReplaceGroupsUriL
+// Replace groups uri to contacts uri
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm2::ReplaceGroupsUriL(CPsSettings& aSettings)
+ {
+ RPointerArray<TDesC> uri;
+ CleanupResetAndDestroyPushL( uri );
+
+ // Set contacts db uri
+ HBufC* cntdb = KVPbkDefaultCntDbURI().AllocLC();
+ uri.AppendL(cntdb);
+ CleanupStack::Pop( cntdb ); // ownership transferred
+ aSettings.SetSearchUrisL(uri);
+
+ // Cleanup
+ CleanupStack::PopAndDestroy( &uri ); // ResetAndDestroy
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::FilterSearchResultsForGroupsL
+// Filters the results that belong to a group
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm2::FilterSearchResultsForGroupsL(RArray<TInt>& contactsInGroup,
+ RPointerArray<CPsData>& aSearchResults)
+ {
+ PRINT ( _L("Enter CPcsAlgorithm2::FilterSearchResultsForGroupsL") );
+
+ // for each search result
+ // Note: aSearchResults.Count() is to be checked everytime,
+ // since the elements are being removed dynamically.
+ for (TInt j = 0; j < aSearchResults.Count(); j++)
+ {
+ TBool includeResult = EFalse;
+
+ if (contactsInGroup.Find(aSearchResults[j]->Id()) != KErrNotFound)
+ {
+ includeResult = ETrue;
+ }
+
+ if (includeResult == EFalse)
+ {
+ aSearchResults.Remove(j);
+ j--; // j is decremented, since that object is removed
+ }
+ }
+
+ PRINT ( _L("End CPcsAlgorithm2::FilterSearchResultsForGroupsL") );
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::GetContactsInGroupL
+// Recover contacts that belong to a group
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm2::GetContactsInGroupL(TInt aGroupId, RArray<TInt>& aGroupContactIds)
+ {
+ // Clear results array
+ aGroupContactIds.Reset();
+
+ // Cache Index for group database
+ TInt cacheIndex = GetCacheIndex(KVPbkDefaultGrpDbURI);
+
+ // Get the groups contact ids
+ if (cacheIndex != -1)
+ {
+ RPointerArray<CPsData> groups;
+ CleanupClosePushL( groups );
+
+ // Get all groups
+ iPcsCache[cacheIndex]->GetAllContentsL(groups);
+
+ // Get all contacts in group
+ const TInt groupsCount = groups.Count();
+ for (TInt i = 0; i < groupsCount; i++)
+ {
+ if (groups[i]->Id() == aGroupId)
+ {
+ groups[i]->IntDataExt(aGroupContactIds); // All contacts in group
+ break;
+ }
+ }
+
+ CleanupStack::PopAndDestroy( &groups ); // Close
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::GetDataOrderL
+//
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm2::GetDataOrderL(TDesC& aURI, RArray<TInt>& aDataOrder)
+ {
+ PRINT ( _L("End CPcsAlgorithm2::GetDataOrderL") );
+
+ TInt arrayIndex = -1;
+
+ if (CPcsAlgorithm2Utils::IsGroupUri(aURI))
+ {
+ // If search in a group uri, use contacts db
+ arrayIndex = GetCacheIndex(KVPbkDefaultCntDbURI);
+ }
+ else
+ {
+ arrayIndex = GetCacheIndex(aURI);
+ }
+
+ if (arrayIndex < 0)
+ {
+ return;
+ }
+
+ CPcsCache* cache = iPcsCache[arrayIndex];
+
+ aDataOrder.Reset();
+
+ // Get the data fields for this cache
+ cache->GetDataFields(aDataOrder);
+
+ PRINT ( _L("End CPcsAlgorithm2::GetDataOrderL") );
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::GetSortOrderL
+//
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm2::GetSortOrderL(TDesC& aURI, RArray<TInt>& aDataOrder)
+ {
+ PRINT ( _L("End CPcsAlgorithm2::GetSortOrderL") );
+
+ TInt arrayIndex = -1;
+
+ if (CPcsAlgorithm2Utils::IsGroupUri(aURI))
+ {
+ // If search in a group uri, use contacts db
+ arrayIndex = GetCacheIndex(KVPbkDefaultCntDbURI);
+ }
+ else
+ {
+ arrayIndex = GetCacheIndex(aURI);
+ }
+
+ if (arrayIndex < 0)
+ {
+ return;
+ }
+
+ CPcsCache* cache = iPcsCache[arrayIndex];
+
+ aDataOrder.Reset();
+
+ // Get the data fields for this cache
+ cache->GetSortOrder(aDataOrder);
+
+ PRINT ( _L("End CPcsAlgorithm2::GetSortOrderL") );
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm2::ChangeSortOrderL
+//
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm2::ChangeSortOrderL(TDesC& aURI, RArray<TInt>& aSortOrder)
+ {
+ PRINT ( _L("Enter CPcsAlgorithm2::ChangeSortOrderL.") );
+
+ PRINT ( _L("CPcsAlgorithm2::ChangeSortOrderL. Sort order change received.") );
+ PRINT1 ( _L("URI = %S"), &aURI );
+
+ // If URI is search in a group URI return
+ if (CPcsAlgorithm2Utils::IsGroupUri(aURI))
+ {
+ PRINT ( _L("CPcsAlgorithm2::ChangeSortOrderL. Sort order change not supported.") );
+ return;
+ }
+
+ // Check if a cache exists
+ TInt arrayIndex = GetCacheIndex(aURI);
+ if (arrayIndex < 0)
+ {
+ PRINT ( _L("CPcsAlgorithm2::ChangeSortOrderL. Cache for URI doesn't exist.") );
+ return;
+ }
+
+ // Cache instance for this URI
+ CPcsCache* cache = iPcsCache[arrayIndex];
+
+ // Check if received sort order is same as before
+ RArray<TInt> mySortOrder;
+ cache->GetSortOrder(mySortOrder);
+
+ if (aSortOrder.Count() == mySortOrder.Count())
+ {
+ TBool same = ETrue;
+ const TInt mySourtOrderCount = mySortOrder.Count();
+ for ( TInt i = 0; i < mySourtOrderCount ; i++ )
+ {
+ if (mySortOrder[i] != aSortOrder[i])
+ {
+ same = EFalse;
+ break;
+ }
+ }
+
+ if (same)
+ {
+ PRINT ( _L("CPcsAlgorithm2::ChangeSortOrderL. Same sort order received. Ignoring ...") );
+ PRINT ( _L("End CPcsAlgorithm2::ChangeSortOrderL.") );
+ mySortOrder.Reset();
+ return;
+ }
+ }
+
+ mySortOrder.Reset();
+
+ PRINT ( _L("CPcsAlgorithm2::ChangeSortOrderL. New sort order received. Refreshing ...") );
+
+ // Set the new sort order on the cache
+ cache->SetSortOrder(aSortOrder);
+
+ // Persist the changes in sort order
+ WriteSortOrderToCenRepL(aURI, aSortOrder);
+
+ // Request for data again
+ TInt err = KErrNone;
+ TRAP(err, cache->ResortdataInPoolsL());
+ if (err != KErrNone)
+ {
+ PRINT ( _L("CPcsAlgorithm1::ChangeSortOrderL() Set Caching Error ") );
+ SetCachingError(aURI, err);
+ UpdateCachingStatus(aURI, ECachingCompleteWithErrors);
+ return;
+ }
+
+ PRINT ( _L("End CPcsAlgorithm2::ChangeSortOrderL.") );
+ }
+
+// ---------------------------------------------------------------------------------
+// Read the persisted sort order from the central repository
+// Persisted sort order is of form URI Field1 Field2 Field3 .. FieldN (space delimited)
+// ---------------------------------------------------------------------------------
+void CPcsAlgorithm2::ReadSortOrderFromCenRepL(const TDesC& aURI, RArray<TInt>& aSortOrder)
+ {
+ PRINT ( _L("Enter CPcsAlgorithm2::ReadSortOrderFromCenRepL.") );
+
+ aSortOrder.Reset();
+
+ CRepository *repository = CRepository::NewL(KCRUidPSSortOrder);
+
+ // Read the sort order from cenrep
+ TBuf<KCRMaxLen> str;
+
+ for ( TInt i(KCenrepFieldsStartKey);
+ i < KCenrepFieldsStartKey + KCenrepNumberOfFieldsCount;
+ i++ )
+ {
+ TInt err = repository->Get(i, str);
+
+ if (KErrNone != err)
+ {
+ break;
+ }
+
+ if (str != KNullDesC)
+ {
+ TLex lex(str);
+
+ // Extract the URI
+ TPtrC token = lex.NextToken();
+
+ if (aURI.Compare(token) == 0)
+ {
+ // Extract the sort order
+ token.Set(lex.NextToken());
+
+ while (token.Length() != 0)
+ {
+ TLex lex1(token);
+
+ TInt intVal;
+ TInt err = lex1.Val(intVal);
+
+ if (KErrNone == err)
+ {
+ aSortOrder.Append(intVal);
+ }
+
+ // Next token
+ token.Set(lex.NextToken());
+ }
+
+ break;
+ }
+ }
+
+ }
+
+ delete repository;
+
+ PRINT ( _L("End CPcsAlgorithm2::ReadSortOrderFromCenRepL.") );
+ }
+
+// ---------------------------------------------------------------------------------
+// Write the sort order into the central repository
+// Persisted sort order is of form URI Field1 Field2 Field3 .. FieldN (space delimited)
+// ---------------------------------------------------------------------------------
+void CPcsAlgorithm2::WriteSortOrderToCenRepL(const TDesC& aURI, RArray<TInt>& aSortOrder)
+ {
+ PRINT ( _L("Enter CPcsAlgorithm2::WriteSortOrderToCenRepL.") );
+
+ CRepository* repository = CRepository::NewLC(KCRUidPSSortOrder);
+
+ // Check if there an entry for this URI in cenrep
+ TBuf<KCRMaxLen> str;
+ TInt keyIndex = -1;
+
+ for ( TInt i(KCenrepFieldsStartKey);
+ i < KCenrepFieldsStartKey + KCenrepNumberOfFieldsCount;
+ i++ )
+ {
+ TInt err = repository->Get(i, str);
+
+ if (KErrNone != err)
+ {
+ PRINT ( _L("CPcsAlgorithm2::WriteSortOrderToCenRepL. cenrep error.") );
+ return;
+ }
+
+ if (str != KNullDesC)
+ {
+ TLex lex(str);
+
+ // Extract the URI
+ TPtrC token = lex.NextToken();
+
+ if (aURI.Compare(token) == 0)
+ {
+ keyIndex = i; // i has the key index for this URI
+ break;
+ }
+ }
+ }
+
+ // No entry for this URI in cenrep
+ // Find the next free location in cenrep
+ if (keyIndex == -1)
+ {
+ // Find the next free key index
+ for ( TInt i(KCenrepFieldsStartKey);
+ i < KCenrepFieldsStartKey + KCenrepNumberOfFieldsCount;
+ i++ )
+ {
+ TInt err = repository->Get(i, str);
+
+ if (KErrNone != err)
+ {
+ PRINT ( _L("CPcsAlgorithm2::WriteSortOrderToCenRepL. cenrep error.") );
+ return;
+ }
+
+ if (str == KNullDesC)
+ {
+ keyIndex = i; // i has the next free location
+ break;
+ }
+ }
+ }
+
+ if (keyIndex == -1)
+ {
+ PRINT ( _L("CPcsAlgorithm2::WriteSortOrderToCenRepL. Persist limit violated.") );
+ return;
+ }
+
+ // Persist the sort order
+ HBufC* str1 = HBufC::NewLC(KCRMaxLen);
+ TPtr ptr(str1->Des());
+
+ // Append the URI
+ ptr.Append(aURI);
+ ptr.Append(KSpace);
+
+ // Append the sort order fields
+ const TInt sortOrderCount = aSortOrder.Count();
+ for (TInt j = 0; j < sortOrderCount; j++)
+ {
+ ptr.AppendNum(aSortOrder[j]);
+ ptr.Append(KSpace);
+ }
+
+ // Write to persistent store
+ TInt err = repository->Set(keyIndex, ptr);
+
+ User::LeaveIfError(err);
+
+ CleanupStack::PopAndDestroy( str1 );
+
+ CleanupStack::PopAndDestroy( repository );
+
+ PRINT ( _L("End CPcsAlgorithm2::WriteSortOrderToCenRepL.") );
+ }
+
+// ---------------------------------------------------------------------------------
+// WriteClientDataL.
+// Write the content required by client
+// ---------------------------------------------------------------------------------
+CPsClientData* CPcsAlgorithm2::WriteClientDataL(CPsData& aPsData)
+ {
+ CPsClientData* clientData = CPsClientData::NewL();
+ CleanupStack::PushL(clientData);
+
+ // set Id
+ clientData->SetId(aPsData.Id());
+
+ // set Uri
+ clientData->SetUriL(GetUriForIdL(aPsData.UriId()));
+
+ // set pointer to the each data element
+ const TInt dataElementCount = aPsData.DataElementCount();
+ for (TInt i = 0; i <dataElementCount; i++)
+ {
+ clientData->SetDataL(i, *(aPsData.Data(i)));
+ }
+
+ // set data extension
+ clientData->SetDataExtensionL(aPsData.DataExtension());
+
+ // Set the Field match
+ clientData->SetFieldMatch(aPsData.DataMatch());
+ CleanupStack::Pop(clientData);
+
+ return clientData;
+ }
+
+// ---------------------------------------------------------------------------------
+// HandleCacheUpdated.
+// ---------------------------------------------------------------------------------
+void CPcsAlgorithm2::HandleCacheUpdated( TCachingStatus aStatus )
+ {
+ TInt psKey( KErrNotFound );
+
+ switch ( aStatus )
+ {
+ case ECacheUpdateContactRemoved:
+ psKey = EPsKeyContactRemovedCounter;
+ break;
+
+ case ECacheUpdateContactModified:
+ psKey = EPsKeyContactModifiedCounter;
+ break;
+
+ case ECacheUpdateContactAdded:
+ psKey = EPsKeyContactAddedCounter;
+ break;
+
+ default:
+ break;
+ }
+
+ // Increment the relevant counter in P&S by one to signal the clients about
+ // the cache update.
+ if( psKey != KErrNotFound )
+ {
+ TInt counter( KErrNotFound );
+ TInt err = RProperty::Get( KPcsInternalUidCacheStatus, psKey, counter );
+ if ( !err )
+ {
+ counter++;
+ RProperty::Set( KPcsInternalUidCacheStatus, psKey, counter );
+ }
+ }
+ }
+
+// ---------------------------------------------------------------------------------
+// ReconstructCacheDataL.
+// ---------------------------------------------------------------------------------
+void CPcsAlgorithm2::ReconstructCacheDataL()
+ {
+ PRINT ( _L("Enter CPcsAlgorithm2::ReconstructCacheDataL.") );
+
+ TInt err;
+ TRAP( err, iKeyMap->ReconstructKeymapL());
+ if (err != KErrNone)
+ {
+ PRINT1 ( _L("keyMap ReconstructKeymapL, err =%d"),err );
+ }
+
+ for (TInt index = 0; index < iCacheCount; index++)
+ {
+ CPcsCache* cache = iPcsCache[index];
+
+ HBufC* uri = cache->GetUri();
+ // Clear the cache
+ cache->RemoveAllFromCache();
+
+ if (err != KErrNone)
+ {
+ SetCachingError(*uri, err);
+ }
+ //Update the caching status as ECachingInProgress, since now the caching
+ // would be started again
+ UpdateCachingStatus(*uri, ECachingInProgress);
+
+ // Request for data again
+ TRAP(err, iPsDataPluginInterface->RequestForDataL(*uri));
+ PRINT1 ( _L("iPsDataPluginInterface->RequestForDataL, err =%d"),err );
+
+ if (err != KErrNone)
+ {
+ SetCachingError(*uri, err);
+ }
+ }
+ }
+
+// ---------------------------------------------------------------------------------
+// DoLaunchPluginsL.
+// launch plugins by idle
+// ---------------------------------------------------------------------------------
+TInt CPcsAlgorithm2::DoLaunchPluginsL(TAny* aPtr)
+ {
+ CPcsAlgorithm2* ptr = (CPcsAlgorithm2*) aPtr;
+ ptr->DoLaunchPluginsL();
+ return EFalse;
+ }
+
+// ---------------------------------------------------------------------------------
+// DoLaunchPluginsL.
+// lauch plugins
+// ---------------------------------------------------------------------------------
+void CPcsAlgorithm2::DoLaunchPluginsL()
+ {
+ // Initialize available data adapters
+ iPsDataPluginInterface = CPsDataPluginInterface::NewL(this, this);
+ iPsDataPluginInterface->InstantiateAllPlugInsL();
+
+ // Store the cache list in TLS
+ // Required to support sort order changes in a memory efficient way
+ // This avoids storing sort order information in the CPsData element
+ // and storing it in CPcsCache. Refer CPcsAlgorithm2Utils::CompareDataBySortOrder
+ // to see how this is being used.
+ User::LeaveIfError(Dll::SetTls(&iPcsCache));
+
+ // Initialize cache
+ RPointerArray<TDesC> dataStores;
+ CleanupClosePushL( dataStores );
+
+ iPsDataPluginInterface->GetAllSupportedDataStoresL(dataStores);
+
+ const TInt dataStoresCount = dataStores.Count();
+ for (TInt dIndex = 0; dIndex < dataStoresCount; dIndex++)
+ {
+ AddDataStore(*(dataStores[dIndex]));
+ }
+
+ CleanupStack::PopAndDestroy( &dataStores ); // Close
+ }
+
+/**
+* Returns the Adaptive Grid for one or more URI
+*
+*/
+ void CPcsAlgorithm2::GetAdaptiveGridL( const MDesCArray& /*aURIs*/,
+ const TBool /*aCompanyName*/,
+ TDes& /*aAdaptiveGrid*/ )
+ {
+ PRINT ( _L("Enter CPcsAlgorithm2::GetAdaptiveGridL") );
+
+
+ PRINT ( _L("End CPcsAlgorithm2::GetAdaptiveGridL") );
+
+ }
+// End of file
+