phonebookui/Phonebook/View/src/CPbkContactEditorDlg.cpp
changeset 0 e686773b3f54
child 21 9da50d567e3c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookui/Phonebook/View/src/CPbkContactEditorDlg.cpp	Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,1431 @@
+/*
+* 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: 
+*           Methods for Phonebook Contact editor dialog.
+*
+*/
+
+
+// INCLUDE FILES
+#include "CPbkContactEditorDlg.h"
+
+#include <eikspane.h>
+#include <avkon.hrh>
+#include <akntitle.h>
+#include <aknnavi.h>
+#include <eikmenub.h>
+#include <featmgr.h>
+#include <StringLoader.h>
+#include <AknQueryDialog.h>
+#include <aknnotewrappers.h>
+#include <AknsUtils.h>
+#include <eikcapc.h>
+#include <hlplch.h>   
+
+#include "CPbkThumbnailCmd.h"
+#include "CPbkContextPaneIcon.h"
+#include "CPbkContactEditorFieldArray.h"
+#include "MPbkContactEditorUiBuilder.h"
+#include <MPbkContactEditorField.h>
+#include <MPbkContactEditorControl.h>
+#include "PbkContactEditorStrategyFactory.h"
+#include "MPbkContactEditorStrategy.h"
+#include "TPbkAddItemManager.h"
+#include "CPbkThumbnailPopup.h"
+#include <PbkView.hrh>
+#include "PbkUID.h"
+#include "MPbkFieldEditorVisitor.h"
+#include "MPbkFieldEditorControl.h"
+#include "MPbkEditorOkToExitCallback.h"
+
+#include <CPbkContactEngine.h>
+#include <CPbkContactItem.h>
+#include <CPbkFieldsInfo.h>
+#include <CPbkConstants.h>
+#include <CPbkFieldData.h>
+#include <PbkView.rsg>
+#include <MPbkContactEditorExtension.h>
+#include <MPbkExtensionFactory.h>
+#include <CPbkExtGlobals.h>
+
+#include <PbkDebug.h>
+
+
+/// Unnamed namespace for local definitions
+namespace {
+
+// LOCAL CONSTANTS AND MACROS
+
+/// Escape key press event
+static const TKeyEvent KEscKeyEvent = { EKeyEscape, 0, 0, 0 };
+
+#ifdef _DEBUG
+/// Panic codes for CPbkContactEditorDlg
+enum TPanicCode
+    {
+    EPanicPostCond_Constructor,
+    EPanicPreCond_ResetWhenDestroyed,
+    EPanicPreCond_CmdFetchThumbnailL,
+    EPanicPreCond_CmdRemoveThumbnailL,
+    EPanicPreCond_PreLayoutDynInitL,
+    EPanicPostCond_PreLayoutDynInitL,
+    EPanicPreCond_SetInitialCurrentLine,
+    EPanicPreCond_ContactAlreadyExistsL
+    };
+
+void Panic(TPanicCode aReason)
+    {
+    _LIT(KPanicText, "CPbkContactEditorDlg");
+    User::Panic(KPanicText, aReason);
+    }
+#endif  // _DEBUG
+
+void UpdateCbasL( MPbkContactEditorField* aCurrentField,
+                  CEikButtonGroupContainer& aCba )
+    {
+    if ( aCurrentField )
+        {
+        TPbkFieldEditMode editMode =
+            aCurrentField->ContactItemField().FieldInfo().EditMode();
+        
+        if ( editMode ==  EPbkFieldEditModeSelector )
+            {
+            if ( !aCba.IsCommandInGroup(EAknSoftkeyChange) )
+                {
+                aCba.SetCommandSetL( R_PBK_SOFTKEYS_OPTIONS_DONE_CHANGE );    
+                aCba.DrawDeferred();
+                } 
+            }
+        else
+            {
+            if ( !aCba.IsCommandInGroup(EAknSoftkeyContextOptions) )
+                {
+                aCba.SetCommandSetL( R_PBK_SOFTKEYS_OPTIONS_DONE_CONTEXT );    
+                aCba.DrawDeferred();                
+                }
+            }
+        }
+    }
+
+}  // namespace
+
+
+// ================= MEMBER FUNCTIONS =======================
+
+/**
+ * Extension implementation.
+ */
+NONSHARABLE_CLASS(CPbkContactEditorDlg::CExtension) :
+        public CBase,
+        public MPbkContactEditorControl
+    {
+    public: // Constructor and destructor
+        /**
+         * Creates a new CExtension.
+         * @param aContact currently edited contact
+         */
+        static CExtension* NewL
+            (CPbkContactItem& aContact,
+            const CPbkContactEditorDlg& aParent);
+        /**
+         * Destructor
+         */
+        ~CExtension();
+
+    public: // From MPbkContactEditorExtension API
+        void DynInitMenuPaneL(TInt aResourceId, CEikMenuPane* aMenuPane);
+        TBool ProcessCommandL(TInt aCommandId);
+        void PreOkToExitL(TInt aButtonId);
+        void PostOkToExitL(TInt aButtonId);
+        void SetStateModified();
+
+    public: // From MPbkContactEditorControl
+        MPbkContactEditorField* FocusedField();
+        TInt EditorCount();
+        const MPbkContactEditorField& FieldAt(TInt aFieldIndex);
+
+    private: // Implementation
+        CExtension(const CPbkContactEditorDlg& aParent);
+        void ConstructL(CPbkContactItem& aContact);
+
+    private: // Data
+        /// Ref: for creating editor extension
+        CPbkExtGlobals* iExtGlobal;
+        /// Ref: editor extension
+        MPbkContactEditorExtension* iEditorExtension;
+        /// Ref: parent editor
+        const CPbkContactEditorDlg& iParent;
+    };
+
+CPbkContactEditorDlg::CExtension::CExtension
+        (const CPbkContactEditorDlg& aParent) :
+        iParent(aParent)
+    {
+    }
+
+void CPbkContactEditorDlg::CExtension::ConstructL
+        (CPbkContactItem& aContact)
+    {
+    iExtGlobal = CPbkExtGlobals::InstanceL();
+    iEditorExtension = iExtGlobal->FactoryL().
+        CreatePbkContactEditorExtensionL(aContact, iParent.iEngine, *this);
+    }
+
+CPbkContactEditorDlg::CExtension* CPbkContactEditorDlg::CExtension::NewL
+        (CPbkContactItem& aContact,
+        const CPbkContactEditorDlg& aParent)
+    {
+    CExtension* self = new (ELeave) CExtension(aParent);
+    CleanupStack::PushL(self);
+    self->ConstructL(aContact);
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+CPbkContactEditorDlg::CExtension::~CExtension()
+    {
+    Release(iEditorExtension);
+    Release(iExtGlobal);
+    }
+
+void CPbkContactEditorDlg::CExtension::DynInitMenuPaneL
+        (TInt aResourceId, CEikMenuPane* aMenuPane)
+    {
+    iEditorExtension->DynInitMenuPaneL(aResourceId, aMenuPane);
+    }
+
+TBool CPbkContactEditorDlg::CExtension::ProcessCommandL(TInt aCommandId)
+    {
+    return iEditorExtension->ProcessCommandL(aCommandId);
+    }
+
+void CPbkContactEditorDlg::CExtension::PreOkToExitL(TInt aButtonId)
+    {
+    iEditorExtension->PreOkToExitL(aButtonId);
+    }
+
+void CPbkContactEditorDlg::CExtension::PostOkToExitL(TInt aButtonId)
+    {
+    iEditorExtension->PostOkToExitL(aButtonId);
+    }
+
+void CPbkContactEditorDlg::CExtension::SetStateModified()
+    {
+    iParent.iEditorStrategy->SetStateModified();
+    }
+
+MPbkContactEditorField* CPbkContactEditorDlg::CExtension::FocusedField()
+    {
+    const TInt id = iParent.IdOfFocusControl();
+    return iParent.iFieldManager->Find(id);
+    }
+
+TInt CPbkContactEditorDlg::CExtension::EditorCount()
+    {
+    return iParent.iFieldManager->EditorCount();
+    }
+
+const MPbkContactEditorField& CPbkContactEditorDlg::CExtension::
+        FieldAt(TInt aFieldIndex)
+    {
+    return iParent.iFieldManager->FieldAt(aFieldIndex);
+    }
+
+/**
+ * Editor implementation class.
+ */
+NONSHARABLE_CLASS(CPbkContactEditorDlgImpl) :
+        public CPbkContactEditorDlg,
+        private MPbkContactEditorUiBuilder
+    {
+    public: // constructor
+        /**
+         * Creates a new instance of this class.
+         * @param aEngine phonebook engine
+         * @param aContactItem contact item
+         * @param aIsNewContact defines is this new contact or not
+         * @param aFocusIndex field to focus
+         * @param AEdited edited flag
+         */
+        static CPbkContactEditorDlgImpl* NewL(
+            CPbkContactEngine& aEngine,
+            CPbkContactItem& aContactItem,
+            TBool aIsNewContact,
+            TInt aFocusIndex = -1,
+            TBool aEdited = EFalse);
+
+        /**
+         * Destructor.
+         */
+        ~CPbkContactEditorDlgImpl();
+
+    private: // from MPbkContactEditorUiBuilder
+        CCoeControl* CreateLineL(const TDesC& aCaption, TInt aControlId,
+                TInt aControlType);
+        CEikCaptionedControl* LineControl(TInt aControlId) const;
+        void DeleteControl(TInt aControlId);
+        void TryChangeFocusL(TInt aControlId);
+        void SetCurrentLineCaptionL(const TDesC& aText);
+        CCoeControl* Control(TInt aControlId) const;
+        void SetEditableL(TBool aState);
+
+    private: // from CAknForm
+        void HandleResourceChange(TInt aType);
+        
+    private: // from CCoeControl
+        void FocusChanged(TDrawNow aDrawNow);
+
+    private: // implementation
+        CPbkContactEditorDlgImpl
+            (CPbkContactEngine& aEngine,
+            CPbkContactItem& aContactItem,
+            TInt aFocusIndex = -1);
+    private:
+        class CPbkIconReloaderVisitor;
+        CPbkIconReloaderVisitor* iIconReloaderVisitor;
+    };
+
+/**
+ * Editor icon reloader visitor.
+ */
+NONSHARABLE_CLASS(CPbkContactEditorDlgImpl::CPbkIconReloaderVisitor) :
+        public CBase,
+        public MPbkFieldEditorVisitor
+    {
+    public:
+        CPbkIconReloaderVisitor(MPbkContactEditorUiBuilder& aUiBuilder);
+        ~CPbkIconReloaderVisitor();
+
+    private: // From MPbkFieldEditorVisitor
+        void VisitL(MPbkFieldEditorControl& aThis);
+
+    private: // Data
+        MPbkContactEditorUiBuilder& iUiBuilder;
+    };
+
+CPbkContactEditorDlgImpl::CPbkIconReloaderVisitor::CPbkIconReloaderVisitor
+        (MPbkContactEditorUiBuilder& aUiBuilder) :
+    iUiBuilder(aUiBuilder)
+    {
+    }
+
+CPbkContactEditorDlgImpl::CPbkIconReloaderVisitor::~CPbkIconReloaderVisitor()
+    {
+    }
+
+void CPbkContactEditorDlgImpl::CPbkIconReloaderVisitor::VisitL
+        (MPbkFieldEditorControl& aThis)
+    {
+    aThis.LoadBitmapToFieldL(iUiBuilder);
+    }
+
+inline CPbkContactEditorDlgImpl::CPbkContactEditorDlgImpl(
+        CPbkContactEngine& aEngine,
+        CPbkContactItem& aContactItem,
+        TInt aFocusIndex) :
+    CPbkContactEditorDlg(aEngine, aContactItem, aFocusIndex)
+    {
+    }
+
+CPbkContactEditorDlgImpl* CPbkContactEditorDlgImpl::NewL(
+        CPbkContactEngine& aEngine,
+        CPbkContactItem& aContactItem,
+        TBool aIsNewContact,
+        TInt aFocusIndex,
+        TBool aEdited)
+    {
+    // Create the dialog
+    CPbkContactEditorDlgImpl* self = new(ELeave) CPbkContactEditorDlgImpl(
+            aEngine, aContactItem, aFocusIndex);
+    CleanupStack::PushL(self);
+    self->BaseConstructL(aIsNewContact, aEdited);
+
+    // create field managing object
+    self->iFieldManager = CPbkContactEditorFieldArray::NewL
+        (aContactItem, *self);
+
+    self->iIconReloaderVisitor = new(ELeave) CPbkIconReloaderVisitor(*self);
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+CPbkContactEditorDlgImpl::~CPbkContactEditorDlgImpl()
+    {
+    delete iIconReloaderVisitor;
+    }
+
+CCoeControl* CPbkContactEditorDlgImpl::CreateLineL
+        (const TDesC& aCaption,
+        TInt aControlId,
+        TInt aControlType)
+    {
+    return CreateLineByTypeL(
+            aCaption, aControlId, aControlType, NULL);
+    }
+
+CEikCaptionedControl* CPbkContactEditorDlgImpl::LineControl
+        (TInt aControlId) const
+    {
+    return Line(aControlId);
+    }
+
+void CPbkContactEditorDlgImpl::DeleteControl
+        (TInt aControlId)
+    {
+    DeleteLine(aControlId);
+    }
+
+void CPbkContactEditorDlgImpl::TryChangeFocusL
+        (TInt aControlId)
+    {
+    if (ControlOrNull(aControlId))
+        {
+        TryChangeFocusToL(aControlId);
+        }
+    }
+
+void CPbkContactEditorDlgImpl::SetCurrentLineCaptionL
+        (const TDesC& aText)
+    {
+    SetControlCaptionL(IdOfFocusControl(), aText);
+    }
+
+CCoeControl* CPbkContactEditorDlgImpl::Control
+        (TInt aControlId) const
+    {
+    return ControlOrNull(aControlId);
+    }
+
+void CPbkContactEditorDlgImpl::SetEditableL(TBool aState)
+    {
+    CPbkContactEditorDlg::SetEditableL(aState);
+    }
+
+void CPbkContactEditorDlgImpl::HandleResourceChange(TInt aType)
+    {
+    CPbkContactEditorDlg::HandleResourceChange(aType);
+
+    if (aType == KAknsMessageSkinChange)
+        {
+        TRAP_IGNORE(iFieldManager->AcceptL(*iIconReloaderVisitor));
+        }
+    else if (aType == KEikDynamicLayoutVariantSwitch)
+        {        
+        // It is not bad if thumbnail showing fails
+        TRAP_IGNORE( ReloadThumbnailL() );        
+        }
+    }
+    
+void CPbkContactEditorDlgImpl::FocusChanged(TDrawNow /*aDrawNow*/)
+    {
+    // Thumbnail will be set as hidden if the control is not focused.
+    // all is done in ReloadThumbnailL -method.
+    // No big deal if thumbnail is not shown    
+    TRAP_IGNORE(ReloadThumbnailL());
+    }
+
+
+///////////////////////////////////////////////////////////////
+/// CPbkContactEditorDlg
+
+inline CPbkContactEditorDlg::CPbkContactEditorDlg
+        (CPbkContactEngine& aEngine,
+        CPbkContactItem& aContactItem,
+        TInt aFocusIndex) :
+    iContactItem(aContactItem),
+    iEngine(aEngine),
+    iFocusIndex(aFocusIndex)
+    {
+    __ASSERT_DEBUG(!iTitlePane && !iThumbnailHandler && !iStoredTitlePaneText,
+        Panic(EPanicPostCond_Constructor));
+    }
+
+inline void CPbkContactEditorDlg::StoreTitlePaneTextL()
+    {
+    CEikStatusPane* statusPane = iEikonEnv->AppUiFactory()->StatusPane();
+    if (statusPane && statusPane->PaneCapabilities(TUid::Uid(EEikStatusPaneUidTitle)).IsPresent())
+        {
+        iTitlePane = static_cast<CAknTitlePane*>
+            (statusPane->ControlL(TUid::Uid(EEikStatusPaneUidTitle)));
+        if (iTitlePane->Text())
+            {
+            iStoredTitlePaneText = iTitlePane->Text()->AllocL();
+            }
+        }
+    }
+
+inline void CPbkContactEditorDlg::ConstructContextMenuL()
+    {
+    CEikMenuBar* newMenuBar = new(ELeave) CEikMenuBar();
+    CleanupStack::PushL(newMenuBar);
+    newMenuBar->ConstructL(this, NULL, R_PBK_CONTACTEDITOR_CONTEXT_MENUBAR);
+    iEikonEnv->EikAppUi()->AddToStackL(newMenuBar, ECoeStackPriorityMenu, ECoeStackFlagRefusesFocus);
+    iContextMenuBar = newMenuBar;
+    CleanupStack::Pop(newMenuBar);
+    }
+
+inline void CPbkContactEditorDlg::ConstructNaviPaneL()
+    {
+    CEikStatusPane* statusPane = iEikonEnv->AppUiFactory()->StatusPane();
+    if (statusPane && statusPane->PaneCapabilities(TUid::Uid(EEikStatusPaneUidNavi)).IsPresent())
+        {
+        // create a default empty status pane, otherwise sync field will show
+        iNaviContainer = static_cast<CAknNavigationControlContainer *>(statusPane->ControlL(
+                TUid::Uid(EEikStatusPaneUidNavi)));
+        iNaviContainer->PushDefaultL();
+        }
+    }
+
+inline void CPbkContactEditorDlg::BaseConstructL
+        (TBool aIsNewContact, TBool aEdited)
+    {
+    // set feature manager in TLS
+    FeatureManager::InitializeLibL();
+
+    CAknDialog::ConstructL(R_PBK_CONTACTEDITOR_MENUBAR);
+
+    iEditorStrategy = PbkContactEditorStrategyFactory::CreateL
+        (iEngine, iContactItem, aIsNewContact);
+    if (aEdited)
+        {
+        iEditorStrategy->SetStateModified();
+        }
+
+    // check existance of syncronization field
+    if(!iContactItem.FindField(EPbkFieldIdSyncronization))
+        {
+        CPbkFieldInfo* syncFieldInfo = iEngine.FieldsInfo().Find(
+            EPbkFieldIdSyncronization);
+        if (syncFieldInfo)
+            {
+            // add syncronization field to contact - compulsory
+            iContactItem.AddFieldL(*syncFieldInfo);
+            iEditorStrategy->SetStateModified();
+            }
+        }
+        
+    StoreTitlePaneTextL();
+    ConstructContextMenuL();
+    ConstructNaviPaneL();
+
+    iThumbnailHandler = CPbkThumbnailPopup::NewL(iEngine);
+    iThumbnailCmd = CPbkThumbnailCmd::NewL(iEngine, *iThumbnailHandler);
+    iExtension = CExtension::NewL(iContactItem, *this);
+    }
+
+EXPORT_C CPbkContactEditorDlg* CPbkContactEditorDlg::NewL
+        (CPbkContactEngine& aEngine,
+        CPbkContactItem& aContactItem,
+        TBool aIsNewContact,
+        TInt aFocusIndex/*=-1*/,
+        TBool aEdited/*=EFalse*/)
+    {
+    return CPbkContactEditorDlgImpl::NewL(
+            aEngine, aContactItem, aIsNewContact, aFocusIndex, aEdited);
+    }
+
+EXPORT_C void CPbkContactEditorDlg::ResetWhenDestroyed
+        (CPbkContactEditorDlg** aSelfPtr)
+    {
+    __ASSERT_DEBUG(!aSelfPtr || *aSelfPtr == this,
+            Panic(EPanicPreCond_ResetWhenDestroyed));
+    iSelfPtr = aSelfPtr;
+    }
+
+EXPORT_C void CPbkContactEditorDlg::HideExitCommand()
+    {
+    iStateFlags.Set(EHideExit);
+    }
+
+EXPORT_C void CPbkContactEditorDlg::SetExitCommandId
+        (TInt aCommandId)
+    {
+    iExitCommandId = aCommandId;
+    }
+
+CPbkContactEditorDlg::~CPbkContactEditorDlg()
+    {
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING("CPbkContactEditorDlg::~CPbkContactEditorDlg"));
+
+    iStateFlags.Set(EUnderDestruction);
+    CloseAllPopups();
+
+    // Save unless saved yet. No other way to handle errors than ignore
+    // because exiting the dialog must always be possible.
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING("CPbkContactEditorDlg::~CPbkContactEditorDlg(0x%x) saving"), this);
+    TRAP_IGNORE(CmdSaveL());
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING("    saved"));
+
+    // delete member data
+    delete iThumbnailHandler;
+    delete iThumbnailCmd;
+
+    if (iContextMenuBar)
+        {
+        iEikonEnv->EikAppUi()->RemoveFromStack(iContextMenuBar);
+        delete iContextMenuBar;
+        }
+
+    delete iFieldManager; // context menu bar's stack removal (above) needs field manager to be alive
+    delete iEditorStrategy;
+    delete iContextPaneIcon;
+
+    // Restore the titlepane text
+    if (iTitlePane && iStoredTitlePaneText)
+        {
+        // iTitlePane takes ownership of iStoredTitlePaneText
+        iTitlePane->SetText(iStoredTitlePaneText);
+        }
+
+    // Remove empty status pane
+    if (iNaviContainer)
+        {
+        iNaviContainer->Pop();
+        }
+    // Reset self pointer
+    if (iSelfPtr)
+        {
+        *iSelfPtr = NULL;
+        }
+    delete iExtension;
+
+    FeatureManager::UnInitializeLib();
+    }
+
+EXPORT_C TContactItemId CPbkContactEditorDlg::ExecuteLD()
+    {
+    TContactItemId ret = KNullContactId;
+    iSavedContactPtr = &ret;
+
+    // Set Phonebook icon on context pane
+    if (!iContextPaneIcon)
+        {
+        iContextPaneIcon = CPbkContextPaneIcon::NewL(*iEikonEnv);
+        }
+
+    // Set status pane layout to the Phonebook one
+    CEikStatusPane* statusPane = iAvkonAppUi->StatusPane();
+    TInt statusPaneLayout = KErrNotFound;
+    if (statusPane)
+        {
+        statusPaneLayout = statusPane->CurrentLayoutResId();
+        statusPane->SwitchLayoutL(R_AVKON_STATUS_PANE_LAYOUT_USUAL);
+        }
+
+    CAknForm::ExecuteLD(R_PBK_EDIT_MEMORY_ENTRY_DIALOG);
+
+    if (statusPane && (statusPaneLayout != KErrNotFound))
+        {
+        statusPane->SwitchLayoutL(statusPaneLayout);
+        }
+
+    return ret;
+    }
+
+
+EXPORT_C void CPbkContactEditorDlg::SetHelpContext
+        (TCoeHelpContext aContext)
+    {
+    iHelpContext = aContext;
+    }
+
+
+/**
+ * Saves dialog's fields to contact fields and saves the contact.
+ * Command sent from class destructor.
+ */
+void CPbkContactEditorDlg::CmdSaveL()
+    {
+    if (iFieldManager)
+        {
+        // Save editor fields
+        iFieldManager->SaveFieldsL();
+        if (iFieldManager->FieldsChanged())
+            {
+            iEditorStrategy->SetStateModified();
+            }
+
+        if (iSavedContactPtr && !iFieldManager->AreAllFieldsEmpty())
+            {
+            *iSavedContactPtr = iEditorStrategy->SaveContactL();
+            }
+        }
+    }
+
+/**
+ * Command sent from OkToExitL.
+ */
+void CPbkContactEditorDlg::CmdDoneL()
+    {
+    if (iFieldManager)
+        {
+        // Save editor fields to contact item
+        iFieldManager->SaveFieldsL();
+        if (iFieldManager->FieldsChanged())
+            {
+            iEditorStrategy->SetStateModified();
+            }
+
+        if (iFieldManager->AreAllFieldsEmpty())
+            {
+            iEditorStrategy->DeleteContactL();
+            }
+
+        *iSavedContactPtr = iEditorStrategy->SaveContactL();
+        }
+    }
+
+/**
+ * Edits the focused memory items caption.
+ */
+void CPbkContactEditorDlg::CmdEditItemLabelL()
+    {
+    MPbkContactEditorField* field = iFieldManager->Find(IdOfFocusControl());
+    if (field)
+        {
+        HBufC* textBuf = HBufC::NewLC(CPbkConstants::FormEditorLength());
+        TPtr text = textBuf->Des();
+        text.Copy(field->FieldLabel().Left(text.MaxLength()));
+        HBufC* prompt = StringLoader::LoadLC(R_QTN_FORM_PRMPT_FIELD_LABEL);
+
+        CAknTextQueryDialog* dlg = CAknTextQueryDialog::NewL(text);
+        dlg->SetMaxLength(CPbkConstants::FormEditorLength());
+        if (dlg->ExecuteLD(R_PBK_EDIT_FIELD_LABEL, *prompt))
+            {
+            if (text != field->FieldLabel())
+                {
+                // Assign new label leave-safely to this form and to the contact field
+                HBufC* newLabel = text.AllocLC();
+                field->SetFieldLabelL(newLabel); // takes ownership of newLabel
+                CleanupStack::Pop(newLabel);
+                iEditorStrategy->SetStateModified();
+                }
+            }
+        CleanupStack::PopAndDestroy(2);  // prompt, textBuf
+        }
+    }
+
+/**
+ * Add new memory item menu command.
+ */
+void CPbkContactEditorDlg::CmdAddItemL()
+    {
+    TPbkAddItemManager manager(iContactItem, *iFieldManager);
+
+    RArray<TInt> addedFieldsControlIds;
+    CleanupClosePushL(addedFieldsControlIds);
+
+    // Query and add field(s) to the contact
+    manager.AddFieldsL(iEngine.FieldsInfo(), addedFieldsControlIds);
+
+    if (addedFieldsControlIds.Count() > 0)
+        {
+        // Activate the first added field
+        TInt focusedControlId = addedFieldsControlIds[0];
+        TryChangeFocusToL(focusedControlId);
+        iEditorStrategy->SetStateModified();
+        // must be DrawNow and not DrawDeferred
+        // otherwise field label and content of
+        // following field will be incorrect
+        DrawNow();
+        }
+    CleanupStack::PopAndDestroy(); //addedFieldsControlIds
+    }
+
+/**
+ * Deletes focused memory entry item.
+ */
+void CPbkContactEditorDlg::CmdDeleteItemL()
+    {
+    // Delete item query
+    MPbkContactEditorField* field = iFieldManager->Find(IdOfFocusControl());
+    if (field)
+        {
+        TPtrC label = field->FieldLabel();
+        HBufC* prompt = StringLoader::LoadLC(R_QTN_PHOB_QUERY_DELETE_ITEM, label);
+
+        CAknQueryDialog* dlg = CAknQueryDialog::NewL();
+        CleanupStack::PushL(dlg);
+        dlg->SetPromptL(*prompt);
+        CleanupStack::Pop(); // dlg
+        if(dlg->ExecuteLD(R_PBK_GENERAL_CONFIRMATION_QUERY_PBKVIEW))
+            {
+            // Notify about voice tag field deletion (unless it's SIND tag)
+            if (iContactItem.VoiceTagField() &&
+                iContactItem.VoiceTagField()->IsSame(field->ContactItemField()) &&
+                !FeatureManager::FeatureSupported(KFeatureIdSind))
+                {
+                HBufC* note = iCoeEnv->AllocReadResourceLC(R_QTN_PHOB_NOTE_VOICE_TAG_DEL);
+                CAknConfirmationNote* dlg = new(ELeave) CAknConfirmationNote(ETrue);
+                dlg->ExecuteLD(*note);
+                CleanupStack::PopAndDestroy(); // note
+                }
+
+            // Notify about speed dial field deletion
+            const TInt fieldIndex = iFieldManager->FindContactItemFieldIndex(
+                    field->ContactItemField());
+            if (iEngine.IsSpeedDialAssigned(iContactItem, fieldIndex))
+                {
+                HBufC* note = iCoeEnv->AllocReadResourceLC(R_QTN_PHOB_NOTE_SPEED_DIAL_DEL);
+                CAknConfirmationNote* dlg = new(ELeave) CAknConfirmationNote(ETrue);
+                dlg->ExecuteLD(*note);
+                CleanupStack::PopAndDestroy(); // note
+                }
+
+            // Delete the field
+            iFieldManager->RemoveField(*field);
+            iEditorStrategy->SetStateModified();
+
+            // Redraw using DrawNow, DrawDeferred does not get the job done
+            DrawNow();
+            }
+
+        CleanupStack::PopAndDestroy(); // prompt
+        }
+    }
+
+/**
+ * Fetches thumbnail image from photoalbum and attaches it to this
+ * contact.
+ */
+void CPbkContactEditorDlg::CmdFetchThumbnailL()
+    {
+    //PreCond:
+    __ASSERT_DEBUG(iThumbnailCmd, Panic(EPanicPreCond_CmdFetchThumbnailL));
+
+    if (iThumbnailCmd->FetchThumbnailL(iContactItem))
+        {
+        iEditorStrategy->SetStateModified();
+        }
+    }
+
+/**
+ * Removes a thumbnail image attachment from this contact.
+ */
+void CPbkContactEditorDlg::CmdRemoveThumbnailL()
+    {
+    //PreCond:
+    __ASSERT_DEBUG(iThumbnailCmd, Panic(EPanicPreCond_CmdRemoveThumbnailL));
+
+    if (iThumbnailCmd->RemoveThumbnailL(iContactItem))
+        {
+        iEditorStrategy->SetStateModified();
+        }
+    }
+
+/**
+ * Updates the application title pane.
+ */
+void CPbkContactEditorDlg::UpdateTitlePaneL()
+    {
+    if (iTitlePane)
+        {
+        CPbkFieldDataArray* titleFields = CPbkFieldDataArray::NewL();
+        titleFields->ResetAndDestroyPushL();
+
+        const TInt fieldCount = iFieldManager->EditorCount();
+        for (TInt i = 0; i < fieldCount; ++i)
+            {
+            const MPbkContactEditorField& field = iFieldManager->FieldAt(i);
+            const TPbkFieldId fieldId = field.FieldId();
+            if (iEngine.IsTitleField(fieldId))
+                {
+                HBufC* textBuf = field.ControlTextL();
+                TPtrC text;
+                if (textBuf)
+                    {
+                    CleanupStack::PushL(textBuf);
+                    text.Set(*textBuf);
+                    }
+
+                CPbkFieldData* fieldData = CPbkFieldData::NewL(fieldId,text);
+                if (textBuf)
+                    {
+                    CleanupStack::PopAndDestroy(textBuf);
+                    }
+                CleanupStack::PushL(fieldData);
+                titleFields->AppendL(fieldData);
+                CleanupStack::Pop(fieldData);
+                }
+            }
+
+        HBufC* newTitle = iEngine.GetContactTitleOrNullL(*titleFields);
+        CleanupStack::PopAndDestroy();  // titleFields
+
+        if (newTitle)
+            {
+            // Update title only if it doesn't contain ZWS or ZWNJ, which
+            // are a sign of incomplete typing in e.g. Hindi
+            const TChar KZeroWidthSpace(0x200b);
+            const TChar KZeroWidthNonJoiner(0x200c);
+            if ((newTitle->Locate(KZeroWidthSpace) == KErrNotFound) &&
+                (newTitle->Locate(KZeroWidthNonJoiner) == KErrNotFound))
+                {
+                iTitlePane->SetText(newTitle);
+                }
+            }
+        else
+            {
+            iTitlePane->SetTextL(iEditorStrategy->DefaultTitle());
+            }
+        }
+    }
+
+TKeyResponse CPbkContactEditorDlg::OfferKeyEventL
+        (const TKeyEvent& aKeyEvent,
+        TEventCode aType)
+    {
+    // display menu bar if the focused control doesnt consume selection keys
+    MPbkContactEditorField* field = iFieldManager->Find(IdOfFocusControl());
+    if (field && field->ConsumesKeyEvent(aKeyEvent, aType))
+        {
+        return CAknForm::OfferKeyEventL(aKeyEvent,aType);
+        }
+
+    if (aType == EEventKey && aKeyEvent.iCode == EKeyOK)
+        {
+        iContextMenuBar->TryDisplayMenuBarL();
+        return EKeyWasConsumed;
+        }
+
+    if (aType == EEventKey && aKeyEvent.iCode == EKeyEscape)
+        {
+        // See CloseAllMenusAndPopups()
+        iStateFlags.Set(EEscKeyReceived);
+        }
+
+    if (!iStateFlags.IsSet(EUnderDestruction))
+        {
+        TKeyResponse ret(EKeyWasNotConsumed);        
+        ret = CAknForm::OfferKeyEventL( aKeyEvent, aType );
+        if ( !iStateFlags.IsSet(EEscKeyReceived) && 
+            ret == EKeyWasConsumed )
+            {
+            UpdateCbasL( iFieldManager->Find(IdOfFocusControl()), 
+                         ButtonGroupContainer() );
+            }   
+        return ret;
+        }
+    else
+        {
+        return EKeyWasConsumed;
+        }
+    }
+
+void CPbkContactEditorDlg::GetHelpContext
+        (TCoeHelpContext& aContext) const
+    {
+    if (iHelpContext.iMajor.iUid)
+        {
+        // If external help context has been set, return it..
+        aContext = iHelpContext;
+        }
+    else
+        {
+        // ..otherwise go with the default context
+        aContext.iMajor.iUid = KPbkUID3;
+        iEditorStrategy->GetHelpContext(aContext);
+        }
+    }
+
+void CPbkContactEditorDlg::PreLayoutDynInitL()
+    {
+    __ASSERT_DEBUG(iFieldManager, Panic(EPanicPreCond_PreLayoutDynInitL));
+
+    SetEditableL(ETrue);
+
+    // create controls for contact items fields
+    iFieldManager->CreateFieldsFromContactL();
+
+    __ASSERT_DEBUG(iFieldManager, Panic(EPanicPostCond_PreLayoutDynInitL));
+    }
+
+void CPbkContactEditorDlg::PostLayoutDynInitL()
+    {
+    UpdateTitlePaneL();
+    
+    if ( iAvkonAppUi->StatusPane()->
+        PaneCapabilities(TUid::Uid(EEikStatusPaneUidContext)).IsInCurrentLayout() )
+        {
+        iThumbnailHandler->Load(iContactItem, NULL );
+        }
+
+    // Set state to initialised (enables save from destructor)
+    iEditorStrategy->SetStateInitialized();
+    }
+
+void CPbkContactEditorDlg::SetInitialCurrentLine()
+    {
+    //PreCond:
+    __ASSERT_DEBUG(iFieldManager,
+            Panic(EPanicPreCond_SetInitialCurrentLine));
+
+    CAknForm::SetInitialCurrentLine();
+    const TInt fieldCount = iFieldManager->ContactItemFieldCount();
+    if (fieldCount > 0)
+        {
+        if (iFocusIndex < 0 || iFocusIndex >= fieldCount)
+            {
+            // In any case focus the first line
+            iFocusIndex = 0;
+            }
+        iFieldManager->SetFocusToIndex(iFocusIndex);
+        }
+    }
+
+void CPbkContactEditorDlg::ProcessCommandL
+        (TInt aCommandId)
+    {
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING("CPbkContactEditorDlg::ProcessCommandL start"));
+
+    HideMenu();
+    iContextMenuBar->StopDisplayingMenuBar();
+
+    if ( iExtension->ProcessCommandL(aCommandId) )
+        {
+        return; // command processed
+        }
+
+    switch (aCommandId)
+        {
+        case EPbkCmdAddItem:
+            {
+            CmdAddItemL();
+            break;
+            }
+
+        case EPbkCmdDeleteItem:
+            {
+            CmdDeleteItemL();
+            break;
+            }
+
+        case EPbkCmdEditItemLabel:
+            {
+            CmdEditItemLabelL();
+            break;
+            }
+
+        case EPbkCmdFetchThumbnail:
+            {
+            CmdFetchThumbnailL();
+            break;
+            }
+
+        case EPbkCmdRemoveThumbnail:
+            {
+            CmdRemoveThumbnailL();
+            break;
+            }
+        
+        case EAknCmdHelp:
+            {
+            HlpLauncher::LaunchHelpApplicationL(iEikonEnv->WsSession(),
+                iEikonEnv->EikAppUi()->AppHelpContextL());
+            break;
+            }
+
+        case EEikCmdExit:   // FALLTHROUGH
+        case EAknCmdExit:   // Exit calling application
+            {
+            PBK_DEBUG_PRINT(PBK_DEBUG_STRING("CPbkContactEditorDlg::ProcessCommandL exit"));
+
+            // If exit callback returned EFalse, the exit is cancelled
+            if (iExitCallback && !iExitCallback->OkToExitL(aCommandId))
+                {
+                break;
+                }
+            const TInt exitCommandId = iExitCommandId;
+            CEikAppUi* appUi = iEikonEnv->EikAppUi();
+            // Close this dialog first
+            delete this;
+            if (exitCommandId)
+                {
+                // Exit application
+                static_cast<MEikCommandObserver*>(appUi)->ProcessCommandL(exitCommandId);
+                }
+            else
+                {
+                // Exit application
+                static_cast<MEikCommandObserver*>(appUi)->ProcessCommandL(aCommandId);
+                }
+            break;
+            }
+
+        default:
+            {
+            // Command not handled here, forward it to the app ui.
+            iEikonEnv->EikAppUi()->HandleCommandL(aCommandId);
+            break;
+            }
+        }
+
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING("CPbkContactEditorDlg::ProcessCommandL end"));
+    }
+
+void CPbkContactEditorDlg::DynInitMenuPaneL
+        (TInt aResourceId,
+        CEikMenuPane* aMenuPane)
+    {
+    iExtension->DynInitMenuPaneL(aResourceId, aMenuPane);
+
+    iEditorStrategy->DynInitMenuPaneL(aResourceId, aMenuPane);
+
+    // Options menu
+    if (aResourceId == R_CONTACTEDITOR_MENUPANE)
+        {
+        // don't show 'Exit' command if it is disabled
+        if (iStateFlags.IsSet(EHideExit))
+            {
+            aMenuPane->SetItemDimmed(EAknCmdExit,ETrue);
+            }
+
+        iThumbnailCmd->DynInitMenuPaneL(aResourceId, *aMenuPane, iContactItem);
+        }
+
+    // Common items in Options and context menus
+    if (aResourceId == R_CONTACTEDITOR_MENUPANE ||
+        aResourceId == R_PBK_CONTACTEDITOR_CONTEXT_MENUPANE)
+        {
+        // filter delete item away from menu for first and last name fields
+        // and from the syncronization field
+        MPbkContactEditorField* currentField = iFieldManager->Find(IdOfFocusControl());
+        if (currentField)
+            {
+            const TPbkFieldId fieldId = currentField->FieldId();
+            if (fieldId == EPbkFieldIdLastName || fieldId == EPbkFieldIdFirstName ||
+                fieldId == EPbkFieldIdSyncronization)
+                {
+                aMenuPane->SetItemDimmed(EPbkCmdDeleteItem, ETrue);
+                }
+            }
+        }
+    }
+
+TBool CPbkContactEditorDlg::OkToExitL(TInt aKeyCode)
+    {
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING
+        ("CPbkContactEditorDlg::OkToExitL(0x%x,%d)"), this, aKeyCode);
+
+    // editor can't be closed if this leaves
+    TRAPD(err, iExtension->PreOkToExitL(aKeyCode));
+
+    TBool ret = EFalse;
+    switch (aKeyCode)
+        {
+        case EAknSoftkeyOptions:
+            {
+            DisplayMenuL();
+            break;
+            }
+        case EAknSoftkeyDone:
+            {
+            if (!iThumbnailCmd->OkToExit())
+                {
+                // ThumbnailCmd state is not ready for exit
+                break;
+                }
+            if(iEngine.Constants()->
+               LocallyVariatedFeatureEnabled(EPbkLVCheckDuplicateEntry))
+                {
+                ret = CheckForDuplicateEntryL();
+                }
+            else
+                {
+                if (err != KErrNone)
+                    {
+                    // cannot affect on editor closing, but let's show
+                    // that something was wrong
+                    iCoeEnv->HandleError(err);
+                    }
+                TRAP(err,CmdDoneL());
+                ret = ETrue;
+                }
+            break;
+            }
+        case EAknSoftkeyChange: // Fallthrough
+        case EAknSoftkeyContextOptions:
+            {
+            // Launch context menu if the control is not popup control
+            CEikCaptionedControl* line=CurrentLine();
+            TInt type=line->iControlType;
+            TBool isPopUp = ( type == EAknCtPopupFieldText ) ||
+                ( type == EAknCtPopupField );
+            if (isPopUp)
+                {
+                CAknPopupField* ctrl =
+                    static_cast<CAknPopupField*>( line->iControl );
+                ctrl->ActivateSelectionListL();
+                }
+            else
+                {
+                iContextMenuBar->SetMenuTitleResourceId( R_PBK_CONTACTEDITOR_CONTEXT_MENUBAR );
+                iContextMenuBar->SetMenuType( CEikMenuBar::EMenuContext );
+                iContextMenuBar->StopDisplayingMenuBar();
+                iContextMenuBar->TryDisplayMenuBarL();
+                iContextMenuBar->SetMenuTitleResourceId( R_PBK_CONTACTEDITOR_MENUBAR );
+                iContextMenuBar->SetMenuType( CEikMenuBar::EMenuOptions );
+                }
+            break;
+            }
+        default:
+            break;
+        }
+
+    if (err == KErrNone)
+        {
+        TRAP(err, iExtension->PostOkToExitL(aKeyCode));
+        }
+    if (err != KErrNone)
+        {
+        // cannot affect on editor closing, but let's show
+        // that something was wrong
+        iCoeEnv->HandleError(err);
+        }
+    return ret;
+    }
+
+void CPbkContactEditorDlg::HandleControlStateChangeL
+        (TInt aControlId)
+    {
+    MPbkContactEditorField* changedField = iFieldManager->Find(aControlId);
+    if (changedField)
+        {
+        if ( iEngine.IsTitleField(changedField->FieldId()) )
+            {
+            UpdateTitlePaneL();
+            }
+        }
+    }
+
+/**
+ * Closes popups opened from this dialog by sending them Escape key events.
+ * @see CPbkContactEditorDlg::OfferKeyEventL
+ */
+void CPbkContactEditorDlg::CloseAllPopups()
+    {
+    const TInt KMaxAttempts = 50;
+    iStateFlags.Clear(EEscKeyReceived);
+    // Send Escape key until this dialog itself receives it
+    for (TInt attempt=0;
+        attempt < KMaxAttempts && !iStateFlags.IsSet(EEscKeyReceived);
+        ++attempt)
+        {
+        TRAP_IGNORE(iEikonEnv->SimulateKeyEventL(KEscKeyEvent,EEventKey));
+        }
+    }
+
+
+/*  This function will check to see if the user entered information, coming out of the
+  *  TPbkContactItemFields, matches (exactly) any entries in the contact database, based
+  *  on the results of the GetContactTitle function. This function will only return what
+  *  is being displayed to the user. For example, a first name of "Eric", no last name, and
+  *  a company name of "Nokia" will only display "Eric" and would match an entry with
+  *  just the first name of "Eric".
+  *
+  *  The search has already been performed and ANY entry that matches any of the fields
+  *  the user has entered (first name, last name, and/or company name) is passed into
+  *  this function in the aIdArray parameter.
+  *
+  *  We are checking for entries that are separate from the current entry the user is
+  *  creating / editing. Therefore, if the user is editing an existing entry, we don't want
+  *  to signal a match when we find that specific entry. We can check this based on the stored
+  *  variable iContactItem and it's Id() function.
+  */
+TBool CPbkContactEditorDlg::DuplicateNameMatchL
+        (CContactIdArray* aIdArray)
+    {
+    TBool exactMatch = EFalse;
+    // just check the titles of the current item with the titles of each of the
+    // potentially matched items
+
+    HBufC* title = iContactItem.GetContactTitleL();
+    CleanupStack::PushL(title);
+
+    // iterate through each contact in aIdArray
+    for (TInt count = 0; count < aIdArray->Count(); count++)
+        {
+        // only continue with this check if we aren't checking our own entry. check with ID
+        if (iContactItem.Id() != (*aIdArray)[count])
+            {
+            // read the current contact
+            CPbkContactItem* contact = iEngine.ReadContactLC((*aIdArray)[count]);
+
+            // get the title of this current contact to compare
+            HBufC* contactTitle = contact->GetContactTitleL();
+            CleanupStack::PushL(contactTitle);
+
+            // now just compare the titles of this loop contact and the user-entered contact
+            if (!title->CompareF(*contactTitle))
+                {
+                exactMatch = ETrue;
+                CleanupStack::PopAndDestroy(2);     // name, contact
+                break;
+                }
+            CleanupStack::PopAndDestroy(2);         // name, contact
+            }
+        }
+
+    CleanupStack::PopAndDestroy(title);
+    return exactMatch;
+    }
+
+ /*
+  *  This function pulls user-entered info from the dialog for firstname, lastname and companyname.
+  *  We search the contact database on the first of these that is non-empty and not all spaces. If
+  *  we come up with any matches, we pass this info to the function DuplicateNameMatch, which checks
+  *  that all three fields match the found entries from the database search. If this is the case,
+  *  we pass back an ETrue value, EFalse otherwise.
+  */
+TBool CPbkContactEditorDlg::ContactAlreadyExistsL()
+    {
+    TBool found = EFalse;
+    CContactIdArray* idArray = NULL;
+
+    CPbkFieldIdArray* findFrom = new(ELeave) CPbkFieldIdArray;
+    CleanupStack::PushL(findFrom);
+
+    // add all fields, firstname, lastname and companyname to our contact database find parameter
+    findFrom->AppendL(EPbkFieldIdFirstName);
+    findFrom->AppendL(EPbkFieldIdLastName);
+    findFrom->AppendL(EPbkFieldIdCompanyName);
+
+    // get local copies of user-filled-in contact fields' text values
+    TPbkContactItemField* firstName = iContactItem.FindField(EPbkFieldIdFirstName);
+    TPbkContactItemField* lastName = iContactItem.FindField(EPbkFieldIdLastName);
+    TPbkContactItemField* companyName = iContactItem.FindField(EPbkFieldIdCompanyName);
+
+    // this is terribly slow
+    if (firstName && !firstName->IsEmptyOrAllSpaces())
+        {
+        idArray = iEngine.FindLC(firstName->Text(), findFrom);
+        }
+    else if (lastName && !lastName->IsEmptyOrAllSpaces())
+        {
+        idArray = iEngine.FindLC(lastName->Text(), findFrom);
+        }
+    else if (companyName && !companyName->IsEmptyOrAllSpaces())
+        {
+        idArray = iEngine.FindLC(companyName->Text(), findFrom);
+        }
+    else
+        {
+        // fname, lname and cname all empty - check for other "Unnamed" entries
+        // Two unnamed contacts are considered duplicates
+        idArray = iEngine.FindLC(KNullDesC, findFrom);
+        }
+
+    // if we have at least one match, check that all fields match
+    if (idArray)
+        {
+        if (idArray->Count() > 0 && DuplicateNameMatchL(idArray))
+            {
+            found = ETrue;
+            }
+        CleanupStack::PopAndDestroy(idArray);
+        }
+
+    CleanupStack::PopAndDestroy(findFrom);
+    return found;
+    }
+
+
+TBool CPbkContactEditorDlg::CheckForDuplicateEntryL()
+    {
+    TBool retVal = ETrue;
+    TBool exitNormally = ETrue;
+
+    // Check for duplicate entry and give the user the option to
+    // save duplicate or return to enter more information.
+
+    // To perform that check, we must save the info the user has
+    // just entered (just locally, not in the contact database)
+    if (iFieldManager)
+        {
+        iFieldManager->SaveFieldsL();
+        if ( iFieldManager->FieldsChanged() )
+            {
+            iEditorStrategy->SetStateModified();
+            }
+
+        // Totally empty contacts are not checked for duplicates
+        if ( !iFieldManager->AreAllFieldsEmpty() )
+            {
+            // If contact already exists, inform the user and given them
+            // the option to add the duplicate, or go back to the screen
+            // and enter information
+            if ( ContactAlreadyExistsL() )
+                {
+                // Get contact title to display
+                HBufC* name = iContactItem.GetContactTitleL();
+                CleanupStack::PushL( name );
+
+                HBufC* prompt = StringLoader::LoadL(R_QTN_PHOB_ADD_DUPLICATE,
+                    *name );
+                CleanupStack::PushL( prompt );
+
+                CAknQueryDialog* dlg = CAknQueryDialog::NewL();
+                CleanupStack::PushL( dlg );
+                dlg->SetPromptL( *prompt );
+                CleanupStack::Pop(); // dlg
+                // If user hits no, we'll put them back to the edit screen
+                if ( !dlg->ExecuteLD(R_PBK_GENERAL_CONFIRMATION_QUERY_PBKVIEW) )
+                    {
+                    exitNormally = EFalse;
+                    retVal = EFalse;
+                    }
+                CleanupStack::PopAndDestroy( 2 ); // prompt, name
+                }
+            }
+        }
+
+    if (exitNormally)
+        {
+        CmdDoneL();                     // saving occurs here
+        retVal = ETrue;
+        }
+
+    return retVal;
+    }
+
+EXPORT_C void CPbkContactEditorDlg::SetExitCallback
+    (MPbkEditorOkToExitCallback* aCallback)
+    {
+    iExitCallback = aCallback;
+    }
+
+void CPbkContactEditorDlg::ReloadThumbnailL()
+    {
+    if ( iAvkonAppUi->StatusPane()->
+        PaneCapabilities(TUid::Uid(EEikStatusPaneUidContext)).IsInCurrentLayout() )
+        {
+        if (IsFocused())
+            {
+            if (!iThumbnailHandler)
+                {
+                iThumbnailHandler = CPbkThumbnailPopup::NewL(iEngine);
+                }
+            iThumbnailHandler->Load(iContactItem, NULL );
+            }
+        else
+            {
+            if (iThumbnailHandler)
+                {
+                iThumbnailHandler->CancelLoading();
+                }
+            }   
+        }
+    }
+
+// End of File