phonebookui/Phonebook/Engine/src/CContactDbConnection.cpp
changeset 0 e686773b3f54
child 32 2828b4d142c0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookui/Phonebook/Engine/src/CContactDbConnection.cpp	Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,734 @@
+/*
+* Copyright (c) 2002 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*        Implementation helper class for class CPbkContactEngine.
+*
+*/
+
+
+// INCLUDE FILES
+#include "CPbkContactEngine.h"
+#include "CContactDbConnection.h" 
+
+#include <cntdb.h>
+#include <cntview.h>
+#include <cntitem.h>
+#include <sysutil.h>
+#include <featmgr.h>
+#include <shareddataclient.h>
+
+#include <PbkDebug.h>
+#include "PbkProfiling.h"
+
+#include "PbkCompressConfig.h"
+#include "CPbkDefaultCompressionStrategy.h"
+
+#include "PbkUID.h"
+#include "CPbkFieldsInfo.h"
+#include "TPbkMatchPriorityLevel.h"
+#include "CPbkEngineExtension.h"
+#include "CPbkSortOrderManager.h"
+#include "PbkNameFormatterFactory.h"
+#include <MPbkContactNameFormat.h>
+
+// Unnamed namespace for local definitions
+
+namespace {
+
+// LOCAL CONSTANTS AND MACROS
+/// Name of the shared contacts view
+_LIT(KPbkAllContactsViewName, "AllContacts");
+
+/// Default contact database name
+_LIT(KDefaultDbName, "C:Contacts.cdb");
+
+/// Default contact view preferences
+const TContactViewPreferences KPbkDefaultContactViewPrefs =
+    static_cast<TContactViewPreferences>
+        (EContactsOnly | EUnSortedAtEnd | ESingleWhiteSpaceIsEmptyField);
+
+#ifdef _DEBUG
+enum TPanicCode
+    {
+    EPanicUninitializedData = 1
+    };
+
+// LOCAL FUNCTIONS
+void Panic(TPanicCode aReason)
+    {
+    _LIT(KPanicText, "CContactDbConnection");
+    User::Panic(KPanicText, aReason);
+    }
+#endif
+
+
+// ==================== LOCAL FUNCTIONS ====================
+
+/**
+ * Returns true if aLhs and aRhs differ.
+ */
+inline TBool operator!=
+        (const RContactViewSortOrder& aLhs, const RContactViewSortOrder& aRhs)
+    {
+    return !(aLhs == aRhs);
+    }
+
+/**
+ * Wrapper class for calling default file name or specified filename versions
+ * of CContactDatabase::ReplaceL, OpenL and CreateL.
+ */
+NONSHARABLE_CLASS(TDbOpen)
+    {
+    public:
+        /**
+         * Constructor.
+		 * @param aFileName file name
+		 * @param aReplace open or replace the database
+		 * @param aSharedDataClient shared data client
+         */ 
+        TDbOpen(const TDesC* aFileName, TBool aReplace, 
+            const RSharedDataClient& aSharedDataClient);
+
+        /**
+         * Opens or replaces database.
+         */ 
+        CContactDatabase* OpenOrReplaceL() const;
+
+        /**
+         * Creates a new database.
+         */
+        CContactDatabase* CreateL() const;
+
+        /**
+         * Returns the drive the database is stored on.
+         * @precond OpenOrReplaceL() or CreateL() has been called.
+         */
+        TDriveNumber DbDrive(RFs& aFs) const;
+
+    private: // Implementation
+        CContactDatabase* ReplaceL() const;
+        CContactDatabase* OpenL() const;
+
+    private:
+		/// Own: file name
+        TFileName iFileName;
+		/// Own: open or replace flag
+        const TBool iReplace;
+		/// Ref: contact database
+        mutable CContactDatabase* iDb;
+        /// Ref: Shared data client
+        const RSharedDataClient& iSharedDataClient;
+    };
+
+/**
+ * Updates system template to reflect aFieldsInfo.
+ */
+TBool UpdateSystemTemplateFieldsL
+        (CContactItem& aSysTemplate, 
+        const CPbkFieldsInfo& aFieldsInfo);
+
+}  // namespace
+
+
+// ================= MEMBER FUNCTIONS =======================
+
+inline CPbkContactEngine::CContactDbConnection::CContactDbConnection()
+    {
+    }
+
+inline TBool CPbkContactEngine::CContactDbConnection::CheckSystemTemplateL
+        (const CPbkFieldsInfo& aFieldsInfo)
+    {
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING(
+        "CContactDbConnection::CheckSystemTemplateL(0x%x)"),this);
+
+    // Open the system template
+    TRAPD(err, iSysTemplate = iContactDb->OpenContactL(
+        iContactDb->TemplateId()));
+    switch (err)
+        {
+        case KErrNone:
+            {
+            // All is well
+            break;
+            }
+        case KErrInUse:
+            {
+            // Assume some other CPbkContactEngine instance is currently 
+            // performing this check -> skip the test. The test could be
+            // reattempted after a delay but that would slow down the
+            // initialisation of this class even more.
+            return EFalse;
+            }
+        default:
+            {
+            // Propagate other errors to caller
+            User::Leave(err);
+            return EFalse;
+            }
+        }
+
+	TBool result = EFalse;
+    if (UpdateSystemTemplateFieldsL(*iSysTemplate,aFieldsInfo))
+        {
+        PBK_DEBUG_PRINT(PBK_DEBUG_STRING(
+            "CContactDbConnection::CheckSystemTemplateL(0x%x): updating system template...."),
+            this);
+        iContactDb->CommitContactL(*iSysTemplate);
+
+		result = ETrue;
+        PBK_DEBUG_PRINT(PBK_DEBUG_STRING(
+            "CContactDbConnection::CheckSystemTemplateL(0x%x): system template updated."), this);
+        }
+
+    CloseSystemTemplate();
+
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING(
+        "CContactDbConnection::CheckSystemTemplateL(0x%x) succesful"),this);
+	return result;
+    }
+
+inline void CPbkContactEngine::CContactDbConnection::CreateAllContactsViewL
+        (const RContactViewSortOrder& aSortOrder)
+    {
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING(
+        "CContactDbConnection::CreateAllContactsViewL(0x%x)"),this);
+
+    __PBK_PROFILE_RESET(PbkProfiling::EAllContactsViewOpen);
+    __PBK_PROFILE_START(PbkProfiling::EAllContactsViewOpen);
+    iAllContactsView = CContactNamedRemoteView::NewL
+        (*this, 
+        KPbkAllContactsViewName, 
+        Database(), 
+        aSortOrder, 
+        KPbkDefaultContactViewPrefs);
+
+	InitViewL(*iAllContactsView);
+
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING(
+        "CContactDbConnection::CreateAllContactsViewL(0x%x) succesful"),this);
+    }
+
+inline void CPbkContactEngine::CContactDbConnection::ConstructL
+        (const TParams& aParams, TBool aSettingsVisible)
+    {
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING(
+        "CContactDbConnection::ConstructL(0x%x)"),this);
+    iFs = aParams.iFs;
+
+    __PBK_PROFILE_START(PbkProfiling::EContactDbOpen);
+
+    // Shared data client is created and connected in CPbkContactEngine
+    __ASSERT_DEBUG(aParams.iEngine && aParams.iEngine->iSharedDataClient,
+        Panic(EPanicUninitializedData));
+    
+    TDbOpen dbOpen(aParams.iDbFileName, aParams.iReplaceExistingDb, 
+        *aParams.iEngine->iSharedDataClient);
+    TRAPD(error, iContactDb = dbOpen.OpenOrReplaceL());
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING(
+        "CContactDbConnection::ConstructL(0x%x): CContactDatabase open result=%d."),this, error);
+    if (error == KErrNotFound)
+        {
+	    // Db not found, create it
+	    TRAP(error, iContactDb = dbOpen.CreateL());
+        PBK_DEBUG_PRINT(PBK_DEBUG_STRING(
+            "CContactDbConnection::ConstructL(0x%x): CContactDatabase create result=%d."),this, error);
+        }
+
+    __PBK_PROFILE_END(PbkProfiling::EContactDbOpen);
+
+    *aParams.iDbOpenError = error;
+    if (error != KErrNone)
+        {
+        User::Leave(error);
+        }
+
+    // Store database drive
+    iDbDrive = dbOpen.DbDrive(iFs);
+
+    // Call engine extension plugins
+    aParams.iExtension->AddFieldTypesL(*aParams.iFieldsInfo);
+    aParams.iExtension->ModifyFieldTypesL(*aParams.iFieldsInfo);
+
+    // Check and update system template if needed
+	TBool updated = EFalse;
+    TRAP(error, updated = CheckSystemTemplateL(*aParams.iFieldsInfo));
+    *aParams.iDbOpenError = error;
+    if (error != KErrNone)
+        {
+        User::Leave(error);
+        }
+
+	if (updated)
+		{
+		// close and reopen contact database if system template has been updated
+		delete iContactDb;
+		iContactDb = NULL;
+		iContactDb = dbOpen.OpenOrReplaceL();
+		}
+
+    // Create contact DB change notifier and connect it to aObserver
+    iContactChangeNotifier = CContactChangeNotifier::NewL
+        (*iContactDb, aParams.iContactDbObserver);
+
+    // Create DB compressor
+    iCompressionStrategy = CPbkDefaultCompressionStrategy::NewL
+        (*iContactDb, iDbDrive, iFs);
+
+	// Create contact Sort order managing object
+    iSortOrderManager = CPbkSortOrderManager::NewL(iFs, aSettingsVisible);
+
+    // Create the shared all contacts view
+    CreateAllContactsViewL(iSortOrderManager->SortOrder());
+
+	// Set view to sort order manager
+	iSortOrderManager->SetContactView(*iAllContactsView);
+
+    // create name formatting object
+    iContactNameFormatter = PbkNameFormatterFactory::CreateL
+        (*aParams.iUnnamedTitle, *iSortOrderManager, aSettingsVisible);
+
+
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING(
+        "CContactDbConnection::ConstructL(0x%x) succesful."),this);
+    }
+
+CPbkContactEngine::CContactDbConnection* CPbkContactEngine::CContactDbConnection::NewL
+        (const TParams& aParams, TBool aSettingsVisible)
+    {
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING("CContactDbConnection::NewL()"));
+
+    CContactDbConnection* self = new(ELeave) CContactDbConnection;
+    CleanupStack::PushL(self);
+    self->ConstructL(aParams, aSettingsVisible);
+    CleanupStack::Pop(self);
+
+    PBK_DEBUG_PRINT(PBK_DEBUG_STRING(
+        "CContactDbConnection::NewL() succesful, result=0x%x"), self);
+    return self;
+    }
+
+CPbkContactEngine::CContactDbConnection::~CContactDbConnection()
+    {
+    for (TInt i = iFilteredViews.Count()-1; i >= 0; --i)
+        {
+        iFilteredViews[i].iFilteredView->Close(*this);
+        }
+    iFilteredViews.Close();
+    if (iGroupsLocalView)
+        {
+        iGroupsLocalView->Close(*this);
+        }
+
+    if (iAllContactsView)
+        {
+        iAllContactsView->Close(*this);
+        }
+    
+    if (iCompressionStrategy)
+        {
+        iCompressionStrategy->Release();
+        }
+    delete iContactChangeNotifier;
+	delete iContactNameFormatter;
+	delete iSortOrderManager;
+    CloseSystemTemplate();
+    delete iContactDb;
+    }
+
+CContactViewBase& CPbkContactEngine::CContactDbConnection::AllGroupsViewL()
+    {
+    // start loading the all the groups
+    if (!iGroupsLocalView)
+        {
+        // Create a CContactLocalView that contains only groups.
+        RContactViewSortOrder groupViewSortOrder;
+        CleanupClosePushL(groupViewSortOrder);
+        // KUidContactFieldTemplateLabel contains the group label
+        groupViewSortOrder.AppendL(KUidContactFieldTemplateLabel);
+
+        iGroupsLocalView = CContactLocalView::NewL(
+            *this, *iContactDb, groupViewSortOrder, EGroupsOnly);
+
+		InitViewL(*iGroupsLocalView);
+
+        CleanupStack::PopAndDestroy();  // groupViewSortOrder
+        }
+    
+    return *iGroupsLocalView;
+    }
+
+CContactViewBase& CPbkContactEngine::CContactDbConnection::FilteredContactsViewL
+        (TInt aFilter)
+    {
+    const TInt count = iFilteredViews.Count();
+    for (TInt i=0; i < count; ++i)
+        {
+        if (iFilteredViews[i].iFilter == aFilter)
+            {
+            PBK_DEBUG_PRINT(PBK_DEBUG_STRING(
+                "Returned filtered view filter=%x from the cache"), aFilter);
+            return *iFilteredViews[i].iFilteredView;
+            }
+        }
+
+    // Ending this profile is in HandleContactViewEvent
+    __PBK_PROFILE_RESET(PbkProfiling::EFilteredViewOpen);
+    __PBK_PROFILE_START(PbkProfiling::EFilteredViewOpen);
+
+    TFilteredView filter;
+    filter.iFilter = aFilter;
+    filter.iFilteredView = CContactFilteredView::NewL
+        (*this, *iContactDb, *iAllContactsView, aFilter);
+	InitViewL(*filter.iFilteredView);
+    const TInt err = iFilteredViews.Append(filter);
+    if (err != KErrNone)
+        {
+        filter.iFilteredView->Close(*this);
+        User::Leave(err);
+        }
+    
+    return *filter.iFilteredView;
+    }
+
+void CPbkContactEngine::CContactDbConnection::SetCompressUi
+        (MPbkCompressUi* aCompressUi)
+    {
+    iCompressionStrategy->SetCompressUi(aCompressUi);
+    }
+
+TBool CPbkContactEngine::CContactDbConnection::IsCompressionEnabled() const
+    {
+    return iCompressionStrategy->IsCompressionEnabled();
+    }
+
+TBool CPbkContactEngine::CContactDbConnection::CheckCompress()
+    {
+    return iCompressionStrategy->CheckCompress();
+    }
+
+void CPbkContactEngine::CContactDbConnection::CompressL()
+    {
+    iCompressionStrategy->CompressL();
+    }
+
+void CPbkContactEngine::CContactDbConnection::CancelCompress() const
+    {
+    iCompressionStrategy->CancelCompress();
+    }
+
+void CPbkContactEngine::CContactDbConnection::CheckFileSystemSpaceAndCompressL()
+    {
+    PBK_COMPRESS_LOG
+        (PBK_COMPRESS_STRING(
+        "CContactDbConnection::CheckFileSystemSpaceAndCompressL(0x%x), DB size = %d bytes"), 
+        this, Database().FileSize());
+
+    // Cancel any async compress in progress
+    CancelCompress();
+
+    // Compress synchronously always if compression is required by the DB 
+    // or file system space is below critical level
+    if (Database().CompressRequired() || FileSpaceLowOnDbDrive())
+        {
+        TRAPD(result, Database().CompactL());
+        PBK_COMPRESS_LOG(PBK_COMPRESS_STRING("    Compacted database, result=%d"), result);
+        }
+
+    // If file system space is still under critical level leave with 
+    // error code KErrDiskFull.
+    if (FileSpaceLowOnDbDrive())
+        {
+        PBK_COMPRESS_LOG
+            (PBK_COMPRESS_STRING("    FFS space is under critical level -> leaving with KErrDiskFull(%d)"), 
+            KErrDiskFull);
+        User::Leave(KErrDiskFull);
+        }
+    }
+
+TBool CPbkContactEngine::CContactDbConnection::FileSpaceLowOnDbDrive() const
+    {
+    TBool result = EFalse;
+    TRAP_IGNORE(result = SysUtil::DiskSpaceBelowCriticalLevelL(&iFs,0,iDbDrive));
+    if (result)
+        {
+        PBK_COMPRESS_LOG(PBK_COMPRESS_STRING("CContactDbConnection::FileSpaceLowOnDbDrive() returning ETrue"));
+        }
+    return result;
+    }
+
+void CPbkContactEngine::CContactDbConnection::HandleContactViewEvent
+#ifdef PBK_ENABLE_PROFILE
+        (const CContactViewBase& aView, const TContactViewEvent& aEvent)
+#else
+        (const CContactViewBase& /*aView*/, const TContactViewEvent& /*aEvent*/)
+#endif
+    {
+#ifdef PBK_ENABLE_PROFILE
+    if (aEvent.iEventType != TContactViewEvent::EReady)
+        {
+        return;
+        }
+    if (&aView == iAllContactsView)
+        {
+        __PBK_PROFILE_END(PbkProfiling::EAllContactsViewOpen);
+        __PBK_PROFILE_DISPLAY(PbkProfiling::EAllContactsViewOpen);
+        __PBK_PROFILE_RESET(PbkProfiling::EAllContactsViewOpen);
+        }
+    else if (iFilteredViews.Count() > 0)
+        {
+        for (TInt i=0; i < iFilteredViews.Count(); ++i)
+            {
+            if (iFilteredViews[i].iFilteredView == &aView)
+                {
+                __PBK_PROFILE_END(PbkProfiling::EFilteredViewOpen);
+                __PBK_PROFILE_DISPLAY(PbkProfiling::EFilteredViewOpen);
+                __PBK_PROFILE_RESET(PbkProfiling::EFilteredViewOpen);
+                }
+            }
+
+        }
+#endif // PBK_ENABLE_PROFILE
+    }
+
+void CPbkContactEngine::CContactDbConnection::CloseSystemTemplate()
+    {
+    if (iSysTemplate)
+        {
+        // Contact Model documentation says CloseContactL cannot leave
+        iContactDb->CloseContactL(iSysTemplate->Id());
+        delete iSysTemplate;
+        iSysTemplate = NULL;
+        }
+    }
+
+void CPbkContactEngine::CContactDbConnection::ChangeSortOrderL
+		(const RContactViewSortOrder& aSortOrder) const
+	{
+	// Compare is the new sort order same than the previous one
+	if (iAllContactsView->SortOrderL() != aSortOrder)
+		{
+		// It wasn't, change the sort order
+		iAllContactsView->ChangeSortOrderL(aSortOrder);
+		}
+	}
+
+MPbkContactNameFormat& CPbkContactEngine::CContactDbConnection::ContactNameFormatter() const
+	{
+	return *iContactNameFormatter;
+	}
+
+void CPbkContactEngine::CContactDbConnection::SetNameDisplayOrderL
+		(TPbkNameOrder aNameOrder)
+	{
+	iSortOrderManager->SetNameDisplayOrderL(aNameOrder);
+	}
+
+CPbkContactEngine::TPbkNameOrder CPbkContactEngine::CContactDbConnection::NameDisplayOrder()
+	{
+	return iSortOrderManager->NameDisplayOrder();
+	}
+	
+	
+void CPbkContactEngine::CContactDbConnection::SetNameSeparatorL(TChar aNameSeparator)
+    {
+    iSortOrderManager->SetNameSeparatorL(aNameSeparator);
+    }
+    
+TChar CPbkContactEngine::CContactDbConnection::NameSeparator()
+    {
+    return iSortOrderManager->NameSeparator();
+    }
+
+/**
+ * Call this method for all views created in this class.
+ */
+void CPbkContactEngine::CContactDbConnection::InitViewL(CContactViewBase& aView)
+	{
+	// Set find plugin
+	aView.SetViewFindConfigPlugin(TUid::Uid(KFindPluginUID));
+	}
+
+
+namespace {
+
+const TInt KDiskSpaceForDbOpening = 140*1024; // Space for db opening
+
+// ==================== LOCAL FUNCTIONS ====================
+
+/**
+ * Returns the default database name using CContactDatabase::GetDefaultNameL().
+ * If GetDefaultNameL() fails returns silently KDefaultDbName.
+ */ 
+void GetDefaultDatabaseName(TDes& aName)
+    {
+    TRAPD(err, CContactDatabase::GetDefaultNameL(aName));
+    if (err != KErrNone)
+        {
+        PBK_DEBUG_PRINT(PBK_DEBUG_STRING(
+            "CContactDatabase::GetDefaultNameL() failed with error code %d"),
+            err);
+        aName.Copy(KDefaultDbName);
+        }
+    }
+TDbOpen::TDbOpen(const TDesC* aFileName, TBool aReplace, 
+    const RSharedDataClient& aSharedDataClient):
+    iReplace(aReplace), iSharedDataClient(aSharedDataClient)
+    {
+    if (aFileName)
+        {
+        iFileName.Copy(aFileName->Left(iFileName.MaxLength()));
+        }
+    else
+        {
+        GetDefaultDatabaseName(iFileName);
+        }
+    }
+
+inline CContactDatabase* TDbOpen::ReplaceL() const
+    {
+    iDb = CContactDatabase::ReplaceL(iFileName);
+    return iDb;
+    }
+
+
+inline CContactDatabase* TDbOpen::OpenL() const
+    {   
+     
+    TRAPD(err,iDb = CContactDatabase::OpenL(iFileName));
+
+    //Handle KErrDiskFull case separately
+    if(KErrDiskFull==err)
+        {
+        PBK_DEBUG_PRINT(PBK_DEBUG_STRING(
+            "CContactDbConnection::TDbOpen::OpenL(0x%x) KErrDiskFull"),this);
+        // Try to release space for contact db opening
+        iSharedDataClient.RequestFreeDiskSpaceLC(KDiskSpaceForDbOpening);
+        iDb = CContactDatabase::OpenL(iFileName);        
+        CleanupStack::PopAndDestroy();  // RequestFreeDiskSpaceLC
+        PBK_DEBUG_PRINT(PBK_DEBUG_STRING(
+            "CContactDbConnection::TDbOpen::OpenL(0x%x) ContactDb open"),this);
+        }
+    else
+        {
+        User::LeaveIfError(err);
+        }        
+    return iDb;
+    }
+
+
+CContactDatabase* TDbOpen::OpenOrReplaceL() const
+    {
+    return (iReplace ? ReplaceL() : OpenL());
+    }
+
+CContactDatabase* TDbOpen::CreateL() const
+    {
+    iDb = CContactDatabase::CreateL(iFileName);
+    return iDb;
+    }
+
+TDriveNumber TDbOpen::DbDrive(RFs& aFs) const
+    {
+    TInt result = EDriveC;
+    TParsePtrC fileParser(iFileName);
+    if (fileParser.DrivePresent())
+        {
+        const TChar driveLetter(fileParser.Drive()[0]);
+        TInt drive;
+        if (aFs.CharToDrive(driveLetter,drive) == KErrNone)
+            {
+            result = drive;
+            }
+        }
+    else
+        {
+        TDriveUnit driveUnit;
+        //Note: this function can leave
+        TRAPD(err, iDb->DatabaseDrive(driveUnit));
+        if (err == KErrNone)
+            {
+            result = driveUnit;
+            }
+        }
+    return static_cast<TDriveNumber>(result);
+    }
+
+/**
+ * Updates a single field to the contact database system template. If the field
+ * does not exist in the system template it is added. If the field exists but 
+ * its label differs from the field type label the system template label is 
+ * updated.
+ *
+ * @param aSysTemplate  the system template.
+ * @param aFieldInfo    the field type to update.
+ * @return true if the system template was updated.
+ */
+TBool UpdateSystemTemplateFieldL
+        (CContactItem& aSysTemplate, const CPbkFieldInfo& aFieldInfo)
+    {
+    TBool updated = EFalse;
+    // Scan system template field set for the field
+    CContactItemFieldSet& fieldSet = aSysTemplate.CardFields();
+    TInt i;
+    const TInt fieldCount = fieldSet.Count();
+    for (i = 0; i < fieldCount; ++i)
+        {
+        CContactItemField& sysTemplateField = fieldSet[i];
+        if (aFieldInfo.IsEqualType(sysTemplateField))
+            {
+            // Field was found, just check the label
+            if (!aFieldInfo.IsEqualLabel(sysTemplateField))
+                {
+                sysTemplateField.SetLabelL(aFieldInfo.FieldName());
+                updated = ETrue;
+                }
+            break;
+            }
+        }
+    
+    if (i == fieldCount)
+        {
+        // Field was not found, add it
+        CContactItemField* field = aFieldInfo.CreateFieldL();
+        CleanupStack::PushL(field);
+        fieldSet.AddL(*field);
+        CleanupStack::Pop(field);
+        updated = ETrue;
+        }    
+    return updated;
+    }
+
+TBool UpdateSystemTemplateFieldsL
+        (CContactItem& aSysTemplate, 
+        const CPbkFieldsInfo& aFieldsInfo)
+    {
+    TBool updated = EFalse;
+    const TInt fieldInfoCount = aFieldsInfo.Count();
+
+    // Update fields
+    for (TInt i=0; i < fieldInfoCount; ++i)
+        {
+        if (UpdateSystemTemplateFieldL(aSysTemplate, *aFieldsInfo[i]))
+            {
+            updated = ETrue;
+            }
+        }
+
+    return updated;
+    }
+
+}  // namespace
+
+//  End of File