phonebookui/Phonebook/View/src/CPbkDataSaveAppUi.cpp
changeset 0 e686773b3f54
child 68 9da50d567e3c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookui/Phonebook/View/src/CPbkDataSaveAppUi.cpp	Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,899 @@
+/*
+* Copyright (c) 2002 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: 
+*       Provides methods for Phonebook Data Save service helper.
+*
+*/
+
+
+// INCLUDE FILES
+#include "CPbkDataSaveAppUi.h"
+#include <cntfldst.h>
+#include <eikmenup.h>
+#include <avkon.rsg>
+
+// PbkView include files
+#include "PbkDataSaveAppUi.hrh"
+#include <PbkView.rsg>
+#include "CPbkContactEditorDlg.h"
+#include "CPbkSingleEntryFetchDlg.h"
+#include "CPbkMemoryEntryAddItemDlg.h"
+#include <CPbkFFSCheck.h>
+
+// PbkExt include files
+#include <CPbkExtGlobals.h>
+
+// PbkEng include files
+#include <CPbkContactEngine.h>
+#include <CPbkContactItem.h>
+#include <CPbkFieldInfo.h>
+
+
+/// Unnamed namespace for local definitions
+namespace {
+
+// LOCAL CONSTANTS AND MACROS
+#ifdef _DEBUG
+enum TPanicCode
+    {
+    EPanicPreCond_CTextFieldData_AddFieldL = 1,
+    EPanicPreCond_CDateFieldData_AddFieldL,
+    EPanicPreCond_DoHandleCommandL,
+    EPanicPreCond_ResetWhenDestroyed,
+    EPanicPreCond_SelectFieldTypeL,
+    EPanicPreCond_EditContactL,
+    EPanicPreCond_GetContactItemL,
+    EPanicPreCond_ExecuteLD
+    };
+#endif
+
+/**
+ * Flags for CPbkDataSaveAppUi.
+ */
+enum TFlags
+    {
+    EFlagsHideEditorExit = 0x00000001
+    };
+
+
+// ==================== LOCAL FUNCTIONS ====================
+
+#ifdef _DEBUG
+void Panic(TPanicCode aReason)
+    {
+    _LIT(KPanicText, "CPbkDataSaveAppUi");
+    User::Panic(KPanicText, aReason);
+    }
+#endif
+
+
+}  // namespace
+
+
+// MODULE DATA STRUCTURES
+
+/**
+ * Field adder strategy class for CPbkDataSaveAppUi implementation.
+ * Encapsulates the data to be added to the contact.
+ */
+class CPbkDataSaveAppUi::MFieldData
+    {
+    public:
+        /**
+         * Virtual destructor.
+         */
+        virtual ~MFieldData() { }
+
+        /**
+         * Returns the storage type of data to be added.
+         */
+        virtual TUint StorageType() const = 0;
+
+        /**
+         * Adds a field with data encapsulated in this class in to a contact.
+         *
+         * @param aContact  contact where the field and data is to be added.
+         * @param aFieldType    type of the field to add. 
+         * @param aCallback     calls back to this object if there are 
+         *                      problems when adding the field.
+         * @return  the added field containing data, NULL if field couldn't be
+         *          added.
+         * @precond aFieldType.FieldStorageType()==this->StorageType()
+         */
+        virtual TPbkContactItemField* AddFieldL
+            (CPbkContactItem& aContact, 
+            CPbkFieldInfo& aFieldType,
+            MPbkDataSaveCallback* aCallback) = 0;
+
+    };
+
+/**
+ * Text field data implementation.
+ */
+NONSHARABLE_CLASS(CPbkDataSaveAppUi::CTextFieldData) : 
+        public CBase, 
+        public CPbkDataSaveAppUi::MFieldData
+    {
+    public:
+        static CTextFieldData* NewLC(const TDesC& aText);
+        ~CTextFieldData();
+
+    public:  // from MFieldData
+        TUint StorageType() const;
+        TPbkContactItemField* AddFieldL
+            (CPbkContactItem& aContact, 
+            CPbkFieldInfo& aFieldType,
+            MPbkDataSaveCallback* aCallback);
+
+    private:  // Implementation
+        CTextFieldData();
+
+    private:  // Data
+        /// Own: text data
+        HBufC* iText;
+    };
+
+/**
+ * Date field data implementation.
+ */
+NONSHARABLE_CLASS(CPbkDataSaveAppUi::CDateFieldData) : 
+        public CBase, 
+        public CPbkDataSaveAppUi::MFieldData
+    {
+    public:
+        static CDateFieldData* NewLC(const TTime& aText);
+
+    public:  // from MFieldData
+        TUint StorageType() const;
+        TPbkContactItemField* AddFieldL
+            (CPbkContactItem& aContact, 
+            CPbkFieldInfo& aFieldType,
+            MPbkDataSaveCallback* aCallback);
+
+    private:  // Implementation
+        CDateFieldData();
+
+    private:  // Data
+        /// Own: date data
+        TTime iDate;
+    };
+
+/**
+ * Command base class for CPbkDataSaveAppUi::HandleCommandL implementation.
+ */
+NONSHARABLE_CLASS(CPbkDataSaveAppUi::CCommandBase) : 
+        public CBase
+    {
+    public:  // Interface
+        /**
+         * Command intialisation data.
+         */
+        struct TData
+            {
+            /// Own: the command id to execute
+            TInt iCommandId;
+            /// Ref: Phonebook engine
+            CPbkContactEngine* iEngine;
+            /// Ref: field types to apply
+            CArrayPtr<CPbkFieldInfo>* iFieldTypes;
+            /// Ref: field data to save
+            MFieldData* iFieldData;
+            /// Ref: callback interface
+            MPbkDataSaveCallback* iCallback;
+            /// Own: copy of CPbkDataSaveAppUi's flags
+            TUint iFlags;
+            };
+
+        /**
+         * Resets aSelfPtr to NULL when this object is destroyed.
+         * @precond !aSelfPtr || *aSelfPtr==this
+         */
+        void ResetWhenDestroyed(CCommandBase** aSelfPtr);
+
+        /**
+         * Executes this command
+         */
+        TBool ExecuteLD();
+
+        /**
+         * Destructor.
+         */
+        ~CCommandBase();
+
+    protected:  // Interface
+        /**
+         * Constructor.
+         */
+        CCommandBase();
+
+        /**
+         * Creates/Reads the contact item where to add data.
+         */
+        virtual CPbkContactItem* GetContactItemL() = 0;
+
+        /**
+         * Creates the field type dialog to use in SelectFieldTypeL.
+         */
+        virtual CPbkMemoryEntryAddItemDlg* CreateFieldTypeDialogL() = 0;
+
+        /**
+         * Selects field type.
+         * @param aFieldTypes   types where to select from.
+         * @return selected field type or NULL if canceled or nothing to select.
+         */
+        CPbkFieldInfo* SelectFieldTypeL(CArrayPtr<CPbkFieldInfo>& aFieldTypes);
+
+        /**
+         * Opens contact editor for a contact.
+         *
+         * @param aContact  contact to be edited.
+         * @param aField    field to focus intially in the editor.
+         * @return ETrue if contact was saved, EFalse otherwise.
+         */
+        TBool EditContactL
+            (CPbkContactItem& aContact, const TPbkContactItemField& aField);
+
+        /**
+         * Returns the index of the field to be focused in the contact editor
+         * dialog. Default implementation returns aField's index in aContact's
+         * field set.
+         */
+        virtual TInt FocusedFieldIndex
+            (CPbkContactItem& aContact,
+            const TPbkContactItemField& aField) const;
+
+        /**
+         * Returns ETrue if this command modfies a new contact, EFalse 
+         * otherwise.
+         */
+        virtual TBool NewContact() = 0;
+
+        /**
+         * Filters applicable field types according to what new fields the
+         * contact can accept and compabilty between field type and storage
+         * type.
+         *
+         * @param aContact  contact where the field is to be added.
+         * @param aFieldTypes   list of field types to be filtered.
+         * @param aStorageType  type of data to be added to the field.
+         * @return new filtered array of field types.
+         */
+        CArrayPtr<CPbkFieldInfo>* GetFilterFieldTypesLC
+            (const CPbkContactItem& aContact, 
+            CArrayPtr<CPbkFieldInfo>& aFieldTypes,
+            TUint aStorageType);
+
+        /**
+         * Returns true field type aFieldType should be included in selectable 
+         * types. Checks if the new field can be added to aContact and that the
+         * field type is compatible with aStorageType.
+         */
+        TBool FieldTypeIncluded
+            (CPbkFieldInfo& aFieldType,
+            const CPbkContactItem& aContact, 
+            TUint aStorageType);
+
+    protected:  // Data
+        /// Own: data
+        TData iData;
+
+    private: // Implementation
+        NONSHARABLE_CLASS(TSelfCleanup)
+            {
+            public:
+                inline TSelfCleanup(CCommandBase* aSelf) : iSelf(aSelf) 
+                    { 
+                    }
+                inline operator TCleanupItem()
+                    {
+                    return TCleanupItem(Cleanup,this);
+                    }
+                inline void Reset() { iSelf=NULL; }
+            private:
+                static void Cleanup(TAny* aObject);
+                CCommandBase* iSelf;
+            };
+
+    private:  // Data
+        /// Ref: referred pointer is set to NULL in destructor
+        CCommandBase** iSelfPtr;
+        /// Own: for cleanup purposes
+        TSelfCleanup* iSelfCleanup;
+        /// Own: iContactItem
+        CPbkContactItem* iContactItem;
+        /// Own: add item dialog
+        CPbkMemoryEntryAddItemDlg* iItemTypeDlg;
+        /// Own: editor dialog
+        CPbkContactEditorDlg* iEditDlg;
+    };
+
+/**
+ * Command implementation for Create New service.
+ */
+NONSHARABLE_CLASS(CPbkDataSaveAppUi::CCreateNewCommand) : 
+        public CPbkDataSaveAppUi::CCommandBase
+    {
+    public:  // Interface
+        static CCreateNewCommand* NewL(const TData& aData);
+
+    public:  // from CCommandBase
+        CPbkContactItem* GetContactItemL();
+        CPbkMemoryEntryAddItemDlg* CreateFieldTypeDialogL();
+        TInt FocusedFieldIndex
+            (CPbkContactItem& aContact,
+            const TPbkContactItemField& aField) const;
+        TBool NewContact();
+
+    private:  // Implementation
+        CCreateNewCommand();
+    };
+
+/**
+ * Command implementation for Add to Existing service.
+ */
+NONSHARABLE_CLASS(CPbkDataSaveAppUi::CAddToExistingCommand) : 
+        public CPbkDataSaveAppUi::CCommandBase
+    {
+    public:  // Interface
+        static CAddToExistingCommand* NewL(const TData& aData);
+        ~CAddToExistingCommand();
+
+    public:  // from CCommandBase
+        CPbkContactItem* GetContactItemL();
+        CPbkMemoryEntryAddItemDlg* CreateFieldTypeDialogL();
+        TBool NewContact();
+
+    private:  // Implementation
+        CAddToExistingCommand();
+
+    private:  // Data
+        /// Own: Active fetch dialog
+        CPbkSingleEntryFetchDlg* iFetchDlg;
+    };
+
+
+// ==================== MEMBER FUNCTIONS ====================
+
+////////////////////////////////////////////////////////////
+// CPbkDataSaveAppUi
+inline CPbkDataSaveAppUi::CPbkDataSaveAppUi(CPbkContactEngine& aEngine) :
+    iEngine(&aEngine),
+    iBaseCommandId(EPbkCmdDataSaveBase)
+    {
+    // CBase::operator new() will reset other members
+    }
+
+inline void CPbkDataSaveAppUi::ConstructL()
+    {
+    iFFSCheck = CPbkFFSCheck::NewL();
+
+    // Keep a handle to the UI extension factory in this dialog to prevent 
+    // multiple inits of the factory by the subdialogs that are launched by
+    // this service.
+    iExtGlobals = CPbkExtGlobals::InstanceL();
+    }
+
+EXPORT_C CPbkDataSaveAppUi* CPbkDataSaveAppUi::NewL
+        (CPbkContactEngine& aEngine)
+    {
+    CPbkDataSaveAppUi* self = new(ELeave) CPbkDataSaveAppUi(aEngine);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+CPbkDataSaveAppUi::~CPbkDataSaveAppUi()
+    {
+    delete iExecutingCommand;
+    Release(iExtGlobals);
+    delete iFFSCheck;
+    }
+
+EXPORT_C void CPbkDataSaveAppUi::AddMenuItemsL
+        (CEikMenuPane* aMenuPane, TInt aCommandId)
+    {
+    // Store base command id
+    iBaseCommandId = aCommandId;
+    // Store replaced menu item's position
+    TInt pos;
+    aMenuPane->ItemAndPos(aCommandId, pos);
+    // Add data save submenu after marker item
+    aMenuPane->AddMenuItemsL(R_PBK_DATA_SAVE_MENU, aCommandId);
+    // Delete marker item from the menu
+    aMenuPane->DeleteBetweenMenuItems(pos,pos);
+    }
+
+EXPORT_C void CPbkDataSaveAppUi::DynInitMenuPaneL(TInt aResourceId, CEikMenuPane* aMenuPane)
+    {
+    if (aResourceId == R_PBK_DATA_SAVE_SUBMENU)
+        {
+        // Patch command ids of the submenu to be relative to iBaseCommandId
+        CEikMenuPaneItem::SData& createNewItemData = 
+            aMenuPane->ItemData(EPbkCmdDataSaveCreateNew);
+        CEikMenuPaneItem::SData& addToExistingItemData =
+            aMenuPane->ItemData(EPbkCmdDataSaveAddToExisting); 
+        createNewItemData.iCommandId += iBaseCommandId;
+        addToExistingItemData.iCommandId += iBaseCommandId;
+        }
+    }
+
+EXPORT_C TBool CPbkDataSaveAppUi::HandleCommandL
+        (TInt aCommandId, 
+        CArrayPtr<CPbkFieldInfo>& aFieldTypes,
+        const TDesC& aText,
+        MPbkDataSaveCallback* aCallback/*=NULL*/)
+    {
+    TBool result = EFalse;
+    if (iFFSCheck->FFSClCheckL())
+        {
+        // Pack data into a MFieldData wrapper
+        CTextFieldData* fieldData = CTextFieldData::NewLC(aText);
+        result = DoHandleCommandL
+            (aCommandId, aFieldTypes, *fieldData, aCallback);
+        CleanupStack::PopAndDestroy();  // fieldData
+        }
+    return result;
+    }
+
+EXPORT_C void CPbkDataSaveAppUi::HideEditorExitCommand()
+    {
+    iFlags |= EFlagsHideEditorExit;
+    }
+
+EXPORT_C TBool CPbkDataSaveAppUi::HandleCommandL
+        (TInt aCommandId, 
+        CArrayPtr<CPbkFieldInfo>& aFieldTypes,
+        const TTime& aDate,
+        MPbkDataSaveCallback* aCallback/*=NULL*/)
+    {
+    TBool result = EFalse;
+    if (iFFSCheck->FFSClCheckL())
+        {
+        // Pack data into a MFieldData wrapper
+        CDateFieldData* fieldData = CDateFieldData::NewLC(aDate);
+        result = DoHandleCommandL
+            (aCommandId, aFieldTypes, *fieldData, aCallback);
+        CleanupStack::PopAndDestroy();  // fieldData
+        }
+    return result;
+    }
+
+TBool CPbkDataSaveAppUi::DoHandleCommandL
+        (TInt aCommandId, 
+        CArrayPtr<CPbkFieldInfo>& aFieldTypes,
+        MFieldData& aFieldData,
+        MPbkDataSaveCallback* aCallback)
+    {
+    // Create command object parameter data
+    __ASSERT_DEBUG(!iExecutingCommand, Panic(EPanicPreCond_DoHandleCommandL));
+
+    CCommandBase::TData cmdData;
+    cmdData.iCommandId = aCommandId-iBaseCommandId;
+    cmdData.iEngine = iEngine;
+    cmdData.iFieldTypes = &aFieldTypes;
+    cmdData.iFieldData = &aFieldData;
+    cmdData.iFlags = iFlags;
+
+    // Default callback object
+    MPbkDataSaveCallback defaultCallback;
+    if (aCallback)
+        {
+        cmdData.iCallback = aCallback;
+        }
+    else
+        {
+        cmdData.iCallback = &defaultCallback;
+        }
+
+    // Create a command object
+    TBool result = EFalse;
+    switch (cmdData.iCommandId)
+        {
+        case EPbkCmdDataSaveCreateNew:
+            {
+            iExecutingCommand = CCreateNewCommand::NewL(cmdData);
+            break;
+            }
+        case EPbkCmdDataSaveAddToExisting:
+            {
+            iExecutingCommand = CAddToExistingCommand::NewL(cmdData);
+            break;
+            }
+        }
+
+    if (iExecutingCommand)
+        {
+        iExecutingCommand->ResetWhenDestroyed(&iExecutingCommand);
+        result = iExecutingCommand->ExecuteLD();
+        }
+
+    return result;
+    }
+
+
+////////////////////////////////////////////////////////////
+// CPbkDataSaveAppUi::CTextFieldData
+
+inline CPbkDataSaveAppUi::CTextFieldData::CTextFieldData()
+    {
+    // operator new(TLeave) resets member data
+    }
+
+CPbkDataSaveAppUi::CTextFieldData* CPbkDataSaveAppUi::CTextFieldData::NewLC
+        (const TDesC& aText)
+    {
+    CTextFieldData* self = new(ELeave) CTextFieldData;
+    CleanupStack::PushL(self);
+    self->iText = aText.AllocL();
+    return self;
+    }
+
+CPbkDataSaveAppUi::CTextFieldData::~CTextFieldData()
+    {
+    delete iText;
+    }
+
+TUint CPbkDataSaveAppUi::CTextFieldData::StorageType() const
+    {
+    return KStorageTypeText;
+    }
+
+TPbkContactItemField* CPbkDataSaveAppUi::CTextFieldData::AddFieldL
+        (CPbkContactItem& aContact, 
+        CPbkFieldInfo& aFieldInfo,
+        MPbkDataSaveCallback* aCallback)
+    {
+    __ASSERT_DEBUG(aFieldInfo.FieldStorageType() == StorageType(), 
+        Panic(EPanicPreCond_CTextFieldData_AddFieldL));
+
+    TPtrC text = *iText;
+    if (text.Length() > aFieldInfo.MaxLength())
+        {
+        if (aCallback)
+            {
+            text.Set(aCallback->PbkDataSaveClipTextL(*iText, aFieldInfo));
+            // Give up if text is still too long
+            if (text.Length() > aFieldInfo.MaxLength())
+                {
+                User::Leave(KErrOverflow);
+                }
+            }
+        else
+            {
+            text.Set(iText->Left(aFieldInfo.MaxLength()));
+            }
+        }
+
+    // Don't add an empty field
+    if (text.Length() == 0)
+        {
+        return NULL;
+        }
+
+    // Add field and text into it leave-safely
+    HBufC* textBuf = text.AllocLC();
+    TPbkContactItemField* field = aContact.AddOrReturnUnusedFieldL(aFieldInfo);
+    CleanupStack::Pop();  // textBuf
+    field->TextStorage()->SetText(textBuf);
+    return field;
+    }
+
+
+////////////////////////////////////////////////////////////
+// CPbkDataSaveAppUi::CDateFieldData
+
+inline CPbkDataSaveAppUi::CDateFieldData::CDateFieldData()
+    {
+    // operator new(TLeave) resets member data
+    }
+
+CPbkDataSaveAppUi::CDateFieldData* CPbkDataSaveAppUi::CDateFieldData::NewLC
+        (const TTime& aDate)
+    {
+    CDateFieldData* self = new(ELeave) CDateFieldData;
+    CleanupStack::PushL(self);
+    self->iDate = aDate;
+    return self;
+    }
+
+TUint CPbkDataSaveAppUi::CDateFieldData::StorageType() const
+    {
+    return KStorageTypeDateTime;
+    }
+
+TPbkContactItemField* CPbkDataSaveAppUi::CDateFieldData::AddFieldL
+        (CPbkContactItem& aContact, 
+        CPbkFieldInfo& aFieldInfo,
+        MPbkDataSaveCallback* /*aCallback*/)
+    {
+    __ASSERT_DEBUG(aFieldInfo.FieldStorageType() == StorageType(), 
+        Panic(EPanicPreCond_CDateFieldData_AddFieldL));
+    TPbkContactItemField* field = aContact.AddOrReturnUnusedFieldL(aFieldInfo);
+    field->DateTimeStorage()->SetTime(iDate);
+    return field;
+    }
+
+
+////////////////////////////////////////////////////////////
+// CPbkDataSaveAppUi::CCommandBase
+
+inline CPbkDataSaveAppUi::CCommandBase::CCommandBase()
+    {
+    // operator new(TLeave) resets member data
+    }
+
+void CPbkDataSaveAppUi::CCommandBase::ResetWhenDestroyed(CCommandBase** aSelfPtr)
+    {
+    __ASSERT_DEBUG(!aSelfPtr || *aSelfPtr==this, Panic(EPanicPreCond_ResetWhenDestroyed));
+
+    iSelfPtr = aSelfPtr;
+    }
+
+TBool CPbkDataSaveAppUi::CCommandBase::ExecuteLD()
+    {
+    __ASSERT_DEBUG(!iContactItem, Panic(EPanicPreCond_ExecuteLD));
+
+    TSelfCleanup selfCleanup(this);
+    iSelfCleanup = &selfCleanup;
+    CleanupStack::PushL(selfCleanup);
+
+    TBool result = EFalse;
+    iContactItem = GetContactItemL();
+    if (iContactItem)
+        {
+        CArrayPtr<CPbkFieldInfo>* filteredFieldTypes = GetFilterFieldTypesLC
+            (*iContactItem, *iData.iFieldTypes, iData.iFieldData->StorageType());
+
+        CPbkFieldInfo* fieldType = NULL;
+        if (filteredFieldTypes->Count() > 1)
+            {
+            fieldType = SelectFieldTypeL(*filteredFieldTypes);
+            }
+        else if (filteredFieldTypes->Count() == 1)
+            {
+            fieldType = (*filteredFieldTypes)[0];
+            }
+        else
+            {
+            if (iData.iCallback) 
+                {
+                iData.iCallback->PbkDataSaveNoFieldL(*iContactItem);
+                }
+            }
+
+        TPbkContactItemField* field = NULL;
+        if (fieldType)
+            {
+            field = iData.iFieldData->AddFieldL(*iContactItem, *fieldType, iData.iCallback);
+            }
+
+        if (field)
+            {
+            result = EditContactL(*iContactItem, *field);
+            }
+
+        CleanupStack::PopAndDestroy();  // filteredFieldTypes
+        }
+
+    CleanupStack::PopAndDestroy();  // selfCleanup
+    return result;
+    }
+
+CPbkDataSaveAppUi::CCommandBase::~CCommandBase()
+    {
+    if (iSelfCleanup)
+        {
+        // Prevent double deletion through cleanup stack
+        iSelfCleanup->Reset();
+        }
+    if (iSelfPtr)
+        {
+        *iSelfPtr = NULL;
+        }
+    delete iItemTypeDlg;
+    delete iEditDlg;
+    if (iContactItem)
+        {
+        // CpbkContactEngine::CloseContactL() never leaves despite its name
+        iData.iEngine->CloseContactL(iContactItem->Id());
+        delete iContactItem;
+        }
+    }
+
+CPbkFieldInfo* CPbkDataSaveAppUi::CCommandBase::SelectFieldTypeL
+        (CArrayPtr<CPbkFieldInfo>& aFieldTypes)
+    {
+    __ASSERT_DEBUG(!iItemTypeDlg, Panic(EPanicPreCond_SelectFieldTypeL));
+    iItemTypeDlg = CreateFieldTypeDialogL();
+    iItemTypeDlg->ResetWhenDestroyed(&iItemTypeDlg);
+    CPbkFieldInfo* result = NULL;
+    result = iItemTypeDlg->ExecuteLD(aFieldTypes);
+    return result;
+    }
+
+TBool CPbkDataSaveAppUi::CCommandBase::EditContactL
+        (CPbkContactItem& aContact, const TPbkContactItemField& aField)
+    {
+    __ASSERT_DEBUG(!iEditDlg, Panic(EPanicPreCond_EditContactL));
+
+    const TInt fieldIndex = FocusedFieldIndex(aContact,aField);
+	iEditDlg = CPbkContactEditorDlg::NewL
+        (*iData.iEngine, aContact, NewContact(), fieldIndex, ETrue);
+    iEditDlg->ResetWhenDestroyed(&iEditDlg);
+    if (iData.iFlags & EFlagsHideEditorExit)
+        {
+        iEditDlg->HideExitCommand();
+        }
+	TBool result = EFalse;
+    result = iEditDlg->ExecuteLD() != KNullContactId; 
+    return result;
+    }
+
+TInt CPbkDataSaveAppUi::CCommandBase::FocusedFieldIndex
+        (CPbkContactItem& aContact,
+        const TPbkContactItemField& aField) const
+    {
+    return aContact.FindFieldIndex(aField);
+    }
+
+inline TBool CPbkDataSaveAppUi::CCommandBase::FieldTypeIncluded
+        (CPbkFieldInfo& aFieldType,
+        const CPbkContactItem& aContact, 
+        TUint aStorageType)
+    {
+    return 
+        (aFieldType.FieldStorageType()==aStorageType &&
+        aFieldType.IsEditable() &&
+        aContact.CanAcceptDataOfType(aFieldType) &&
+        aFieldType.UserCanAddField() );
+    }
+
+CArrayPtr<CPbkFieldInfo>* CPbkDataSaveAppUi::CCommandBase::GetFilterFieldTypesLC
+        (const CPbkContactItem& aContact, 
+        CArrayPtr<CPbkFieldInfo>& aFieldTypes,
+        TUint aStorageType)
+    {
+    CArrayPtrFlat<CPbkFieldInfo>* filteredFieldTypes = 
+        new(ELeave) CArrayPtrFlat<CPbkFieldInfo>(1 /*realloc granularity*/);
+    CleanupStack::PushL(filteredFieldTypes);
+    const TInt count = aFieldTypes.Count();
+    filteredFieldTypes->SetReserveL(count);
+    for (TInt i = 0; i < count; ++i)
+        {
+        CPbkFieldInfo* fieldType = aFieldTypes[i];
+        if (FieldTypeIncluded(*fieldType,aContact,aStorageType))
+            {
+            filteredFieldTypes->AppendL(fieldType);
+            }
+        }
+    return filteredFieldTypes;
+    }
+
+void CPbkDataSaveAppUi::CCommandBase::TSelfCleanup::Cleanup(TAny* aObject)
+    {
+    delete (static_cast<TSelfCleanup*>(aObject)->iSelf);
+    }
+
+
+////////////////////////////////////////////////////////////
+// CPbkDataSaveAppUi::CCreateNewCommand
+
+inline CPbkDataSaveAppUi::CCreateNewCommand::CCreateNewCommand()
+    {
+    // operator new(TLeave) resets member data
+    }
+
+CPbkDataSaveAppUi::CCreateNewCommand* CPbkDataSaveAppUi::CCreateNewCommand::NewL
+        (const TData& aData)
+    {
+    CCreateNewCommand* self = new(ELeave) CCreateNewCommand;
+    self->iData = aData;
+    return self;
+    }
+
+CPbkContactItem* CPbkDataSaveAppUi::CCreateNewCommand::GetContactItemL()
+    {
+    CPbkContactItem* ci = iData.iEngine->CreateEmptyContactL();
+    return ci;
+    }
+
+CPbkMemoryEntryAddItemDlg* CPbkDataSaveAppUi::CCreateNewCommand::CreateFieldTypeDialogL()
+    {
+    return new(ELeave) CPbkItemTypeSelectCreateNew;
+    }
+
+TInt CPbkDataSaveAppUi::CCreateNewCommand::FocusedFieldIndex
+        (CPbkContactItem& /*aContact*/,
+        const TPbkContactItemField& /*aField*/) const
+    {
+    // Always focus the first field
+    return 0;
+    }
+
+TBool CPbkDataSaveAppUi::CCreateNewCommand::NewContact()
+    {
+    return ETrue;
+    }
+
+
+////////////////////////////////////////////////////////////
+// CPbkDataSaveAppUi::CAddToExistingCommand
+
+inline CPbkDataSaveAppUi::CAddToExistingCommand::CAddToExistingCommand()
+    {
+    // operator new(TLeave) resets member data
+    }
+
+CPbkDataSaveAppUi::CAddToExistingCommand* CPbkDataSaveAppUi::CAddToExistingCommand::NewL
+        (const TData& aData)
+    {
+    CAddToExistingCommand* self = new(ELeave) CAddToExistingCommand;
+    self->iData = aData;
+    return self;
+    }
+
+CPbkDataSaveAppUi::CAddToExistingCommand::~CAddToExistingCommand()
+    {
+    delete iFetchDlg;
+    }
+
+CPbkContactItem* CPbkDataSaveAppUi::CAddToExistingCommand::GetContactItemL()
+    {
+    __ASSERT_DEBUG(!iFetchDlg, Panic(EPanicPreCond_GetContactItemL));
+
+    // Run Single Entry Fetch
+    CPbkSingleEntryFetchDlg::TParams params;
+    params.iContactView = &iData.iEngine->AllContactsView();
+	params.iCbaId = R_PBK_SOFTKEYS_SINGLE_ENTRY_FETCH;
+
+    iFetchDlg = CPbkSingleEntryFetchDlg::NewL(params);
+    iFetchDlg->ResetWhenDestroyed(&iFetchDlg);
+	TInt res = 0;
+    res = iFetchDlg->ExecuteLD();
+
+    CPbkContactItem* ci = NULL;
+    if (res && params.iSelectedEntry != KNullContactId)
+        {
+        ci = iData.iEngine->OpenContactL(params.iSelectedEntry);
+        }
+    return ci;
+    }
+
+CPbkMemoryEntryAddItemDlg* CPbkDataSaveAppUi::CAddToExistingCommand::CreateFieldTypeDialogL()
+    {
+    return new(ELeave) CPbkItemTypeSelectAddToExisting;
+    }
+
+TBool CPbkDataSaveAppUi::CAddToExistingCommand::NewContact()
+    {
+    return EFalse;
+    }
+
+
+////////////////////////////////////////////////////////////
+// MPbkDataSaveCallback default implementation
+
+EXPORT_C void MPbkDataSaveCallback::PbkDataSaveNoFieldL
+        (CPbkContactItem& /*aContact*/)
+    {
+    }
+
+EXPORT_C TPtrC MPbkDataSaveCallback::PbkDataSaveClipTextL
+        (const TDesC& aText, CPbkFieldInfo& aFieldInfo)
+    {
+    return aText.Left(aFieldInfo.MaxLength());
+    }
+
+// End of File