diff -r 000000000000 -r e686773b3f54 phonebookengines/VirtualPhonebook/VPbkSimStore/src/CFindViewBase.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/phonebookengines/VirtualPhonebook/VPbkSimStore/src/CFindViewBase.cpp Tue Feb 02 10:12:17 2010 +0200 @@ -0,0 +1,760 @@ +/* +* 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: Sim store filtered contact view implementation. +* +*/ + + +#include "CFindViewBase.h" + +#include "CRefineView.h" +#include "CContactStore.h" +#include "CContactLink.h" +#include "CContactView.h" +#include "CViewContact.h" + +// Virtual Phonebook +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// System includes +#include +#include + +namespace VPbkSimStore { + +#ifdef _DEBUG +enum TCFindViewBasePanicCode + { + EPreCond_SetFindStringsL = 1 + }; + +void Panic( TCFindViewBasePanicCode aPanicCode ) + { + _LIT( KPanicText, "CFindViewBase" ); + User::Panic( KPanicText, aPanicCode ); + } +#endif // _DEBUG + +const TInt KGranularity( 4 ); + +// -------------------------------------------------------------------------- +// CFindViewBase::CFindViewBase +// -------------------------------------------------------------------------- +// +CFindViewBase::CFindViewBase( MParentViewForFiltering& aParentView, + CContactView& aAllContactsView, + TBool aOwnsMatchedContacts ) + : iParentView( aParentView ), + iAllContactsView( aAllContactsView ), + iOwnsContacts( aOwnsMatchedContacts ) + { + } + +// -------------------------------------------------------------------------- +// CFindViewBase::BaseConstructL +// -------------------------------------------------------------------------- +// +void CFindViewBase::BaseConstructL( + MVPbkContactViewObserver& aExternalViewObserver, + const MDesCArray& aFindStrings, + MVPbkContactFindPolicy& aFindPolicy ) + { + iObserverOp = + CVPbkAsyncObjectOperation::NewL(); + iFilterObsOp = + CVPbkAsyncObjectOperation::NewL(); + + // Copy find words + iFindStrings = new(ELeave)CDesCArrayFlat( KGranularity ); + SetFindStringsL( aFindStrings ); + + iCurrentContact = CViewContact::NewL( iAllContactsView, SortOrder() ); + + // Assign contact find policy + iContactFindPolicy = &aFindPolicy; + + //Create field type list + iFieldTypeRefsList = CVPbkFieldTypeRefsList::NewL(); + + // Append the observer who created the view. Events must be always send + // to this observer first. + iObservers.AppendL( &aExternalViewObserver ); + } + +// -------------------------------------------------------------------------- +// CFindViewBase::~CFindViewBase +// -------------------------------------------------------------------------- +// +CFindViewBase::~CFindViewBase() + { + delete iObserverOp; + delete iFilterObsOp; + iObservers.Close(); + iFilteringObservers.Close(); + ResetContacts(); + delete iCurrentContact; + delete iFindStrings; + delete iFieldTypeRefsList; + iParentView.RemoveFilteringObserver( *this ); + } + +// -------------------------------------------------------------------------- +// CFindViewBase::ActivateContactMatchL +// -------------------------------------------------------------------------- +// +void CFindViewBase::ActivateContactMatchL() + { + // If used from update then we must renew the observing + iParentView.RemoveFilteringObserver( *this ); + // Get the state of the parent view asynchrnounsly + iParentView.AddFilteringObserverL( *this ); + } + +// -------------------------------------------------------------------------- +// CFindViewBase::ParentObject +// -------------------------------------------------------------------------- +// +MVPbkObjectHierarchy& CFindViewBase::ParentObject() const + { + return iParentView.ParentObject(); + } + +// -------------------------------------------------------------------------- +// CFindViewBase::RefreshL +// -------------------------------------------------------------------------- +// +void CFindViewBase::RefreshL() + { + iParentView.RefreshL(); + } + +// -------------------------------------------------------------------------- +// CFindViewBase::ContactCountL +// -------------------------------------------------------------------------- +// +TInt CFindViewBase::ContactCountL() const + { + return iMatchedContacts.Count(); + } + +// -------------------------------------------------------------------------- +// CFindViewBase::ContactAtL +// -------------------------------------------------------------------------- +// +const MVPbkViewContact& CFindViewBase::ContactAtL( + TInt aIndex ) const + { + __ASSERT_ALWAYS( aIndex >= 0, + VPbkError::Panic( VPbkError::EInvalidContactIndex ) ); + if ( aIndex >= iMatchedContacts.Count() ) + { + User::Leave( KErrArgument ); + } + + iCurrentContact->SetSimContactL( *iMatchedContacts[ aIndex ] ); + return *iCurrentContact; + } + +// -------------------------------------------------------------------------- +// CFindViewBase::CreateLinkLC +// -------------------------------------------------------------------------- +// +MVPbkContactLink* CFindViewBase::CreateLinkLC( + TInt aIndex ) const + { + __ASSERT_ALWAYS( aIndex >= 0, + VPbkError::Panic(VPbkError::EInvalidContactIndex) ); + if ( aIndex >= iMatchedContacts.Count() ) + { + User::Leave( KErrArgument ); + } + + TInt simIndex = iMatchedContacts[aIndex]->SimIndex(); + return CContactLink::NewLC( iAllContactsView.Store(), simIndex ); + } + +// -------------------------------------------------------------------------- +// CFindViewBase::IndexOfLinkL +// -------------------------------------------------------------------------- +// +TInt CFindViewBase::IndexOfLinkL( + const MVPbkContactLink& aContactLink ) const + { + if ( &aContactLink.ContactStore() == &iAllContactsView.Store() ) + { + TInt simIndex = + static_cast( aContactLink ).SimIndex(); + + const TInt count( iMatchedContacts.Count() ); + for ( TInt i(0); i < count; ++i ) + { + if ( iMatchedContacts[i]->SimIndex() == simIndex ) + { + return i; + } + } + } + return KErrNotFound; + } + +// -------------------------------------------------------------------------- +// CFindViewBase::Type +// -------------------------------------------------------------------------- +// +TVPbkContactViewType CFindViewBase::Type() const + { + return iParentView.Type(); + } + +// -------------------------------------------------------------------------- +// CFindViewBase::ChangeSortOrderL +// -------------------------------------------------------------------------- +// +void CFindViewBase::ChangeSortOrderL( + const MVPbkFieldTypeList& aSortOrder ) + { + iParentView.ChangeSortOrderL( aSortOrder ); + } + +// -------------------------------------------------------------------------- +// CFindViewBase::SortOrder +// -------------------------------------------------------------------------- +// +const MVPbkFieldTypeList& CFindViewBase::SortOrder() const + { + return iParentView.SortOrder(); + } + +// -------------------------------------------------------------------------- +// CFindViewBase::AddObserverL +// -------------------------------------------------------------------------- +// +void CFindViewBase::AddObserverL( + MVPbkContactViewObserver& aObserver ) + { + CVPbkAsyncObjectCallback* callback = + VPbkEngUtils::CreateAsyncObjectCallbackLC( + *this, + &CFindViewBase::DoAddObserver, + &CFindViewBase::DoAddObserverError, + aObserver); + iObserverOp->CallbackL( callback ); + CleanupStack::Pop( callback ); + + // Insert to first position because events are send in reverse order. + // Events must be send in the same order as the observers were added. + iObservers.InsertL( &aObserver, 0 ); + } + +// -------------------------------------------------------------------------- +// CFindViewBase::RemoveObserver +// -------------------------------------------------------------------------- +// +void CFindViewBase::RemoveObserver( + MVPbkContactViewObserver& aObserver ) + { + iObserverOp->CancelCallback( &aObserver ); + const TInt index = iObservers.Find( &aObserver ); + if ( index != KErrNotFound ) + { + iObservers.Remove( index ); + } + } + +// -------------------------------------------------------------------------- +// CFindViewBase::MatchContactStore +// -------------------------------------------------------------------------- +// +TBool CFindViewBase::MatchContactStore( + const TDesC& aContactStoreUri ) const + { + return iParentView.MatchContactStore( aContactStoreUri ); + } + +// -------------------------------------------------------------------------- +// CFindViewBase::MatchContactStoreDomain +// -------------------------------------------------------------------------- +// +TBool CFindViewBase::MatchContactStoreDomain( + const TDesC& aContactStoreDomain ) const + { + return iParentView.MatchContactStoreDomain( aContactStoreDomain ); + } + +// -------------------------------------------------------------------------- +// CFindViewBase::CreateBookmarkLC +// -------------------------------------------------------------------------- +// +MVPbkContactBookmark* CFindViewBase::CreateBookmarkLC( + TInt aIndex ) const + { + __ASSERT_ALWAYS( aIndex >= 0, + VPbkError::Panic(VPbkError::EInvalidContactIndex) ); + if ( aIndex >= iMatchedContacts.Count() ) + { + User::Leave( KErrArgument ); + } + + TInt simIndex = iMatchedContacts[aIndex]->SimIndex(); + return CContactLink::NewLC( iAllContactsView.Store(), simIndex ); + } + +// -------------------------------------------------------------------------- +// CFindViewBase::IndexOfBookmarkL +// -------------------------------------------------------------------------- +// +TInt CFindViewBase::IndexOfBookmarkL( + const MVPbkContactBookmark& aContactBookmark ) const + { + // Bookmark is implemented as a link in this store + const CContactLink* link = + dynamic_cast( &aContactBookmark ); + if ( link && ( &link->ContactStore() == &iAllContactsView.Store() ) ) + { + TInt simIndex = link->SimIndex(); + + const TInt count( iMatchedContacts.Count() ); + for ( TInt i(0); i < count; ++i ) + { + if ( iMatchedContacts[i]->SimIndex() == simIndex ) + { + return i; + } + } + } + + + return KErrNotFound; + } + +// -------------------------------------------------------------------------- +// CFindViewBase::AddFilteringObserverL +// -------------------------------------------------------------------------- +// +void CFindViewBase::AddFilteringObserverL( + MFilteredViewSupportObserver& aObserver ) + { + // Insert observer in callback function. That ensures that the observer + // will always get the event asynchronously. + + CVPbkAsyncObjectCallback* callback = + VPbkEngUtils::CreateAsyncObjectCallbackLC( + *this, + &CFindViewBase::DoAddFilteringObserverL, + &CFindViewBase::DoAddFilteringObserverError, + aObserver); + + iFilterObsOp->CallbackL( callback ); + CleanupStack::Pop( callback ); + } + +// -------------------------------------------------------------------------- +// CFindViewBase::RemoveFilteringObserver +// -------------------------------------------------------------------------- +// +void CFindViewBase::RemoveFilteringObserver( + MFilteredViewSupportObserver& aObserver ) + { + iFilterObsOp->CancelCallback( &aObserver ); + const TInt index( iFilteringObservers.Find( &aObserver ) ); + if ( index != KErrNotFound ) + { + iFilteringObservers.Remove( index ); + } + } + +// -------------------------------------------------------------------------- +// CFindViewBase::ViewFiltering +// -------------------------------------------------------------------------- +// +MVPbkContactViewFiltering* CFindViewBase::ViewFiltering() + { + // Find view supports further filtering using CRefineView + return this; + } + +// -------------------------------------------------------------------------- +// CFindViewBase::CreateFilteredViewLC +// -------------------------------------------------------------------------- +// +MVPbkContactViewBase* CFindViewBase::CreateFilteredViewLC( + MVPbkContactViewObserver& aObserver, + const MDesCArray& aFindWords, + const MVPbkContactBookmarkCollection* /*aAlwaysIncludedContacts*/ ) + { + // NOTE: aAlwaysIncludedContacts is commented because in VPbkSimStore + // filtered views are linked. CFindView->CRefineView->CRefineView etc. + // Only the CFindView saves the always included contacts and they + // are used also by all CRefineView instances through + // MAlwaysIncludedContacts interface. + CRefineView* refineView = CRefineView::NewLC( aFindWords, *this, + iAllContactsView, aObserver, *iContactFindPolicy, *this ); + refineView->ActivateContactMatchL(); + return refineView; + } + +// -------------------------------------------------------------------------- +// CFindViewBase::ContactViewUnavailable +// -------------------------------------------------------------------------- +// +void CFindViewBase::ContactViewUnavailable( + MVPbkContactViewBase& aView ) + { + if ( &iParentView == &aView ) + { + SendViewStateEventToObservers(); + } + } + +// -------------------------------------------------------------------------- +// CFindViewBase::ContactAddedToView +// -------------------------------------------------------------------------- +// +void CFindViewBase::ContactAddedToView( + MVPbkContactViewBase& aView, + TInt aIndex, + const MVPbkContactLink& aContactLink ) + { + TRAPD( error, HandleContactAddedToViewL( aView, aIndex, aContactLink ) ); + if ( error != KErrNone ) + { + ContactViewError( aView, error, EFalse ); + } + } + +// -------------------------------------------------------------------------- +// CFindViewBase::ContactRemovedFromView +// -------------------------------------------------------------------------- +// +void CFindViewBase::ContactRemovedFromView( + MVPbkContactViewBase& aView, + TInt aIndex, + const MVPbkContactLink& aContactLink ) + { + TRAPD( error, HandleContactRemovedFromViewL( aView, aIndex, aContactLink ) ); + if ( error != KErrNone ) + { + ContactViewError( aView, error, EFalse ); + } + } + +// -------------------------------------------------------------------------- +// CFindViewBase::ContactViewError +// -------------------------------------------------------------------------- +// +void CFindViewBase::ContactViewError( + MVPbkContactViewBase& /*aView*/, + TInt aError, + TBool aErrorNotified ) + { + // This function can be called from the parent view or from the subclass. + // In both cases this view is not usable anymore. + iViewReady = EFalse; + ResetContacts(); + + // Send first to external observers... + VPbkEng::SendEventToObservers( *this, aError, aErrorNotified, iObservers, + &MVPbkContactViewObserver::ContactViewError ); + // ...then to internal. This ensures that events come first from lower + // level find view. + VPbkEng::SendEventToObservers( *this, aError, aErrorNotified, + iFilteringObservers, &MVPbkContactViewObserver::ContactViewError ); + } + +// -------------------------------------------------------------------------- +// CFindViewBase::ContactViewUnavailableForFiltering +// -------------------------------------------------------------------------- +// +void CFindViewBase::ContactViewUnavailableForFiltering( + MParentViewForFiltering& aView ) + { + if ( &iParentView == &aView ) + { + iViewReady = EFalse; + ResetContacts(); + // Send events first to filtered views that are built on this + // view so that they can update them selves before notifying + // any external observers. + // Parent view will call ContactViewUnvailable after this and then + // the external observers will get the view event too. + VPbkEng::SendViewEventToObservers( *this, iFilteringObservers, + &MFilteredViewSupportObserver::ContactViewUnavailableForFiltering, + &MVPbkContactViewObserver::ContactViewError ); + } + } + +// -------------------------------------------------------------------------- +// CFindViewBase::MatchContactsL +// -------------------------------------------------------------------------- +// +void CFindViewBase::MatchContactsL() + { + // Destroy old matches + ResetContacts(); + // Do the match + MatchL( iMatchedContacts ); + iViewReady = ETrue; + // Send events to filtered views that are built on this + // view so that they can update them selves before notifying + // any external observers. + // It's subclass responsibility to call SendViewStateEventToObservers + // when external observers are allowed to get view event. + VPbkEng::SendViewEventToObservers( *this, iFilteringObservers, + &MFilteredViewSupportObserver::ContactViewReadyForFiltering, + &MVPbkContactViewObserver::ContactViewError ); + } + +// -------------------------------------------------------------------------- +// CFindViewBase::IsMatchL +// -------------------------------------------------------------------------- +// +TBool CFindViewBase::IsMatchL( const MVPbkViewContact& aViewContact ) + { + return iContactFindPolicy->MatchContactNameL( *iFindStrings, + aViewContact ); + } + +// -------------------------------------------------------------------------- +// CFindViewBase::FindStrings +// -------------------------------------------------------------------------- +// +const MDesCArray& CFindViewBase::FindStrings() const + { + return *iFindStrings; + } + +// -------------------------------------------------------------------------- +// CFindViewBase::SetFindStringsL +// -------------------------------------------------------------------------- +// +void CFindViewBase::SetFindStringsL( const MDesCArray& aFindStrings ) + { + __ASSERT_DEBUG( iFindStrings, Panic( EPreCond_SetFindStringsL ) ); + + iFindStrings->Reset(); + const TInt count( aFindStrings.MdcaCount() ); + for ( TInt i(0); i < count; ++i ) + { + iFindStrings->AppendL( aFindStrings.MdcaPoint( i ) ); + } + } + +// ------------------------------------------------------------------------- +// CFindViewBase::SendViewStateEventToObservers +// -------------------------------------------------------------------------- +// +void CFindViewBase::SendViewStateEventToObservers() + { + // Cancel any new AddObserverL callbacks to avoid duplicate event + // sending. + iObserverOp->Purge(); + + void (MVPbkContactViewObserver::*notifyFunc)(MVPbkContactViewBase&); + notifyFunc = &MVPbkContactViewObserver::ContactViewReady; + + if ( !iViewReady ) + { + notifyFunc = &MVPbkContactViewObserver::ContactViewUnavailable; + } + + VPbkEng::SendViewEventToObservers( *this, iObservers, + notifyFunc, &MVPbkContactViewObserver::ContactViewError ); + VPbkEng::SendViewEventToObservers( *this, iFilteringObservers, + notifyFunc, &MVPbkContactViewObserver::ContactViewError ); + } + +// -------------------------------------------------------------------------- +// CFindViewBase::DoAddObserver +// -------------------------------------------------------------------------- +// +void CFindViewBase::DoAddObserver( MVPbkContactViewObserver& aObserver ) + { + if (iViewReady) + { + // If this view is ready and there was no error, + // tell it to the observer + aObserver.ContactViewReady( *this ); + } + else + { + aObserver.ContactViewUnavailable( *this ); + } + } + +// -------------------------------------------------------------------------- +// CFindViewBase::DoAddObserverError +// -------------------------------------------------------------------------- +// +void CFindViewBase::DoAddObserverError( + MVPbkContactViewObserver& /*aObserver*/, TInt /*aError*/ ) + { + // Empty implementation + } + +// -------------------------------------------------------------------------- +// CFindViewBase::DoAddFilteringObserverL +// -------------------------------------------------------------------------- +// +void CFindViewBase::DoAddFilteringObserverL( + MFilteredViewSupportObserver& aObserver ) + { + // Insert to first position because events are send in reverse order. + iFilteringObservers.InsertL( &aObserver, 0 ); + + if (iViewReady) + { + aObserver.ContactViewReadyForFiltering( *this ); + aObserver.ContactViewReady( *this ); + } + else + { + aObserver.ContactViewUnavailableForFiltering( *this ); + aObserver.ContactViewUnavailable( *this ); + } + } + +// -------------------------------------------------------------------------- +// CFindViewBase::DoAddFilteringObserverError +// -------------------------------------------------------------------------- +// +void CFindViewBase::DoAddFilteringObserverError( + MFilteredViewSupportObserver& aObserver, TInt aError ) + { + aObserver.ContactViewError( *this, aError, EFalse ); + } + +// -------------------------------------------------------------------------- +// CFindViewBase::HandleContactAddedToViewL +// -------------------------------------------------------------------------- +// +void CFindViewBase::HandleContactAddedToViewL( MVPbkContactViewBase& aView, + TInt aIndex, const MVPbkContactLink& aContactLink ) + { + if ( &iParentView == &aView ) + { + // Let sub class do the addition if needed + DoContactAddedToViewL( aView, aIndex, aContactLink, + iMatchedContacts ); + + // Get the index of the new contact in this view. + TInt index( IndexOfLinkL( aContactLink ) ); + if ( index != KErrNotFound ) + { + VPbkEng::SendViewEventToObservers( *this, index, aContactLink, + iObservers, + &MVPbkContactViewObserver::ContactAddedToView, + &MVPbkContactViewObserver::ContactViewError ); + VPbkEng::SendViewEventToObservers( *this, index, aContactLink, + iFilteringObservers, + &MVPbkContactViewObserver::ContactAddedToView, + &MVPbkContactViewObserver::ContactViewError ); + } + } + } + +// -------------------------------------------------------------------------- +// CFindViewBase::HandleContactRemovedFromViewL +// -------------------------------------------------------------------------- +// +void CFindViewBase::HandleContactRemovedFromViewL( + MVPbkContactViewBase& aView, TInt /*aIndex*/, const + MVPbkContactLink& aContactLink ) + { + if ( &iParentView == &aView ) + { + // We know that link is always VPbkSimStore::CContactLink + const CContactLink& link = + static_cast(aContactLink); + + TInt index = KErrNotFound; + MVPbkSimContact* removedContact = NULL; + const TInt simIndex = link.SimIndex(); + const TInt count( iMatchedContacts.Count() ); + for ( TInt i= 0; i < count && !removedContact; ++i ) + { + MVPbkSimContact* contact = iMatchedContacts[i]; + + // Filter away the removed contact + if ( contact->SimIndex() == simIndex ) + { + // Remove contact from the array + iMatchedContacts.Remove( i ); + // Save the removed index for the observers + index = i; + // At this point nobody owns removedContact. + removedContact = contact; + } + } + TBool takeCareOfOwnership = (removedContact && iOwnsContacts); + + // Notice: we can not delete the contact instance before + // all observers have received the event. This is because + // in case of CRefineView, iMatchedContacts contains references + // to MVPbkSimContact instances. If we delete the contact + // before notifying observer then the there will be invalid + // pointer. + if ( takeCareOfOwnership ) + { + CleanupDeletePushL( removedContact ); + } + + if ( index != KErrNotFound ) + { + VPbkEng::SendViewEventToObservers( *this, index, aContactLink, + iObservers, + &MVPbkContactViewObserver::ContactRemovedFromView, + &MVPbkContactViewObserver::ContactViewError ); + VPbkEng::SendViewEventToObservers( *this, index, aContactLink, + iFilteringObservers, + &MVPbkContactViewObserver::ContactRemovedFromView, + &MVPbkContactViewObserver::ContactViewError ); + } + + if ( takeCareOfOwnership) + { + // After all observers have received the Removed -event, it's + // safe to actually destroy the contact. + CleanupStack::PopAndDestroy(); // removedContact + } + } + } + + +// -------------------------------------------------------------------------- +// CFindViewBase::ResetContacts +// -------------------------------------------------------------------------- +// +void CFindViewBase::ResetContacts() + { + if ( iOwnsContacts ) + { + iMatchedContacts.ResetAndDestroy(); + } + else + { + iMatchedContacts.Reset(); + } + } +} // namespace VPbkSimStore +// End of File