phonebookui/Phonebook2/CommandsExtension/src/CPbk2MergeContactsCmd.cpp
branchRCL_3
changeset 63 f4a778e096c2
child 64 c1e8ba0c2b16
child 68 9da50d567e3c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookui/Phonebook2/CommandsExtension/src/CPbk2MergeContactsCmd.cpp	Wed Sep 01 12:29:52 2010 +0100
@@ -0,0 +1,1505 @@
+/*
+* Copyright (c) 2009 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:  Phonebook 2 merge contacts command.
+*
+*/
+
+
+// INCLUDE FILES
+
+//Phonebook2
+#include "CPbk2MergeContactsCmd.h"
+#include "CPbk2MergeResolver.h"
+#include <MPbk2CommandObserver.h>
+#include <MPbk2ContactUiControl.h>
+#include <MPbk2ApplicationServices.h>
+#include <MPbk2AppUi.h>
+#include <MPbk2DialogEliminator.h>
+#include <MPbk2ContactLinkIterator.h>
+#include <CPbk2FetchDlg.h>
+#include <CPbk2ContactViewBuilder.h>
+#include <CVPbkFilteredContactView.h>
+#include <CPbk2ApplicationServices.h>
+#include <CPbk2PresentationContact.h>
+#include <CPbk2FieldPropertyArray.h>
+#include <MPbk2ContactViewSupplier.h>
+#include <CPbk2StoreConfiguration.h>
+#include <CPbk2StorePropertyArray.h>
+#include <CPbk2StoreProperty.h>
+#include <Pbk2StoreProperty.hrh>
+#include <Pbk2ProcessDecoratorFactory.h>
+#include <MPbk2ContactNameFormatter.h>
+
+#include <CPbk2MergeConflictsDlg.h>
+#include <CPbk2MergePhotoConflictDlg.h>
+
+#include <Pbk2UIControls.rsg> 
+#include <Pbk2CmdExtRes.rsg>
+#include <Pbk2CommonUi.rsg>
+//Virtual Phonebook
+#include <MVPbkContactLink.h>
+#include <MVPbkContactViewBase.h>
+#include <CVPbkContactStoreUriArray.h>
+#include <MVPbkContactStore.h>
+#include <MVPbkContactStoreProperties.h>
+#include <MVPbkContactOperationBase.h>
+#include <CVPbkContactManager.h>
+#include <MVPbkStoreContact.h>
+#include <MVPbkContactFieldBinaryData.h>
+#include <MVPbkContactFieldTextData.h>
+#include <VPbkEng.rsg>
+#include <MVPbkContactGroup.h>
+
+//System
+#include <aknnotewrappers.h>
+#include <StringLoader.h>
+//#include <aknnavide.h>
+#include <akntitle.h>
+#include <imageconversion.h>
+
+// Debugging headers
+#include <Pbk2Debug.h>
+#include <Pbk2Profile.h>
+
+/// Unnamed namespace for local definitions
+namespace {
+
+const TInt KFirstContact = 0;
+const TInt KSecondContact = 1;
+const TInt KAmountToMerge = 2;
+const TInt KDeletionDelay = 1000000; // 1s
+
+_LIT( KLocalStore, "cntdb://c:contacts.cdb" );
+
+enum TPbk2PanicCodes
+        {
+        EPbk2CommandObserverMissing,
+        EPbk2WronglyActivated,
+        EPbk2DuplicateCallToExecuteLD,
+        EPbk2ViewsAlreadyCreated,
+        EPbk2WrongTypeOfData,
+		EPbk2PhotoConflictError
+        };
+    
+    void Panic(TPbk2PanicCodes aReason)
+        {
+        _LIT( KPanicText, "CPbk2_Merge_Contacts" );
+        User::Panic(KPanicText,aReason);
+        }
+
+} /// namespace
+
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::CPbk2MergeContactsCmd
+// --------------------------------------------------------------------------
+//
+CPbk2MergeContactsCmd::CPbk2MergeContactsCmd(
+    MPbk2ContactUiControl& aUiControl ) :
+        CActive( EPriorityStandard ),
+        iNextPhase( EPhaseNone ),
+        iUiControl( &aUiControl )
+    {
+    CActiveScheduler::Add( this );
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::~CPbk2MergeContactsCmd
+// --------------------------------------------------------------------------
+//
+CPbk2MergeContactsCmd::~CPbk2MergeContactsCmd()
+    {
+    PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING
+        ("CPbk2NlxMergeContactsCmd(%x)::~CPbk2MergeContactsCmd()"), 
+        this);
+    
+    Cancel();
+    
+    if ( iUiControl )
+        {
+        iUiControl->RegisterCommand( NULL );
+        }
+
+    CleanAfterFetching();
+    iTimer.Cancel();
+    iTimer.Close();
+    delete iFirstContactString;
+    delete iSecondContactString;
+    delete iMergedContactString;
+    delete iRetrieveOperation;
+    delete iDeleteOperation;
+    delete iCommitOperation;
+	delete iDeleteMergedOperation;
+    Release( iAppServices );
+    delete iContactFirst;
+    delete iContactSecond;
+    delete iMergedContactLink;
+    delete iStoreContactFirst;
+    delete iStoreContactSecond;
+    delete iMergedContact;
+    delete iMergeResolver;
+    delete iWaitDecorator;
+    if( iGroupsToAdd )
+        {
+        iGroupsToAdd->ResetAndDestroy();
+        delete iGroupsToAdd;
+        }
+    if ( iContactToCommit )
+        {
+        iContactToCommit->Reset();
+        delete iContactToCommit;
+        }
+    if ( iContactsToDelete )
+        {
+        iContactsToDelete->Reset();
+        delete iContactsToDelete;
+        }
+    if( iGroupLinksFirst )
+        {
+        iGroupLinksFirst->ResetAndDestroy();
+        delete iGroupLinksFirst;
+        }
+    if( iGroupLinksSecond )
+        {
+        iGroupLinksSecond->ResetAndDestroy();
+        delete iGroupLinksSecond;
+        }
+    TRAP_IGNORE( SetTitlePaneL( EFalse ) );
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::NewL
+// --------------------------------------------------------------------------
+//
+CPbk2MergeContactsCmd* CPbk2MergeContactsCmd::NewL(
+    MPbk2ContactUiControl& aUiControl )
+    {
+    CPbk2MergeContactsCmd* self = 
+        new ( ELeave ) CPbk2MergeContactsCmd( aUiControl );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::ConstructL
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::ConstructL()
+    {    
+    if( iUiControl )
+        {
+        iUiControl->RegisterCommand( this );
+        }    
+    
+    iContactManager = &Phonebook2::Pbk2AppUi()->ApplicationServices().ContactManager();
+    iAppServices = CPbk2ApplicationServices::InstanceL();
+    iPhotoConflictIndex = KErrNotFound;
+    User::LeaveIfError( iTimer.CreateLocal() );
+    }
+    
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::ExecuteLD
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::ExecuteLD()
+    {
+    __ASSERT_ALWAYS( iCommandObserver, Panic( EPbk2CommandObserverMissing ));	    
+    __ASSERT_ALWAYS( !IsActive(), Panic( EPbk2WronglyActivated ));	
+    __ASSERT_ALWAYS( iNextPhase == EPhaseNone, Panic( EPbk2DuplicateCallToExecuteLD ));
+    
+    if( iUiControl )
+        {
+        // Blank UI control to avoid flicker
+        iUiControl->SetBlank( ETrue );
+        }
+    StartNext( EPhaseGetSelection );
+    }
+    
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::ResetUiControl
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::ResetUiControl( 
+    MPbk2ContactUiControl& aUiControl )
+    {
+    if ( iUiControl == &aUiControl )
+        {
+        iUiControl = NULL;
+        }
+    }
+    
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::AddObserver
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::AddObserver( 
+    MPbk2CommandObserver& aObserver )
+    {
+    iCommandObserver = &aObserver;
+    }        
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::AutomaticMergeL
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::AutomaticMergeL()
+    {
+    if(iStoreContactFirst && iStoreContactSecond)
+        {
+        iMergeResolver = CPbk2MergeResolver::NewL(
+                CPbk2PresentationContact::NewL( *iStoreContactFirst, iAppServices->FieldProperties() ), 
+                CPbk2PresentationContact::NewL( *iStoreContactSecond, iAppServices->FieldProperties() ) );
+        iMergeResolver->MergeL();
+        StartNext(EPhaseResolveConflicts);
+        }
+    else
+        {
+        Finish(KErrArgument);
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::AddGroupsL
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::AddGroupsL()
+    {
+    TInt countGroups = iGroupsToAdd->Count();
+    if(countGroups)
+        {
+        MVPbkStoreContact *group = iGroupsToAdd->At(countGroups - 1);
+        group->LockL(*this);
+        }
+    else
+        {
+        DeleteSourceContactsL();
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::RunL
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::RunL()
+    {
+    if( !iUiControl )
+        {
+        //UiControl reseted, so cancel all processing
+        iNextPhase = EPhaseFinish ;
+        }
+
+    switch( iNextPhase )
+    	{
+    	case EPhaseGetSelection:
+    	    {
+    	    GetContactsFromUiFetchL();    	    
+    	    }
+    	    break;
+    	case EPhaseGetStoreContacts:
+            {
+            GetStoreContacts();
+            }   
+            break;
+    	case EPhaseMerge:
+    	    {
+            AutomaticMergeL();
+    	    }
+            break;
+    	case EPhaseResolveConflicts:
+            {
+            ResolveConflictsL();
+            }
+            break;
+        case EPhaseResolvePhotoConflict:
+            {
+            ResolvePhotoConflictL();
+            }
+            break;
+    	case EPhaseCreateMergedContact:
+        	{
+        	iWaitDecorator = Pbk2ProcessDecoratorFactory::CreateWaitNoteDecoratorL
+                                   ( R_QTN_MERGE_CONTACTS_WAIT_NOTE, EFalse );
+        	iWaitDecorator->SetObserver( *this );
+            iWaitDecorator->ProcessStartedL( 0 );
+            FinalizeMergeL();
+        	}
+    		break;
+    	case EPhaseGetGroups:
+            {
+            GetGroupsL();
+            }
+            break;
+    	case EPhaseAddGroups:
+            {
+            AddGroupsL();
+            }
+            break;
+    	case EPhaseFinish:
+            {
+            if ( iWaitDecorator )
+                {
+                // Decorator calls ProcessDismissed
+                iWaitDecorator->ProcessStopped();
+                }
+            else
+                {
+                // In case Decorator wasn't initialized we invoke
+                // ProcessDismissed to finish merge command execution
+                ProcessDismissed( KErrNone );
+                }
+            }
+            break;
+            
+    	default:
+    		Panic( EPbk2WronglyActivated );
+    		break;
+    	}
+    }    
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::RunError
+// --------------------------------------------------------------------------
+//
+TInt CPbk2MergeContactsCmd::RunError(TInt aError)
+	{
+	Finish( aError );
+    return KErrNone;
+	}
+    
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::FinalizeMergeL
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::FinalizeMergeL()
+    {
+    if( !iMergeResolver ||  
+            ( !iMergeResolver->CountMerged() && !iMergeResolver->CountConflicts() ) )
+        {
+        Finish( KErrNone );
+        return;
+        }
+    
+    MVPbkContactStore& store = iStoreContactFirst->ParentStore();
+    iMergedContact = store.CreateNewContactLC();
+    CleanupStack::Pop();
+    
+    // the conflict thumbnail data's field, used for comparing
+    MVPbkStoreContactField* thumbnailPicField = NULL;
+    
+    TInt conflictCount = iMergeResolver->CountConflicts();
+    // add conflicted fields
+    for ( TInt i = 0; i < conflictCount; i++ )
+        {
+        MPbk2MergeConflict& conflict = iMergeResolver->GetConflictAt( i );
+        
+        RPointerArray<MVPbkStoreContactField> fields;
+        conflict.GetChosenFieldsL( fields );
+        
+        TInt newFields = fields.Count();
+        /// if newFields == 0 not resolved conflict exist
+        
+        for ( TInt j = 0; j < newFields; j++ )
+            {
+            MVPbkStoreContactField* field = fields[ j ];
+            const MVPbkFieldType* fieldType = field->BestMatchingFieldType();
+            
+            // assign value to thumnailPicField with the field's value
+            if ( fieldType->FieldTypeResId() == R_VPBK_FIELD_TYPE_THUMBNAILPIC )
+                {
+                thumbnailPicField = field;
+                }
+            AddFieldToMergedContactL( *field );
+            } 
+        fields.Close();
+        }
+    
+    TInt mergedFieldsCount = iMergeResolver->CountMerged();
+        
+    // add merged fields
+    for ( TInt i = 0; i < mergedFieldsCount; i++ )
+        {
+        MVPbkStoreContactField& field = iMergeResolver->GetMergedAt( i );
+        const MVPbkFieldType* fieldType = field.BestMatchingFieldType();
+        
+        // avoid merging filePath when the two field unmatched to a contact
+        if ( fieldType->FieldTypeResId() == R_VPBK_FIELD_TYPE_CALLEROBJIMG && thumbnailPicField )
+            {
+            if ( !thumbnailPicField->ParentContact().IsSame( field.ParentContact() ) )
+                {
+                continue;
+                }
+            }
+        AddFieldToMergedContactL( field );
+        }
+    
+    iContactToCommit = new ( ELeave ) CArrayPtrFlat<MVPbkStoreContact>( 1 );
+    iContactToCommit->AppendL( iMergedContact );
+    iCommitOperation = iContactManager->CommitContactsL( iContactToCommit->Array(), *this );
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::ShowContactsMergedNoteL
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::ShowContactsMergedNoteL()
+    {
+    HBufC* unnamed = StringLoader::LoadLC( R_QTN_PHOB_UNNAMED );
+    CDesCArrayFlat* strings = new(ELeave) CDesCArrayFlat( 3 );
+    CleanupStack::PushL( strings );
+    
+    HBufC* prompt = NULL;
+
+    if ( ( iFirstContactString->Compare( *unnamed ) || iSecondContactString->Compare( *unnamed ) )
+            && iMergedContactString->Compare( *unnamed ) )
+        {
+        strings->AppendL( *iFirstContactString );
+        strings->AppendL( *iSecondContactString );
+        strings->AppendL( *iMergedContactString );
+
+        prompt = StringLoader::LoadLC( R_QTN_PHOB_NOTE_CONTACTS_WERE_MERGED, *strings );
+        }
+    else
+        {
+        strings->AppendL( *unnamed );
+        prompt = StringLoader::LoadLC( R_QTN_PHOB_NOTE_UNNAMED_CONTACTS_WERE_MERGED , *strings );
+        }
+
+    CAknQueryDialog* dlg = CAknQueryDialog::NewL();
+    dlg->ExecuteLD( R_PBK2_MERGE_CONTACTS_CONFIRMATION_NOTE, *prompt );
+    
+    CleanupStack::PopAndDestroy( prompt );
+    CleanupStack::PopAndDestroy( strings );
+    CleanupStack::PopAndDestroy( unnamed );
+
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::ContactAsStringLC
+// --------------------------------------------------------------------------
+//
+HBufC* CPbk2MergeContactsCmd::ContactAsStringL( MVPbkStoreContact* aStoreContact )
+    {
+    MVPbkStoreContactFieldCollection& fields = aStoreContact->Fields();
+    HBufC* result = NULL;
+    const TInt KDefaultListFormatting = 
+            MPbk2ContactNameFormatter::EDisableCompanyNameSeparator;
+    result = Phonebook2::Pbk2AppUi()->
+            ApplicationServices().NameFormatter().GetContactTitleL( fields, KDefaultListFormatting );
+    if( !result )
+        {
+        result = StringLoader::LoadLC( R_QTN_PHOB_UNNAMED );
+        CleanupStack::Pop( result );
+        }
+    return result;
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::DoCancel
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::DoCancel()
+    {
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::NotifyObservers
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::NotifyObservers()
+    {
+    if ( iCommandObserver )
+        {
+        iCommandObserver->CommandFinished( *this );
+        }
+    
+    if ( iUiControl )
+        {
+        iUiControl->SetBlank( EFalse );
+        iUiControl->UpdateAfterCommandExecution();
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::AcceptFetchSelectionL
+// --------------------------------------------------------------------------
+//
+MPbk2FetchDlgObserver::TPbk2FetchAcceptSelection CPbk2MergeContactsCmd::AcceptFetchSelectionL(
+    TInt /*aNumMarkedEntries*/,
+    MVPbkContactLink& /*aLastSelection*/ )
+    {
+    return MPbk2FetchDlgObserver::EFetchYes;
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::FetchCompletedL
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::FetchCompletedL(
+    MVPbkContactLinkArray* aMarkedEntries )
+    {   
+    if ( aMarkedEntries )
+        {
+        TInt count = aMarkedEntries->Count();
+        if ( count == 2 )
+            {
+            iContactFirst = aMarkedEntries->At( KFirstContact ).CloneLC();
+            CleanupStack::Pop();
+            iContactSecond = aMarkedEntries->At( KSecondContact ).CloneLC();
+            CleanupStack::Pop();
+            StartNext( EPhaseGetStoreContacts );
+            }
+        else
+            {
+            // Show a note
+            HBufC* prompt = NULL;
+            prompt = StringLoader::LoadLC( R_QTN_PHOB_NOTE_SELECT_2_TO_MERGE );
+            CAknQueryDialog* dlg = CAknQueryDialog::NewL();
+            dlg->ExecuteLD( R_PBK2_MERGE_CONTACTS_ERROR_NOTE, *prompt );
+            CleanupStack::PopAndDestroy( prompt ); 
+            }
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::FetchCanceled
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::FetchCanceled()
+    {
+    Finish( KErrCancel );
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::FetchAborted
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::FetchAborted()
+    {
+    Finish( KErrCancel );
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::FetchOkToExit
+// --------------------------------------------------------------------------
+//
+TBool CPbk2MergeContactsCmd::FetchOkToExit()
+    {
+    if ( iNextPhase == EPhaseFinish )
+        {
+        return ETrue;
+        }
+    
+    if ( iContactFirst && iContactSecond )
+        {
+        return ETrue;
+        }
+    else
+        {
+        return EFalse;
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::GetContactsFromUiFetchL
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::GetContactsFromUiFetchL()
+    {
+    __ASSERT_DEBUG( !iAllContactsView, Panic( EPbk2ViewsAlreadyCreated ));
+    CPbk2FetchDlg::TParams params;
+    params.iResId = R_PBK2_MULTIPLE_ENTRY_FETCH_NO_GROUPS_DLG;
+    params.iCbaId = R_PBK2_SOFTKEYS_MERGE_BACK_MARK;
+    params.iNaviPaneId = R_PBK2_MERGE_CONTACTS_FETCH_NAVILABEL;
+    params.iMinSelection = KAmountToMerge;
+    
+    CPbk2StorePropertyArray& storeProperties =
+        Phonebook2::Pbk2AppUi()->ApplicationServices().StoreProperties();
+    
+    // Fetch dlg uses this view instead of AllNameslistView if it is not suitable
+    iStoreUris = Phonebook2::Pbk2AppUi()->
+        ApplicationServices().StoreConfiguration().CurrentConfigurationL();
+    
+    TBool createNewView = EFalse;
+    for ( TInt i = iStoreUris->Count()-1; i >= 0; --i )
+        {
+        const CPbk2StoreProperty* storeProperty = 
+            storeProperties.FindProperty( ( *iStoreUris )[i] );
+        
+        if ( storeProperty != NULL && storeProperty->StoreUri().UriDes().Compare( KLocalStore ) )
+            {
+            iStoreUris->Remove( (*iStoreUris)[i] );
+            createNewView = ETrue;
+            }
+        }    
+    
+    if ( createNewView )
+        {
+        iAllContactsView = CVPbkFilteredContactView::NewL
+            ( *Phonebook2::Pbk2AppUi()->ApplicationServices().ViewSupplier().
+              AllContactsViewL(), *this, *this, iContactManager->FieldTypes() );
+        
+        params.iNamesListView = iAllContactsView;
+        iObservedView = iAllContactsView;
+        }
+    else{
+        params.iNamesListView =
+            Phonebook2::Pbk2AppUi()->ApplicationServices().ViewSupplier().AllContactsViewL();
+        iObservedView =
+            Phonebook2::Pbk2AppUi()->ApplicationServices().ViewSupplier().AllContactsViewL();
+        }    
+
+    iObservedView->AddObserverL( *this );
+        
+    params.iGroupsListView = NULL;
+    params.iFlags = CPbk2FetchDlg::EFetchMultiple;
+    params.iExitCallback = this;
+    
+    CPbk2FetchDlg* dlg = CPbk2FetchDlg::NewL( params, *this );
+    iFetchDlgEliminator = dlg;
+    iFetchDlgEliminator->ResetWhenDestroyed( &iFetchDlgEliminator );
+    
+    SetTitlePaneL( ETrue );
+    dlg->ExecuteLD(); // Completion is signalled with a callback.
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::IsFromReadOnlyStore
+// --------------------------------------------------------------------------
+//
+TBool CPbk2MergeContactsCmd::IsFromReadOnlyStore
+        ( const MVPbkContactLink& aContactLink ) const
+    {
+    TBool ret = EFalse;
+
+    const MVPbkContactStore& store = aContactLink.ContactStore();
+    if ( store.StoreProperties().ReadOnly() )
+        {
+        ret = ETrue;
+        }
+
+    return ret;
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::CleanAfterFetching
+// insure the fetch dlg is deleted and destroy resources used by it 
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::CleanAfterFetching()
+    {
+    if ( iFetchDlgEliminator )
+        {
+        iFetchDlgEliminator->ForceExit();
+        }
+    if ( iObservedView )
+        {
+        iObservedView->RemoveObserver( *this );
+        }
+    delete iAllContactsView;
+    iAllContactsView = NULL;   
+    delete iStoreUris;
+    iStoreUris = NULL;
+    }
+
+// ---------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::Finish
+// ---------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::Finish( TInt aReason )
+	{
+	if ( aReason != KErrNone && aReason != KErrCancel )
+	    {
+	    CCoeEnv::Static()->HandleError( aReason );
+	    }
+	
+	if( iNextPhase != EPhaseFinish )
+		{
+    	StartNext( EPhaseFinish );
+		}
+	}
+
+// ---------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::StartNext
+// ---------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::StartNext( TPhase aPhase )
+    {
+    __ASSERT_DEBUG( !IsActive(), Panic( EPbk2WronglyActivated )); 
+    
+    iNextPhase = aPhase;
+    
+    if ( iNextPhase == EPhaseGetGroups )
+        {
+        iTimer.After( iStatus, KDeletionDelay ); 
+        }
+    else
+        {
+        TRequestStatus* status = &iStatus;
+        User::RequestComplete( status, KErrNone );
+        }
+    SetActive();
+    }
+
+// ---------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::StartNext
+// ---------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::StartNext()
+    {
+    __ASSERT_DEBUG( !IsActive(), Panic( EPbk2WronglyActivated ));    
+    TRequestStatus* status = &iStatus;
+    User::RequestComplete(status, KErrNone);
+    SetActive();
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::RetrieveContactL
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::RetrieveContact(
+        const MVPbkContactLink& aContactLink )
+    {
+    // Retrieve the actual store contact from the given link
+    TRAPD( error, 
+        iRetrieveOperation = iAppServices->
+        ContactManager().RetrieveContactL( aContactLink, *this );
+    );
+    if( error != KErrNone )
+        {
+        Finish( error );
+        }
+    }
+
+////////////////////////////// CALLBACKS /////////////////////////////////////
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::VPbkSingleContactOperationComplete
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::VPbkSingleContactOperationComplete(
+        MVPbkContactOperationBase& aOperation,
+        MVPbkStoreContact* aContact )
+    {
+    if ( &aOperation == iRetrieveOperation )
+        {
+        delete iRetrieveOperation;
+        iRetrieveOperation = NULL;
+
+        if( !iStoreContactFirst )
+            {
+            iStoreContactFirst = aContact;
+            TRAPD( error, iStoreContactFirst->LockL( *this ) );
+            if( error != KErrNone )
+                {
+                Finish( error );
+                }
+            }
+        else if( !iStoreContactSecond )
+            {
+            iStoreContactSecond = aContact;
+            TRAPD( error, iStoreContactSecond->LockL( *this ) );
+            if( error != KErrNone )
+                {
+                Finish( error );
+                }
+            }
+        else if( iNextPhase == EPhaseGetGroups 
+                 && aContact->Group()
+                 && iGroupLinksFirst 
+                 && iGroupLinksSecond
+                 && iGroupsToAdd )
+            {
+            TBool sameGroup = EFalse;
+            for( TInt idx = 0; idx < iGroupsToAdd->Count(); idx++ )
+                {
+                if( aContact->IsSame( *iGroupsToAdd->At( idx ) ) )
+                    {
+                    sameGroup = ETrue;
+                    break;
+                    }
+                }
+            TInt error = KErrNone;
+            if( !sameGroup )
+                {
+                TRAP( error, iGroupsToAdd->AppendL( aContact ); );
+                if ( error != KErrNone )
+                    {
+                    delete aContact;
+                    DeleteMergedContact();
+                    return;
+                    }
+                }
+            else
+                {
+                delete aContact;
+                }
+            
+            TInt countFirst = iGroupLinksFirst->Count();
+            TInt countSecond = iGroupLinksSecond->Count();
+            
+            if( countFirst )
+                {
+                delete &( iGroupLinksFirst->At( countFirst - 1 ) );
+                iGroupLinksFirst->Remove( countFirst - 1 );
+                }
+            else if( countSecond )
+                {
+                delete &( iGroupLinksSecond->At( countSecond - 1 ) );
+                iGroupLinksSecond->Remove( countSecond - 1 );
+                }
+            
+            countFirst = iGroupLinksFirst->Count();
+            countSecond = iGroupLinksSecond->Count();
+            
+            if( countFirst )
+                {
+                RetrieveContact( iGroupLinksFirst->At( countFirst - 1 ) );
+                }
+            else if( countSecond )
+                {
+                RetrieveContact( iGroupLinksSecond->At( countSecond - 1 ) );
+                }
+            else
+                {
+                StartNext( EPhaseAddGroups );
+                }
+            if ( error != KErrNone )
+                {
+                delete aContact;
+                DeleteMergedContact();
+                }
+            }
+        else
+            {
+            delete aContact;
+            DeleteMergedContact();
+            }
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::VPbkSingleContactOperationFailed
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::VPbkSingleContactOperationFailed(
+        MVPbkContactOperationBase& aOperation,
+        TInt aError )
+    {
+    if ( &aOperation == iRetrieveOperation )
+        {
+        delete iRetrieveOperation;
+        iRetrieveOperation = NULL;
+        
+        Finish( aError );
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::ContactOperationCompleted
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::ContactOperationCompleted(
+        TContactOpResult aResult )
+    {
+    if( aResult.iOpCode == MVPbkContactObserver::EContactLock 
+            && iNextPhase == EPhaseGetStoreContacts && !iStoreContactSecond )
+        {
+        RetrieveContact( *iContactSecond );
+        }
+    else if( aResult.iOpCode == MVPbkContactObserver::EContactLock 
+            && iNextPhase == EPhaseGetStoreContacts )
+        {
+        StartNext( EPhaseMerge );
+        }
+    else if( aResult.iOpCode == MVPbkContactObserver::EContactLock )
+        {
+        TInt countGroups = iGroupsToAdd->Count();
+        if( countGroups )
+            {
+            MVPbkStoreContact* group = iGroupsToAdd->At( countGroups - 1 );
+            TRAPD( error, 
+                group->Group()->AddContactL( *iMergedContactLink );
+                group->CommitL( *this );
+            );
+            if ( error != KErrNone )
+                {
+                DeleteMergedContact();
+                }
+            }
+        }
+    else if( aResult.iOpCode == MVPbkContactObserver::EContactCommit) 
+        {
+        TInt countGroups = iGroupsToAdd->Count();
+        if( countGroups )
+            {
+            MVPbkStoreContact* group = iGroupsToAdd->At( countGroups - 1 );
+            delete group;
+            iGroupsToAdd->Delete( countGroups - 1 );
+            }
+        countGroups = iGroupsToAdd->Count();
+        if( countGroups )
+            {
+            MVPbkStoreContact* group = iGroupsToAdd->At( countGroups - 1 );
+            TRAPD( error, 
+                group->LockL( *this );
+            );
+           if ( error != KErrNone )
+               {
+               DeleteMergedContact();
+               }
+            }
+        else
+            {
+            TRAPD( error, 
+                DeleteSourceContactsL();
+            );
+           if ( error != KErrNone )
+               {
+               DeleteMergedContact();
+               }
+            }
+        }
+    delete aResult.iStoreContact;
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::ContactOperationFailed
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::ContactOperationFailed(
+        TContactOp aOpCode, TInt aErrorCode, TBool /*aErrorNotified*/ )
+    {
+    if( aOpCode == MVPbkContactObserver::EContactLock && iNextPhase == EPhaseGetStoreContacts )
+        {
+        Finish( aErrorCode );
+        }
+    else
+        {
+        DeleteMergedContact();
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::ProcessDismissed
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::ProcessDismissed
+        ( TInt /*aCancelCode*/ )
+    {
+    if( iMergedContact )
+        {
+        TRAP_IGNORE( ShowContactsMergedNoteL() );
+        }
+    NotifyObservers();
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::ContactViewReady
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::ContactViewReady
+        ( MVPbkContactViewBase& /*aView*/ )
+    {
+    // Do nothing
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::ContactViewUnavailable
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::ContactViewUnavailable
+        ( MVPbkContactViewBase& /*aView*/ )
+    {
+    // Do nothing
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::ContactAddedToView
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::ContactAddedToView
+        ( MVPbkContactViewBase& /*aView*/, TInt /*aIndex*/,
+          const MVPbkContactLink& aContactLink )
+    {
+    if ( iMergedContact && iNextPhase == EPhaseCreateMergedContact )
+        {
+        TRAPD( error,
+            if( !iMergedContactLink  )
+                {
+                iMergedContactLink = iMergedContact->CreateLinkLC();
+                if ( iMergedContactLink )
+                    {
+                    CleanupStack::Pop();
+                    }
+                else
+                    {
+                    User::Leave( KErrGeneral );
+                    }
+                }
+            if ( iMergedContactLink && iMergedContactLink->IsSame( aContactLink ) )
+                {
+                StartNext( EPhaseGetGroups );
+                }
+        );
+        if ( error != KErrNone )
+            {
+            Finish( error );
+            }
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::ContactRemovedFromView
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::ContactRemovedFromView
+        ( MVPbkContactViewBase& /*aView*/, TInt /*aIndex*/,
+          const MVPbkContactLink& /*aContactLink*/ )
+    {
+    // Do nothing
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::ContactViewError
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::ContactViewError
+        ( MVPbkContactViewBase& /*aView*/, TInt /*aError*/,
+          TBool /*aErrorNotified*/ )
+    {
+    // Do nothing
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::OkToExitL
+// --------------------------------------------------------------------------
+//
+TBool CPbk2MergeContactsCmd::OkToExitL( TInt /*aCommandId*/ )
+    {
+    return ETrue;
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::IsContactIncluded
+// --------------------------------------------------------------------------
+//
+TBool CPbk2MergeContactsCmd::IsContactIncluded
+        ( const MVPbkBaseContact& aContact )
+    {
+    for ( TInt i = iStoreUris->Count()-1; i >= 0; --i )
+        {
+        if ( aContact.MatchContactStore((*iStoreUris)[i].UriDes()) )
+            {
+            return ETrue;
+            }
+        }  
+    return EFalse;
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::StepComplete
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::StepComplete( MVPbkContactOperationBase& /*aOperation*/, TInt /*aStepSize*/ )
+    {
+    
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::StepFailed
+// --------------------------------------------------------------------------
+//
+TBool CPbk2MergeContactsCmd::StepFailed( MVPbkContactOperationBase& aOperation, 
+                                         TInt /*aStepSize*/, TInt aError )
+    {
+    if ( &aOperation == iCommitOperation )
+        {
+        delete iCommitOperation;
+        iCommitOperation = NULL;
+        iContactToCommit->Reset();
+        delete iContactToCommit;
+        iContactToCommit = NULL;
+        Finish( aError );
+        }
+    else if ( &aOperation == iDeleteOperation )
+        {
+        delete iDeleteOperation;
+        iDeleteOperation = NULL;
+        // Merged contact must be deleted
+        DeleteMergedContact();
+        }
+    else if ( &aOperation == iDeleteMergedOperation )
+        {
+        delete iDeleteMergedOperation;
+        iDeleteMergedOperation = NULL;
+        Finish( aError );
+        }
+    return EFalse;
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::perationComplete
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::OperationComplete( MVPbkContactOperationBase& aOperation )
+    {
+    if ( &aOperation == iCommitOperation )
+        {
+        delete iCommitOperation;
+        iCommitOperation = NULL;
+        iContactToCommit->Reset();
+        delete iContactToCommit;
+        iContactToCommit = NULL;
+        }
+    else if ( &aOperation == iDeleteOperation )
+        {
+        delete iDeleteOperation;
+        iDeleteOperation = NULL;
+        Finish( KErrNone );
+        }
+    else if ( &aOperation == iDeleteMergedOperation )
+        {
+        delete iDeleteMergedOperation;
+        iDeleteMergedOperation = NULL;
+        delete iMergedContact;
+        iMergedContact = NULL;
+        Finish( KErrInUse );
+        }
+    }
+
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::SetTitlePaneL
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::SetTitlePaneL( TBool aCustom )
+    {
+    if ( iAvkonAppUi )
+        {
+        CEikStatusPane* statusPane = iAvkonAppUi->StatusPane();
+        if ( statusPane && statusPane->PaneCapabilities( TUid::Uid( EEikStatusPaneUidTitle ) ).IsPresent() )
+            {
+            CAknTitlePane* titlePane = static_cast<CAknTitlePane*>
+                ( statusPane->ControlL ( TUid::Uid( EEikStatusPaneUidTitle ) ) );
+        
+            if ( aCustom )
+                {
+                HBufC* title = StringLoader::LoadLC( R_QTN_PHOB_TITLE_MERGE_CONTACTS );
+                titlePane->SetTextL( *title );
+                CleanupStack::PopAndDestroy( title );  
+                }
+            else
+                {
+                titlePane->SetTextToDefaultL();
+                }
+            }
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::CheckPhotoConflictL
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::CheckPhotoConflictL()
+    {
+    iImageTypeConflictsCount = 0;
+    iPhotoConflictIndex = KErrNotFound;
+    TInt conflictsCount = iMergeResolver->CountConflicts();
+    for ( TInt i = 0; i < conflictsCount; i++ )
+        {
+        MPbk2MergeConflict& conflict = iMergeResolver->GetConflictAt( i );
+        TInt type = conflict.GetConflictType();
+        if ( type == EPbk2ConflictTypeImage )
+            {
+            iImageTypeConflictsCount++;
+            CPbk2MergeConflict& conflict =
+                ( CPbk2MergeConflict& ) iMergeResolver->GetConflictAt( i );
+            const MVPbkStoreContactField* firstField;
+            const MVPbkStoreContactField* secondField;
+            conflict.GetFieldsL( firstField, secondField );
+            
+            const MVPbkFieldType* fieldType = firstField->BestMatchingFieldType();
+            if ( fieldType )
+                {
+                TArray<TVPbkFieldVersitProperty> versitPropArr = fieldType->VersitProperties();
+                TInt count = versitPropArr.Count();
+            
+                for( TInt idx = 0; idx < count; idx++ )
+                    {
+                    TVPbkFieldVersitProperty versitProp = versitPropArr[idx];
+                    if( versitProp.Name() == EVPbkVersitNamePHOTO )
+                        {
+                        if ( firstField->FieldData().DataType() == EVPbkFieldStorageTypeBinary && 
+                                secondField->FieldData().DataType() == EVPbkFieldStorageTypeBinary )
+                            {
+                            iPhotoConflictIndex = i;
+                            break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::ResolveAllPhotoConflicts
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::ResolveAllPhotoConflicts( 
+        EPbk2ConflictedNumber aConflictResolutionNumber )
+    {
+    TInt conflictsCount = iMergeResolver->CountConflicts();
+    for ( TInt i = 0; i < conflictsCount; i++ )
+        {
+        MPbk2MergeConflict& conflict = iMergeResolver->GetConflictAt( i );
+        if ( conflict.GetConflictType() == EPbk2ConflictTypeImage )
+            {
+            conflict.ResolveConflict( aConflictResolutionNumber );
+            }
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::ResolvePhotoConflictL
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::ResolvePhotoConflictL()
+    {
+    if ( iStatus != KErrNone || iPhotoConflictIndex == KErrNotFound )
+        {
+        StartNext( EPhaseCreateMergedContact );
+        return;
+        }
+    
+    TInt result = EPbk2ConflictedFirst;
+    
+    CPbk2MergePhotoConflictDlg* dlg = 
+        CPbk2MergePhotoConflictDlg::NewL( iStoreContactFirst, iStoreContactSecond, &result );
+    if ( !dlg->ExecuteLD( R_PBK2_MERGE_CONTACTS_PHOTO_CONFLICT_RESOLUTION_DLG ) )
+        {
+        // dlg returns 0 if canceled
+        Finish( KErrNone );
+        }
+    else
+        {
+        ResolveAllPhotoConflicts( (EPbk2ConflictedNumber) result );
+        StartNext( EPhaseCreateMergedContact );
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::AddFieldToMergedContactL
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::AddFieldToMergedContactL( MVPbkStoreContactField& field )
+    {
+    const MVPbkFieldType* type = field.BestMatchingFieldType();
+    if ( type )
+        {
+        MVPbkStoreContactField* newField = iMergedContact->CreateFieldLC( *type );
+        newField->SetFieldLabelL( field.FieldLabel() );
+        newField->FieldData().CopyL( field.FieldData() );
+        iMergedContact->AddFieldL( newField );
+        CleanupStack::Pop( newField );
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::DoResolveConflictsL
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::ResolveConflictsL()
+    {
+    CheckPhotoConflictL();
+    
+    TBool isPhotoConflict = iPhotoConflictIndex != KErrNotFound;
+    TInt normalConflicts = 0;
+    if( iMergeResolver )
+        {
+        normalConflicts = iMergeResolver->CountConflicts() - iImageTypeConflictsCount;
+        }
+    
+    if( normalConflicts )
+        {
+        // resolve conflicts
+        CPbk2MergeConflictsDlg* dlg = CPbk2MergeConflictsDlg::NewL( iMergeResolver, isPhotoConflict );
+        if ( !dlg->ExecuteLD( R_PBK2_MERGE_CONTACTS_CONFLICT_RESOLUTION_DLG ) )
+            {
+            // dlg returns 0 if canceled
+            Finish( KErrCancel );
+            }
+        else
+            {
+            StartNext( EPhaseResolvePhotoConflict );
+            }
+        }
+    else
+        {
+        StartNext( EPhaseResolvePhotoConflict );
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::GetStoreContactsL
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::GetStoreContacts()
+    {
+    if( iContactFirst && iContactSecond )
+        {
+        if( !iStoreContactFirst )
+            {
+            RetrieveContact( *iContactFirst );
+            }
+        else
+            {
+            Finish( KErrArgument );
+            }
+        }
+    else
+        {
+        Finish( KErrArgument );
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::DeleteSourceContactsL
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::DeleteSourceContactsL()
+    {
+    User::LeaveIfNull( iContactFirst );
+    User::LeaveIfNull( iContactSecond );
+    
+    iFirstContactString = ContactAsStringL( iStoreContactFirst );
+    iSecondContactString = ContactAsStringL( iStoreContactSecond );
+    iMergedContactString = ContactAsStringL( iMergedContact );
+    
+    delete iStoreContactFirst;
+    iStoreContactFirst = NULL;
+    
+    delete iStoreContactSecond;
+    iStoreContactSecond = NULL;
+    
+    if( iContactsToDelete )
+        {
+        delete iContactsToDelete;
+        iContactsToDelete = NULL;
+        }
+    iContactsToDelete = CVPbkContactLinkArray::NewL();
+    iContactsToDelete->AppendL( iContactSecond );
+    iContactsToDelete->AppendL( iContactFirst );
+    if( iDeleteOperation )
+        {
+        delete iDeleteOperation;
+        iDeleteOperation = NULL;
+        }
+    iDeleteOperation = iContactManager->DeleteContactsL( *iContactsToDelete, *this );
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::DeleteMergedContact
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::DeleteMergedContact()
+    {
+    TRAPD( error, 
+            DeleteMergedContactL();
+    );
+    if( error != KErrNone )
+        {
+        Finish( KErrGeneral );
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::DeleteMergedContactL
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::DeleteMergedContactL()
+    {
+    if ( iContactsToDelete )
+        {
+        iContactsToDelete->Reset();
+        }
+    else
+        {
+        iContactsToDelete = CVPbkContactLinkArray::NewL();
+        }
+    
+    if ( iMergedContact )
+        {
+        if( !iMergedContactLink  )
+            {
+            MVPbkContactLink* iMergedContactLink = iMergedContact->CreateLinkLC();
+            if ( iMergedContactLink )
+                {
+                CleanupStack::Pop();
+                }
+            else
+                {
+                User::Leave( KErrGeneral );
+                }
+            }
+        iContactsToDelete->AppendL( iMergedContactLink );
+        iDeleteMergedOperation = iContactManager->DeleteContactsL( *iContactsToDelete, *this );
+        }
+    else
+        {
+        User::Leave( KErrGeneral );
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2MergeContactsCmd::GetGroupsL
+// --------------------------------------------------------------------------
+//
+void CPbk2MergeContactsCmd::GetGroupsL()
+    {
+    if( iStoreContactFirst && iStoreContactFirst && iMergedContact )
+        {
+        if( !iGroupsToAdd )
+            {
+            iGroupsToAdd = new ( ELeave ) CArrayPtrFlat<MVPbkStoreContact>( 1 );
+            }
+        iGroupLinksFirst = static_cast<CVPbkContactLinkArray*>( iStoreContactFirst->GroupsJoinedLC() );
+        CleanupStack::Pop(); 
+        iGroupLinksSecond = static_cast<CVPbkContactLinkArray*>( iStoreContactSecond->GroupsJoinedLC() );
+        CleanupStack::Pop(); 
+        
+        TInt countFirst = iGroupLinksFirst->Count();
+        TInt countSecond = iGroupLinksSecond->Count();
+        
+        if( countFirst )
+            {
+            RetrieveContact( iGroupLinksFirst->At( countFirst - 1 ) );
+            }
+        else if( countSecond )
+            {
+            RetrieveContact( iGroupLinksSecond->At( countSecond - 1 ) );
+            }
+        else
+            {
+            DeleteSourceContactsL();
+            }
+        }
+    else
+        {
+        DeleteMergedContactL();
+        }
+    }
+//  End of File