phonebookui/Phonebook/Engine/src/CPbkContactItem.cpp
changeset 0 e686773b3f54
equal deleted inserted replaced
-1:000000000000 0:e686773b3f54
       
     1 /*
       
     2 * Copyright (c) 2002 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *		Phonebook Contact item class
       
    16 *
       
    17 */
       
    18 
       
    19 
       
    20 // INCLUDE FILES
       
    21 #include    "CPbkContactItem.h"
       
    22 #include    <cntfield.h>    // CContactItemField
       
    23 #include    <cntitem.h>     // CContactItem
       
    24 #include    <featmgr.h>	    // Feature manager
       
    25 #include    "CPbkFieldsInfo.h"
       
    26 #include    "CPbkFieldInfo.h"
       
    27 #include    "TPbkContactItemField.h"
       
    28 #include    "PbkFields.hrh"
       
    29 #include    <PbkEngUtils.h>
       
    30 #include    <PbkDebug.h>
       
    31 #include    "PbkDefaults.h"
       
    32 #include    <MPbkContactNameFormat.h>
       
    33 #include    "TPbkMatchPriorityLevel.h"
       
    34 #include    "CPbkContactEngine.h"
       
    35 #include    "CPbkSyncronizationConstants.h"
       
    36 
       
    37 #ifdef _DEBUG
       
    38 // Engine needed only for a few asserts
       
    39 #include    "CPbkContactEngine.h"
       
    40 #endif
       
    41 
       
    42 // Unnamed namespace for local definitions
       
    43 
       
    44 namespace {
       
    45 
       
    46 // LOCAL CONSTANTS AND MACROS
       
    47 enum TPanicCode
       
    48     {
       
    49     EPanicPostCond_Constructor = 1,
       
    50     EPanicPreCond_ConstructL,
       
    51     EPanicInvariant_Pointer,
       
    52     EPanicInvariant_Count,
       
    53     EPanicInvariant_Field,
       
    54     EPanicInvariant_FieldInfo,
       
    55     EPanicInvariant_Sorting,
       
    56     EPanicInvariant_PrefCount,
       
    57     EPanicInvariant_SmsCount,
       
    58     EPanicInvariant_PrefSmsCount,
       
    59     EPanicInvariant_PhoneDefaultCount,
       
    60     EPanicInvariant_SmsDefaultCount,
       
    61     EPanicInvariant_EmailDefaultCount,
       
    62     EPanicInvariant_VideoTagCount,
       
    63     EPanicPostCond_FindFieldIndex,
       
    64     EPanicPreCond_RemoveField,
       
    65     EPanicLogic_RemoveField,
       
    66     EPanicPostCond_RemoveField,
       
    67     EPanicPostCond_AddFieldL,
       
    68     EPanicPreCond_GroupsJoinedLC,
       
    69     EPanicPostCond_SetDefaultPhoneNumberFieldL,
       
    70     EPanicPostCond_SetDefaultVideoNumberFieldL,
       
    71     EPanicPostCond_SetDefaultEmailFieldL,
       
    72     EPanicPreCond_UpdateFieldSetL,
       
    73     EPanicPostCond_InsertionPos,
       
    74     EPanicPostCond_SetVoiceTagFieldL,
       
    75     EPanicInvariant_VoiceTagCount,
       
    76     EPanicInvariant_VoiceTagFieldCount,
       
    77     EPanicPostCond_SetDefaultMmsFieldL,
       
    78     EPanicPostCond_SetDefaultEmailOverSmsFieldL,
       
    79     EPanicPostCond_SetDefaultPocFieldL,
       
    80     EPanicPostCond_SetDefaultVoipFieldL,
       
    81     EPanicPreCond_VoiceTagField1,
       
    82     EPanicPreCond_VoiceTagField2,
       
    83     EPanicPreCond_LoadSindHandlerImplL,
       
    84     EPanicDeprecatedFunction
       
    85     };
       
    86 
       
    87 // ==================== LOCAL FUNCTIONS ====================
       
    88 
       
    89 void Panic(TPanicCode aReason)
       
    90     {
       
    91     _LIT(KPanicText, "CPbkContactItem");
       
    92     User::Panic(KPanicText, aReason);
       
    93     }
       
    94 
       
    95 /**
       
    96  * Searches a field set for the first field with type specified type.
       
    97  *
       
    98  * @param aFields   the field set to search.
       
    99  * @param aFieldInfo    the field type to search for.
       
   100  * @param aIndex        index where to start the search.
       
   101  * @return index of the matching field in aFields or KErrNotFound if not found.
       
   102  */
       
   103 TInt FindFieldWithType
       
   104         (const CPbkFieldArray& aFields,
       
   105         const CPbkFieldInfo& aFieldInfo,
       
   106         TInt aIndex=0)
       
   107     {
       
   108     const TInt fieldCount = aFields.Count();
       
   109     for (TInt i=aIndex; i < fieldCount; ++i)
       
   110         {
       
   111         if (aFields[i].FieldInfo().IsSame(aFieldInfo))
       
   112             {
       
   113             return i;
       
   114             }
       
   115         }
       
   116     return KErrNotFound;
       
   117     }
       
   118 
       
   119 }  // namespace
       
   120 
       
   121 
       
   122 // ================= MEMBER FUNCTIONS =======================
       
   123 
       
   124 /**
       
   125  * C++ constructor.
       
   126  */
       
   127 inline CPbkContactItem::CPbkContactItem(MPbkContactNameFormat& aNameFormat) :
       
   128     iNameFormat(aNameFormat)
       
   129     {
       
   130     // new(ELeave) in NewL will reset members
       
   131     __ASSERT_DEBUG(!iItem, Panic(EPanicPostCond_Constructor));
       
   132     }
       
   133 
       
   134 /**
       
   135  * Second phase constructor.
       
   136  */
       
   137 inline void CPbkContactItem::ConstructL
       
   138         (CContactItem* aItem,
       
   139         const CPbkFieldsInfo& aFieldsInfo)
       
   140     {
       
   141     //PreCond:
       
   142     __ASSERT_DEBUG(aItem && !iItem, Panic(EPanicPreCond_ConstructL));
       
   143 
       
   144     CreateFieldArrayL(*aItem, aFieldsInfo);
       
   145     // construction was succesful, take ownership of aItem
       
   146     iItem = aItem;
       
   147 
       
   148     // Philosophical note: class invariant is effectively a postcondition
       
   149     // for a constructor.
       
   150     __TEST_INVARIANT;
       
   151     }
       
   152 
       
   153 EXPORT_C CPbkContactItem* CPbkContactItem::NewL
       
   154         (CContactItem* aItem,
       
   155         const CPbkFieldsInfo& aFieldsInfo,
       
   156         MPbkContactNameFormat& aNameFormat)
       
   157     {
       
   158     CPbkContactItem* self = new(ELeave) CPbkContactItem(aNameFormat);
       
   159     CleanupStack::PushL(self);
       
   160     self->ConstructL(aItem, aFieldsInfo);
       
   161     CleanupStack::Pop(self);
       
   162     return self;
       
   163     }
       
   164 
       
   165 CPbkContactItem::~CPbkContactItem()
       
   166     {
       
   167 #ifdef _DEBUG
       
   168     // Test invariant only at the beginning of destructor and only if
       
   169     // construction was succesful.
       
   170     if (iItem)
       
   171         __TEST_INVARIANT;
       
   172 #endif
       
   173 
       
   174     // Delete own data
       
   175     delete iItem;
       
   176     }
       
   177 
       
   178 EXPORT_C CContactItem& CPbkContactItem::ContactItem()
       
   179     {
       
   180     return *iItem;
       
   181     }
       
   182 
       
   183 EXPORT_C const CContactItem& CPbkContactItem::ContactItem() const
       
   184     {
       
   185     return *iItem;
       
   186     }
       
   187 
       
   188 EXPORT_C HBufC* CPbkContactItem::GetContactTitleL() const
       
   189     {
       
   190     __TEST_INVARIANT;
       
   191 
       
   192     // Delegate call to iNameFormat
       
   193     return iNameFormat.GetContactTitleL(*this);
       
   194     }
       
   195 
       
   196 EXPORT_C HBufC* CPbkContactItem::GetContactTitleOrNullL() const
       
   197     {
       
   198     __TEST_INVARIANT;
       
   199 
       
   200     // Delegate call to iNameFormat
       
   201     return iNameFormat.GetContactTitleOrNullL(*this);
       
   202     }
       
   203 
       
   204 EXPORT_C TPbkIconId CPbkContactItem::ContactIconIdL() const
       
   205     {
       
   206     __TEST_INVARIANT;
       
   207 
       
   208     TPbkContactItemField* field = DefaultPhoneNumberField();
       
   209     if (field)
       
   210         {
       
   211         return field->IconId();
       
   212         }
       
   213     return EPbkNullIconId;
       
   214     }
       
   215 
       
   216 EXPORT_C TPbkContactItemField* CPbkContactItem::DefaultPhoneNumberField() const
       
   217     {
       
   218     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
   219 
       
   220     // scan the fields for a match in default field for field id.
       
   221     const TInt fieldCount = iFields.Count();
       
   222     for(TInt i=0; i < fieldCount; ++i)
       
   223         {
       
   224         if (iFields[i].DefaultPhoneNumberField())
       
   225             {
       
   226             return const_cast<TPbkContactItemField*>(&(iFields[i]));
       
   227             }
       
   228         }
       
   229     return NULL;
       
   230     }
       
   231 
       
   232 EXPORT_C void CPbkContactItem::SetDefaultPhoneNumberFieldL
       
   233         (TPbkContactItemField* aField)
       
   234     {
       
   235     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
   236 
       
   237     if (aField)
       
   238         {
       
   239         aField = FindSameField(*aField);
       
   240         if (!aField)
       
   241             {
       
   242             // Not this item's field
       
   243             User::Leave(KErrNotFound);
       
   244             }
       
   245         }
       
   246 
       
   247     // Test can we set the default for this field
       
   248     if (aField && !aField->FieldInfo().IsPhoneNumberField())
       
   249         {
       
   250         User::Leave(KErrNotSupported);
       
   251         }
       
   252 
       
   253     // 1. Fetch previous default
       
   254     TPbkContactItemField* prevDefault = DefaultPhoneNumberField();
       
   255 
       
   256     // 2. Set the new default, if specified
       
   257     if (aField)
       
   258         {
       
   259         if (prevDefault == aField)
       
   260             {
       
   261             // Default already set to aField
       
   262             return;
       
   263             }
       
   264         // If this leaves, this object's state remains unchanged
       
   265         aField->ItemField().AddFieldTypeL(KUidPbkDefaultFieldPref);
       
   266         }
       
   267 
       
   268     // 3. Unset any previous default (invariant tests that there is always just
       
   269     // one default.
       
   270     if (prevDefault)
       
   271         {
       
   272         // Unset previous default
       
   273         prevDefault->ItemField().RemoveFieldType(KUidPbkDefaultFieldPref);
       
   274         }
       
   275 
       
   276     __ASSERT_DEBUG(
       
   277         (aField && DefaultPhoneNumberField()==aField) ||
       
   278         (!aField && !DefaultPhoneNumberField()),
       
   279         Panic(EPanicPostCond_SetDefaultPhoneNumberFieldL));
       
   280     }
       
   281 
       
   282 EXPORT_C void CPbkContactItem::RemoveDefaultPhoneNumberField()
       
   283     {
       
   284     // This is safe because SetDefaultPhoneNumberFieldL(NULL)
       
   285     // guarantees not to leave
       
   286     SetDefaultPhoneNumberFieldL(NULL);
       
   287     }
       
   288 
       
   289 EXPORT_C TPbkContactItemField* CPbkContactItem::DefaultVideoNumberField() const
       
   290     {
       
   291     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
   292 
       
   293     // scan the fields for a match in default field for field id.
       
   294     const TInt fieldCount = iFields.Count();
       
   295     for(TInt i=0; i < fieldCount; ++i)
       
   296         {
       
   297         if (iFields[i].DefaultVideoNumberField())
       
   298             {
       
   299             return const_cast<TPbkContactItemField*>(&(iFields[i]));
       
   300             }
       
   301         }
       
   302     return NULL;
       
   303     }
       
   304 
       
   305 EXPORT_C void CPbkContactItem::SetDefaultVideoNumberFieldL
       
   306         (TPbkContactItemField* aField)
       
   307     {
       
   308     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
   309 
       
   310     if (aField)
       
   311         {
       
   312         aField = FindSameField(*aField);
       
   313         if (!aField)
       
   314             {
       
   315             // Not this item's field
       
   316             User::Leave(KErrNotFound);
       
   317             }
       
   318         }
       
   319 
       
   320     // Test can we set the default for this field
       
   321     if (aField && !aField->FieldInfo().IsPhoneNumberField())
       
   322         {
       
   323         User::Leave(KErrNotSupported);
       
   324         }
       
   325 
       
   326     // 1. Fetch previous default
       
   327     TPbkContactItemField* prevDefault = DefaultVideoNumberField();
       
   328 
       
   329     // 2. Set the new default, if specified
       
   330     if (aField)
       
   331         {
       
   332         if (prevDefault == aField)
       
   333             {
       
   334             // Default already set to aField
       
   335             return;
       
   336             }
       
   337         // If this leaves, this object's state remains unchanged
       
   338         aField->ItemField().AddFieldTypeL(KUidPbkDefaultFieldVideo);
       
   339         }
       
   340 
       
   341     // 3. Unset any previous default (invariant tests that there is always just
       
   342     // one default.
       
   343     if (prevDefault)
       
   344         {
       
   345         // Unset previous default
       
   346         prevDefault->ItemField().RemoveFieldType(KUidPbkDefaultFieldVideo);
       
   347         }
       
   348 
       
   349     __ASSERT_DEBUG(
       
   350         (aField && DefaultVideoNumberField()==aField) ||
       
   351         (!aField && !DefaultVideoNumberField()),
       
   352         Panic(EPanicPostCond_SetDefaultVideoNumberFieldL));
       
   353     }
       
   354 
       
   355 EXPORT_C void CPbkContactItem::RemoveDefaultVideoNumberField()
       
   356     {
       
   357     // This is safe because SetDefaultPhoneNumberFieldL(NULL)
       
   358     // guarantees not to leave
       
   359     SetDefaultVideoNumberFieldL(NULL);
       
   360     }
       
   361 
       
   362 EXPORT_C TPbkContactItemField* CPbkContactItem::DefaultSmsField() const
       
   363     {
       
   364     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
   365 
       
   366     const TInt fieldCount = iFields.Count();
       
   367     for (TInt i=0; i < fieldCount; ++i)
       
   368         {
       
   369         const TPbkContactItemField& field = iFields[i];
       
   370         if (field.DefaultSmsField())
       
   371             {
       
   372             return const_cast<TPbkContactItemField*>(&field);
       
   373             }
       
   374         }
       
   375     return NULL;
       
   376     }
       
   377 
       
   378 EXPORT_C void CPbkContactItem::SetDefaultSmsFieldL
       
   379         (TPbkContactItemField* aField)
       
   380     {
       
   381     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
   382 
       
   383     if (aField)
       
   384         {
       
   385         aField = FindSameField(*aField);
       
   386         if (!aField)
       
   387             {
       
   388             // Not this item's field
       
   389             User::Leave(KErrNotFound);
       
   390             }
       
   391         }
       
   392 
       
   393     // Test can we set the default for this field
       
   394     if (aField && !aField->FieldInfo().IsPhoneNumberField())
       
   395         {
       
   396         User::Leave(KErrNotSupported);
       
   397         }
       
   398 
       
   399     // 1. Fetch previous default
       
   400     TPbkContactItemField* prevDefault = DefaultSmsField();
       
   401 
       
   402     // 2. Set the new default if specified
       
   403     if (aField)
       
   404         {
       
   405         if (aField == prevDefault)
       
   406             {
       
   407             // Already set
       
   408             return;
       
   409             }
       
   410         // If this leaves, this object's state remains unchanged
       
   411         aField->ItemField().AddFieldTypeL(KUidPbkDefaultFieldSms);
       
   412         }
       
   413 
       
   414     // 3. Unset any previous default (invariant tests that there is always just
       
   415     // one default).
       
   416     if (prevDefault)
       
   417         {
       
   418         prevDefault->ItemField().RemoveFieldType(KUidPbkDefaultFieldSms);
       
   419         }
       
   420 
       
   421     __ASSERT_DEBUG(
       
   422         (aField && DefaultSmsField()==aField) ||
       
   423         (!aField && !DefaultSmsField()),
       
   424         Panic(EPanicPostCond_SetDefaultPhoneNumberFieldL));
       
   425     }
       
   426 
       
   427 EXPORT_C void CPbkContactItem::RemoveDefaultSmsField()
       
   428     {
       
   429     // This is safe because SetDefaultSmsFieldL(NULL) guarantees
       
   430     // not to leave
       
   431     SetDefaultSmsFieldL(NULL);
       
   432     }
       
   433 
       
   434 EXPORT_C TPbkContactItemField* CPbkContactItem::DefaultEmailField() const
       
   435     {
       
   436     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
   437 
       
   438     // scan the fields for a match in default field for field id.
       
   439     const TInt fieldCount = iFields.Count();
       
   440     for (TInt i = 0; i < fieldCount; ++i)
       
   441         {
       
   442         const TPbkContactItemField& field = iFields[i];
       
   443         if (field.DefaultEmailField())
       
   444             {
       
   445             return const_cast<TPbkContactItemField*>(&field);
       
   446             }
       
   447         }
       
   448     return NULL;
       
   449     }
       
   450 
       
   451 EXPORT_C void CPbkContactItem::SetDefaultEmailFieldL
       
   452         (TPbkContactItemField* aField)
       
   453     {
       
   454     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
   455 
       
   456     if (aField)
       
   457         {
       
   458         aField = FindSameField(*aField);
       
   459         if (!aField)
       
   460             {
       
   461             // Not this item's field
       
   462             User::Leave(KErrNotFound);
       
   463             }
       
   464         }
       
   465 
       
   466     if (aField && aField->FieldInfo().FieldId() != EPbkFieldIdEmailAddress)
       
   467         {
       
   468         User::Leave(KErrNotSupported);
       
   469         }
       
   470 
       
   471     // 1. Fetch previous default
       
   472     TPbkContactItemField* prevDefault = DefaultEmailField();
       
   473 
       
   474     // 2. Set the new default if specified
       
   475     if (aField)
       
   476         {
       
   477         if (aField == prevDefault)
       
   478             {
       
   479             // Already set
       
   480             return;
       
   481             }
       
   482         aField->ItemField().AddFieldTypeL(KUidPbkDefaultFieldPref);
       
   483         }
       
   484 
       
   485     // 3. Unset any previous default (invariant tests that there is always just
       
   486     // one default).
       
   487     if (prevDefault)
       
   488         {
       
   489         prevDefault->ItemField().RemoveFieldType(KUidPbkDefaultFieldPref);
       
   490         }
       
   491 
       
   492     __ASSERT_DEBUG(
       
   493         (aField && DefaultEmailField()==aField) ||
       
   494         (!aField && !DefaultEmailField()),
       
   495         Panic(EPanicPostCond_SetDefaultEmailFieldL));
       
   496     }
       
   497 
       
   498 EXPORT_C void CPbkContactItem::RemoveDefaultEmailField()
       
   499     {
       
   500     // This is safe because SetDefaultEmailFieldL(NULL) guarantees
       
   501     // not to leave
       
   502     SetDefaultEmailFieldL(NULL);
       
   503     }
       
   504 
       
   505 
       
   506 EXPORT_C TPbkContactItemField* CPbkContactItem::DefaultEmailOverSmsField() const
       
   507     {
       
   508     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
   509 
       
   510     // scan the fields for a match in default field for field id.
       
   511     const TInt fieldCount = iFields.Count();
       
   512     for (TInt i = 0; i < fieldCount; ++i)
       
   513         {
       
   514         const TPbkContactItemField& field = iFields[i];
       
   515         if (field.DefaultEmailOverSmsField())
       
   516             {
       
   517             return const_cast<TPbkContactItemField*>(&field);
       
   518             }
       
   519         }
       
   520     return NULL;
       
   521     }
       
   522 
       
   523 EXPORT_C void CPbkContactItem::SetDefaultEmailOverSmsFieldL
       
   524         (TPbkContactItemField* aField)
       
   525     {
       
   526     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
   527 
       
   528     if (aField)
       
   529         {
       
   530         aField = FindSameField(*aField);
       
   531         if (!aField)
       
   532             {
       
   533             // Not this item's field
       
   534             User::Leave(KErrNotFound);
       
   535             }
       
   536         }
       
   537 
       
   538     if (aField && !aField->FieldInfo().IsEmailOverSmsField())
       
   539         {
       
   540         User::Leave(KErrNotSupported);
       
   541         }
       
   542 
       
   543     // 1. Fetch previous default
       
   544     TPbkContactItemField* prevDefault = DefaultEmailOverSmsField();
       
   545 
       
   546     // 2. Set the new default if specified
       
   547     if (aField)
       
   548         {
       
   549         if (aField == prevDefault)
       
   550             {
       
   551             // Already set
       
   552             return;
       
   553             }
       
   554         aField->ItemField().AddFieldTypeL(KUidPbkDefaultFieldEmailOverSms);
       
   555         }
       
   556 
       
   557     // 3. Unset any previous default (invariant tests that there is always just
       
   558     // one default).
       
   559     if (prevDefault)
       
   560         {
       
   561         prevDefault->ItemField().RemoveFieldType(KUidPbkDefaultFieldEmailOverSms);
       
   562         }
       
   563 
       
   564     __ASSERT_DEBUG(
       
   565         (aField && DefaultEmailOverSmsField()==aField) ||
       
   566         (!aField && !DefaultEmailOverSmsField()),
       
   567         Panic(EPanicPostCond_SetDefaultEmailOverSmsFieldL));
       
   568     }
       
   569 
       
   570 EXPORT_C void CPbkContactItem::RemoveDefaultEmailOverSmsField()
       
   571     {
       
   572     // This is safe because SetDefaultEmailOverSmsFieldL(NULL) guarantees
       
   573     // not to leave
       
   574     SetDefaultEmailOverSmsFieldL(NULL);
       
   575     }
       
   576 
       
   577 EXPORT_C TPbkContactItemField* CPbkContactItem::DefaultMmsField() const
       
   578     {
       
   579     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
   580 
       
   581     // scan the fields for a match in default field for field id.
       
   582     const TInt fieldCount = iFields.Count();
       
   583     for (TInt i = 0; i < fieldCount; ++i)
       
   584         {
       
   585         const TPbkContactItemField& field = iFields[i];
       
   586         if (field.DefaultMmsField())
       
   587             {
       
   588             return const_cast<TPbkContactItemField*>(&field);
       
   589             }
       
   590         }
       
   591     return NULL;
       
   592     }
       
   593 
       
   594 EXPORT_C void CPbkContactItem::SetDefaultMmsFieldL
       
   595         (TPbkContactItemField* aField)
       
   596     {
       
   597     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
   598 
       
   599     if (aField)
       
   600         {
       
   601         aField = FindSameField(*aField);
       
   602         if (!aField)
       
   603             {
       
   604             // Not this item's field
       
   605             User::Leave(KErrNotFound);
       
   606             }
       
   607         }
       
   608 
       
   609     if (aField && !aField->FieldInfo().IsMmsField())
       
   610         {
       
   611         User::Leave(KErrNotSupported);
       
   612         }
       
   613 
       
   614     // 1. Fetch previous default
       
   615     TPbkContactItemField* prevDefault = DefaultMmsField();
       
   616 
       
   617     // 2. Set the new default if specified
       
   618     if (aField)
       
   619         {
       
   620         if (aField == prevDefault)
       
   621             {
       
   622             // Already set
       
   623             return;
       
   624             }
       
   625         aField->ItemField().AddFieldTypeL(KUidPbkDefaultFieldMms);
       
   626         }
       
   627 
       
   628     // 3. Unset any previous default (invariant tests that there is always just
       
   629     // one default).
       
   630     if (prevDefault)
       
   631         {
       
   632         prevDefault->ItemField().RemoveFieldType(KUidPbkDefaultFieldMms);
       
   633         }
       
   634 
       
   635     __ASSERT_DEBUG(
       
   636         (aField && DefaultMmsField()==aField) ||
       
   637         (!aField && !DefaultMmsField()),
       
   638         Panic(EPanicPostCond_SetDefaultMmsFieldL));
       
   639     }
       
   640 
       
   641 EXPORT_C void CPbkContactItem::RemoveDefaultMmsField()
       
   642     {
       
   643     // This is safe because SetDefaultMmsFieldL(NULL) guarantees
       
   644     // not to leave
       
   645     SetDefaultMmsFieldL(NULL);
       
   646     }
       
   647 
       
   648 EXPORT_C TPbkContactItemField* CPbkContactItem::DefaultPocField() const
       
   649     {
       
   650     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
   651 
       
   652     // scan the fields for a match in default field for field id.
       
   653     const TInt fieldCount = iFields.Count();
       
   654     for (TInt i = 0; i < fieldCount; ++i)
       
   655         {
       
   656         const TPbkContactItemField& field = iFields[i];
       
   657         if (field.DefaultPocField())
       
   658             {
       
   659             return const_cast<TPbkContactItemField*>(&field);
       
   660             }
       
   661         }
       
   662     return NULL;
       
   663     }
       
   664 
       
   665 EXPORT_C void CPbkContactItem::SetDefaultPocFieldL
       
   666         (TPbkContactItemField* aField)
       
   667     {
       
   668     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
   669 
       
   670     if (aField)
       
   671         {
       
   672         aField = FindSameField(*aField);
       
   673         if (!aField)
       
   674             {
       
   675             // Not this item's field
       
   676             User::Leave(KErrNotFound);
       
   677             }
       
   678         }
       
   679 
       
   680     if (aField && !aField->FieldInfo().IsPocField())
       
   681         {
       
   682         User::Leave(KErrNotSupported);
       
   683         }
       
   684 
       
   685     // 1. Fetch previous default
       
   686     TPbkContactItemField* prevDefault = DefaultPocField();
       
   687 
       
   688     // 2. Set the new default if specified
       
   689     if (aField)
       
   690         {
       
   691         if (aField == prevDefault)
       
   692             {
       
   693             // Already set
       
   694             return;
       
   695             }
       
   696         aField->ItemField().AddFieldTypeL(KUidPbkDefaultFieldPoc);
       
   697         }
       
   698 
       
   699     // 3. Unset any previous default (invariant tests that there is always just
       
   700     // one default).
       
   701     if (prevDefault)
       
   702         {
       
   703         prevDefault->ItemField().RemoveFieldType(KUidPbkDefaultFieldPoc);
       
   704         }
       
   705 
       
   706     __ASSERT_DEBUG(
       
   707         (aField && DefaultPocField()==aField) ||
       
   708         (!aField && !DefaultPocField()),
       
   709         Panic(EPanicPostCond_SetDefaultPocFieldL));
       
   710     }
       
   711 
       
   712 EXPORT_C void CPbkContactItem::RemoveDefaultPocField()
       
   713     {
       
   714     // This is safe because SetDefaultPocFieldL(NULL) guarantees
       
   715     // not to leave
       
   716     SetDefaultPocFieldL(NULL);
       
   717     }
       
   718 
       
   719 EXPORT_C TPbkContactItemField* CPbkContactItem::DefaultVoipField() const
       
   720     {
       
   721     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
   722 
       
   723     // scan the fields for a match in default field for field id.
       
   724     const TInt fieldCount = iFields.Count();
       
   725     for (TInt i = 0; i < fieldCount; ++i)
       
   726         {
       
   727         const TPbkContactItemField& field = iFields[i];
       
   728         if (field.DefaultVoipField())
       
   729             {
       
   730             return const_cast<TPbkContactItemField*>(&field);
       
   731             }
       
   732         }
       
   733     return NULL;
       
   734     }
       
   735 
       
   736 EXPORT_C void CPbkContactItem::SetDefaultVoipFieldL
       
   737         (TPbkContactItemField* aField)
       
   738     {
       
   739     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
   740 
       
   741     if (aField)
       
   742         {
       
   743         aField = FindSameField(*aField);
       
   744         if (!aField)
       
   745             {
       
   746             // Not this item's field
       
   747             User::Leave(KErrNotFound);
       
   748             }
       
   749         }
       
   750 
       
   751     if (aField && !aField->FieldInfo().IsVoipField())
       
   752         {
       
   753         User::Leave(KErrNotSupported);
       
   754         }
       
   755 
       
   756     // 1. Fetch previous default
       
   757     TPbkContactItemField* prevDefault = DefaultVoipField();
       
   758 
       
   759     // 2. Set the new default if specified
       
   760     if (aField)
       
   761         {
       
   762         if (aField == prevDefault)
       
   763             {
       
   764             // Already set
       
   765             return;
       
   766             }
       
   767         aField->ItemField().AddFieldTypeL(KUidPbkDefaultFieldVoip);
       
   768         }
       
   769 
       
   770     // 3. Unset any previous default (invariant tests that there is always just
       
   771     // one default).
       
   772     if (prevDefault)
       
   773         {
       
   774         prevDefault->ItemField().RemoveFieldType(KUidPbkDefaultFieldVoip);
       
   775         }
       
   776 
       
   777     __ASSERT_DEBUG(
       
   778         (aField && DefaultVoipField()==aField) ||
       
   779         (!aField && !DefaultVoipField()),
       
   780         Panic(EPanicPostCond_SetDefaultVoipFieldL));
       
   781     }
       
   782 
       
   783 EXPORT_C void CPbkContactItem::RemoveDefaultVoipField()
       
   784     {
       
   785     // This is safe because SetDefaultVoipFieldL(NULL) guarantees
       
   786     // not to leave
       
   787     SetDefaultVoipFieldL(NULL);
       
   788     }
       
   789 
       
   790 EXPORT_C TPbkContactItemField* CPbkContactItem::VoiceTagField() const
       
   791     {
       
   792     TPbkContactItemField* ret = NULL;
       
   793 
       
   794     // Deprecated function
       
   795     if ( !FeatureManager::FeatureSupported( KFeatureIdSind ))
       
   796         {
       
   797         // scan the fields for a match in voice tag field for field id.
       
   798         const TInt fieldCount = iFields.Count();
       
   799         for (TInt i = 0; i < fieldCount; ++i)
       
   800             {
       
   801             const TPbkContactItemField& field = iFields[i];
       
   802             if (field.ItemField().ContentType().ContainsFieldType(
       
   803                 KUidContactsVoiceDialField))
       
   804                 {
       
   805                 ret = const_cast<TPbkContactItemField*>(&field);
       
   806                 break;
       
   807                 }
       
   808             }
       
   809         }
       
   810 
       
   811     return ret;
       
   812     }
       
   813 
       
   814 EXPORT_C void CPbkContactItem::SetVoiceTagFieldL
       
   815         (TPbkContactItemField* aField)
       
   816     {
       
   817     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
   818     if ( !FeatureManager::FeatureSupported(KFeatureIdSind) )
       
   819         {
       
   820 
       
   821         if (aField)
       
   822             {
       
   823             aField = FindSameField(*aField);
       
   824             if (!aField)
       
   825                 {
       
   826                 // Not this item's field
       
   827                 User::Leave(KErrNotFound);
       
   828                 }
       
   829             }
       
   830 
       
   831         // Test can we set a voice tag for this field
       
   832         // The VoIP field completely includes the IsPhoneNumberField subset,
       
   833         // so its enough to test with IsVoipField method only.
       
   834         if (aField && !aField->FieldInfo().IsVoipField())
       
   835             {
       
   836             User::Leave(KErrNotSupported);
       
   837             }
       
   838 
       
   839         // 1. Fetch previous voice tag field
       
   840         TPbkContactItemField* prevTag = VoiceTagField();
       
   841 
       
   842         // 2. Set the new voice tag, if specified
       
   843         if (aField)
       
   844             {
       
   845             if (prevTag == aField)
       
   846                 {
       
   847                 // Voice tag already set to aField
       
   848                 return;
       
   849                 }
       
   850             // If this leaves, this object's state remains unchanged
       
   851             aField->ItemField().AddFieldTypeL(KUidContactsVoiceDialField);
       
   852             }
       
   853 
       
   854         // 3. Unset any previous voice tag (invariant tests that there is always
       
   855         // just one voice tag).
       
   856         if (prevTag)
       
   857             {
       
   858             // Unset previous voice tag
       
   859             prevTag->ItemField().RemoveFieldType(KUidContactsVoiceDialField);
       
   860             }
       
   861 
       
   862         __ASSERT_DEBUG(
       
   863             (aField && VoiceTagField()==aField) ||
       
   864             (!aField && !VoiceTagField()),
       
   865             Panic(EPanicPostCond_SetVoiceTagFieldL));
       
   866         }
       
   867     }
       
   868 
       
   869 EXPORT_C void CPbkContactItem::RemoveVoiceTagField()
       
   870     {
       
   871     if ( !FeatureManager::FeatureSupported(KFeatureIdSind) )
       
   872         {
       
   873         // This is safe because SetVoiceTagFieldL(NULL) guarantees
       
   874         // not to leave
       
   875         SetVoiceTagFieldL(NULL);
       
   876         }
       
   877     }
       
   878 
       
   879 EXPORT_C TPbkContactItemField* CPbkContactItem::FindField
       
   880         (TPbkFieldId aFieldId) const
       
   881     {
       
   882     TInt index = 0;
       
   883     return FindField(aFieldId, index);
       
   884     }
       
   885 
       
   886 EXPORT_C TPbkContactItemField* CPbkContactItem::FindField
       
   887         (TPbkFieldId aFieldId, TInt& aIndex) const
       
   888     {
       
   889     __TEST_INVARIANT;
       
   890 
       
   891     const TInt fieldCount = iFields.Count();
       
   892     for (TInt i = Max(aIndex,0) ; i < fieldCount; ++i)
       
   893         {
       
   894         const TPbkContactItemField& field = iFields[i];
       
   895         if (field.FieldInfo().Match(aFieldId))
       
   896             {
       
   897             aIndex = i;
       
   898             return const_cast<TPbkContactItemField*>(&field);
       
   899             }
       
   900         }
       
   901 
       
   902     aIndex = KErrNotFound;
       
   903     return NULL;
       
   904     }
       
   905 
       
   906 EXPORT_C TPbkContactItemField* CPbkContactItem::FindField
       
   907         (const CPbkFieldInfo& aFieldInfo) const
       
   908     {
       
   909     TInt index = 0;
       
   910     return FindField(aFieldInfo, index);
       
   911     }
       
   912 
       
   913 EXPORT_C TPbkContactItemField* CPbkContactItem::FindField
       
   914         (const CPbkFieldInfo& aFieldInfo, TInt& aIndex) const
       
   915     {
       
   916     __TEST_INVARIANT;
       
   917 
       
   918     aIndex = FindFieldWithType(iFields, aFieldInfo, Max(aIndex,0));
       
   919     if (aIndex != KErrNotFound)
       
   920         {
       
   921         return const_cast<TPbkContactItemField*>(&iFields[aIndex]);
       
   922         }
       
   923     else
       
   924         {
       
   925         return NULL;
       
   926         }
       
   927     }
       
   928 
       
   929 EXPORT_C TInt CPbkContactItem::FindFieldIndex
       
   930         (const TPbkContactItemField& aField) const
       
   931     {
       
   932     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
   933 
       
   934     const TInt fieldCount = iFields.Count();
       
   935     for (TInt i = 0; i < fieldCount; ++i)
       
   936         {
       
   937         if(iFields[i].IsSame(aField))
       
   938             {
       
   939             __ASSERT_DEBUG(CardFields()[i].IsSame(aField),
       
   940                 Panic(EPanicPostCond_FindFieldIndex));
       
   941             return i;
       
   942             }
       
   943         }
       
   944 
       
   945     return KErrNotFound;
       
   946     }
       
   947 
       
   948 EXPORT_C TInt CPbkContactItem::FindContactItemFieldIndex
       
   949         (const CContactItemField& aField) const
       
   950     {
       
   951     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
   952 
       
   953     const CContactItemFieldSet& fields = iItem->CardFields();
       
   954     const TInt fieldCount = fields.Count();
       
   955     for (TInt i = 0; i < fieldCount; ++i)
       
   956         {
       
   957         if (&fields[i] == &aField)
       
   958             {
       
   959             return i;
       
   960             }
       
   961         }
       
   962     return KErrNotFound;
       
   963     }
       
   964 
       
   965 EXPORT_C TPbkContactItemField* CPbkContactItem::FindNextFieldWithPhoneNumber(
       
   966         const TDesC& aNumber,
       
   967         TInt aNumberOfDigits,
       
   968         TInt& aIndex) const
       
   969     {
       
   970     __TEST_INVARIANT;
       
   971 
       
   972     const TInt fieldCount = iFields.Count();
       
   973     for (TInt i = Max(aIndex,0); i < fieldCount; ++i)
       
   974         {
       
   975         const TPbkContactItemField& field = iFields[i];
       
   976         if (field.FieldInfo().IsPhoneNumberField())
       
   977             {
       
   978             if (PbkEngUtils::ContainSameDigits(field.Text(), aNumber,
       
   979                 aNumberOfDigits))
       
   980                 {
       
   981                 aIndex = i;
       
   982                 return const_cast<TPbkContactItemField*>(&field);
       
   983                 }
       
   984             }
       
   985         }
       
   986 
       
   987     aIndex = KErrNotFound;
       
   988     return NULL;
       
   989     }
       
   990 
       
   991 EXPORT_C TPbkContactItemField* CPbkContactItem::FindNextFieldWithText
       
   992         (const TDesC& aText,
       
   993         TInt& aIndex) const
       
   994     {
       
   995     __TEST_INVARIANT;
       
   996 
       
   997     const TInt fieldCount = iFields.Count();
       
   998     for (TInt i = Max(aIndex,0); i < fieldCount; ++i)
       
   999         {
       
  1000         const TPbkContactItemField& field = iFields[i];
       
  1001         if (field.StorageType() == KStorageTypeText)
       
  1002             {
       
  1003             if (field.Text().FindF(aText) >= 0)
       
  1004                 {
       
  1005                 aIndex = i;
       
  1006                 return const_cast<TPbkContactItemField*>(&field);
       
  1007                 }
       
  1008             }
       
  1009         }
       
  1010 
       
  1011     aIndex = KErrNotFound;
       
  1012     return NULL;
       
  1013     }
       
  1014 
       
  1015 EXPORT_C TPbkContactItemField* CPbkContactItem::FindSameField
       
  1016         (const TPbkContactItemField& aField) const
       
  1017     {
       
  1018     const TInt fieldCount = iFields.Count();
       
  1019     for (TInt i=0; i < fieldCount; ++i)
       
  1020         {
       
  1021         if (iFields[i].IsSame(aField))
       
  1022             {
       
  1023             return const_cast<TPbkContactItemField*>(&iFields[i]);
       
  1024             }
       
  1025         }
       
  1026     return NULL;
       
  1027     }
       
  1028 
       
  1029 EXPORT_C void CPbkContactItem::RemoveField
       
  1030         (TInt aIndex)
       
  1031     {
       
  1032     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
  1033     __ASSERT_DEBUG(aIndex >= 0 && aIndex < CardFields().Count(),
       
  1034         Panic(EPanicPreCond_RemoveField));
       
  1035     PBK_DEBUG_ONLY(TInt old_myCount = CardFields().Count());
       
  1036     PBK_DEBUG_ONLY(TInt old_otherCount = iItem->CardFields().Count());
       
  1037 
       
  1038     CContactItemField* field = &(CardFields()[aIndex].ItemField());
       
  1039     TInt i;
       
  1040     const TInt fieldCount = iItem->CardFields().Count();
       
  1041     for (i=0; i < fieldCount; ++i)
       
  1042         {
       
  1043         if (&iItem->CardFields()[i] == field)
       
  1044             {
       
  1045             break;
       
  1046             }
       
  1047         }
       
  1048     // Field must be found
       
  1049     __ASSERT_DEBUG(i < iItem->CardFields().Count(), Panic(EPanicLogic_RemoveField));
       
  1050     iItem->RemoveField(i);
       
  1051 
       
  1052     iFields.Delete(aIndex);
       
  1053 
       
  1054     __ASSERT_DEBUG(CardFields().Count() == old_myCount-1,
       
  1055         Panic(EPanicPostCond_RemoveField));
       
  1056     __ASSERT_DEBUG(iItem->CardFields().Count() == old_otherCount-1,
       
  1057         Panic(EPanicPostCond_RemoveField));
       
  1058     }
       
  1059 
       
  1060 
       
  1061 EXPORT_C TPbkContactItemField& CPbkContactItem::AddFieldL
       
  1062         (CPbkFieldInfo& aFieldInfo)
       
  1063     {
       
  1064     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
  1065     PBK_DEBUG_ONLY(TInt old_Count = CardFields().Count());
       
  1066 
       
  1067     // Create new contact model field with help from aFieldInfo
       
  1068     CContactItemField* itemField = aFieldInfo.CreateFieldL();
       
  1069     CleanupStack::PushL(itemField);
       
  1070 
       
  1071     // Create and initialize a new Phonebook field object.
       
  1072     TPbkContactItemField pbkField(itemField,&aFieldInfo);
       
  1073 
       
  1074     // Try to make room to iFields for the new Phonebook field. This call makes
       
  1075     // this function leave-safe, see *)
       
  1076     iFields.SetReserveL(iFields.Count()+1);
       
  1077 
       
  1078     // Check that calling SetReserveL doesn't break the class invariant.
       
  1079     // It shouldn't because it doesnt change iFields.Count().
       
  1080     __TEST_INVARIANT;
       
  1081 
       
  1082     // Add the contact model field to iItem
       
  1083     iItem->AddFieldL(*itemField);
       
  1084     CleanupStack::Pop(itemField);  // itemField now owned by iItem
       
  1085 
       
  1086     // Here the invariant doesn't hold
       
  1087 
       
  1088     // Insert the new Phonebook field.
       
  1089     // *) This call is guaranteed NOT to leave because we have succesfully
       
  1090     // reserved space to iFields with the SetReserveL call above.
       
  1091     TInt index = InsertionPos(pbkField);
       
  1092     iFields.InsertL(index, pbkField);
       
  1093 
       
  1094     TPbkContactItemField& newField = iFields[index];
       
  1095 
       
  1096     //PostCond:
       
  1097     __ASSERT_DEBUG(&newField.ItemField() == itemField,
       
  1098         Panic(EPanicPostCond_AddFieldL));
       
  1099     __ASSERT_DEBUG(newField.FieldInfo().IsSame(aFieldInfo),
       
  1100         Panic(EPanicPostCond_AddFieldL));
       
  1101     __ASSERT_DEBUG(iFields.Count() == old_Count+1,
       
  1102         Panic(EPanicPostCond_AddFieldL));
       
  1103     __ASSERT_DEBUG(index == iFields.Count()-1 ||
       
  1104         iFields[index+1].Compare(iFields[index]) > 0,
       
  1105         Panic(EPanicPostCond_AddFieldL));
       
  1106 
       
  1107     return newField;
       
  1108     }
       
  1109 
       
  1110 EXPORT_C TBool CPbkContactItem::CanAcceptDataOfType
       
  1111         (CPbkFieldInfo& aFieldInfo) const
       
  1112     {
       
  1113     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
  1114 
       
  1115     // Search for an empty field of type aFieldInfo
       
  1116     const TInt fieldCount = CardFields().Count();
       
  1117     TInt countOfFieldsOfSameType = 0;
       
  1118     for (TInt i=0; i < fieldCount; ++i)
       
  1119         {
       
  1120         const TPbkContactItemField& f = iFields[i];
       
  1121         if (f.FieldInfo().IsSame(aFieldInfo))
       
  1122             {
       
  1123             ++countOfFieldsOfSameType;
       
  1124             if (f.IsEmpty())
       
  1125                 {
       
  1126                 // Empty field of same type found
       
  1127                 return ETrue;
       
  1128                 }
       
  1129             }
       
  1130         }
       
  1131 
       
  1132     // Check if a new field can be added
       
  1133     if (countOfFieldsOfSameType == 0 ||
       
  1134          aFieldInfo.Multiplicity()==EPbkFieldMultiplicityMany)
       
  1135         {
       
  1136         // New field can be added
       
  1137         return ETrue;
       
  1138         }
       
  1139 
       
  1140     // Out of luck
       
  1141     return EFalse;
       
  1142     }
       
  1143 
       
  1144 EXPORT_C TPbkContactItemField* CPbkContactItem::AddOrReturnUnusedFieldL
       
  1145         (CPbkFieldInfo& aFieldInfo)
       
  1146     {
       
  1147     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
  1148 
       
  1149     TPbkContactItemField* field = NULL;
       
  1150 
       
  1151     // Search for an empty field of type aFieldInfo
       
  1152     const TInt fieldCount = CardFields().Count();
       
  1153     TInt countOfFieldsOfSameType = 0;
       
  1154     for (TInt i=0; i < fieldCount; ++i)
       
  1155         {
       
  1156         TPbkContactItemField& f = iFields[i];
       
  1157         if (f.FieldInfo().IsSame(aFieldInfo))
       
  1158             {
       
  1159             ++countOfFieldsOfSameType;
       
  1160             if (f.IsEmpty())
       
  1161                 {
       
  1162                 // Empty field of same type found
       
  1163                 field = &f;
       
  1164                 break;
       
  1165                 }
       
  1166             }
       
  1167         }
       
  1168 
       
  1169     if (!field)
       
  1170         {
       
  1171         // Empty field of same type was not found
       
  1172         if (countOfFieldsOfSameType == 0 ||
       
  1173              aFieldInfo.Multiplicity()==EPbkFieldMultiplicityMany)
       
  1174             {
       
  1175             // Add a new field
       
  1176             field = &AddFieldL(aFieldInfo);
       
  1177             }
       
  1178         }
       
  1179 
       
  1180     return field;
       
  1181     }
       
  1182 
       
  1183 EXPORT_C void CPbkContactItem::UpdateFieldSetL
       
  1184         (const CPbkFieldsInfo& aFieldsInfo)
       
  1185     {
       
  1186     //PreCond:
       
  1187     __ASSERT_DEBUG(iItem, Panic(EPanicPreCond_UpdateFieldSetL));
       
  1188     // Don't test invariant, because this function needs to be called when
       
  1189     // the invariant is broken!
       
  1190 
       
  1191     // Recreate field array like in ConstructL
       
  1192     CreateFieldArrayL(*iItem, aFieldsInfo);
       
  1193 
       
  1194     __TEST_INVARIANT;
       
  1195     }
       
  1196 
       
  1197 EXPORT_C CPbkFieldArray& CPbkContactItem::CardFields() const
       
  1198     {
       
  1199     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
  1200     return const_cast<CPbkFieldArray&>(iFields);
       
  1201     }
       
  1202 
       
  1203 
       
  1204 EXPORT_C TUid CPbkContactItem::Type() const
       
  1205     {
       
  1206     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
  1207     return iItem->Type();
       
  1208     }
       
  1209 
       
  1210 
       
  1211 EXPORT_C TContactItemId CPbkContactItem::Id() const
       
  1212     {
       
  1213     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
  1214     return iItem->Id();
       
  1215     }
       
  1216 
       
  1217 EXPORT_C CContactIdArray* CPbkContactItem::GroupsJoinedLC() const
       
  1218     {
       
  1219     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
  1220     __ASSERT_ALWAYS(iItem->Type() == KUidContactCard,
       
  1221         Panic(EPanicPreCond_GroupsJoinedLC));
       
  1222     return static_cast<const CContactCard*>(iItem)->GroupsJoinedLC();
       
  1223     }
       
  1224 
       
  1225 TInt CPbkContactItem::PbkFieldCount() const
       
  1226     {
       
  1227     return iFields.Count();
       
  1228     }
       
  1229 
       
  1230 MPbkFieldData& CPbkContactItem::PbkFieldAt(TInt aIndex)
       
  1231     {
       
  1232     // PreCond: iFields will __ASSERT_ALWAYS aIndex validity
       
  1233     return iFields[aIndex];
       
  1234     }
       
  1235 
       
  1236 const MPbkFieldData& CPbkContactItem::PbkFieldAt(TInt aIndex) const
       
  1237     {
       
  1238     // PreCond: iFields will __ASSERT_ALWAYS aIndex validity
       
  1239     return iFields[aIndex];
       
  1240     }
       
  1241 
       
  1242 void CPbkContactItem::PrepareForSaveL()
       
  1243     {
       
  1244     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
  1245 
       
  1246     // check that there is the syncronization field
       
  1247     // otherwise add the syncronization field
       
  1248     TPbkContactItemField* syncField = FindField(EPbkFieldIdSyncronization);
       
  1249     if (!syncField)
       
  1250         {
       
  1251         // add the syncronization field to the contact
       
  1252         CPbkContactEngine* engine = CPbkContactEngine::Static();
       
  1253         if (engine)
       
  1254             {
       
  1255             CPbkFieldInfo* syncFieldInfo = engine->FieldsInfo().Find(
       
  1256                 EPbkFieldIdSyncronization);
       
  1257             if (syncFieldInfo)
       
  1258                 {
       
  1259                 // add syncronization field to contact - compulsory
       
  1260                 AddFieldL(*syncFieldInfo);
       
  1261                 }
       
  1262             }
       
  1263         }
       
  1264 
       
  1265     for (TInt i=iFields.Count()-1; i >= 0; --i)
       
  1266         {
       
  1267         TPbkContactItemField& field = iFields[i];
       
  1268 
       
  1269         // check that syncronization field has correct value
       
  1270         if (field.FieldInfo().FieldId() == EPbkFieldIdSyncronization)
       
  1271             {
       
  1272             // check that theres private, public or none text in the field
       
  1273             // use the default if incorrect or no value
       
  1274             const TDesC& fieldtext = field.TextStorage()->Text();
       
  1275             // safely detect whether theres syncronization setting in the field
       
  1276             if (!(!fieldtext.CompareF(KPbkContactSyncPrivate) ||
       
  1277                 !fieldtext.CompareF(KPbkContactSyncPublic) ||
       
  1278                 !fieldtext.CompareF(KPbkContactSyncNoSync)))
       
  1279                 {
       
  1280                 // set default sync setting to field
       
  1281                 field.TextStorage()->SetTextL(KPbkContactSyncPrivate);
       
  1282                 }
       
  1283             }
       
  1284 
       
  1285         field.PrepareForSaveL();
       
  1286         if (field.HasInvalidDate())
       
  1287             {
       
  1288             RemoveField(i);
       
  1289             }
       
  1290         }
       
  1291     }
       
  1292 
       
  1293 void CPbkContactItem::PrepareAfterLoadL()
       
  1294     {
       
  1295     PBK_DEBUG_TEST_INVARIANT_ON_ENTRY_AND_EXIT;
       
  1296     for (TInt i=iFields.Count()-1; i >= 0; --i)
       
  1297         {
       
  1298         TPbkContactItemField& field = iFields[i];
       
  1299         field.PrepareAfterLoadL();
       
  1300         if (field.HasInvalidDate())
       
  1301             {
       
  1302             RemoveField(i);
       
  1303             }
       
  1304         }
       
  1305     }
       
  1306 
       
  1307 /**
       
  1308  * Class invariant.
       
  1309  */
       
  1310 EXPORT_C void CPbkContactItem::__DbgTestInvariant() const
       
  1311     {
       
  1312 #ifdef _DEBUG
       
  1313     // Check proper construction
       
  1314     __ASSERT_DEBUG(iItem, Panic(EPanicInvariant_Pointer));
       
  1315 
       
  1316     // Check field counts
       
  1317     __ASSERT_DEBUG(iItem->CardFields().Count() >= iFields.Count(),
       
  1318         Panic(EPanicInvariant_Count));
       
  1319 
       
  1320     TInt phoneDefaultCount = 0;
       
  1321     TInt smsDefaultCount = 0;
       
  1322     TInt emailDefaultCount = 0;
       
  1323     TInt voiceTagFieldCount = 0;
       
  1324 
       
  1325     CPbkContactEngine* engine = CPbkContactEngine::Static();
       
  1326 
       
  1327     // Scan all fields
       
  1328     TInt i;
       
  1329     const TInt fieldCount = iFields.Count();
       
  1330     for (i=0; i < fieldCount; ++i)
       
  1331         {
       
  1332         const TPbkContactItemField& pbkField = iFields[i];
       
  1333 
       
  1334         // Check field info for all fields
       
  1335         if (engine)
       
  1336             {
       
  1337             const CPbkFieldInfo* fieldInfo =
       
  1338                 engine->FieldsInfo().Find(pbkField.ItemField());
       
  1339             __ASSERT_DEBUG(fieldInfo && fieldInfo->IsSame(pbkField.FieldInfo()),
       
  1340                            Panic(EPanicInvariant_FieldInfo));
       
  1341             }
       
  1342 
       
  1343         // Search field from iItem's fieldset
       
  1344         TInt j;
       
  1345         const TInt itemFieldCount = iItem->CardFields().Count();
       
  1346         for (j = 0; j < itemFieldCount; ++j)
       
  1347             {
       
  1348             CContactItemField& field = iItem->CardFields()[j];
       
  1349             // Check if field found
       
  1350             if(&pbkField.ItemField() == &field)
       
  1351                 {
       
  1352                 break;
       
  1353                 }
       
  1354             }
       
  1355         // field must be found
       
  1356         __ASSERT_DEBUG(j < iItem->CardFields().Count(),
       
  1357             Panic(EPanicInvariant_Field));
       
  1358 
       
  1359         // Update default field counts
       
  1360         TInt prefCount = 0;
       
  1361         TInt smsCount = 0;
       
  1362         TInt voiceTagCount = 0;
       
  1363         TInt videoTagCount = 0;
       
  1364         const CContentType& contentType = pbkField.ItemField().ContentType();
       
  1365         for (TInt t = 0; t < contentType.FieldTypeCount(); ++t)
       
  1366             {
       
  1367             if (contentType.FieldType(t) == KUidPbkDefaultFieldPref)
       
  1368                 ++prefCount;
       
  1369             else if (contentType.FieldType(t) == KUidPbkDefaultFieldSms)
       
  1370                 ++smsCount;
       
  1371             else if (contentType.FieldType(t) == KUidContactsVoiceDialField)
       
  1372                 ++voiceTagCount;
       
  1373             else if (contentType.FieldType(t) == KUidPbkDefaultFieldVideo)
       
  1374                 ++videoTagCount;
       
  1375             }
       
  1376         __ASSERT_DEBUG(prefCount <= 2, Panic(EPanicInvariant_PrefCount));
       
  1377         __ASSERT_DEBUG(smsCount <= 1, Panic(EPanicInvariant_SmsCount));
       
  1378         __ASSERT_DEBUG(prefCount < 2 || smsCount == 1,
       
  1379             Panic(EPanicInvariant_PrefSmsCount));
       
  1380         __ASSERT_DEBUG(voiceTagCount <= 1,
       
  1381             Panic(EPanicInvariant_VoiceTagCount));
       
  1382         __ASSERT_DEBUG(videoTagCount <= 1,
       
  1383             Panic(EPanicInvariant_VideoTagCount));
       
  1384 
       
  1385         if (pbkField.FieldInfo().IsPhoneNumberField() && prefCount >= 1)
       
  1386             {
       
  1387             if (smsCount == 1)
       
  1388                 {
       
  1389                 ++smsDefaultCount;
       
  1390                 }
       
  1391             if ((prefCount==1 && smsCount==0) || (prefCount==2 && smsCount==1))
       
  1392                 {
       
  1393                 ++phoneDefaultCount;
       
  1394                 }
       
  1395             }
       
  1396         if (pbkField.FieldInfo().FieldId() == EPbkFieldIdEmailAddress &&
       
  1397             prefCount==1)
       
  1398             {
       
  1399             ++emailDefaultCount;
       
  1400             }
       
  1401         if (voiceTagCount > 0)
       
  1402             {
       
  1403             ++voiceTagFieldCount;
       
  1404             }
       
  1405         }
       
  1406 
       
  1407     // Check default counts: only one default per category allowed
       
  1408     __ASSERT_DEBUG(phoneDefaultCount <= 1,
       
  1409         Panic(EPanicInvariant_PhoneDefaultCount));
       
  1410     __ASSERT_DEBUG(smsDefaultCount <= 1,
       
  1411         Panic(EPanicInvariant_SmsDefaultCount));
       
  1412     __ASSERT_DEBUG(emailDefaultCount <= 1,
       
  1413         Panic(EPanicInvariant_EmailDefaultCount));
       
  1414     __ASSERT_DEBUG(voiceTagFieldCount <= 1,
       
  1415         Panic(EPanicInvariant_VoiceTagFieldCount));
       
  1416 
       
  1417     // Test field sorting
       
  1418     for (i = 0; i < iFields.Count()-1; ++i)
       
  1419         {
       
  1420         __ASSERT_DEBUG(iFields[i].Compare(iFields[i+1]) <= 0,
       
  1421             Panic(EPanicInvariant_Sorting));
       
  1422         }
       
  1423 #endif
       
  1424     }
       
  1425 
       
  1426 void CPbkContactItem::CreateFieldArrayL
       
  1427         (CContactItem& aContactItem,
       
  1428         const CPbkFieldsInfo& aFieldsInfo)
       
  1429     {
       
  1430     const TInt fieldCount = aContactItem.CardFields().Count();
       
  1431     iFields.SetReserveL(fieldCount);
       
  1432     // Use Delete instead of Reset to keep the array buffer allocated above
       
  1433     iFields.Delete(0, iFields.Count());
       
  1434     CContactItemFieldSet& fieldSet = aContactItem.CardFields();
       
  1435 
       
  1436     // Loop through all import priority levels
       
  1437     for (TPbkMatchPriorityLevel priorityLevel(aFieldsInfo.CreateMatchPriority());
       
  1438         !priorityLevel.End();
       
  1439         priorityLevel.Next())
       
  1440         {
       
  1441         // Loop through all the fields
       
  1442         for (TInt i=0; i < fieldCount; ++i)
       
  1443             {
       
  1444             CContactItemField& field = fieldSet[i];
       
  1445             CPbkFieldInfo* fieldType = aFieldsInfo.Match(field, priorityLevel);
       
  1446             if (fieldType)
       
  1447                 {
       
  1448                 // Check that the field has not already been added
       
  1449                 const TInt fieldCount = iFields.Count();
       
  1450                 TInt i;
       
  1451                 for (i=0; i < fieldCount; ++i)
       
  1452                     {
       
  1453                     const TPbkContactItemField& pbkField = iFields[i];
       
  1454                     if (&pbkField.ItemField()==&field ||
       
  1455                         (fieldType->Multiplicity()==EPbkFieldMultiplicityOne &&
       
  1456                         pbkField.FieldInfo().IsSame(*fieldType)))
       
  1457                         {
       
  1458                         break;
       
  1459                         }
       
  1460                     }
       
  1461                 if (i == fieldCount)
       
  1462                     {
       
  1463                     // Insert the field directly into presentation order
       
  1464                     TPbkContactItemField pbkField(&field, fieldType);
       
  1465                     iFields.InsertL(InsertionPos(pbkField), pbkField);
       
  1466                     }
       
  1467                 }
       
  1468             }
       
  1469         }
       
  1470     }
       
  1471 
       
  1472 /**
       
  1473  * Returns insertion position for aField.
       
  1474  */
       
  1475 TInt CPbkContactItem::InsertionPos
       
  1476         (const TPbkContactItemField& aField) const
       
  1477     {
       
  1478     // Search for an insertion pos using the "upper bound" algorithm.
       
  1479     TInt first = 0;
       
  1480     TInt len = iFields.Count();
       
  1481     while (len > 0)
       
  1482         {
       
  1483         const TInt half = len / 2;
       
  1484         const TInt middle = first + half;
       
  1485         if (aField.Compare(iFields[middle]) < 0)
       
  1486             {
       
  1487             len = half;
       
  1488             }
       
  1489         else
       
  1490             {
       
  1491             first = middle + 1;
       
  1492             len = len - half - 1;
       
  1493             }
       
  1494         }
       
  1495 
       
  1496     // If upper bound found a match, insertion pos is after that.
       
  1497     if (first < iFields.Count() && aField.Compare(iFields[first]) == 0)
       
  1498         {
       
  1499         ++first;
       
  1500         }
       
  1501 
       
  1502     // PostCond
       
  1503     __ASSERT_DEBUG(first >= 0 && first <= iFields.Count(),
       
  1504         Panic(EPanicPostCond_InsertionPos));
       
  1505     return first;
       
  1506     }
       
  1507 
       
  1508 // ================= OTHER EXPORTED FUNCTIONS ==============
       
  1509 
       
  1510 EXPORT_C TBool operator==
       
  1511         (const CPbkContactItem& aLeft, const CPbkContactItem& aRight)
       
  1512     {
       
  1513     const TInt fieldCount = aLeft.iFields.Count();
       
  1514     if (aRight.iFields.Count() != fieldCount)
       
  1515         {
       
  1516         return EFalse;
       
  1517         }
       
  1518 
       
  1519     for (TInt i=0; i < fieldCount; ++i)
       
  1520         {
       
  1521         if (aLeft.iFields[i] != aRight.iFields[i])
       
  1522             {
       
  1523             return EFalse;
       
  1524             }
       
  1525         }
       
  1526 
       
  1527     return ETrue;
       
  1528     }
       
  1529 
       
  1530 //  End of File