phonebookengines/VirtualPhonebook/VPbkEng/src/CVPbkCompositeContactView.cpp
changeset 0 e686773b3f54
child 6 e8e3147d53eb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookengines/VirtualPhonebook/VPbkEng/src/CVPbkCompositeContactView.cpp	Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,1269 @@
+/*
+* Copyright (c) 2002-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:  Composite contact view.
+*
+*/
+
+
+#include "CVPbkCompositeContactView.h"
+#include <MVPbkFieldType.h>
+#include <CVPbkSortOrder.h>
+#include <CVPbkAsyncCallback.h>
+#include <MVPbkContactLink.h>
+#include "CVPbkEventArrayItem.h"
+#include <VPbkError.h>
+
+// Debugging headers
+#include <VPbkProfile.h>
+#include <VPbkDebug.h>
+
+/// Unnamed namespace for local definitions
+namespace {
+
+#ifdef _DEBUG
+    enum TPanic
+        {
+        EPanicLogic_CreateBookmarkLC = 3
+        };
+        
+    void Panic(TPanic aPanic)
+        {
+        _LIT(KPanicCat, "CVPbkCompositeContactView");
+        User::Panic(KPanicCat, aPanic);
+        }
+#endif // _DEBUG
+
+/// Observer granulatiry
+const TInt KObserverArrayGranularity = 4;
+
+/////////////////////////////////////////////////////////////////////////////
+// Event sending functions for different amount of parameters
+//
+
+// --------------------------------------------------------------------------
+// SendEventToObservers
+// --------------------------------------------------------------------------
+//
+template <class NotifyFunc>
+void SendEventToObservers( MVPbkContactViewBase& aView, 
+        RPointerArray<MVPbkContactViewObserver>& aObservers,
+        NotifyFunc aNotifyFunc )
+    {
+    const TInt count = aObservers.Count();
+    for (TInt i = count - 1; i >= 0; --i)
+        {
+        MVPbkContactViewObserver* observer = aObservers[i];
+        (observer->*aNotifyFunc)(aView);
+        }
+    }
+
+// --------------------------------------------------------------------------
+// SendEventToObservers
+// --------------------------------------------------------------------------
+//
+template <class NotifyFunc, class ParamType1, class ParamType2>
+void SendEventToObservers( MVPbkContactViewBase& aView, 
+        RPointerArray<MVPbkContactViewObserver>& aObservers,
+        NotifyFunc aNotifyFunc, ParamType1 aParam1, const ParamType2& aParam2 )
+    {
+    const TInt count = aObservers.Count();
+    for (TInt i = count - 1; i >= 0; --i)
+        {
+        MVPbkContactViewObserver* observer = aObservers[i];
+        (observer->*aNotifyFunc)(aView, aParam1, aParam2);
+        }
+    }
+
+} /// namespace
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::CSubViewData::~CSubViewData
+// --------------------------------------------------------------------------
+//
+CVPbkCompositeContactView::CSubViewData::~CSubViewData()
+    {
+    delete iView;
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::CVPbkCompositeContactView
+// --------------------------------------------------------------------------
+//
+CVPbkCompositeContactView::CVPbkCompositeContactView() :
+        iAsyncOperation( CActive::EPriorityStandard ),
+        iObservers( KObserverArrayGranularity )
+    {
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::~CVPbkCompositeContactView
+// --------------------------------------------------------------------------
+//
+CVPbkCompositeContactView::~CVPbkCompositeContactView()
+    {    
+    delete iCompositePolicy;
+    delete iSortOrder;
+    iSubViews.ResetAndDestroy();
+    iObservers.Close();
+    iContactMapping.Reset();
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::BaseConstructL
+// --------------------------------------------------------------------------
+//
+void CVPbkCompositeContactView::BaseConstructL
+        (const MVPbkFieldTypeList& aSortOrder)
+    {
+    // Create sort order
+    iSortOrder = CVPbkSortOrder::NewL(aSortOrder);
+
+    // Always apply internal policy
+    iCompositePolicy = 
+            CVPbkInternalCompositeViewPolicy::NewL( *this, iObservers );
+
+    // External policy's view event buffering mechanism does not work when
+    // native contact views reside in a separate process, therefore we
+    // always apply internal policy.
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::AddSubViewL
+// Adds subview to this composite view.
+// --------------------------------------------------------------------------
+//
+void CVPbkCompositeContactView::AddSubViewL(MVPbkContactViewBase* aSubView, TInt  aViewId)
+    {
+    CSubViewData* subViewData =
+        new(ELeave) CSubViewData(CSubViewData::ENotKnown);
+    CleanupStack::PushL(subViewData);
+    User::LeaveIfError(iSubViews.Append(subViewData));
+    CleanupStack::Pop(subViewData);
+
+    subViewData->iView = aSubView;
+    subViewData->iViewId = aViewId;
+    }
+        
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::ActualContactCountL
+// --------------------------------------------------------------------------
+//        
+TInt CVPbkCompositeContactView::ActualContactCountL() const
+    {
+    const TInt subViewCount = iSubViews.Count();
+    TInt contactCount = 0;
+    for (TInt i = 0; i < subViewCount; ++i)
+        {
+        if ( iSubViews[i]->iState == CSubViewData::EReady )
+            {
+            if ( iSubViews[i]->iView->Type() == EVPbkCompositeView )
+                {
+                // The view can be safely casted because
+                // CVPbkCompositeContactView is VPbkEng internal
+                // and EVPbkCompositeView type view is always
+                // derived from CVPbkCompositeContactView.
+                contactCount += static_cast<CVPbkCompositeContactView*>( 
+                    iSubViews[i]->iView )->ActualContactCountL();
+                }
+            else
+                {
+                contactCount += iSubViews[i]->iView->ContactCountL();
+                }
+            }
+        }
+    return contactCount;
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::ApplyInternalCompositePolicyL
+// --------------------------------------------------------------------------
+//        
+void CVPbkCompositeContactView::ApplyInternalCompositePolicyL()
+    {
+    if ( !iCompositePolicy || !iCompositePolicy->InternalPolicy() )
+        {
+        MVPbkCompositeContactViewPolicy* newPolicy = 
+                CVPbkInternalCompositeViewPolicy::NewL( *this, iObservers );
+        delete iCompositePolicy;
+        iCompositePolicy = newPolicy;
+        }
+    }
+    
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::Type
+// Returns view type.
+// --------------------------------------------------------------------------
+//
+TVPbkContactViewType CVPbkCompositeContactView::Type() const
+    {
+    return EVPbkCompositeView;
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::ChangeSortOrderL
+// Changes sort order.
+// --------------------------------------------------------------------------
+//
+void CVPbkCompositeContactView::ChangeSortOrderL
+        (const MVPbkFieldTypeList& aSortOrder)
+    {
+    const TInt subViewCount = iSubViews.Count();
+    for (TInt i = 0; i < subViewCount; ++i)
+        {
+        // All ready subviews go to unknown state because
+        // they need to be re-sorted.
+        // State is known again when an event comes.
+        if (iSubViews[i]->iState == CSubViewData::EReady)
+            {
+            iSubViews[i]->iState = CSubViewData::ENotKnown;
+            iSubViews[i]->iView->ChangeSortOrderL(aSortOrder);
+            }
+        }
+    
+    // Create new sort order and take it in use
+    MVPbkFieldTypeList* sortOrder = CVPbkSortOrder::NewL(aSortOrder);
+    delete iSortOrder;
+    iSortOrder = sortOrder;
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::SortOrder
+// Returns current sort order.
+// --------------------------------------------------------------------------
+//
+const MVPbkFieldTypeList& CVPbkCompositeContactView::SortOrder() const
+    {
+    return *iSortOrder;
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::RefreshL
+// Refreshes all subviews
+// --------------------------------------------------------------------------
+//
+void CVPbkCompositeContactView::RefreshL()
+    {
+    const TInt subViewCount = iSubViews.Count();
+    for (TInt i = 0; i < subViewCount; ++i)
+        {
+        iSubViews[i]->iView->RefreshL();
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::ContactCountL
+// Returns contact count.
+// --------------------------------------------------------------------------
+//
+TInt CVPbkCompositeContactView::ContactCountL() const
+    {
+    return iCompositePolicy->ContactCountL();
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::ContactAtL
+// Returns contact at aIndex.
+// --------------------------------------------------------------------------
+//
+const MVPbkViewContact& CVPbkCompositeContactView::ContactAtL
+        (TInt aIndex) const
+    {
+    __ASSERT_ALWAYS(
+        aIndex >= 0, VPbkError::Panic( VPbkError::EInvalidContactIndex ) );
+    if ( aIndex >= iContactMapping.Count() )
+        {
+        User::Leave( KErrArgument );
+        }
+
+    const TContactMapping& mapping = iContactMapping[aIndex];
+    MVPbkContactViewBase* view = iSubViews[mapping.iViewIndex]->iView;
+    return view->ContactAtL( mapping.iContactIndex );
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::CreateLinkLC
+// Creates link from a contact at aIndex.
+// --------------------------------------------------------------------------
+//
+MVPbkContactLink* CVPbkCompositeContactView::CreateLinkLC(TInt aIndex) const
+    {
+    __ASSERT_ALWAYS(
+        aIndex >= 0, VPbkError::Panic( VPbkError::EInvalidContactIndex ) );
+    if ( aIndex >= iContactMapping.Count() )
+        {
+        User::Leave( KErrArgument );
+        }
+
+    const TContactMapping& mapping = iContactMapping[aIndex];
+    MVPbkContactViewBase* view = iSubViews[mapping.iViewIndex]->iView;
+    return view->CreateLinkLC( mapping.iContactIndex );
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::IndexOfLinkL
+// Returns index of aContactLink.
+// --------------------------------------------------------------------------
+//
+TInt CVPbkCompositeContactView::IndexOfLinkL
+        (const MVPbkContactLink& aContactLink) const
+    {
+    TIdentityRelation<TContactMapping> comparisonOperator
+        (&CVPbkCompositeContactView::CompareMappings);
+    TInt result = KErrNotFound;
+
+    // Search the link from all the subviews
+    const TInt subViewCount = iSubViews.Count();
+    for (TInt i = 0; i < subViewCount; ++i)
+        {
+        // Check that the view is ready before using it.
+        TInt index = KErrNotFound;
+        if (iSubViews[i]->iState == CSubViewData::EReady)
+            {
+            index = iSubViews[i]->iView->IndexOfLinkL(aContactLink);        
+            }        
+            
+        if (index != KErrNotFound)
+            {
+            // Establish contact mapping for view and contact index
+            TContactMapping mapping;
+            mapping.iViewIndex = i;
+            mapping.iContactIndex = index;
+            // Find the composite index by comparing the two mappings
+            result = iContactMapping.Find(mapping, comparisonOperator);
+            break;
+            }
+        }
+    return result;
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::AddObserverL
+// --------------------------------------------------------------------------
+//
+void CVPbkCompositeContactView::AddObserverL
+        (MVPbkContactViewObserver& aObserver)
+    {
+    // Add the observer only if it is not already added
+    TInt err( iObservers.InsertInAddressOrder(&aObserver) );
+    if ( err != KErrNone && err != KErrAlreadyExists)
+        {
+        User::Leave( err );
+        }
+
+    TRAP(err, 
+        {
+        VPbkEngUtils::MAsyncCallback* notifyObserver =
+            VPbkEngUtils::CreateAsyncCallbackLC(
+                *this, 
+                &CVPbkCompositeContactView::DoAddObserverL, 
+                &CVPbkCompositeContactView::AddObserverError, 
+                aObserver);
+        iAsyncOperation.CallbackL(notifyObserver);
+        CleanupStack::Pop(notifyObserver);
+        });
+
+    if (err != KErrNone)
+        {
+        RemoveObserver(aObserver);
+        User::Leave(err);
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::RemoveObserver
+// --------------------------------------------------------------------------
+//
+void CVPbkCompositeContactView::RemoveObserver
+        (MVPbkContactViewObserver& aObserver)
+    {
+    const TInt index = iObservers.FindInAddressOrder( &aObserver );
+    if (index != KErrNotFound)
+        {
+        iObservers.Remove(index);
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::MatchContactStore
+// Check does any of the subviews match given contact store.
+// --------------------------------------------------------------------------
+//
+TBool CVPbkCompositeContactView::MatchContactStore
+        (const TDesC& aContactStoreUri) const
+    {
+    const TInt count = iSubViews.Count();
+    TBool result = EFalse;
+    for (TInt i = 0; i < count && !result; ++i)
+        {
+        result = iSubViews[i]->iView->MatchContactStore(aContactStoreUri);
+        }
+    return result;
+    }
+    
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::MatchContactStoreDomain
+// Check does any of the subviews match given contact store domain.
+// --------------------------------------------------------------------------
+//
+
+ TBool CVPbkCompositeContactView::MatchContactStoreDomain
+        (const TDesC& aContactStoreDomain) const
+    {
+    const TInt count = iSubViews.Count();
+    TBool result = EFalse;
+    for (TInt i = 0; i < count && !result; ++i)
+        {
+        result = iSubViews[i]->iView->MatchContactStoreDomain
+            (aContactStoreDomain);
+        }
+    return result;
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::CreateBookmarkLC
+// Creates a bookmark for given index.
+// --------------------------------------------------------------------------
+//
+MVPbkContactBookmark* CVPbkCompositeContactView::CreateBookmarkLC
+        (TInt aIndex) const
+    {
+    __ASSERT_ALWAYS( aIndex >= 0, 
+        VPbkError::Panic( VPbkError::EInvalidContactIndex ) );
+    __ASSERT_DEBUG(ContactCountL() > aIndex, 
+            Panic(EPanicLogic_CreateBookmarkLC));
+
+    const TContactMapping& mapping = iContactMapping[aIndex];
+    MVPbkContactViewBase* view = iSubViews[mapping.iViewIndex]->iView;
+    return view->CreateBookmarkLC( mapping.iContactIndex );
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::IndexOfBookmarkL
+// Returns the index of given bookmark.
+// --------------------------------------------------------------------------
+//
+TInt CVPbkCompositeContactView::IndexOfBookmarkL
+        (const MVPbkContactBookmark& aContactBookmark) const
+    {
+    TIdentityRelation<TContactMapping> comparisonOperator(
+        &CVPbkCompositeContactView::CompareMappings);
+    TInt result = KErrNotFound;
+    
+    // Search the bookmark from all the subviews
+    const TInt subViewCount = iSubViews.Count();
+    for (TInt i = 0; i < subViewCount; ++i)
+        {
+        // Check that the view is ready before using it.
+        TInt index(KErrNotFound);
+        if (iSubViews[i]->iState == CSubViewData::EReady)
+            {
+            index = iSubViews[i]->iView->IndexOfBookmarkL(aContactBookmark);
+            }
+            
+        if (index != KErrNotFound)
+            {
+            // Establish contact mapping for view and contact index
+            TContactMapping mapping;
+            mapping.iViewIndex = i;
+            mapping.iContactIndex = index;
+            // Find the composite index by comparing the two mappings
+            result = iContactMapping.Find(mapping, comparisonOperator);
+            break;
+            }
+        }
+    return result;
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::ViewFiltering
+// --------------------------------------------------------------------------
+//
+MVPbkContactViewFiltering* CVPbkCompositeContactView::ViewFiltering()
+    {
+    // Composite views support filtering and is also a filtered view.
+    // The subclass must implement the interface.
+    return this;
+    }
+
+TAny* CVPbkCompositeContactView::ContactViewBaseExtension(TUid aExtensionUid)
+    {
+    MVPbkContactViewBaseChildAccessExtension* extChild = NULL;
+    if ( aExtensionUid == TUid::Uid(KVPbkViewBaseExtChildAccess) )
+        {
+        extChild = this;
+        }
+    return extChild;
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::ContactViewReady
+// --------------------------------------------------------------------------
+//
+void CVPbkCompositeContactView::ContactViewReady(MVPbkContactViewBase& aView)
+    {
+    TRAPD( res, HandleContactViewReadyL( aView ) );
+    if ( res != KErrNone )
+        {
+        // There was an error when building a composite. Reset composite
+        // inform client that this view unavailable and there is an error
+        ResetContactMapping();
+        SendViewUnavailableEvent();
+        SendViewErrorEvent( res, EFalse );
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::ContactViewUnavailable
+// --------------------------------------------------------------------------
+//
+void CVPbkCompositeContactView::ContactViewUnavailable
+        (MVPbkContactViewBase& aView)
+    {
+    TRAPD( res, HandleContactViewUnavailableL( aView ) );
+    if ( res != KErrNone )
+        {
+        // There was an error when building a composite. Reset composite
+        // inform client that this view unavailable and there is an error
+        ResetContactMapping();
+        SendViewUnavailableEvent();
+        SendViewErrorEvent( res, EFalse );
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::ContactAddedToView
+// --------------------------------------------------------------------------
+//
+void CVPbkCompositeContactView::ContactAddedToView
+        (MVPbkContactViewBase& aView, TInt aIndex,
+        const MVPbkContactLink& aContactLink)
+    {
+    TInt compositeIndex = HandleContactAddition(aView, aIndex);
+
+    TRAPD( error, iCompositePolicy->HandleViewEventsL( 
+        CVPbkEventArrayItem::EAdded, aView, compositeIndex, aContactLink ) );
+    if ( error != KErrNone )
+        {
+        // If error occurs reset policy
+        iCompositePolicy->Reset();
+        SendViewErrorEvent( error, EFalse );
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::ContactRemovedFromView
+// --------------------------------------------------------------------------
+//
+void CVPbkCompositeContactView::ContactRemovedFromView
+        (MVPbkContactViewBase& aView, TInt aIndex,
+        const MVPbkContactLink& aContactLink)
+    {
+    TInt compositeIndex( KErrNotFound );
+    compositeIndex = HandleContactRemoval(aView, aIndex);
+    TRAPD( error, iCompositePolicy->HandleViewEventsL( 
+        CVPbkEventArrayItem::ERemoved, aView, compositeIndex, 
+            aContactLink ) );
+    if ( error != KErrNone )
+        {
+        // If error occurs reset policy
+        iCompositePolicy->Reset();
+        SendViewErrorEvent( error, EFalse );
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::ContactViewError
+// --------------------------------------------------------------------------
+//
+void CVPbkCompositeContactView::ContactViewError
+        (MVPbkContactViewBase& /*aView*/, TInt aError, TBool aErrorNotified)
+    {
+    SendViewErrorEvent( aError, aErrorNotified );
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::UpdateFilterL
+// --------------------------------------------------------------------------
+//    
+void CVPbkCompositeContactView::UpdateFilterL( 
+        const MDesCArray& aFindWords,
+        const MVPbkContactBookmarkCollection* aAlwaysIncludedContacts )
+    {
+    const TInt count = iSubViews.Count();
+    for( TInt i = 0; i < count; ++i )
+        {
+        MVPbkContactViewFiltering* filtering = 
+            iSubViews[i]->iView->ViewFiltering();
+        // Check if the subview supports filtering.
+        if ( filtering )
+            {
+            // Filtering supported
+            filtering->UpdateFilterL( aFindWords, aAlwaysIncludedContacts );
+            // Set state to unknown. NOTE: this set so that the composite
+            // becomes ready state when all subviews have notified something.
+            // Otherwise the composite would notify its own observers every
+            // time a subview notifies composite. This is not wanted because
+            // client must get only one notification after update.
+            // On the other hand a client can still use this view while it's
+            // updating itself so in that point of view the composite is not
+            // in unknown state but in update state.
+            iSubViews[i]->iState = CSubViewData::ENotKnown;            
+            }
+        }
+    }
+
+TInt CVPbkCompositeContactView::ChildViewCount() const
+    {
+    return iSubViews.Count();
+    }
+
+MVPbkContactViewBase& CVPbkCompositeContactView::ChildViewAt( TInt aIndex )
+    {
+    return *iSubViews[aIndex]->iView;
+    }
+
+MVPbkContactViewBase* CVPbkCompositeContactView::GetChildViewById( TInt aId)
+    {
+    MVPbkContactViewBase* view = NULL;
+    const TInt count = iSubViews.Count();
+    for (TInt i = 0; i < count; ++i)
+        {
+        view=iSubViews[i]->iView; 
+        if (iSubViews[i]->iViewId == aId)
+           {
+           return view;
+           }
+        }
+    return NULL;
+    }
+
+TInt CVPbkCompositeContactView::GetViewId()
+    {
+     return iViewId;
+    }
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::SendViewReadyEvent
+// --------------------------------------------------------------------------
+//         
+void CVPbkCompositeContactView::SendViewReadyEvent()
+    {
+    VPBK_DEBUG_PRINT( VPBK_DEBUG_STRING(
+        "CVPbkCompositeContactView::SendViewReadyEvent(0x%x)"), this );
+    // Cancel operation to avoid unnecessary event sending in DoAddObserverL
+    iAsyncOperation.Purge();
+    SendEventToObservers( *this, iObservers,
+        &MVPbkContactViewObserver::ContactViewReady );
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::SendViewUnavailableEvent
+// --------------------------------------------------------------------------
+//        
+void CVPbkCompositeContactView::SendViewUnavailableEvent()
+    {
+    VPBK_DEBUG_PRINT( VPBK_DEBUG_STRING(
+        "CVPbkCompositeContactView::SendViewUnavailableEvent(0x%x)"), this );
+    // Cancel operation to avoid unnecessary event sending in DoAddObserverL
+    iAsyncOperation.Purge();
+    SendEventToObservers( *this, iObservers,
+        &MVPbkContactViewObserver::ContactViewUnavailable );
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::SendViewErrorEvent
+// --------------------------------------------------------------------------
+//
+void CVPbkCompositeContactView::SendViewErrorEvent( TInt aError, 
+        TBool aErrorNotified )
+    {
+    SendEventToObservers(*this, iObservers, 
+        &MVPbkContactViewObserver::ContactViewError, aError, aErrorNotified);
+    }
+    
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::CompareMappings
+// --------------------------------------------------------------------------
+//
+TBool CVPbkCompositeContactView::CompareMappings
+        (const TContactMapping& aLhs, const TContactMapping& aRhs)
+    {
+    // Mappings match if both the contact index and the view index match
+    return (aLhs.iContactIndex == aRhs.iContactIndex &&
+            aLhs.iViewIndex == aRhs.iViewIndex);
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::IsCompositeReady
+// --------------------------------------------------------------------------
+//
+TBool CVPbkCompositeContactView::IsCompositeReady() const
+    {
+    // Composite view is ready if states of all sub views are known and
+    // at least one of them is ready.
+    return AllSubViewsKnown() && AnySubViewReady();
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::CompositePolicy
+// --------------------------------------------------------------------------
+//        
+MVPbkCompositeContactViewPolicy& 
+        CVPbkCompositeContactView::CompositePolicy() const
+    {
+    return *iCompositePolicy;
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::FindSubViewIndex
+// --------------------------------------------------------------------------
+//
+TInt CVPbkCompositeContactView::FindSubViewIndex
+        (MVPbkContactViewBase& aView) const
+    {
+    TInt result = KErrNotFound;
+    const TInt count = iSubViews.Count();
+    for (TInt i = 0; i < count; ++i)
+        {
+        if (iSubViews[i]->iView == &aView)
+            {
+            result = i;
+            break;
+            }
+        }
+    return result;
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::AllSubViewsKnown
+// Returns true if all the subviews are known.
+// --------------------------------------------------------------------------
+//
+TBool CVPbkCompositeContactView::AllSubViewsKnown() const
+    {
+    TBool ret = ETrue;
+    const TInt count = iSubViews.Count();
+    for (TInt i = 0; i < count; ++i)
+        {
+        if (iSubViews[i]->iState == CSubViewData::ENotKnown)
+            {
+            ret = EFalse;
+            break;
+            }
+        }
+    return ret;
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::AnySubViewReady
+// Returns true if any of the subviews is ready.
+// --------------------------------------------------------------------------
+//
+TBool CVPbkCompositeContactView::AnySubViewReady() const
+    {
+    TBool ret = EFalse;
+    const TInt count = iSubViews.Count();
+    for (TInt i = 0; i < count; ++i)
+        {
+        if (iSubViews[i]->iState == CSubViewData::EReady)
+            {
+            ret = ETrue;
+            break;
+            }
+        }
+
+    return ret;
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::ResetContactMapping
+// --------------------------------------------------------------------------
+//    
+void CVPbkCompositeContactView::ResetContactMapping()
+    {
+    iContactMapping.Reset();
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::RemoveContactMappingsFromView
+// --------------------------------------------------------------------------
+//
+void CVPbkCompositeContactView::RemoveContactMappingsFromView( 
+        MVPbkContactViewBase& aView )
+    {
+    TInt subviewIndex = FindSubViewIndex( aView );
+    if ( subviewIndex != KErrNotFound )
+        {
+        const TInt count = iContactMapping.Count();
+        for ( TInt i = count - 1; i >= 0; --i )
+            {
+            if ( iContactMapping[i].iViewIndex == subviewIndex )
+                {
+                iContactMapping.Remove( i );
+                }
+            }
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::HandleContactViewReadyL
+// --------------------------------------------------------------------------
+//
+void CVPbkCompositeContactView::HandleContactViewReadyL( 
+        MVPbkContactViewBase& aView )
+    {
+    VPBK_DEBUG_PRINT( VPBK_DEBUG_STRING(
+        "CVPbkCompositeContactView::HandleContactViewReadyL(0x%x)"), this );
+    
+    // Find matching subview and set its state to ready
+    TInt subViewIndex = FindSubViewIndex(aView);
+    if (subViewIndex != KErrNotFound)
+        {
+        iSubViews[subViewIndex]->iState = CSubViewData::EReady;
+        }
+
+    // Check that composite's sort order up to date with subviews.
+    UpdateSortOrderL();
+    
+    // If composite is ready, build view mapping and notify observers
+    if ( IsCompositeReady() )
+        {
+        VPBK_PROFILE_START(VPbkProfile::ECompositeContactViewMapping);
+        DoBuildContactMappingL();
+        VPBK_PROFILE_END(VPbkProfile::ECompositeContactViewMapping);
+        SendViewReadyEvent();
+        }    
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::HandleContactViewUnavailableL
+// --------------------------------------------------------------------------
+//
+void CVPbkCompositeContactView::HandleContactViewUnavailableL( 
+        MVPbkContactViewBase& aView )
+    {
+    VPBK_DEBUG_PRINT( VPBK_DEBUG_STRING(
+        "CVPbkCompositeContactView::ContactViewUnavailable(0x%x)"), this );
+    
+    // Find matching subview and set its state
+    TInt subViewIndex = FindSubViewIndex(aView);
+    if (subViewIndex != KErrNotFound)
+        {
+        iSubViews[subViewIndex]->iState = CSubViewData::EUnavailable;
+        }
+
+    if ( IsCompositeReady() )
+        {
+        // Composite is still in ready state. The mapping must be updated
+        // because one of the subviews became unavailable.
+        DoBuildContactMappingL();
+        // Call observers so that they know about update.
+        SendViewReadyEvent();
+        }
+    else
+        {
+        if ( AllSubViewsKnown() )
+            {
+            // Composite is unavailable. Notify observers.
+            ResetContactMapping();
+            SendViewUnavailableEvent();
+            }
+        else
+            {
+            // Composite is still under construction.
+            
+            // Dont't send event here because the state of the composite is
+            // not yet known and sending event can cause problems for client
+            // e.g unwanted changes in the UI state.
+            RemoveContactMappingsFromView( aView );
+            }
+        }
+    }
+    
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::CVPbkCompositeContactView
+// --------------------------------------------------------------------------
+//
+TInt CVPbkCompositeContactView::HandleContactRemoval
+        ( MVPbkContactViewBase& aView, TInt aIndex )
+    {
+    TInt index = KErrNotFound;
+    
+    // Find correct subview
+    TInt subViewIndex = FindSubViewIndex( aView );
+    if ( subViewIndex != KErrNotFound )
+        {
+        TIdentityRelation<TContactMapping> comparisonOperator
+            ( &CVPbkCompositeContactView::CompareMappings );
+        // Establish contact mapping for view and contact index
+        TContactMapping mapping;
+        mapping.iViewIndex = subViewIndex;
+        mapping.iContactIndex = aIndex;
+        // Find the composite index by comparing the two mappings
+        index = iContactMapping.Find( mapping, comparisonOperator );
+        
+        if ( index > KErrNotFound )
+            {            
+            // Loop through the rest of the contacts of the subview
+            // and modify their global contact mapping information
+            for (TInt i = index; i < iContactMapping.Count(); ++i)
+                {
+                if (iContactMapping[i].iViewIndex == subViewIndex)
+                    {
+                    // Subtract one because one contact was deleted
+                    // from the list before the current index
+                    --iContactMapping[i].iContactIndex;
+                    }
+                }
+            // Finally remove the deleted index from global mapping
+            iContactMapping.Remove( index );
+            }
+        else
+            {
+            // mapping inconsistent with the underlying view, rebuild it
+            DoBuildContactMappingL();
+            }
+        }
+    return index;
+    }
+        
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::HandleContactAddition
+// --------------------------------------------------------------------------
+//
+TInt CVPbkCompositeContactView::HandleContactAddition
+        (MVPbkContactViewBase& aView, TInt aIndex)
+    {
+    TInt index = KErrNotFound;
+    
+    // Find correct subview
+    TInt subViewIndex = FindSubViewIndex(aView);
+    if (subViewIndex != KErrNotFound)
+        {
+        TRAPD( err, index = DoHandleContactAdditionL
+            ( subViewIndex, aIndex ) );
+        if (err != KErrNone)
+            {
+            index = err;
+            }
+        else 
+        	{
+        	// We have to fix the indexes of all the succeeding
+            // contacts in the view where the contact addition took place
+            for ( TInt i = index + 1; i < iContactMapping.Count(); ++i )
+                {
+                if (iContactMapping[i].iViewIndex == subViewIndex)
+                    {
+                    ++iContactMapping[i].iContactIndex;
+                    }
+                }
+        	}
+        }
+    return index;
+    }
+    
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::DoAddObserverL
+// Notifies composite view readiness to observer.
+// --------------------------------------------------------------------------
+//
+void CVPbkCompositeContactView::DoAddObserverL
+        (MVPbkContactViewObserver& aObserver)
+    {
+    // Check if aObserver is still observer of this view and the view is ready.
+    // View is considered to be ready if all subviews are ready (iIsReady)
+    // or if there are no subviews
+    if ( iObservers.FindInAddressOrder( &aObserver ) != KErrNotFound )
+        {
+        if( IsCompositeReady() )
+            {            
+            // If this view is ready and there was no error tell it to the observer            
+            aObserver.ContactViewReady(*this);            
+            }
+        else if ( AllSubViewsKnown() )
+            {
+            // All subviews are known but the composite is not ready ->
+            // view is unavailable.
+            aObserver.ContactViewUnavailable( *this );
+            }
+        // If this view was not ready and there was no error, observer will
+        // be called back in HandleContactViewEvent
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::AddObserverError
+// Notifies composite view problems to observer.
+// --------------------------------------------------------------------------
+//
+void CVPbkCompositeContactView::AddObserverError
+        (MVPbkContactViewObserver& aObserver, TInt aError)
+    {
+    // Check if aObserver is still observer of this view
+    if (iObservers.FindInAddressOrder( &aObserver ) != KErrNotFound)
+        {
+        aObserver.ContactViewError(*this, aError, EFalse);
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkCompositeContactView::UpdateSortOrderL
+// --------------------------------------------------------------------------
+//
+void CVPbkCompositeContactView::UpdateSortOrderL()
+    {
+    const MVPbkFieldTypeList* sortOrder = NULL;
+    
+    // Inspect the sort order of subviews. If all ready subviews have
+    // same sort order then update composite's sort order.
+    // This is done because subviews can be shared views whose sort order
+    // is not changed to client's sort order when a new handle is created.
+    TBool subViewsHaveSameOrder = ETrue;
+    const TInt count = iSubViews.Count();
+    for ( TInt i = 0; i < count && subViewsHaveSameOrder; ++i )
+        {
+        if ( iSubViews[i]->iState == CSubViewData::EReady )
+            {
+            const MVPbkFieldTypeList& curViewsOrder = 
+                    iSubViews[i]->iView->SortOrder();
+            if ( sortOrder )
+                {
+                subViewsHaveSameOrder = 
+                    VPbkFieldTypeList::IsSame( *sortOrder, curViewsOrder );
+                }
+            sortOrder = &curViewsOrder;
+            }
+        }
+        
+    if ( subViewsHaveSameOrder && sortOrder && 
+         !VPbkFieldTypeList::IsSame( *sortOrder, *iSortOrder ) )
+        {
+        CVPbkSortOrder* newOrder = CVPbkSortOrder::NewL( *sortOrder );
+        delete iSortOrder;
+        iSortOrder = newOrder;
+        }
+    }
+    
+void CVPbkCompositeContactView::SetViewId(TInt aViewId)
+    {
+    iViewId = aViewId;
+    }   
+// --------------------------------------------------------------------------
+// CVPbkExternalCompositeViewPolicy::CVPbkExternalCompositeViewPolicy
+// --------------------------------------------------------------------------
+//
+CVPbkExternalCompositeViewPolicy::CVPbkExternalCompositeViewPolicy( 
+        CVPbkCompositeContactView& aCompositeView,
+        RPointerArray<MVPbkContactViewObserver>& aObservers )
+        :   iCompositeView( aCompositeView ),
+            iObservers( aObservers )
+    {
+    }
+    
+// --------------------------------------------------------------------------
+// CVPbkExternalCompositeViewPolicy::NewL
+// --------------------------------------------------------------------------
+//
+CVPbkExternalCompositeViewPolicy* CVPbkExternalCompositeViewPolicy::NewL(
+        CVPbkCompositeContactView& aCompositeView,
+        RPointerArray<MVPbkContactViewObserver>& aObservers )
+    {
+    CVPbkExternalCompositeViewPolicy* self = 
+        new ( ELeave ) CVPbkExternalCompositeViewPolicy( aCompositeView, 
+            aObservers );
+    return self;
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkExternalCompositeViewPolicy::~CVPbkExternalCompositeViewPolicy
+// --------------------------------------------------------------------------
+//    
+CVPbkExternalCompositeViewPolicy::~CVPbkExternalCompositeViewPolicy()
+    {
+    iEventArray.ResetAndDestroy();
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkExternalCompositeViewPolicy::HandleViewEventsL
+// --------------------------------------------------------------------------
+//    
+void CVPbkExternalCompositeViewPolicy::HandleViewEventsL( 
+        CVPbkEventArrayItem::TViewEventType aEvent,
+        MVPbkContactViewBase& /*aSubview*/,
+        TInt aIndex, const 
+        MVPbkContactLink& aContactLink )
+    {        
+    // Append all view events to proper event array.
+    CVPbkEventArrayItem* item = 
+        CVPbkEventArrayItem::NewLC( aIndex, aContactLink, aEvent );
+            
+    iEventArray.AppendL( item );
+    CleanupStack::Pop(); // item
+    
+    // Check if the composite is up to date. Note that if the underlying
+    // native store view resides in a separate process or thread,
+    // this check may "accidentally" pass whilst the native view is still
+    // updating itself. This means that the composite might fall out of sync
+    // anytime after this check and it will then mean severe problems to the
+    // client, since if it asks for ContactCountL the answer will
+    // be zero, as the sync check is implemented in
+    // CVPbkExternalCompositeViewPolicy::ContactCountL too.
+    // The count of zero might be in severe contradiction with the
+    // view events the client just received.
+    // If the native view resides in the  same process, there are no risks.
+    if (iCompositeView.CompositeContactCountL() == 
+            iCompositeView.ActualContactCountL() )
+        {
+        // Composite mapping is valid according to contact counts. Flush
+        // the event cache.
+        TInt eventCount( iEventArray.Count() );
+                          
+        for( TInt i = 0; i < eventCount; ++i )
+            {
+            if ( iEventArray[ i ]->Event() == CVPbkEventArrayItem::ERemoved )
+                {
+                SendEventToObservers( iCompositeView, iObservers,
+                    &MVPbkContactViewObserver::ContactRemovedFromView,
+                    iEventArray[ i ]->Index(), 
+                    *iEventArray[ i ]->Link() ); 
+                }
+            else
+                {
+                SendEventToObservers( iCompositeView, iObservers,
+                    &MVPbkContactViewObserver::ContactAddedToView,
+                    iEventArray[ i ]->Index(), 
+                    *iEventArray[ i ]->Link() );                                                
+                }            
+            }                   
+        iEventArray.ResetAndDestroy();
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkExternalCompositeViewPolicy::Reset
+// --------------------------------------------------------------------------
+//    
+void CVPbkExternalCompositeViewPolicy::Reset()
+    {
+    iEventArray.ResetAndDestroy();
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkExternalCompositeViewPolicy::ContactCountL
+// --------------------------------------------------------------------------
+//    
+TInt CVPbkExternalCompositeViewPolicy::ContactCountL() const
+    {
+    TInt compositeCount = iCompositeView.CompositeContactCountL();
+    
+    if ( compositeCount != iCompositeView.ActualContactCountL() )
+        {
+        // If composite count is different as the contact count in subviews
+        // it means that composite hasn't got all view events yet and its
+        // contact mapping is not in valid state. It's too heavy to build
+        // the whole mapping so zero is returned to inform client that
+        // it must not call ContactAtL because it can panic.
+        compositeCount = 0;
+        }
+    return compositeCount;
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkExternalCompositeViewPolicy::InternalPolicy
+// --------------------------------------------------------------------------
+//    
+TBool CVPbkExternalCompositeViewPolicy::InternalPolicy() const
+    {
+    return EFalse;
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkInternalCompositeViewPolicy::CVPbkInternalCompositeViewPolicy
+// --------------------------------------------------------------------------
+//
+CVPbkInternalCompositeViewPolicy::CVPbkInternalCompositeViewPolicy( 
+        CVPbkCompositeContactView& aCompositeView,
+        RPointerArray<MVPbkContactViewObserver>& aObservers )
+        :   iCompositeView( aCompositeView ),
+            iObservers( aObservers )
+    {
+    }
+    
+// --------------------------------------------------------------------------
+// CVPbkInternalCompositeViewPolicy::NewL
+// --------------------------------------------------------------------------
+//
+CVPbkInternalCompositeViewPolicy* CVPbkInternalCompositeViewPolicy::NewL(
+        CVPbkCompositeContactView& aCompositeView,
+        RPointerArray<MVPbkContactViewObserver>& aObservers )
+    {
+    CVPbkInternalCompositeViewPolicy* self = 
+        new ( ELeave ) CVPbkInternalCompositeViewPolicy( aCompositeView, 
+            aObservers );
+    return self;
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkInternalCompositeViewPolicy::HandleViewEventsL
+// --------------------------------------------------------------------------
+//
+void CVPbkInternalCompositeViewPolicy::HandleViewEventsL( 
+        CVPbkEventArrayItem::TViewEventType aEvent,
+        MVPbkContactViewBase& /*aSubview*/,
+        TInt aIndex, const 
+        MVPbkContactLink& aContactLink )
+    {
+    if ( aEvent == CVPbkEventArrayItem::ERemoved )
+        {
+        SendEventToObservers( iCompositeView, iObservers,
+            &MVPbkContactViewObserver::ContactRemovedFromView,
+            aIndex, 
+            aContactLink ); 
+        }
+    else
+        {
+        SendEventToObservers( iCompositeView, iObservers,
+            &MVPbkContactViewObserver::ContactAddedToView,
+            aIndex, 
+            aContactLink ); 
+        }            
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkInternalCompositeViewPolicy::Reset
+// --------------------------------------------------------------------------
+//    
+void CVPbkInternalCompositeViewPolicy::Reset()
+    {
+    // No cached data to reset
+    }
+    
+// --------------------------------------------------------------------------
+// CVPbkInternalCompositeViewPolicy::ContactCountL
+// --------------------------------------------------------------------------
+//    
+TInt CVPbkInternalCompositeViewPolicy::ContactCountL() const
+    {
+    return iCompositeView.CompositeContactCountL();
+    }
+
+// --------------------------------------------------------------------------
+// CVPbkInternalCompositeViewPolicy::InternalPolicy
+// --------------------------------------------------------------------------
+//    
+TBool CVPbkInternalCompositeViewPolicy::InternalPolicy() const
+    {
+    return ETrue;
+    }
+    
+// End of File