diff -r 5b6f26637ad3 -r f4a778e096c2 phonebookui/Phonebook2/UIControls/src/cpbk2predictiveviewstack.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/phonebookui/Phonebook2/UIControls/src/cpbk2predictiveviewstack.cpp Wed Sep 01 12:29:52 2010 +0100 @@ -0,0 +1,1418 @@ +/* +* Copyright (c) 2005-2007 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: Phonebook 2 Predictive search view stack +* +*/ + +#include "CPbk2ContactPositionInfo.h" +#include "cpbk2predictiveviewstack.h" + +// Phonebook 2 / Virtual Phonebook +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cpbk2filteredviewstack.h" +#include +#include +#include +#include "CPbk2PredictiveSearchFilter.h" +#include +#include + +// Predictive seard engine headers +#include +#include +#include +#include + +// Debugging headers +#include +#include +#include +#include "Phonebook2PrivateCRKeys.h" + + +// System includes +#include +#include +// CONSTANTS +const TInt Kspace = ' '; +_LIT(KPsGroupDBSuffix, "?id=%d"); + +/// Unnamed namespace for local definitions +namespace { + + + + +// -------------------------------------------------------------------------- +// SendEventToObservers +// Sends events to the array of observes that take MVPbkContactViewBase. +// as a parameter. +// +// @param aView The parameter for the NotifyFunc. +// @param aObservers An array of MVPbkContactViewObservers. +// @param aNotifyFunc A member function pointer of the +// MVPbkContactViewObserver. +// -------------------------------------------------------------------------- +// +template +void SendEventToObservers( MVPbkContactViewBase& aView, + RPointerArray& aObservers, + NotifyFunc aNotifyFunc ) + { + const TInt count = aObservers.Count(); + for (TInt i = count-1; i >= 0 ; --i) + { + Observer* observer = aObservers[i]; + (observer->*aNotifyFunc)(aView); + } + } + +// -------------------------------------------------------------------------- +// SendEventToObservers +// Sends events to the array of MVPbkContactViewObserver. +// Used for MVPbkContactViewObserver functions that have two extra parameters +// in addition to MVPbkContactViewBase. +// +// @param aView The first parameter for the NotifyFunc. +// @param aObservers An array of MVPbkContactViewObserver. +// @param aNotifyFunc A member function pointer of the +// MVPbkContactViewObserver. +// @param aParam1 The second parameter for the aNotifyFunc. +// @param aParam2 The third parameter for the aNotifyFunc. +// -------------------------------------------------------------------------- +// +template +void SendEventToObservers( MVPbkContactViewBase& aView, + RPointerArray& aObservers, + FuncPtr aNotifyFunc, + ParamType1 aParam1, ParamType2& aParam2) + { + const TInt count = aObservers.Count(); + for (TInt i = count-1; i >= 0 ; --i) + { + Observer* observer = aObservers[i]; + (observer->*aNotifyFunc)(aView, aParam1, aParam2); + } + } + +} /// namespace + +TInt CPbk2ContactPositionInfo::CompareByPosition( + const CPbk2ContactPositionInfo& aFirst, + const CPbk2ContactPositionInfo& aSecond ) + { + if( aFirst.iPos < aSecond.iPos ) + { + return -1; + } + else if( aFirst.iPos == aSecond.iPos ) + { + return 0; + } + else + { + return 1; + } + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::CPbk2PredictiveViewStack +// -------------------------------------------------------------------------- +CPbk2PredictiveViewStack::CPbk2PredictiveViewStack( CPbk2PredictiveSearchFilter& aSearchFilter, + MPbk2ContactNameFormatter& aNameformatter ): + CActive( EPriorityStandard ), iSearchFilter( aSearchFilter ), + iNameformatter(aNameformatter), + iNonMatchedMarkedContactStartIndex(KErrNotFound), + iNonMatchedMarkedContactEndIndex(KErrNotFound) + { + CActiveScheduler::Add( this ); + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::~CPbk2PredictiveViewStack +// -------------------------------------------------------------------------- +// +CPbk2PredictiveViewStack::~CPbk2PredictiveViewStack() + { + Cancel(); + iBidiPatterns.ResetAndDestroy(); + iPatternsCollection.ResetAndDestroy(); + iStackObservers.Reset(); + iViewObservers.Reset(); + delete iConverterDefaultStore; + delete iPsQuery; + delete iPsHandler; + delete iCurrentGroupLink; + if ( iBaseView ) + { + iBaseView->RemoveObserver( *this ); + } + + if( iPredictiveSearchResultContactLinkArrray ) + { + iPredictiveSearchResultContactLinkArrray->ResetAndDestroy(); + delete iPredictiveSearchResultContactLinkArrray; + } + + iTopContactPositionInfoArray.ResetAndDestroy(); + iMarkedContactsPositionInfoArray.ResetAndDestroy(); + + delete iTopContactManager; + iSearchText.Close(); + if(iFeatureManagerInitilized) + { + FeatureManager::UnInitializeLib(); + } + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::NewL +// -------------------------------------------------------------------------- +// +CPbk2PredictiveViewStack* CPbk2PredictiveViewStack::NewL( + MVPbkContactViewBase& aBaseView, + CPbk2PredictiveSearchFilter& aSearchFilter, + MPbk2ContactNameFormatter& aNameformatter ) + { + CPbk2PredictiveViewStack* self = new ( ELeave ) CPbk2PredictiveViewStack( aSearchFilter, + aNameformatter ); + CleanupStack::PushL( self ); + self->ConstructL( aBaseView ); + CleanupStack::Pop( self ); + return self; + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::ConstructL +// -------------------------------------------------------------------------- +// +void CPbk2PredictiveViewStack::ConstructL( MVPbkContactViewBase& aBaseView ) + { + PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING( + "CPbk2PredictiveViewStack::ConstructL")); + + iSearchedState = EFalse; + iViewReady = EFalse; + iBaseView = &aBaseView; + + // Initialize feature manager + FeatureManager::InitializeLibL(); + iFeatureManagerInitilized = ETrue; + // Initilize the PCS engine + InitializePCSEngineL(); + + CVPbkContactManager& manager = Phonebook2::Pbk2AppUi()-> + ApplicationServices().ContactManager(); + + iTopContactManager = CVPbkTopContactManager::NewL( manager ); + + // Arrary for holding the search result links + iPredictiveSearchResultContactLinkArrray = CVPbkContactLinkArray::NewL(); + + // Start listening view events + iBaseView->AddObserverL( *this ); + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::UpdateFilterL +// -------------------------------------------------------------------------- +// +void CPbk2PredictiveViewStack::UpdateFilterL( const MDesCArray& aFindStrings, + const MVPbkContactBookmarkCollection* aAlwaysincluded, + TBool aAlwaysIncludedChanged ) + { + if ( aAlwaysIncludedChanged ) + { + // iBookMarkCollection is not owned + iBookMarkCollection = + const_cast( aAlwaysincluded ); + } + + iPredictiveSearch = iSearchFilter.IsPredictiveActivated(); + + TKeyboardModes pcsKeyboardMode( EItut ); + if ( iPredictiveSearch ) + { + pcsKeyboardMode = EItut; + } + else + { + pcsKeyboardMode = EQwerty; + } + + // During filtering if there were multitaps, Fep transacton is broken + // and search box sends canceletion of last tap, we ignore this. + if( iPredictiveSearch && iSearchFilter.IsFiltering() ) + { + return; + } + + RBuf searchText; + iSearchFilter.GetSearchTextL( searchText ); + CleanupClosePushL( searchText ); + // Events go on up and down key, it is not good do search always twice + TInt compareSearchText = iSearchText.Compare(searchText); + + iSearchText.Close(); + iSearchText.CreateL(searchText.Length()); + iSearchText = searchText; + + CleanupStack::PopAndDestroy(&searchText); + + if( compareSearchText == 0 ) + { + return; + } + + if( !aFindStrings.MdcaCount() ) + { + if( compareSearchText == 1 ) + { + if( !iSearchText.Length() ) + { + Reset(); + } + else + { + ClearSearch(); + } + } + return; + } + + // Delete the previous query + delete iPsQuery; + iPsQuery = NULL; + + // Create the new search query + iPsQuery = CPsQuery::NewL(); + + // Combine the search strings and create the PCS query + for ( TInt j = 0; j < aFindStrings.MdcaCount(); j++ ) + { + HBufC* searchString = aFindStrings.MdcaPoint(j).AllocL(); + TPtrC searchStringPtr(*searchString); + CleanupStack::PushL( searchString ); + + for ( TInt i = 0; i < searchStringPtr.Length(); i++ ) + { + // Add a query item + CPsQueryItem* item = CPsQueryItem::NewL(); + item->SetCharacter(searchStringPtr[i]); + + TInt qwertyNumber = KErrCancel; + if( iPredictiveSearch ) + { + TLex numberVal( searchStringPtr.Mid(i, 1) ); + TInt num = 0; + qwertyNumber = numberVal.Val(num); + } + if( qwertyNumber == KErrNone ) + { + // Set qwerty search mode (in predictive search we can tap numbers only by long tap) + item->SetMode( EQwerty ); + } + else + { + // Set current search mode + item->SetMode( pcsKeyboardMode ); + } + + iPsQuery->AppendL(*item); + } + + //Add a space in between two words + if(aFindStrings.MdcaCount() > 1) + { + CPsQueryItem* item = CPsQueryItem::NewL(); + item->SetCharacter(Kspace); + item->SetMode(EItut); + iPsQuery->AppendL(*item); + } + + //Cleanup + CleanupStack::PopAndDestroy( searchString); + } + + //Send the search query to the PCS engine + iPsHandler->SearchL(*iPsQuery); + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::Reset +// -------------------------------------------------------------------------- +// +void CPbk2PredictiveViewStack::Reset() + { + PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING( + "CPbk2PredictiveViewStack::Reset: topview(0x%x), current stack level = %d")); + TRAP_IGNORE(iSearchFilter.ResetL()); + iPsHandler->CancelSearch(); + ClearSearch(); + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::ClearSearch +// -------------------------------------------------------------------------- +// +void CPbk2PredictiveViewStack::ClearSearch() + { + iNonMatchedMarkedContactStartIndex = KErrNotFound; + iNonMatchedMarkedContactEndIndex = KErrNotFound; + iSearchedState = EFalse; + iPredictiveSearchResultContactLinkArrray->ResetAndDestroy(); + iTopContactPositionInfoArray.ResetAndDestroy(); + iSearchText.Close(); + SendTopViewChangedEvent( *iBaseView ); + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::BaseView +// -------------------------------------------------------------------------- +// +MVPbkContactViewBase& CPbk2PredictiveViewStack::BaseView() const + { + return *iBaseView; + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::SetNewBaseViewL +// -------------------------------------------------------------------------- +// +void CPbk2PredictiveViewStack::SetNewBaseViewL( + MVPbkContactViewBase& aBaseView ) + { + Reset(); + + // Remove observering the old base view + if ( iBaseView ) + { + iBaseView->RemoveObserver( *this ); + } + + iBaseView = &aBaseView; + + // Start listening to new base view + iBaseView->AddObserverL( *this ); + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::Level +// -------------------------------------------------------------------------- +// +TInt CPbk2PredictiveViewStack::Level() const + { + if ( iSearchedState ) + { + return 1; + } + + return 0; + } + + +// -------------------------------------------------------------------------- +// CPbk2FilteredViewStack::AddStackObserverL +// -------------------------------------------------------------------------- +void CPbk2PredictiveViewStack::AddStackObserverL( + MPbk2FilteredViewStackObserver& aStackObserver ) + { + iStackObservers.AppendL( &aStackObserver ); + } + +// -------------------------------------------------------------------------- +// CPbk2FilteredViewStack::RemoveStackObserver +// -------------------------------------------------------------------------- +// +void CPbk2PredictiveViewStack::RemoveStackObserver( + MPbk2FilteredViewStackObserver& aStackObserver ) + { + TInt index = iStackObservers.Find( &aStackObserver ); + if ( index != KErrNotFound ) + { + iStackObservers.Remove( index ); + } + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::Type +// -------------------------------------------------------------------------- +// +TVPbkContactViewType CPbk2PredictiveViewStack::Type() const + { + return iBaseView->Type(); + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::ChangeSortOrderL +// -------------------------------------------------------------------------- +// +void CPbk2PredictiveViewStack::ChangeSortOrderL( + const MVPbkFieldTypeList& aSortOrder ) + { + return iBaseView->ChangeSortOrderL( aSortOrder ); + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::SortOrder +// -------------------------------------------------------------------------- +// +const MVPbkFieldTypeList& CPbk2PredictiveViewStack::SortOrder() const + { + return iBaseView->SortOrder(); + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::RefreshL +// -------------------------------------------------------------------------- +// +void CPbk2PredictiveViewStack::RefreshL() + { + return iBaseView->RefreshL(); + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::ContactCountL +// -------------------------------------------------------------------------- +// +TInt CPbk2PredictiveViewStack::ContactCountL() const + { + TInt count; + if ( iSearchedState ) + { + count = iPredictiveSearchResultContactLinkArrray->Count(); + } + else + { + count = iBaseView->ContactCountL(); + } + return count; + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::ContactAtL +// -------------------------------------------------------------------------- +// +const MVPbkViewContact& CPbk2PredictiveViewStack::ContactAtL + ( TInt aIndex ) const + { + TInt ret = BaseViewIndex( aIndex); + User::LeaveIfError( ret ); + return iBaseView->ContactAtL( ret ); + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::CreateLinkLC +// -------------------------------------------------------------------------- +// +MVPbkContactLink* CPbk2PredictiveViewStack::CreateLinkLC( TInt aIndex ) const + { + TInt ret = BaseViewIndex( aIndex); + User::LeaveIfError( ret ); + return iBaseView->CreateLinkLC( ret ); + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::IndexOfLinkL +// -------------------------------------------------------------------------- +// +TInt CPbk2PredictiveViewStack::IndexOfLinkL( + const MVPbkContactLink& aContactLink ) const + { + TInt ret = KErrNotFound; + + if ( iSearchedState ) + { + ret = iPredictiveSearchResultContactLinkArrray->Find( aContactLink ); + } + else + { + // Just return the index in the baseview + ret = iBaseView->IndexOfLinkL( aContactLink ); + } + + return ret; + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::AddObserverL +// -------------------------------------------------------------------------- +// +void CPbk2PredictiveViewStack::AddObserverL + ( MVPbkContactViewObserver& aObserver ) + { + PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING( + "CPbk2PredictiveViewStack::AddObserverL - IN")); + + if ( IsActive() ) + { + Cancel(); + } + + TRequestStatus* status = &iStatus; + User::RequestComplete( status, KErrNone ); + SetActive(); + + // Events are sent in reverse order so insert to first position. + iViewObservers.InsertL( &aObserver, 0 ); + + PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING( + "CPbk2PredictiveViewStack::AddObserverL - OUT")); + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::RemoveObserver +// -------------------------------------------------------------------------- +// +void CPbk2PredictiveViewStack::RemoveObserver( + MVPbkContactViewObserver& aObserver ) + { + PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING( + "CPbk2PredictiveViewStack::RemoveObserver - IN")); + + TInt index = iViewObservers.Find( &aObserver ); + if ( index != KErrNotFound ) + { + iViewObservers.Remove( index ); + } + + PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING( + "CPbk2PredictiveViewStack::RemoveObserver - OUT")); + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::MatchContactStore +// -------------------------------------------------------------------------- +// +TBool CPbk2PredictiveViewStack::MatchContactStore( + const TDesC& aContactStoreUri ) const + { + return iBaseView->MatchContactStore( aContactStoreUri ); + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::MatchContactStoreDomain +// -------------------------------------------------------------------------- +// +TBool CPbk2PredictiveViewStack::MatchContactStoreDomain( + const TDesC& aContactStoreDomain ) const + { + return iBaseView->MatchContactStoreDomain( aContactStoreDomain ); + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::CreateBookmarkLC +// -------------------------------------------------------------------------- +// +MVPbkContactBookmark* CPbk2PredictiveViewStack::CreateBookmarkLC( + TInt aIndex ) const + { + return iBaseView->CreateBookmarkLC( BaseViewIndex( aIndex ) ); + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::IndexOfBookmarkL +// -------------------------------------------------------------------------- +// +TInt CPbk2PredictiveViewStack::IndexOfBookmarkL( + const MVPbkContactBookmark& aContactBookmark ) const + { + TInt ret = KErrNotFound; + + if ( iSearchedState ) + { + TInt indexInBaseView = iBaseView->IndexOfBookmarkL( aContactBookmark ); + const MVPbkViewContact& contact = iBaseView->ContactAtL( indexInBaseView ); + + TInt countInSearchedResult = iPredictiveSearchResultContactLinkArrray->Count(); + + for ( TInt i = 0; i < countInSearchedResult && ret == KErrNotFound; i++ ) + { + const MVPbkContactLink& link = iPredictiveSearchResultContactLinkArrray->At( i ); + if ( link.RefersTo( contact ) ) + { + ret = i; + } + } + } + else + { + ret = iBaseView->IndexOfBookmarkL( aContactBookmark ); + } + + return ret; + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::ViewFiltering +// -------------------------------------------------------------------------- +// +MVPbkContactViewFiltering* CPbk2PredictiveViewStack::ViewFiltering() + { + // The stack itself doesn't support filtering + return NULL; + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::ContactViewReady +// -------------------------------------------------------------------------- +// +void CPbk2PredictiveViewStack::ContactViewReady( MVPbkContactViewBase& /*aView*/ ) + { + iViewReady = ETrue; + SendBaseViewChangedEvent(); + + SendEventToObservers( *this, iViewObservers, + &MVPbkContactViewObserver::ContactViewReady ); + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::ContactViewUnavailable +// -------------------------------------------------------------------------- +// +void CPbk2PredictiveViewStack::ContactViewUnavailable( + MVPbkContactViewBase& /*aView*/ ) + { + iViewReady = EFalse; + SendEventToObservers( *this, iViewObservers, + &MVPbkContactViewObserver::ContactViewUnavailable ); + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::ContactAddedToView +// -------------------------------------------------------------------------- +// +void CPbk2PredictiveViewStack::ContactAddedToView + ( MVPbkContactViewBase& aView, TInt aIndex, + const MVPbkContactLink& aContactLink ) + { + // Reset since we need to return to base view + // when a new contact is added + Reset(); + + //Send observer events + if ( iBaseView == &aView ) + { + SendEventToObservers( *this, iStackObservers, + &MPbk2FilteredViewStackObserver::ContactAddedToBaseView, aIndex, + aContactLink ); + + // Always forward only top view events to clients + SendEventToObservers( *this, iViewObservers, + &MVPbkContactViewObserver::ContactAddedToView, aIndex, + aContactLink ); + } + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::ContactRemovedFromView +// -------------------------------------------------------------------------- +// +void CPbk2PredictiveViewStack::ContactRemovedFromView + ( MVPbkContactViewBase& aView, TInt aIndex, + const MVPbkContactLink& aContactLink ) + { + TRAP_IGNORE ( HandleContactDeletionL( aView, aIndex,aContactLink ) ) + + //Send observer events + if ( iBaseView == &aView ) + { + // Always forward top view events to clients + SendEventToObservers( *this, iViewObservers, + &MVPbkContactViewObserver::ContactRemovedFromView, aIndex, + aContactLink ); + } + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::ContactViewError +// -------------------------------------------------------------------------- +// +void CPbk2PredictiveViewStack::ContactViewError + ( MVPbkContactViewBase& aView, TInt aError, TBool aErrorNotified ) + { + iViewReady = EFalse; + //Send observer events + if ( iBaseView == &aView ) + { + // Always forward only top view events to clients + SendEventToObservers( *this, iViewObservers, + &MVPbkContactViewObserver::ContactViewError, aError, + aErrorNotified ); + } + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::HandlePsResultsUpdate +// -------------------------------------------------------------------------- +void CPbk2PredictiveViewStack::HandlePsResultsUpdate( + RPointerArray& aSearchResults, + RPointerArray& searchSeqs ) + { + //set the searched state to indicate that + // predictive search view is now active + iSearchedState = ETrue; + + // update pattern array + TRAP_IGNORE( CreatePatternsL(searchSeqs) ); + + //Clean up the data stored during previous search + iPredictiveSearchResultContactLinkArrray->ResetAndDestroy(); + iTopContactPositionInfoArray.ResetAndDestroy(); + + //Calculate the search result indexes + TRAPD( err, CalculateSearchResultIndexesL( aSearchResults ) ); + if ( err != KErrNone ) + { + Reset(); + } + else + { + if ( !aSearchResults.Count() ) + { + TRAP_IGNORE( SendPSNoResultsEventL() ); + } + } + + SendTopViewChangedEvent( *this ); + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::HandlePsError +// -------------------------------------------------------------------------- +void CPbk2PredictiveViewStack::HandlePsError( TInt /*aErrorCode*/ ) + { + Reset(); + TRAP_IGNORE( InitializePCSEngineL() ); + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::CachingStatus +// -------------------------------------------------------------------------- +void CPbk2PredictiveViewStack::CachingStatus( TCachingStatus& /*aStatus*/, + TInt& /*aError*/) + { + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::RunL +// -------------------------------------------------------------------------- +// +void CPbk2PredictiveViewStack::RunL() + { + PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING( + "CPbk2PredictiveViewStack::RunL - IN")); + + if ( iViewReady ) + { + iViewObservers[0]->ContactViewReady( *this ); + } + + PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING( + "CPbk2PredictiveViewStack::RunL - OUT")); + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::DoCancel +// -------------------------------------------------------------------------- +// +void CPbk2PredictiveViewStack::DoCancel() + { + // Nothing to cancel + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::RunError +// -------------------------------------------------------------------------- +// +TInt CPbk2PredictiveViewStack::RunError( TInt aError ) + { + iViewObservers[0]->ContactViewError( *this, aError, ETrue ); + return KErrNone; + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::CalculateSearchResultIndexesL +// -------------------------------------------------------------------------- +void CPbk2PredictiveViewStack::CalculateSearchResultIndexesL( + RPointerArray& aSearchResults ) + { + __ASSERT_ALWAYS( iTopContactManager, User::Leave( KErrGeneral ) ); + + //Holds the Matched Char Seq of the First Item in the + //Nameslist View w.r.t the initiated Predictive Search + TBuf matchSeqChr; + + CVPbkContactManager& cntManager = Phonebook2::Pbk2AppUi()-> + ApplicationServices().ContactManager(); + + const TInt resultCount = aSearchResults.Count(); + for( TInt n = 0 ; n < resultCount ; ++n ) + { + // Store the view index of search results + CPsClientData* result = aSearchResults[n]; + MVPbkContactLink* contactLink = iPsHandler->ConvertToVpbkLinkLC(*result,cntManager); + + //Get the index in the base view + // We need to check if base view contains this contact + TInt posInBaseView = iBaseView->IndexOfLinkL( *contactLink ); + if ( posInBaseView != KErrNotFound ) + { + const MVPbkViewContact& contact = iBaseView->ContactAtL( posInBaseView ); + TBuf< KPsQueryMaxLen > result; + iSearchFilter.LookupL( contact, *this, iNameformatter, result ); + + if( result.Length() <= 0 ) + { + CleanupStack::Pop(); //contactLink + continue; + } + + TBool topcontact = iTopContactManager->IsTopContact( contact ); + if ( topcontact ) + { + // ownership of contactLink is transfered, CPbk2TopContactPositionInfo + // also keeps the contactLink' position from iBaseView + CPbk2ContactPositionInfo* topContactPosInfo = + CPbk2ContactPositionInfo::NewLC( contactLink, posInBaseView ); + + iTopContactPositionInfoArray.AppendL( topContactPosInfo ); + CleanupStack::Pop( topContactPosInfo ); + } + else + { + iPredictiveSearchResultContactLinkArrray->AppendL( contactLink ); + } + CleanupStack::Pop(); //contactLink + } + else + { + CleanupStack::PopAndDestroy(); //contactLink + } + } + + iNonMatchedMarkedContactStartIndex = KErrNotFound; + iNonMatchedMarkedContactEndIndex = KErrNotFound; + + //save marked contacts info to iMarkedContactsPositionInfoArray + if ( iBookMarkCollection ) + { + SaveBookmarkContatsInfoL(); + SortbyPositionInMainView( iMarkedContactsPositionInfoArray ); + iNonMatchedMarkedContactStartIndex = 0; + iNonMatchedMarkedContactEndIndex = iMarkedContactsPositionInfoArray.Count() - 1; + MoveArrayToSearchedResultTopL( iMarkedContactsPositionInfoArray ); + } + + // add those top contacts to top of the iPredictiveSearchResultContactLinkArrray, + // the order follows top contact orders in name list + SortbyPositionInMainView( iTopContactPositionInfoArray ); + if ( iNonMatchedMarkedContactStartIndex != KErrNotFound ) + { + iNonMatchedMarkedContactStartIndex += iTopContactPositionInfoArray.Count(); + iNonMatchedMarkedContactEndIndex += iTopContactPositionInfoArray.Count(); + } + MoveArrayToSearchedResultTopL( iTopContactPositionInfoArray ); + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::InitializePCSEngineL +// -------------------------------------------------------------------------- +void CPbk2PredictiveViewStack::InitializePCSEngineL() + { + if(iPsHandler) + { + delete iPsHandler; + iPsHandler = NULL; + } + // Create async request handle for predictive search engine + iPsHandler = CPSRequestHandler::NewL(); + iPsHandler->AddObserverL( this ); + + // If the iCurrentGroupLink is set, then no need to re-do the settings.It is already done. + if(iCurrentGroupLink) + { + return; + } + + RPointerArray databases; + if ( iBaseView->MatchContactStore( VPbkContactStoreUris::SimGlobalFdnUri() ) ) + { + //FDN view, initialize PS with FDN contacts only + databases.AppendL(VPbkContactStoreUris::SimGlobalFdnUri().AllocL()); + } + else + { + CPbk2StoreConfiguration& config = Phonebook2::Pbk2AppUi()->ApplicationServices().StoreConfiguration(); + CVPbkContactStoreUriArray* stores = config.SearchStoreConfigurationL(); + CleanupStack::PushL(stores); + TInt count = stores->Count(); + for ( TInt i = 0; i < count; ++i) + { + TVPbkContactStoreUriPtr uriPtr = stores->operator[](i); + databases.AppendL(uriPtr.UriDes().AllocL()); + } + CleanupStack::PopAndDestroy(); //stores + } + + + SetPsSettingL(databases); + + databases.ResetAndDestroy(); + + } + +// -------------------------------------------------------------------------- +// Maps from the search subset position index to base view index. +// @param aSearchResultIndex Index within scope of search result set. +// @return Index of the contact in base view. +// -------------------------------------------------------------------------- +TInt CPbk2PredictiveViewStack::BaseViewIndex( TInt aSearchResultIndex ) const + { + // If search is not active, the argument is actually already a base view index. + TInt index = aSearchResultIndex; + if ( iSearchedState ) + { + TRAP_IGNORE( index = + iBaseView->IndexOfLinkL( + iPredictiveSearchResultContactLinkArrray->At( aSearchResultIndex ) ) ); + } + + return index; + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::HandleContactDeletionL +// -------------------------------------------------------------------------- +void CPbk2PredictiveViewStack::HandleContactDeletionL( MVPbkContactViewBase& /*aView*/, + TInt /*aIndex*/, const MVPbkContactLink& aContactLink ) + { + + TInt removedContactPos = iPredictiveSearchResultContactLinkArrray->Find(aContactLink); + if(removedContactPos != KErrNotFound) + { + //Remove the link from iPredictiveSearchResultContactLinkArrray + iPredictiveSearchResultContactLinkArrray->Remove(removedContactPos); + } + + if (iPredictiveSearchResultContactLinkArrray->Count() == 0) + { + //clear patterns collection + iPatternsCollection.ResetAndDestroy(); + // back to name list view + iSearchFilter.FindPaneResetL(); + // Reset() must be called after iSearchFilter.FindPaneResetL() + // as it will make some judgment by the content of FindBox. + Reset(); + } + + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::SendTopViewChangedEvent +// -------------------------------------------------------------------------- +void CPbk2PredictiveViewStack::SendTopViewChangedEvent + ( MVPbkContactViewBase& aOldTopView ) + { + const TInt count = iStackObservers.Count(); + for ( TInt i = count - 1; i >= 0; --i ) + { + TRAPD( res, iStackObservers[i]->TopViewChangedL( aOldTopView ) ); + if ( res != KErrNone ) + { + PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING + ("CPbk2FilteredViewStack::SendTopViewChangedEvent:error %d"), + res ); + iStackObservers[i]->ViewStackError( res ); + } + } + } + +// -------------------------------------------------------------------------- +// CPbk2FilteredViewStack::SendTopViewUpdatedEvent +// -------------------------------------------------------------------------- +// +void CPbk2PredictiveViewStack::SendTopViewUpdatedEvent() + { + const TInt count = iStackObservers.Count(); + for ( TInt i = count - 1; i >= 0; --i ) + { + TRAPD( res, iStackObservers[i]->TopViewUpdatedL() ); + if ( res != KErrNone ) + { + PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING + ("CPbk2FilteredViewStack::SendTopViewUpdatedEvent:error %d"), + res ); + iStackObservers[i]->ViewStackError( res ); + } + } + } + +// -------------------------------------------------------------------------- +// CPbk2FilteredViewStack::SendBaseViewChangedEvent +// -------------------------------------------------------------------------- +// +void CPbk2PredictiveViewStack::SendBaseViewChangedEvent() + { + const TInt count = iStackObservers.Count(); + for ( TInt i = count - 1; i >= 0; --i ) + { + TRAPD( res, iStackObservers[i]->BaseViewChangedL() ); + if ( res != KErrNone ) + { + PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING + ("CPbk2FilteredViewStack::SendBaseViewChangedEvent:error %d"), + res ); + iStackObservers[i]->ViewStackError( res ); + } + } + } + + +// --------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::LastPCSQuery +// --------------------------------------------------------------------------- +const CPsQuery* CPbk2PredictiveViewStack::LastPCSQuery() const + { + return iSearchedState?iPsQuery:NULL; + } + + +// --------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::PSHandler +// --------------------------------------------------------------------------- +CPSRequestHandler* CPbk2PredictiveViewStack::PSHandler() const + { + return iPsHandler; + } + +// --------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::CreatePatternsL() +// --------------------------------------------------------------------------- +void CPbk2PredictiveViewStack::CreatePatternsL(RPointerArray& searchSeqs) + { + iPatternsCollection.ResetAndDestroy(); + iBidiPatterns.ResetAndDestroy(); + TBidirectionalState::TRunInfo* runInfoArray = new (ELeave)TBidirectionalState::TRunInfo[4]; + + for (TInt i = 0; i < searchSeqs.Count(); i++) + { + //create standard pattern + TInt nIndex = searchSeqs[i]->FirstIndex(); + TDesC& patternText = searchSeqs[i]->Pattern(); + CPsPattern* pattern = CPsPattern::NewL(); + iPatternsCollection.Append(pattern); + pattern->SetFirstIndex( nIndex ); + pattern->SetPatternL( patternText ); + + //create bidirectional pattern + HBufC* bidiPattern = HBufC::NewLC( patternText.Length() + TBidiLogicalToVisual::KMinCharAvailable ); + TPtr tmpPtr2 = bidiPattern->Des(); + TBidiLogicalToVisual converter2( patternText, runInfoArray, /*runInfoArrayMaxLength*/4 ) ; + converter2.Reorder(); + converter2.GetVisualLine( tmpPtr2, 0, patternText.Length(), TChar(0xffff) ); + iBidiPatterns.Append( bidiPattern ); + CleanupStack::Pop( bidiPattern ); + } + delete runInfoArray; + } + +// --------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::GetMatchingPartsL() +// Main assumption to use this method only for bidirectional +// languages and patterns +// --------------------------------------------------------------------------- +void CPbk2PredictiveViewStack::GetMatchingPartsL( const TDesC& aSearchData, + RArray& aMatchLocation) const + { + // If list of mathes empty just return + if ( iPatternsCollection.Count() == 0 ) + { + return; + } + //This method is implemented for bidirectional languages only + RBuf parserText; + parserText.CreateL(aSearchData); + parserText.CleanupClosePushL(); + TLex lexParser(parserText); + TPtrC ptr; + //parse for all words in contact information + TInt currentPos = 0; + lexParser.SkipSpace(); + currentPos = lexParser.Offset(); + for (ptr.Set(lexParser.NextToken()); ptr.Length(); ptr.Set(lexParser.NextToken()) ) + { + //loop by all patterns + for (TInt j = iBidiPatterns.Count() - 1; j >= 0; j--) + { + HBufC* pattern = iBidiPatterns[j]; + TInt pos = ptr.Find(pattern->Des()); + if ( pos != KErrNotFound) + { + //check if pattern is in th end of the string + if ( (pos + pattern->Length()) == ptr.Length() ) + { + // add math to output array + TPsMatchLocation location; + location.index = currentPos + pos; + location.length = pattern->Length(); + location.direction = TBidiText::ELeftToRight; + aMatchLocation.Append(location); + break; + } + } + } + lexParser.SkipSpace(); + currentPos = lexParser.Offset(); + } + CleanupStack::PopAndDestroy();//parserText + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::SetCurrentGroupLinkL +// -------------------------------------------------------------------------- +// +void CPbk2PredictiveViewStack::SetCurrentGroupLinkL( MVPbkContactLink* aGroupLinktoSet) + { + + //Create contactid converter instance for default store if not already exists + if(!iConverterDefaultStore) + { + CVPbkContactManager& manager = Phonebook2::Pbk2AppUi()-> + ApplicationServices().ContactManager(); + MVPbkContactStore* defaultStore = manager.ContactStoresL().Find( + VPbkContactStoreUris::DefaultCntDbUri() ); + __ASSERT_DEBUG( defaultStore, User::Panic(_L("Pbk2 vstack"), 52)); + + iConverterDefaultStore = CVPbkContactIdConverter::NewL( *defaultStore ); + } + //Delete the existing group link + if(iCurrentGroupLink) + { + delete iCurrentGroupLink; + iCurrentGroupLink = NULL; + } + + + iCurrentGroupLink = aGroupLinktoSet->CloneLC(); + CleanupStack::Pop(); + + if(iCurrentGroupLink) + { + RPointerArray databases; + RBuf storeUrl; + //CleanupResetAndDestroyPushL( databases ); + // Set max size for group URI + TInt32 maxLength = sizeof(TInt32) + KVPbkDefaultGrpDbURI().Size() + + KPsGroupDBSuffix().Size() + 2; + storeUrl.CreateL(KVPbkDefaultGrpDbURI(), maxLength); + storeUrl.CleanupClosePushL(); + + //get group id and create the url to be passed to ps engine + TInt32 id = iConverterDefaultStore->LinkToIdentifier(*iCurrentGroupLink); + storeUrl.AppendFormat(KPsGroupDBSuffix, NULL, id); + databases.AppendL(storeUrl.AllocL()); + CleanupStack::PopAndDestroy(&storeUrl); + + // Perform the search settings + SetPsSettingL(databases); + + databases.ResetAndDestroy(); + } + + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::SetPsSettingL +// -------------------------------------------------------------------------- +// +void CPbk2PredictiveViewStack::SetPsSettingL( RPointerArray& aDatabases) + { + // Perform search settings + CPsSettings* psSettings = CPsSettings::NewL(); + CleanupStack::PushL( psSettings ); + psSettings->SetSearchUrisL(aDatabases); + + RArray displayFields; + displayFields.AppendL(R_VPBK_FIELD_TYPE_FIRSTNAME); // Firstname + displayFields.AppendL(R_VPBK_FIELD_TYPE_LASTNAME); // Lastname + displayFields.AppendL(R_VPBK_FIELD_TYPE_COMPANYNAME);// Companyname + + psSettings->SetDisplayFieldsL(displayFields); + + iPsHandler->SetSearchSettingsL(*psSettings); + + //Clean up + CleanupStack::PopAndDestroy(psSettings); + displayFields.Close(); + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::SaveBookmarkContatsInfoL +// -------------------------------------------------------------------------- +// +void CPbk2PredictiveViewStack::SaveBookmarkContatsInfoL() + { + TInt count = iBookMarkCollection->Count(); + + for ( TInt i = count-1; i >= 0; i-- ) + { + const MVPbkContactBookmark& contactBookmark = + iBookMarkCollection->At( i ); + TInt indexInBaseView = iBaseView->IndexOfBookmarkL( contactBookmark ); + + if ( indexInBaseView != KErrNotFound ) + { + MVPbkContactLink* link = iBaseView->CreateLinkLC( indexInBaseView ); + + // find from Searched result + TInt indexInSearchedResult = iPredictiveSearchResultContactLinkArrray->Find( *link ); + + TInt matchingTopContactIndex = MatchingTopContactFind( indexInBaseView ); + + if ( indexInSearchedResult == KErrNotFound && + matchingTopContactIndex == KErrNotFound ) + { + const MVPbkViewContact& contact = iBaseView->ContactAtL( indexInBaseView ); + + CPbk2ContactPositionInfo* positionInfo = CPbk2ContactPositionInfo::NewLC( link, indexInBaseView ); + CleanupStack::Pop( positionInfo ); + CleanupStack::Pop(); // link + CleanupStack::PushL( positionInfo ); + + // non matching marked top contacts + if ( iTopContactManager->IsTopContact( contact ) ) + { + iTopContactPositionInfoArray.AppendL( positionInfo ); + } + else + { + // non matching marked contacts(non top) + iMarkedContactsPositionInfoArray.AppendL( positionInfo ); + } + + CleanupStack::Pop( positionInfo ); + } + else + { + CleanupStack::PopAndDestroy(); // link + } + } + } + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::MoveArrayToSearchedResultTopL +// -------------------------------------------------------------------------- +// +void CPbk2PredictiveViewStack::MoveArrayToSearchedResultTopL( + RPointerArray& aContactInfoArray ) + { + TInt posZero = 0; + TInt count = aContactInfoArray.Count(); + + for( TInt i = count-1; i >=0; i-- ) + { + CPbk2ContactPositionInfo* positionInfo = aContactInfoArray[ i ]; + + // ownership of contactLink is transferred + MVPbkContactLink* contactLink = positionInfo->ContactLink(); + CleanupStack::PushL( contactLink ); + // always insert to the top of iPredictiveSearchResultContactLinkArrray + iPredictiveSearchResultContactLinkArrray->InsertL( contactLink, posZero ); + CleanupStack::Pop( contactLink ); + // remove positionInfo from iTopContactPositionInfoArray + aContactInfoArray.Remove( i ); + delete positionInfo; + } + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::MatchingTopContactFind +// -------------------------------------------------------------------------- +// +TInt CPbk2PredictiveViewStack::MatchingTopContactFind( const TInt aIndexInBaseView ) + { + TInt ret = KErrNotFound; + + TInt topContactCount = iTopContactPositionInfoArray.Count(); + for( TInt i = 0; i < topContactCount && ret == KErrNotFound; i++ ) + { + CPbk2ContactPositionInfo* topContactPositionInfo = + iTopContactPositionInfoArray[i]; + + if ( aIndexInBaseView == topContactPositionInfo->Position() ) + { + ret = i; + } + } + return ret; + } + +// -------------------------------------------------------------------------- +// CPbk2PredictiveViewStack::SortbyPositionInMainView +// -------------------------------------------------------------------------- +// +void CPbk2PredictiveViewStack::SortbyPositionInMainView( + RPointerArray& aContactInfoArray ) + { + TLinearOrder< CPbk2ContactPositionInfo > + position( *CPbk2ContactPositionInfo::CompareByPosition ); + aContactInfoArray.Sort( position ); + } + +// -------------------------------------------------------------------------- +// CPbk2FilteredViewStack::SendPSNoResultsEventL +// -------------------------------------------------------------------------- +// +void CPbk2PredictiveViewStack::SendPSNoResultsEventL() + { + CPsQuery* lastQuery = const_cast (LastPCSQuery()); + if ( lastQuery ) + { + TDesC& strQuery = lastQuery->QueryAsStringLC(); + //Send the matched char Sequence of the first item + //to the Search Pane filter + iSearchFilter.HandlePSNoMatchL( strQuery, KNullDesC ); + CleanupStack::PopAndDestroy(); // QueryAsStringLC + } + } + +// -------------------------------------------------------------------------- +// CPbk2FilteredViewStack::IsNonMatchingMarkedContact +// -------------------------------------------------------------------------- +// +TBool CPbk2PredictiveViewStack::IsNonMatchingMarkedContact( const TInt aIndex ) + { + TBool ret = EFalse; + + if ( aIndex >= iNonMatchedMarkedContactStartIndex && + aIndex <= iNonMatchedMarkedContactEndIndex ) + { + ret = ETrue; + } + return ret; + } + +// End of File