diff -r 5b6f26637ad3 -r f4a778e096c2 phonebookui/Phonebook2/UIControls/src/CPbk2ContactEditorFieldArray.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/phonebookui/Phonebook2/UIControls/src/CPbk2ContactEditorFieldArray.cpp Wed Sep 01 12:29:52 2010 +0100 @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include "TPbk2ContactEditorParams.h" +#include +#include "CPbk2IconInfo.h" +#include +#include +#include "CPbk2UIFieldArray.h" +#include "CPbk2UIField.h" +#include "Pbk2UIFieldProperty.hrh" +#include "Pbk2AddressTools.h" +#include + + +// Virtual Phonebook +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// System includes +#include +#include +#include +#include + +/// 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* 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 + ( iAppServices->MPbk2ApplicationServicesExtension( + KMPbk2ApplicationServicesExtension2Uid ) ); + } + else + { + // Add xsp service icons + servicesExtension = + reinterpret_cast + ( 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 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 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 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 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