--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/predictivesearch/PcsAlgorithm/Algorithm1/src/CPcsAlgorithm1.cpp Wed Sep 01 12:29:52 2010 +0100
@@ -0,0 +1,1788 @@
+/*
+* 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 "CPcsAlgorithm1.h"
+#include "CPcsAlgorithm1Helper.h"
+#include "CPcsAlgorithm1MultiSearchHelper.h"
+#include "CPcsAlgorithm1Utils.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"
+
+const TText KSpace = ' ';
+
+
+// ============================== MEMBER FUNCTIONS ============================
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::NewL
+// Two Phase Construction
+// ----------------------------------------------------------------------------
+CPcsAlgorithm1* CPcsAlgorithm1::NewL()
+{
+ PRINT ( _L("Enter CPcsAlgorithm1::NewL") );
+
+ CPcsAlgorithm1* self = new ( ELeave ) CPcsAlgorithm1();
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop( self );
+
+ PRINT ( _L("End CPcsAlgorithm1::NewL") );
+
+ return self;
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::CPcsAlgorithm1
+// Two Phase Construction
+// ----------------------------------------------------------------------------
+CPcsAlgorithm1::CPcsAlgorithm1()
+{
+ PRINT ( _L("Enter CPcsAlgorithm1::CPcsAlgorithm1") );
+ PRINT ( _L("End CPcsAlgorithm1::CPcsAlgorithm1") );
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::ConstructL
+// Two Phase Construction
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::ConstructL()
+{
+ PRINT ( _L("Enter CPcsAlgorithm1::ConstructL") );
+
+ iCacheStatus = ECachingNotStarted; // Starting status
+ iCacheError = KErrNone; // No error
+
+ 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() );
+ if ( keyMapErr != KErrNone )
+ {
+ PRINT ( _L("**********************************************."));
+ PRINT1( _L("CPcsAlgorithm1::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 = CPcsAlgorithm1Helper::NewL(this);
+ iMultiSearchHelper = CPcsAlgorithm1MultiSearchHelper::NewL(this);
+
+ if(!iPluginLauncher->IsActive())
+ {
+ iPluginLauncher->Start(TCallBack(CPcsAlgorithm1::DoLaunchPluginsL, this));
+ }
+
+ PRINT ( _L("End CPcsAlgorithm1::ConstructL") );
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::~CPcsAlgorithm1
+// Destructor
+// ----------------------------------------------------------------------------
+CPcsAlgorithm1::~CPcsAlgorithm1()
+{
+ PRINT ( _L("Enter CPcsAlgorithm1::~CPcsAlgorithm1") );
+
+ // 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 iPluginLauncher;
+
+ PRINT ( _L("End CPcsAlgorithm1::~CPcsAlgorithm1") );
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::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 CPcsAlgorithm1::DefinePropertyL( TPcsInternalKeyCacheStatus aPsKey )
+ {
+ TInt err = RProperty::Define( KPcsInternalUidCacheStatus,
+ aPsKey,
+ RProperty::EInt );
+ if ( err != KErrAlreadyExists )
+ {
+ User::LeaveIfError(err);
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::RemoveSpacesL
+// Remove leading and trailing spaces of search query
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::RemoveSpacesL(CPsQuery& aQuery)
+{
+ PRINT ( _L("Enter CPcsAlgorithm1::RemoveSpacesL") );
+
+ //PRINTQUERY ( _L("CPcsAlgorithm1::RemoveSpacesL (BEFORE): "), aQuery );
+
+ // 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);
+ }
+
+ //PRINTQUERY ( _L("CPcsAlgorithm1::RemoveSpacesL (AFTER): "), aQuery );
+
+ PRINT ( _L("End CPcsAlgorithm1::RemoveSpacesL") );
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::ReplaceZeroWithSpaceL
+// Replace all "0"s in a search query with " "s if those characters are on
+// the same key.
+// ----------------------------------------------------------------------------
+TBool CPcsAlgorithm1::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.
+ for ( TInt index = skipIndex; index < aQuery.Count(); 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;
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::PerformSearchL
+// Search function for cache
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::PerformSearchL(const CPsSettings& aSettings,
+ CPsQuery& aQuery,
+ RPointerArray<CPsClientData>& aSearchResults,
+ RPointerArray<CPsPattern>& aSearchSeqs)
+{
+ PRINT ( _L("Enter CPcsAlgorithm1::PerformSearchL") );
+
+ __LATENCY_MARK ( _L("CPcsAlgorithm1::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> tempSearchResultsIni;
+ CleanupClosePushL( tempSearchResultsIni );
+ RPointerArray<CPsData> tempSearchResultsMod;
+ CleanupClosePushL( tempSearchResultsMod );
+
+ // ----------------------- Perform the basic search -----------------------
+ /* Even before replacing zeroes with spaces the query can have multiple words
+ * Some phones support infact double keyboards with possibility to type a space in qwerty mode
+ * A space in qwerty mode can even be typed disabling temporarily PCS
+ */
+ RemoveSpacesL(aQuery);
+ PRINTQUERY ( _L("CPcsAlgorithm1::PerformSearchL: 1st search query: "), aQuery );
+ DoSearchL(aSettings, aQuery, tempSearchResultsIni, 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.
+ * - If the original search string is "00Zxc" then we will search again with "Zxc".
+ */
+ TBool isQueryModified = ReplaceZeroWithSpaceL(aQuery);
+ RemoveSpacesL(aQuery);
+ if ( isQueryModified && (aQuery.Count() > 0) )
+ {
+ PRINTQUERY ( _L("CPcsAlgorithm1::PerformSearchL: 2nd search query: "), aQuery );
+ DoSearchL(aSettings, aQuery, tempSearchResultsMod, aSearchSeqs );
+ }
+ // ------------------------------------------------------------------------
+
+ // ------------------ Merge and sort the search results -------------------
+ if ( tempSearchResultsIni.Count() + tempSearchResultsMod.Count() > 0)
+ {
+ // Sort rule
+ TLinearOrder<CPsData> rule( CPcsAlgorithm1Utils::CompareDataBySortOrderL );
+
+ // Avoid duplicates and add new results
+ TIdentityRelation<CPsData> identityRule(CPsData::CompareById);
+
+ for ( TInt i = 0; i < tempSearchResultsIni.Count(); i++ )
+ {
+ if ( tempSearchResults.Find( tempSearchResultsIni[i],identityRule ) == KErrNotFound )
+ {
+ if (aSettings.GetSortType() == EAlphabetical)
+ {
+ tempSearchResults.InsertInOrderAllowRepeats(tempSearchResultsIni[i], rule);
+ }
+ else
+ {
+ tempSearchResults.AppendL(tempSearchResultsIni[i]);
+ }
+ }
+ }
+
+ for ( TInt i = 0; i < tempSearchResultsMod.Count(); i++ )
+ {
+ if ( tempSearchResults.Find( tempSearchResultsMod[i],identityRule ) == KErrNotFound )
+ {
+ if (aSettings.GetSortType() == EAlphabetical)
+ {
+ tempSearchResults.InsertInOrderAllowRepeats(tempSearchResultsMod[i], rule);
+ }
+ else
+ {
+ tempSearchResults.AppendL(tempSearchResultsMod[i]);
+ }
+ }
+ }
+ }
+ // ------------------------------------------------------------------------
+
+ // ------------------ 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( &tempSearchResultsMod ); // Close, don't destroy
+ CleanupStack::PopAndDestroy( &tempSearchResultsIni ); // Close, don't destroy
+ CleanupStack::PopAndDestroy( &tempSearchResults ); // Close, don't destroy
+
+ __LATENCY_MARKEND ( _L("CPcsAlgorithm1::PerformSearchL") );
+
+ PRINT ( _L("End CPcsAlgorithm1::PerformSearchL") );
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::SearchInputL
+// Search function for input string
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::SearchInputL(CPsQuery& aQuery,
+ TDesC& aData,
+ RPointerArray<TDesC>& aMatchSet,
+ RArray<TPsMatchLocation>& aMatchLocation )
+{
+ PRINT ( _L("Enter CPcsAlgorithm1::SearchInputL") );
+
+ __LATENCY_MARK ( _L("CPcsAlgorithm1::SearchInputL") );
+
+ // ----------------------- Perform the basic search -----------------------
+ /* Even before replacing zeroes with spaces the query can have multiple words
+ * Some phones support infact double keyboards with possibility to type a space in qwerty mode
+ * A space in qwerty mode can even be typed disabling temporarily PCS
+ */
+ RemoveSpacesL(aQuery);
+ DoSearchInputL(aQuery, aData, aMatchSet, aMatchLocation);
+ PRINTQUERY ( _L("CPcsAlgorithm1::SearchInputL: 1st search: "), aQuery );
+ PRINT1 ( _L("CPcsAlgorithm1::SearchInputL: 1st search: Search Data: %S"), &aData );
+ PRINTMATCHSET ( _L("CPcsAlgorithm1::SearchInputL: 1st search: "), aMatchSet );
+ PRINTMATCHLOC ( _L("CPcsAlgorithm1::SearchInputL: 1st search: "), 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 isQueryModified = ReplaceZeroWithSpaceL(aQuery);
+ RemoveSpacesL(aQuery);
+ if ( isQueryModified && (aQuery.Count() > 0) )
+ {
+ DoSearchInputL(aQuery, aData, aMatchSet, aMatchLocation);
+ PRINTQUERY ( _L("CPcsAlgorithm1::SearchInputL: 2nd search: "), aQuery );
+ PRINT1 ( _L("CPcsAlgorithm1::SearchInputL: 2nd search: Search Data: %S"), &aData );
+ PRINTMATCHSET ( _L("CPcsAlgorithm1::SearchInputL: 2nd search: "), aMatchSet );
+ PRINTMATCHLOC ( _L("CPcsAlgorithm1::SearchInputL: 2nd search: "), aMatchLocation );
+ }
+ /* In cases like we have a contact "Nik0 Abc" and the search query is "Nik0" we do:
+ * - a 1st search with "Nik0" that matches "Nik0" (4 chars) of "Nik0 Abc",
+ * - a 2nd search with "Nik" that matches "Nik" (3 chars) of "Nik0 Abc".
+ * We have to remove from aMatchLocation the occurrence that has a shorter match length.
+ * We have to remove the match ("Nik" in this case) even from aMatchSet if there is not
+ * any other match for it than the one in "Nik0".
+ */
+
+ // --- Remove duplicate items from aMatchLocation ---
+ TInt i = 0;
+ TBool incrementFirstCursor;
+ while ( i < aMatchLocation.Count() )
+ {
+ incrementFirstCursor = ETrue;
+ TInt j = i+1;
+ while ( j < aMatchLocation.Count() )
+ {
+ if (aMatchLocation[j].index == aMatchLocation[i].index)
+ {
+ // 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 duplicate items from aMatchSet ---
+ 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;
+ for ( TInt i = 0; i < aMatchLocation.Count(); 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
+ }
+ // --- Remove items End ---
+
+ }
+ CleanupStack::PopAndDestroy( dataUpper );
+ // ------------------------------------------------------------------------
+
+ // Sort match set
+ iHelper->SortSearchSeqsL(aMatchSet);
+
+ PRINTQUERY ( _L("CPcsAlgorithm1::SearchInputL: Final: "), aQuery );
+ PRINT1 ( _L("CPcsAlgorithm1::SearchInputL: Final: Search Data: %S"), &aData );
+ PRINTMATCHSET ( _L("CPcsAlgorithm1::SearchInputL: Final: "), aMatchSet );
+ PRINTMATCHLOC ( _L("CPcsAlgorithm1::SearchInputL: Final: "), aMatchLocation );
+
+ __LATENCY_MARKEND ( _L("CPcsAlgorithm1::SearchInputL") );
+
+ PRINT ( _L("End CPcsAlgorithm1::SearchInputL") );
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::SearchMatchStringL
+// Search function for input string, result also as string
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::SearchMatchStringL( CPsQuery& aSearchQuery,
+ TDesC& aSearchData,
+ TDes& aMatch )
+ {
+ PRINT ( _L("Enter CPcsAlgorithm1::SearchMatchStringL") );
+
+ __LATENCY_MARK ( _L("CPcsAlgorithm1::SearchMatchStringL") );
+
+ // ---------------------- Perform the initial search ----------------------
+ iMultiSearchHelper->LookupMatchL( aSearchQuery, aSearchData, aMatch );
+ PRINTQUERY ( _L("CPcsAlgorithm1::SearchMatchStringL: 1st search: "), aSearchQuery );
+ PRINT1 ( _L("CPcsAlgorithm1::SearchMatchStringL: 1st search: Search Data: %S"), &aSearchData );
+ PRINT1 ( _L("CPcsAlgorithm1::SearchMatchStringL: 1st search: Result: %S"), &aMatch );
+ // ------------------------------------------------------------------------
+
+ // ---- 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.
+ */
+ if ( aMatch.Length() <= 0 )
+ {
+ TBool isQueryModified = ReplaceZeroWithSpaceL(aSearchQuery);
+ if ( isQueryModified && (aSearchQuery.Count() > 0) )
+ {
+ iMultiSearchHelper->LookupMatchL( aSearchQuery, aSearchData, aMatch );
+ PRINTQUERY ( _L("CPcsAlgorithm1::SearchMatchStringL: 2nd search: "), aSearchQuery );
+ PRINT1 ( _L("CPcsAlgorithm1::SearchMatchStringL: 2nd search: Search Data: %S"), &aSearchData );
+ PRINT1 ( _L("CPcsAlgorithm1::SearchMatchStringL: 2nd search: Result: %S"), &aMatch );
+ }
+ }
+
+ __LATENCY_MARKEND ( _L("CPcsAlgorithm1::SearchMatchStringL") );
+
+ PRINT ( _L("End CPcsAlgorithm1::SearchMatchStringL") );
+ }
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::DoSearchL
+// Search function helper
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::DoSearchL( const CPsSettings& aSettings,
+ CPsQuery& aQuery,
+ RPointerArray<CPsData>& aSearchResults,
+ RPointerArray<CPsPattern>& aSearchSeqs )
+{
+ PRINT ( _L("Enter CPcsAlgorithm1::DoSearchL") );
+
+ __LATENCY_MARK ( _L("CPcsAlgorithm1::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 );
+ PRINTQUERYLIST ( _L("CPcsAlgorithm1::DoSearchL: "), 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 ) // single query
+ {
+ PRINT ( _L("CPcsAlgorithm1::DoSearchL: Query received is Single. Performing a SingleSearch") );
+
+ iHelper->SearchSingleL(*tempSettings, *queryList[0], isGroupSearch,
+ contactsInGroup, aSearchResults, aSearchSeqs);
+ }
+ // ------------------------------------------------------------------------
+
+ // (3)-------------------- Perform a multi query search -------------------
+ else // multiple query
+ {
+ PRINT ( _L("CPcsAlgorithm1::DoSearchL: Query received is Multiple. Performing a MultiSearch") );
+
+ // 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("CPcsAlgorithm1::DoSearchL") );
+
+ PRINT ( _L("End CPcsAlgorithm1::DoSearchL") );
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::DoSearchInputL
+// Search function helper
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::DoSearchInputL( CPsQuery& aQuery,
+ const TDesC& aData,
+ RPointerArray<TDesC>& aMatchSet,
+ RArray<TPsMatchLocation>& aMatchLocation )
+{
+ PRINT ( _L("Enter CPcsAlgorithm1::DoSearchInputL") );
+
+ TInt queryWords = iMultiSearchHelper->CountMultiQueryWordsL(aQuery);
+
+ // No query
+ if ( queryWords == 0 )
+ {
+ PRINT ( _L("CPcsAlgorithm1::DoSearchInputL: Query received is empty") );
+ return;
+ }
+
+ RPointerArray<CPsQuery> queryList = iMultiSearchHelper->MultiQueryL(aQuery);
+ CleanupResetAndDestroyPushL( queryList );
+
+ PRINTQUERYLIST ( _L("CPcsAlgorithm1::DoSearchInputL: "), queryList );
+
+ if ( queryList.Count() == 1 ) // Single query
+ {
+ PRINT ( _L("CPcsAlgorithm1::DoSearchInputL: Query received is single. Performing a single search.") );
+ iHelper->SearchMatchSeqL(aQuery,
+ aData,
+ aMatchSet,
+ aMatchLocation);
+ }
+ else // multiple query
+ {
+ PRINT ( _L("CPcsAlgorithm1::DoSearchInputL: Query received is Multiple. Performing a MultiSearch") );
+ iMultiSearchHelper->SearchMatchSeqMultiL(queryList,
+ aData,
+ aMatchSet,
+ aMatchLocation);
+ }
+
+ // Delete all the query elements
+ CleanupStack::PopAndDestroy( &queryList ); // ResetAndDestroy
+
+ PRINT ( _L("End CPcsAlgorithm1::DoSearchInputL") );
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::AddData
+// Add a data element to the pool
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::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("CPcsAlgorithm1::AddData: Unknown data store"));
+ return;
+ }
+
+ TRAPD(err, cache->AddToCacheL(*aData));
+
+ if ( err != KErrNone )
+ {
+ SetCachingError(aDataStore, err);
+ }
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::RemoveData
+// Remove a data element from the pool
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::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);
+ }
+}
+
+// ---------------------------------------------------------------------
+// CPcsAlgorithm1::RemoveAll
+// Remove all the contacts from a datastore
+// ---------------------------------------------------------------------
+void CPcsAlgorithm1::RemoveAll(TDesC& aDataStore)
+{
+ TInt dataStoreIndex = GetCacheIndex(aDataStore);
+
+ if(dataStoreIndex < 0) return;
+
+ CPcsCache* cache = iPcsCache[dataStoreIndex];
+
+ cache->RemoveAllFromCache();
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::GetCacheIndex
+// Return the cache index for a data store
+// ----------------------------------------------------------------------------
+TInt CPcsAlgorithm1::GetCacheIndex(const TDesC& aDataStore)
+{
+ for ( int i = 0; i < iPcsCache.Count(); i++ )
+ {
+ CPcsCache* cache = iPcsCache[i];
+
+ if ( cache->GetURI().CompareC(aDataStore) == 0 ) return i;
+ }
+
+ return KErrNotFound;
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::AddDataStore
+// Adds a new store
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::AddDataStore(TDesC& aDataStore)
+{
+ // Check if the datastore cache already exists
+ TInt index = GetCacheIndex(aDataStore);
+ if ( index != KErrNotFound )
+ {
+ // Already exists
+ return;
+ }
+
+ // Create a new cache
+ CPcsCache* cache = NULL;
+ TRAPD(err, cache = CPcsCache::NewL(aDataStore, *iKeyMap, (TUint8) iPcsCache.Count()));
+ if ( err != KErrNone )
+ {
+ SetCachingError(aDataStore, err);
+ return;
+ }
+
+ 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 )
+ {
+ PRINT ( _L("CPcsAlgorithm1::AddDataStore() Set Caching Error ") );
+ SetCachingError(aDataStore, err);
+ UpdateCachingStatus(aDataStore,ECachingCompleteWithErrors);
+ return;
+ }
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::RemoveDataStore
+// Removes an existing data store
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::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);
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::IsLanguageSupportedL
+// Returns ETrue if this language is supported
+// ----------------------------------------------------------------------------
+TBool CPcsAlgorithm1::IsLanguageSupportedL(TUint32 aLang)
+{
+ return iKeyMap->IsLanguageSupported(aLang);
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::GetUriForIdL
+// Get the URI string for this internal id
+// ----------------------------------------------------------------------------
+const TDesC& CPcsAlgorithm1::GetUriForIdL(TUint8 aUriId)
+{
+ TBool found = EFalse;
+ TInt i = 0;
+
+ for ( i = 0; i < iPcsCache.Count(); i++ )
+ {
+ if ( iPcsCache[i]->GetUriId() == aUriId )
+ {
+ found = ETrue;
+ break;
+ }
+ }
+
+ if ( ! found )
+ {
+ User::Leave(KErrNotFound);
+ }
+
+ return iPcsCache[i]->GetURI();
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::FindStoreUri
+// Checks if this store exists
+// ----------------------------------------------------------------------------
+TInt CPcsAlgorithm1::FindStoreUri ( const TDesC& aDataStore )
+{
+ for ( TInt i = 0; i < iPcsCache.Count(); i++ )
+ {
+ if ( aDataStore.CompareC(iPcsCache[i]->GetURI()) == 0 )
+ {
+ return i;
+ }
+ }
+
+ return KErrNotFound;
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::UpdateCachingStatus
+// Update caching status
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::UpdateCachingStatus(TDesC& aDataStore, TInt aStatus)
+{
+ PRINT ( _L("Enter CPcsAlgorithm1::UpdateCachingStatus") );
+ PRINT2 ( _L("CPcsAlgorithm1::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("CPcsAlgorithm1::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("CPcsAlgorithm1::UpdateCachingStatus: Cumulative caching status is %d"),
+ status );
+
+ // Check if status changed
+ if ( status != iCacheStatus )
+ {
+ PRINT2 ( _L("CPcsAlgorithm1::UpdateCachingStatus: Cumulative caching changed: %d -> %d"),
+ iCacheStatus, status );
+
+ iCacheStatus = status;
+ RProperty::Set(KPcsInternalUidCacheStatus, EPsKeyCacheStatus, iCacheStatus );
+ }
+
+ PRINT( _L("End CPcsAlgorithm1::UpdateCachingStatus") );
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::SetCachingError
+// Updates cachinge error
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::SetCachingError(const TDesC& aDataStore, TInt aError)
+{
+ PRINT2 ( _L("CPcsAlgorithm1::SetCachingError: URI=%S, ERROR=%d"), &aDataStore, aError );
+
+ iCacheError = aError;
+ RProperty::Set( KPcsInternalUidCacheStatus, EPsKeyCacheError, iCacheError );
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::GetAllContentsL
+// Returns all the contents of a store
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::GetAllContentsL ( const CPsSettings& aSettings,
+ RPointerArray<CPsData>& aResults )
+{
+ __LATENCY_MARK ( _L("CPcsAlgorithm1::GetAllContentsL") );
+
+ PRINT ( _L("Enter CPcsAlgorithm1::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
+ for ( TInt dsIndex = 0;
+ dsIndex < dataStores.Count();
+ 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
+ CPcsAlgorithm1Utils::FormCompleteSearchResultsL(searchResultsArr,
+ aResults);
+
+ // Cleanup the local arrays
+ for(TInt i = 0; i < searchResultsArr.Count(); i++)
+ {
+ searchResultsArr[i]->Reset();
+ }
+ CleanupStack::PopAndDestroy( &searchResultsArr ); // ResetAndDestroy
+
+ PRINT1 ( _L("Number of results = %d"), aResults.Count() );
+
+ PRINT ( _L("End CPcsAlgorithm1::GetAllContentsL") );
+
+ __LATENCY_MARKEND ( _L("CPcsAlgorithm1::GetAllContentsL") );
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::IsGroupSearchL
+// Checks if a group search is required
+// ----------------------------------------------------------------------------
+TBool CPcsAlgorithm1::IsGroupSearchL ( CPsSettings& aSettings,
+ RArray<TInt>& aGroupIdArray )
+{
+ PRINT ( _L("Enter CPcsAlgorithm1::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 CPcsAlgorithm1::IsGroupSearchL") );
+
+ if ( aGroupIdArray.Count() == 1 )
+ return ETrue;
+
+ return EFalse;
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::ReplaceGroupsUriL
+// Replace groups uri to contacts uri
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::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
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::FilterSearchResultsForGroupsL
+// Filters the results that belong to a group
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::FilterSearchResultsForGroupsL(RArray<TInt>& contactsInGroup,
+ RPointerArray<CPsData>& aSearchResults)
+{
+ PRINT ( _L("Enter CPcsAlgorithm1::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 CPcsAlgorithm1::FilterSearchResultsForGroupsL") );
+}
+
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::GetContactsInGroupL
+// Recover contacts that belong to a group
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::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
+ for ( TInt i = 0; i < groups.Count(); i++ )
+ {
+ if ( groups[i]->Id() == aGroupId )
+ {
+ groups[i]->IntDataExt(aGroupContactIds); // All contacts in group
+ break;
+ }
+ }
+
+ CleanupStack::PopAndDestroy( &groups ); // Close
+ }
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::GetDataOrderL
+//
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::GetDataOrderL ( TDesC& aURI,
+ RArray<TInt>& aDataOrder )
+{
+ PRINT ( _L("End CPcsAlgorithm1::GetDataOrderL") );
+
+ TInt arrayIndex = KErrNotFound;
+
+ if ( CPcsAlgorithm1Utils::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 CPcsAlgorithm1::GetDataOrderL") );
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::GetSortOrderL
+//
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::GetSortOrderL ( TDesC& aURI,
+ RArray<TInt>& aDataOrder )
+{
+ PRINT ( _L("End CPcsAlgorithm1::GetSortOrderL") );
+
+ TInt arrayIndex = KErrNotFound;
+
+ if ( CPcsAlgorithm1Utils::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 CPcsAlgorithm1::GetSortOrderL") );
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::ChangeSortOrderL
+//
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::ChangeSortOrderL ( TDesC& aURI,
+ RArray<TInt>& aSortOrder )
+{
+ PRINT ( _L("Enter CPcsAlgorithm1::ChangeSortOrderL") );
+
+ PRINT ( _L("CPcsAlgorithm1::ChangeSortOrderL. Sort order change received.") );
+ PRINT1 ( _L("CPcsAlgorithm1::ChangeSortOrderL. URI = %S"), &aURI );
+
+ // If URI is search in a group URI return
+ if ( CPcsAlgorithm1Utils::IsGroupUri(aURI) )
+ {
+ PRINT ( _L("CPcsAlgorithm1::ChangeSortOrderL. Sort order change not supported.") );
+ return;
+ }
+
+ // Check if a cache exists
+ TInt arrayIndex = GetCacheIndex(aURI);
+ if ( arrayIndex < 0 )
+ {
+ PRINT ( _L("CPcsAlgorithm1::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;
+ for ( TInt i = 0; i < mySortOrder.Count(); i++ )
+ {
+ if ( mySortOrder[i] != aSortOrder[i] )
+ {
+ same = EFalse;
+ break;
+ }
+ }
+
+ if ( same )
+ {
+ PRINT ( _L("CPcsAlgorithm1::ChangeSortOrderL. Same sort order received. Ignoring ...") );
+ PRINT ( _L("End CPcsAlgorithm1::ChangeSortOrderL.") );
+ mySortOrder.Reset();
+ return;
+ }
+ }
+
+ mySortOrder.Reset();
+
+ PRINT ( _L("CPcsAlgorithm1::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);
+
+ // Resort data
+ 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 CPcsAlgorithm1::ChangeSortOrderL") );
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::GetAdaptiveGridL
+//
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::GetAdaptiveGridL( const MDesCArray& aURIs,
+ const TBool aCompanyName,
+ TDes& aAdaptiveGrid )
+{
+ PRINT ( _L("Enter CPcsAlgorithm1::GetAdaptiveGridL") );
+
+ PRINT1 ( _L("CPcsAlgorithm1::GetAdaptiveGridL. Request of Adaptive Grid for %d URI(s)"),
+ aURIs.MdcaCount() );
+
+ if ( iCacheStatus != ECachingComplete )
+ {
+ PRINT ( _L("CPcsAlgorithm1::GetAdaptiveGridL: PCS Caching is not ready, returning empty Adaptive Grid") );
+ aAdaptiveGrid.Zero();
+ }
+ else
+ {
+ GetAdaptiveGridFromCacheL( aURIs, aCompanyName, aAdaptiveGrid );
+ }
+
+ PRINT ( _L("End CPcsAlgorithm1::GetAdaptiveGridL") );
+}
+
+// ----------------------------------------------------------------------------
+// CPcsAlgorithm1::GetAdaptiveGridFromCacheL
+//
+// ----------------------------------------------------------------------------
+void CPcsAlgorithm1::GetAdaptiveGridFromCacheL( const MDesCArray& aURIs,
+ const TBool aCompanyName,
+ TDes& aAdaptiveGrid )
+{
+ PRINT ( _L("Enter CPcsAlgorithm1::GetAdaptiveGridFromCacheL") );
+
+ PRINT1 ( _L("CPcsAlgorithm1::GetAdaptiveGridFromCacheL. Request of Adaptive Grid for %d URI(s)"),
+ aURIs.MdcaCount() );
+
+ RArray<TInt> cacheIds;
+ CleanupClosePushL( cacheIds );
+
+ // Create the list of the cache indexes that will form the Adaptive Grid
+ for ( TInt i=0; i < aURIs.MdcaCount(); i++ )
+ {
+ TPtrC16 uri = aURIs.MdcaPoint(i);
+
+ // If URI is a group URI skip it
+ if ( CPcsAlgorithm1Utils::IsGroupUri( uri ) )
+ {
+ PRINT1 ( _L("CPcsAlgorithm1::GetAdaptiveGridFromCacheL. Adaptive Grid for URI \"%S\" is not supported. Skipping"),
+ &uri );
+ continue;
+ }
+
+ TInt cacheIndex = GetCacheIndex( uri );
+ if ( cacheIndex == KErrNotFound )
+ {
+ PRINT1 ( _L("CPcsAlgorithm1::GetAdaptiveGridFromCacheL. Cache for URI \"%S\" doesn't exist"),
+ &uri );
+ continue;
+ }
+
+ PRINT1 ( _L("CPcsAlgorithm1::GetAdaptiveGridFromCacheL. Cache for URI \"%S\" will be used to form the Adaptive Grid"),
+ &uri );
+
+ cacheIds.AppendL( cacheIndex );
+ }
+
+ PRINT1 ( _L("CPcsAlgorithm1::GetAdaptiveGridFromCacheL. Number of caches that will be used to form the grid is %d"),
+ cacheIds.Count( ) );
+
+ // Create the Adaptive Grid from the cache(s)
+ if ( cacheIds.Count() == 1 ) // No merge if we have only one cache
+ {
+ // Cache instance for this URI
+ CPcsCache* cache = iPcsCache[cacheIds[0]];
+
+ // Get the Adaptive Grid
+ cache->GetAdaptiveGridL( aCompanyName, aAdaptiveGrid );
+
+ PRINT1 ( _L("CPcsAlgorithm1::GetAdaptiveGridFromCacheL. Adaptive Grid: \"%S\" (No merge was needed)"),
+ &aAdaptiveGrid );
+ }
+ else if ( cacheIds.Count() > 1 ) // Merge if we have more than one cache
+ {
+ RArray<TChar> gridAll;
+ CleanupClosePushL( gridAll );
+ TUint gridSize = 0;
+
+ HBufC16* gridOne = HBufC::NewLC(KPsAdaptiveGridStringMaxLen);
+ TPtr16 gridOnePtr( gridOne->Des( ));
+
+ TLinearOrder<TChar> rule( CPcsAlgorithm1Utils::CompareByCharacter );
+
+ // Loop through the caches that form the Adaptive Grid
+ for ( TUint i=0;
+ gridSize < KPsAdaptiveGridStringMaxLen && i < cacheIds.Count();
+ i++ )
+ {
+ // Cache instance for this URI
+ CPcsCache* cache = iPcsCache[cacheIds[i]];
+
+ // Get the Adaptive Grid
+ gridOnePtr.Zero();
+ cache->GetAdaptiveGridL( aCompanyName, gridOnePtr );
+
+ PRINT2 ( _L("CPcsAlgorithm1::GetAdaptiveGridFromCacheL. Adaptive Grid for cache \"%S\" is \"%S\""),
+ &cache->GetURI(), &gridOnePtr );
+
+ // Loop through the characters of the Adaptive Grid for the cache
+ for ( TUint j=0;
+ gridSize < KPsAdaptiveGridStringMaxLen && j < gridOnePtr.Length();
+ j++ )
+ {
+ if ( i == 0 ) // Grid from one cache is already ordered with no repetitions
+ {
+ gridAll.Append( gridOnePtr[j]);
+ }
+ else // Grids from more caches can have repeated characters
+ {
+ gridAll.InsertInOrder( gridOnePtr[j], rule ); // No repeats !!!
+ }
+ gridSize++;
+ }
+ }
+
+ // Form the Adaptive Grid to be returned
+ aAdaptiveGrid.Zero();
+ for ( TUint i=0; i < gridAll.Count(); i++ )
+ {
+ aAdaptiveGrid.Append( gridAll[i] );
+ }
+
+ PRINT1 ( _L("CPcsAlgorithm1::GetAdaptiveGridFromCacheL. Adaptive Grid: \"%S\" (Merge was done)"),
+ &aAdaptiveGrid );
+
+ CleanupStack::PopAndDestroy( gridOne );
+ CleanupStack::PopAndDestroy( &gridAll ); // Close
+ }
+
+ CleanupStack::PopAndDestroy( &cacheIds ); // Close
+
+ PRINT ( _L("End CPcsAlgorithm1::GetAdaptiveGridFromCacheL") );
+}
+
+// ---------------------------------------------------------------------------------
+// Read the persisted sort order from the central repository
+// Persisted sort order is of form URI Field1 Field2 Field3 .. FieldN (space delimited)
+// ---------------------------------------------------------------------------------
+void CPcsAlgorithm1::ReadSortOrderFromCenRepL(const TDesC& aURI,
+ RArray<TInt>& aSortOrder)
+{
+ PRINT ( _L("Enter CPcsAlgorithm1::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 CPcsAlgorithm1::ReadSortOrderFromCenRepL.") );
+}
+
+// ---------------------------------------------------------------------------------
+// Write the sort order into the central repository
+// Persisted sort order is of form URI Field1 Field2 Field3 .. FieldN (space delimited)
+// ---------------------------------------------------------------------------------
+void CPcsAlgorithm1::WriteSortOrderToCenRepL(const TDesC& aURI,
+ RArray<TInt>& aSortOrder)
+{
+ PRINT ( _L("Enter CPcsAlgorithm1::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("CPcsAlgorithm1::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("CPcsAlgorithm1::WriteSortOrderToCenRepL. cenrep error.") );
+ return;
+ }
+
+ if (str == KNullDesC)
+ {
+ keyIndex = i; // i has the next free location
+ break;
+ }
+ }
+ }
+
+ if ( keyIndex == -1 )
+ {
+ PRINT ( _L("CPcsAlgorithm1::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
+ for ( TInt j = 0; j < aSortOrder.Count(); 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 CPcsAlgorithm1::WriteSortOrderToCenRepL.") );
+}
+
+// ---------------------------------------------------------------------------------
+// WriteClientDataL.
+// Write the content required by client
+// ---------------------------------------------------------------------------------
+CPsClientData* CPcsAlgorithm1::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
+ for(TInt i = 0; i < aPsData.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 CPcsAlgorithm1::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;
+ }
+
+ if ( psKey != KErrNotFound )
+ {
+ // Increment the related counter in P&S by one to signal the clients about
+ // the cache update.
+ TInt counter( KErrNotFound );
+ TInt err = RProperty::Get( KPcsInternalUidCacheStatus, psKey, counter );
+ if ( !err )
+ {
+ counter++;
+ RProperty::Set( KPcsInternalUidCacheStatus, psKey, counter );
+ }
+ }
+ }
+
+// ---------------------------------------------------------------------------------
+// DoLaunchPluginsL.
+// launch plugins by idle
+// ---------------------------------------------------------------------------------
+TInt CPcsAlgorithm1::DoLaunchPluginsL(TAny* aPtr)
+ {
+ CPcsAlgorithm1* ptr = (CPcsAlgorithm1*) aPtr;
+ ptr->DoLaunchPluginsL();
+ return EFalse;
+ }
+
+// ---------------------------------------------------------------------------------
+// DoLaunchPluginsL.
+// lauch plugins
+// ---------------------------------------------------------------------------------
+void CPcsAlgorithm1::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 CPcsAlgorithm1Utils::CompareDataBySortOrderL
+ // to see how this is being used.
+ User::LeaveIfError( Dll::SetTls(&iPcsCache) );
+
+ // Initialize cache
+ RPointerArray<TDesC> dataStores;
+ CleanupClosePushL( dataStores );
+
+ iPsDataPluginInterface->GetAllSupportedDataStoresL(dataStores);
+
+ for ( TInt dIndex = 0; dIndex < dataStores.Count(); dIndex++ )
+ {
+ AddDataStore(*(dataStores[dIndex]));
+ }
+
+ CleanupStack::PopAndDestroy( &dataStores ); // Close
+ }
+
+// End of file
+