/*
* 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: Base class for Contact and RMU match observers
*
*/
// for PCS support
#include "emailtrace.h"
#include <CPsQueryItem.h>
#include <CPsRequestHandler.h>
#include <aknnotewrappers.h>
#include <AknFepInternalCRKeys.h> // KCRUidAknFep, KAknFepPredTxtFlag
#include <VPbkEng.rsg>
#include "FreestyleEmailUiCLSListsHandler.h" // CFSEmailUiClsListsHandler
#include "FreestyleEMailUiCLSMatchObserverInterface.h" // CFSEmailUiClsMatchObserver
#include "FreestyleEmailUiUtilities.h"
#include "FreestyleEmailUiLiterals.h"
#include "FreestyleEmailUiCLSItem.h"
#include "FreestyleEmailUiAppui.h"
#include "FreestyleEmailUiLayoutHandler.h"
// ================= MEMBER FUNCTIONS ==========================================
CFSEmailUiClsMatchObserver* CFSEmailUiClsMatchObserver::NewL(CRepository& aCr,
CFSEmailUiClsListsHandler& aListsHandler,
CPSRequestHandler& aRequestHandler,
CVPbkContactManager* aContactManager)
{
FUNC_LOG;
CFSEmailUiClsMatchObserver* api = CFSEmailUiClsMatchObserver::NewLC( aCr, aListsHandler,
aRequestHandler, aContactManager );
CleanupStack::Pop( api );
return api;
}
CFSEmailUiClsMatchObserver* CFSEmailUiClsMatchObserver::NewLC(CRepository& aCr,
CFSEmailUiClsListsHandler& aListsHandler,
CPSRequestHandler& aRequestHandler,
CVPbkContactManager* aContactManager )
{
FUNC_LOG;
CFSEmailUiClsMatchObserver* api = new (ELeave) CFSEmailUiClsMatchObserver(
aCr,
aListsHandler,
aRequestHandler,
aContactManager );
CleanupStack::PushL( api );
api->ConstructL();
return api;
}
// -----------------------------------------------------------------------------
// CFSEmailUiClsMatchObserver::CFSEmailUiClsMatchObserver
// -----------------------------------------------------------------------------
CFSEmailUiClsMatchObserver::CFSEmailUiClsMatchObserver(
CRepository& aCr,
CFSEmailUiClsListsHandler& aListsHandler,
CPSRequestHandler& aRequestHandler,
CVPbkContactManager* aContactManager ) :
iRequestHandler( &aRequestHandler ),
iAknFepCenRep( aCr ),
iListHandler( aListsHandler ),
iInputMode( EQwerty ),
iContactManager( aContactManager )
{
FUNC_LOG;
}
// -----------------------------------------------------------------------------
// CFSEmailUiClsMatchObserver::~CFSEmailUiClsMatchObserver
// -----------------------------------------------------------------------------
CFSEmailUiClsMatchObserver::~CFSEmailUiClsMatchObserver()
{
FUNC_LOG;
delete iQuery;
if ( iRequestHandler )
{
iRequestHandler->RemoveObserver( this );
}
}
void CFSEmailUiClsMatchObserver::ConstructL()
{
FUNC_LOG;
iRequestHandler->AddObserverL( this );
iInputMode = GetInputMode();
iQuery = CPsQuery::NewL();
}
// -----------------------------------------------------------------------------
// CFSEmailUiClsMatchObserver::SearchMatchesL
// -----------------------------------------------------------------------------
void CFSEmailUiClsMatchObserver::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();
if ( itemCount > 50 )
{
itemCount = 50;
}
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 );
}
}
}
// -----------------------------------------------------------------------------
// CFSEmailUiClsMatchObserver::SetInputModeL
// -----------------------------------------------------------------------------
void CFSEmailUiClsMatchObserver::SetInputMode( TKeyboardModes aInputMode )
{
FUNC_LOG;
iInputMode = aInputMode;
}
// -----------------------------------------------------------------------------
// CFSEmailUiClsMatchObserver::HandleMatchComplete
// -----------------------------------------------------------------------------
void CFSEmailUiClsMatchObserver::HandlePsResultsUpdate(
RPointerArray<CPsClientData>& aSearchResults,
RPointerArray<CPsPattern>& searchSeqs )
{
FUNC_LOG;
TRAP_IGNORE( HandlePsResultsUpdateL( aSearchResults, searchSeqs) );
}
// -----------------------------------------------------------------------------
// CFSEmailUiClsMatchObserver::HandleMatchComplete
// -----------------------------------------------------------------------------
void CFSEmailUiClsMatchObserver::HandlePsResultsUpdateL(
RPointerArray<CPsClientData>& aSearchResults,
RPointerArray<CPsPattern>& aSearchSeqs )
{
FUNC_LOG;
RPointerArray<CFSEmailUiClsItem> contacts;
CleanupResetAndDestroyClosePushL( contacts );
CleanupResetAndDestroyClosePushL( aSearchResults );
CleanupResetAndDestroyClosePushL( aSearchSeqs );
// Iterate through all or maximum number of search results
CFreestyleEmailUiAppUi* appUi =
static_cast<CFreestyleEmailUiAppUi*>( CCoeEnv::Static()->AppUi() );
TInt maxPcsMatches = appUi->LayoutHandler()->MaxPcsMatches();
for ( TInt counter = 0 ; counter < aSearchResults.Count() && counter < maxPcsMatches ; counter++ )
{
// Get search result
CPsClientData* result = aSearchResults[counter];
// Get the order of the data fields in result
RArray<TInt> dataOrder;
CleanupClosePushL( dataOrder );
iRequestHandler->GetDataOrderL( *( result->Uri() ), dataOrder );
TPtrC firstname( KNullDesC );
TPtrC lastname( KNullDesC );
RArray<TPtrC> emailFields;
CleanupClosePushL( 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.Set( *(result->Data(dataField)) );
break;
case R_VPBK_FIELD_TYPE_LASTNAME:
lastname.Set( *(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 )
{
TPtrC email( *result->Data( dataField ) );
ChopEmailEntriesList(email, emailFields);
}
}
}
break;
}
}
TDesC& sourceUri = *( result->Uri() );
TBool isMruItem = sourceUri.Find( KDefaultMailBoxURI ) != KErrNotFound;
MVPbkContactLink* contactLink = NULL;
if ( !isMruItem )
{
contactLink = iRequestHandler->ConvertToVpbkLinkLC( *result, *iContactManager );
CleanupStack::Pop( contactLink );
}
HBufC* displayname;
// 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(10);
CleanupStack::PushL( matchSet );
// Create display name, this will be used in UI.
displayname = TFsEmailUiUtility::CreateDisplayNameLC(
firstname, lastname, KNullDesC, iListHandler.UseLastNameFirstOrder() );
RArray<TPsMatchLocation> matchLocation;
CleanupClosePushL( matchLocation );
iRequestHandler->LookupL( *iQuery, *displayname, *matchSet, matchLocation );
// Create contact item and set highlighting for it
CFSEmailUiClsItem* contactItem = CFSEmailUiClsItem::NewLC();
contactItem->SetDisplayNameL( *displayname );
contactItem->SetHighlights( 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. If the
// contact does not contain either firstname nor lastname,
// the displayname is left empty.
displayname = TFsEmailUiUtility::CreateDisplayNameLC(
firstname, lastname, iListHandler.UseLastNameFirstOrder() );
// Create match text field, containing display field and email address
HBufC* matchText = HBufC::NewLC( displayname->Length() +
KSpace().Length() +
emailFields[fieldIndex].Length() );
//This condition is for checking if there is no display name like in the case of MRU and therefore
//we dont need to add displayname + KSpace(unnnecessary space) which is causing problem in drawing Underline
if (displayname->Length() > 0)
{
matchText->Des().Copy( *displayname );
matchText->Des().Append( KSpace );
}
matchText->Des().Append( emailFields[fieldIndex] );
// Use Ps engine to check if the text matches the search query
CDesCArray* matchSet = new (ELeave) CDesCArrayFlat(10);
CleanupStack::PushL( matchSet );
RArray<TPsMatchLocation> matchLocation;
CleanupClosePushL( matchLocation );
iRequestHandler->LookupL( *iQuery, *matchText, *matchSet, matchLocation );
if ( matchLocation.Count() > 0 )
{
// Create contact item and set highlighting for it
CFSEmailUiClsItem* contactItem = CFSEmailUiClsItem::NewLC();
contactItem->SetDisplayNameL( *displayname );
contactItem->SetIsMruItem( isMruItem );
contactItem->SetEmailAddressL( emailFields[fieldIndex] );
contactItem->SetHighlights( matchLocation );
if ( contactLink )
{
contactItem->SetContactLinkL( *contactLink );
}
if ( emailFields.Count() > 1 )
{
contactItem->SetMultipleEmails( ETrue );
}
contacts.AppendL( contactItem );
CleanupStack::Pop( contactItem );
}
CleanupStack::PopAndDestroy( &matchLocation );
CleanupStack::PopAndDestroy( matchSet );
CleanupStack::PopAndDestroy( matchText );
CleanupStack::PopAndDestroy( displayname );
}
}
if ( !isMruItem )
{
delete contactLink;
}
// Close arrays
CleanupStack::PopAndDestroy( &emailFields );
CleanupStack::PopAndDestroy( &dataOrder );
}
iListHandler.UpdateContactMatchListsL( contacts );
CleanupStack::PopAndDestroy( &aSearchSeqs );
CleanupStack::PopAndDestroy( &aSearchResults );
CleanupStack::PopAndDestroy( &contacts );
}
void CFSEmailUiClsMatchObserver::HandlePsError(TInt aErrorCode)
{
FUNC_LOG;
TRAP_IGNORE( iListHandler.OperationErrorL( aErrorCode ) );
}
void CFSEmailUiClsMatchObserver::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 ) );
}
// -----------------------------------------------------------------------------
// CFSEmailUiClsMatchObserver::IsCurrentInputModePredictive
// -----------------------------------------------------------------------------
TKeyboardModes CFSEmailUiClsMatchObserver::GetInputMode()
{
FUNC_LOG;
TInt repVal = 0;
// 1 = predictive, 0 = non predictive
iAknFepCenRep.Get( KAknFepPredTxtFlag, repVal );
//If true, EItut (predictive)
if( repVal == 0 )
{
return EQwerty;
}
return EItut;
}
TInt CFSEmailUiClsMatchObserver::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;
}
// -----------------------------------------------------------------------------
// CFSEmailUiClsMatchObserver::ChopEmailEntriesList
// -----------------------------------------------------------------------------
void CFSEmailUiClsMatchObserver::ChopEmailEntriesList(TPtrC & aEmail, RArray<
TPtrC> & aEmailFields)
{
FUNC_LOG;
const TInt KUnitSeparator = 31;
TInt prevSeparatorIndex = 0;
TInt nextSeparatorIndex = aEmail.Locate( KUnitSeparator );
// check if there are more than one email entry
if ( nextSeparatorIndex == KErrNotFound )
{
aEmailFields.Append( aEmail ); //one entry only
}
else //more then one entry
{
// loop through all but last email entries
while ( nextSeparatorIndex != KErrNotFound )
{
// First entry needs a separate handling
if ( prevSeparatorIndex == 0 )
{
// -1 because there is a space before a separator character
TPtrC entry = aEmail.Mid( 0, nextSeparatorIndex - 1 );
aEmailFields.Append( entry );
}
else //Append the next entry
{
nextSeparatorIndex = nextSeparatorIndex + 1 + prevSeparatorIndex;
TInt length = nextSeparatorIndex - prevSeparatorIndex - 1;
// +2 and -2 because there are a spaces before and after a separator character
TPtrC entry = aEmail.Mid(prevSeparatorIndex + 2, //starting pos
length - 2); //length
aEmailFields.Append(entry);
}
// Take the part of the list skiping the entries already appended
TPtrC nextEntry = aEmail.Mid(nextSeparatorIndex + 1);
prevSeparatorIndex = nextSeparatorIndex;
nextSeparatorIndex = nextEntry.Locate(KUnitSeparator);
}
// the last element does not contain the separator so it needs to be taken here
if (nextSeparatorIndex == KErrNotFound && aEmail.Mid(prevSeparatorIndex + 1).Length() > 1)
{
aEmailFields.Append(aEmail.Mid(prevSeparatorIndex + 2));
}
}
}