--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookui/Phonebook2/UIControls/src/CPbk2ContactEditorFieldArray.cpp Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,1060 @@
+/*
+* Copyright (c) 2002-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: Phonebook 2 contact editor field array.
+*
+*/
+
+#include "CPbk2ContactEditorFieldArray.h"
+
+// Phonebook 2
+#include "CPbk2ReadingFieldEditorVisitor.h"
+#include "CPbk2IconInfoContainer.h"
+#include "Pbk2ContactEditorFieldFactory.h"
+#include "MPbk2ContactEditorField.h"
+#include "MPbk2ContactEditorUiBuilder.h"
+#include <Pbk2CommonUi.rsg>
+#include <CPbk2PresentationContact.h>
+#include <CPbk2PresentationContactFieldCollection.h>
+#include <CPbk2PresentationContactField.h>
+#include <MPbk2FieldProperty.h>
+#include <Pbk2UIControls.rsg>
+#include <MPbk2AppUi.h>
+#include <CPbk2ServiceManager.h>
+#include "TPbk2ContactEditorParams.h"
+#include <MPbk2ApplicationServices.h>
+#include "CPbk2IconInfo.h"
+#include <aknsutils.h>
+#include <aknlayoutscalable_avkon.cdl.h>
+#include "CPbk2UIFieldArray.h"
+#include "CPbk2UIField.h"
+#include "Pbk2UIFieldProperty.hrh"
+#include "Pbk2AddressTools.h"
+#include <MPbk2ApplicationServices2.h>
+
+
+// Virtual Phonebook
+#include <MVPbkContactStore.h>
+#include <MVPbkContactStoreProperties.h>
+#include <CVPbkFieldTypeSelector.h>
+#include <VPbkEng.rsg>
+#include <MVPbkFieldType.h>
+#include <VPbkFieldType.hrh>
+#include <TVPbkFieldVersitProperty.h>
+#include <MVPbkContactFieldData.h>
+#include <MVPbkContactFieldTextData.h>
+
+
+// System includes
+#include <barsread.h>
+#include <coemain.h>
+#include <AknUtils.h>
+#include <StringLoader.h>
+
+/// Unnamed namespace for local definitions
+namespace {
+
+_LIT( KPbk2UIControlsResFile, "Pbk2UIControls.rsc" );
+
+#ifdef _DEBUG
+
+enum TPanicCode
+ {
+ EPanicInvariant_CountMismatch = 1,
+ EPanicInvariant_FieldNotFound,
+ EPanicInvariant_NotEditableFieldFound,
+ EPanic_AddNewFieldL_OOB,
+ EPanic_GetUiFieldIndex_OOB
+ };
+
+void Panic(TInt aReason)
+ {
+ _LIT(KPanicText, "CPbk2ContactEditorFieldArray");
+ User::Panic(KPanicText, aReason);
+ }
+
+#endif // _DEBUG
+
+/**
+ * Finds property of given type from given contact.
+ *
+ * @param aFieldType Field type to search for.
+ * @param aContact The contact in question.
+ * @return Field property if any.
+ */
+const MPbk2FieldProperty* FindProperty
+ ( const MVPbkFieldType& aType,
+ const CPbk2PresentationContact& aContact )
+ {
+ CArrayPtr<const MPbk2FieldProperty>* props=
+ aContact.AvailableFieldsToAddL();
+ CleanupStack::PushL( props );
+ TInt count( props->Count() );
+ const MPbk2FieldProperty* property = NULL;
+ for ( TInt i = 0; i < count && !property; ++i )
+ {
+ if ( props->At( i )->FieldType().IsSame( aType ) )
+ {
+ property = props->At( i );
+ }
+ }
+ CleanupStack::PopAndDestroy( props );
+ return property;
+ }
+
+/**
+ * Returns maximum number of fields of given type in given contact.
+ *
+ * @param aType Field type in question.
+ * @param aContact Contact in question.
+ * @return Maximum number of fields.
+ */
+TInt MaxNumberOfFieldL
+ ( const MVPbkFieldType& aType,
+ const CPbk2PresentationContact& aContact )
+ {
+ // Get the store limits
+ TInt res = aContact.MaxNumberOfFieldL(aType);
+
+ // If store has no limits or the number is bigger than one
+ // -> check the UI limits
+ const TInt oneFieldInContact = 1;
+ if (res > oneFieldInContact || res == KVPbkStoreContactUnlimitedNumber)
+ {
+ const MPbk2FieldProperty* prop = FindProperty( aType, aContact );
+ if (prop && prop->Multiplicity() == EPbk2FieldMultiplicityOne)
+ {
+ res = oneFieldInContact;
+ }
+ }
+ return res;
+ }
+
+/**
+ * Returns current amount of fields of given type in given contact.
+ *
+ * @param aType Field type in question.
+ * @param aContact Contact in question.
+ * @return Amount of fields.
+ */
+TInt CurrentAmountOfFieldTypeInContact
+ ( const MVPbkFieldType& aType,
+ const CPbk2PresentationContact& aContact )
+ {
+ const TInt maxMatchPriority = aContact.ContactStore().
+ StoreProperties().SupportedFields().MaxMatchPriority();
+
+ const TInt count = aContact.PresentationFields().FieldCount();
+ TInt res = 0;
+ for ( TInt i = 0; i < count; ++i )
+ {
+ const MVPbkStoreContactField& field =
+ aContact.PresentationFields().FieldAt(i);
+ const MVPbkFieldType* type = NULL;
+ for ( TInt j = 0; j < maxMatchPriority && !type; ++j )
+ {
+ type = field.MatchFieldType(j);
+ }
+
+ if ( (aType.IsSame( *type ) ) )
+ {
+ ++res;
+ }
+ }
+ return res;
+ }
+
+/**
+ * Checks is field addition possible.
+ *
+ * @param aType Field type to add.
+ * @param aContact Contact in question.
+ * @return ETrue if field addition is possible.
+ */
+TBool IsFieldAdditionPossibleL
+ ( const MVPbkFieldType& aType,
+ const CPbk2PresentationContact& aContact )
+ {
+ TInt max = MaxNumberOfFieldL(aType, aContact);
+ if (max == KVPbkStoreContactUnlimitedNumber)
+ {
+ return ETrue;
+ }
+ else
+ {
+ TInt cur = CurrentAmountOfFieldTypeInContact( aType, aContact );
+ return cur < max;
+ }
+ }
+
+} /// namespace
+
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorFieldArray::CPbk2ContactEditorFieldArray
+// --------------------------------------------------------------------------
+//
+inline CPbk2ContactEditorFieldArray::CPbk2ContactEditorFieldArray
+ ( CPbk2PresentationContact& aContact,
+ MPbk2ContactEditorUiBuilder& aUiBuilder,
+ CPbk2ContactEditorFieldFactory& aFieldFactory,
+ MPbk2ApplicationServices* aAppServices ) :
+ iContact( aContact ),
+ iUiBuilder( aUiBuilder ),
+ iFieldFactory(aFieldFactory),
+ iAppServices( aAppServices )
+ {
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorFieldArray::~CPbk2ContactEditorFieldArray
+// --------------------------------------------------------------------------
+//
+CPbk2ContactEditorFieldArray::~CPbk2ContactEditorFieldArray()
+ {
+ iFieldArray.ResetAndDestroy();
+ delete iIconInfoContainer;
+ delete iReadingFieldBinder;
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorFieldArray::NewL
+// --------------------------------------------------------------------------
+//
+CPbk2ContactEditorFieldArray* CPbk2ContactEditorFieldArray::NewL
+ ( CVPbkContactManager& aContactManager,
+ CPbk2PresentationContact& aContact,
+ MPbk2ContactEditorUiBuilder& aUiBuilder,
+ CPbk2ContactEditorFieldFactory& aFieldFactory )
+ {
+ CPbk2ContactEditorFieldArray* self =
+ new ( ELeave ) CPbk2ContactEditorFieldArray
+ ( aContact, aUiBuilder, aFieldFactory );
+ CleanupStack::PushL( self );
+ self->ConstructL( aContactManager );
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorFieldArray::NewL
+// --------------------------------------------------------------------------
+//
+CPbk2ContactEditorFieldArray* CPbk2ContactEditorFieldArray::NewL
+ ( CVPbkContactManager& aContactManager,
+ CPbk2PresentationContact& aContact,
+ MPbk2ContactEditorUiBuilder& aUiBuilder,
+ CPbk2ContactEditorFieldFactory& aFieldFactory,
+ MPbk2ApplicationServices* aAppServices )
+ {
+ CPbk2ContactEditorFieldArray* self =
+ new ( ELeave ) CPbk2ContactEditorFieldArray
+ ( aContact, aUiBuilder, aFieldFactory,aAppServices );
+ CleanupStack::PushL( self );
+ self->ConstructL( aContactManager );
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorFieldArray::ConstructL
+// --------------------------------------------------------------------------
+//
+inline void CPbk2ContactEditorFieldArray::ConstructL
+ ( CVPbkContactManager& aContactManager )
+ {
+ iIconInfoContainer = CPbk2IconInfoContainer::NewL
+ ( R_PBK2_ICON_INFO_ARRAY );
+
+ //Calculate preferred size for xsp service icons
+ TRect mainPane;
+ AknLayoutUtils::LayoutMetricsRect(
+ AknLayoutUtils::EMainPane, mainPane );
+ TAknLayoutRect listLayoutRect;
+ listLayoutRect.LayoutRect(
+ mainPane,
+ AknLayoutScalable_Avkon::list_single_graphic_pane_g2(0).LayoutLine() );
+ TSize size(listLayoutRect.Rect().Size());
+
+ /*
+ * Use iAppServices if provided. This is to enable editor use outside from pbk2 context
+ */
+ MPbk2ApplicationServices2* servicesExtension = NULL;
+ if( iAppServices )
+ {
+ // Add xsp service icons
+ servicesExtension =
+ reinterpret_cast<MPbk2ApplicationServices2*>
+ ( iAppServices->MPbk2ApplicationServicesExtension(
+ KMPbk2ApplicationServicesExtension2Uid ) );
+ }
+ else
+ {
+ // Add xsp service icons
+ servicesExtension =
+ reinterpret_cast<MPbk2ApplicationServices2*>
+ ( Phonebook2::Pbk2AppUi()->ApplicationServices().
+ MPbk2ApplicationServicesExtension(
+ KMPbk2ApplicationServicesExtension2Uid ) );
+ }
+
+
+ CPbk2ServiceManager& servMan = servicesExtension->ServiceManager();
+ const CPbk2ServiceManager::RServicesArray& services = servMan.Services();
+ TUid uid;
+ uid.iUid = KPbk2ServManId;
+ for ( TInt i = 0; i < services.Count(); i++ )
+ {
+ const CPbk2ServiceManager::TService& service = services[i];
+ if ( service.iBitmapId && service.iBitmap )
+ {
+ AknIconUtils::SetSize(
+ services[i].iBitmap,
+ size );
+ AknIconUtils::SetSize(
+ services[i].iMask,
+ size );
+ TPbk2IconId id = TPbk2IconId( uid, services[i].iBitmapId );
+ CPbk2IconInfo* info = CPbk2IconInfo::NewLC(
+ id, services[i].iBitmap, services[i].iMask, size );
+ iIconInfoContainer->AppendIconL(info);
+ CleanupStack::Pop(info);
+ }
+ }
+ iReadingFieldBinder = CPbk2ReadingFieldEditorVisitor::NewL
+ ( aContactManager );
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorFieldArray::CreateFieldsFromContactL
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactEditorFieldArray::CreateFieldsFromContactL(TPbk2ContactEditorParams& aParams)
+ {
+ __TEST_INVARIANT;
+ iParams = aParams;
+
+ RArray<TPbk2FieldGroupId> addedGroups;
+ CleanupClosePushL(addedGroups);
+
+
+ CPbk2UIFieldArray* uiArray = CPbk2UIFieldArray::NewL(
+ KPbk2UIControlsResFile, CCoeEnv::Static()->FsSession(), iFieldFactory);
+ CleanupStack::PushL(uiArray);
+
+ TInt nextFreePos = 0;
+ CreateUIFieldL(*uiArray, EPbk2FieldGroupIdNone, EPbk2FieldOrderTop, nextFreePos);
+
+ const TInt count = iContact.PresentationFields().FieldCount();
+ for (TInt i = 0; i < count; ++i)
+ {
+ CPbk2PresentationContactField& contactField =
+ iContact.PresentationFields().At(i);
+
+ if ( contactField.IsEditable() )
+ {
+ if( IsFieldPartOfAddress(contactField) )
+ {
+ if( Pbk2AddressTools::MapViewTypeToAddress(iParams.iActiveView) ==
+ contactField.FieldProperty().GroupId() )
+ {
+ MPbk2ContactEditorField* field =
+ iFieldFactory.CreateFieldLC( contactField, nextFreePos++, *iIconInfoContainer );
+ iFieldArray.AppendL( CPbk2ContactEditorArrayItem::NewL( field ) );
+ CleanupStack::Pop();
+ }
+ else if( iParams.iActiveView == TPbk2ContactEditorParams::EEditorView )
+ {
+ if( addedGroups.Find(contactField.FieldProperty().GroupId()) == KErrNotFound )
+ {
+ CreateUIFieldL(
+ *uiArray,
+ contactField.FieldProperty().GroupId(),
+ (TPbk2FieldOrder)Pbk2AddressTools::MapAddressToOrdering(contactField.FieldProperty().GroupId()),
+ nextFreePos );
+ addedGroups.AppendL(contactField.FieldProperty().GroupId());
+ }
+ }
+ }
+ else if( iParams.iActiveView == TPbk2ContactEditorParams::EEditorView )
+ {
+ MPbk2ContactEditorField* field =
+ iFieldFactory.CreateFieldLC( contactField, nextFreePos, *iIconInfoContainer );
+ if ( field )
+ {
+ nextFreePos++;
+ iFieldArray.AppendL( CPbk2ContactEditorArrayItem::NewL( field ) );
+ CleanupStack::Pop();
+ }
+ }
+ }
+ }
+
+ CreateUIFieldL(*uiArray, EPbk2FieldGroupIdNone, EPbk2FieldOrderBottom, nextFreePos);
+
+ AcceptL(*iReadingFieldBinder);
+ CleanupStack::PopAndDestroy(uiArray);
+ CleanupStack::PopAndDestroy(&addedGroups);
+ __TEST_INVARIANT;
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorFieldArray::CreateUIFieldL
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactEditorFieldArray::CreateUIFieldL(
+ CPbk2UIFieldArray& aFieldsArr,
+ TPbk2FieldGroupId aAddressGroup,
+ TPbk2FieldOrder aOrder,
+ TInt& aNextFreePos )
+ {
+ if( aOrder == EPbk2FieldOrderUndefinied )
+ {
+ return;
+ }
+
+ for(TInt idx = 0; idx < aFieldsArr.Count(); idx++)
+ {
+ MPbk2UIField& field = aFieldsArr.At(idx);
+ if( field.Order() == aOrder )
+ {
+ if( iParams.iActiveView == TPbk2ContactEditorParams::EEditorView &&
+ field.CtrlType() == EPbk2FieldCtrlTypeExtAssignFromMapsEditor )
+ {
+ continue;
+ }
+ RBuf text;
+ TBool textAlloc = EFalse;
+ if( aAddressGroup == EPbk2FieldGroupIdPostalAddress ||
+ aAddressGroup == EPbk2FieldGroupIdHomeAddress ||
+ aAddressGroup == EPbk2FieldGroupIdCompanyAddress )
+ {
+ Pbk2AddressTools::GetAddressPreviewLC( iContact.StoreContact(), aAddressGroup, text );
+ textAlloc = ETrue;
+ }
+ MPbk2ContactEditorUIField* cefield =
+ iFieldFactory.CreateFieldLC(field, aNextFreePos, iUiBuilder, text, *iIconInfoContainer);
+ if( cefield )
+ {
+ aFieldsArr.RemoveAt(idx);
+ iFieldArray.AppendL(CPbk2ContactEditorArrayItem::NewL(cefield));
+ CleanupStack::Pop(cefield);
+ aNextFreePos++;
+ }
+ if ( textAlloc )
+ {
+ CleanupStack::PopAndDestroy(); //text
+ }
+ else
+ {
+ text.Close();
+ }
+ break;
+ }
+ }
+ }
+
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorFieldArray::UpdateControlsL
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactEditorFieldArray::UpdateControlsL()
+ {
+ const TInt count = iFieldArray.Count();
+ for(TInt i = 0; i < count; ++i)
+ {
+ if( iFieldArray[i]->ContactEditorUIField() &&
+ iFieldArray[i]->ContactEditorUIField()->UIField()->CtrlType() !=
+ EPbk2FieldCtrlTypeExtAssignFromMapsEditor )
+ {
+ RBuf text;
+ Pbk2AddressTools::GetAddressPreviewLC( iContact.StoreContact(),
+ Pbk2AddressTools::MapCtrlTypeToAddress(
+ iFieldArray[i]->ContactEditorUIField()->UIField()->CtrlType()), text );
+
+ iFieldArray[i]->ContactEditorUIField()->SetControlTextL(text);
+ CleanupStack::PopAndDestroy(); //text
+ }
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorFieldArray::IsEditorFieldControlEmpty
+// --------------------------------------------------------------------------
+//
+TBool CPbk2ContactEditorFieldArray::IsEditorFieldControlEmpty( TInt aIndex ) const
+ {
+ TBool result = ETrue;
+ const TInt count = iFieldArray.Count();
+ if ( aIndex >= count )
+ {
+ return result;
+ }
+
+ if ( iFieldArray[aIndex]->ContactEditorField() )
+ {
+ HBufC* text = NULL;
+ TRAP_IGNORE( text = iFieldArray[aIndex]->ContactEditorField()->ControlTextL() );
+ TInt fld = iFieldArray[aIndex]->ContactEditorField()->FieldProperty().FieldType().FieldTypeResId();
+
+ if ( fld != R_VPBK_FIELD_TYPE_RINGTONE &&
+ fld != R_VPBK_FIELD_TYPE_THUMBNAILPIC &&
+ fld != R_VPBK_FIELD_TYPE_CALLEROBJIMG )
+ {
+ if ( text && text->Length() > 0 )
+ {
+ // If Fields contain only spaces; then treat field as empty field
+ text->Des().TrimAll();
+ if ( text->Length() > 0 )
+ {
+ result = EFalse;
+ }
+ }
+ }
+
+ delete text;
+ text = NULL;
+ }
+
+ return result;
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorFieldArray::IsEditorUiFieldControlEmpty
+// --------------------------------------------------------------------------
+//
+TBool CPbk2ContactEditorFieldArray::IsEditorUiFieldControlEmpty( TInt aIndex ) const
+ {
+ TBool result = ETrue;
+
+ const TInt count = iFieldArray.Count();
+ if ( aIndex >= count )
+ {
+ return result;
+ }
+
+ if( iFieldArray[aIndex]->ContactEditorUIField() )
+ {
+ TInt type = iFieldArray[aIndex]->ContactEditorUIField()->UIField()->CtrlType();
+ if( type == EPbk2FieldCtrlTypeExtAddressEditor
+ || type == EPbk2FieldCtrlTypeExtAddressHomeEditor
+ || type == EPbk2FieldCtrlTypeExtAddressOfficeEditor )
+ {
+ TPtrC* data = NULL;
+ RHashMap<TInt, TPtrC> aFieldsMap;
+
+ Pbk2AddressTools::GetAddressFieldsLC( iContact.StoreContact(),
+ Pbk2AddressTools::MapCtrlTypeToAddress(
+ iFieldArray[aIndex]->ContactEditorUIField()->UIField()->CtrlType() ), aFieldsMap );
+
+ for(TInt addrType = EVPbkVersitSubFieldPostOfficeAddress; addrType <= EVPbkVersitSubFieldCountry; addrType++ )
+ {
+ data = aFieldsMap.Find( addrType );
+ if(data && data->Length() > 0 )
+ {
+ result= EFalse;
+ }
+ }
+
+ CleanupStack::PopAndDestroy( &aFieldsMap );
+ }
+ }
+ return result;
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorFieldArray::SaveFieldsL
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactEditorFieldArray::SaveFieldsL()
+ {
+ const TInt count = iFieldArray.Count();
+ for(TInt i = 0; i < count; ++i)
+ {
+ if( iFieldArray[i]->ContactEditorField() )
+ {
+ iFieldArray[i]->ContactEditorField()->SaveFieldL();
+ }
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorFieldArray::FieldsChanged
+// --------------------------------------------------------------------------
+//
+TBool CPbk2ContactEditorFieldArray::FieldsChanged() const
+ {
+ TBool result = EFalse;
+ for (TInt i = 0; i < iFieldArray.Count(); ++i)
+ {
+ if ( iFieldArray[i]->ContactEditorField() &&
+ iFieldArray[i]->ContactEditorField()->FieldDataChanged() )
+ {
+ result = ETrue;
+ }
+ // can break because at least one field has changed
+ if (result)
+ {
+ break;
+ }
+ }
+ return result;
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorFieldArray::AreAllUiFieldsEmpty
+// --------------------------------------------------------------------------
+//
+TBool CPbk2ContactEditorFieldArray::AreAllUiFieldsEmpty() const
+ {
+ TBool result(ETrue);
+ const TInt count = iFieldArray.Count();
+
+ for(TInt i = 0; i < count && result; ++i)
+ {
+ if( iFieldArray[i]->ContactEditorField() )
+ {
+ result = IsEditorFieldControlEmpty( i );
+ }
+
+ // if not managed in ContactEditorField, judge whether available in ContactEditorUIField
+ else if( iFieldArray[i]->ContactEditorUIField() )
+ {
+ result = IsEditorUiFieldControlEmpty( i );
+ }
+ }
+ return result;
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorFieldArray::SetFocus
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactEditorFieldArray::SetFocus(TInt aFieldIndex)
+ {
+ if (aFieldIndex >= 0 && aFieldIndex < iFieldArray.Count())
+ {
+ iFieldArray[aFieldIndex]->SetFocus();
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorFieldArray::Find
+// --------------------------------------------------------------------------
+//
+CPbk2ContactEditorArrayItem* CPbk2ContactEditorFieldArray::Find
+ ( TInt aControlId )
+ {
+ const TInt count = iFieldArray.Count();
+ for (TInt i = 0; i < count; ++i)
+ {
+ if (iFieldArray[i]->ControlId() == aControlId)
+ {
+ return iFieldArray[i];
+ }
+ }
+ return NULL;
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorFieldArray::FindIndex
+// --------------------------------------------------------------------------
+//
+TInt CPbk2ContactEditorFieldArray::FindIndex
+ ( TInt aControlId )
+ {
+ const TInt count = iFieldArray.Count();
+ for (TInt i = 0; i < count; ++i)
+ {
+ if (iFieldArray[i]->ControlId() == aControlId)
+ {
+ return i;
+ }
+ }
+ return KErrArgument;
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorFieldArray::AddNewFieldL
+// --------------------------------------------------------------------------
+//
+TInt CPbk2ContactEditorFieldArray::AddNewFieldL
+ ( const MVPbkFieldType& aFieldType)
+ {
+ return AddNewFieldL(aFieldType, KNullDesC);
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorFieldArray::AddNewFieldL
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactEditorFieldArray::AddNewFieldL
+ ( const TPbk2FieldGroupId aAddressGroup )
+ {
+ CPbk2UIFieldArray* uiArray = CPbk2UIFieldArray::NewL(
+ KPbk2UIControlsResFile, CCoeEnv::Static()->FsSession(), iFieldFactory);
+ CleanupStack::PushL(uiArray);
+
+ TInt uiIndex = GetUiFieldIndex(aAddressGroup);
+
+ // Before adding a new field the focus must be on the previous item
+ TInt focusIndex = uiIndex - 1;
+ SetFocus(focusIndex);
+
+ for(TInt idx = 0; idx < uiArray->Count(); idx++)
+ {
+ MPbk2UIField& field = uiArray->At(idx);
+ if( aAddressGroup == Pbk2AddressTools::MapCtrlTypeToAddress( field.CtrlType() ) )
+ {
+ MPbk2ContactEditorUIField* cefield =
+ iFieldFactory.CreateFieldLC(field, uiIndex, iUiBuilder, KNullDesC(), *iIconInfoContainer);
+ if( cefield )
+ {
+ uiArray->RemoveAt(idx);
+ iFieldArray.InsertL( CPbk2ContactEditorArrayItem::NewL(cefield), uiIndex );
+ cefield->ActivateL();
+ CleanupStack::Pop(cefield);
+ }
+ break;
+ }
+ }
+
+ CleanupStack::PopAndDestroy(uiArray);
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorFieldArray::AddNewFieldL
+// --------------------------------------------------------------------------
+//
+TInt CPbk2ContactEditorFieldArray::AddNewFieldL
+ ( const MVPbkFieldType& aFieldType, const TDesC& aName )
+ {
+ __TEST_INVARIANT;
+
+ // Check first is field adding possible. If there already is max amount
+ // of this type fields, leave with KErrNotSupported.
+ if ( !IsFieldAdditionPossibleL( aFieldType, iContact ) )
+ {
+ User::Leave( KErrNotSupported );
+ }
+
+
+ MVPbkStoreContactField* storeField = iContact.CreateFieldLC(aFieldType);
+ TInt index = iContact.AddFieldL(storeField, aName);
+ CleanupStack::Pop( storeField );
+
+ TArray<TVPbkFieldVersitProperty> propArr = aFieldType.VersitProperties();
+ TInt count = propArr.Count();
+ TBool addrProp = EFalse;
+ for( TInt idx = 0; idx < count; idx++)
+ {
+ if( propArr[idx].Name() == EVPbkVersitNameADR )
+ {
+ addrProp = ETrue;
+ }
+ }
+ if( iParams.iActiveView == TPbk2ContactEditorParams::EEditorView && addrProp )
+ {
+ return KErrNone;
+ }
+
+ TInt uiIndex = GetUiFieldIndex(index);
+
+ // Before adding a new field the focus must be on the previous item
+ TInt focusIndex = uiIndex - 1;
+ SetFocus(focusIndex);
+
+ __ASSERT_DEBUG( iContact.PresentationFields().FieldCount() > index,
+ Panic( EPanic_AddNewFieldL_OOB ) );
+ MPbk2ContactEditorField* uiField = iFieldFactory.CreateFieldLC(
+ iContact.PresentationFields().At(index), NULL, *iIconInfoContainer);
+ iFieldArray.InsertL(CPbk2ContactEditorArrayItem::NewL(uiField), uiIndex);
+ CleanupStack::Pop();
+ // The first SetFocus is needed.
+ // Otherwise the added focused field can be outside of screen.
+ SetFocus( 0 );
+ SetFocus( uiIndex );
+ uiField->AcceptL(*iReadingFieldBinder);
+ uiField->ActivateL();
+
+ __TEST_INVARIANT;
+ return uiField->ControlId();
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorFieldArray::RemoveField
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactEditorFieldArray::RemoveField
+ ( CPbk2ContactEditorArrayItem& aField )
+ {
+ __TEST_INVARIANT;
+ const TInt count = iFieldArray.Count();
+ for (TInt i = 0; i < count; ++i)
+ {
+ CPbk2ContactEditorArrayItem* field = iFieldArray[i];
+ if (field == &aField)
+ {
+ iUiBuilder.DeleteControl(field->ControlId());
+ if( field->ContactEditorField() )
+ {
+ TInt index = iContact.PresentationFields().FindFieldIndex(
+ field->ContactEditorField()->ContactField());
+ iContact.RemoveField(index);
+ iFieldArray.Remove(i);
+ delete field;
+ }
+ else if( field->ContactEditorUIField() )
+ {
+ TPbk2FieldGroupId groupId =
+ Pbk2AddressTools::MapCtrlTypeToAddress(
+ field->ContactEditorUIField()->UIField()->CtrlType() );
+ iFieldArray.Remove(i);
+ delete field;
+
+ if( groupId == EPbk2FieldGroupIdNone )
+ {
+ break;
+ }
+
+ CPbk2PresentationContactFieldCollection& fields = iContact.PresentationFields();
+ TBool removed = EFalse;
+ for(TInt idx = 0; idx < fields.FieldCount() && !removed; idx++)
+ {
+ MVPbkStoreContactField& storeField = fields.FieldAt(idx);
+ TInt countProps =
+ storeField.BestMatchingFieldType()->VersitProperties().Count();
+ TArray<TVPbkFieldVersitProperty> props =
+ storeField.BestMatchingFieldType()->VersitProperties();
+ for( TInt idx2 = 0; idx2 < countProps && !removed; idx2++ )
+ {
+ if ( props[ idx2 ].Name() == EVPbkVersitNameGEO &&
+ ( ( props[ idx2 ].Parameters().Contains( EVPbkVersitParamHOME ) &&
+ groupId == EPbk2FieldGroupIdHomeAddress ) ||
+ ( props[ idx2 ].Parameters().Contains( EVPbkVersitParamWORK ) &&
+ groupId == EPbk2FieldGroupIdCompanyAddress ) ||
+ ( !props[ idx2 ].Parameters().Contains( EVPbkVersitParamHOME ) &&
+ !props[ idx2 ].Parameters().Contains( EVPbkVersitParamWORK ) &&
+ groupId == EPbk2FieldGroupIdPostalAddress ) ) )
+ {
+ iContact.RemoveField(idx);
+ removed = ETrue;
+ }
+ }
+ }
+
+ for( TInt idx = fields.FieldCount() - 1; idx >= 0 ; idx-- )
+ {
+ if( groupId == fields.At( idx ).FieldProperty().GroupId() )
+ {
+ iContact.RemoveField(idx);
+ }
+ }
+ }
+ break;
+ }
+ }
+ __TEST_INVARIANT;
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorFieldArray::RemoveFieldFromUI
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactEditorFieldArray::RemoveFieldFromUI( TInt aIndex )
+ {
+ __TEST_INVARIANT;
+ CPbk2ContactEditorArrayItem* field = iFieldArray[aIndex];
+ iUiBuilder.DeleteControl(field->ControlId());
+ iFieldArray.Remove(aIndex);
+ delete field;
+ __TEST_INVARIANT;
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorFieldArray::GetUiFieldIndex
+// The fields are in the same order in the ui and in the contact.
+// The difference is that ui has only editable fields while contact can have
+// not editable fields too and for every address all address fields are
+// joined into one field.
+// --------------------------------------------------------------------------
+//
+inline TInt CPbk2ContactEditorFieldArray::GetUiFieldIndex
+ ( TInt aContactFieldIndex )
+ {
+ TPbk2FieldGroupId previousGroupId = EPbk2FieldGroupIdNone;
+ TInt result = aContactFieldIndex;
+ for (TInt i = aContactFieldIndex - 1; i >= 0; --i)
+ {
+ __ASSERT_DEBUG( iContact.PresentationFields().FieldCount() > i,
+ Panic( EPanic_GetUiFieldIndex_OOB ) );
+ CPbk2PresentationContactField& contactField =
+ iContact.PresentationFields().At(i);
+
+ if (!contactField.IsEditable())
+ {
+ --result;
+ continue;
+ }
+
+ if(TPbk2ContactEditorParams::EEditorView && IsFieldPartOfAddress(contactField))
+ {
+ if(contactField.FieldProperty().GroupId() == previousGroupId)
+ {
+ //Every address has one button, if address has 'n' fields we must remove 'n-1'
+ --result;
+ }
+ previousGroupId = contactField.FieldProperty().GroupId();
+ }
+ }
+
+ return result;
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorFieldArray::GetUiFieldIndex
+// The fields are in the same order in the ui and in the contact.
+// The difference is that ui has only editable fields while contact can have
+// not editable fields too and for every address all address fields are
+// joined into one field.
+// --------------------------------------------------------------------------
+//
+inline TInt CPbk2ContactEditorFieldArray::GetUiFieldIndex
+ ( TPbk2FieldGroupId aContactAddressGroupID )
+ {
+ TPbk2FieldGroupId previousGroupId = EPbk2FieldGroupIdNone;
+ TInt result = KErrNone;
+ for (TInt i = iContact.PresentationFields().FieldCount() - 1; i >= 0; --i)
+ {
+ __ASSERT_DEBUG( iContact.PresentationFields().FieldCount() > i,
+ Panic( EPanic_GetUiFieldIndex_OOB ) );
+ CPbk2PresentationContactField& contactField =
+ iContact.PresentationFields().At(i);
+
+ if (!contactField.IsEditable() && result != KErrNone)
+ {
+ --result;
+ continue;
+ }
+
+ if(TPbk2ContactEditorParams::EEditorView && IsFieldPartOfAddress(contactField))
+ {
+ if(contactField.FieldProperty().GroupId() == previousGroupId)
+ {
+ if(result != KErrNone)
+ {
+ //Every address has one button, if address has 'n' fields we must remove 'n-1'
+ --result;
+ }
+ }
+ else if(previousGroupId == aContactAddressGroupID)
+ {
+ //Start counting down from first address field position in CPbk2PresentationContact
+ result = i + 1;
+ }
+ previousGroupId = contactField.FieldProperty().GroupId();
+ }
+ else if(previousGroupId != EPbk2FieldGroupIdNone)
+ {
+ if(previousGroupId == aContactAddressGroupID)
+ {
+ //Start counting down from first address field position in CPbk2PresentationContact
+ result = i + 1;
+ }
+ previousGroupId = EPbk2FieldGroupIdNone;
+ }
+ }
+
+ return result;
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorFieldArray::AcceptL
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactEditorFieldArray::AcceptL
+ ( MPbk2ContactEditorFieldVisitor& aVisitor )
+ {
+ const TInt count = iFieldArray.Count();
+ for (TInt i = 0; i < count; ++i)
+ {
+ if( iFieldArray[i]->ContactEditorField() )
+ {
+ iFieldArray[i]->ContactEditorField()->AcceptL(aVisitor);
+ }
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorFieldArray::__DbgTestInvariant
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactEditorFieldArray::__DbgTestInvariant() const
+ {
+ #if defined(_DEBUG)
+ const TInt fieldCount = iContact.Fields().FieldCount();
+ TInt editableFields = 0;
+ for (TInt i = 0; i < fieldCount; ++i)
+ {
+ if (iContact.PresentationFields().At(i).IsEditable())
+ {
+ ++editableFields;
+ }
+ }
+ __ASSERT_DEBUG(iFieldArray.Count() <= editableFields,
+ Panic(EPanicInvariant_CountMismatch));
+
+ const TInt uiCount = iFieldArray.Count();
+ const TInt storeFieldCount = iContact.StoreContact().Fields().FieldCount();
+ for (TInt i = 0; i < uiCount; ++i)
+ {
+ if( !iFieldArray[i]->ContactEditorField() )
+ {
+ continue;
+ }
+
+ __ASSERT_DEBUG( !( iFieldArray[i]->ContactEditorField()->FieldProperty().Flags() &
+ KPbk2FieldFlagDisableEdit ),
+ Panic(EPanicInvariant_NotEditableFieldFound));
+
+ TBool result = EFalse;
+ for (TInt j = 0; j < storeFieldCount && !result; ++j)
+ {
+ MVPbkStoreContactField& field =
+ iContact.StoreContact().Fields().FieldAt( j );
+ if ( iFieldArray[i]->ContactEditorField()->ContactField().IsSame( field ) )
+ {
+ result = ETrue;
+ }
+ }
+ __ASSERT_DEBUG(result, Panic(EPanicInvariant_FieldNotFound));
+ }
+ #endif // _DEBUG
+ }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactEditorFieldArray::IsFieldPartOfAddress
+// --------------------------------------------------------------------------
+//
+TBool CPbk2ContactEditorFieldArray::IsFieldPartOfAddress
+ ( CPbk2PresentationContactField& aField )
+ {
+ if( aField.FieldProperty().GroupId() == EPbk2FieldGroupIdPostalAddress ||
+ aField.FieldProperty().GroupId() == EPbk2FieldGroupIdHomeAddress ||
+ aField.FieldProperty().GroupId() == EPbk2FieldGroupIdCompanyAddress )
+ return ETrue;
+ return EFalse;
+ }
+// End of File