/*
* 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