diff -r 000000000000 -r e686773b3f54 phonebookengines/VirtualPhonebook/VPbkEng/src/CVPbkCompositeContactView.cpp --- /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 +#include +#include +#include +#include "CVPbkEventArrayItem.h" +#include + +// Debugging headers +#include +#include + +/// 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 +void SendEventToObservers( MVPbkContactViewBase& aView, + RPointerArray& 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 +void SendEventToObservers( MVPbkContactViewBase& aView, + RPointerArray& 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( + 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 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 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 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& aObservers ) + : iCompositeView( aCompositeView ), + iObservers( aObservers ) + { + } + +// -------------------------------------------------------------------------- +// CVPbkExternalCompositeViewPolicy::NewL +// -------------------------------------------------------------------------- +// +CVPbkExternalCompositeViewPolicy* CVPbkExternalCompositeViewPolicy::NewL( + CVPbkCompositeContactView& aCompositeView, + RPointerArray& 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& aObservers ) + : iCompositeView( aCompositeView ), + iObservers( aObservers ) + { + } + +// -------------------------------------------------------------------------- +// CVPbkInternalCompositeViewPolicy::NewL +// -------------------------------------------------------------------------- +// +CVPbkInternalCompositeViewPolicy* CVPbkInternalCompositeViewPolicy::NewL( + CVPbkCompositeContactView& aCompositeView, + RPointerArray& 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