--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookui/Phonebook/Engine/src/CPbkContactItemOld.cpp Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,1600 @@
+/*
+* 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:
+* Phonebook Contact item class
+*
+*/
+
+
+// INCLUDE FILES
+#include "CPbkContactItem.h"
+#include <cntfield.h> // CContactItemField
+#include <cntitem.h> // CContactItem
+#include <FeatMgr.h> // Feature manager
+#include <CPbkSINDHandlerInterface.h>
+#include "CPbkFieldsInfo.h"
+#include "CPbkFieldInfo.h"
+#include "TPbkContactItemField.h"
+#include "PbkFields.hrh"
+#include <PbkEngUtils.h>
+#include <pbkdebug.h>
+#include "PbkDefaults.h"
+#include <MPbkContactNameFormat.h>
+#include "TPbkMatchPriorityLevel.h"
+#include "CPbkContactEngine.h"
+#include "cpbkenginelocalstorage.h"
+#include "CPbkSyncronizationConstants.h"
+
+#ifdef _DEBUG
+// Engine needed only for a few asserts
+#include "CPbkContactEngine.h"
+#endif
+
+// Unnamed namespace for local definitions
+
+namespace {
+
+// LOCAL CONSTANTS AND MACROS
+enum TPanicCode
+ {
+ EPanicPostCond_Constructor = 1,
+ EPanicPreCond_ConstructL,
+ EPanicInvariant_Pointer,
+ EPanicInvariant_Count,
+ EPanicInvariant_Field,
+ EPanicInvariant_FieldInfo,
+ EPanicInvariant_Sorting,
+ EPanicInvariant_PrefCount,
+ EPanicInvariant_SmsCount,
+ EPanicInvariant_PrefSmsCount,
+ EPanicInvariant_PhoneDefaultCount,
+ EPanicInvariant_SmsDefaultCount,
+ EPanicInvariant_EmailDefaultCount,
+ EPanicInvariant_VideoTagCount,
+ EPanicPostCond_FindFieldIndex,
+ EPanicPreCond_RemoveField,
+ EPanicLogic_RemoveField,
+ EPanicPostCond_RemoveField,
+ EPanicPostCond_AddFieldL,
+ EPanicPreCond_GroupsJoinedLC,
+ EPanicPostCond_SetDefaultPhoneNumberFieldL,
+ EPanicPostCond_SetDefaultVideoNumberFieldL,
+ EPanicPostCond_SetDefaultEmailFieldL,
+ EPanicPreCond_UpdateFieldSetL,
+ EPanicPostCond_InsertionPos,
+ EPanicPostCond_SetVoiceTagFieldL,
+ EPanicInvariant_VoiceTagCount,
+ EPanicInvariant_VoiceTagFieldCount,
+ EPanicPostCond_SetDefaultMmsFieldL,
+ EPanicPostCond_SetDefaultEmailOverSmsFieldL,
+ EPanicPostCond_SetDefaultPocFieldL,
+ EPanicPostCond_SetDefaultVoipFieldL,
+ EPanicPreCond_VoiceTagField1,
+ EPanicPreCond_VoiceTagField2,
+ EPanicPreCond_LoadSindHandlerImplL
+ };
+
+// ==================== LOCAL FUNCTIONS ====================
+
+void Panic(TPanicCode aReason)
+ {
+ _LIT(KPanicText, "CPbkContactItem");
+ User::Panic(KPanicText, aReason);
+ }
+
+/**
+ * Searches a field set for the first field with type specified type.
+ *
+ * @param aFields the field set to search.
+ * @param aFieldInfo the field type to search for.
+ * @param aIndex index where to start the search.
+ * @return index of the matching field in aFields or KErrNotFound if not found.
+ */
+TInt FindFieldWithType
+ (const CPbkFieldArray& aFields,
+ const CPbkFieldInfo& aFieldInfo,
+ TInt aIndex=0)
+ {
+ const TInt fieldCount = aFields.Count();
+ for (TInt i=aIndex; i < fieldCount; ++i)
+ {
+ if (aFields[i].FieldInfo().IsSame(aFieldInfo))
+ {
+ return i;
+ }
+ }
+ return KErrNotFound;
+ }
+
+inline void LoadSindHandlerImplL(TUid& aDtorIDKey,
+ CPbkSINDHandlerInterface*& aSINDHandler)
+ {
+ // Check does the SIND handler implementation exist:
+ TUid interfaceUid = {KPbkSINDHandlerInterfaceUID};
+ RImplInfoPtrArray pluginArray;
+ REComSession::ListImplementationsL( interfaceUid ,pluginArray );
+ __ASSERT_DEBUG(pluginArray.Count() == 1, Panic(EPanicPreCond_LoadSindHandlerImplL));
+ if ( pluginArray.Count() > 0 )
+ {
+ // There should be only one implementation for SIND handler and
+ // we would like to use that one
+ TUid SINDHandlerImpUid = {KPbkSINDHandlerPluginUID};
+
+ aSINDHandler = static_cast<CPbkSINDHandlerInterface*>
+ (REComSession::CreateImplementationL(SINDHandlerImpUid ,aDtorIDKey));
+ }
+ pluginArray.ResetAndDestroy();
+ }
+
+} // namespace
+
+
+// ================= MEMBER FUNCTIONS =======================
+
+/**
+ * C++ constructor.
+ */
+inline CPbkContactItem::CPbkContactItem(MPbkContactNameFormat& aNameFormat) :
+ iNameFormat(aNameFormat)
+ {
+ // new(ELeave) in NewL will reset members
+ __ASSERT_DEBUG(!iItem, Panic(EPanicPostCond_Constructor));
+ }
+
+/**
+ * Second phase constructor.
+ */
+inline void CPbkContactItem::ConstructL
+ (CContactItem* aItem,
+ const CPbkFieldsInfo& aFieldsInfo)
+ {
+ //PreCond:
+ __ASSERT_DEBUG(aItem && !iItem, Panic(EPanicPreCond_ConstructL));
+
+ CreateFieldArrayL(*aItem, aFieldsInfo);
+ // construction was succesful, take ownership of aItem
+ iItem = aItem;
+
+ // Philosophical note: class invariant is effectively a postcondition
+ // for a constructor.
+ __TEST_INVARIANT;
+ }
+
+EXPORT_C CPbkContactItem* CPbkContactItem::NewL
+ (CContactItem* aItem,
+ const CPbkFieldsInfo& aFieldsInfo,
+ MPbkContactNameFormat& aNameFormat)
+ {
+ CPbkContactItem* self = new(ELeave) CPbkContactItem(aNameFormat);
+ CleanupStack::PushL(self);
+ self->ConstructL(aItem, aFieldsInfo);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CPbkContactItem::~CPbkContactItem()
+ {
+#ifdef _DEBUG
+ // Test invariant only at the beginning of destructor and only if
+ // construction was succesful.
+ if (iItem)
+ __TEST_INVARIANT;
+#endif
+
+ // Delete own data
+ delete iItem;
+ }
+
+EXPORT_C CContactItem& CPbkContactItem::ContactItem()
+ {
+ return *iItem;
+ }
+
+EXPORT_C const CContactItem& CPbkContactItem::ContactItem() const
+ {
+ return *iItem;
+ }
+
+EXPORT_C HBufC* CPbkContactItem::GetContactTitleL() const
+ {
+ __TEST_INVARIANT;
+
+ // Delegate call to iNameFormat
+ return iNameFormat.GetContactTitleL(*this);
+ }
+
+EXPORT_C HBufC* CPbkContactItem::GetContactTitleOrNullL() const
+ {
+ __TEST_INVARIANT;
+
+ // Delegate call to iNameFormat
+ return iNameFormat.GetContactTitleOrNullL(*this);
+ }
+
+EXPORT_C TPbkIconId CPbkContactItem::ContactIconIdL() const
+ {
+ __TEST_INVARIANT;
+
+ TPbkContactItemField* field = DefaultPhoneNumberField();
+ if (field)
+ {
+ return field->IconId();
+ }
+ return EPbkNullIconId;
+ }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::DefaultPhoneNumberField() const
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+ // scan the fields for a match in default field for field id.
+ const TInt fieldCount = iFields.Count();
+ for(TInt i=0; i < fieldCount; ++i)
+ {
+ if (iFields[i].DefaultPhoneNumberField())
+ {
+ return const_cast<TPbkContactItemField*>(&(iFields[i]));
+ }
+ }
+ return NULL;
+ }
+
+EXPORT_C void CPbkContactItem::SetDefaultPhoneNumberFieldL
+ (TPbkContactItemField* aField)
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+ if (aField)
+ {
+ aField = FindSameField(*aField);
+ if (!aField)
+ {
+ // Not this item's field
+ User::Leave(KErrNotFound);
+ }
+ }
+
+ // Test can we set the default for this field
+ if (aField && !aField->FieldInfo().IsPhoneNumberField())
+ {
+ User::Leave(KErrNotSupported);
+ }
+
+ // 1. Fetch previous default
+ TPbkContactItemField* prevDefault = DefaultPhoneNumberField();
+
+ // 2. Set the new default, if specified
+ if (aField)
+ {
+ if (prevDefault == aField)
+ {
+ // Default already set to aField
+ return;
+ }
+ // If this leaves, this object's state remains unchanged
+ aField->ItemField().AddFieldTypeL(KUidPbkDefaultFieldPref);
+ }
+
+ // 3. Unset any previous default (invariant tests that there is always just
+ // one default.
+ if (prevDefault)
+ {
+ // Unset previous default
+ prevDefault->ItemField().RemoveFieldType(KUidPbkDefaultFieldPref);
+ }
+
+ __ASSERT_DEBUG(
+ (aField && DefaultPhoneNumberField()==aField) ||
+ (!aField && !DefaultPhoneNumberField()),
+ Panic(EPanicPostCond_SetDefaultPhoneNumberFieldL));
+ }
+
+EXPORT_C void CPbkContactItem::RemoveDefaultPhoneNumberField()
+ {
+ // This is safe because SetDefaultPhoneNumberFieldL(NULL)
+ // guarantees not to leave
+ SetDefaultPhoneNumberFieldL(NULL);
+ }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::DefaultVideoNumberField() const
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+ // scan the fields for a match in default field for field id.
+ const TInt fieldCount = iFields.Count();
+ for(TInt i=0; i < fieldCount; ++i)
+ {
+ if (iFields[i].DefaultVideoNumberField())
+ {
+ return const_cast<TPbkContactItemField*>(&(iFields[i]));
+ }
+ }
+ return NULL;
+ }
+
+EXPORT_C void CPbkContactItem::SetDefaultVideoNumberFieldL
+ (TPbkContactItemField* aField)
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+ if (aField)
+ {
+ aField = FindSameField(*aField);
+ if (!aField)
+ {
+ // Not this item's field
+ User::Leave(KErrNotFound);
+ }
+ }
+
+ // Test can we set the default for this field
+ if (aField && !aField->FieldInfo().IsPhoneNumberField())
+ {
+ User::Leave(KErrNotSupported);
+ }
+
+ // 1. Fetch previous default
+ TPbkContactItemField* prevDefault = DefaultVideoNumberField();
+
+ // 2. Set the new default, if specified
+ if (aField)
+ {
+ if (prevDefault == aField)
+ {
+ // Default already set to aField
+ return;
+ }
+ // If this leaves, this object's state remains unchanged
+ aField->ItemField().AddFieldTypeL(KUidPbkDefaultFieldVideo);
+ }
+
+ // 3. Unset any previous default (invariant tests that there is always just
+ // one default.
+ if (prevDefault)
+ {
+ // Unset previous default
+ prevDefault->ItemField().RemoveFieldType(KUidPbkDefaultFieldVideo);
+ }
+
+ __ASSERT_DEBUG(
+ (aField && DefaultVideoNumberField()==aField) ||
+ (!aField && !DefaultVideoNumberField()),
+ Panic(EPanicPostCond_SetDefaultVideoNumberFieldL));
+ }
+
+EXPORT_C void CPbkContactItem::RemoveDefaultVideoNumberField()
+ {
+ // This is safe because SetDefaultPhoneNumberFieldL(NULL)
+ // guarantees not to leave
+ SetDefaultVideoNumberFieldL(NULL);
+ }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::DefaultSmsField() const
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+ const TInt fieldCount = iFields.Count();
+ for (TInt i=0; i < fieldCount; ++i)
+ {
+ const TPbkContactItemField& field = iFields[i];
+ if (field.DefaultSmsField())
+ {
+ return const_cast<TPbkContactItemField*>(&field);
+ }
+ }
+ return NULL;
+ }
+
+EXPORT_C void CPbkContactItem::SetDefaultSmsFieldL
+ (TPbkContactItemField* aField)
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+ if (aField)
+ {
+ aField = FindSameField(*aField);
+ if (!aField)
+ {
+ // Not this item's field
+ User::Leave(KErrNotFound);
+ }
+ }
+
+ // Test can we set the default for this field
+ if (aField && !aField->FieldInfo().IsPhoneNumberField())
+ {
+ User::Leave(KErrNotSupported);
+ }
+
+ // 1. Fetch previous default
+ TPbkContactItemField* prevDefault = DefaultSmsField();
+
+ // 2. Set the new default if specified
+ if (aField)
+ {
+ if (aField == prevDefault)
+ {
+ // Already set
+ return;
+ }
+ // If this leaves, this object's state remains unchanged
+ aField->ItemField().AddFieldTypeL(KUidPbkDefaultFieldSms);
+ }
+
+ // 3. Unset any previous default (invariant tests that there is always just
+ // one default).
+ if (prevDefault)
+ {
+ prevDefault->ItemField().RemoveFieldType(KUidPbkDefaultFieldSms);
+ }
+
+ __ASSERT_DEBUG(
+ (aField && DefaultSmsField()==aField) ||
+ (!aField && !DefaultSmsField()),
+ Panic(EPanicPostCond_SetDefaultPhoneNumberFieldL));
+ }
+
+EXPORT_C void CPbkContactItem::RemoveDefaultSmsField()
+ {
+ // This is safe because SetDefaultSmsFieldL(NULL) guarantees
+ // not to leave
+ SetDefaultSmsFieldL(NULL);
+ }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::DefaultEmailField() const
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+ // scan the fields for a match in default field for field id.
+ const TInt fieldCount = iFields.Count();
+ for (TInt i = 0; i < fieldCount; ++i)
+ {
+ const TPbkContactItemField& field = iFields[i];
+ if (field.DefaultEmailField())
+ {
+ return const_cast<TPbkContactItemField*>(&field);
+ }
+ }
+ return NULL;
+ }
+
+EXPORT_C void CPbkContactItem::SetDefaultEmailFieldL
+ (TPbkContactItemField* aField)
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+ if (aField)
+ {
+ aField = FindSameField(*aField);
+ if (!aField)
+ {
+ // Not this item's field
+ User::Leave(KErrNotFound);
+ }
+ }
+
+ if (aField && aField->FieldInfo().FieldId() != EPbkFieldIdEmailAddress)
+ {
+ User::Leave(KErrNotSupported);
+ }
+
+ // 1. Fetch previous default
+ TPbkContactItemField* prevDefault = DefaultEmailField();
+
+ // 2. Set the new default if specified
+ if (aField)
+ {
+ if (aField == prevDefault)
+ {
+ // Already set
+ return;
+ }
+ aField->ItemField().AddFieldTypeL(KUidPbkDefaultFieldPref);
+ }
+
+ // 3. Unset any previous default (invariant tests that there is always just
+ // one default).
+ if (prevDefault)
+ {
+ prevDefault->ItemField().RemoveFieldType(KUidPbkDefaultFieldPref);
+ }
+
+ __ASSERT_DEBUG(
+ (aField && DefaultEmailField()==aField) ||
+ (!aField && !DefaultEmailField()),
+ Panic(EPanicPostCond_SetDefaultEmailFieldL));
+ }
+
+EXPORT_C void CPbkContactItem::RemoveDefaultEmailField()
+ {
+ // This is safe because SetDefaultEmailFieldL(NULL) guarantees
+ // not to leave
+ SetDefaultEmailFieldL(NULL);
+ }
+
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::DefaultEmailOverSmsField() const
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+ // scan the fields for a match in default field for field id.
+ const TInt fieldCount = iFields.Count();
+ for (TInt i = 0; i < fieldCount; ++i)
+ {
+ const TPbkContactItemField& field = iFields[i];
+ if (field.DefaultEmailOverSmsField())
+ {
+ return const_cast<TPbkContactItemField*>(&field);
+ }
+ }
+ return NULL;
+ }
+
+EXPORT_C void CPbkContactItem::SetDefaultEmailOverSmsFieldL
+ (TPbkContactItemField* aField)
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+ if (aField)
+ {
+ aField = FindSameField(*aField);
+ if (!aField)
+ {
+ // Not this item's field
+ User::Leave(KErrNotFound);
+ }
+ }
+
+ if (aField && !aField->FieldInfo().IsEmailOverSmsField())
+ {
+ User::Leave(KErrNotSupported);
+ }
+
+ // 1. Fetch previous default
+ TPbkContactItemField* prevDefault = DefaultEmailOverSmsField();
+
+ // 2. Set the new default if specified
+ if (aField)
+ {
+ if (aField == prevDefault)
+ {
+ // Already set
+ return;
+ }
+ aField->ItemField().AddFieldTypeL(KUidPbkDefaultFieldEmailOverSms);
+ }
+
+ // 3. Unset any previous default (invariant tests that there is always just
+ // one default).
+ if (prevDefault)
+ {
+ prevDefault->ItemField().RemoveFieldType(KUidPbkDefaultFieldEmailOverSms);
+ }
+
+ __ASSERT_DEBUG(
+ (aField && DefaultEmailOverSmsField()==aField) ||
+ (!aField && !DefaultEmailOverSmsField()),
+ Panic(EPanicPostCond_SetDefaultEmailOverSmsFieldL));
+ }
+
+EXPORT_C void CPbkContactItem::RemoveDefaultEmailOverSmsField()
+ {
+ // This is safe because SetDefaultEmailOverSmsFieldL(NULL) guarantees
+ // not to leave
+ SetDefaultEmailOverSmsFieldL(NULL);
+ }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::DefaultMmsField() const
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+ // scan the fields for a match in default field for field id.
+ const TInt fieldCount = iFields.Count();
+ for (TInt i = 0; i < fieldCount; ++i)
+ {
+ const TPbkContactItemField& field = iFields[i];
+ if (field.DefaultMmsField())
+ {
+ return const_cast<TPbkContactItemField*>(&field);
+ }
+ }
+ return NULL;
+ }
+
+EXPORT_C void CPbkContactItem::SetDefaultMmsFieldL
+ (TPbkContactItemField* aField)
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+ if (aField)
+ {
+ aField = FindSameField(*aField);
+ if (!aField)
+ {
+ // Not this item's field
+ User::Leave(KErrNotFound);
+ }
+ }
+
+ if (aField && !aField->FieldInfo().IsMmsField())
+ {
+ User::Leave(KErrNotSupported);
+ }
+
+ // 1. Fetch previous default
+ TPbkContactItemField* prevDefault = DefaultMmsField();
+
+ // 2. Set the new default if specified
+ if (aField)
+ {
+ if (aField == prevDefault)
+ {
+ // Already set
+ return;
+ }
+ aField->ItemField().AddFieldTypeL(KUidPbkDefaultFieldMms);
+ }
+
+ // 3. Unset any previous default (invariant tests that there is always just
+ // one default).
+ if (prevDefault)
+ {
+ prevDefault->ItemField().RemoveFieldType(KUidPbkDefaultFieldMms);
+ }
+
+ __ASSERT_DEBUG(
+ (aField && DefaultMmsField()==aField) ||
+ (!aField && !DefaultMmsField()),
+ Panic(EPanicPostCond_SetDefaultMmsFieldL));
+ }
+
+EXPORT_C void CPbkContactItem::RemoveDefaultMmsField()
+ {
+ // This is safe because SetDefaultMmsFieldL(NULL) guarantees
+ // not to leave
+ SetDefaultMmsFieldL(NULL);
+ }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::DefaultPocField() const
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+ // scan the fields for a match in default field for field id.
+ const TInt fieldCount = iFields.Count();
+ for (TInt i = 0; i < fieldCount; ++i)
+ {
+ const TPbkContactItemField& field = iFields[i];
+ if (field.DefaultPocField())
+ {
+ return const_cast<TPbkContactItemField*>(&field);
+ }
+ }
+ return NULL;
+ }
+
+EXPORT_C void CPbkContactItem::SetDefaultPocFieldL
+ (TPbkContactItemField* aField)
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+ if (aField)
+ {
+ aField = FindSameField(*aField);
+ if (!aField)
+ {
+ // Not this item's field
+ User::Leave(KErrNotFound);
+ }
+ }
+
+ if (aField && !aField->FieldInfo().IsPocField())
+ {
+ User::Leave(KErrNotSupported);
+ }
+
+ // 1. Fetch previous default
+ TPbkContactItemField* prevDefault = DefaultPocField();
+
+ // 2. Set the new default if specified
+ if (aField)
+ {
+ if (aField == prevDefault)
+ {
+ // Already set
+ return;
+ }
+ aField->ItemField().AddFieldTypeL(KUidPbkDefaultFieldPoc);
+ }
+
+ // 3. Unset any previous default (invariant tests that there is always just
+ // one default).
+ if (prevDefault)
+ {
+ prevDefault->ItemField().RemoveFieldType(KUidPbkDefaultFieldPoc);
+ }
+
+ __ASSERT_DEBUG(
+ (aField && DefaultPocField()==aField) ||
+ (!aField && !DefaultPocField()),
+ Panic(EPanicPostCond_SetDefaultPocFieldL));
+ }
+
+EXPORT_C void CPbkContactItem::RemoveDefaultPocField()
+ {
+ // This is safe because SetDefaultPocFieldL(NULL) guarantees
+ // not to leave
+ SetDefaultPocFieldL(NULL);
+ }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::DefaultVoipField() const
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+ // scan the fields for a match in default field for field id.
+ const TInt fieldCount = iFields.Count();
+ for (TInt i = 0; i < fieldCount; ++i)
+ {
+ const TPbkContactItemField& field = iFields[i];
+ if (field.DefaultVoipField())
+ {
+ return const_cast<TPbkContactItemField*>(&field);
+ }
+ }
+ return NULL;
+ }
+
+EXPORT_C void CPbkContactItem::SetDefaultVoipFieldL
+ (TPbkContactItemField* aField)
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+ if (aField)
+ {
+ aField = FindSameField(*aField);
+ if (!aField)
+ {
+ // Not this item's field
+ User::Leave(KErrNotFound);
+ }
+ }
+
+ if (aField && !aField->FieldInfo().IsVoipField())
+ {
+ User::Leave(KErrNotSupported);
+ }
+
+ // 1. Fetch previous default
+ TPbkContactItemField* prevDefault = DefaultVoipField();
+
+ // 2. Set the new default if specified
+ if (aField)
+ {
+ if (aField == prevDefault)
+ {
+ // Already set
+ return;
+ }
+ aField->ItemField().AddFieldTypeL(KUidPbkDefaultFieldVoip);
+ }
+
+ // 3. Unset any previous default (invariant tests that there is always just
+ // one default).
+ if (prevDefault)
+ {
+ prevDefault->ItemField().RemoveFieldType(KUidPbkDefaultFieldVoip);
+ }
+
+ __ASSERT_DEBUG(
+ (aField && DefaultVoipField()==aField) ||
+ (!aField && !DefaultVoipField()),
+ Panic(EPanicPostCond_SetDefaultVoipFieldL));
+ }
+
+EXPORT_C void CPbkContactItem::RemoveDefaultVoipField()
+ {
+ // This is safe because SetDefaultVoipFieldL(NULL) guarantees
+ // not to leave
+ SetDefaultVoipFieldL(NULL);
+ }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::VoiceTagField() const
+ {
+ TPbkContactItemField* ret = NULL;
+
+ if (FeatureManager::FeatureSupported( KFeatureIdSind ))
+ {
+ // Try to initiaze SindHandler.
+ CPbkEngineLocalStorage* storage =
+ reinterpret_cast<CPbkEngineLocalStorage*> ( Dll::Tls( ) );
+
+ if (storage && !storage->iSINDHandler)
+ {
+ // SindHandler lazy construction.
+ // Possible leave codes ignored.
+ TRAP_IGNORE(LoadSindHandlerImplL(storage->iDtorIDKey,
+ storage->iSINDHandler));
+ if (storage->iSINDHandler)
+ {
+ // Update engine TLS if SindHandler is loaded
+ TInt err = Dll::SetTls(storage);
+ __ASSERT_DEBUG( err == KErrNone,
+ Panic( EPanicPreCond_VoiceTagField2 ) );
+ }
+ }
+
+ if ( storage && storage->iSINDHandler )
+ {
+ TPbkFieldId voiceTaggedFieldId =
+ storage->iSINDHandler->VoiceTagField(Id());
+
+ if ( voiceTaggedFieldId >= 0 ) // otherwise error has occured
+ {
+ // check is default call number set
+ TPbkContactItemField* defaultField = DefaultPhoneNumberField();
+ if ( defaultField )
+ {
+ return defaultField;
+ }
+ const TInt fieldCount = iFields.Count();
+ for (TInt i = 0; i < fieldCount; ++i)
+ {
+ const TPbkContactItemField& field = iFields[i];
+ if ( field.PbkFieldId() == voiceTaggedFieldId )
+ {
+ ret = const_cast<TPbkContactItemField*>(&field);
+ break;
+ }
+ }
+ }
+ }
+
+ // If the field id does not match with existing fields or the
+ // sindhandler return error (not found), NULL is returned.
+ }
+ else
+ {
+ // scan the fields for a match in voice tag field for field id.
+ const TInt fieldCount = iFields.Count();
+ for (TInt i = 0; i < fieldCount; ++i)
+ {
+ const TPbkContactItemField& field = iFields[i];
+ if (field.ItemField().ContentType().ContainsFieldType(
+ KUidContactsVoiceDialField))
+ {
+ ret = const_cast<TPbkContactItemField*>(&field);
+ break;
+ }
+ }
+ }
+
+ return ret;
+ }
+
+EXPORT_C void CPbkContactItem::SetVoiceTagFieldL
+ (TPbkContactItemField* aField)
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+ if ( !FeatureManager::FeatureSupported(KFeatureIdSind) )
+ {
+
+ if (aField)
+ {
+ aField = FindSameField(*aField);
+ if (!aField)
+ {
+ // Not this item's field
+ User::Leave(KErrNotFound);
+ }
+ }
+
+ // Test can we set a voice tag for this field
+ // The VoIP field completely includes the IsPhoneNumberField subset,
+ // so its enough to test with IsVoipField method only.
+ if (aField && !aField->FieldInfo().IsVoipField())
+ {
+ User::Leave(KErrNotSupported);
+ }
+
+ // 1. Fetch previous voice tag field
+ TPbkContactItemField* prevTag = VoiceTagField();
+
+ // 2. Set the new voice tag, if specified
+ if (aField)
+ {
+ if (prevTag == aField)
+ {
+ // Voice tag already set to aField
+ return;
+ }
+ // If this leaves, this object's state remains unchanged
+ aField->ItemField().AddFieldTypeL(KUidContactsVoiceDialField);
+ }
+
+ // 3. Unset any previous voice tag (invariant tests that there is always
+ // just one voice tag).
+ if (prevTag)
+ {
+ // Unset previous voice tag
+ prevTag->ItemField().RemoveFieldType(KUidContactsVoiceDialField);
+ }
+
+ __ASSERT_DEBUG(
+ (aField && VoiceTagField()==aField) ||
+ (!aField && !VoiceTagField()),
+ Panic(EPanicPostCond_SetVoiceTagFieldL));
+ }
+ }
+
+EXPORT_C void CPbkContactItem::RemoveVoiceTagField()
+ {
+ if ( !FeatureManager::FeatureSupported(KFeatureIdSind) )
+ {
+ // This is safe because SetVoiceTagFieldL(NULL) guarantees
+ // not to leave
+ SetVoiceTagFieldL(NULL);
+ }
+ }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::FindField
+ (TPbkFieldId aFieldId) const
+ {
+ TInt index = 0;
+ return FindField(aFieldId, index);
+ }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::FindField
+ (TPbkFieldId aFieldId, TInt& aIndex) const
+ {
+ __TEST_INVARIANT;
+
+ const TInt fieldCount = iFields.Count();
+ for (TInt i = Max(aIndex,0) ; i < fieldCount; ++i)
+ {
+ const TPbkContactItemField& field = iFields[i];
+ if (field.FieldInfo().Match(aFieldId))
+ {
+ aIndex = i;
+ return const_cast<TPbkContactItemField*>(&field);
+ }
+ }
+
+ aIndex = KErrNotFound;
+ return NULL;
+ }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::FindField
+ (const CPbkFieldInfo& aFieldInfo) const
+ {
+ TInt index = 0;
+ return FindField(aFieldInfo, index);
+ }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::FindField
+ (const CPbkFieldInfo& aFieldInfo, TInt& aIndex) const
+ {
+ __TEST_INVARIANT;
+
+ aIndex = FindFieldWithType(iFields, aFieldInfo, Max(aIndex,0));
+ if (aIndex != KErrNotFound)
+ {
+ return const_cast<TPbkContactItemField*>(&iFields[aIndex]);
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+
+EXPORT_C TInt CPbkContactItem::FindFieldIndex
+ (const TPbkContactItemField& aField) const
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+ const TInt fieldCount = iFields.Count();
+ for (TInt i = 0; i < fieldCount; ++i)
+ {
+ if(iFields[i].IsSame(aField))
+ {
+ __ASSERT_DEBUG(CardFields()[i].IsSame(aField),
+ Panic(EPanicPostCond_FindFieldIndex));
+ return i;
+ }
+ }
+
+ return KErrNotFound;
+ }
+
+EXPORT_C TInt CPbkContactItem::FindContactItemFieldIndex
+ (const CContactItemField& aField) const
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+ const CContactItemFieldSet& fields = iItem->CardFields();
+ const TInt fieldCount = fields.Count();
+ for (TInt i = 0; i < fieldCount; ++i)
+ {
+ if (&fields[i] == &aField)
+ {
+ return i;
+ }
+ }
+ return KErrNotFound;
+ }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::FindNextFieldWithPhoneNumber(
+ const TDesC& aNumber,
+ TInt aNumberOfDigits,
+ TInt& aIndex) const
+ {
+ __TEST_INVARIANT;
+
+ const TInt fieldCount = iFields.Count();
+ for (TInt i = Max(aIndex,0); i < fieldCount; ++i)
+ {
+ const TPbkContactItemField& field = iFields[i];
+ if (field.FieldInfo().IsPhoneNumberField())
+ {
+ if (PbkEngUtils::ContainSameDigits(field.Text(), aNumber,
+ aNumberOfDigits))
+ {
+ aIndex = i;
+ return const_cast<TPbkContactItemField*>(&field);
+ }
+ }
+ }
+
+ aIndex = KErrNotFound;
+ return NULL;
+ }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::FindNextFieldWithText
+ (const TDesC& aText,
+ TInt& aIndex) const
+ {
+ __TEST_INVARIANT;
+
+ const TInt fieldCount = iFields.Count();
+ for (TInt i = Max(aIndex,0); i < fieldCount; ++i)
+ {
+ const TPbkContactItemField& field = iFields[i];
+ if (field.StorageType() == KStorageTypeText)
+ {
+ if (field.Text().FindF(aText) >= 0)
+ {
+ aIndex = i;
+ return const_cast<TPbkContactItemField*>(&field);
+ }
+ }
+ }
+
+ aIndex = KErrNotFound;
+ return NULL;
+ }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::FindSameField
+ (const TPbkContactItemField& aField) const
+ {
+ const TInt fieldCount = iFields.Count();
+ for (TInt i=0; i < fieldCount; ++i)
+ {
+ if (iFields[i].IsSame(aField))
+ {
+ return const_cast<TPbkContactItemField*>(&iFields[i]);
+ }
+ }
+ return NULL;
+ }
+
+EXPORT_C void CPbkContactItem::RemoveField
+ (TInt aIndex)
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+ __ASSERT_DEBUG(aIndex >= 0 && aIndex < CardFields().Count(),
+ Panic(EPanicPreCond_RemoveField));
+ PBK_DEBUG_ONLY(TInt old_myCount = CardFields().Count());
+ PBK_DEBUG_ONLY(TInt old_otherCount = iItem->CardFields().Count());
+
+ CContactItemField* field = &(CardFields()[aIndex].ItemField());
+ TInt i;
+ const TInt fieldCount = iItem->CardFields().Count();
+ for (i=0; i < fieldCount; ++i)
+ {
+ if (&iItem->CardFields()[i] == field)
+ {
+ break;
+ }
+ }
+ // Field must be found
+ __ASSERT_DEBUG(i < iItem->CardFields().Count(), Panic(EPanicLogic_RemoveField));
+ iItem->RemoveField(i);
+
+ iFields.Delete(aIndex);
+
+ __ASSERT_DEBUG(CardFields().Count() == old_myCount-1,
+ Panic(EPanicPostCond_RemoveField));
+ __ASSERT_DEBUG(iItem->CardFields().Count() == old_otherCount-1,
+ Panic(EPanicPostCond_RemoveField));
+ }
+
+
+EXPORT_C TPbkContactItemField& CPbkContactItem::AddFieldL
+ (CPbkFieldInfo& aFieldInfo)
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+ PBK_DEBUG_ONLY(TInt old_Count = CardFields().Count());
+
+ // Create new contact model field with help from aFieldInfo
+ CContactItemField* itemField = aFieldInfo.CreateFieldL();
+ CleanupStack::PushL(itemField);
+
+ // Create and initialize a new Phonebook field object.
+ TPbkContactItemField pbkField(itemField,&aFieldInfo);
+
+ // Try to make room to iFields for the new Phonebook field. This call makes
+ // this function leave-safe, see *)
+ iFields.SetReserveL(iFields.Count()+1);
+
+ // Check that calling SetReserveL doesn't break the class invariant.
+ // It shouldn't because it doesnt change iFields.Count().
+ __TEST_INVARIANT;
+
+ // Add the contact model field to iItem
+ iItem->AddFieldL(*itemField);
+ CleanupStack::Pop(itemField); // itemField now owned by iItem
+
+ // Here the invariant doesn't hold
+
+ // Insert the new Phonebook field.
+ // *) This call is guaranteed NOT to leave because we have succesfully
+ // reserved space to iFields with the SetReserveL call above.
+ TInt index = InsertionPos(pbkField);
+ iFields.InsertL(index, pbkField);
+
+ TPbkContactItemField& newField = iFields[index];
+
+ //PostCond:
+ __ASSERT_DEBUG(&newField.ItemField() == itemField,
+ Panic(EPanicPostCond_AddFieldL));
+ __ASSERT_DEBUG(newField.FieldInfo().IsSame(aFieldInfo),
+ Panic(EPanicPostCond_AddFieldL));
+ __ASSERT_DEBUG(iFields.Count() == old_Count+1,
+ Panic(EPanicPostCond_AddFieldL));
+ __ASSERT_DEBUG(index == iFields.Count()-1 ||
+ iFields[index+1].Compare(iFields[index]) > 0,
+ Panic(EPanicPostCond_AddFieldL));
+
+ return newField;
+ }
+
+EXPORT_C TBool CPbkContactItem::CanAcceptDataOfType
+ (CPbkFieldInfo& aFieldInfo) const
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+ // Search for an empty field of type aFieldInfo
+ const TInt fieldCount = CardFields().Count();
+ TInt countOfFieldsOfSameType = 0;
+ for (TInt i=0; i < fieldCount; ++i)
+ {
+ const TPbkContactItemField& f = iFields[i];
+ if (f.FieldInfo().IsSame(aFieldInfo))
+ {
+ ++countOfFieldsOfSameType;
+ if (f.IsEmpty())
+ {
+ // Empty field of same type found
+ return ETrue;
+ }
+ }
+ }
+
+ // Check if a new field can be added
+ if (countOfFieldsOfSameType == 0 ||
+ aFieldInfo.Multiplicity()==EPbkFieldMultiplicityMany)
+ {
+ // New field can be added
+ return ETrue;
+ }
+
+ // Out of luck
+ return EFalse;
+ }
+
+EXPORT_C TPbkContactItemField* CPbkContactItem::AddOrReturnUnusedFieldL
+ (CPbkFieldInfo& aFieldInfo)
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+ TPbkContactItemField* field = NULL;
+
+ // Search for an empty field of type aFieldInfo
+ const TInt fieldCount = CardFields().Count();
+ TInt countOfFieldsOfSameType = 0;
+ for (TInt i=0; i < fieldCount; ++i)
+ {
+ TPbkContactItemField& f = iFields[i];
+ if (f.FieldInfo().IsSame(aFieldInfo))
+ {
+ ++countOfFieldsOfSameType;
+ if (f.IsEmpty())
+ {
+ // Empty field of same type found
+ field = &f;
+ break;
+ }
+ }
+ }
+
+ if (!field)
+ {
+ // Empty field of same type was not found
+ if (countOfFieldsOfSameType == 0 ||
+ aFieldInfo.Multiplicity()==EPbkFieldMultiplicityMany)
+ {
+ // Add a new field
+ field = &AddFieldL(aFieldInfo);
+ }
+ }
+
+ return field;
+ }
+
+EXPORT_C void CPbkContactItem::UpdateFieldSetL
+ (const CPbkFieldsInfo& aFieldsInfo)
+ {
+ //PreCond:
+ __ASSERT_DEBUG(iItem, Panic(EPanicPreCond_UpdateFieldSetL));
+ // Don't test invariant, because this function needs to be called when
+ // the invariant is broken!
+
+ // Recreate field array like in ConstructL
+ CreateFieldArrayL(*iItem, aFieldsInfo);
+
+ __TEST_INVARIANT;
+ }
+
+EXPORT_C CPbkFieldArray& CPbkContactItem::CardFields() const
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+ return const_cast<CPbkFieldArray&>(iFields);
+ }
+
+
+EXPORT_C TUid CPbkContactItem::Type() const
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+ return iItem->Type();
+ }
+
+
+EXPORT_C TContactItemId CPbkContactItem::Id() const
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+ return iItem->Id();
+ }
+
+EXPORT_C CContactIdArray* CPbkContactItem::GroupsJoinedLC() const
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+ __ASSERT_ALWAYS(iItem->Type() == KUidContactCard,
+ Panic(EPanicPreCond_GroupsJoinedLC));
+ return static_cast<const CContactCard*>(iItem)->GroupsJoinedLC();
+ }
+
+TInt CPbkContactItem::PbkFieldCount() const
+ {
+ return iFields.Count();
+ }
+
+MPbkFieldData& CPbkContactItem::PbkFieldAt(TInt aIndex)
+ {
+ // PreCond: iFields will __ASSERT_ALWAYS aIndex validity
+ return iFields[aIndex];
+ }
+
+const MPbkFieldData& CPbkContactItem::PbkFieldAt(TInt aIndex) const
+ {
+ // PreCond: iFields will __ASSERT_ALWAYS aIndex validity
+ return iFields[aIndex];
+ }
+
+void CPbkContactItem::PrepareForSaveL()
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+
+ // check that there is the syncronization field
+ // otherwise add the syncronization field
+ TPbkContactItemField* syncField = FindField(EPbkFieldIdSyncronization);
+ if (!syncField)
+ {
+ // add the syncronization field to the contact
+ CPbkContactEngine* engine = CPbkContactEngine::Static();
+ if (engine)
+ {
+ CPbkFieldInfo* syncFieldInfo = engine->FieldsInfo().Find(
+ EPbkFieldIdSyncronization);
+ if (syncFieldInfo)
+ {
+ // add syncronization field to contact - compulsory
+ AddFieldL(*syncFieldInfo);
+ }
+ }
+ }
+
+ for (TInt i=iFields.Count()-1; i >= 0; --i)
+ {
+ TPbkContactItemField& field = iFields[i];
+
+ // check that syncronization field has correct value
+ if (field.FieldInfo().FieldId() == EPbkFieldIdSyncronization)
+ {
+ // check that theres private, public or none text in the field
+ // use the default if incorrect or no value
+ const TDesC& fieldtext = field.TextStorage()->Text();
+ // safely detect whether theres syncronization setting in the field
+ if (!(!fieldtext.CompareF(KPbkContactSyncPrivate) ||
+ !fieldtext.CompareF(KPbkContactSyncPublic) ||
+ !fieldtext.CompareF(KPbkContactSyncNoSync)))
+ {
+ // set default sync setting to field
+ field.TextStorage()->SetTextL(KPbkContactSyncPrivate);
+ }
+ }
+
+ field.PrepareForSaveL();
+ if (field.HasInvalidDate())
+ {
+ RemoveField(i);
+ }
+ }
+ }
+
+void CPbkContactItem::PrepareAfterLoadL()
+ {
+ PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
+ for (TInt i=iFields.Count()-1; i >= 0; --i)
+ {
+ TPbkContactItemField& field = iFields[i];
+ field.PrepareAfterLoadL();
+ if (field.HasInvalidDate())
+ {
+ RemoveField(i);
+ }
+ }
+ }
+
+/**
+ * Class invariant.
+ */
+EXPORT_C void CPbkContactItem::__DbgTestInvariant() const
+ {
+#ifdef _DEBUG
+ // Check proper construction
+ __ASSERT_DEBUG(iItem, Panic(EPanicInvariant_Pointer));
+
+ // Check field counts
+ __ASSERT_DEBUG(iItem->CardFields().Count() >= iFields.Count(),
+ Panic(EPanicInvariant_Count));
+
+ TInt phoneDefaultCount = 0;
+ TInt smsDefaultCount = 0;
+ TInt emailDefaultCount = 0;
+ TInt voiceTagFieldCount = 0;
+
+ CPbkContactEngine* engine = CPbkContactEngine::Static();
+
+ // Scan all fields
+ TInt i;
+ const TInt fieldCount = iFields.Count();
+ for (i=0; i < fieldCount; ++i)
+ {
+ const TPbkContactItemField& pbkField = iFields[i];
+
+ // Check field info for all fields
+ if (engine)
+ {
+ const CPbkFieldInfo* fieldInfo =
+ engine->FieldsInfo().Find(pbkField.ItemField());
+ __ASSERT_DEBUG(fieldInfo && fieldInfo->IsSame(pbkField.FieldInfo()),
+ Panic(EPanicInvariant_FieldInfo));
+ }
+
+ // Search field from iItem's fieldset
+ TInt j;
+ const TInt itemFieldCount = iItem->CardFields().Count();
+ for (j = 0; j < itemFieldCount; ++j)
+ {
+ CContactItemField& field = iItem->CardFields()[j];
+ // Check if field found
+ if(&pbkField.ItemField() == &field)
+ {
+ break;
+ }
+ }
+ // field must be found
+ __ASSERT_DEBUG(j < iItem->CardFields().Count(),
+ Panic(EPanicInvariant_Field));
+
+ // Update default field counts
+ TInt prefCount = 0;
+ TInt smsCount = 0;
+ TInt voiceTagCount = 0;
+ TInt videoTagCount = 0;
+ const CContentType& contentType = pbkField.ItemField().ContentType();
+ for (TInt t = 0; t < contentType.FieldTypeCount(); ++t)
+ {
+ if (contentType.FieldType(t) == KUidPbkDefaultFieldPref)
+ ++prefCount;
+ else if (contentType.FieldType(t) == KUidPbkDefaultFieldSms)
+ ++smsCount;
+ else if (contentType.FieldType(t) == KUidContactsVoiceDialField)
+ ++voiceTagCount;
+ else if (contentType.FieldType(t) == KUidPbkDefaultFieldVideo)
+ ++videoTagCount;
+ }
+ __ASSERT_DEBUG(prefCount <= 2, Panic(EPanicInvariant_PrefCount));
+ __ASSERT_DEBUG(smsCount <= 1, Panic(EPanicInvariant_SmsCount));
+ __ASSERT_DEBUG(prefCount < 2 || smsCount == 1,
+ Panic(EPanicInvariant_PrefSmsCount));
+ __ASSERT_DEBUG(voiceTagCount <= 1,
+ Panic(EPanicInvariant_VoiceTagCount));
+ __ASSERT_DEBUG(videoTagCount <= 1,
+ Panic(EPanicInvariant_VideoTagCount));
+
+ if (pbkField.FieldInfo().IsPhoneNumberField() && prefCount >= 1)
+ {
+ if (smsCount == 1)
+ {
+ ++smsDefaultCount;
+ }
+ if ((prefCount==1 && smsCount==0) || (prefCount==2 && smsCount==1))
+ {
+ ++phoneDefaultCount;
+ }
+ }
+ if (pbkField.FieldInfo().FieldId() == EPbkFieldIdEmailAddress &&
+ prefCount==1)
+ {
+ ++emailDefaultCount;
+ }
+ if (voiceTagCount > 0)
+ {
+ ++voiceTagFieldCount;
+ }
+ }
+
+ // Check default counts: only one default per category allowed
+ __ASSERT_DEBUG(phoneDefaultCount <= 1,
+ Panic(EPanicInvariant_PhoneDefaultCount));
+ __ASSERT_DEBUG(smsDefaultCount <= 1,
+ Panic(EPanicInvariant_SmsDefaultCount));
+ __ASSERT_DEBUG(emailDefaultCount <= 1,
+ Panic(EPanicInvariant_EmailDefaultCount));
+ __ASSERT_DEBUG(voiceTagFieldCount <= 1,
+ Panic(EPanicInvariant_VoiceTagFieldCount));
+
+ // Test field sorting
+ for (i = 0; i < iFields.Count()-1; ++i)
+ {
+ __ASSERT_DEBUG(iFields[i].Compare(iFields[i+1]) <= 0,
+ Panic(EPanicInvariant_Sorting));
+ }
+#endif
+ }
+
+void CPbkContactItem::CreateFieldArrayL
+ (CContactItem& aContactItem,
+ const CPbkFieldsInfo& aFieldsInfo)
+ {
+ const TInt fieldCount = aContactItem.CardFields().Count();
+ iFields.SetReserveL(fieldCount);
+ // Use Delete instead of Reset to keep the array buffer allocated above
+ iFields.Delete(0, iFields.Count());
+ CContactItemFieldSet& fieldSet = aContactItem.CardFields();
+
+ // Loop through all import priority levels
+ for (TPbkMatchPriorityLevel priorityLevel(aFieldsInfo.CreateMatchPriority());
+ !priorityLevel.End();
+ priorityLevel.Next())
+ {
+ // Loop through all the fields
+ for (TInt i=0; i < fieldCount; ++i)
+ {
+ CContactItemField& field = fieldSet[i];
+ CPbkFieldInfo* fieldType = aFieldsInfo.Match(field, priorityLevel);
+ if (fieldType)
+ {
+ // Check that the field has not already been added
+ const TInt fieldCount = iFields.Count();
+ TInt i;
+ for (i=0; i < fieldCount; ++i)
+ {
+ const TPbkContactItemField& pbkField = iFields[i];
+ if (&pbkField.ItemField()==&field ||
+ (fieldType->Multiplicity()==EPbkFieldMultiplicityOne &&
+ pbkField.FieldInfo().IsSame(*fieldType)))
+ {
+ break;
+ }
+ }
+ if (i == fieldCount)
+ {
+ // Insert the field directly into presentation order
+ TPbkContactItemField pbkField(&field, fieldType);
+ iFields.InsertL(InsertionPos(pbkField), pbkField);
+ }
+ }
+ }
+ }
+ }
+
+/**
+ * Returns insertion position for aField.
+ */
+TInt CPbkContactItem::InsertionPos
+ (const TPbkContactItemField& aField) const
+ {
+ // Search for an insertion pos using the "upper bound" algorithm.
+ TInt first = 0;
+ TInt len = iFields.Count();
+ while (len > 0)
+ {
+ const TInt half = len / 2;
+ const TInt middle = first + half;
+ if (aField.Compare(iFields[middle]) < 0)
+ {
+ len = half;
+ }
+ else
+ {
+ first = middle + 1;
+ len = len - half - 1;
+ }
+ }
+
+ // If upper bound found a match, insertion pos is after that.
+ if (first < iFields.Count() && aField.Compare(iFields[first]) == 0)
+ {
+ ++first;
+ }
+
+ // PostCond
+ __ASSERT_DEBUG(first >= 0 && first <= iFields.Count(),
+ Panic(EPanicPostCond_InsertionPos));
+ return first;
+ }
+
+// ================= OTHER EXPORTED FUNCTIONS ==============
+
+EXPORT_C TBool operator==
+ (const CPbkContactItem& aLeft, const CPbkContactItem& aRight)
+ {
+ const TInt fieldCount = aLeft.iFields.Count();
+ if (aRight.iFields.Count() != fieldCount)
+ {
+ return EFalse;
+ }
+
+ for (TInt i=0; i < fieldCount; ++i)
+ {
+ if (aLeft.iFields[i] != aRight.iFields[i])
+ {
+ return EFalse;
+ }
+ }
+
+ return ETrue;
+ }
+
+// End of File