phonebookengines/VirtualPhonebook/VPbkEng/src/CVPbkCopyContactsOperation.cpp
changeset 0 e686773b3f54
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookengines/VirtualPhonebook/VPbkEng/src/CVPbkCopyContactsOperation.cpp	Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,475 @@
+/*
+* 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:  Copy contacts operation
+*
+*/
+
+
+#include "CVPbkCopyContactsOperation.h"
+
+#include <MVPbkBatchOperationObserver.h>
+#include <MVPbkStoreContactFieldCollection.h>
+#include <MVPbkStoreContactField.h>
+#include <MVPbkStoreContact.h>
+#include <MVPbkContactStore.h>
+#include <MVPbkContactFieldData.h>
+#include <MVPbkFieldType.h>
+#include <CVPbkContactManager.h>
+#include <MVPbkContactStoreProperties.h>
+#include <MVPbkContactLinkArray.h>
+#include <MVPbkContactLink.h>
+#include <CVPbkContactCopyPolicyManager.h>
+#include <MVPbkContactCopyPolicy.h>
+#include <MVPbkContactOperationBase.h>
+#include <CVPbkContactCopier.h>
+#include <CVPbkContactDuplicatePolicy.h>
+
+namespace {
+
+const TInt KOneStep = 1;
+const TInt KDuplicatesToFind = 1;
+
+TInt CurNumberOfField( MVPbkStoreContact& aContact,
+        const MVPbkFieldType& aFieldType )
+    {
+    MVPbkStoreContactFieldCollection& fields = aContact.Fields();
+    TInt res = 0;
+    const TInt count = fields.FieldCount();
+    for (TInt i = 0; i < count; ++i)
+        {
+        const MVPbkFieldType* type = fields.FieldAt(i).BestMatchingFieldType();
+        if (type && type->IsSame(aFieldType))
+            {
+            ++res;
+            }
+        }
+    return res;
+    }
+}
+
+CVPbkCopyContactsOperation::CVPbkCopyContactsOperation(
+        CVPbkContactManager& aContactManager,
+        const MVPbkContactLinkArray& aLinks,
+        MVPbkContactStore* aTargetStore,
+        CVPbkContactLinkArray* aCopiedContactLinks,
+        MVPbkBatchOperationObserver& aObserver)
+        :   CActive( EPriorityStandard ),
+            iContactManager( aContactManager ),
+            iLinks( aLinks ),
+            iTargetStore( aTargetStore ),
+            iCopiedContactLinks( aCopiedContactLinks ),
+            iObserver( aObserver ),
+            iState( ERetrieveNextContact )
+    {
+    CActiveScheduler::Add(this);
+    }
+
+inline void CVPbkCopyContactsOperation::ConstructL( TUint32 aCopyContactFlags )
+    {
+    // If client gave NULL target store then contacts are duplicated
+    if ( !iTargetStore )
+        {
+        iDuplicateContacts = ETrue;
+        }
+
+    SetTargetStoreL();
+
+    const TUint32 copyPolicyFlags =
+        CVPbkContactCopier::EVPbkUseStoreSpecificCopyPolicy |
+        CVPbkContactCopier::EVPbkUsePlatformSpecificDuplicatePolicy;
+    const TUint32 duplicatePolicyFlags =
+        CVPbkContactCopier::EVPbkUsePlatformSpecificDuplicatePolicy;
+
+    // Check if copy policy is needed
+    if ( aCopyContactFlags & copyPolicyFlags )
+        {
+        iCopyPolicyManager = CVPbkContactCopyPolicyManager::NewL();
+        if ( iTargetStore )
+            {
+            iCopyPolicy = iCopyPolicyManager->GetPolicyL( iContactManager,
+                iTargetStore->StoreProperties().Uri() );
+            }
+        }
+
+    // Check if duplicate policy is needed
+    if ( aCopyContactFlags & duplicatePolicyFlags && iCopyPolicy &&
+         iCopyPolicy->SupportsContactMerge() )
+        {
+        CVPbkContactDuplicatePolicy::TParam param( iContactManager );
+        TRAPD( res, iDuplicatePolicy = CVPbkContactDuplicatePolicy::NewL( param ));
+        // Don't leave if duplicate policy is not found -> duplicate checking
+        // is not used.
+        if ( res != KErrNone && res != KErrNotFound )
+            {
+            User::LeaveIfError( res );
+            }
+        }
+    }
+
+CVPbkCopyContactsOperation* CVPbkCopyContactsOperation::NewLC(
+        TUint32 aCopyContactFlags,
+        CVPbkContactManager& aContactManager,
+        const MVPbkContactLinkArray& aLinks,
+        MVPbkContactStore* aTargetStore,
+        CVPbkContactLinkArray* aCopiedContactLinks,
+        MVPbkBatchOperationObserver& aObserver)
+    {
+    CVPbkCopyContactsOperation* self = new(ELeave) CVPbkCopyContactsOperation(
+            aContactManager,
+            aLinks,
+            aTargetStore,
+            aCopiedContactLinks,
+            aObserver);
+    CleanupStack::PushL(self);
+    self->ConstructL( aCopyContactFlags );
+    return self;
+    }
+
+CVPbkCopyContactsOperation::~CVPbkCopyContactsOperation()
+    {
+    Cancel();
+    delete iDuplicatePolicy;
+    delete iCopyPolicyManager;
+    delete iStoreContact;
+    delete iOperation;
+    iDuplicates.ResetAndDestroy();
+    iSourceContactsForMerge.ResetAndDestroy();
+    }
+
+void CVPbkCopyContactsOperation::DoCancel()
+    {
+    }
+
+void CVPbkCopyContactsOperation::RunL()
+    {
+    switch (iState)
+        {
+        case ERetrieveNextContact:
+            {
+            RetrieveNextContactL();
+            break;
+            }
+        case EDefaultCopy:
+            {
+            DefaultCopyL();
+            break;
+            }
+        case ECopyUsingPolicy:
+            {
+            CopyUsingPolicyL();
+            break;
+            }
+        case EFindDuplicates:
+            {
+            FindDuplicatesL();
+            break;
+            }
+        case EComplete:
+            {
+            iObserver.OperationComplete(*this);
+            break;
+            }
+        }
+    }
+
+TInt CVPbkCopyContactsOperation::RunError(TInt aError)
+    {
+    ContinueAfterFailure( aError );
+    return KErrNone;
+    }
+
+void CVPbkCopyContactsOperation::StartL()
+    {
+    IssueRequest();
+    }
+
+void CVPbkCopyContactsOperation::Cancel()
+    {
+    CActive::Cancel();
+    }
+
+void CVPbkCopyContactsOperation::VPbkSingleContactOperationComplete(
+        MVPbkContactOperationBase& /*aOperation*/,
+        MVPbkStoreContact* aContact)
+    {
+    delete iOperation;
+    iOperation = NULL;
+    delete iStoreContact;
+    iStoreContact = aContact;
+
+    // Default action is own copy logic
+    iState = EDefaultCopy;
+    if ( iDuplicatePolicy && iCopyPolicy )
+        {
+        // But if the duplicate policy exists it's done before copying
+        iState = EFindDuplicates;
+        }
+    else if ( iCopyPolicy )
+        {
+        // Duplicate checking was not defined but copy policy was.
+        // Make more advanced copy using the policy
+        iState = ECopyUsingPolicy;
+        }
+    IssueRequest();
+    }
+
+void CVPbkCopyContactsOperation::VPbkSingleContactOperationFailed(
+        MVPbkContactOperationBase& /*aOperation*/,
+        TInt aError)
+    {
+    delete iOperation;
+    iOperation = NULL;
+
+    ContinueAfterFailure( aError );
+    }
+
+void CVPbkCopyContactsOperation::ContactsSaved(
+        MVPbkContactOperationBase& aOperation,
+        MVPbkContactLinkArray* aResults)
+    {
+    delete iOperation;
+    iOperation = NULL;
+    delete iStoreContact;
+    iStoreContact = NULL;
+
+    TRAPD( res,
+        {
+        CleanupDeletePushL( aResults );
+        AppendResultsL( *aResults );
+        CleanupStack::PopAndDestroy(); // aResults
+        });
+
+    if ( res == KErrNone )
+        {
+        // One contact copied, notify observer and start retrieve next contact.
+        iObserver.StepComplete( *this, KOneStep );
+
+        iState = ERetrieveNextContact;
+        IssueRequest();
+        }
+    else
+        {
+        ContactsSavingFailed( aOperation, res );
+        }
+    }
+
+void CVPbkCopyContactsOperation::ContactsSavingFailed(
+        MVPbkContactOperationBase& /*aOperation*/,
+        TInt aError)
+    {
+    ContinueAfterFailure( aError );
+    }
+
+void CVPbkCopyContactsOperation::ContactOperationCompleted(
+        TContactOpResult aResult )
+    {
+    // Default copy successfully done -> continue with next contact
+    delete iOperation;
+    iOperation = NULL;
+
+    TRAPD( res,
+        {
+        if ( iCopiedContactLinks )
+            {
+            iCopiedContactLinks->AppendL( iStoreContact->CreateLinkLC() );
+            CleanupStack::Pop(); // link
+            }
+        });
+
+    if ( res == KErrNone )
+        {
+        iObserver.StepComplete( *this, KOneStep );
+        iState = ERetrieveNextContact;
+        IssueRequest();
+        }
+    else
+        {
+        ContactOperationFailed( aResult.iOpCode, res, EFalse );
+        }
+    }
+
+void CVPbkCopyContactsOperation::ContactOperationFailed( TContactOp /*aOpCode*/,
+        TInt aErrorCode, TBool /*aErrorNotified*/ )
+    {
+    // Default copy failed -> send step failed and continue with next contact
+    ContinueAfterFailure( aErrorCode );
+    }
+
+void CVPbkCopyContactsOperation::FindCompleteL( MVPbkContactLinkArray* aResults )
+    {
+    delete aResults;
+    delete iOperation;
+    iOperation = NULL;
+
+    if ( iDuplicates.Count() > 0 )
+        {
+        // Merge iStoreContact to the duplicate.
+        iSourceContactsForMerge.ResetAndDestroy();
+        /// Ownership of the iStoreContact changes
+        iSourceContactsForMerge.AppendL( iStoreContact );
+        iStoreContact = NULL;
+        iOperation = iCopyPolicy->MergeAndSaveContactsL(
+            iSourceContactsForMerge, *iDuplicates[0], *this );
+        }
+    else
+        {
+        // No duplicates found -> use copy policy to copy contact
+        iState = ECopyUsingPolicy;
+        IssueRequest();
+        }
+    }
+
+void CVPbkCopyContactsOperation::FindFailed( TInt aError )
+    {
+    ContinueAfterFailure( aError );
+    }
+
+void CVPbkCopyContactsOperation::IssueRequest()
+    {
+    TRequestStatus* status = &iStatus;
+    User::RequestComplete(status, KErrNone);
+    SetActive();
+    }
+
+void CVPbkCopyContactsOperation::SetTargetStoreL()
+    {
+    if ( iDuplicateContacts && iCurrentLinkIndex < iLinks.Count() )
+        {
+        // if duplicates are created then set the store to the store of the
+        // current link
+        iTargetStore = &iLinks.At( iCurrentLinkIndex ).ContactStore();
+        if ( iTargetStore && iCopyPolicyManager )
+            {
+            iCopyPolicy = iCopyPolicyManager->GetPolicyL( iContactManager,
+                    iTargetStore->StoreProperties().Uri() );
+            }
+        }
+    }
+
+void CVPbkCopyContactsOperation::RetrieveNextContactL()
+    {
+    // In duplicate mode target store is same as source store
+    // so this needs to be checked every time
+    SetTargetStoreL();
+
+    delete iStoreContact;
+    iStoreContact = NULL;
+
+    if ( iCurrentLinkIndex < iLinks.Count() )
+        {
+        iOperation = iContactManager.RetrieveContactL(
+                iLinks.At( iCurrentLinkIndex++ ), *this);
+        }
+    else
+        {
+        iState = EComplete;
+        IssueRequest();
+        }
+    }
+
+void CVPbkCopyContactsOperation::DefaultCopyL()
+    {
+    // Own simple copy logic. Copy the field if the target supports it and
+    // store contact has space for the new field.
+    // Copy labels if target field supports label.
+    const MVPbkContactStoreProperties& props = iTargetStore->StoreProperties();
+    const MVPbkFieldTypeList& supportedFields = props.SupportedFields();
+    MVPbkStoreContact* newContact = iTargetStore->CreateNewContactLC();
+    MVPbkStoreContactFieldCollection& fields = iStoreContact->Fields();
+    const TInt fieldCount = fields.FieldCount();
+    for (TInt i = 0; i < fieldCount; ++i)
+        {
+        MVPbkStoreContactField& field = fields.FieldAt(i);
+        const MVPbkFieldType* fieldType = field.BestMatchingFieldType();
+        if (fieldType && supportedFields.ContainsSame(*fieldType))
+            {
+            TInt maxNumber = newContact->MaxNumberOfFieldL(*fieldType);
+            if (maxNumber == KVPbkStoreContactUnlimitedNumber ||
+                CurNumberOfField(*newContact, *fieldType) < maxNumber)
+                {
+                MVPbkStoreContactField* newField =
+                    newContact->CreateFieldLC(*fieldType);
+                TPtrC label(field.FieldLabel());
+                if (newField->SupportsLabel() &&
+                    label.Length() > 0)
+                    {
+                    newField->SetFieldLabelL(label);
+                    }
+                newField->FieldData().CopyL(field.FieldData());
+                newContact->AddFieldL(newField);
+                CleanupStack::Pop(); // newField
+                }
+            }
+        }
+
+    if ( newContact->Fields().FieldCount() > 0 )
+        {
+        // Save the new contact if fields were copied
+        delete iStoreContact;
+        iStoreContact = newContact;
+        CleanupStack::Pop(); // newContact
+        iStoreContact->CommitL( *this );
+        }
+    else
+        {
+        // No fields were copied -> Continue with next contact.
+        CleanupStack::PopAndDestroy(); // newContact
+        // Return success.
+        iObserver.StepComplete( *this, KOneStep );
+        iState = ERetrieveNextContact;
+        IssueRequest();
+        }
+    }
+
+void CVPbkCopyContactsOperation::CopyUsingPolicyL()
+    {
+    iOperation = iCopyPolicy->CopyContactL( *iStoreContact, *iTargetStore,
+        *this );
+    }
+
+void CVPbkCopyContactsOperation::FindDuplicatesL()
+    {
+    iDuplicates.ResetAndDestroy();
+    iOperation = iDuplicatePolicy->FindDuplicatesL( *iStoreContact,
+        *iTargetStore, iDuplicates, *this, KDuplicatesToFind );
+    }
+
+void CVPbkCopyContactsOperation::ContinueAfterFailure( TInt aError )
+    {
+    delete iOperation;
+    iOperation = NULL;
+
+    iState = EComplete;
+    if ( iObserver.StepFailed( *this, KOneStep, aError ) )
+        {
+        // Continue only if ETrue is answered. This operation might be deleted
+        // if EFalse is answered.
+        iState = ERetrieveNextContact;
+        IssueRequest();
+        }
+    }
+
+void CVPbkCopyContactsOperation::AppendResultsL( MVPbkContactLinkArray& aLinks )
+    {
+    if ( iCopiedContactLinks )
+        {
+        const TInt count = aLinks.Count();
+        for ( TInt i = 0; i < count; ++i )
+            {
+            iCopiedContactLinks->AppendL( aLinks.At(i).CloneLC() );
+            CleanupStack::Pop(); // link
+            }
+        }
+    }
+// End of File