--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookui/Phonebook2/UIControls/src/CPbk2ContactEditorDlg.cpp Wed Sep 01 12:29:52 2010 +0100
@@ -0,0 +1,638 @@
+/*
+* Copyright (c) 2005-2007 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: Phonebook2 contact editor dialog.
+*
+*/
+
+
+// INCLUDE FILES
+#include <CPbk2ContactEditorDlg.h>
+
+// Phonebook 2
+#include "CPbk2ContactEditorDlgImpl.h"
+#include "Pbk2ContactEditorStrategyFactory.h"
+#include "MPbk2ContactEditorStrategy.h"
+#include <CPbk2ContactRelocator.h>
+#include <CPbk2FieldPropertyArray.h>
+#include <MPbk2ContactEditorEventObserver.h>
+#include <MPbk2EditedContactObserver.h>
+#include <CPbk2PresentationContact.h>
+#include <CPbk2StoreSpecificFieldPropertyArray.h>
+#include <CPbk2PresentationContactFieldCollection.h>
+#include <MPbk2FieldProperty.h>
+#include <MPbk2ApplicationServices.h>
+#include <MPbk2AppUi.h>
+
+// Virtual Phonebook
+#include <CVPbkContactManager.h>
+#include <MVPbkStoreContact.h>
+#include <MVPbkContactStore.h>
+#include <MVPbkContactFieldTextData.h>
+#include <MVPbkContactStoreProperties.h>
+#include <MVPbkFieldType.h>
+#include <barsread.h>
+
+
+// System includes
+#include <coemain.h>
+
+/// Unnamed namespace for local definitions
+namespace {
+
+#ifdef _DEBUG
+enum TPanicCode
+ {
+ ENullPointer,
+ EPanicPreCond_ResetWhenDestroyed
+ };
+
+void Panic(TPanicCode aReason)
+ {
+ _LIT(KPanicText, "CPbk2ContactEditorDlg");
+ User::Panic(KPanicText,aReason);
+ }
+#endif // _DEBUG
+
+} /// namespace
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorDlg::CPbk2ContactEditorDlg
+// --------------------------------------------------------------------------
+//
+CPbk2ContactEditorDlg::CPbk2ContactEditorDlg
+ ( TPbk2ContactEditorParams& aParams,
+ MPbk2EditedContactObserver& aContactObserver,
+ MPbk2ApplicationServices* aAppServices,
+ TInt aEditorFieldsId ) :
+ iParams( aParams ),
+ iContactObserver( aContactObserver ),
+ iAddItemFieldTypeResourceId( KErrNotFound ),
+ iAppServices( aAppServices ),
+ iEditorFieldsId( aEditorFieldsId )
+ {
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorDlg::~CPbk2ContactEditorDlg
+// --------------------------------------------------------------------------
+//
+CPbk2ContactEditorDlg::~CPbk2ContactEditorDlg()
+ {
+ ForceExit();
+
+ delete iTitleText;
+ if ( iSelfPtr )
+ {
+ *iSelfPtr = NULL;
+ }
+ if ( iDestroyedPtr )
+ {
+ *iDestroyedPtr = ETrue;
+ }
+ delete iContact;
+ delete iSpecificFieldProperties;
+ delete iFieldProperties;
+ delete iEditorStrategy;
+ delete iContactRelocator;
+ delete iStoreContact;
+ delete iAddItemFieldTypeXspName;
+ }
+
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorDlg::NewL
+// --------------------------------------------------------------------------
+//
+EXPORT_C CPbk2ContactEditorDlg* CPbk2ContactEditorDlg::NewL(
+ TPbk2ContactEditorParams& aParams, MVPbkStoreContact* aContact,
+ MPbk2EditedContactObserver& aContactObserver)
+ {
+ CPbk2ContactEditorDlg* self =
+ new(ELeave) CPbk2ContactEditorDlg(aParams, aContactObserver);
+ CleanupStack::PushL(self);
+ self->ConstructL( aContact );
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorDlg::NewL
+// --------------------------------------------------------------------------
+//
+EXPORT_C CPbk2ContactEditorDlg* CPbk2ContactEditorDlg::NewL(
+ TPbk2ContactEditorParams& aParams,
+ MVPbkStoreContact* aContact,
+ MPbk2EditedContactObserver& aContactObserver,
+ MPbk2ApplicationServices* aAppServices,
+ HBufC* aTitleText,
+ TInt aEditorFieldsId )
+ {
+ CPbk2ContactEditorDlg* self =
+ new(ELeave) CPbk2ContactEditorDlg(aParams, aContactObserver,aAppServices,aEditorFieldsId );
+ CleanupStack::PushL(self);
+ self->ConstructL( aContact );
+ self->iTitleText = aTitleText;
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorDlg::ConstructL
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactEditorDlg::ConstructL( MVPbkStoreContact* aStoreContact )
+ {
+ CreatePresentationContactL( *aStoreContact );
+
+ iEditorStrategy =
+ Pbk2ContactEditorStrategyFactory::CreateL
+ (iParams, iContact);
+
+ // Take ownership of the contact after all leaving initialization has
+ // been done.
+ iStoreContact = aStoreContact;
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorDlg::ExecuteLD
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CPbk2ContactEditorDlg::ExecuteLD()
+ {
+ CleanupStack::PushL( this );
+
+ TBool destroyed = EFalse;
+ iDestroyedPtr = &destroyed;
+
+ // Implementation dialog must be run again e.g when relocation
+ // is done due to item addition.
+ do
+ {
+ // Reset state
+ iRelocationState.ClearAll();
+
+ iImplementation = CPbk2ContactEditorDlgImpl::NewL
+ ( iParams, *iContact, *iFieldProperties, *this,
+ *iEditorStrategy, *this, iAppServices, iTitleText );
+ // ownership is passed
+ iTitleText = NULL;
+ iEliminator = iImplementation;
+ iImplementation->ResetWhenDestroyed( &iEliminator );
+ iImplementation->ExecuteLD();
+ } while ( ContinueAfterRelocation() );
+
+ if ( destroyed )
+ {
+ CleanupStack::Pop( this );
+ }
+ else
+ {
+ CleanupStack::PopAndDestroy( this );
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorDlg::RequestExitL
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactEditorDlg::RequestExitL( TInt aCommandId )
+ {
+ __ASSERT_DEBUG( iEliminator, Panic( ENullPointer ) );
+ iEliminator->RequestExitL( aCommandId );
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorDlg::ForceExit
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactEditorDlg::ForceExit()
+ {
+ if ( iEliminator )
+ {
+ iEliminator->ForceExit();
+ }
+ // The contact relocator should be destructed
+ // if the edit dialog has been destructed
+ if ( iContactRelocator )
+ {
+ iRelocationState.ClearAll();
+ delete iContactRelocator;
+ iContactRelocator = NULL;
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorDlg::ResetWhenDestroyed
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactEditorDlg::ResetWhenDestroyed(
+ MPbk2DialogEliminator** aSelfPtr )
+ {
+ __ASSERT_DEBUG(!aSelfPtr || *aSelfPtr == this,
+ Panic(EPanicPreCond_ResetWhenDestroyed));
+ iSelfPtr = aSelfPtr;
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorDlg::ContactRelocatedL
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactEditorDlg::ContactRelocatedL
+ (MVPbkStoreContact* aRelocatedContact)
+ {
+ iStoreContact = aRelocatedContact; // take ownership
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorDlg::ContactRelocationFailed
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactEditorDlg::ContactRelocationFailed
+ ( TInt aReason, MVPbkStoreContact* aContact )
+ {
+ // Take the contact back
+ iStoreContact = aContact;
+ iAddItemFieldTypeResourceId = KErrNotFound;
+ iAddItemFieldTypeXspName = NULL;
+
+ if ( aReason != KErrCancel )
+ {
+ // Reset state
+ iRelocationState.Set( ERelocationFailed );
+ // No error note is to be shown to the user when she
+ // manually cancels the relocation process, therefore
+ // the error code must be converted
+ CCoeEnv::Static()->HandleError( aReason );
+ }
+ else
+ {
+ // Relocation cancelled
+ iRelocationState.Set( ERelocationCancelled );
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorDlg::ContactsRelocationFailed
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactEditorDlg::ContactsRelocationFailed
+ ( TInt /*aReason*/, CVPbkContactLinkArray* /*aContacts*/ )
+ {
+ // Not called in editor case
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorDlg::RelocationProcessComplete
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactEditorDlg::RelocationProcessComplete()
+ {
+ TRAPD( res, HandleRelocationProcessCompleteL() );
+ if ( res != KErrNone )
+ {
+ // Shows system messages
+ CCoeEnv::Static()->HandleError( res );
+ // If application is not closed then at least destroy
+ // the dialog
+ iRelocationState.ClearAll();
+ iRelocationState.Set( ERelocationFailed );
+ delete iImplementation;
+ iImplementation = NULL;
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorDlg::RelocateContactL
+// --------------------------------------------------------------------------
+//
+TBool CPbk2ContactEditorDlg::RelocateContactL(
+ TPbk2RelocationQyeryPolicy aQueryPolicy )
+ {
+ TBool result = RelocateContactL( KErrNotFound, KNullDesC, aQueryPolicy );
+ // Clear the add item state because this is called in other cases than
+ // relocation due to add item.
+ iRelocationState.Clear( ERelocationDueToItemAddition );
+
+ return result;
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorDlg::RelocateContactL
+// --------------------------------------------------------------------------
+//
+TBool CPbk2ContactEditorDlg::RelocateContactL(
+ TInt aAddItemFieldTypeResourceId,
+ const TDesC& aAddItemXspName,
+ TPbk2RelocationQyeryPolicy aQueryPolicy )
+ {
+ iRelocationState.ClearAll();
+ delete iContactRelocator;
+ iContactRelocator = NULL;
+ iContactRelocator = CPbk2ContactRelocator::NewL();
+
+ TBool result = EFalse;
+ if (iContactRelocator->IsPhoneMemoryInConfigurationL())
+ {
+ CPbk2ContactRelocator::TFlags flags =
+ CPbk2ContactRelocator::EPbk2RelocatorExistingContact;
+ if ( iParams.iFlags & TPbk2ContactEditorParams::ENewContact )
+ {
+ flags = CPbk2ContactRelocator::EPbk2RelocatorNewContact;
+ }
+
+ result = iContactRelocator->RelocateAndLockContactL(
+ iStoreContact, *this,
+ aQueryPolicy,
+ flags );
+ iStoreContact = NULL; // relocator took away ownership
+ iAddItemFieldTypeResourceId = aAddItemFieldTypeResourceId;
+ if (aAddItemXspName != KNullDesC())
+ {
+ delete iAddItemFieldTypeXspName;
+ iAddItemFieldTypeXspName = NULL;
+ iAddItemFieldTypeXspName = aAddItemXspName.AllocL();
+ }
+ // else not needed because iAddItemFieldTypeXspName is NULL
+
+ /// Dialog must be started again if relocation is done due to
+ /// item addition.
+ if ( iContactRelocator )
+ {
+ iRelocationState.Set( ERelocationDueToItemAddition );
+ }
+ }
+ return result;
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorDlg::IsPhoneMemoryInConfigurationL
+// --------------------------------------------------------------------------
+//
+TBool CPbk2ContactEditorDlg::IsPhoneMemoryInConfigurationL()
+ {
+ CPbk2ContactRelocator* contactRelocator = CPbk2ContactRelocator::NewL();
+ CleanupStack::PushL( contactRelocator );
+ TBool ret = contactRelocator->IsPhoneMemoryInConfigurationL();
+ CleanupStack::PopAndDestroy( contactRelocator );
+ return ret;
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorDlg::IsTemplateFieldL
+// --------------------------------------------------------------------------
+//
+TBool CPbk2ContactEditorDlg::IsTemplateFieldL( TInt aResId,
+ const TDesC& aXSpName )
+ {
+ TBool result( EFalse );
+ const MVPbkFieldType* fieldType =
+ Phonebook2::Pbk2AppUi()->ApplicationServices().ContactManager().
+ FieldTypes().Find( aResId );
+ if ( fieldType )
+ {
+ const MPbk2FieldProperty* fieldProp =
+ iFieldProperties->FindProperty( *fieldType, aXSpName );
+ if ( fieldProp
+ && ( fieldProp->Flags() & KPbk2FieldFlagTemplateField ) )
+ {
+ result = ETrue;
+ }
+ }
+ return result;
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorDlg::EditorReadyL
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactEditorDlg::EditorReadyL()
+ {
+ // Editor is ready
+ if (iAddItemFieldTypeResourceId != KErrNotFound)
+ {
+ TPtrC xSpName = iAddItemFieldTypeXspName ? *iAddItemFieldTypeXspName :
+ KNullDesC();
+ // If new field is template field in relocated contact,
+ // do not add new field. Just focus the field in contact.
+ if ( IsTemplateFieldL( iAddItemFieldTypeResourceId, xSpName ) )
+ {
+ iImplementation->TryChangeFocusWithTypeIdL
+ ( iAddItemFieldTypeResourceId, xSpName );
+ }
+ else
+ {
+ // Lets run the add item dialog silently
+ iImplementation->AddItemToContactL
+ ( iAddItemFieldTypeResourceId, xSpName );
+ }
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorDlg::ContactEditingComplete
+//
+// aEditedContact is commented because it is called from the
+// CPbk2ContactEditorDlgImpl who actually don't own it. So against
+// observer documentation ownership is not changed. This is
+// an implementation detail of
+// CPbk2ContactEditorDlg <-> CPbk2ContactEditorDlgImpl
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactEditorDlg::ContactEditingComplete(
+ MVPbkStoreContact* /*aEditedContact*/ )
+ {
+ // Don't inform observer if the dialog need to be run again
+ if ( !ContinueAfterRelocation() )
+ {
+ // Give ownership of the iStoreContact to the observer
+ MVPbkStoreContact* contact = iStoreContact;
+ iStoreContact = NULL;
+ iContactObserver.ContactEditingComplete( contact );
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorDlg::ContactEditingDeletedContact
+//
+// aEditedContact is commented because it is called from the
+// CPbk2ContactEditorDlgImpl who actually don't own it. So against
+// observer documentation ownership is not changed. This is
+// an implementation detail of
+// CPbk2ContactEditorDlg <-> CPbk2ContactEditorDlgImpl
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactEditorDlg::ContactEditingDeletedContact(
+ MVPbkStoreContact* /*aEditedContact*/ )
+ {
+ // Don't inform observer if the dialog need to be run again
+ if ( !ContinueAfterRelocation() )
+ {
+ // Give ownership of the iStoreContact to the observer
+ MVPbkStoreContact* contact = iStoreContact;
+ iStoreContact = NULL;
+ iContactObserver.ContactEditingDeletedContact( contact );
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorDlg::ContactEditingAborted
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactEditorDlg::ContactEditingAborted()
+ {
+ // Forward from implementation dialog to the actual client
+ iContactObserver.ContactEditingAborted();
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorDlg::HandleRelocationProcessCompleteL
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactEditorDlg::HandleRelocationProcessCompleteL()
+ {
+ if ( !iRelocationState.IsSet( ERelocationCancelled ) &&
+ !iRelocationState.IsSet( ERelocationFailed ) )
+ {
+ // Update contact
+ CreatePresentationContactL();
+
+ // Contact has been relocated which means that the state changes
+ // from creating a new contact to editing an relocated contact.
+
+ // Remove the new contact flag...
+ iParams.iFlags &= ~TPbk2ContactEditorParams::ENewContact;
+ // ... and set the editing flag
+ iParams.iFlags |= TPbk2ContactEditorParams::EModified;
+ // Update strategy
+ delete iEditorStrategy;
+ iEditorStrategy = NULL;
+ iEditorStrategy = Pbk2ContactEditorStrategyFactory::CreateL
+ ( iParams, iContact );
+
+ // Set iFocusedContactField to NULL so that
+ // the right field (new field) will be focused
+ iParams.iFocusedContactField = NULL;
+
+ TBool informObserver = EFalse;
+ if ( !iRelocationState.IsSet( ERelocationDueToItemAddition ) )
+ {
+ informObserver = ETrue;
+ }
+ // Delete current implementation dialog nicely and create
+ // a new dialog in ExecuteLD if needed.
+ iImplementation->CloseWithoutSaving( informObserver );
+ }
+ else
+ {
+ // Reset state if dialog is not closed -> continued with old contact
+ iRelocationState.ClearAll();
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorDlg::CreatePresentationContactL
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactEditorDlg::CreatePresentationContactL()
+ {
+ CreatePresentationContactL( *iStoreContact );
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorDlg::CreatePresentationContactL
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactEditorDlg::CreatePresentationContactL(
+ MVPbkStoreContact& aStoreContact)
+ {
+ delete iSpecificFieldProperties;
+ iSpecificFieldProperties = NULL;
+ delete iFieldProperties;
+ iFieldProperties = NULL;
+
+ const MVPbkFieldTypeList& supportedFieldTypes =
+ aStoreContact.ParentStore().StoreProperties().SupportedFields();
+
+ //If custom fields are provided (social phonebook)
+ if( iEditorFieldsId != KErrNotFound )
+ {
+ HBufC8* res = CCoeEnv::Static()->AllocReadResourceAsDes8L( iEditorFieldsId );
+ CleanupStack::PushL( res );
+ TResourceReader reader;
+ reader.SetBuffer( res );
+ // Create a field property list of the provided fields on reader
+ iFieldProperties = CPbk2FieldPropertyArray::NewL
+ ( supportedFieldTypes, reader, CCoeEnv::Static()->FsSession() );
+ CleanupStack::PopAndDestroy( res );
+ }
+ else
+ {
+ // Create a field property list of the supported
+ // field types of the used store
+ iFieldProperties = CPbk2FieldPropertyArray::NewL
+ ( supportedFieldTypes, CCoeEnv::Static()->FsSession() );
+ }
+
+ // if iAppServices is set. This is used if EditorDlg is used outside of Pbk2 context
+ if( iAppServices )
+ {
+ iSpecificFieldProperties = CPbk2StoreSpecificFieldPropertyArray::NewL
+ ( *iFieldProperties,
+ iAppServices->StoreProperties(),
+ supportedFieldTypes, aStoreContact.ParentStore() );
+ }
+ else
+ {
+ iSpecificFieldProperties = CPbk2StoreSpecificFieldPropertyArray::NewL
+ ( *iFieldProperties,
+ Phonebook2::Pbk2AppUi()->ApplicationServices().StoreProperties(),
+ supportedFieldTypes, aStoreContact.ParentStore() );
+ }
+
+ delete iContact;
+ iContact = NULL;
+ iContact = CPbk2PresentationContact::NewL
+ ( aStoreContact, *iSpecificFieldProperties );
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorDlg::ContinueAfterRelocation
+// --------------------------------------------------------------------------
+//
+TBool CPbk2ContactEditorDlg::ContinueAfterRelocation()
+ {
+ TBool ret = EFalse;
+
+ // Currently 4 ways to continue after relocation:
+ // 1) User cancels relocation -> editor stays open with the OLD contact.
+ // 2) Relocation done due to add item and user approves
+ // relocation -> editor stays open with the NEW contact
+ // 3) Relocation done due to other reason than add item.
+ // User approves relocation -> editor is closed.
+ // 4) Error case
+
+ if ( iRelocationState.IsSet( ERelocationDueToItemAddition ) &&
+ !iRelocationState.IsSet( ERelocationCancelled ) &&
+ !iRelocationState.IsSet( ERelocationFailed ) )
+ {
+ // Continue only in case 2
+ ret = ETrue;
+ }
+
+ return ret;
+ }
+
+// End of File