--- a/phonebookui/Phonebook2/UIControls/src/CPbk2AdaptiveSearchGridFiller.cpp Tue May 11 16:00:21 2010 +0300
+++ b/phonebookui/Phonebook2/UIControls/src/CPbk2AdaptiveSearchGridFiller.cpp Tue May 25 12:26:45 2010 +0300
@@ -29,7 +29,7 @@
const TInt KMaxAdaptiveGridCacheCount = 10;
const TInt KAdaptiveSearchKeyMapGranularity = 100;
-const TInt KAdaptiveSearchRefineStep = 10;
+const TInt KAdaptiveSearchRefineStep = 25;
const TInt KContactFormattingFlags = MPbk2ContactNameFormatter::EPreserveLeadingSpaces |
MPbk2ContactNameFormatter::EReplaceNonGraphicChars |
MPbk2ContactNameFormatter::EDisableCompanyNameSeparator;
@@ -63,12 +63,12 @@
iKeyMap = aKeyMap.AllocL();
}
- const TDesC& FindText() const
+ const TDesC& GetFindText() const
{
return *iFindText;
}
- const TDesC& KeyMap() const
+ const TDesC& GetKeyMap() const
{
return *iKeyMap;
}
@@ -92,6 +92,7 @@
CPbk2AdaptiveSearchGridFiller::~CPbk2AdaptiveSearchGridFiller()
{
Cancel();
+ delete iGridWaiter;
delete iKeyMap;
delete iCurrentGrid;
iAdaptiveGridCache.ResetAndDestroy();
@@ -124,6 +125,7 @@
{
iKeyMap = HBufC::NewL( KAdaptiveSearchKeyMapGranularity );
iFindUtil = CFindUtil::NewL();
+ iGridWaiter = CPbk2AdaptiveSearchGridWaiter::NewL( *this );
}
void CPbk2AdaptiveSearchGridFiller::StartFilling( const MVPbkContactViewBase& aView, const TDesC& aSearchString )
@@ -132,7 +134,8 @@
if( keyMap )
{
- iSearchField.SetAdaptiveGridChars( keyMap->KeyMap() );
+ iSearchField.SetAdaptiveGridChars( keyMap->GetKeyMap() );
+ iGridWaiter->Stop();
return;
}
@@ -143,7 +146,7 @@
// If there is no search word, the user is not searching any contacts
// so we should reset the array to prepare for the next searching.
- if ( iSearchString->Length()== 0 )
+ if ( iSearchString->Length() == 0 )
{
iDigraphContactsTitleArray.ResetAndDestroy();
}
@@ -151,7 +154,6 @@
iKeyMap->Des().Zero();
-
iCounter = 0;
SetActive();
@@ -174,13 +176,16 @@
TInt stopCount = iCounter + KAdaptiveSearchRefineStep;
const TInt itemCount = iView->ContactCountL();
- TInt maxSpacesNumber = 0;
-
if( stopCount > itemCount )
{
stopCount = itemCount;
}
+ TInt maxSpacesNumber = 0;
+
+ CDesC16Array* searchWordsArray = SplitSearchFieldTextIntoArrayLC( *iSearchString );
+ TInt searchStringSpacesNumber = searchWordsArray->MdcaCount() - 1;
+
for( ; iCounter < stopCount; iCounter++ )
{
const MVPbkViewContact& contact = iView->ContactAtL( iCounter );
@@ -210,7 +215,7 @@
}
CleanupStack::PushL( title );
- BuildGridL( *title, *iSearchString, iKeyMap );
+ BuildGridL( *title, searchWordsArray, iKeyMap );
// check number of spaces in the contact title
TInt numberOfSpaces = NumberOfSpacesInString( *title );
@@ -227,7 +232,7 @@
}
else
{
- CleanupStack::PopAndDestroy(); //title
+ CleanupStack::PopAndDestroy( title );
}
}
// If there are titles in array, we should add them to build grids again,
@@ -238,14 +243,15 @@
for( TInt i(0); i < iDigraphContactsTitleArray.Count() ; i++ )
{
TPtr ptrContactsTitle = iDigraphContactsTitleArray[i]->Des();
- BuildGridL( ptrContactsTitle, *iSearchString, iKeyMap );
+ BuildGridL( ptrContactsTitle, searchWordsArray, iKeyMap );
}
}
+ CleanupStack::PopAndDestroy( searchWordsArray ); //searchWordsArray
if( stopCount == itemCount )
{
- SetAdaptiveGridCharsL( maxSpacesNumber );
+ SetAdaptiveGridCharsL( maxSpacesNumber, searchStringSpacesNumber );
AddKeyMapToCacheL( *iSearchString, *iKeyMap );
}
else
@@ -274,7 +280,8 @@
for( TInt i( 0 ); i < count; i++ )
{
- if( !aFindText.Compare( iAdaptiveGridCache[i]->FindText() ) )
+ if( iAdaptiveGridCache[i] != NULL
+ && !aFindText.Compare( iAdaptiveGridCache[i]->GetFindText() ) )
{
return iAdaptiveGridCache[i];
}
@@ -285,17 +292,40 @@
void CPbk2AdaptiveSearchGridFiller::AddKeyMapToCacheL( const TDesC& aFindText, const TDesC& aKeyMap )
{
- CPbk2AdaptiveGrid* keyMap = new( ELeave )CPbk2AdaptiveGrid;
- CleanupStack::PushL( keyMap );
- keyMap->SetKeyMapL( aFindText, aKeyMap );
- iAdaptiveGridCache.InsertL( keyMap, 0 );
- CleanupStack::Pop();//keyMap
+ CPbk2AdaptiveGrid* keyMap = new( ELeave )CPbk2AdaptiveGrid;
+ CleanupStack::PushL( keyMap );
+ keyMap->SetKeyMapL( aFindText, aKeyMap );
+
+ // Keep always in the cache at position 0 the grid cache element for empty find box,
+ // which is the one that requires more time to be built
+ if ( aFindText.Length() == 0 )
+ {
+ if ( iAdaptiveGridCache.Count() > 0 )
+ {
+ delete iAdaptiveGridCache[0];
+ iAdaptiveGridCache.Remove( 0 );
+ }
- if( iAdaptiveGridCache.Count() > KMaxAdaptiveGridCacheCount )
- {
- delete iAdaptiveGridCache[0];
- iAdaptiveGridCache.Remove( 0 );
- }
+ iAdaptiveGridCache.InsertL( keyMap, 0 );
+ }
+ else
+ {
+ if ( iAdaptiveGridCache.Count() == 0 )
+ {
+ iAdaptiveGridCache.InsertL( NULL, 0 );
+ }
+
+ iAdaptiveGridCache.InsertL( keyMap, 1 );
+
+ // Delete oldest cache element
+ if( iAdaptiveGridCache.Count() > KMaxAdaptiveGridCacheCount )
+ {
+ delete iAdaptiveGridCache[KMaxAdaptiveGridCacheCount];
+ iAdaptiveGridCache.Remove( KMaxAdaptiveGridCacheCount );
+ }
+ }
+
+ CleanupStack::Pop(); //keyMap
}
void CPbk2AdaptiveSearchGridFiller::ClearCache()
@@ -311,6 +341,7 @@
void CPbk2AdaptiveSearchGridFiller::InvalidateAdaptiveSearchGrid()
{
iInvalidateAdaptiveSearchGrid = ETrue;
+ iGridWaiter->Start();
}
void CPbk2AdaptiveSearchGridFiller::SetFocusToAdaptiveSearchGrid()
@@ -318,11 +349,12 @@
iSetFocusToSearchGrid = ETrue;
}
-void CPbk2AdaptiveSearchGridFiller::SetAdaptiveGridCharsL( const TInt aMaxSpacesNumber )
+void CPbk2AdaptiveSearchGridFiller::SetAdaptiveGridCharsL(
+ const TInt aMaxSpacesNumber, const TInt aSearchStringSpacesNumber )
{
TPtr ptr = iKeyMap->Des();
- //To do upper case for all characters
+ // Do upper case for all characters
ptr.UpperCase();
CDesCArray* array = new (ELeave) CDesCArrayFlat( KAdaptiveSearchKeyMapGranularity );
CleanupStack::PushL( array );
@@ -337,21 +369,17 @@
array->Sort( ECmpCollated );
ptr.Zero();
- // Add space character only if user typed already some characters
- // in the find pane and more spaces can be found in contacts than
- // in the current search string.
- TInt searchTextLength = iSearchField.TextLength();
- HBufC* searchText = HBufC::NewL( searchTextLength );
- TPtr ptrSearchText = searchText->Des();
- iSearchField.GetSearchText( ptrSearchText );
- if ( searchTextLength > 0
- && NumberOfSpacesInString( ptrSearchText ) < aMaxSpacesNumber )
+ // Add space character only if:
+ // - user typed already some characters in the find pane,
+ // - and more spaces can be found in contacts than in the current search string,
+ // - and space is not the last character in the search string.
+ if ( iSearchString->Length() > 0
+ && aMaxSpacesNumber > aSearchStringSpacesNumber
+ && (*iSearchString)[iSearchString->Length() - 1] != TChar( ' ' ) )
{
ptr.Append( TChar( ' ' ) );
}
- delete searchText;
- searchText = NULL;
-
+
for( TInt ii = 0; ii < length; ii++ )
{
ptr.Append(array->MdcaPoint( ii ));
@@ -368,17 +396,22 @@
//if grid hasn't been invalidated, we do not need to set it again
return;
}
-
}
}
- iInvalidateAdaptiveSearchGrid = EFalse;
-
delete iCurrentGrid;
iCurrentGrid = NULL;
iCurrentGrid = iKeyMap->Des().AllocL();
iSearchField.SetAdaptiveGridChars( *iKeyMap );
+
+ if( iInvalidateAdaptiveSearchGrid )
+ {
+ iGridWaiter->Stop();
+ }
+
+ iInvalidateAdaptiveSearchGrid = EFalse;
+
if ( iSetFocusToSearchGrid )
{
// set the focus to findbox
@@ -392,120 +425,149 @@
CDesC16Array* CPbk2AdaptiveSearchGridFiller::SplitContactFieldTextIntoArrayLC(
const TDesC& aText )
{
- const TInt KGranularity = 2;
+ // Attempt to minimize the allocations considering 3 words for the search fields:
+ // FirstName, LastName, CompanyName.
+ const TInt KGranularity = 2; // Attempt to minimize the allocations
+
CDesCArrayFlat* array = new ( ELeave ) CDesCArrayFlat( KGranularity );
CleanupStack::PushL( array );
const TInt textLength = aText.Length();
- for ( TInt beg = 0; beg < textLength; ++beg )
+ for ( TInt beg = 0; beg < textLength; beg++ )
{
// Skip separators before next word
- if ( !iNameFormatter.IsFindSeparatorChar( aText[beg] ) )
+ if ( iNameFormatter.IsFindSeparatorChar( aText[beg] ) )
{
- // Scan the end of the word
- TInt end = beg;
- for (; end < textLength &&
- !iNameFormatter.IsFindSeparatorChar( aText[end] );
- ++end )
- {
- }
- const TInt len = end - beg;
- // Append found word to the array
- array->AppendL( aText.Mid( beg,len ) );
- // Scan for next word
- beg = end;
+ continue;
}
+
+ // Scan till the end of the word
+ TInt end;
+ for ( end = beg + 1;
+ end < textLength && !iNameFormatter.IsFindSeparatorChar( aText[end] );
+ ++end )
+ {
+ }
+
+ // Append found word to the array
+ array->AppendL( aText.Mid( beg, end - beg) );
+
+ // Scan for next word
+ beg = end;
}
- if ( array->MdcaCount() == 0 && textLength > 0 )
- {
- // aText is all word separator characters
- // -> make a "word" out of those
- array->AppendL( aText );
- }
return array;
}
-
-
-void CPbk2AdaptiveSearchGridFiller::BuildGridL( const TDesC& aContactTitle, const TDesC& aSearchString, HBufC*& aKeyMap )
- {
- CDesC16Array* contactTitles = SplitContactFieldTextIntoArrayLC( aContactTitle );
- CDesC16Array* searchWords = SplitContactFieldTextIntoArrayLC( aSearchString );
+CDesC16Array* CPbk2AdaptiveSearchGridFiller::SplitSearchFieldTextIntoArrayLC(
+ const TDesC& aText )
+ {
+ CDesC16Array* searchWordsArray = SplitContactFieldTextIntoArrayLC( aText );
- //in searchWords list, the last term is the only one which generates new keymap characters
- //other ones are used only for matching
+ // In searchWordsArray, the last word is the only one which generates new keymap characters
+ // for the grid; the other words are used only for matching the contact words.
+ //
+ // KNullDesC fake word as last word in search string will match all contact words so that all
+ // initials of contact words will be put into the grid.
+ // We do this in case the search string is empty or the last character is a space separator.
+
+ if( searchWordsArray->MdcaCount() == 0 ||
+ ( aText.Length() > 0 && aText[aText.Length() - 1] == TChar(' ') ) )
+ {
+ searchWordsArray->AppendL( KNullDesC );
+ }
- if( searchWords->MdcaCount() == 0 )
- {
- searchWords->AppendL( KNullDesC );
- }
+ return searchWordsArray;
+ }
- if( aSearchString.Length() > 0 )
- {
- if( aSearchString[ aSearchString.Length() - 1 ] == TChar( ' ' ) )
- {
- //because we now start new search term, we must add KNullDesC so we
- //can find the matching new words
- searchWords->AppendL( KNullDesC );
- }
- }
+void CPbk2AdaptiveSearchGridFiller::BuildGridL( const TDesC& aContactString, const CDesC16Array* aSearchWords, HBufC*& aKeyMap )
+ {
+ CDesC16Array* contactWords = SplitContactFieldTextIntoArrayLC( aContactString );
+
+ const TInt contactWordCount = contactWords->MdcaCount();
+ const TInt searchWordCount = aSearchWords->MdcaCount();
+ TPtrC searchWord;
+ TPtrC contactWord;
- const TInt searchWordCount = searchWords->MdcaCount();
+ // Try to make as fast algorithm as possible if there is only one search word,
+ // which is the most common case
+ if ( searchWordCount == 1 )
+ {
+ searchWord.Set( aSearchWords->MdcaPoint( 0 ) ); // Search word
- TBool contactMatch( searchWordCount == 1 );
-
- for( TInt i( 0 ); i < searchWordCount; i++ )
- {
- TInt contactTitleCount = contactTitles->MdcaCount();
-
- TBool contactTitleMatch( EFalse );
-
- for( TInt j( 0 ); j < contactTitleCount; j++ )
- {
- TPtrC searchWord = searchWords->MdcaPoint( i );
- TPtrC contactTitle = contactTitles->MdcaPoint( j );
+ for( TInt j = 0; j < contactWordCount; j++ )
+ {
+ contactWord.Set( contactWords->MdcaPoint( j ) );
+
+ iFindUtil->Interface()->MatchAdaptiveRefineL( contactWord, searchWord, aKeyMap );
+ }
+ }
+
+ // The clients of this method will provide at least one search word, so 0 is unexpected
+ else if ( searchWordCount > 1 )
+ {
+ RArray<TBool> contactWordsMatchedArray;
+ contactWordsMatchedArray.ReserveL( contactWordCount );
+ for ( TInt i = 0; i < contactWordCount; ++i )
+ {
+ contactWordsMatchedArray.AppendL( EFalse );
+ }
- const TBool lastSearchWord = ( i == searchWordCount - 1 );
+ TBool matched = ETrue;
- TBool match( EFalse );
+ // Scan search words except for the last one
+ for ( TInt i = 0; matched && i < searchWordCount - 1; i++ )
+ {
+ searchWord.Set( aSearchWords->MdcaPoint( i ) );
- if( lastSearchWord )
- {
- if( !contactMatch )
- {
- //none of the previous words didin't match, so why this is not filtered?
- //marked contact!?
- }
- else
- {
- match = iFindUtil->Interface()->MatchAdaptiveRefineL( contactTitle, searchWord, aKeyMap );
- }
- }
- else
- {
- match = iFindUtil->Interface()->MatchRefineL( contactTitle, searchWord );
- }
+ matched = EFalse; // Search word not matched yet
+
+ // Check if the search word is matched in the contact
+ for( TInt j = 0; !matched && j < contactWordCount; j++ )
+ {
+ contactWord.Set( contactWords->MdcaPoint( j ) );
+
+ // Partially or fully matched
+ if ( iFindUtil->Interface()->MatchRefineL( contactWord, searchWord ) )
+ {
+ // Allow one search word to match only one contact word.
+ // This could be done better if both search and grid creation would
+ // work in the same way for contacts matching...
+ // Example: Contact: "Dim Din Dit"
+ // Search: "DIN DI"
+ // - DIN is matched fully
+ // - DI is matched partially and assigned to "Dim"
+ // - The grid will show "_T" instead of "_MT"
+ contactWordsMatchedArray[j] = ETrue;
+ matched = ETrue;
+ }
+ }
+ }
- if( match )
- {
-
- if( !contactTitleMatch )
- {
- contactTitles->Delete( j );
- //allow one search word to take away only one contactTitle
- contactTitleMatch = ETrue;
- //for loop must go from first contact title to last
- //to be consistent with match functionality of VPbk.
- j--; contactTitleCount--;
- }
- contactMatch = ETrue;
- }
- }
-
- }
-
- CleanupStack::PopAndDestroy( 2 );//contactTitle, searchWords
+ // If all search words before the last one matched (fully or partially),
+ // add characters to the grid using last search word.
+ if ( matched )
+ {
+ searchWord.Set( aSearchWords->MdcaPoint( searchWordCount - 1 ) ); // Last search word
+
+ for( TInt j = 0; j < contactWordCount; j++ )
+ {
+ // skip Contact words matched by previous search words
+ if (contactWordsMatchedArray[j])
+ {
+ continue;
+ }
+
+ contactWord.Set( contactWords->MdcaPoint( j ) );
+
+ iFindUtil->Interface()->MatchAdaptiveRefineL( contactWord, searchWord, aKeyMap );
+ }
+ }
+
+ contactWordsMatchedArray.Close();
+ }
+
+ CleanupStack::PopAndDestroy( contactWords );
}
TInt CPbk2AdaptiveSearchGridFiller::NumberOfSpacesInString(
@@ -545,4 +607,21 @@
}
return isDigraphic;
}
+
+void CPbk2AdaptiveSearchGridFiller::GridDelayCompleteL()
+ {
+ // simulating pointer event to hide adaptive grid
+ TPointerEvent pointerEvent;
+ pointerEvent.iType = TPointerEvent::EButton1Down;
+ TPoint position = iSearchField.Rect().iTl;
+ position.iX += 1;
+ position.iY += 1;
+ pointerEvent.iPosition = position;
+ iSearchField.HandlePointerEventL( pointerEvent );
+ }
+
+void CPbk2AdaptiveSearchGridFiller::WaitNoteDismissed()
+ {
+ iSearchField.ShowAdaptiveSearchGrid();
+ }
// End of File