/*
* Copyright (c) 2009 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: Base class for Contact and RMU match observers
*
*/
#include "emailtrace.h"
#include "cesmrclsmatchobserver.h"
#include "cesmrclslistshandler.h"
#include "esmrfieldbuilderdef.h"
// for PCS support
#include <CPsRequestHandler.h>
#include <CPsSettings.h>
#include <CPsQuery.h>
#include <CPsQueryItem.h>
#include <CPcsDefs.h>
#include <MVPbkContactLink.h>
#include <CVPbkContactManager.h>
#include <aknnotewrappers.h>
#include <centralrepository.h> // CRepository
#include <AknFepInternalCRKeys.h> // KCRUidAknFep, KAknFepPredTxtFlag
#include <VPbkEng.rsg>
//Constants
// Unnamed namespace for local definitions
namespace{ // codescanner::namespace
const TInt KMatchLen = 10;
template<typename T> class CleanupResetAndDestroyClose
{
public:
inline static void PushL( T& aRef );
private:
static void Close( TAny *aPtr );
};
template<typename T> inline void CleanupResetAndDestroyClosePushL( T& aRef );
template<typename T> inline void CleanupResetAndDestroyClose<T>::PushL( T& aRef )
{
CleanupStack::PushL( TCleanupItem( &Close, &aRef ) );
}
template<typename T> void CleanupResetAndDestroyClose<T>::Close( TAny *aPtr )
{
static_cast<T*>(aPtr)->ResetAndDestroy();
static_cast<T*>(aPtr)->Close();
}
template<typename T> inline void CleanupResetAndDestroyClosePushL( T& aRef )
{
CleanupResetAndDestroyClose<T>::PushL( aRef );
}
}//namespace
// ======== MEMBER FUNCTIONS ========
// -----------------------------------------------------------------------------
// CESMRClsMatchObserver::NewL
// -----------------------------------------------------------------------------
//
CESMRClsMatchObserver* CESMRClsMatchObserver::NewL(CRepository& aCr,
CESMRClsListsHandler& aListsHandler,
CPSRequestHandler& aRequestHandler,
CVPbkContactManager* aContactManager)
{
FUNC_LOG;
CESMRClsMatchObserver* api = CESMRClsMatchObserver::NewLC( aCr, aListsHandler,
aRequestHandler, aContactManager );
CleanupStack::Pop( api );
return api;
}
// -----------------------------------------------------------------------------
// CESMRClsMatchObserver::NewLC
// -----------------------------------------------------------------------------
//
CESMRClsMatchObserver* CESMRClsMatchObserver::NewLC(CRepository& aCr,
CESMRClsListsHandler& aListsHandler,
CPSRequestHandler& aRequestHandler,
CVPbkContactManager* aContactManager )
{
FUNC_LOG;
CESMRClsMatchObserver* api = new (ELeave) CESMRClsMatchObserver(
aCr,
aListsHandler,
aRequestHandler,
aContactManager );
CleanupStack::PushL( api );
api->ConstructL();
return api;
}
// -----------------------------------------------------------------------------
// CESMRClsMatchObserver::CESMRClsMatchObserver
// -----------------------------------------------------------------------------
//
CESMRClsMatchObserver::CESMRClsMatchObserver(
CRepository& aCr,
CESMRClsListsHandler& aListsHandler,
CPSRequestHandler& aRequestHandler,
CVPbkContactManager* aContactManager ) :
iRequestHandler( &aRequestHandler ),
iAknFepCenRep( aCr ),
iListHandler( aListsHandler ),
iInputMode(EQwerty),
iContactManager( aContactManager )
{
FUNC_LOG;
}
// -----------------------------------------------------------------------------
// CESMRClsMatchObserver::~CESMRClsMatchObserver
// -----------------------------------------------------------------------------
//
CESMRClsMatchObserver::~CESMRClsMatchObserver()
{
FUNC_LOG;
delete iQuery;
if(iRequestHandler)
{
iRequestHandler->RemoveObserver(this);
}
}
void CESMRClsMatchObserver::ConstructL()
{
FUNC_LOG;
iRequestHandler->AddObserverL( this );
iInputMode = GetInputMode();
iQuery = CPsQuery::NewL();
}
// -----------------------------------------------------------------------------
// CESMRClsMatchObserver::SearchMatchesL
// -----------------------------------------------------------------------------
//
void CESMRClsMatchObserver::SearchMatchesL( const TDesC& aText )
{
FUNC_LOG;
if( iRequestHandler )
{
TInt cacheStatus = CheckCacheStatusL();
if ( !cacheStatus )
{
// Reset query
iQuery->Reset();
// Create one queryitem for every character in the query string and append it to the query object
// Every queryitem is filled with two fields :
// 1) a character from the query string
// 2) the keyboard mode using which the query was entered
TInt itemCount = aText.Length();
for ( TInt i = 0; i < itemCount; i++ )
{
// Add a query item
CPsQueryItem* item = CPsQueryItem::NewL();
item->SetCharacter(aText[i]);
item->SetMode(iInputMode); // EItut refers to numeric keypad
// Use EQwerty if QWERTY keyboard is used
iQuery->AppendL(*item);
}
// Initiate a search request
iRequestHandler->SearchL(*iQuery);
}
else //Cache isn't ready
{
iListHandler.OperationErrorL( cacheStatus );
}
}
}
// -----------------------------------------------------------------------------
// CESMRClsMatchObserver::SetInputModeL
// -----------------------------------------------------------------------------
//
void CESMRClsMatchObserver::SetInputMode( TKeyboardModes aInputMode )
{
FUNC_LOG;
iInputMode = aInputMode;
}
// -----------------------------------------------------------------------------
// CESMRClsMatchObserver::HandleMatchComplete
// -----------------------------------------------------------------------------
//
void CESMRClsMatchObserver::HandlePsResultsUpdate(
RPointerArray<CPsClientData>& searchResults,
RPointerArray<CPsPattern>& searchSeqs)
{
FUNC_LOG;
TRAP_IGNORE( HandlePsResultsUpdateL( searchResults, searchSeqs) );
}
void CESMRClsMatchObserver::HandlePsError(TInt aErrorCode)
{
FUNC_LOG;
TRAP_IGNORE( iListHandler.OperationErrorL( aErrorCode ) );
}
// -----------------------------------------------------------------------------
// CESMRClsMatchObserver::CachingStatus
// -----------------------------------------------------------------------------
//
void CESMRClsMatchObserver::CachingStatus(
TCachingStatus& aStatus, TInt& /*aError*/)
{
FUNC_LOG;
TInt err = KErrNone;
switch ( aStatus )
{
case ECachingComplete:
err = KErrNone;
break;
case ECachingNotStarted:
err = KErrNotFound;
break;
case ECachingInProgress:
err = KErrNotReady;
break;
case ECachingCompleteWithErrors:
err = KErrCorrupt;
break;
default:
break;
}
TRAP_IGNORE( iListHandler.OperationErrorL( err ) );
}
// -----------------------------------------------------------------------------
// CESMRClsMatchObserver::IsCurrentInputModePredictive
// -----------------------------------------------------------------------------
//
TKeyboardModes CESMRClsMatchObserver::GetInputMode()
{
FUNC_LOG;
TInt repVal = 0;
// 1 = predictive, 0 = non predictive
iAknFepCenRep.Get( KAknFepPredTxtFlag, repVal );
//If true, EItut (predictive)
if( repVal == 1 )
{
return EItut;
}
return EQwerty;
}
// -----------------------------------------------------------------------------
// CESMRClsMatchObserver::CheckCacheStatusL
// -----------------------------------------------------------------------------
//
TBool CESMRClsMatchObserver::CheckCacheStatusL()
{
FUNC_LOG;
// Get the caching status synchronously
// 'status' has the caching status
// 'err' has KErrNone or any caching errors
TCachingStatus status;
TInt err = iRequestHandler->GetCachingStatusL(status);
switch (status)
{
case ECachingComplete:
return KErrNone;
case ECachingNotStarted:
return KErrNotFound;
case ECachingInProgress:
return KErrNotReady;
case ECachingCompleteWithErrors:
return KErrCorrupt;
default:
break;
}
return EFalse;
}
// -----------------------------------------------------------------------------
// CESMRClsMatchObserver::CreateDisplayNameLC
// -----------------------------------------------------------------------------
//
HBufC* CESMRClsMatchObserver::CreateDisplayNameLC( const TDesC& aFirstname, const TDesC& aLastname, const TDesC& aEmailField )
{
FUNC_LOG;
HBufC* displayname;
if ( aFirstname.Length() == 0)
{
if ( aLastname.Length() == 0 )
{
//There's just the email address for Displayname
displayname = HBufC::NewLC( aEmailField.Length() );
displayname->Des().Copy( aEmailField );
}
else
{
//Lastname = displayname
displayname = HBufC::NewLC( aLastname.Length() );
displayname->Des().Copy( aLastname );
}
}
else if ( aLastname.Length() == 0 )
{
//Firstname = displayname
displayname = HBufC::NewLC( aFirstname.Length() );
displayname->Des().Copy( aFirstname );
}
else
{
//Displayname = firstname + " " + lastname
displayname = HBufC::NewLC( aFirstname.Length() +
1 +
aLastname.Length() );
displayname->Des().Copy( aFirstname );
displayname->Des().Append( KEmptySpace );
displayname->Des().Append( aLastname );
}
return displayname;
}
// -----------------------------------------------------------------------------
// CESMRClsMatchObserver::HandlePsResultsUpdateL
// -----------------------------------------------------------------------------
//
void CESMRClsMatchObserver::HandlePsResultsUpdateL(
RPointerArray<CPsClientData>& searchResults,
RPointerArray<CPsPattern>& searchSeqs)
{
FUNC_LOG;
RPointerArray<CESMRClsItem> contacts;
CleanupResetAndDestroyClosePushL( contacts );
CleanupResetAndDestroyClosePushL( searchResults );
CleanupResetAndDestroyClosePushL( searchSeqs );
// Iterate through all the search results
for( TInt counter = 0 ; counter < searchResults.Count(); counter++ )
{
// Get search result
CPsClientData* result = searchResults[counter];
// Get the order of the data fields in result
RArray<TInt> dataOrder;
CleanupClosePushL( dataOrder );
iRequestHandler->GetDataOrderL( *( result->Uri() ), dataOrder );
HBufC* firstname = HBufC::NewLC( KMaxTextLength );
HBufC* lastname = HBufC::NewLC( KMaxTextLength );
RPointerArray<HBufC> emailFields;
CleanupResetAndDestroyClosePushL( emailFields );
// Iterate through all the data fields in the result.
// Collect the result and resolve which fields did match.
// Email fields are collected into array
for( TInt dataField = 0 ; dataField < dataOrder.Count(); dataField++ )
{
switch( dataOrder[dataField] )
{
case R_VPBK_FIELD_TYPE_FIRSTNAME:
firstname->Des().Append( *(result->Data(dataField)) );
break;
case R_VPBK_FIELD_TYPE_LASTNAME:
lastname->Des().Append( *(result->Data(dataField)) );
break;
case R_VPBK_FIELD_TYPE_EMAILGEN:
case R_VPBK_FIELD_TYPE_EMAILHOME:
case R_VPBK_FIELD_TYPE_EMAILWORK:
{
if( result->Data( dataField ) )
{
if( (*(result->Data( dataField ))).Length() > 0 )
{
HBufC* email = HBufC::NewLC( KMaxTextLength );
email->Des().Append( *(result->Data( dataField )) );
emailFields.Append( email );
CleanupStack::Pop( email );
}
}
}
break;
}
}
TDesC& sourceUri = *( result->Uri() );
TBool isMruItem = sourceUri.Find( KDefaultMailBoxURI ) != KErrNotFound;
MVPbkContactLink* contactLink = NULL;
if( !isMruItem )
{
contactLink = iRequestHandler->ConvertToVpbkLinkLC( *result, *iContactManager );
CleanupStack::Pop();
// Push M-pointer to contactLink into CleanupStack for proper cleanup
CleanupDeletePushL( contactLink );
}
// Determine how many contact address to create:
// If there's no email fields, create one item without email address
if ( emailFields.Count() == 0 )
{
// Use Ps engine to check if the text matches the search query
CDesCArray* matchSet = new (ELeave) CDesCArrayFlat(KMatchLen);
CleanupStack::PushL( matchSet );
// Create display name, this will be used in UI.
HBufC* displayname = CreateDisplayNameLC( *firstname, *lastname, KNullDesC );
RArray<TPsMatchLocation> matchLocation;
CleanupClosePushL( matchLocation );
iRequestHandler->LookupL( *iQuery, *displayname, *matchSet, matchLocation );
// Create contact item and set highlighting for it
CESMRClsItem* contactItem = CESMRClsItem::NewLC();
contactItem->SetDisplayNameL( *displayname );
contactItem->SetHighlightsL( matchLocation );
if ( contactLink )
{
contactItem->SetContactLinkL( *contactLink );
}
contactItem->SetIsMruItem( isMruItem );
contacts.AppendL( contactItem );
CleanupStack::Pop( contactItem );
CleanupStack::Pop( &matchLocation );
matchLocation.Close();
CleanupStack::PopAndDestroy( displayname );
CleanupStack::PopAndDestroy( matchSet );
}
else
{
// Iterate through all the email fields, check if they match the search criteria and
// create new contact item for each one that matches
for(TInt fieldIndex = 0; fieldIndex < emailFields.Count(); ++fieldIndex )
{
// Create display name, this will be used in UI.
HBufC* displayname = CreateDisplayNameLC( *firstname,
*lastname,
*emailFields[fieldIndex] );
// Create match text field, containing display field and email address
HBufC* matchText = HBufC::NewLC( displayname->Des().Length() +
1 +
emailFields[fieldIndex]->Des().Length() );
matchText->Des().Copy( *displayname );
matchText->Des().Append( KEmptySpace );
matchText->Des().Append( *emailFields[fieldIndex] );
// Use Ps engine to check if the text matches the search query
CDesCArray* matchSet = new (ELeave) CDesCArrayFlat(KMatchLen);
CleanupStack::PushL( matchSet );
RArray<TPsMatchLocation> matchLocation;
iRequestHandler->LookupL( *iQuery, *matchText, *matchSet, matchLocation );
CleanupClosePushL( matchLocation );
if( matchLocation.Count() > 0 )
{
// Create contact item and set highlighting for it
CESMRClsItem* contactItem = CESMRClsItem::NewLC();
contactItem->SetDisplayNameL( *displayname );
contactItem->SetIsMruItem( isMruItem );
contactItem->SetEmailAddressL( *emailFields[fieldIndex] );
contactItem->SetHighlightsL(matchLocation);
if ( contactLink )
{
contactItem->SetContactLinkL( *contactLink );
}
if ( emailFields.Count() > 1 )
{
contactItem->SetMultipleEmails( );
}
contacts.AppendL( contactItem );
CleanupStack::Pop( contactItem );
}
CleanupStack::PopAndDestroy( &matchLocation );
CleanupStack::PopAndDestroy( matchSet );
CleanupStack::PopAndDestroy( matchText );
CleanupStack::PopAndDestroy( displayname );
}
}
if ( contactLink )
{
CleanupStack::PopAndDestroy(); //codescanner::cleanup
}
// De-allocate name fields, first & last name
CleanupStack::PopAndDestroy( &emailFields );
CleanupStack::PopAndDestroy( lastname );
CleanupStack::PopAndDestroy( firstname );
CleanupStack::PopAndDestroy( &dataOrder );
}
iListHandler.UpdateContactMatchListsL(contacts);
CleanupStack::PopAndDestroy( &searchSeqs );
CleanupStack::PopAndDestroy( &searchResults );
CleanupStack::PopAndDestroy( &contacts );
}
//EOF