--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookui/Phonebook/Engine/src/CPbkContactEngine.cpp Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,1184 @@
+/*
+* 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:
+* Represents a connection to the Phonebook contact database
+*
+*/
+
+
+// INCLUDE FILES
+#include "CPbkContactEngine.h"
+#include <cntdb.h> // CContactDatabase class
+#include <cntitem.h> // ContactItem class
+#include <barsc.h> // RResourceFile
+#include <barsread.h> // TResourceReader
+#include <shareddataclient.h> // RSharedDataClient
+#include <featmgr.h> // Feature manager
+#include <ecom/ecom.h>
+#include <PbkUID.h>
+#include <bautils.h> // BaflUtils
+
+#include <PbkEng.rsg> // Engine resources
+#include "CPbkFieldsInfo.h"
+#include "CPbkFieldInfo.h"
+#include "CPbkContactItem.h"
+#include "CPbkContactIter.h"
+#include "MPbkContactDbObserver.h"
+#include "CPbkContactChangeNotifier.h"
+#include "CPbkIdleFinder.h"
+#include <PbkEngUtils.h>
+#include <CPbkConstants.h>
+#include "CPbkEngineExtension.h"
+
+#include "CContactDbConnection.h"
+#include <MPbkContactNameFormat.h>
+#include "CPbkDeleteContacts.h"
+#include "CPbkIdleProcessRunner.h"
+#include "PbkDataCaging.hrh"
+#include "cpbkenginelocalstorage.h"
+
+#include <PbkDebug.h> // Phonebook debugging support
+#include "PbkProfiling.h"
+
+/// Unnamed namespace for local definitons
+namespace {
+
+// LOCAL CONSTANTS AND MACROS
+
+_LIT(KCntModelResFileName, "cntmodel.rsc");
+_LIT(KCntModelResFileDrive, "z:");
+_LIT8(KSettingsVisibleCompareStr, "*1*");
+
+enum TPanicCode
+ {
+ EPanicContactNotGroup = 1,
+ EPanicPreCond_AddObserverL,
+ EPanicPostCond_AddObserverL,
+ EPanicPreCond_RemoveObserver,
+ EPanicPostCond_RemoveObserver,
+ EPanicObserverNotFoundInRemove,
+ EPanicPreCond_ConstructL,
+ EPanicPreCond_UnnamedTitle,
+ EPanicPreCond_CreateEmptyContactL,
+ EPanicFieldInfoNotFound,
+ EPanicLogic_ConstructL,
+ EPanicSetTlsFails,
+ EPanicSINDHandlerNotFound // obsolete
+ };
+
+
+// ==================== LOCAL FUNCTIONS ====================
+
+void Panic(TPanicCode aReason)
+ {
+ _LIT(KPanicText, "CPbkContactEngine");
+ User::Panic(KPanicText, aReason);
+ }
+
+/**
+ * Returns true if aError is a fatal database open error.
+ */
+TBool IsFatalDbOpenError(TInt aError);
+
+/**
+ * Removes all information that should not be duplicated from aContactItem.
+ */
+void RemoveNonDuplicableContactInformation(CContactItem& aContactItem);
+
+} // namespace
+
+
+// ================= MEMBER FUNCTIONS =======================
+
+inline CPbkContactEngine::CPbkContactEngine() :
+ iFreeSpaceRequiredToDelete(8*1024) // 8 kB by default
+ // CBase::operator new(TLeave) will reset other members
+ {
+ }
+
+EXPORT_C CPbkContactEngine* CPbkContactEngine::NewL(RFs* aFs/*=NULL*/)
+ {
+ CPbkContactEngine* self = new(ELeave) CPbkContactEngine;
+ CleanupStack::PushL(self);
+ self->ConstructL(NULL, EFalse, aFs);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+EXPORT_C CPbkContactEngine* CPbkContactEngine::NewL
+ (const TDesC& aFileName, TBool aReplace/*=EFalse*/, RFs* aFs/*=NULL*/)
+ {
+ CPbkContactEngine* self = new(ELeave) CPbkContactEngine;
+ CleanupStack::PushL(self);
+ self->ConstructL(&aFileName, aReplace, aFs);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+EXPORT_C CPbkContactEngine* CPbkContactEngine::ReplaceL
+ (RFs* aFs/*=NULL*/)
+ {
+ CPbkContactEngine* self = new(ELeave) CPbkContactEngine;
+ CleanupStack::PushL(self);
+ self->ConstructL(NULL, ETrue, aFs);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CPbkContactEngine::~CPbkContactEngine()
+ {
+ PBK_DEBUG_PRINT(PBK_DEBUG_STRING("CPbkContactEngine(%x)::~CPbkContactEngine"), this);
+
+ // Check if this is the Tls-registered instance and remove it from Tls
+ CPbkEngineLocalStorage* storage =
+ reinterpret_cast<CPbkEngineLocalStorage*> (Dll::Tls());
+ if ( storage )
+ {
+ // check that this instance is the same than stored instance
+ if ( &storage->iEngine == this )
+ {
+ // delete the storage instance.
+ delete storage;
+ Dll::SetTls( NULL );
+ }
+
+ }
+
+ if (iSharedDataClient)
+ {
+ iSharedDataClient->Close();
+ delete iSharedDataClient;
+ }
+
+ delete iDbConnection;
+ delete iObservers;
+ delete iPbkFieldsInfo;
+ delete iPbkConstants;
+ delete iExtension;
+
+ FeatureManager::UnInitializeLib();
+ iOwnFs.Close();
+
+ // Cleanup ECom session
+ REComSession::FinalClose();
+ }
+
+EXPORT_C CPbkContactEngine* CPbkContactEngine::Static()
+ {
+ CPbkEngineLocalStorage* storage =
+ reinterpret_cast<CPbkEngineLocalStorage*> ( Dll::Tls( ) );
+
+ if ( storage )
+ {
+ return &storage->iEngine;
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+
+inline void CPbkContactEngine::ConnectFsL(RFs* aRfs)
+ {
+ PBK_DEBUG_PRINT(PBK_DEBUG_STRING("CPbkContactEngine::ConnectFsL(0x%x)"), this);
+
+ if (aRfs)
+ {
+ iFs = *aRfs;
+ }
+ else
+ {
+ User::LeaveIfError(iOwnFs.Connect());
+ iFs = iOwnFs;
+ }
+
+ PBK_DEBUG_PRINT(PBK_DEBUG_STRING("CPbkContactEngine::ConnectFsL(0x%x) succesful"), this);
+ }
+
+inline void CPbkContactEngine::ReadResourcesL(TBool& aSettingsVisibility)
+ {
+ PBK_DEBUG_PRINT(PBK_DEBUG_STRING
+ ("CPbkContactEngine::ReadResourcesL(0x%x)"), this);
+ __PBK_PROFILE_START(PbkProfiling::EInitEngineResources);
+
+ // Open the resource files
+ RResourceFile pbkResFile;
+ PbkEngUtils::FindAndOpenDefaultResourceFileLC(iFs, pbkResFile);
+ RResourceFile cntModelResFile;
+ PbkEngUtils::FindAndOpenResourceFileLC
+ (iFs, KCntModelResFileName, KDC_CONTACTS_RESOURCE_DIR, KCntModelResFileDrive,
+ cntModelResFile);
+
+ // Read fields info array
+ iPbkFieldsInfo = CPbkFieldsInfo::NewL(pbkResFile, cntModelResFile);
+
+ // load phonebook constants
+ iPbkConstants = CPbkConstants::NewL(pbkResFile);
+
+ // read the name ordering settings menu item visibility value:
+ HBufC8* buffer = pbkResFile.AllocReadLC(R_PBK_NAME_ORDERING_SETTINGS_VISIBILITY);
+
+ if ( buffer->MatchF(KSettingsVisibleCompareStr) == 0 )
+ {
+ aSettingsVisibility = ETrue;
+ }
+
+ // Close resource files
+ CleanupStack::PopAndDestroy(3);
+
+ __PBK_PROFILE_END(PbkProfiling::EInitEngineResources);
+ PBK_DEBUG_PRINT(PBK_DEBUG_STRING
+ ("CPbkContactEngine::ReadResourcesL(0x%x) succesful"), this);
+ }
+
+inline void CPbkContactEngine::CreateDbConnectionL
+ (const TDesC* aFileName,
+ TBool aReplace,
+ TInt& aDbOpenError,
+ TBool aSettingsVisible)
+ {
+ PBK_DEBUG_PRINT(PBK_DEBUG_STRING
+ ("CPbkContactEngine::CreateDbConnectionL(0x%x)"), this);
+
+ // Create contact database connection object
+ CContactDbConnection::TParams params;
+ params.iDbFileName = aFileName;
+ params.iReplaceExistingDb = aReplace;
+ params.iContactDbObserver = this;
+ params.iFs = iFs;
+ params.iFieldsInfo = iPbkFieldsInfo;
+ params.iExtension = iExtension;
+ params.iDbOpenError = &aDbOpenError;
+ params.iUnnamedTitle = &iPbkConstants->UnnamedTitle();
+ params.iEngine = this;
+
+ iDbConnection = CContactDbConnection::NewL(params, aSettingsVisible);
+
+ PBK_DEBUG_PRINT(PBK_DEBUG_STRING
+ ("CPbkContactEngine::CreateDbConnectionL(0x%x) succesful"), this);
+ }
+
+void CPbkContactEngine::ConstructL
+ (const TDesC* aFileName,
+ TBool aReplace, RFs* aRfs)
+ {
+ __ASSERT_DEBUG(
+ !iDbConnection && !iPbkFieldsInfo,
+ Panic(EPanicPreCond_ConstructL));
+
+ PBK_DEBUG_PRINT(PBK_DEBUG_STRING
+ ("CPbkContactEngine::ConstructL(0x%x)"), this);
+
+ ConnectFsL(aRfs);
+
+ FeatureManager::InitializeLibL();
+
+ // Shared data objects have to created after ConnectFsL,
+ // but before ReadResourcesL
+ iSharedDataClient = new (ELeave) RSharedDataClient;
+ User::LeaveIfError(iSharedDataClient->Connect());
+
+ iExtension = CPbkEngineExtension::NewL(iFs);
+
+ TBool settingsVisible(EFalse);
+
+ ReadResourcesL(settingsVisible);
+ TInt dbOpenError = KErrNone;
+ TRAPD(dbConnectError, CreateDbConnectionL(aFileName, aReplace, dbOpenError, settingsVisible));
+ if (IsFatalDbOpenError(dbOpenError))
+ {
+ __ASSERT_DEBUG(dbOpenError == dbConnectError, Panic(EPanicLogic_ConstructL));
+ // Map all fatal database open errors to KErrCorrupt
+ User::Leave(KErrCorrupt);
+ }
+ if (dbConnectError != KErrNone)
+ {
+ if (dbConnectError == KErrCorrupt)
+ {
+ // Convert KErrCorrupt to another error code to avoid clients
+ // mixing this error up with database corruption
+ dbConnectError = KErrGeneral;
+ }
+ User::Leave(dbConnectError);
+ }
+
+ if (!Dll::Tls())
+ {
+ CPbkEngineLocalStorage* storage = CPbkEngineLocalStorage::NewL(*this);
+ TInt ret = Dll::SetTls(storage); // Takes ownership
+ __ASSERT_DEBUG( ret == KErrNone, Panic( EPanicSetTlsFails ) );
+ }
+
+ PBK_DEBUG_PRINT(PBK_DEBUG_STRING
+ ("CPbkContactEngine::ConstructL(0x%x) succesful"), this);
+ }
+
+EXPORT_C CPbkContactItem* CPbkContactEngine::CreateEmptyContactL()
+ {
+ // Create an empty (ie. no fields) contact card
+ CContactCard* card = CContactCard::NewLC();
+ __ASSERT_DEBUG(card->CardFields().Count()==0,
+ Panic(EPanicPreCond_CreateEmptyContactL));
+
+ // Loop through Phonebook field infos
+ const TInt count = FieldsInfo().Count();
+ for (TInt i=0; i < count; ++i)
+ {
+ const CPbkFieldInfo* fi = FieldsInfo()[i];
+ if (fi->TemplateField())
+ {
+ // Create a CContactItemField for fields belonging
+ // to the default template
+ CContactItemField* field = fi->CreateFieldL();
+ CleanupStack::PushL(field);
+ // Add the field to the contact card
+ card->AddFieldL(*field);
+ CleanupStack::Pop(field);
+ }
+ }
+
+ // Create phonebook contact item from card and return it.
+ CPbkContactItem* pbkItem = CPbkContactItem::NewL(card,
+ FieldsInfo(), ContactNameFormat());
+ CleanupStack::Pop(); // card
+ return pbkItem;
+ }
+
+EXPORT_C const CPbkFieldsInfo& CPbkContactEngine::FieldsInfo()
+ {
+ return *iPbkFieldsInfo;
+ }
+
+EXPORT_C RFs& CPbkContactEngine::FsSession() const
+ {
+ return const_cast<RFs&>(iFs);
+ }
+
+EXPORT_C CPbkContactIter* CPbkContactEngine::CreateContactIteratorLC
+ (TBool aUseMinimalRead/*=EFalse*/)
+ {
+ iDbConnection->CancelCompress();
+ return CPbkContactIter::NewLC(*this, aUseMinimalRead);
+ }
+
+EXPORT_C CPbkContactChangeNotifier*
+ CPbkContactEngine::CreateContactChangeNotifierL
+ (MPbkContactDbObserver *aObserver)
+ {
+ return CPbkContactChangeNotifier::NewL(*this, aObserver);
+ }
+
+EXPORT_C const TDesC& CPbkContactEngine::UnnamedTitle() const
+ {
+ __ASSERT_DEBUG(iPbkConstants, Panic(EPanicPreCond_UnnamedTitle));
+ return iPbkConstants->UnnamedTitle();
+ }
+
+EXPORT_C TContactItemId CPbkContactEngine::AddNewContactL
+ (CPbkContactItem& aContact, TBool aImmediateNotify/*=EFalse*/)
+ {
+ PBK_DEBUG_PRINT(PBK_DEBUG_STRING
+ ("CPbkContactEngine(%x)::AddNewContactL(aContact=%x, aImmediateNotify=%d)"),
+ this, &aContact, aImmediateNotify);
+
+ iDbConnection->CancelCompress();
+ // Prepare contact for saving to the DB
+ aContact.PrepareForSaveL();
+ TContactItemId cid = iDbConnection->Database().AddNewContactL
+ (aContact.ContactItem());
+ // Undo PrepareForSaveL
+ aContact.PrepareAfterLoadL();
+
+ // Send immediate event
+ SendImmidiateEventToAllObservers(EContactDbObserverEventContactAdded,
+ cid, aImmediateNotify);
+
+ return cid;
+ }
+
+EXPORT_C CPbkContactItem* CPbkContactEngine::ReadContactL
+ (TContactItemId aContactId,
+ const CPbkFieldIdArray* aFieldTypes/*=NULL*/)
+ {
+ CPbkContactItem* item = ReadContactLC(aContactId, aFieldTypes);
+ CleanupStack::Pop(); // item
+ return item;
+ }
+
+EXPORT_C CPbkContactItem* CPbkContactEngine::ReadContactLC
+ (TContactItemId aContactId,
+ const CPbkFieldIdArray* aFieldTypes/*=NULL*/)
+ {
+ iDbConnection->CancelCompress();
+ CContactItem* item = NULL;
+ if (aFieldTypes)
+ {
+ CContactItemViewDef* viewDef =
+ FieldsInfo().CreateContactItemViewDefLC(*aFieldTypes);
+ item = iDbConnection->Database().ReadContactL(aContactId, *viewDef);
+ CleanupStack::PopAndDestroy(viewDef);
+ CleanupStack::PushL(item);
+ }
+ else
+ {
+ item = iDbConnection->Database().ReadContactLC(aContactId);
+ }
+ CPbkContactItem* pbkItem = CPbkContactItem::NewL
+ (item, FieldsInfo(), ContactNameFormat());
+ // CPbkContactItem takes ownership of item
+ CleanupStack::Pop(); // item
+ CleanupStack::PushL(pbkItem);
+
+ // Prep empty fields for use in the application.
+ // See also CommitContactL.
+ pbkItem->PrepareAfterLoadL();
+
+ iDbConnection->CompressL();
+ return pbkItem;
+ }
+
+EXPORT_C CPbkContactItem* CPbkContactEngine::ReadMinimalContactLC
+ (TContactItemId aContactId)
+ {
+ iDbConnection->CancelCompress();
+ CContactItem* item =
+ iDbConnection->Database().ReadMinimalContactLC(aContactId);
+ CPbkContactItem* pbkItem = CPbkContactItem::NewL
+ (item, FieldsInfo(), ContactNameFormat());
+ // CPbkContactItem takes ownership of item
+ CleanupStack::Pop(); // item
+ CleanupStack::PushL(pbkItem);
+
+ // Prep empty fields for use in the application.
+ // See also CommitContactL.
+ pbkItem->PrepareAfterLoadL();
+
+ iDbConnection->CompressL();
+ return pbkItem;
+ }
+
+EXPORT_C CPbkContactItem* CPbkContactEngine::OpenContactL
+ (TContactItemId aContactId)
+ {
+ PBK_DEBUG_PRINT(
+ PBK_DEBUG_STRING("CPbkContactEngine(%x)::OpenContactL(aContactId=%d)"),
+ this, aContactId);
+
+ CPbkContactItem* pbkItem = OpenContactLCX(aContactId);
+ CleanupStack::Pop(2); // pbkItem, lock
+ return pbkItem;
+ }
+
+EXPORT_C CPbkContactItem* CPbkContactEngine::OpenContactLCX
+ (TContactItemId aContactId)
+ {
+ PBK_DEBUG_PRINT(
+ PBK_DEBUG_STRING("CPbkContactEngine(%x)::OpenContactLCX(aContactId=%d)"),
+ this, aContactId);
+
+ iDbConnection->CancelCompress();
+ CContactItem* item = iDbConnection->Database().OpenContactLX(aContactId);
+ CleanupStack::PushL(item);
+ CPbkContactItem* pbkItem =
+ CPbkContactItem::NewL(item, FieldsInfo(), ContactNameFormat());
+ // CPbkContactItem takes ownership of item
+ CleanupStack::Pop(item);
+ CleanupStack::PushL(pbkItem);
+
+ // Prep empty fields for use in the application.
+ // See also CommitContactL.
+ pbkItem->PrepareAfterLoadL();
+
+ return pbkItem;
+ }
+
+EXPORT_C void CPbkContactEngine::CommitContactL
+ (CPbkContactItem& aContact, TBool aImmediateNotify/*=EFalse*/)
+ {
+ PBK_DEBUG_PRINT(
+ PBK_DEBUG_STRING(
+ "CPbkContactEngine(%x)::CommitContactL(aContact=%x, aImmediateNotify=%d)"),
+ this, &aContact, aImmediateNotify);
+
+ iDbConnection->CancelCompress();
+ // Prepare contact for saving to the DB
+ aContact.PrepareForSaveL();
+ iDbConnection->Database().CommitContactL(aContact.ContactItem());
+ // Undo PrepareForSaveL
+ aContact.PrepareAfterLoadL();
+
+ // Send immediate event
+ SendImmidiateEventToAllObservers(EContactDbObserverEventContactChanged,
+ aContact.ContactItem().Id(), aImmediateNotify);
+ }
+
+EXPORT_C void CPbkContactEngine::CloseContactL
+ (TContactItemId aContactId)
+ {
+ PBK_DEBUG_PRINT(
+ PBK_DEBUG_STRING("CPbkContactEngine(%x)::CloseContactL(aContactId=%d)"),
+ this, aContactId);
+
+ iDbConnection->CancelCompress();
+ iDbConnection->Database().CloseContactL(aContactId);
+ }
+
+EXPORT_C void CPbkContactEngine::DeleteContactL
+ (TContactItemId aContactId, TBool aImmediateNotify/*=EFalse*/)
+ {
+ PBK_DEBUG_PRINT(
+ PBK_DEBUG_STRING(
+ "ENTER: CPbkContactEngine(%x)::DeleteContactL(aContactId=%d, aImmediateNotify=%d)"),
+ this, aContactId, aImmediateNotify);
+
+ doDeleteContactL(aContactId);
+
+ // Send immediate event
+ SendImmidiateEventToAllObservers(EContactDbObserverEventContactDeleted,
+ aContactId, aImmediateNotify);
+ }
+
+EXPORT_C void CPbkContactEngine::DeleteContactGroupL
+ (TContactItemId aContactId, TBool aImmediateNotify/*=EFalse*/)
+ {
+ PBK_DEBUG_PRINT(
+ PBK_DEBUG_STRING(
+ "ENTER: CPbkContactEngine(%x)::DeleteContactL(aContactId=%d, aImmediateNotify=%d)"),
+ this, aContactId, aImmediateNotify);
+
+ doDeleteContactL(aContactId);
+
+ // Send immediate event
+ SendImmidiateEventToAllObservers(EContactDbObserverEventGroupDeleted,
+ aContactId, aImmediateNotify);
+ }
+
+
+EXPORT_C void CPbkContactEngine::DeleteContactsL
+ (const CContactIdArray& aContactIds, TBool aImmediateNotify/*=EFalse*/)
+ {
+ PBK_DEBUG_PRINT(
+ PBK_DEBUG_STRING(
+ "ENTER: CPbkContactEngine(%x)::DeleteContactsL(count=%d, aImmediateNotify=%d)"),
+ this, aContactIds.Count(), aImmediateNotify);
+
+ iDbConnection->CancelCompress();
+ iDbConnection->Database().DeleteContactsL(aContactIds);
+
+ SendImmidiateEventToAllObservers(EContactDbObserverEventUnknownChanges,
+ KNullContactId, aImmediateNotify);
+ }
+
+EXPORT_C void CPbkContactEngine::DeleteContactsOnBackgroundL
+ (const CContactIdArray& aContactIds)
+ {
+ iDbConnection->CancelCompress();
+ // Shared data client is connected during construction
+ CPbkDeleteContacts* process = CPbkDeleteContacts::NewLC(*this,aContactIds, *iSharedDataClient);
+ CPbkIdleProcessRunner* runner =
+ CPbkIdleProcessRunner::NewL(CActive::EPriorityIdle);
+ CleanupStack::PushL(runner);
+ runner->SynchronousExecuteL(*process);
+
+ if (process->DeletedCount() > 0)
+ {
+ SendImmidiateEventToAllObservers(EContactDbObserverEventUnknownChanges,
+ KNullContactId, ETrue);
+ }
+ CleanupStack::PopAndDestroy(2); // runner, process
+ }
+
+EXPORT_C CContactGroup* CPbkContactEngine::CreateContactGroupL
+ (const TDesC& aGroupLabel,
+ TBool aInTransaction)
+ {
+ iDbConnection->CancelCompress();
+ CContactGroup* group =
+ static_cast<CContactGroup*>
+ (iDbConnection->Database().CreateContactGroupL(aGroupLabel, aInTransaction));
+
+ // Send immediate event
+ SendImmidiateEventToAllObservers(EContactDbObserverEventGroupAdded,
+ group->Id(), ETrue);
+
+ return group;
+ }
+
+EXPORT_C void CPbkContactEngine::AddContactToGroupL
+ (TContactItemId aItemId,
+ TContactItemId aGroupId)
+ {
+ iDbConnection->CancelCompress();
+ iDbConnection->Database().AddContactToGroupL(aItemId, aGroupId);
+ }
+
+
+EXPORT_C void CPbkContactEngine::RemoveContactFromGroupL
+ (TContactItemId aItemId,
+ TContactItemId aGroupId)
+ {
+ iDbConnection->CancelCompress();
+ iDbConnection->Database().RemoveContactFromGroupL(aItemId, aGroupId);
+ }
+
+EXPORT_C CContactGroup* CPbkContactEngine::ReadContactGroupL
+ (TContactItemId aId)
+ {
+ iDbConnection->CancelCompress();
+ CContactItem* item = iDbConnection->Database().ReadContactL(aId);
+ __ASSERT_ALWAYS(item->Type() == KUidContactGroup,
+ Panic(EPanicContactNotGroup));
+ return static_cast<CContactGroup*>(item);
+ }
+
+EXPORT_C CContactGroup* CPbkContactEngine::OpenContactGroupL
+ (TContactItemId aId)
+ {
+ iDbConnection->CancelCompress();
+ CContactItem* item = iDbConnection->Database().OpenContactL(aId);
+ __ASSERT_ALWAYS(item->Type() == KUidContactGroup,
+ Panic(EPanicContactNotGroup));
+ return static_cast<CContactGroup*>(item);
+ }
+
+EXPORT_C CContactGroup* CPbkContactEngine::OpenContactGroupLCX
+ (TContactItemId aId)
+ {
+ iDbConnection->CancelCompress();
+ CContactItem* item = iDbConnection->Database().OpenContactLX(aId);
+ __ASSERT_ALWAYS(item->Type() == KUidContactGroup,
+ Panic(EPanicContactNotGroup));
+ CContactGroup* group = static_cast<CContactGroup*>(item);
+ CleanupStack::PushL(group);
+ return group;
+ }
+
+EXPORT_C void CPbkContactEngine::CommitContactGroupL
+ (CContactGroup& aGroup,
+ TBool aImmediateNotify/*=EFalse*/)
+ {
+ iDbConnection->CancelCompress();
+ iDbConnection->Database().CommitContactL(aGroup);
+
+ SendImmidiateEventToAllObservers(EContactDbObserverEventGroupChanged,
+ aGroup.Id(), aImmediateNotify);
+ }
+
+EXPORT_C TContactItemId CPbkContactEngine::DuplicateContactL(TContactItemId aId,
+ TBool aImmediateNotify/*=EFalse*/)
+ {
+ PBK_DEBUG_PRINT(
+ PBK_DEBUG_STRING(
+ "CPbkContactEngine(%x)::DuplicateContactL(aId=%d, aImmediateNotify=%d)"),
+ this, aId, aImmediateNotify);
+
+ iDbConnection->CancelCompress();
+ CContactItem* item = iDbConnection->Database().ReadContactLC(
+ aId, *iDbConnection->Database().AllFieldsView());
+ // remove all non duplicable contact information
+ RemoveNonDuplicableContactInformation(*item);
+
+ TContactItemId dupId = iDbConnection->Database().AddNewContactL(*item);
+ CleanupStack::PopAndDestroy(); // item
+
+ // Send immediate event
+ SendImmidiateEventToAllObservers(EContactDbObserverEventContactAdded,
+ dupId, aImmediateNotify);
+ return dupId;
+ }
+
+EXPORT_C void CPbkContactEngine::SetFieldAsSpeedDialL
+ (CPbkContactItem& aItem,
+ TInt aFieldIndex,
+ TInt aSpeedDialPosition)
+ {
+ iDbConnection->CancelCompress();
+ // find correct CContactItemField index
+ CContactItemField& field = aItem.CardFields()[aFieldIndex].ItemField();
+ for (TInt i = 0; i < aItem.ContactItem().CardFields().Count(); ++i)
+ {
+ if (&field == &(aItem.ContactItem().CardFields()[i]))
+ {
+ aFieldIndex = i;
+ break;
+ }
+ }
+
+ // Prepare contact for saving to the DB
+ aItem.PrepareForSaveL();
+
+ iDbConnection->Database().SetFieldAsSpeedDialL(
+ aItem.ContactItem(), aFieldIndex, aSpeedDialPosition);
+
+ // Undo PrepareForSaveL
+ aItem.PrepareAfterLoadL();
+
+ // update the aItem's field set
+ aItem.UpdateFieldSetL(*iPbkFieldsInfo);
+
+ // CContactDatabase::SetFieldAsSpeedDialL does not send notifications
+ // Send immediate event
+ SendImmidiateEventToAllObservers(EContactDbObserverEventContactChanged,
+ aItem.Id(), ETrue);
+ }
+
+EXPORT_C CContactDatabase& CPbkContactEngine::Database()
+ {
+ return iDbConnection->Database();
+ }
+
+EXPORT_C CContactViewBase& CPbkContactEngine::AllContactsView()
+ {
+ return iDbConnection->AllContactsView();
+ }
+
+EXPORT_C CContactViewBase& CPbkContactEngine::AllGroupsViewL()
+ {
+ return iDbConnection->AllGroupsViewL();
+ }
+
+EXPORT_C CContactViewBase& CPbkContactEngine::FilteredContactsViewL
+ (TInt aFilter)
+ {
+ return iDbConnection->FilteredContactsViewL(aFilter);
+ }
+
+EXPORT_C HBufC* CPbkContactEngine::GetContactTitleL
+ (const CPbkContactItem& aItem) const
+ {
+ // Delegate call to iContactNameFormatter
+ return ContactNameFormat().GetContactTitleL(aItem);
+ }
+
+EXPORT_C void CPbkContactEngine::SetCompressUi(MPbkCompressUi* aCompressUi)
+ {
+ iDbConnection->SetCompressUi(aCompressUi);
+ }
+
+EXPORT_C TBool CPbkContactEngine::CheckCompress()
+ {
+ return iDbConnection->CheckCompress();
+ }
+
+EXPORT_C void CPbkContactEngine::CompressL()
+ {
+ iDbConnection->CompressL();
+ }
+
+EXPORT_C void CPbkContactEngine::CancelCompress()
+ {
+ iDbConnection->CancelCompress();
+ }
+
+EXPORT_C void CPbkContactEngine::CheckFileSystemSpaceAndCompressL()
+ {
+ iDbConnection->CheckFileSystemSpaceAndCompressL();
+ }
+
+EXPORT_C HBufC* CPbkContactEngine::GetContactTitleOrNullL
+ (const MPbkFieldDataArray& aContactData)
+ {
+ // Delegate call to iContactNameFormatter
+ return ContactNameFormat().GetContactTitleOrNullL(aContactData);
+ }
+
+EXPORT_C TBool CPbkContactEngine::IsTitleField(TPbkFieldId aFieldId) const
+ {
+ // Delegate call to iContactNameFormatter
+ return ContactNameFormat().IsTitleField(aFieldId);
+ }
+
+EXPORT_C MPbkContactNameFormat& CPbkContactEngine::ContactNameFormat() const
+ {
+ return iDbConnection->ContactNameFormatter();
+ }
+
+EXPORT_C TContactItemId CPbkContactEngine::GetSpeedDialFieldL
+ (TInt aSpeedDialPosition,
+ TDes& aPhoneNumber) const
+ {
+ iDbConnection->CancelCompress();
+ return iDbConnection->Database().GetSpeedDialFieldL
+ (aSpeedDialPosition,aPhoneNumber);
+ }
+
+EXPORT_C void CPbkContactEngine::RemoveSpeedDialFieldL
+ (TContactItemId aContactId,
+ TInt aSpeedDialPosition)
+ {
+ iDbConnection->CancelCompress();
+ iDbConnection->Database().RemoveSpeedDialFieldL(
+ aContactId, aSpeedDialPosition);
+ }
+
+EXPORT_C TBool CPbkContactEngine::IsSpeedDialAssigned
+ (const CPbkContactItem& aItem, TInt aFieldIndex) const
+ {
+ const CContentType& contentType =
+ aItem.CardFields()[aFieldIndex].ItemField().ContentType();
+ TBool result = EFalse;
+
+ const TInt fieldtypeCount = contentType.FieldTypeCount();
+ for (TInt i = 0; i < fieldtypeCount; ++i)
+ {
+ TFieldType fieldType = contentType.FieldType(i);
+ switch (fieldType.iUid)
+ {
+ case KUidSpeedDialOneValue: // FALLTHROUGH
+ case KUidSpeedDialTwoValue: // FALLTHROUGH
+ case KUidSpeedDialThreeValue: // FALLTHROUGH
+ case KUidSpeedDialFourValue: // FALLTHROUGH
+ case KUidSpeedDialFiveValue: // FALLTHROUGH
+ case KUidSpeedDialSixValue: // FALLTHROUGH
+ case KUidSpeedDialSevenValue: // FALLTHROUGH
+ case KUidSpeedDialEightValue: // FALLTHROUGH
+ case KUidSpeedDialNineValue:
+ {
+ result = ETrue;
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+EXPORT_C CContactIdArray* CPbkContactEngine::MatchPhoneNumberL
+ (const TDesC& aNumber, const TInt aMatchLengthFromRight)
+ {
+ iDbConnection->CancelCompress();
+ return iDbConnection->Database().MatchPhoneNumberL
+ (aNumber,aMatchLengthFromRight);
+ }
+
+EXPORT_C CContactIdArray* CPbkContactEngine::FindLC
+ (const TDesC& aText,
+ const CPbkFieldIdArray* aFieldTypes/*=NULL*/)
+ {
+ iDbConnection->CancelCompress();
+ CContactItemFieldDef* fieldDef =
+ FieldsInfo().CreateContactItemFieldDefLC(aFieldTypes);
+
+ // Call contact db's FindLC
+ CContactIdArray* result = iDbConnection->Database().FindLC(aText, fieldDef);
+ CleanupStack::Pop(); // result
+
+ // Cleanup and return
+ CleanupStack::PopAndDestroy(fieldDef);
+ CleanupStack::PushL(result);
+ return result;
+ }
+
+EXPORT_C CPbkIdleFinder* CPbkContactEngine::FindAsyncL
+ (const TDesC& aText,
+ const CPbkFieldIdArray* aFieldTypes/*=NULL*/,
+ MIdleFindObserver* aObserver/*=NULL*/)
+ {
+ iDbConnection->CancelCompress();
+ CContactItemFieldDef* fieldDef =
+ FieldsInfo().CreateContactItemFieldDefLC(aFieldTypes);
+
+ // Call contact db's FindAsyncL
+ CIdleFinder* finder =
+ iDbConnection->Database().FindAsyncL(aText, fieldDef, aObserver);
+ CleanupStack::PushL(finder);
+
+ // Pack result and fieldDef array into a CPbkIdleFinder
+ CPbkIdleFinder* pbkFinder = new(ELeave) CPbkIdleFinder(finder, fieldDef);
+
+ // Cleanup and return
+ CleanupStack::Pop(2); // finder, fieldDef
+ return pbkFinder;
+ }
+
+/**
+ * Distributes CContactDatabase observer events in Phonebook.
+ */
+void CPbkContactEngine::HandleDatabaseEventL(TContactDbObserverEvent aEvent)
+ {
+ PBK_DEBUG_PRINT(
+ PBK_DEBUG_STRING(
+ "CPbkContactEngine(%x)::HandleDatabaseEventL(), type=%d, id=%d, conn=%d"),
+ this, aEvent.iType, aEvent.iContactId, aEvent.iConnectionId);
+
+ // Forward the event to all observers of this engine object
+ SendEventToAllObservers(aEvent);
+ }
+
+void CPbkContactEngine::SendEventToAllObservers
+ (const TContactDbObserverEvent& aEvent)
+ {
+ if (iObservers)
+ {
+ TInt i;
+
+ // First forward the standard event to all observers
+ for (i = iObservers->Count()-1; i >= 0; --i)
+ {
+ #ifndef _DEBUG
+ TRAP_IGNORE((*iObservers)[i]->HandleDatabaseEventL(aEvent));
+ #else
+ TRAPD(ignore, (*iObservers)[i]->HandleDatabaseEventL(aEvent));
+ if (ignore != KErrNone)
+ {
+ RDebug::Print(
+ _L("Leave %d occured in MPbkContactDbObserver(%x)::HandleDatabaseEventL()"),
+ ignore, (*iObservers)[i]);
+ }
+ #endif
+ }
+
+ // Next tell all observers that all observers have had their
+ // HandleDatabaseEventL function called.
+ for (i = iObservers->Count()-1; i >= 0; --i)
+ {
+ #ifndef _DEBUG
+ TRAP_IGNORE((*iObservers)[i]->DatabaseEventHandledL(aEvent));
+ #else
+ TRAPD(ignore, (*iObservers)[i]->DatabaseEventHandledL(aEvent));
+ if (ignore != KErrNone)
+ {
+ RDebug::Print(
+ _L("Leave %d occured in MPbkContactDbObserver(%x)::DatabaseEventHandledL()"),
+ ignore, (*iObservers)[i]);
+ }
+ #endif
+ }
+ }
+
+ PBK_DEBUG_PRINT(
+ PBK_DEBUG_STRING(
+ "CPbkContactEngine(%x)::SendEventToAllObservers() executed. type=%d, id=%d, conn=%d"),
+ this, aEvent.iType, aEvent.iContactId, aEvent.iConnectionId);
+ }
+
+void CPbkContactEngine::SendImmidiateEventToAllObservers
+ (TContactDbObserverEventType aEventType,
+ TContactItemId aContactId,
+ TBool aSendEvent)
+ {
+ if (aSendEvent)
+ {
+ TContactDbObserverEvent event;
+ event.iType = aEventType;
+ event.iContactId = aContactId;
+ event.iConnectionId = iDbConnection->Database().ConnectionId();
+ SendEventToAllObservers(event);
+ }
+ }
+
+void CPbkContactEngine::AddObserverL(MPbkContactDbObserver* aObserver)
+ {
+ // PreCond
+ __ASSERT_DEBUG(aObserver, Panic(EPanicPreCond_AddObserverL));
+
+ if (!iObservers)
+ {
+ iObservers = new(ELeave) CArrayPtrFlat<MPbkContactDbObserver>(4);
+ }
+
+ PBK_DEBUG_ONLY(const TInt old_Count=iObservers->Count());
+
+ iObservers->AppendL(aObserver);
+
+ PBK_DEBUG_PRINT(
+ PBK_DEBUG_STRING("CPbkContactEngine(%x)::AddObserverL(%x), count = %d"),
+ this, aObserver, iObservers->Count());
+
+ // PostCond
+ __ASSERT_DEBUG(iObservers->Count()==old_Count+1 &&
+ (*iObservers)[iObservers->Count()-1]==aObserver,
+ Panic(EPanicPostCond_AddObserverL));
+ }
+
+void CPbkContactEngine::RemoveObserver(MPbkContactDbObserver* aObserver)
+ {
+ // PreCond
+ __ASSERT_DEBUG(iObservers && aObserver,
+ Panic(EPanicPreCond_RemoveObserver));
+
+ const TInt count = iObservers->Count();
+ for (TInt i = 0; i < count; ++i)
+ {
+ if ((*iObservers)[i] == aObserver)
+ {
+ PBK_DEBUG_ONLY(const TInt old_Count=iObservers->Count());
+
+ iObservers->Delete(i);
+
+
+ PBK_DEBUG_PRINT(
+ PBK_DEBUG_STRING(
+ "CPbkContactEngine(%x)::RemoveObserver(%x), count = %d"),
+ this, aObserver, iObservers->Count());
+
+ // PostCond
+ __ASSERT_DEBUG(iObservers->Count()==old_Count-1,
+ Panic(EPanicPostCond_RemoveObserver));
+ return;
+ }
+ }
+
+ // Illegal state
+ __ASSERT_DEBUG(EFalse, Panic(EPanicObserverNotFoundInRemove));
+ }
+
+void CPbkContactEngine::doDeleteContactL(TContactItemId aContactId)
+ {
+ iDbConnection->CancelCompress();
+ CContactDatabase& db = iDbConnection->Database();
+ const TInt sizeBefore = db.FileSize();
+
+ iSharedDataClient->RequestFreeDiskSpaceLC(iFreeSpaceRequiredToDelete);
+ db.DeleteContactL(aContactId);
+ CleanupStack::PopAndDestroy(); // RequestFreeDiskSpaceLC
+
+ // Calculate how much database grew rounded to next kB
+ const TInt KB = 1024;
+ TInt sizeDiff = db.FileSize() - sizeBefore + KB;
+ sizeDiff -= sizeDiff % KB;
+ if (sizeDiff > iFreeSpaceRequiredToDelete)
+ {
+ // Update maximum size required
+ iFreeSpaceRequiredToDelete = sizeDiff;
+ }
+ }
+
+EXPORT_C void CPbkContactEngine::SetNameDisplayOrderL
+ (TPbkNameOrder aNameOrder)
+ {
+ // change sort order
+ iDbConnection->SetNameDisplayOrderL(aNameOrder);
+ }
+
+EXPORT_C CPbkContactEngine::TPbkNameOrder
+ CPbkContactEngine::NameDisplayOrderL()
+ {
+ // retrieve sort order from sort order manager
+ return iDbConnection->NameDisplayOrder();
+ }
+
+EXPORT_C CPbkConstants* CPbkContactEngine::Constants()
+ {
+ return iPbkConstants;
+ }
+
+const CPbkSortOrderManager& CPbkContactEngine::SortOrderManager() const
+ {
+ return iDbConnection->SortOrderManager();
+ }
+
+EXPORT_C void CPbkContactEngine::SetNameSeparatorL(TChar aSeparator)
+ {
+ iDbConnection->SetNameSeparatorL(aSeparator);
+ }
+
+EXPORT_C TChar CPbkContactEngine::NameSeparator() const
+ {
+ return iDbConnection->NameSeparator();
+ }
+
+// ==================== LOCAL FUNCTIONS ====================
+
+namespace {
+
+TBool IsFatalDbOpenError(TInt aError)
+ {
+ switch (aError)
+ {
+ case KErrNone: //FALLTHROUGH
+ case KErrCancel: //FALLTHROUGH
+ case KErrNoMemory: //FALLTHROUGH
+ case KErrDied: //FALLTHROUGH
+ case KErrInUse: //FALLTHROUGH
+ case KErrServerTerminated: //FALLTHROUGH
+ case KErrServerBusy: //FALLTHROUGH
+ case KErrNotReady: //FALLTHROUGH
+ case KErrAccessDenied: //FALLTHROUGH
+ case KErrLocked: //FALLTHROUGH
+ case KErrWrite: //FALLTHROUGH
+ case KErrDisMounted: //FALLTHROUGH
+ case KErrDiskFull: //FALLTHROUGH
+ case KErrAbort: //FALLTHROUGH
+ case KErrBadPower: //FALLTHROUGH
+ case KErrDirFull: //FALLTHROUGH
+ case KErrHardwareNotAvailable:
+ {
+ return EFalse;
+ }
+
+ // All error codes not handled above end up here, especially
+ // KErrCorrupt.
+ default:
+ {
+ return ETrue;
+ }
+ }
+ }
+
+TBool IsNonDuplicableFieldType(TFieldType aFieldType)
+ {
+ switch (aFieldType.iUid)
+ {
+ case KUidContactsVoiceDialFieldValue: //FALLTHROUGH
+ case KUidSpeedDialOneValue: //FALLTHROUGH
+ case KUidSpeedDialTwoValue: //FALLTHROUGH
+ case KUidSpeedDialThreeValue: //FALLTHROUGH
+ case KUidSpeedDialFourValue: //FALLTHROUGH
+ case KUidSpeedDialFiveValue: //FALLTHROUGH
+ case KUidSpeedDialSixValue: //FALLTHROUGH
+ case KUidSpeedDialSevenValue: //FALLTHROUGH
+ case KUidSpeedDialEightValue: //FALLTHROUGH
+ case KUidSpeedDialNineValue:
+ {
+ return ETrue;
+ }
+
+ default:
+ {
+ return EFalse;
+ }
+ }
+ }
+
+void RemoveNonDuplicableContactInformation(CContactItem& aContactItem)
+ {
+ // Remove all non duplicable field types from all fields
+ const TInt fieldCount = aContactItem.CardFields().Count();
+ for (TInt fieldIndex = 0; fieldIndex < fieldCount; ++fieldIndex)
+ {
+ CContactItemField& field = aContactItem.CardFields()[fieldIndex];
+ const CContentType& contentType = field.ContentType();
+ TBool typeRemoved;
+ do
+ {
+ typeRemoved = EFalse;
+ const TInt typeCount = contentType.FieldTypeCount();
+ for (TInt typeIndex = 0; typeIndex < typeCount; ++typeIndex)
+ {
+ const TFieldType type = contentType.FieldType(typeIndex);
+ if (IsNonDuplicableFieldType(type))
+ {
+ field.RemoveFieldType(type);
+ typeRemoved = ETrue;
+ break;
+ }
+ }
+ }
+ while (typeRemoved);
+ }
+ }
+
+} // namespace
+
+// End of File