phonebookui/Phonebook2/remotecontactlookup/contactactionservice/src/CFscAddressSelect.cpp
/*
* Copyright (c) 2008 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: Implementation of the class CFscAddressSelect.
*
*/
#include "emailtrace.h"
#include "CFscAddressSelect.h"
// Phonebook 2
#include "CFscSelectFieldDlg.h"
#include "MFscControlKeyObserver.h"
#include <MPbk2ContactNameFormatter.h>
#include "CFscFieldPropertyArray.h"
#include "TFscAddressSelectParams.h"
#include <MPbk2ApplicationServices.h>
#include <MPbk2AppUi.h>
// Virtual Phonebook
#include <CVPbkFieldFilter.h>
#include <MVPbkStoreContactField.h>
#include <MVPbkStoreContact.h>
#include <CVPbkFieldTypeSelector.h>
#include <MVPbkContactFieldData.h>
#include <MVPbkStoreContactFieldCollection.h>
#include <CVPbkContactManager.h>
#include <CVPbkDefaultAttribute.h>
// System includes
#include <avkon.hrh>
#include <aknnotewrappers.h>
#include <StringLoader.h>
#include <CVPbkContactManager.h>
/// Unnamed namespace for local definitions
namespace
{
#ifdef _DEBUG
enum TPanicCode
{
EPanicPostCond_Constructor = 1,
EPanicPreCond_ExecuteLD
};
static void Panic(TPanicCode aReason)
{
_LIT(KPanicText, "CPbk2AddressSelect");
User::Panic(KPanicText, aReason);
}
#endif // _DEBUG
const TInt KFirstField = 0;
const TInt KDefaultTitleFormat = MPbk2ContactNameFormatter::EUseSeparator;
/**
* Returns index of given field in store contact field collection.
*
* @param aCollection Store contact field collection.
* @param aField Store contact field to search for.
* @return Index of the given field.
*/
inline TInt IndexOfField(
const MVPbkStoreContactFieldCollection& aCollection,
const MVPbkStoreContactField& aField)
{
TInt ret = KErrNotFound;
const TInt count = aCollection.FieldCount();
for (TInt i = 0; i < count; ++i)
{
MVPbkStoreContactField* field = aCollection.FieldAtLC(i);
if (aField.IsSame( *field) )
{
ret = i;
CleanupStack::PopAndDestroy(); // field
break;
}
CleanupStack::PopAndDestroy(); // field
}
return ret;
}
} /// namespace
// MODULE DATA STRUCTURES
/**
* Special field selection dialog class for CFscAddressSelect.
* The main purpose of this class is to
* get #include of MFscControlKeyObserver
* away from public header cfscaddressselect.h.
*/
NONSHARABLE_CLASS(CFscAddressSelect::CSelectFieldDlg) :
public CFscSelectFieldDlg,
private MFscControlKeyObserver
{
public: // Construction
/**
* Constructor.
*
* @param aParent Parent.
*/
CSelectFieldDlg( CFscAddressSelect& aParent ) :
iParent( aParent )
{
SetObserver( this );
}
private: // From MFscControlKeyObserver
TKeyResponse FscControlKeyEventL
( const TKeyEvent& aKeyEvent, TEventCode aType );
private: // Data
/// Ref: Parent
CFscAddressSelect& iParent;
};
// --------------------------------------------------------------------------
// CFscAddressSelect::CSelectFieldDlg::FscControlKeyEventL
// --------------------------------------------------------------------------
//
TKeyResponse CFscAddressSelect::CSelectFieldDlg::FscControlKeyEventL(
const TKeyEvent& aKeyEvent, TEventCode aType)
{
FUNC_LOG;
// Forward call to virtual function in CFscAddressSelect interface
return iParent.FscControlKeyEventL(aKeyEvent, aType);
}
// --------------------------------------------------------------------------
// CFscAddressSelect::CFscAddressSelect
// --------------------------------------------------------------------------
//
CFscAddressSelect::CFscAddressSelect(TFscAddressSelectParams& aParams) :
iParams(aParams)
{
FUNC_LOG;
__ASSERT_DEBUG
( !iFieldDlg && !iDestroyedPtr,
Panic( EPanicPostCond_Constructor ) );
}
// --------------------------------------------------------------------------
// CFscAddressSelect::~CFscAddressSelect
// --------------------------------------------------------------------------
//
CFscAddressSelect::~CFscAddressSelect()
{
FUNC_LOG;
// Tell ExecuteLD this object is already destroyed
if (iDestroyedPtr)
{
*iDestroyedPtr = ETrue;
}
// Set eliminator pointer to NULL
if (iSelfPtr)
{
*iSelfPtr = NULL;
}
delete iFieldDlg;
delete iFieldFilter;
delete iFieldTypeSelector;
}
// --------------------------------------------------------------------------
// CFscAddressSelect::NewL
// --------------------------------------------------------------------------
//
CFscAddressSelect* CFscAddressSelect::NewL
( TFscAddressSelectParams& aParams )
{
FUNC_LOG;
CFscAddressSelect* self = new ( ELeave ) CFscAddressSelect( aParams );
CleanupStack::PushL( self );
self->ConstructL();
CleanupStack::Pop( self );
return self;
}
// --------------------------------------------------------------------------
// CFscAddressSelect::ConstructL
// --------------------------------------------------------------------------
//
void CFscAddressSelect::ConstructL()
{
FUNC_LOG;
// Read the resource referenced in address select resource struct
const TInt fieldTypeSelectorRes = iParams.iResReader.ReadInt32();
TResourceReader selectorReader;
CCoeEnv::Static()->CreateResourceReaderLC(selectorReader, fieldTypeSelectorRes);
// Give that resource reader to the field type selector
iFieldTypeSelector = CVPbkFieldTypeSelector::NewL(selectorReader,
iParams.iContactManager.FieldTypes() );
CleanupStack::PopAndDestroy(); // selectorReader
iNoAddressesForNamePromptResource = iParams.iResReader.ReadInt32();
iNoAddressesPromptResource = iParams.iResReader.ReadInt32();
iSoftKeyResource = iParams.iResReader.ReadInt32();
const CVPbkFieldFilter::TConfig
config(
const_cast<MVPbkStoreContactFieldCollection&> (iParams.iContact.Fields() ),
iFieldTypeSelector, NULL);
iFieldFilter = CVPbkFieldFilter::NewL(config);
CVPbkContactManager& iContactManager =
const_cast<CVPbkContactManager&>(iParams.iContactManager);
iAttributeManager = &iContactManager.ContactAttributeManagerL();
}
// --------------------------------------------------------------------------
// CFscAddressSelect::ExecuteLD
// --------------------------------------------------------------------------
//
MVPbkStoreContactField* CFscAddressSelect::ExecuteLD()
{
FUNC_LOG;
__ASSERT_DEBUG( !iFieldDlg, Panic( EPanicPreCond_ExecuteLD ) );
// "D" function semantics
CleanupStack::PushL( this );
TBool thisDestroyed = EFalse;
// Ensure that thisDestroyed will be ETrue if this object is destroyed.
// See in destructor how this is done.
iDestroyedPtr = &thisDestroyed;
SelectFieldL();
MVPbkStoreContactField* returnedField = NULL;
if ( iSelectedField )
{
// We cannot return iSelectedField directly since if its NULL,
// it's value changes to 0xdedede before it is returned.
// Therefore we must test iSelectedField before assigning it
// to returnedField.
returnedField = iSelectedField;
}
if ( thisDestroyed )
{
// This object has already been destroyed
CleanupStack::Pop( this );
returnedField = NULL;
}
else
{
CleanupStack::PopAndDestroy( this );
}
return returnedField;
}
// --------------------------------------------------------------------------
// CFscAddressSelect::AttemptExitL
// --------------------------------------------------------------------------
//
void CFscAddressSelect::AttemptExitL(TBool aAccept)
{
FUNC_LOG;
if (iFieldDlg)
{
iFieldDlg->AttemptExitL(aAccept);
}
}
// --------------------------------------------------------------------------
// CFscAddressSelect::FscControlKeyEventL
// --------------------------------------------------------------------------
//
TKeyResponse CFscAddressSelect::FscControlKeyEventL
( const TKeyEvent& aKeyEvent, TEventCode aType )
{
FUNC_LOG;
TKeyResponse ret = EKeyWasNotConsumed;
if ( aType == EEventKey && aKeyEvent.iCode == EKeyPhoneSend )
{
// Event is Send key, tell field selection dialog to accept
// current selection
AttemptExitL( ETrue );
ret = EKeyWasConsumed;
}
else
if ( aType == EEventKey && aKeyEvent.iCode == EKeyPhoneEnd )
{
ForceExit();
ret = EKeyWasConsumed;
}
return ret;
}
// --------------------------------------------------------------------------
// CFscAddressSelect::RequestExitL
// --------------------------------------------------------------------------
//
void CFscAddressSelect::RequestExitL(TInt aCommandId)
{
FUNC_LOG;
if (aCommandId == EEikBidCancel)
{
AttemptExitL(EFalse);
}
else
if (aCommandId == EEikBidOk)
{
AttemptExitL(ETrue);
}
}
// --------------------------------------------------------------------------
// CFscAddressSelect::ForceExit
// --------------------------------------------------------------------------
//
void CFscAddressSelect::ForceExit()
{
FUNC_LOG;
TRAPD( err, AttemptExitL( EFalse ) )
;
if (err != KErrNone)
{
// If not nicely then use the force
delete this;
}
}
// --------------------------------------------------------------------------
// CFscAddressSelect::ResetWhenDestroyed
// --------------------------------------------------------------------------
//
void CFscAddressSelect::ResetWhenDestroyed(MFscDialogEliminator** aSelfPtr)
{
FUNC_LOG;
iSelfPtr = aSelfPtr;
}
// --------------------------------------------------------------------------
// CFscAddressSelect::AddressField
// Returns true if aField is an applicable address field.
// --------------------------------------------------------------------------
//
TBool CFscAddressSelect::AddressField(const MVPbkStoreContactField& aField) const
{
FUNC_LOG;
TBool ret = EFalse;
// Return true if field belongs to the selector
ret = (iFieldFilter->FindField(aField) == KErrNotFound ) ? EFalse : ETrue;
return ret;
}
// --------------------------------------------------------------------------
// CFscAddressSelect::NoAddressesL
// Called if there are no applicable address fields in a contact passed
// to ExecuteLD.
// --------------------------------------------------------------------------
//
void CFscAddressSelect::NoAddressesL(TFscAddressSelectParams aParams) const
{
FUNC_LOG;
if ( !aParams.iSuppressWarnings)
{
HBufC* prompt= NULL;
HBufC* name = aParams.iNameFormatter.GetContactTitleOrNullL(
iParams.iContact.Fields(), KDefaultTitleFormat);
if (name)
{
CleanupStack::PushL(name);
prompt = StringLoader::LoadL(iNoAddressesForNamePromptResource,
*name);
CleanupStack::PopAndDestroy(); // name
}
else
{
prompt = StringLoader::LoadL(iNoAddressesPromptResource);
}
if (prompt)
{
CleanupStack::PushL(prompt);
// This is a waiting dialog because the address select might be
// used from the application server and the information note will
// disappear if the application server closes before the
// note timeout has expired, thus causing blinking
CAknInformationNote* noteDlg = new ( ELeave ) CAknInformationNote( ETrue );
noteDlg->ExecuteLD( *prompt);
CleanupStack::PopAndDestroy(); // prompt
}
}
}
// --------------------------------------------------------------------------
// CFscAddressSelect::SelectFieldL
// --------------------------------------------------------------------------
//
inline void CFscAddressSelect::SelectFieldL()
{
FUNC_LOG;
// If currently focused field is an applicable field
if (iParams.iFocusedField && AddressField( *iParams.iFocusedField) )
{
// Applicable field was focused -> return field
SetSelectedFieldL(iParams.iFocusedField);
}
else
{
TBool found = EFalse;
// Focus is in on some other field, first check default field
if (iParams.iDefaultPriorities && iParams.iUseDefaultDirectly
&& iParams.iDefaultPriorities->Count() > 0)
{
found = SelectFromDefaultFieldsL();
}
if ( !found)
{
// No direct call to focused or default number, we have to
// select from applicable fields
SelectFromApplicableFieldsL();
}
}
}
// --------------------------------------------------------------------------
// CFscAddressSelect::SelectFromApplicableFieldsL
// --------------------------------------------------------------------------
//
inline void CFscAddressSelect::SelectFromApplicableFieldsL()
{
FUNC_LOG;
TInt indexOfDefault = IndexOfDefaultFieldL();
const TInt fieldCount = iFieldFilter->FieldCount();
// Different actions for different number of applicable fields found
if (fieldCount == 0)
{
// No applicable addresses found
NoAddressesL(iParams);
}
else
if (fieldCount == 1)
{
// Exactly one applicable address found, just return it
SetSelectedFieldL( &iFieldFilter->FieldAt(KFirstField) );
}
else
if (fieldCount > 1)
{
HBufC* entryTitle = iParams.iNameFormatter.GetContactTitleL(
iParams.iContact.Fields(), KDefaultTitleFormat);
CleanupStack::PushL(entryTitle);
HBufC* title= NULL;
if (iParams.iTitleResId)
{
if (iParams.iIncludeContactNameInPrompt)
{
title = StringLoader::LoadL(iParams.iTitleResId,
*entryTitle);
}
else
{
title = StringLoader::LoadL(iParams.iTitleResId);
}
CleanupStack::PopAndDestroy(entryTitle);
}
else
{
title = entryTitle; // takes ownership of entryTitle
CleanupStack::Pop(entryTitle);
entryTitle = NULL;
}
// Run the address selection dialog
CleanupStack::PushL(title);
iFieldDlg = new ( ELeave ) CSelectFieldDlg( *this );
iFieldDlg->ResetWhenDestroyed( &iFieldDlg);
MVPbkStoreContactField* field= NULL;
field = iFieldDlg->ExecuteLD( *iFieldFilter,
iParams.iContactManager, iParams.iFieldPropertyArray,
iSoftKeyResource, *title, indexOfDefault);
CleanupDeletePushL( field );
SetSelectedFieldL(field);
CleanupStack::PopAndDestroy( 2); // field, title
}
}
// --------------------------------------------------------------------------
// CFscAddressSelect::IndexOfDefaultFieldL
// --------------------------------------------------------------------------
//
inline TInt CFscAddressSelect::IndexOfDefaultFieldL()
{
FUNC_LOG;
TInt ret = KErrNotFound;
const MVPbkStoreContactField* field = FindDefaultFieldLC();
if (field)
{
ret = iFieldFilter->FindField( *field);
}
CleanupStack::PopAndDestroy(); // field
return ret;
}
// --------------------------------------------------------------------------
// CFscAddressSelect::SelectFromDefaultFieldsL
// --------------------------------------------------------------------------
//
inline TBool CFscAddressSelect::SelectFromDefaultFieldsL()
{
FUNC_LOG;
TBool found = EFalse;
const MVPbkStoreContactField* field = FindDefaultFieldLC();
if (field)
{
SetSelectedFieldL(field);
found = ETrue;
}
CleanupStack::PopAndDestroy(); // field
return found;
}
// --------------------------------------------------------------------------
// CFscAddressSelect::FindDefaultFieldLC
// --------------------------------------------------------------------------
//
MVPbkStoreContactField* CFscAddressSelect::FindDefaultFieldLC()
{
FUNC_LOG;
MVPbkStoreContactField* ret= NULL;
// Go through the default priorities array, and
// check does a specific default exist
if (iParams.iDefaultPriorities)
{
const TInt defaultCount = iParams.iDefaultPriorities->Count();
for (TInt i=0; i<defaultCount; ++i)
{
TVPbkDefaultType defaultType =
(TVPbkDefaultType) iParams.iDefaultPriorities->At(i);
// Create an attribute prototype out of the attribute identifier
CVPbkDefaultAttribute* attr =
CVPbkDefaultAttribute::NewL(defaultType);
CleanupStack::PushL(attr);
if (iAttributeManager->HasContactAttributeL( *attr,
iParams.iContact) )
{
const MVPbkStoreContactFieldCollection& fields =
iParams.iContact.Fields();
// Get the field with attribute
const TInt fieldCount = fields.FieldCount();
for (TInt j = 0; j < fieldCount; ++j)
{
if (iAttributeManager->HasFieldAttributeL( *attr,
fields.FieldAt(j) ) )
{
ret = fields.FieldAtLC(j);
CleanupStack::Pop(); // ret
break;
}
}
}
CleanupStack::PopAndDestroy(attr);
}
}
CleanupDeletePushL(ret);
return ret;
}
// --------------------------------------------------------------------------
// CFscAddressSelect::SetSelectedFieldL
// --------------------------------------------------------------------------
//
inline void CFscAddressSelect::SetSelectedFieldL(
const MVPbkStoreContactField* aField)
{
FUNC_LOG;
if (aField)
{
const MVPbkStoreContactFieldCollection& fields =
iParams.iContact.Fields();
TInt index = IndexOfField(fields, *aField);
iSelectedField = fields.FieldAtLC(index);
CleanupStack::Pop();
}
}
// End of File