javaextensions/pim/cntadapter/src.s60/cpimcontactlistadapter.cpp
branchRCL_3
changeset 19 04becd199f91
child 67 63b81d807542
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javaextensions/pim/cntadapter/src.s60/cpimcontactlistadapter.cpp	Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,827 @@
+/*
+* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  Handles PIM contact list <-> Contacts Model conversions
+ *
+*/
+
+
+// CLASS HEADER
+#include "cpimcontactlistadapter.h"
+
+// INTERNAL INCLUDES
+#include "cpimcontactcategorymanager.h"
+#include "cpimcontactitemadapter.h"
+#include "mpimcontactitem.h"
+#include "mpimitemdata.h"
+#include "logger.h"
+
+// EXTERNAL INCLUDES
+#include <badesca.h>
+#include <cntdb.h>
+#include <cntitem.h> // CContactGroup
+#include <cntfilt.h> // CCntFilter
+
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CPIMContactListAdapter::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CPIMContactListAdapter* CPIMContactListAdapter::NewL(
+    java::util::FunctionServer* aFuncServer)
+{
+    JELOG2(EPim);
+    CPIMContactListAdapter* self =
+        new(ELeave) CPIMContactListAdapter(aFuncServer);
+
+    CallMethodL(self, &CPIMContactListAdapter::ConstructL, self->iFuncServer);
+
+    return self;
+}
+
+// Destructor
+CPIMContactListAdapter::~CPIMContactListAdapter()
+{
+    JELOG2(EPim);
+    Close();
+}
+// -----------------------------------------------------------------------------
+// CPIMContactListAdapter::HandleDatabaseEventL
+// Tests the contact database observer event type and handles it. The ID of
+// a contact affected by the change event, if relevant, can be retrieved
+// via TContactDbObserverEvent::iContactId.
+// -----------------------------------------------------------------------------
+//
+void CPIMContactListAdapter::HandleDatabaseEventL(
+    TContactDbObserverEvent aEvent) // information about the change event
+{
+    JELOG2(EPim);
+    switch (aEvent.iType)
+    {
+    case EContactDbObserverEventGroupAdded:
+    {
+        ExternalGroupChangeL(aEvent.iContactId, EPIMExternalChangeNew);
+        break;
+    }
+    case EContactDbObserverEventGroupChanged:
+    {
+        ExternalGroupChangeL(aEvent.iContactId, EPIMExternalChangeModified);
+        break;
+    }
+    case EContactDbObserverEventGroupDeleted:
+    {
+        ExternalGroupChangeL(aEvent.iContactId, EPIMExternalChangeRemoved);
+        break;
+    }
+    case EContactDbObserverEventContactAdded:
+    {
+        ExternalItemChangeL(aEvent.iContactId, EPIMExternalChangeNew);
+        break;
+    }
+    case EContactDbObserverEventContactChanged:
+    {
+        ExternalItemChangeL(aEvent.iContactId, EPIMExternalChangeModified);
+        break;
+    }
+    case EContactDbObserverEventContactDeleted:
+    {
+        ExternalItemChangeL(aEvent.iContactId, EPIMExternalChangeRemoved);
+        break;
+    }
+    default:
+    {
+        // we don't care about other changes
+        return;
+    }
+    }
+}
+
+
+// -----------------------------------------------------------------------------
+// CPIMContactListAdapter::GetCategoriesL
+// Provides all categories currently existing in the native database.
+// Returns: Array of categories
+// -----------------------------------------------------------------------------
+//
+const CDesCArray& CPIMContactListAdapter::GetCategoriesL()
+{
+    JELOG2(EPim);
+    __ASSERT_ALWAYS(iCategoryManager, User::Leave(KErrNotReady));
+    return iCategoryManager->CallGetCategoriesL();
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactListAdapter::AddCategoryL
+// Adds a new category to the native database.
+// If the category already  exists, nothing is done and the method returns
+// successfully.
+// -----------------------------------------------------------------------------
+//
+void CPIMContactListAdapter::AddCategoryL(const TDesC& aNewCategory)
+{
+    JELOG2(EPim);
+    __ASSERT_ALWAYS(iCategoryManager, User::Leave(KErrNotReady));
+    CallMethodL(iCategoryManager, &CPIMContactCategoryManager::AddCategoryL,
+                aNewCategory, iFuncServer);
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactListAdapter::DeleteCategoryL
+// Deletes an existing category.
+// If there is no such category, nothing is done and the method returns
+// successfully.
+// -----------------------------------------------------------------------------
+//
+void CPIMContactListAdapter::DeleteCategoryL(const TDesC& aCategory)
+{
+    JELOG2(EPim);
+    __ASSERT_ALWAYS(iCategoryManager, User::Leave(KErrNotReady));
+    CallMethodL(iCategoryManager, &CPIMContactCategoryManager::DeleteCategoryL,
+                aCategory, iFuncServer);
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactListAdapter::RenameCategoryL
+// Renames an existing category.
+// Entries in the old category are moved to the new category.
+// -----------------------------------------------------------------------------
+//
+void CPIMContactListAdapter::RenameCategoryL(const TDesC& aOldCategory, // The old category name
+        const TDesC& aNewCategory) // The new category name
+{
+    JELOG2(EPim);
+    __ASSERT_ALWAYS(iCategoryManager, User::Leave(KErrNotReady));
+    CallMethodL(iCategoryManager, &CPIMContactCategoryManager::RenameCategoryL,
+                aOldCategory, aNewCategory, iFuncServer);
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactListAdapter::IsCategoriesExternallyModified
+// Checks whether there have been external changes to the categories in
+// the native database after last call to
+// GetExternalCategoryModifications or list adapter creation.
+// Returns: ETrue: If there are any external changes
+//          EFalse: Otherwise
+// -----------------------------------------------------------------------------
+//
+TBool CPIMContactListAdapter::IsCategoriesExternallyModified()
+{
+    JELOG2(EPim);
+    if (iCategoryChanges)
+    {
+        return ETrue;
+    }
+    return EFalse;
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactListAdapter::GetExternalCategoryModificationsL
+// Provides the external changes to the categories in the native database.
+// Returns: An array of category state change objects. The ownership
+//          of the array is transferred to the caller. Note that the
+//          array elements contain heap-allocated data.
+// -----------------------------------------------------------------------------
+//
+RPointerArray<CPIMCategoryStateChange>*
+CPIMContactListAdapter::GetExternalCategoryModificationsL()
+{
+    JELOG2(EPim);
+    CallMethodL(this, &CPIMContactListAdapter::IsDatabaseReadyL, iFuncServer);
+    RPointerArray<CPIMCategoryStateChange>* retval = iCategoryChanges;
+    iCategoryChanges = NULL;
+    return retval;
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactListAdapter::IsItemsExternallyModified
+// Checks whether there have been external changes to the items in
+// the native database after last call to
+// GetExternalItemModifications or list adapter creation.
+// Returns: EExternalChangesMinor: If there are any external changes
+//          EExternalChangesNone: Otherwise
+// -----------------------------------------------------------------------------
+//
+MPIMListAdapter::TExternalItemChangeClass CPIMContactListAdapter::IsItemsExternallyModified()
+{
+    JELOG2(EPim);
+    if ((iItemChanges || iFirstItemChanges))
+    {
+        return MPIMListAdapter::EExternalChangesMinor;
+    }
+    return MPIMListAdapter::EExternalChangesNone;
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactListAdapter::GetExternalItemModificationsL
+// Provides the external changes to the items in the native database.
+// Returns: An array of item state change objects. The ownership
+//          of the array is transferred to the caller. Note that the
+//          array elements contain heap-allocated data.
+// -----------------------------------------------------------------------------
+//
+RPointerArray<CPIMItemStateChange>*
+CPIMContactListAdapter::GetExternalItemModificationsL()
+{
+    JELOG2(EPim);
+    CallMethodL(this, &CPIMContactListAdapter::IsDatabaseReadyL, iFuncServer);
+
+    // the first time,
+    // we check for all cards
+    if (iFirstItemChanges)
+    {
+        //FilterAllContactsL();
+        CallMethodL(this, &CPIMContactListAdapter::FilterAllContactsL,
+                    iFuncServer);
+        iFirstItemChanges = EFalse;
+    }
+
+    RPointerArray<CPIMItemStateChange>* retval = iItemChanges;
+    iItemChanges = NULL;
+    return retval;
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactListAdapter::Close
+// Used to inform the list adapter that the list has been closed.
+// The list adapter may then release all resources it has reserved.
+// -----------------------------------------------------------------------------
+//
+void CPIMContactListAdapter::Close()
+{
+    JELOG2(EPim);
+    CallMethod(this, &CPIMContactListAdapter::DoClose, iFuncServer);
+}
+
+void CPIMContactListAdapter::DoClose()
+{
+    JELOG2(EPim);
+    if (iCategoryChanges)
+    {
+        iCategoryChanges->ResetAndDestroy();
+        delete iCategoryChanges;
+        iCategoryChanges = NULL;
+    }
+    if (iItemChanges)
+    {
+        iItemChanges->ResetAndDestroy();
+        delete iItemChanges;
+        iItemChanges = NULL;
+    }
+    delete iNotifier;
+    iNotifier = NULL;
+    delete iItemAdapter;
+    iItemAdapter = NULL;
+    delete iCategoryManager;
+    iCategoryManager = NULL;
+    delete iDatabase;
+    iDatabase = NULL;
+    delete iMinimalFieldsViewDef;
+    iMinimalFieldsViewDef = NULL;
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactListAdapter::GetPimListAdapter
+// Provides access to the MPIMListAdapter representation of this
+// MPIMContactListAdapter object.
+// -----------------------------------------------------------------------------
+//
+MPIMListAdapter* CPIMContactListAdapter::GetPimListAdapter()
+{
+    JELOG2(EPim);
+    return this;
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactListAdapter::CreateContactItemL
+// Creates a new contact item (entry) in the native database.
+// The adapter creates a new native database entry, sets its data
+// according to the data in aContactItem, adds it to the database
+// and sets the Item ID of aContactItem. aContactItem must
+// contain valid data and have Item ID KPIMNullItemID.
+// -----------------------------------------------------------------------------
+//
+void CPIMContactListAdapter::CreateContactItemL(MPIMContactItem& aContactItem) // The contact item to add
+{
+    JELOG2(EPim);
+    CallMethodL(this, &CPIMContactListAdapter::DoCreateContactItemL,
+                aContactItem, iFuncServer);
+    ReadContactItemL(aContactItem);
+}
+
+void CPIMContactListAdapter::DoCreateContactItemL(MPIMContactItem& aContactItem) // The contact item to add
+{
+    JELOG2(EPim);
+    __ASSERT_ALWAYS(iItemAdapter || iDatabase, User::Leave(KErrNotReady));
+    CContactCard* card = iItemAdapter->CardL(aContactItem);
+    CleanupStack::PushL(card);
+    // Leaves with KErrDiskFull if there is not enough disk
+    // space to create a new contact item
+    TContactItemId id = iDatabase->AddNewContactL(*card);
+    // Set new item id. If this leaves it means that
+    // SetContactItemIdL leaved with KErrOutNoMemory
+    TRAPD(err, aContactItem.SetContactItemIdL(id));
+    if (KErrNone != err)
+    {
+        TBuf8<KPIMItemIdDesSize> entryId;
+        entryId.Num(static_cast<TUint>(id));
+        DoRemoveContactItemL(entryId);
+        User::Leave(err);
+    }
+    iItemAdapter->UpdateCategoriesL(aContactItem, *card);
+    CleanupStack::PopAndDestroy(card);
+    // update possible changes (e.g. dropped attributes) to the item
+    aContactItem.PrepareForLoadL();
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactListAdapter::ReadContactItemL
+// Reads an existing contact item from the native database.
+// The adapter maps the Item ID in aContactItem to a native database
+// entry identifier, reads the entry and sets the data of
+// aContactItem according to the data in the native entry. This operation
+// is very performance sensitive, so it must be used with cause and only
+// when the full contact item is needed
+// -----------------------------------------------------------------------------
+//
+void CPIMContactListAdapter::ReadContactItemL(MPIMContactItem& aContactItem) // The contact item to be read
+{
+    JELOG2(EPim);
+    CallMethodL(this, &CPIMContactListAdapter::DoCallReadContactItemL,
+                aContactItem, iFuncServer);
+}
+
+void CPIMContactListAdapter::DoCallReadContactItemL(
+    MPIMContactItem& aContactItem) // The contact item to be read
+{
+    JELOG2(EPim);
+    __ASSERT_ALWAYS(iItemAdapter || iDatabase, User::Leave(KErrNotReady));
+    const TContactItemId id = aContactItem.ContactItemIdL();
+    __ASSERT_ALWAYS(id != 0, User::Leave(KErrArgument));
+    // If the contact item contains data we don't want to overwrite it
+    // so we create a mask item view definition if needed. Otherwise
+    // we just read full contact item from the database
+    CContactItemViewDef* itemViewDef = CContactItemViewDef::NewLC(
+                                           CContactItemViewDef::EMaskFields,
+                                           CContactItemViewDef::EIncludeHiddenFields);
+    CArrayFix<TPIMField>* fields = aContactItem.ItemData().FieldsLC();
+    TInt count = fields->Count();
+
+    // Mask fields and do not include. Note that if there is no fields in the
+    // item the view should provide all possible fields from the database
+    for (TInt i = 0; i < count; i++)
+    {
+        TPIMContactField field = static_cast<TPIMContactField>(fields->At(i));
+        // Get Contacts Model fields mapped to PIM fields
+        CArrayFix<TInt>* fieldArray = iItemAdapter->ContactsModelFieldTypeL(
+                                          field);
+        CleanupStack::PushL(fieldArray);
+        // Add retrieved fields to the item view definition
+        TInt fieldCount = fieldArray->Count();
+        for (TInt j = 0; j < fieldCount; j++)
+        {
+            const TUid fieldUid =
+                { fieldArray->At(j) };
+            // Do not add the field to the view if it already contains
+            // this type of a field (e.g the field is a name array element)
+            if (itemViewDef->Find(fieldUid) == KErrNotFound)
+            {
+                itemViewDef->AddL(fieldUid);
+            }
+        }
+        CleanupStack::PopAndDestroy(fieldArray);
+    }
+    DoReadContactItemL(aContactItem, *itemViewDef);
+    CleanupStack::PopAndDestroy(2, itemViewDef);
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactListAdapter::ReadMinimalContactItemL
+// This version reads a minimal contact item from the native database by using
+// contact database view definition. The view definition is initialized in
+// the constructor of this class and needs to be up to date with currently
+// required contact fields when the item is read for the first time. This
+// function was introduced due to improve poor performance of the PIM API
+// ContactList
+// -----------------------------------------------------------------------------
+
+void CPIMContactListAdapter::ReadMinimalContactItemL(
+    MPIMContactItem& aContactItem)
+{
+    JELOG2(EPim);
+    CallMethodL(this, &CPIMContactListAdapter::DoCallReadMinimalContactItemL,
+                aContactItem, iFuncServer);
+}
+
+void CPIMContactListAdapter::DoCallReadMinimalContactItemL(
+    MPIMContactItem& aContactItem)
+{
+    JELOG2(EPim);
+    __ASSERT_ALWAYS(iItemAdapter || iDatabase, User::Leave(KErrNotReady));
+    TContactItemId id = aContactItem.ContactItemIdL();
+    __ASSERT_ALWAYS(id != 0, User::Leave(KErrArgument));
+
+    // Reset item for reading
+    aContactItem.PrepareForLoadL();
+
+    // Use contact database filtering. Currently only all name elements
+    // are retrieved from the database to improve performance of the list
+    DoReadContactItemL(aContactItem, *iMinimalFieldsViewDef);
+
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactListAdapter::ReadMinimalContactItemL
+// This version reads a minimal contact item from the native database by using
+// contact database view definition. The view definition is initialized in
+// the constructor of this class and it can be modified to fetch specified fields
+// by the matching item given as an argument to this function
+// -----------------------------------------------------------------------------
+
+void CPIMContactListAdapter::ReadMinimalContactItemL(
+    MPIMContactItem& aContactItem, const MPIMContactItem& aMatchingContactItem)
+{
+    JELOG2(EPim);
+    // Get fields from the matching item and add those to the view definition
+    CArrayFix<TPIMField>* fields = aMatchingContactItem.ItemData().FieldsLC();
+    TInt count = fields->Count();
+    for (TInt i = 0; i < count; i++)
+    {
+        TPIMContactField field = static_cast<TPIMContactField>(fields->At(i));
+        // Get Contacts Model fields mapped to PIM fields
+        CArrayFix<TInt>* fieldArray = iItemAdapter->ContactsModelFieldTypeL(
+                                          field);
+        CleanupStack::PushL(fieldArray);
+        // Add retrieved fields to the item view definition
+        TInt fieldCount = fieldArray->Count();
+        for (TInt j = 0; j < fieldCount; j++)
+        {
+            const TUid fieldUid =
+                { fieldArray->At(j) };
+            // Do not add the field to the view if it already contains
+            // this type of a field (e.g the field is a name array element)
+            if (iMinimalFieldsViewDef->Find(fieldUid) == KErrNotFound)
+            {
+                iMinimalFieldsViewDef->AddL(fieldUid);
+            }
+        }
+        CleanupStack::PopAndDestroy(fieldArray);
+    }
+    CleanupStack::PopAndDestroy(fields);
+    // Read contact item using minimal field definition
+    ReadMinimalContactItemL(aContactItem);
+    // Reset the view definition to its previous state
+    InitializeMinimalViewDefinitionL();
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactListAdapter::ReadContactFieldL
+// Reads one field from the contact database
+// -----------------------------------------------------------------------------
+//
+void CPIMContactListAdapter::ReadContactFieldL(MPIMContactItem& aContactItem,
+        TPIMContactField aContactField)
+{
+    JELOG2(EPim);
+    CallMethodL(this, &CPIMContactListAdapter::DoReadContactFieldL,
+                aContactItem, aContactField, iFuncServer);
+}
+
+void CPIMContactListAdapter::DoReadContactFieldL(MPIMContactItem& aContactItem,
+        TPIMContactField aContactField)
+{
+    JELOG2(EPim);
+    __ASSERT_ALWAYS(iItemAdapter || iDatabase, User::Leave(KErrNotReady));
+    TContactItemId id = aContactItem.ContactItemIdL();
+    __ASSERT_ALWAYS(id != 0, User::Leave(KErrArgument));
+
+    // Create new view definition
+    CContactItemViewDef* itemViewDef = CContactItemViewDef::NewLC(
+                                           CContactItemViewDef::EIncludeFields,
+                                           CContactItemViewDef::EIncludeHiddenFields);
+    CArrayFix<TInt>* fieldArray = iItemAdapter->ContactsModelFieldTypeL(
+                                      aContactField);
+    CleanupStack::PushL(fieldArray);
+    // Add retrieved fields to the item view definition
+    TInt fieldCount = fieldArray->Count();
+    for (TInt i = 0; i < fieldCount; i++)
+    {
+        const TUid fieldUid =
+            { fieldArray->At(i) };
+        itemViewDef->AddL(fieldUid);
+    }
+    // The view cannot be empty so check the field count in debug builds
+    __ASSERT_DEBUG(itemViewDef->Count() > 0, User::Panic(KPIMPanicCategory,
+                   EPIMPanicInvalidState));
+    CleanupStack::PopAndDestroy(fieldArray);
+    DoReadContactItemL(aContactItem, *itemViewDef);
+    CleanupStack::PopAndDestroy(itemViewDef);
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactListAdapter::WriteContactItemL
+// Writes an existing contact item to the native database.
+// The adapter maps the Item ID in aContactItem to a native database
+// entry identifier, reads the entry and sets the data of the entry
+// according to the data in aContactItem.
+// -----------------------------------------------------------------------------
+//
+void CPIMContactListAdapter::WriteContactItemL(MPIMContactItem& aContactItem) // The contact item to write
+{
+    JELOG2(EPim);
+    CallMethodL(this, &CPIMContactListAdapter::DoWriteContactItemL,
+                aContactItem, iFuncServer);
+    ReadContactItemL(aContactItem);
+}
+
+void CPIMContactListAdapter::DoWriteContactItemL(MPIMContactItem& aContactItem) // The contact item to write
+{
+    JELOG2(EPim);
+    __ASSERT_ALWAYS(iItemAdapter || iDatabase, User::Leave(KErrNotReady));
+    TContactItemId id = aContactItem.ContactItemIdL();
+    __ASSERT_ALWAYS(id != 0, User::Leave(KErrArgument));
+
+    // OpenContactLX leaves the lock item in the cleanup stack
+    CContactCard* contactItem =
+        static_cast<CContactCard*>(iDatabase->OpenContactLX(id));
+    CleanupStack::PushL(contactItem);
+    iItemAdapter->UpdateCardL(aContactItem, *contactItem);
+    iDatabase->CommitContactL(*contactItem);
+    // Note: Even though the above line closed the contact, we can still
+    // keep the lock item in the cleanup stack as closing a contact
+    // twice is harmless
+    iItemAdapter->UpdateCategoriesL(aContactItem, *contactItem);
+    CleanupStack::PopAndDestroy(contactItem);
+    CleanupStack::Pop(); // contactItem lock item
+    // update possible changes (e.g. dropped attributes) to the item
+    aContactItem.PrepareForLoadL();
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactListAdapter::ReadContactItemL
+// Removes an existing contact from the native database.
+// The adapter maps aItemID to a native database entry and removes it.
+// -----------------------------------------------------------------------------
+//
+void CPIMContactListAdapter::RemoveContactItemL(TPIMItemID aItemID)
+{
+    JELOG2(EPim);
+    CallMethodL(this, &CPIMContactListAdapter::DoRemoveContactItemL, aItemID,
+                iFuncServer);
+}
+
+void CPIMContactListAdapter::DoRemoveContactItemL(TPIMItemID aItemID)
+{
+    JELOG2(EPim);
+    __ASSERT_ALWAYS(iDatabase, User::Leave(KErrNotReady));
+    // Convert string id to integer id
+    TUint id;
+    TLex8 lex(aItemID);
+    TInt status = lex.Val(id);
+    User::LeaveIfError(status);
+    // Delete contact from the contact database
+    iDatabase->DeleteContactL(id);
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactListAdapter::CPIMContactListAdapter
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CPIMContactListAdapter::CPIMContactListAdapter(
+    java::util::FunctionServer* aFuncServer)
+{
+    JELOG2(EPim);
+    iFirstItemChanges = ETrue;
+    iFuncServer = aFuncServer;
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactListAdapter::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CPIMContactListAdapter::ConstructL()
+{
+    JELOG2(EPim);
+    // Create default contact database if it does not exist. This may happen
+    // if the current Phonebook engine is not running or started during
+    // device boot. Usually, the database should be available but this is precaution
+    if (!CContactDatabase::DefaultContactDatabaseExistsL())
+    {
+        iDatabase
+        = CContactDatabase::CreateL(/*CContactDatabase::EMultiThread*/);
+    }
+    else
+    {
+        iDatabase = CContactDatabase::OpenL(/*CContactDatabase::EMultiThread*/);
+    }
+
+    // Create other contact adapter resources and initialize item view
+    iCategoryManager
+    = CPIMContactCategoryManager::NewL(*iDatabase, iFuncServer);
+    iNotifier = CContactChangeNotifier::NewL(*iDatabase, this);
+    iItemAdapter = CPIMContactItemAdapter::NewL(*iCategoryManager);
+    // Initialize minimal fields view definition
+    iMinimalFieldsViewDef = CContactItemViewDef::NewL(
+                                CContactItemViewDef::EIncludeFields,
+                                CContactItemViewDef::EIncludeHiddenFields);
+    InitializeMinimalViewDefinitionL();
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactListAdapter::ExternalGroupChangeL
+// Adds an entry to external category change list.
+// Also causes the category cache to be flushed.
+// -----------------------------------------------------------------------------
+//
+void CPIMContactListAdapter::ExternalGroupChangeL(TContactItemId aId, // Id of the changed category
+        TPIMExternalChangeType aType) // type of the change
+{
+    JELOG2(EPim);
+    iCategoryManager->FlushCache();
+
+    // This should never happen
+    __ASSERT_ALWAYS(iCategoryManager, User::Leave(KErrNotReady));
+
+    if (!iCategoryChanges)
+    {
+        iCategoryChanges
+        = new(ELeave) RPointerArray<CPIMCategoryStateChange> (1);
+    }
+    CPIMCategoryStateChange* change = NULL;
+    switch (aType)
+    {
+    case EPIMExternalChangeModified:
+    {
+        HBufC* newCategoryName = iCategoryManager->GroupLabelL(aId);
+        CleanupStack::PushL(newCategoryName);
+        HBufC* oldCategoryName = iCategoryManager->LabelFromCacheL(aId);
+        CleanupStack::PushL(oldCategoryName);
+        change
+        = new(ELeave) CPIMCategoryStateChange(oldCategoryName, aType, newCategoryName);
+        CleanupStack::Pop(2); // newCategoryName and oldCategoryName are
+        // now owned by change
+        break;
+    }
+    case EPIMExternalChangeNew:
+    {
+        HBufC* newCategoryName = iCategoryManager->GroupLabelL(aId);
+        CleanupStack::PushL(newCategoryName);
+        change = new(ELeave) CPIMCategoryStateChange(newCategoryName, aType);
+        CleanupStack::Pop(); // newCategoryName is now owned by change
+        break;
+    }
+    case EPIMExternalChangeRemoved:
+    {
+        HBufC* oldCategoryName = iCategoryManager->LabelFromCacheL(aId);
+        CleanupStack::PushL(oldCategoryName);
+        change = new(ELeave) CPIMCategoryStateChange(oldCategoryName, aType);
+        CleanupStack::Pop(); // newCategoryName is now owned by change
+        break;
+    }
+    default:
+    {
+        User::Leave(KErrArgument);
+    }
+    }
+
+    CleanupStack::PushL(change);
+    User::LeaveIfError(iCategoryChanges->Append(change));
+    CleanupStack::Pop(change);
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactListAdapter::ExternalItemChangeL
+// Adds an entry to external item change list.
+// -----------------------------------------------------------------------------
+//
+void CPIMContactListAdapter::ExternalItemChangeL(TContactItemId aId, // Id of the changed category
+        TPIMExternalChangeType aType) // type of the change
+{
+    JELOG2(EPim);
+    if (!iItemChanges)
+    {
+        iItemChanges = new(ELeave) RPointerArray<CPIMItemStateChange> (10);
+    }
+    HBufC8* changeId = HBufC8::NewLC(KPIMItemIdDesSize);
+    TPtr8 entryId = changeId->Des();
+    entryId.Num(static_cast<TUint>(aId));
+    CPIMItemStateChange* change =
+        new(ELeave) CPIMItemStateChange(changeId, aType);
+    // The ownership of changeId is transferred to the item state change object
+    CleanupStack::Pop(changeId);
+
+    CleanupStack::PushL(change);
+    iItemChanges->AppendL(change);
+    CleanupStack::Pop(change);
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactListAdapter::FilterAllContacts
+// Filters all contact items from the database to the changes list
+// -----------------------------------------------------------------------------
+//
+void CPIMContactListAdapter::FilterAllContactsL()
+{
+    JELOG2(EPim);
+    CCntFilter* filter = CCntFilter::NewLC();
+    filter->SetIncludeNewContacts(EFalse);
+    if (!iItemChanges)
+    {
+        iItemChanges = new(ELeave) RPointerArray<CPIMItemStateChange> (10);
+    }
+    filter->SetContactFilterTypeALL(EFalse);
+    filter->SetContactFilterTypeCard(ETrue);
+    iDatabase->FilterDatabaseL(*filter);
+    CContactIdArray* idArray = filter->iIds;
+    TInt idCount = idArray->Count();
+    TInt i = 0;
+    for (i = 0; i < idCount; i++)
+    {
+        TContactItemId id = (*idArray)[i];
+        TBool wasInList = EFalse;
+        TInt changeCount = iItemChanges->Count();
+        for (TInt j = 0; j < changeCount; j++)
+        {
+            TBuf8<KPIMItemIdDesSize> entryId;
+            entryId.Num(static_cast<TUint>(id));
+            if ((*iItemChanges)[j]->ItemID().Compare(entryId) == 0)
+            {
+                wasInList = ETrue;
+            }
+        }
+        if (!wasInList)
+        {
+            ExternalItemChangeL(id, EPIMExternalChangeNew);
+        }
+    }
+    CleanupStack::PopAndDestroy(); // filter
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactListAdapter::InitializeMinimalViewDefinitionL
+// Initializes minimal view definition
+// -----------------------------------------------------------------------------
+//
+void CPIMContactListAdapter::InitializeMinimalViewDefinitionL()
+{
+    JELOG2(EPim);
+    __ASSERT_DEBUG(iMinimalFieldsViewDef, User::Panic(KPIMPanicCategory,
+                   EPIMPanicInvalidState));
+    // Reset view definition
+    iMinimalFieldsViewDef->Reset();
+    // Add fields which are to retrieved from the native database
+    // when minimal item is to be created or read
+    iMinimalFieldsViewDef->AddL(KUidContactFieldAdditionalName);
+    iMinimalFieldsViewDef->AddL(KUidContactFieldGivenName);
+    iMinimalFieldsViewDef->AddL(KUidContactFieldFamilyName);
+    iMinimalFieldsViewDef->AddL(KUidContactFieldGivenNamePronunciation);
+    iMinimalFieldsViewDef->AddL(KUidContactFieldFamilyNamePronunciation);
+    iMinimalFieldsViewDef->AddL(KUidContactFieldPrefixName);
+    iMinimalFieldsViewDef->AddL(KUidContactFieldSuffixName);
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactListAdapter::DoReadContactItemL
+// Reads contact from the contacts database using item view definition
+// -----------------------------------------------------------------------------
+//
+void CPIMContactListAdapter::DoReadContactItemL(MPIMContactItem& aContactItem,
+        const CContactItemViewDef& aContactItemViewDef)
+{
+    JELOG2(EPim);
+    const TContactItemId id = aContactItem.ContactItemIdL();
+    __ASSERT_DEBUG(id != 0, User::Panic(KPIMPanicCategory,
+                                        EPIMPanicInvalidItemID));
+    // Read contact item using the item view definition
+    CContactCard* contactItem =
+        static_cast<CContactCard*>(iDatabase->ReadContactLC(id,
+                                   aContactItemViewDef));
+    // Set date and fill the PIM item
+    TTime lastModified = contactItem->LastModified();
+    aContactItem.SetLastModifiedL(lastModified);
+    iItemAdapter->FillItemL(aContactItem, *contactItem);
+    CleanupStack::PopAndDestroy(contactItem);
+}
+
+void CPIMContactListAdapter::IsDatabaseReadyL()
+{
+    JELOG2(EPim);
+    __ASSERT_ALWAYS(iDatabase, User::Leave(KErrNotReady));
+}
+
+// End of file