phonebookengines/VirtualPhonebook/VPbkCntModel/src/CSpeedDialAttributeOperation.cpp
changeset 0 e686773b3f54
--- /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 <CVPbkSpeedDialAttribute.h>
+
+#include <MVPbkStoreContactField.h>
+#include <MVPbkContactAttributeManager.h>
+#include <MVPbkContactAttribute.h>
+#include <CVPbkAsyncOperation.h>
+#include <CVPbkAsyncCallback.h>
+#include <CVPbkContactManager.h>
+#include <MVPbkContactStoreList.h>
+#include <VPbkStoreUriLiterals.h>
+#include <TVPbkContactStoreUriPtr.h>
+#include <MVPbkContactFindObserver.h>
+#include <CVPbkContactLinkArray.h>
+#include <CVPbkBatchOperation.h>
+
+// From Contacts Model
+#include <cntitem.h>
+
+// Debug includes
+#include <VPbkDebug.h>
+
+#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<CVPbkSpeedDialAttribute*>(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<CContact&>(iField->ParentContact());
+        TContactField& field = static_cast<TContactField&>(*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<KSpeedDialPhoneLength> 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<KSpeedDialPhoneLength> 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