phonebookui/Phonebook2/remotecontactlookup/contactactionservice/src/CFscAddressSelect.cpp
changeset 0 e686773b3f54
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookui/Phonebook2/remotecontactlookup/contactactionservice/src/CFscAddressSelect.cpp	Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,620 @@
+/*
+* 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
+