diff -r 000000000000 -r e686773b3f54 phonebookengines/VirtualPhonebook/VPbkCntModel/src/CSpeedDialAttributeOperation.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/phonebookengines/VirtualPhonebook/VPbkCntModel/src/CSpeedDialAttributeOperation.cpp Tue Feb 02 10:12:17 2010 +0200 @@ -0,0 +1,555 @@ +/* +* Copyright (c) 2005-2007 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: A operation class for setting/getting speeddial information +* +*/ + + +#include "CSpeedDialAttributeOperation.h" +#include "CContactStore.h" +#include "TContactField.h" +#include "CContact.h" +#include "CContactLink.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// From Contacts Model +#include + +// Debug includes +#include + +#ifdef _DEBUG +namespace { + enum TPanic + { + EPreCond_FindSpeedDialsL, + EPreCond_FindSpeedDialL + }; + + void Panic(TPanic aPanic) + { + _LIT(KPanicCat, "CSpeedDialAttributeOperation"); + User::Panic(KPanicCat, aPanic); + } +} +#endif // _DEBUG + +namespace VPbkCntModel { + +const TInt KMinPhoneNumberBufLength = 50; +const TInt KMaxPhoneNumberBufLength = 200; + +static const TInt speedDialUids[] = + {0, // to make this array 1-based + KUidSpeedDialOneValue, + KUidSpeedDialTwoValue, + KUidSpeedDialThreeValue, + KUidSpeedDialFourValue, + KUidSpeedDialFiveValue, + KUidSpeedDialSixValue, + KUidSpeedDialSevenValue, + KUidSpeedDialEightValue, + KUidSpeedDialNineValue}; + +// --------------------------------------------------------------------------- +// CSpeedDialAttributeOperation::CSpeedDialAttributeOperation +// --------------------------------------------------------------------------- +// +CSpeedDialAttributeOperation::CSpeedDialAttributeOperation( + TOperationMode aOperationMode, + CContactStore& aContactStore, + MVPbkStoreContactField& aField, + MVPbkSetAttributeObserver& aObserver) : + iOperationMode(aOperationMode), + iContactStore(aContactStore), + iField(&aField), + iSetObserver(&aObserver) + { + } + +// --------------------------------------------------------------------------- +// CSpeedDialAttributeOperation::CSpeedDialAttributeOperation +// --------------------------------------------------------------------------- +// +CSpeedDialAttributeOperation::CSpeedDialAttributeOperation( + TOperationMode aOperationMode, + CContactStore& aContactStore, + MVPbkContactFindObserver& aObserver) : + iOperationMode(aOperationMode), + iContactStore(aContactStore), + iFindObserver(&aObserver) + { + } + +// --------------------------------------------------------------------------- +// CSpeedDialAttributeOperation::ConstructL +// --------------------------------------------------------------------------- +// +void CSpeedDialAttributeOperation::ConstructL( + const CVPbkSpeedDialAttribute& aAttribute) + { + iAsyncOperation = new(ELeave) VPbkEngUtils::CVPbkAsyncOperation; + iAttribute = static_cast(aAttribute.CloneLC()); + CleanupStack::Pop(); + } + +// --------------------------------------------------------------------------- +// CSpeedDialAttributeOperation::NewSetLC +// --------------------------------------------------------------------------- +// +CSpeedDialAttributeOperation* CSpeedDialAttributeOperation::NewSetLC( + CContactStore& aContactStore, + MVPbkStoreContactField& aField, + const CVPbkSpeedDialAttribute& aAttribute, + MVPbkSetAttributeObserver& aObserver) + { + CSpeedDialAttributeOperation* self = new(ELeave) CSpeedDialAttributeOperation( + ESet, aContactStore, aField, aObserver); + CleanupStack::PushL(self); + self->ConstructL(aAttribute); + return self; + } + +// --------------------------------------------------------------------------- +// CSpeedDialAttributeOperation::NewRemoveLC +// --------------------------------------------------------------------------- +// +CSpeedDialAttributeOperation* CSpeedDialAttributeOperation::NewRemoveLC( + CContactStore& aContactStore, + MVPbkStoreContactField& aField, + const CVPbkSpeedDialAttribute& aAttribute, + MVPbkSetAttributeObserver& aObserver) + { + CSpeedDialAttributeOperation* self = new(ELeave) CSpeedDialAttributeOperation( + ERemove, aContactStore, aField, aObserver); + CleanupStack::PushL(self); + self->ConstructL(aAttribute); + return self; + } + +// --------------------------------------------------------------------------- +// CSpeedDialAttributeOperation::NewListLC +// --------------------------------------------------------------------------- +// +CSpeedDialAttributeOperation* CSpeedDialAttributeOperation::NewListLC( + CContactStore& aContactStore, + const CVPbkSpeedDialAttribute& aAttribute, + MVPbkContactFindObserver& aObserver) + { + CSpeedDialAttributeOperation* self = new(ELeave) CSpeedDialAttributeOperation( + EList, aContactStore, aObserver); + CleanupStack::PushL(self); + self->ConstructL(aAttribute); + return self; + } + +// --------------------------------------------------------------------------- +// CSpeedDialAttributeOperation::~CSpeedDialAttributeOperation +// --------------------------------------------------------------------------- +// +CSpeedDialAttributeOperation::~CSpeedDialAttributeOperation() + { + delete iAsyncOperation; + delete iAttribute; + delete iLinkArray; + delete iEmptyOperation; + } + +// --------------------------------------------------------------------------- +// From class MVPbkContactOperation +// CSpeedDialAttributeOperation::StartL +// --------------------------------------------------------------------------- +// +void CSpeedDialAttributeOperation::StartL() + { + if (iOperationMode == EList) + { + VPbkEngUtils::MAsyncCallback* callback = + VPbkEngUtils::CreateAsyncCallbackLC( + *this, + &CSpeedDialAttributeOperation::DoListOperationL, + &CSpeedDialAttributeOperation::ListOperationError, + *iFindObserver); + iAsyncOperation->CallbackL(callback); + CleanupStack::Pop(callback); + } + else + { + VPbkEngUtils::MAsyncCallback* callback = + VPbkEngUtils::CreateAsyncCallbackLC( + *this, + &CSpeedDialAttributeOperation::DoSetOperationL, + &CSpeedDialAttributeOperation::SetOperationError, + *iSetObserver); + iAsyncOperation->CallbackL(callback); + CleanupStack::Pop(callback); + } + } + +// --------------------------------------------------------------------------- +// From class MVPbkContactOperation +// CSpeedDialAttributeOperation::Cancel +// --------------------------------------------------------------------------- +// +void CSpeedDialAttributeOperation::Cancel() + { + iAsyncOperation->Purge(); + } + +// --------------------------------------------------------------------------- +// From class MVPbkBatchOperationObserver +// CSpeedDialAttributeOperation::StepComplete +// --------------------------------------------------------------------------- +// +void CSpeedDialAttributeOperation::StepComplete( + MVPbkContactOperationBase& /*aOperation*/, + TInt /*aStepSize*/ ) + { + // Do nothing + } + +// --------------------------------------------------------------------------- +// From class MVPbkBatchOperationObserver +// CSpeedDialAttributeOperation::StepFailed +// --------------------------------------------------------------------------- +// +TBool CSpeedDialAttributeOperation::StepFailed( + MVPbkContactOperationBase& /*aOperation*/, + TInt /*aStepSize*/, + TInt /*aError*/ ) + { + // Do not continue batch operation. + return EFalse; + } + +// --------------------------------------------------------------------------- +// From class MVPbkBatchOperationObserver +// CSpeedDialAttributeOperation::OperationComplete +// --------------------------------------------------------------------------- +// +void CSpeedDialAttributeOperation::OperationComplete + ( MVPbkContactOperationBase& /*aOperation*/ ) + { + TRAPD( error, HandleOperationCompleteL() ); + if ( error != KErrNone ) + { + // If error has occured, we don't continue. + iFindObserver->FindFailed( error ); + } + } + +// --------------------------------------------------------------------------- +// CSpeedDialAttributeOperation::HandleOperationCompleteL() +// --------------------------------------------------------------------------- +// +void CSpeedDialAttributeOperation::HandleOperationCompleteL() + { + if ( iAttribute->Index() == + CVPbkSpeedDialAttribute::KSpeedDialIndexNotDefined ) + { + // Find all + FindSpeedDialsL(); + } + else + { + // Find specified + FindSpeedDialL(); + } + } + +// --------------------------------------------------------------------------- +// CSpeedDialAttributeOperation::DoSetOperationL +// --------------------------------------------------------------------------- +// +void CSpeedDialAttributeOperation::DoSetOperationL( + MVPbkSetAttributeObserver& aObserver) + { + if (&iField->ContactStore() == &iContactStore) + { + CContact& contact = static_cast(iField->ParentContact()); + TContactField& field = static_cast(*iField); + + if (iOperationMode == ESet) + { + TContactItemId cid = contact.NativeContact()->Id(); + const TInt nativeFieldIndex = field.NativeFieldIndex(); + + iContactStore.NativeDatabase().SetFieldAsSpeedDialL( + *contact.NativeContact(), + nativeFieldIndex, + iAttribute->Index()); + + // SetFieldAsSpeedDialL commits the contact, so we want to load it again + CContactItem* contactItem = iContactStore.NativeDatabase().OpenContactL(cid); + contact.SetContact(contactItem); + // This is called because we want the parent contact's field collection + // iCurrentField to be refreshed to point again to this field + contact.Fields().FieldAt(nativeFieldIndex); + } + else if (iOperationMode == ERemove) + { + if (iAttribute->Index() == CVPbkSpeedDialAttribute::KSpeedDialIndexNotDefined) + { + for (TInt i = 1; i <= KCntMaxSpeedDialIndex; ++i) + { + TBuf phoneNumber; + TContactItemId cid = + iContactStore.NativeDatabase().GetSpeedDialFieldL(i, phoneNumber); + + if (cid == contact.NativeContact()->Id() && + field.NativeField()->ContentType().ContainsFieldType( + TFieldType::Uid(speedDialUids[i]))) + { + iContactStore.NativeDatabase().CommitContactL( + *contact.NativeContact()); + + iContactStore.NativeDatabase().RemoveSpeedDialFieldL( + contact.NativeContact()->Id(), + i); + + const TInt fieldIndex = NativeFieldIndex(contact, field); + // RemoveSpeedDialFieldL commits the contact, so we want to + // load it again + CContactItem* contactItem = + iContactStore.NativeDatabase().OpenContactL(cid); + contact.SetContact(contactItem); + // This is called because we want the parent contact's field + // collection iCurrentField to be refreshed to point again + // to this field + contact.Fields().FieldAt(fieldIndex); + } + } + } + else + { + const TInt index( iAttribute->Index() ); + TBuf phoneNumber; + TContactItemId cid = + iContactStore.NativeDatabase().GetSpeedDialFieldL( + index, phoneNumber); + + if ( cid == contact.NativeContact()->Id() ) + { + iContactStore.NativeDatabase().CommitContactL(*contact.NativeContact()); + + iContactStore.NativeDatabase().RemoveSpeedDialFieldL( cid, index ); + + const TInt fieldIndex = NativeFieldIndex(contact, field); + // RemoveSpeedDialFieldL commits the contact, so we want to load it again + CContactItem* contactItem = iContactStore.NativeDatabase().OpenContactL(cid); + contact.SetContact(contactItem); + // This is called because we want the parent contact's field collection + // iCurrentField to be refreshed to point again to this field + contact.Fields().FieldAt(fieldIndex); + } + else + { + User::Leave( KErrArgument ); + } + } + } + } + + aObserver.AttributeOperationComplete(*this); + } + +// --------------------------------------------------------------------------- +// CSpeedDialAttributeOperation::SetOperationError +// --------------------------------------------------------------------------- +// +void CSpeedDialAttributeOperation::SetOperationError( + MVPbkSetAttributeObserver& aObserver, + TInt aError) + { + aObserver.AttributeOperationFailed(*this, aError); + } + +// --------------------------------------------------------------------------- +// CSpeedDialAttributeOperation::DoListOperationL +// --------------------------------------------------------------------------- +// +void CSpeedDialAttributeOperation::DoListOperationL( + MVPbkContactFindObserver& /*aObserver*/) + { + VPBK_DEBUG_PRINT( VPBK_DEBUG_STRING( + "CSpeedDialAttributeOperation::DoListOperationL" ) ); + + if ( iEmptyOperation ) + { + delete iEmptyOperation; + iEmptyOperation = NULL; + } + + if ( iLinkArray ) + { + delete iLinkArray; + iLinkArray = NULL; + } + + iEmptyOperation = CVPbkBatchOperation::NewLC( *this ); + CleanupStack::Pop( iEmptyOperation ); + iEmptyOperation->StartL(); + + VPBK_DEBUG_PRINT( VPBK_DEBUG_STRING( + "CSpeedDialAttributeOperation::DoListOperationL end" ) ); + } + +// --------------------------------------------------------------------------- +// CSpeedDialAttributeOperation::ListOperationError +// --------------------------------------------------------------------------- +// +void CSpeedDialAttributeOperation::ListOperationError( + MVPbkContactFindObserver& aObserver, + TInt aError) + { + aObserver.FindFailed(aError); + } + +// --------------------------------------------------------------------------- +// CSpeedDialAttributeOperation::NativeFieldIndex +// --------------------------------------------------------------------------- +// +TInt CSpeedDialAttributeOperation::NativeFieldIndex( CContact& aContact, + TContactField& aField ) const + { + TInt result = KErrNotFound; + + CContactItemFieldSet& fields = aContact.NativeContact()->CardFields(); + const TInt count = fields.Count(); + for (TInt i = 0; i < count; ++i) + { + if (&fields[i] == aField.NativeField()) + { + result = i; + break; + } + } + + return result; + } + +// --------------------------------------------------------------------------- +// CSpeedDialAttributeOperation::FindSpeedDialsL +// Find all contacst that have speed dial +// --------------------------------------------------------------------------- +// +void CSpeedDialAttributeOperation::FindSpeedDialsL() + { + __ASSERT_DEBUG( iAttribute->Index() == + CVPbkSpeedDialAttribute::KSpeedDialIndexNotDefined, + Panic( EPreCond_FindSpeedDialsL ) ); + + // Symbian GetSpeedDialFieldL documentation defines these + const TInt firstSpeedDialIndex = 1; + const TInt lastSpeedDialIndex = 9; + + CVPbkContactLinkArray* results = CVPbkContactLinkArray::NewLC(); + for ( TInt i = firstSpeedDialIndex; i <= lastSpeedDialIndex; ++i ) + { + CContactLink* link = DoFindSpeedDialLC( i ); + if ( link ) + { + results->AppendL( link ); + CleanupStack::Pop( link ); + } + } + CleanupStack::Pop( results ); + iFindObserver->FindCompleteL( results ); + } + +// --------------------------------------------------------------------------- +// CSpeedDialAttributeOperation::FindSpeedDialL +// Find contact for specified speed dial index +// --------------------------------------------------------------------------- +// +void CSpeedDialAttributeOperation::FindSpeedDialL() + { + __ASSERT_DEBUG( iAttribute->Index() != + CVPbkSpeedDialAttribute::KSpeedDialIndexNotDefined, + Panic( EPreCond_FindSpeedDialL ) ); + + CVPbkContactLinkArray* results = CVPbkContactLinkArray::NewLC(); + CContactLink* link = DoFindSpeedDialLC( iAttribute->Index() ); + if ( link ) + { + results->AppendL( link ); + CleanupStack::Pop( link ); + } + CleanupStack::Pop( results ); + iFindObserver->FindCompleteL( results ); + } + +// --------------------------------------------------------------------------- +// CSpeedDialAttributeOperation::DoFindSpeedDialLC +// Returns a link if speed dial was set, otherwise NULL (not in CleanupStack) +// --------------------------------------------------------------------------- +// +CContactLink* CSpeedDialAttributeOperation::DoFindSpeedDialLC( TInt aIndex ) + { + VPBK_DEBUG_PRINT( VPBK_DEBUG_STRING( + "CSpeedDialAttributeOperation::FindSpeedDialL index %d)" ), aIndex ); + + const TInt doubleFactor = 2; + TInt bufSize = KMinPhoneNumberBufLength; + TContactItemId cid = KNullContactId; + TBool speedDialFound = EFalse; + // Contacts model responds with KErrOverflow if the buffer is too small + // Grow the buffer until it's big enough. + do + { + HBufC* tmp = HBufC::NewLC( bufSize ); + TPtr tmpPtr( tmp->Des() ); + // Get native contact id from Contacts Model + cid = iContactStore.NativeDatabase().GetSpeedDialFieldL( aIndex, + tmpPtr ); + if ( cid == KErrOverflow ) + { + // Double the size of the buffer + bufSize *= doubleFactor; + } + else if ( tmpPtr.Length() > 0 ) + { + // Symbian documentation says that if the speed dial hasn't been + // set then tmpPtr should be KNullDesC + speedDialFound = ETrue; + } + CleanupStack::PopAndDestroy( tmp ); + } + while ( ( cid == KErrOverflow ) && ( bufSize <= KMaxPhoneNumberBufLength ) ); + + CContactLink* result = NULL; + if ( speedDialFound ) + { + result = CContactLink::NewLC( iContactStore, cid ); + } + + return result; + } +} // namespace VPbkCntModel + +// End of File