/*
* 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