javaextensions/pim/cntadapter/src.s60/cpimcontactlistadapter.cpp
branchRCL_3
changeset 19 04becd199f91
child 67 63b81d807542
equal deleted inserted replaced
16:f5050f1da672 19:04becd199f91
       
     1 /*
       
     2 * Copyright (c) 2008 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:  Handles PIM contact list <-> Contacts Model conversions
       
    15  *
       
    16 */
       
    17 
       
    18 
       
    19 // CLASS HEADER
       
    20 #include "cpimcontactlistadapter.h"
       
    21 
       
    22 // INTERNAL INCLUDES
       
    23 #include "cpimcontactcategorymanager.h"
       
    24 #include "cpimcontactitemadapter.h"
       
    25 #include "mpimcontactitem.h"
       
    26 #include "mpimitemdata.h"
       
    27 #include "logger.h"
       
    28 
       
    29 // EXTERNAL INCLUDES
       
    30 #include <badesca.h>
       
    31 #include <cntdb.h>
       
    32 #include <cntitem.h> // CContactGroup
       
    33 #include <cntfilt.h> // CCntFilter
       
    34 
       
    35 
       
    36 // ============================ MEMBER FUNCTIONS ===============================
       
    37 
       
    38 // -----------------------------------------------------------------------------
       
    39 // CPIMContactListAdapter::NewL
       
    40 // Two-phased constructor.
       
    41 // -----------------------------------------------------------------------------
       
    42 //
       
    43 CPIMContactListAdapter* CPIMContactListAdapter::NewL(
       
    44     java::util::FunctionServer* aFuncServer)
       
    45 {
       
    46     JELOG2(EPim);
       
    47     CPIMContactListAdapter* self =
       
    48         new(ELeave) CPIMContactListAdapter(aFuncServer);
       
    49 
       
    50     CallMethodL(self, &CPIMContactListAdapter::ConstructL, self->iFuncServer);
       
    51 
       
    52     return self;
       
    53 }
       
    54 
       
    55 // Destructor
       
    56 CPIMContactListAdapter::~CPIMContactListAdapter()
       
    57 {
       
    58     JELOG2(EPim);
       
    59     Close();
       
    60 }
       
    61 // -----------------------------------------------------------------------------
       
    62 // CPIMContactListAdapter::HandleDatabaseEventL
       
    63 // Tests the contact database observer event type and handles it. The ID of
       
    64 // a contact affected by the change event, if relevant, can be retrieved
       
    65 // via TContactDbObserverEvent::iContactId.
       
    66 // -----------------------------------------------------------------------------
       
    67 //
       
    68 void CPIMContactListAdapter::HandleDatabaseEventL(
       
    69     TContactDbObserverEvent aEvent) // information about the change event
       
    70 {
       
    71     JELOG2(EPim);
       
    72     switch (aEvent.iType)
       
    73     {
       
    74     case EContactDbObserverEventGroupAdded:
       
    75     {
       
    76         ExternalGroupChangeL(aEvent.iContactId, EPIMExternalChangeNew);
       
    77         break;
       
    78     }
       
    79     case EContactDbObserverEventGroupChanged:
       
    80     {
       
    81         ExternalGroupChangeL(aEvent.iContactId, EPIMExternalChangeModified);
       
    82         break;
       
    83     }
       
    84     case EContactDbObserverEventGroupDeleted:
       
    85     {
       
    86         ExternalGroupChangeL(aEvent.iContactId, EPIMExternalChangeRemoved);
       
    87         break;
       
    88     }
       
    89     case EContactDbObserverEventContactAdded:
       
    90     {
       
    91         ExternalItemChangeL(aEvent.iContactId, EPIMExternalChangeNew);
       
    92         break;
       
    93     }
       
    94     case EContactDbObserverEventContactChanged:
       
    95     {
       
    96         ExternalItemChangeL(aEvent.iContactId, EPIMExternalChangeModified);
       
    97         break;
       
    98     }
       
    99     case EContactDbObserverEventContactDeleted:
       
   100     {
       
   101         ExternalItemChangeL(aEvent.iContactId, EPIMExternalChangeRemoved);
       
   102         break;
       
   103     }
       
   104     default:
       
   105     {
       
   106         // we don't care about other changes
       
   107         return;
       
   108     }
       
   109     }
       
   110 }
       
   111 
       
   112 
       
   113 // -----------------------------------------------------------------------------
       
   114 // CPIMContactListAdapter::GetCategoriesL
       
   115 // Provides all categories currently existing in the native database.
       
   116 // Returns: Array of categories
       
   117 // -----------------------------------------------------------------------------
       
   118 //
       
   119 const CDesCArray& CPIMContactListAdapter::GetCategoriesL()
       
   120 {
       
   121     JELOG2(EPim);
       
   122     __ASSERT_ALWAYS(iCategoryManager, User::Leave(KErrNotReady));
       
   123     return iCategoryManager->CallGetCategoriesL();
       
   124 }
       
   125 
       
   126 // -----------------------------------------------------------------------------
       
   127 // CPIMContactListAdapter::AddCategoryL
       
   128 // Adds a new category to the native database.
       
   129 // If the category already  exists, nothing is done and the method returns
       
   130 // successfully.
       
   131 // -----------------------------------------------------------------------------
       
   132 //
       
   133 void CPIMContactListAdapter::AddCategoryL(const TDesC& aNewCategory)
       
   134 {
       
   135     JELOG2(EPim);
       
   136     __ASSERT_ALWAYS(iCategoryManager, User::Leave(KErrNotReady));
       
   137     CallMethodL(iCategoryManager, &CPIMContactCategoryManager::AddCategoryL,
       
   138                 aNewCategory, iFuncServer);
       
   139 }
       
   140 
       
   141 // -----------------------------------------------------------------------------
       
   142 // CPIMContactListAdapter::DeleteCategoryL
       
   143 // Deletes an existing category.
       
   144 // If there is no such category, nothing is done and the method returns
       
   145 // successfully.
       
   146 // -----------------------------------------------------------------------------
       
   147 //
       
   148 void CPIMContactListAdapter::DeleteCategoryL(const TDesC& aCategory)
       
   149 {
       
   150     JELOG2(EPim);
       
   151     __ASSERT_ALWAYS(iCategoryManager, User::Leave(KErrNotReady));
       
   152     CallMethodL(iCategoryManager, &CPIMContactCategoryManager::DeleteCategoryL,
       
   153                 aCategory, iFuncServer);
       
   154 }
       
   155 
       
   156 // -----------------------------------------------------------------------------
       
   157 // CPIMContactListAdapter::RenameCategoryL
       
   158 // Renames an existing category.
       
   159 // Entries in the old category are moved to the new category.
       
   160 // -----------------------------------------------------------------------------
       
   161 //
       
   162 void CPIMContactListAdapter::RenameCategoryL(const TDesC& aOldCategory, // The old category name
       
   163         const TDesC& aNewCategory) // The new category name
       
   164 {
       
   165     JELOG2(EPim);
       
   166     __ASSERT_ALWAYS(iCategoryManager, User::Leave(KErrNotReady));
       
   167     CallMethodL(iCategoryManager, &CPIMContactCategoryManager::RenameCategoryL,
       
   168                 aOldCategory, aNewCategory, iFuncServer);
       
   169 }
       
   170 
       
   171 // -----------------------------------------------------------------------------
       
   172 // CPIMContactListAdapter::IsCategoriesExternallyModified
       
   173 // Checks whether there have been external changes to the categories in
       
   174 // the native database after last call to
       
   175 // GetExternalCategoryModifications or list adapter creation.
       
   176 // Returns: ETrue: If there are any external changes
       
   177 //          EFalse: Otherwise
       
   178 // -----------------------------------------------------------------------------
       
   179 //
       
   180 TBool CPIMContactListAdapter::IsCategoriesExternallyModified()
       
   181 {
       
   182     JELOG2(EPim);
       
   183     if (iCategoryChanges)
       
   184     {
       
   185         return ETrue;
       
   186     }
       
   187     return EFalse;
       
   188 }
       
   189 
       
   190 // -----------------------------------------------------------------------------
       
   191 // CPIMContactListAdapter::GetExternalCategoryModificationsL
       
   192 // Provides the external changes to the categories in the native database.
       
   193 // Returns: An array of category state change objects. The ownership
       
   194 //          of the array is transferred to the caller. Note that the
       
   195 //          array elements contain heap-allocated data.
       
   196 // -----------------------------------------------------------------------------
       
   197 //
       
   198 RPointerArray<CPIMCategoryStateChange>*
       
   199 CPIMContactListAdapter::GetExternalCategoryModificationsL()
       
   200 {
       
   201     JELOG2(EPim);
       
   202     CallMethodL(this, &CPIMContactListAdapter::IsDatabaseReadyL, iFuncServer);
       
   203     RPointerArray<CPIMCategoryStateChange>* retval = iCategoryChanges;
       
   204     iCategoryChanges = NULL;
       
   205     return retval;
       
   206 }
       
   207 
       
   208 // -----------------------------------------------------------------------------
       
   209 // CPIMContactListAdapter::IsItemsExternallyModified
       
   210 // Checks whether there have been external changes to the items in
       
   211 // the native database after last call to
       
   212 // GetExternalItemModifications or list adapter creation.
       
   213 // Returns: EExternalChangesMinor: If there are any external changes
       
   214 //          EExternalChangesNone: Otherwise
       
   215 // -----------------------------------------------------------------------------
       
   216 //
       
   217 MPIMListAdapter::TExternalItemChangeClass CPIMContactListAdapter::IsItemsExternallyModified()
       
   218 {
       
   219     JELOG2(EPim);
       
   220     if ((iItemChanges || iFirstItemChanges))
       
   221     {
       
   222         return MPIMListAdapter::EExternalChangesMinor;
       
   223     }
       
   224     return MPIMListAdapter::EExternalChangesNone;
       
   225 }
       
   226 
       
   227 // -----------------------------------------------------------------------------
       
   228 // CPIMContactListAdapter::GetExternalItemModificationsL
       
   229 // Provides the external changes to the items in the native database.
       
   230 // Returns: An array of item state change objects. The ownership
       
   231 //          of the array is transferred to the caller. Note that the
       
   232 //          array elements contain heap-allocated data.
       
   233 // -----------------------------------------------------------------------------
       
   234 //
       
   235 RPointerArray<CPIMItemStateChange>*
       
   236 CPIMContactListAdapter::GetExternalItemModificationsL()
       
   237 {
       
   238     JELOG2(EPim);
       
   239     CallMethodL(this, &CPIMContactListAdapter::IsDatabaseReadyL, iFuncServer);
       
   240 
       
   241     // the first time,
       
   242     // we check for all cards
       
   243     if (iFirstItemChanges)
       
   244     {
       
   245         //FilterAllContactsL();
       
   246         CallMethodL(this, &CPIMContactListAdapter::FilterAllContactsL,
       
   247                     iFuncServer);
       
   248         iFirstItemChanges = EFalse;
       
   249     }
       
   250 
       
   251     RPointerArray<CPIMItemStateChange>* retval = iItemChanges;
       
   252     iItemChanges = NULL;
       
   253     return retval;
       
   254 }
       
   255 
       
   256 // -----------------------------------------------------------------------------
       
   257 // CPIMContactListAdapter::Close
       
   258 // Used to inform the list adapter that the list has been closed.
       
   259 // The list adapter may then release all resources it has reserved.
       
   260 // -----------------------------------------------------------------------------
       
   261 //
       
   262 void CPIMContactListAdapter::Close()
       
   263 {
       
   264     JELOG2(EPim);
       
   265     CallMethod(this, &CPIMContactListAdapter::DoClose, iFuncServer);
       
   266 }
       
   267 
       
   268 void CPIMContactListAdapter::DoClose()
       
   269 {
       
   270     JELOG2(EPim);
       
   271     if (iCategoryChanges)
       
   272     {
       
   273         iCategoryChanges->ResetAndDestroy();
       
   274         delete iCategoryChanges;
       
   275         iCategoryChanges = NULL;
       
   276     }
       
   277     if (iItemChanges)
       
   278     {
       
   279         iItemChanges->ResetAndDestroy();
       
   280         delete iItemChanges;
       
   281         iItemChanges = NULL;
       
   282     }
       
   283     delete iNotifier;
       
   284     iNotifier = NULL;
       
   285     delete iItemAdapter;
       
   286     iItemAdapter = NULL;
       
   287     delete iCategoryManager;
       
   288     iCategoryManager = NULL;
       
   289     delete iDatabase;
       
   290     iDatabase = NULL;
       
   291     delete iMinimalFieldsViewDef;
       
   292     iMinimalFieldsViewDef = NULL;
       
   293 }
       
   294 
       
   295 // -----------------------------------------------------------------------------
       
   296 // CPIMContactListAdapter::GetPimListAdapter
       
   297 // Provides access to the MPIMListAdapter representation of this
       
   298 // MPIMContactListAdapter object.
       
   299 // -----------------------------------------------------------------------------
       
   300 //
       
   301 MPIMListAdapter* CPIMContactListAdapter::GetPimListAdapter()
       
   302 {
       
   303     JELOG2(EPim);
       
   304     return this;
       
   305 }
       
   306 
       
   307 // -----------------------------------------------------------------------------
       
   308 // CPIMContactListAdapter::CreateContactItemL
       
   309 // Creates a new contact item (entry) in the native database.
       
   310 // The adapter creates a new native database entry, sets its data
       
   311 // according to the data in aContactItem, adds it to the database
       
   312 // and sets the Item ID of aContactItem. aContactItem must
       
   313 // contain valid data and have Item ID KPIMNullItemID.
       
   314 // -----------------------------------------------------------------------------
       
   315 //
       
   316 void CPIMContactListAdapter::CreateContactItemL(MPIMContactItem& aContactItem) // The contact item to add
       
   317 {
       
   318     JELOG2(EPim);
       
   319     CallMethodL(this, &CPIMContactListAdapter::DoCreateContactItemL,
       
   320                 aContactItem, iFuncServer);
       
   321     ReadContactItemL(aContactItem);
       
   322 }
       
   323 
       
   324 void CPIMContactListAdapter::DoCreateContactItemL(MPIMContactItem& aContactItem) // The contact item to add
       
   325 {
       
   326     JELOG2(EPim);
       
   327     __ASSERT_ALWAYS(iItemAdapter || iDatabase, User::Leave(KErrNotReady));
       
   328     CContactCard* card = iItemAdapter->CardL(aContactItem);
       
   329     CleanupStack::PushL(card);
       
   330     // Leaves with KErrDiskFull if there is not enough disk
       
   331     // space to create a new contact item
       
   332     TContactItemId id = iDatabase->AddNewContactL(*card);
       
   333     // Set new item id. If this leaves it means that
       
   334     // SetContactItemIdL leaved with KErrOutNoMemory
       
   335     TRAPD(err, aContactItem.SetContactItemIdL(id));
       
   336     if (KErrNone != err)
       
   337     {
       
   338         TBuf8<KPIMItemIdDesSize> entryId;
       
   339         entryId.Num(static_cast<TUint>(id));
       
   340         DoRemoveContactItemL(entryId);
       
   341         User::Leave(err);
       
   342     }
       
   343     iItemAdapter->UpdateCategoriesL(aContactItem, *card);
       
   344     CleanupStack::PopAndDestroy(card);
       
   345     // update possible changes (e.g. dropped attributes) to the item
       
   346     aContactItem.PrepareForLoadL();
       
   347 }
       
   348 
       
   349 // -----------------------------------------------------------------------------
       
   350 // CPIMContactListAdapter::ReadContactItemL
       
   351 // Reads an existing contact item from the native database.
       
   352 // The adapter maps the Item ID in aContactItem to a native database
       
   353 // entry identifier, reads the entry and sets the data of
       
   354 // aContactItem according to the data in the native entry. This operation
       
   355 // is very performance sensitive, so it must be used with cause and only
       
   356 // when the full contact item is needed
       
   357 // -----------------------------------------------------------------------------
       
   358 //
       
   359 void CPIMContactListAdapter::ReadContactItemL(MPIMContactItem& aContactItem) // The contact item to be read
       
   360 {
       
   361     JELOG2(EPim);
       
   362     CallMethodL(this, &CPIMContactListAdapter::DoCallReadContactItemL,
       
   363                 aContactItem, iFuncServer);
       
   364 }
       
   365 
       
   366 void CPIMContactListAdapter::DoCallReadContactItemL(
       
   367     MPIMContactItem& aContactItem) // The contact item to be read
       
   368 {
       
   369     JELOG2(EPim);
       
   370     __ASSERT_ALWAYS(iItemAdapter || iDatabase, User::Leave(KErrNotReady));
       
   371     const TContactItemId id = aContactItem.ContactItemIdL();
       
   372     __ASSERT_ALWAYS(id != 0, User::Leave(KErrArgument));
       
   373     // If the contact item contains data we don't want to overwrite it
       
   374     // so we create a mask item view definition if needed. Otherwise
       
   375     // we just read full contact item from the database
       
   376     CContactItemViewDef* itemViewDef = CContactItemViewDef::NewLC(
       
   377                                            CContactItemViewDef::EMaskFields,
       
   378                                            CContactItemViewDef::EIncludeHiddenFields);
       
   379     CArrayFix<TPIMField>* fields = aContactItem.ItemData().FieldsLC();
       
   380     TInt count = fields->Count();
       
   381 
       
   382     // Mask fields and do not include. Note that if there is no fields in the
       
   383     // item the view should provide all possible fields from the database
       
   384     for (TInt i = 0; i < count; i++)
       
   385     {
       
   386         TPIMContactField field = static_cast<TPIMContactField>(fields->At(i));
       
   387         // Get Contacts Model fields mapped to PIM fields
       
   388         CArrayFix<TInt>* fieldArray = iItemAdapter->ContactsModelFieldTypeL(
       
   389                                           field);
       
   390         CleanupStack::PushL(fieldArray);
       
   391         // Add retrieved fields to the item view definition
       
   392         TInt fieldCount = fieldArray->Count();
       
   393         for (TInt j = 0; j < fieldCount; j++)
       
   394         {
       
   395             const TUid fieldUid =
       
   396                 { fieldArray->At(j) };
       
   397             // Do not add the field to the view if it already contains
       
   398             // this type of a field (e.g the field is a name array element)
       
   399             if (itemViewDef->Find(fieldUid) == KErrNotFound)
       
   400             {
       
   401                 itemViewDef->AddL(fieldUid);
       
   402             }
       
   403         }
       
   404         CleanupStack::PopAndDestroy(fieldArray);
       
   405     }
       
   406     DoReadContactItemL(aContactItem, *itemViewDef);
       
   407     CleanupStack::PopAndDestroy(2, itemViewDef);
       
   408 }
       
   409 
       
   410 // -----------------------------------------------------------------------------
       
   411 // CPIMContactListAdapter::ReadMinimalContactItemL
       
   412 // This version reads a minimal contact item from the native database by using
       
   413 // contact database view definition. The view definition is initialized in
       
   414 // the constructor of this class and needs to be up to date with currently
       
   415 // required contact fields when the item is read for the first time. This
       
   416 // function was introduced due to improve poor performance of the PIM API
       
   417 // ContactList
       
   418 // -----------------------------------------------------------------------------
       
   419 
       
   420 void CPIMContactListAdapter::ReadMinimalContactItemL(
       
   421     MPIMContactItem& aContactItem)
       
   422 {
       
   423     JELOG2(EPim);
       
   424     CallMethodL(this, &CPIMContactListAdapter::DoCallReadMinimalContactItemL,
       
   425                 aContactItem, iFuncServer);
       
   426 }
       
   427 
       
   428 void CPIMContactListAdapter::DoCallReadMinimalContactItemL(
       
   429     MPIMContactItem& aContactItem)
       
   430 {
       
   431     JELOG2(EPim);
       
   432     __ASSERT_ALWAYS(iItemAdapter || iDatabase, User::Leave(KErrNotReady));
       
   433     TContactItemId id = aContactItem.ContactItemIdL();
       
   434     __ASSERT_ALWAYS(id != 0, User::Leave(KErrArgument));
       
   435 
       
   436     // Reset item for reading
       
   437     aContactItem.PrepareForLoadL();
       
   438 
       
   439     // Use contact database filtering. Currently only all name elements
       
   440     // are retrieved from the database to improve performance of the list
       
   441     DoReadContactItemL(aContactItem, *iMinimalFieldsViewDef);
       
   442 
       
   443 }
       
   444 
       
   445 // -----------------------------------------------------------------------------
       
   446 // CPIMContactListAdapter::ReadMinimalContactItemL
       
   447 // This version reads a minimal contact item from the native database by using
       
   448 // contact database view definition. The view definition is initialized in
       
   449 // the constructor of this class and it can be modified to fetch specified fields
       
   450 // by the matching item given as an argument to this function
       
   451 // -----------------------------------------------------------------------------
       
   452 
       
   453 void CPIMContactListAdapter::ReadMinimalContactItemL(
       
   454     MPIMContactItem& aContactItem, const MPIMContactItem& aMatchingContactItem)
       
   455 {
       
   456     JELOG2(EPim);
       
   457     // Get fields from the matching item and add those to the view definition
       
   458     CArrayFix<TPIMField>* fields = aMatchingContactItem.ItemData().FieldsLC();
       
   459     TInt count = fields->Count();
       
   460     for (TInt i = 0; i < count; i++)
       
   461     {
       
   462         TPIMContactField field = static_cast<TPIMContactField>(fields->At(i));
       
   463         // Get Contacts Model fields mapped to PIM fields
       
   464         CArrayFix<TInt>* fieldArray = iItemAdapter->ContactsModelFieldTypeL(
       
   465                                           field);
       
   466         CleanupStack::PushL(fieldArray);
       
   467         // Add retrieved fields to the item view definition
       
   468         TInt fieldCount = fieldArray->Count();
       
   469         for (TInt j = 0; j < fieldCount; j++)
       
   470         {
       
   471             const TUid fieldUid =
       
   472                 { fieldArray->At(j) };
       
   473             // Do not add the field to the view if it already contains
       
   474             // this type of a field (e.g the field is a name array element)
       
   475             if (iMinimalFieldsViewDef->Find(fieldUid) == KErrNotFound)
       
   476             {
       
   477                 iMinimalFieldsViewDef->AddL(fieldUid);
       
   478             }
       
   479         }
       
   480         CleanupStack::PopAndDestroy(fieldArray);
       
   481     }
       
   482     CleanupStack::PopAndDestroy(fields);
       
   483     // Read contact item using minimal field definition
       
   484     ReadMinimalContactItemL(aContactItem);
       
   485     // Reset the view definition to its previous state
       
   486     InitializeMinimalViewDefinitionL();
       
   487 }
       
   488 
       
   489 // -----------------------------------------------------------------------------
       
   490 // CPIMContactListAdapter::ReadContactFieldL
       
   491 // Reads one field from the contact database
       
   492 // -----------------------------------------------------------------------------
       
   493 //
       
   494 void CPIMContactListAdapter::ReadContactFieldL(MPIMContactItem& aContactItem,
       
   495         TPIMContactField aContactField)
       
   496 {
       
   497     JELOG2(EPim);
       
   498     CallMethodL(this, &CPIMContactListAdapter::DoReadContactFieldL,
       
   499                 aContactItem, aContactField, iFuncServer);
       
   500 }
       
   501 
       
   502 void CPIMContactListAdapter::DoReadContactFieldL(MPIMContactItem& aContactItem,
       
   503         TPIMContactField aContactField)
       
   504 {
       
   505     JELOG2(EPim);
       
   506     __ASSERT_ALWAYS(iItemAdapter || iDatabase, User::Leave(KErrNotReady));
       
   507     TContactItemId id = aContactItem.ContactItemIdL();
       
   508     __ASSERT_ALWAYS(id != 0, User::Leave(KErrArgument));
       
   509 
       
   510     // Create new view definition
       
   511     CContactItemViewDef* itemViewDef = CContactItemViewDef::NewLC(
       
   512                                            CContactItemViewDef::EIncludeFields,
       
   513                                            CContactItemViewDef::EIncludeHiddenFields);
       
   514     CArrayFix<TInt>* fieldArray = iItemAdapter->ContactsModelFieldTypeL(
       
   515                                       aContactField);
       
   516     CleanupStack::PushL(fieldArray);
       
   517     // Add retrieved fields to the item view definition
       
   518     TInt fieldCount = fieldArray->Count();
       
   519     for (TInt i = 0; i < fieldCount; i++)
       
   520     {
       
   521         const TUid fieldUid =
       
   522             { fieldArray->At(i) };
       
   523         itemViewDef->AddL(fieldUid);
       
   524     }
       
   525     // The view cannot be empty so check the field count in debug builds
       
   526     __ASSERT_DEBUG(itemViewDef->Count() > 0, User::Panic(KPIMPanicCategory,
       
   527                    EPIMPanicInvalidState));
       
   528     CleanupStack::PopAndDestroy(fieldArray);
       
   529     DoReadContactItemL(aContactItem, *itemViewDef);
       
   530     CleanupStack::PopAndDestroy(itemViewDef);
       
   531 }
       
   532 
       
   533 // -----------------------------------------------------------------------------
       
   534 // CPIMContactListAdapter::WriteContactItemL
       
   535 // Writes an existing contact item to the native database.
       
   536 // The adapter maps the Item ID in aContactItem to a native database
       
   537 // entry identifier, reads the entry and sets the data of the entry
       
   538 // according to the data in aContactItem.
       
   539 // -----------------------------------------------------------------------------
       
   540 //
       
   541 void CPIMContactListAdapter::WriteContactItemL(MPIMContactItem& aContactItem) // The contact item to write
       
   542 {
       
   543     JELOG2(EPim);
       
   544     CallMethodL(this, &CPIMContactListAdapter::DoWriteContactItemL,
       
   545                 aContactItem, iFuncServer);
       
   546     ReadContactItemL(aContactItem);
       
   547 }
       
   548 
       
   549 void CPIMContactListAdapter::DoWriteContactItemL(MPIMContactItem& aContactItem) // The contact item to write
       
   550 {
       
   551     JELOG2(EPim);
       
   552     __ASSERT_ALWAYS(iItemAdapter || iDatabase, User::Leave(KErrNotReady));
       
   553     TContactItemId id = aContactItem.ContactItemIdL();
       
   554     __ASSERT_ALWAYS(id != 0, User::Leave(KErrArgument));
       
   555 
       
   556     // OpenContactLX leaves the lock item in the cleanup stack
       
   557     CContactCard* contactItem =
       
   558         static_cast<CContactCard*>(iDatabase->OpenContactLX(id));
       
   559     CleanupStack::PushL(contactItem);
       
   560     iItemAdapter->UpdateCardL(aContactItem, *contactItem);
       
   561     iDatabase->CommitContactL(*contactItem);
       
   562     // Note: Even though the above line closed the contact, we can still
       
   563     // keep the lock item in the cleanup stack as closing a contact
       
   564     // twice is harmless
       
   565     iItemAdapter->UpdateCategoriesL(aContactItem, *contactItem);
       
   566     CleanupStack::PopAndDestroy(contactItem);
       
   567     CleanupStack::Pop(); // contactItem lock item
       
   568     // update possible changes (e.g. dropped attributes) to the item
       
   569     aContactItem.PrepareForLoadL();
       
   570 }
       
   571 
       
   572 // -----------------------------------------------------------------------------
       
   573 // CPIMContactListAdapter::ReadContactItemL
       
   574 // Removes an existing contact from the native database.
       
   575 // The adapter maps aItemID to a native database entry and removes it.
       
   576 // -----------------------------------------------------------------------------
       
   577 //
       
   578 void CPIMContactListAdapter::RemoveContactItemL(TPIMItemID aItemID)
       
   579 {
       
   580     JELOG2(EPim);
       
   581     CallMethodL(this, &CPIMContactListAdapter::DoRemoveContactItemL, aItemID,
       
   582                 iFuncServer);
       
   583 }
       
   584 
       
   585 void CPIMContactListAdapter::DoRemoveContactItemL(TPIMItemID aItemID)
       
   586 {
       
   587     JELOG2(EPim);
       
   588     __ASSERT_ALWAYS(iDatabase, User::Leave(KErrNotReady));
       
   589     // Convert string id to integer id
       
   590     TUint id;
       
   591     TLex8 lex(aItemID);
       
   592     TInt status = lex.Val(id);
       
   593     User::LeaveIfError(status);
       
   594     // Delete contact from the contact database
       
   595     iDatabase->DeleteContactL(id);
       
   596 }
       
   597 
       
   598 // -----------------------------------------------------------------------------
       
   599 // CPIMContactListAdapter::CPIMContactListAdapter
       
   600 // C++ default constructor can NOT contain any code, that
       
   601 // might leave.
       
   602 // -----------------------------------------------------------------------------
       
   603 //
       
   604 CPIMContactListAdapter::CPIMContactListAdapter(
       
   605     java::util::FunctionServer* aFuncServer)
       
   606 {
       
   607     JELOG2(EPim);
       
   608     iFirstItemChanges = ETrue;
       
   609     iFuncServer = aFuncServer;
       
   610 }
       
   611 
       
   612 // -----------------------------------------------------------------------------
       
   613 // CPIMContactListAdapter::ConstructL
       
   614 // Symbian 2nd phase constructor can leave.
       
   615 // -----------------------------------------------------------------------------
       
   616 //
       
   617 void CPIMContactListAdapter::ConstructL()
       
   618 {
       
   619     JELOG2(EPim);
       
   620     // Create default contact database if it does not exist. This may happen
       
   621     // if the current Phonebook engine is not running or started during
       
   622     // device boot. Usually, the database should be available but this is precaution
       
   623     if (!CContactDatabase::DefaultContactDatabaseExistsL())
       
   624     {
       
   625         iDatabase
       
   626         = CContactDatabase::CreateL(/*CContactDatabase::EMultiThread*/);
       
   627     }
       
   628     else
       
   629     {
       
   630         iDatabase = CContactDatabase::OpenL(/*CContactDatabase::EMultiThread*/);
       
   631     }
       
   632 
       
   633     // Create other contact adapter resources and initialize item view
       
   634     iCategoryManager
       
   635     = CPIMContactCategoryManager::NewL(*iDatabase, iFuncServer);
       
   636     iNotifier = CContactChangeNotifier::NewL(*iDatabase, this);
       
   637     iItemAdapter = CPIMContactItemAdapter::NewL(*iCategoryManager);
       
   638     // Initialize minimal fields view definition
       
   639     iMinimalFieldsViewDef = CContactItemViewDef::NewL(
       
   640                                 CContactItemViewDef::EIncludeFields,
       
   641                                 CContactItemViewDef::EIncludeHiddenFields);
       
   642     InitializeMinimalViewDefinitionL();
       
   643 }
       
   644 
       
   645 // -----------------------------------------------------------------------------
       
   646 // CPIMContactListAdapter::ExternalGroupChangeL
       
   647 // Adds an entry to external category change list.
       
   648 // Also causes the category cache to be flushed.
       
   649 // -----------------------------------------------------------------------------
       
   650 //
       
   651 void CPIMContactListAdapter::ExternalGroupChangeL(TContactItemId aId, // Id of the changed category
       
   652         TPIMExternalChangeType aType) // type of the change
       
   653 {
       
   654     JELOG2(EPim);
       
   655     iCategoryManager->FlushCache();
       
   656 
       
   657     // This should never happen
       
   658     __ASSERT_ALWAYS(iCategoryManager, User::Leave(KErrNotReady));
       
   659 
       
   660     if (!iCategoryChanges)
       
   661     {
       
   662         iCategoryChanges
       
   663         = new(ELeave) RPointerArray<CPIMCategoryStateChange> (1);
       
   664     }
       
   665     CPIMCategoryStateChange* change = NULL;
       
   666     switch (aType)
       
   667     {
       
   668     case EPIMExternalChangeModified:
       
   669     {
       
   670         HBufC* newCategoryName = iCategoryManager->GroupLabelL(aId);
       
   671         CleanupStack::PushL(newCategoryName);
       
   672         HBufC* oldCategoryName = iCategoryManager->LabelFromCacheL(aId);
       
   673         CleanupStack::PushL(oldCategoryName);
       
   674         change
       
   675         = new(ELeave) CPIMCategoryStateChange(oldCategoryName, aType, newCategoryName);
       
   676         CleanupStack::Pop(2); // newCategoryName and oldCategoryName are
       
   677         // now owned by change
       
   678         break;
       
   679     }
       
   680     case EPIMExternalChangeNew:
       
   681     {
       
   682         HBufC* newCategoryName = iCategoryManager->GroupLabelL(aId);
       
   683         CleanupStack::PushL(newCategoryName);
       
   684         change = new(ELeave) CPIMCategoryStateChange(newCategoryName, aType);
       
   685         CleanupStack::Pop(); // newCategoryName is now owned by change
       
   686         break;
       
   687     }
       
   688     case EPIMExternalChangeRemoved:
       
   689     {
       
   690         HBufC* oldCategoryName = iCategoryManager->LabelFromCacheL(aId);
       
   691         CleanupStack::PushL(oldCategoryName);
       
   692         change = new(ELeave) CPIMCategoryStateChange(oldCategoryName, aType);
       
   693         CleanupStack::Pop(); // newCategoryName is now owned by change
       
   694         break;
       
   695     }
       
   696     default:
       
   697     {
       
   698         User::Leave(KErrArgument);
       
   699     }
       
   700     }
       
   701 
       
   702     CleanupStack::PushL(change);
       
   703     User::LeaveIfError(iCategoryChanges->Append(change));
       
   704     CleanupStack::Pop(change);
       
   705 }
       
   706 
       
   707 // -----------------------------------------------------------------------------
       
   708 // CPIMContactListAdapter::ExternalItemChangeL
       
   709 // Adds an entry to external item change list.
       
   710 // -----------------------------------------------------------------------------
       
   711 //
       
   712 void CPIMContactListAdapter::ExternalItemChangeL(TContactItemId aId, // Id of the changed category
       
   713         TPIMExternalChangeType aType) // type of the change
       
   714 {
       
   715     JELOG2(EPim);
       
   716     if (!iItemChanges)
       
   717     {
       
   718         iItemChanges = new(ELeave) RPointerArray<CPIMItemStateChange> (10);
       
   719     }
       
   720     HBufC8* changeId = HBufC8::NewLC(KPIMItemIdDesSize);
       
   721     TPtr8 entryId = changeId->Des();
       
   722     entryId.Num(static_cast<TUint>(aId));
       
   723     CPIMItemStateChange* change =
       
   724         new(ELeave) CPIMItemStateChange(changeId, aType);
       
   725     // The ownership of changeId is transferred to the item state change object
       
   726     CleanupStack::Pop(changeId);
       
   727 
       
   728     CleanupStack::PushL(change);
       
   729     iItemChanges->AppendL(change);
       
   730     CleanupStack::Pop(change);
       
   731 }
       
   732 
       
   733 // -----------------------------------------------------------------------------
       
   734 // CPIMContactListAdapter::FilterAllContacts
       
   735 // Filters all contact items from the database to the changes list
       
   736 // -----------------------------------------------------------------------------
       
   737 //
       
   738 void CPIMContactListAdapter::FilterAllContactsL()
       
   739 {
       
   740     JELOG2(EPim);
       
   741     CCntFilter* filter = CCntFilter::NewLC();
       
   742     filter->SetIncludeNewContacts(EFalse);
       
   743     if (!iItemChanges)
       
   744     {
       
   745         iItemChanges = new(ELeave) RPointerArray<CPIMItemStateChange> (10);
       
   746     }
       
   747     filter->SetContactFilterTypeALL(EFalse);
       
   748     filter->SetContactFilterTypeCard(ETrue);
       
   749     iDatabase->FilterDatabaseL(*filter);
       
   750     CContactIdArray* idArray = filter->iIds;
       
   751     TInt idCount = idArray->Count();
       
   752     TInt i = 0;
       
   753     for (i = 0; i < idCount; i++)
       
   754     {
       
   755         TContactItemId id = (*idArray)[i];
       
   756         TBool wasInList = EFalse;
       
   757         TInt changeCount = iItemChanges->Count();
       
   758         for (TInt j = 0; j < changeCount; j++)
       
   759         {
       
   760             TBuf8<KPIMItemIdDesSize> entryId;
       
   761             entryId.Num(static_cast<TUint>(id));
       
   762             if ((*iItemChanges)[j]->ItemID().Compare(entryId) == 0)
       
   763             {
       
   764                 wasInList = ETrue;
       
   765             }
       
   766         }
       
   767         if (!wasInList)
       
   768         {
       
   769             ExternalItemChangeL(id, EPIMExternalChangeNew);
       
   770         }
       
   771     }
       
   772     CleanupStack::PopAndDestroy(); // filter
       
   773 }
       
   774 
       
   775 // -----------------------------------------------------------------------------
       
   776 // CPIMContactListAdapter::InitializeMinimalViewDefinitionL
       
   777 // Initializes minimal view definition
       
   778 // -----------------------------------------------------------------------------
       
   779 //
       
   780 void CPIMContactListAdapter::InitializeMinimalViewDefinitionL()
       
   781 {
       
   782     JELOG2(EPim);
       
   783     __ASSERT_DEBUG(iMinimalFieldsViewDef, User::Panic(KPIMPanicCategory,
       
   784                    EPIMPanicInvalidState));
       
   785     // Reset view definition
       
   786     iMinimalFieldsViewDef->Reset();
       
   787     // Add fields which are to retrieved from the native database
       
   788     // when minimal item is to be created or read
       
   789     iMinimalFieldsViewDef->AddL(KUidContactFieldAdditionalName);
       
   790     iMinimalFieldsViewDef->AddL(KUidContactFieldGivenName);
       
   791     iMinimalFieldsViewDef->AddL(KUidContactFieldFamilyName);
       
   792     iMinimalFieldsViewDef->AddL(KUidContactFieldGivenNamePronunciation);
       
   793     iMinimalFieldsViewDef->AddL(KUidContactFieldFamilyNamePronunciation);
       
   794     iMinimalFieldsViewDef->AddL(KUidContactFieldPrefixName);
       
   795     iMinimalFieldsViewDef->AddL(KUidContactFieldSuffixName);
       
   796 }
       
   797 
       
   798 // -----------------------------------------------------------------------------
       
   799 // CPIMContactListAdapter::DoReadContactItemL
       
   800 // Reads contact from the contacts database using item view definition
       
   801 // -----------------------------------------------------------------------------
       
   802 //
       
   803 void CPIMContactListAdapter::DoReadContactItemL(MPIMContactItem& aContactItem,
       
   804         const CContactItemViewDef& aContactItemViewDef)
       
   805 {
       
   806     JELOG2(EPim);
       
   807     const TContactItemId id = aContactItem.ContactItemIdL();
       
   808     __ASSERT_DEBUG(id != 0, User::Panic(KPIMPanicCategory,
       
   809                                         EPIMPanicInvalidItemID));
       
   810     // Read contact item using the item view definition
       
   811     CContactCard* contactItem =
       
   812         static_cast<CContactCard*>(iDatabase->ReadContactLC(id,
       
   813                                    aContactItemViewDef));
       
   814     // Set date and fill the PIM item
       
   815     TTime lastModified = contactItem->LastModified();
       
   816     aContactItem.SetLastModifiedL(lastModified);
       
   817     iItemAdapter->FillItemL(aContactItem, *contactItem);
       
   818     CleanupStack::PopAndDestroy(contactItem);
       
   819 }
       
   820 
       
   821 void CPIMContactListAdapter::IsDatabaseReadyL()
       
   822 {
       
   823     JELOG2(EPim);
       
   824     __ASSERT_ALWAYS(iDatabase, User::Leave(KErrNotReady));
       
   825 }
       
   826 
       
   827 // End of file