diff -r 000000000000 -r 2f259fa3e83a uiutils/Findutil/src/FindUtilWestern.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uiutils/Findutil/src/FindUtilWestern.cpp Tue Feb 02 01:00:49 2010 +0200 @@ -0,0 +1,1385 @@ +/* +* Copyright (c) 2002-2005 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: Western Find Utilities implementation file. +* +*/ + + + + + + + + + +#include "FindUtilWestern.h" +#include +#include +#include "FindUtilKorean.h" +#include +#include +const TInt KLitTab('\t'); +const TInt KLitSpace(' '); +const TInt KLitHyphen('-'); +const TInt KLitLineFeed(8233); +const TInt KLitStar('*'); +const TInt KLitQuestion('?'); + +const TInt KMatchingBufferLength(256); +const TInt KAknStringBufferSize = 256; + +namespace { + +// --------------------------------------------------------------------------- +// IsFindWordSeparator +// --------------------------------------------------------------------------- +// +inline TBool IsFindWordSeparator(TChar aCh) + { + return aCh == KLitSpace || aCh == KLitHyphen || aCh == KLitTab || aCh == KLitLineFeed; + } + + + +void ReplaceCharacters(TDes &aDes, const TDesC &aChars, TChar aReplacement) + // + // Running time O(aDes.Length() * aChars.Length()) + // Does not change length of the string. + // + { + TInt src = 0; + TInt srclength = aDes.Length(); + while(src < srclength) + { + TChar c = aDes[src]; + if (aChars.LocateF(c) != KErrNotFound) + aDes[src] = TUint16(aReplacement); + ++src; + } + } + +inline TInt MyFindC(const TDesC &aItemString, const TDesC &aSearchText) + { + TBuf<200> searchText; + TBuf<200> itemString; + searchText.Append(aSearchText); + // The replacecharacters are to disable regexp matching provided + // by MatchC(). + _LIT(KQuestion,"?"); + _LIT(KStar,"*"); + ReplaceCharacters(searchText, KQuestion, TChar('\t')); + ReplaceCharacters(searchText, KStar, TChar('\r')); + searchText.Append(KStar); + if (aItemString.Length() < 200) + itemString.Append(aItemString); + else + itemString.Append(aItemString.Left(200)); + ReplaceCharacters(itemString, KQuestion, TChar('\t')); + ReplaceCharacters(itemString, KStar, TChar('\r')); + + + TInt length = itemString.Length(); + for(int i=0;i searchText; + TInt itemStringLength = aItemString.Length(); + + if ( aSearchText.Length() < 200 ) + { + searchText.Append( aSearchText ); + } + else + { + searchText.Append( aSearchText.Left(199) ); + } + + // To disable the wildchar matching provided by MatchC + if (aSearchText.Locate( KLitQuestion ) != KErrNotFound) + { + return IsFindMatchClassic(aItemString, aSearchText, aInputLang); + } + if (aSearchText.Locate( KLitStar ) != KErrNotFound) + { + return IsFindMatchClassic(aItemString, aSearchText, aInputLang); + } + + searchText.Append( KLitStar ); + + TInt result = KErrNone; + + for( TInt i = 0; i < itemStringLength; i++ ) + { + if ( i==0 || IsFindWordSeparator( aItemString[i-1] ) ) + { + + if(aInputLang == ELangHindi +#ifdef RD_MARATHI + || aInputLang == ELangMarathi +#endif + +#ifdef RD_HINDI_PHONETIC_INPUT + || aInputLang == KLangHindiPhonetic +#endif + ) + { + TUint flag = ( TCollationMethod::EIgnoreNone | TCollationMethod::EFoldCase | TCollationMethod::EIgnoreCombining ); + TCollationMethod m = *Mem::GetDefaultMatchingTable(); + m.iFlags |= flag; + result = aItemString.Mid(i).MatchC( searchText, &m, 3); + } + else + { + result = aItemString.Mid(i).MatchC( searchText ); + } + + if(result != KErrNotFound) + { + return ETrue; + } + } + } + + return EFalse; + } +} + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CFindUtilWestern::CFindUtilWestern +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +CFindUtilWestern::CFindUtilWestern() + { + iRepository = NULL; + iNotifyHandler = NULL; + } + +// Destructor +CFindUtilWestern::~CFindUtilWestern() + { + if ( iNotifyHandler ) + { + iNotifyHandler->StopListening(); + delete iNotifyHandler; + iNotifyHandler=NULL; + } + if(iRepository) + { + delete iRepository; + iRepository = NULL; + } + if ( iFindUtilKorean ) + { + delete iFindUtilKorean; + iFindUtilKorean = NULL; + } + if( iDigraphChars ) + { + delete iDigraphChars; + } + } + + +void CFindUtilWestern::OpenL() + { + CFindUtilBase::OpenL(); + + if(!iRepository) + { + iRepository = CRepository::NewL(KCRUidAknFep); + iRepository->Get(KAknFepInputTxtLang, iInputLanguage); + } + if(!iNotifyHandler) + { + iNotifyHandler = CCenRepNotifyHandler::NewL( *this, + *iRepository, + CCenRepNotifyHandler::EIntKey, + KAknFepInputTxtLang ); + iNotifyHandler->StartListeningL(); + } +//TSW: LYEE-7Q2GRV + if(!iFindUtilKorean) + { + iFindUtilKorean = CFindUtilKorean::NewL(); + } + } + +void CFindUtilWestern::HandleNotifyInt( TUint32 aId, TInt aNewValue ) + { + if(aId == KAknFepInputTxtLang) + iInputLanguage = aNewValue; + } + +// ----------------------------------------------------------------------------- +// CFindUtilWestern::Match +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// + +TBool CFindUtilWestern::Match(const TDesC& aContactsField, const TDesC& aWord) + { + if ( iFindUtilKorean->IsKoreanLanguage( aContactsField ) || iFindUtilKorean->IsKoreanLanguage( aWord ) ) + { + return iFindUtilKorean->Match( aContactsField, aWord ); + } + else + { + TInt numChar = 1; + if (!aContactsField.Length()) + { + _LIT( KNone, "*" ); + if( aWord.CompareC(KNone()) == 0 ) + { + return ETrue; + } + else + { + return EFalse; + } + } + if((aWord.Length() > 1) && aWord[aWord.Length()-2] == 0x200B) + { + numChar = 2; + } + if ( IsFindMatch(aContactsField, aWord.Left(aWord.Length()-numChar), iInputLanguage) ) + { + return ETrue; + } + return EFalse; + } + } + + +// ----------------------------------------------------------------------------- +// CFindUtilWestern::MatchRefineL +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +TBool CFindUtilWestern::MatchRefineL( const TDesC& aItemString, const TDesC& aSearchText ) + { + if ( iFindUtilKorean->IsKoreanLanguage( aItemString ) || iFindUtilKorean->IsKoreanLanguage( aSearchText ) ) + { + return iFindUtilKorean->MatchRefineL( aItemString, aSearchText ); + } + else + { + if ( aItemString.Length() == 0 ) + { + return EFalse; + } + + if ( aSearchText.Length() == 0 ) + { + return ETrue; + } + return IsFindMatch( aItemString, aSearchText, iInputLanguage ); + } + } + +// ----------------------------------------------------------------------------- +// CFindUtilWestern::IsWordValidForMatching +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +TBool CFindUtilWestern::IsWordValidForMatching(const TDesC& /*aWord*/) + { + return ETrue; + } + + +// ========================= FOR ADAPTIVE FIND ================================ + +// ----------------------------------------------------------------------------- +// For Vietnamese AS +// +// ----------------------------------------------------------------------------- +// +inline TChar ReplaceVietnameseChar( const TChar aCh ) + { + TChar Char = aCh.GetUpperCase(); + if ( (Char >= 0x00C0 && Char <= 0x00C3) || Char == 0x102 || + ((Char >= 0x1EA0 && Char <= 0x1EB6) && Char%2 == 0) ) + { + Char = 0x0041; // A + return Char; + } + if ( (Char >= 0x00C8 && Char <= 0x00CA) || + ((Char >= 0x1EB8 && Char <= 0x1EC6) && Char%2 == 0) ) + { + Char = 0x0045; // E + return Char; + } + if ( Char == 0x00CC || Char == 0x00CD || Char == 0x0128 || + Char == 0x1EC8 || Char == 0x1ECA ) + { + Char = 0x0049; // I + return Char; + } + if ( (Char >= 0x00D2 && Char <= 0x00D5 ) || Char == 0x1ECE || Char == 0x1ECC || + ((Char >= 0x1ED0 && Char <= 0x1ED8) && Char%2 == 0)) + { + Char = 0x004F; // O + return Char; + } + if ( Char == 0x1EDA || Char == 0x1EDC || Char == 0x1EDE || + Char == 0x1EE0 || Char == 0x1EE2 ) + { + Char = 0x01A0; // O-horn + return Char; + } + if ( Char == 0x00DA || Char == 0x00D9 || Char == 0x0168 || + Char == 0x1EE4 || Char == 0x1EE6 ) + { + Char = 0x0055; // U + return Char; + } + if ( (Char >= 0x1EE8 && Char <= 0x1EF0) && Char%2 == 0 ) + { + Char = 0x01AF; // U-horn + return Char; + } + if ( ((Char >= 0x1EF2 && Char <= 0x1EF8) && Char%2 == 0) || Char == 0x00DD ) + { + Char = 0x0059; // Y + return Char; + } + return Char; + } + + /** + * Checks current character is it special character from Vietnamese language . + * + * @since 5.0 + * @return @c ETrue If it is accent from Vietnamese language, otherwise EFalse. + */ +inline TBool IsVietnameseSpecialCharacter( TChar aCh ) + { + if ( ( aCh >= 0x0300 && aCh <= 0x0303 ) || + aCh == 0x0306 || aCh == 0x0309 || aCh == 0x0323 || aCh == 0x031B ) + { + return ETrue; + } + return EFalse; + } + +/** + * Update next characters if find pane state was changed. + * + * @since 5.0 + * @param aNextChars reference to the next characters for the adaptive search grid + * @param aCh Criteria from the search field. + */ +inline void UpdateNextCharsL( HBufC*& aNextChars, TChar aCh ) + { + TChar ch_temp = aCh; + + TLanguage lang = User::Language(); + if ( lang == ELangVietnamese ) + { + aCh = ReplaceVietnameseChar ( ch_temp ); + } + + if( ( aNextChars->Locate(aCh.GetLowerCase() ) == KErrNotFound ) && + ( aNextChars->Locate(aCh.GetUpperCase() ) == KErrNotFound ) ) + { + if( aNextChars->Des().Length() == aNextChars->Des().MaxLength() ) + { + aNextChars = aNextChars->ReAllocL( aNextChars->Des().MaxLength()+10 ); + TInt length1 = aNextChars->Des().Length(); + TInt maxlength1 = aNextChars->Des().MaxLength(); + } + aNextChars->Des().Append( aCh ); + } + } + +// ----------------------------------------------------------------------------- +// For Devanagari AS +// Checks if aCh denotes a consonant with nukta. +// @return ETrue if aCh is a consonant with nukta EFalse otherwise. +// ----------------------------------------------------------------------------- +// +inline TBool IsIndicCombinedChar( const TChar aCh ) + { + if ( aCh < 0x0900 || aCh > 0x0980 ) + { + return EFalse; + } + else + { + return ( aCh == 0x0929 || aCh == 0x0931 || aCh == 0x0934 || + (aCh >= 0x0958 && aCh <= 0x095F) ); + } + } + +// ----------------------------------------------------------------------------- +// For Devanagari AS +// Returns the correcponding character without nukta +// @param aCh - character to be stripped of nukta +// @return corresponding character with nukta +// ----------------------------------------------------------------------------- +// +inline TChar RemoveIndicNukta( const TChar aCh ) + { + switch (aCh) + { + case 0x0929 : return 0x0928; //vocallic 'nna' to 'na' + case 0x0931 : return 0x0930; //vocallic 'rra' to 'ra' + case 0x0934 : return 0x0933; //vocallic 'lllla' to 'lla' + case 0x0958 : return 0x0915; //vocallic 'qa' to 'ka' + case 0x0959 : return 0x0916; //vocallic 'khha' to 'kha' + case 0x095A : return 0x0917; //vocallic 'ghha' to 'ga' + case 0x095B : return 0x091C; //letter 'za' to 'ja' + case 0x095C : return 0x0921; //vocallic 'dddha' to 'da' + case 0x095D : return 0x0922; //vocallic 'rha' to 'ddha' + case 0x095E : return 0x092B; //letter 'fa' to 'pha' + case 0x095F : return 0x092F; //letter 'yya' to 'ya' + default : return aCh; + } + } + +// ----------------------------------------------------------------------------- +// For Devanagari AS +// Checks if the given character is a Indic consonant. +// @param aSearchChar - character to be checked. +// @return ETrue if this is an independent character EFalse otherwise +// ----------------------------------------------------------------------------- +// +inline TBool IsIndicConsonant( const TChar aSearchChar ) + { + if ( + ( aSearchChar >= 0x0915 && aSearchChar <= 0x0939 ) || + ( aSearchChar >= 0x0958 && aSearchChar <= 0x0961 ) + ) + { + return ETrue; + } + else + { + return EFalse; + } + } + +// ----------------------------------------------------------------------------- +// For Devanagari AS +// Checks if the given character is a Indic matra. +// @param aSearchChar - character to be checked. +// @return ETrue if this is an matra EFalse otherwise +// ----------------------------------------------------------------------------- +// +inline TBool IsIndicMatra( const TChar aSearchChar ) + { + if ( aSearchChar >= 0x093E && aSearchChar <= 0x094C ) + { + return ETrue; + } + else + { + return EFalse; + } + } + +// ----------------------------------------------------------------------------- +// For Devanagari AS +// Checks if the given character is a Devanagari independent character. +// @param aSearchChar - character to be checked. +// @return ETrue if this is an independent character EFalse otherwise +// ----------------------------------------------------------------------------- +// +inline TBool IsIndicIndependentChar( const TChar aSearchChar ) + { + if (( aSearchChar >= 0x0905 && aSearchChar <= 0x0939 ) || + ( aSearchChar >= 0x0958 && aSearchChar <= 0x0961 )) + { + return ETrue; + } + else + { + return EFalse; + } + } + +// ----------------------------------------------------------------------------- +// For Devanagari AS +// Checks if the passed string denotes one of the four special +// Devanagari ligatures - refer UI specs for the description of special ligatures +// @param aCharString - The string containing set of characters to be checked +// @return ETrue if a special ligature is found EFalse otherwise +// ----------------------------------------------------------------------------- +// +inline TBool IsSpecialIndicLigature( const TDesC& aCharString ) + { + TBool ret = EFalse; + if( aCharString.Length() >= 3 ) + { + if( (((aCharString[0] == 0x915) && (aCharString[1] == 0x94D)&& (aCharString[2] == 0x937)) || + ((aCharString[0] == 0x91C) && (aCharString[1] == 0x94D)&& (aCharString[2] == 0x91E)) || + ((aCharString[0] == 0x936) && (aCharString[1] == 0x94D)&& (aCharString[2] == 0x930)) || + ((aCharString[0] == 0x924) && (aCharString[1] == 0x94D)&& (aCharString[2] == 0x930))) ) + { + ret = ETrue; + } + } + return ret; + } + +// ----------------------------------------------------------------------------- +// For Devanagari AS +// Counts the number of Indic syllables in the search string +// For the purpose of supporting mixed language entries, we count each +// non-Devanagari charcter as a single syllable. +// Also replaces the place holder '-' with '*' for searching +// @param aSearchText - The search string entered so far +// @param aSearchTextLength - Number of characters in string excluding '*' +// @return the number of Devanagari syllables in aCriteria +// ----------------------------------------------------------------------------- +// +inline TInt IndicSyllableCount( HBufC* aSearchText, TInt& aSearchTextLength ) + { + TInt syllableCount = 0; + TPtr ptrSearchText = aSearchText->Des(); + TInt strLength = ptrSearchText.Length(); + for(TInt index=0 ; index < strLength ; index++) + { + if( (index) && ptrSearchText[index] == KLitHyphen && + IsIndicIndependentChar(ptrSearchText[index-1]) ) + { + syllableCount++; + ptrSearchText[index] = KLitStar; + --aSearchTextLength; + } + else if ( !IsIndicIndependentChar(ptrSearchText[index]) && ptrSearchText[index]!=0x094D ) + { + //For any other non Indic-independent-character that was entered + //through adaptive grid, we consider it as a seperate syllable. + ++syllableCount; + } + } + return syllableCount; + } + +// ----------------------------------------------------------------------------- +// For Devanagari AS +// Checks if aCriteria[aCurrentIndex] is a fallback rendered character. +// @param aCriteria - string in which we need to check. +// @param aCurrentIndex - position in string of character to be checked +// @return ETrue if aCriteria is a rendered character EFalse otherwise. +// ----------------------------------------------------------------------------- +// +inline TBool IsFallbackRenderedCharacter( const TDesC& aCriteria, TInt aCurrentIndex ) + { + if ( aCriteria[aCurrentIndex] >= 0x0900 && aCriteria[aCurrentIndex] <= 0x0980) + { + // Check for invalid Nuktas: + if ( aCriteria[aCurrentIndex] == 0x093C ) + { + // A Nukta is valid only if placed after a consonant + if ( !IsIndicConsonant(aCriteria[(aCurrentIndex-1)]) ) + { + return ETrue; + } + } + // Check for invalid Matras: + else if ( IsIndicMatra(aCriteria[aCurrentIndex]) ) + { + // These can only be placed after a consonant or a valid nukta + TChar prevChar = aCriteria[(aCurrentIndex-1)]; + if ( !(IsIndicConsonant(prevChar) || prevChar == 0x093C) ) + { + return ETrue; + } + } + // Check for invalid Modifiers: + else if ( aCriteria[aCurrentIndex] >= 0x0901 && aCriteria[aCurrentIndex] <= 0x0903) + { + //These are valid only if placed after an independent vowel or a + //consonant or a valid nukta or a valid matra. + TChar prevChar = aCriteria[(aCurrentIndex-1)]; + //if prev character is nukta or matra, it would have been already validated + if ( !(IsIndicIndependentChar(prevChar) || prevChar == 0x093C + || IsIndicMatra(prevChar) ) ) + { + return ETrue; + } + } + // Check for invalid Halant/Virama: + else if ( aCriteria[aCurrentIndex] == 0x094D ) + { + //This is valid only if placed immediately after a consonant or a valid nukta + TChar prevChar = aCriteria[(aCurrentIndex-1)]; + //if prev character is nukta, it would have been already validated + if ( !(IsIndicConsonant(prevChar) || prevChar == 0x093C) ) + { + return ETrue; + } + } + } //end of "if devanagari character range" + return EFalse; + } + +// ----------------------------------------------------------------------------- +// For Devanagari AS +// Mark the end boundary of syllables in input string +// @param aCriteria - The search/input string entered so far +// @param aStart - The start boundary of syllable to be marked +// @return the end boundary of the syllable +// ----------------------------------------------------------------------------- +// +inline TInt IndicSyllableEnd( TInt& aStart, const TDesC& aCriteria ) + { + TInt maxLength = aCriteria.Length(); + TInt endMarker(-1); + if(aStart >= (maxLength-1)) + { + aStart = endMarker = maxLength-1; + } + else + { + TInt nextCharIndex = aStart + 1 ; + TChar startingChar = aCriteria[aStart]; + if ( IsIndicIndependentChar(startingChar) ) + { + //Check if syllable contains a special ligature + if( aStart < (maxLength-2) && IsSpecialIndicLigature(aCriteria.Mid(aStart, 3)) ) + { + //Move nextCharIndex till after the 3rd symbol of special ligature. + nextCharIndex+=2; + } + //check for the next character that is a matra/halant/nukta/modifier + //Currently this check only for Devanagari characters. If other Indic language support + //is required, we will need to add to this list. + while( (nextCharIndex= 0x0901 && aCriteria[nextCharIndex] <= 0x0903 ))) //Devanagari modifier + { + //check if this is a fallback rendered character. Increment index only if it isn't: + if ( !IsFallbackRenderedCharacter(aCriteria, nextCharIndex) ) + { + ++nextCharIndex; + } + else + { + break; + } + } + } + //nextCharIndex should now be pointing to either the start of the next syllable + //or a non-Devanagari-letter. + //End marker of current syllable should be placed just before the nextCharIndex + endMarker = nextCharIndex-1; + } + return endMarker; + } + +// ----------------------------------------------------------------------------- +// For Devanagari AS +// Parses through each Devanagari-syllable in the input string. +// It will stop when we have gone through aInputSyllableCount number of syllables. +// @param aCriteria - The search string entered so far +// @param aStart - The start boundary of the last parsed syllable +// @param aEnd - The end boundary of the last parsed syllable +// ----------------------------------------------------------------------------- +// +inline void IndicSyllableBoundary( TInt& aStart, TInt& aEnd, TInt aInputSyllableCount, + const TDesC &aCriteria ) + { + TInt boundaryCount = 0; + TInt tStart = aStart = 0; + while( boundaryCount != aInputSyllableCount ) + { + aEnd = IndicSyllableEnd(tStart, aCriteria); + boundaryCount++; + aStart = tStart; + tStart = aEnd+1; + } + } + +// ----------------------------------------------------------------------------- +// For Devanagari AS +// Checks if aItemString contains atleast one Indic letter +// @param aItemString - string to be checked +// @return ETrue if aItemString contains Devanagari letter EFalse otherwise. +// ----------------------------------------------------------------------------- +// +inline TBool IsIndicWord( const TDesC& aItemString ) + { + TInt strLength = aItemString.Length(); + for ( TInt index = 0; index < strLength; ++index ) + { + if ( (aItemString[index] >= 0x900) && (aItemString[index] <= 0x980) ) + return ETrue; + } + return EFalse; + } + +// ----------------------------------------------------------------------------- +// For Devanagari AS +// Checks if the last character from aNextChars can be displayed on +// the adaptive search grid or not. For now, this filters out the Devanagari +// vowels and other special symbol which are represented by the placeholder '-'. +// @param aNextChars list of characters to be displayed on adaptive search grid +// @return ETrue last character is valid for AS Grid, else EFalse. +// ----------------------------------------------------------------------------- +// +inline TBool IsValidNextChars( const TDesC &aNextChars ) + { + TBool ret = ETrue; + if(aNextChars.Length()>0) + { + TChar ch = aNextChars[aNextChars.Length()-1]; + if( (ch >= 0x0901 && ch <= 0x0903) || (ch >= 0x093C && ch <= 0x094D) ) + { + ret = EFalse; + } + } + return ret; + } + + +// ----------------------------------------------------------------------------- +// For Devanagari AS +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +inline void UpdateNextCharsL( HBufC*& aNextChars, const TDesC& aItemString ) + { + TChar searchChar = aItemString[0]; + //Check if this is an Indic special ligature + if ( IsIndicConsonant(searchChar) && aItemString.Length() > 2 + && IsSpecialIndicLigature(aItemString) + && KErrNotFound == (*aNextChars).Find(aItemString.Mid(0,3)) ) + { + //Check if we have enough space for 3 more characters + if( aNextChars->Des().Length() >= aNextChars->Des().MaxLength()-3 ) + { + aNextChars = aNextChars->ReAllocL( aNextChars->Des().MaxLength()+10 ); + } + aNextChars->Des().Append( aItemString.Mid(0,3) ); + } + else + { + //check if this is an Indic combined Char + if ( IsIndicCombinedChar(searchChar) ) + { + searchChar = RemoveIndicNukta( searchChar ); + } + //Now update the nextChars string + TInt strLength = aNextChars->Length(); + for ( TInt i(0); i < strLength ; ++i ) + { + if ( IsSpecialIndicLigature( (*aNextChars).Mid( i ) ) ) + { + //As aItemString is not a special ligature (checked above) + //we can move directly to the 3rd character from here + i+=2; + } + else if ( searchChar.GetUpperCase() == (*aNextChars)[i] || + searchChar.GetLowerCase() == (*aNextChars)[i] ) + { + //already exists - do nothing + return; + } + //else continue the loop + } + //So this character is not yet in the list of nextChars. + if ( aNextChars->Des().Length() == aNextChars->Des().MaxLength() ) + { + aNextChars = aNextChars->ReAllocL( aNextChars->Des().MaxLength()+10 ); + } + aNextChars->Des().Append( searchChar ); + } + } + +/** + * Update next chars from the list box item text, when search field is empty. + * This need to be done for update next characters for adaptive grid + * works faster then calling IsAdaptiveFindMatch(). + * + * @since 5.0 + * @param aNextChars reference to the next characters for the adaptive search grid + * @param aItemString List box item text. + */ + +inline void UpdateNextCharsFromString( HBufC*& aNextChars, const TDesC& aItemString ) + { + TInt itemStringLength = aItemString.Length(); + + for( TInt i = 0; i < itemStringLength; i++ ) + { + if ( i == 0 || IsFindWordSeparator( aItemString[i-1] ) ) + { + //If this is an Indic letter + if ( aItemString[i] >= 0x0900 && aItemString[i] <= 0x0980 ) + { + TRAP_IGNORE( UpdateNextCharsL( aNextChars, aItemString.Mid(i) ) ); + } + else if (!(IsVietnameseSpecialCharacter( aItemString[i]))) + { + TRAP_IGNORE( UpdateNextCharsL( aNextChars, aItemString[i] ) ); + } + } + } + } + +inline TBool IsAdaptiveFindMatchClassic( const TDesC& aItemString, const TDesC& aSearchText ) + { + TPtrC itemptr = aItemString; + TPtrC searchptr = aSearchText; + + TBool match = EFalse; + + for(;;) + { + // Loop invariant: itemptr is next character from ' ' or '-' + // Loop invariant: seachptr is at beginning of searched item + + TInt val = MyFindC(itemptr,searchptr); + if (val == 0) + { + match = ETrue; + break; + } + if (val != KErrNotFound && IsFindWordSeparator(itemptr[val-1])) + { + match = ETrue; + break; + } + + // find the word separator characters from list item + TInt spacepos = itemptr.LocateF(TChar(' ')); + TInt minuspos = itemptr.LocateF(TChar('-')); + TInt tabpos = itemptr.LocateF(TChar('\t')); + if (spacepos != KErrNotFound) + { + itemptr.Set(itemptr.Mid(spacepos+1)); + } + else if (minuspos != KErrNotFound) + { + itemptr.Set(itemptr.Mid(minuspos+1)); + } + else if (tabpos != KErrNotFound) + { + itemptr.Set(itemptr.Mid(tabpos+1)); + } + else + { + match = EFalse; + break; + } + if (itemptr.Length() == 0) + { + match = EFalse; + break; + } + + } + return match; + } + +/** + * Checks the current character for special character from Thai language . + * + * @since 5.0 + * @return @c ETrue If tone mark or diatric from Thai language otherwise EFalse. + */ +inline TBool IsThaiSpecialCharacter( TChar aCh ) + { + if( ( aCh > 0xE46 && aCh < 0xE4F ) || aCh == 0xE3A ) + { + return ETrue; + } + return EFalse; + } + +/** + * Checks if @c aItemText matches @c aSearchText in the sense described in + * S60. Calls UpdateNextCharsL() if findutil is not supported. + * + * @since 5.0 + * @param aItemText list box item text. + * @param aSearchText search text. + * @param aNextChars reference to the next characters for the adaptive search grid + * @param aDigraphs digraphs and trigraph text. + * + * @return @c ETrue if list box item text matches aSearchText EFalse otherwise. + */ +inline TBool IsAdaptiveFindMatch( const TDesC& aItemString, + const TDesC& aSearchText, HBufC*& aNextChars, TInt /*aInputLang*/, const TDesC& aDigraphs ) + { + HBufC16* searchText = NULL; + TRAPD( error, searchText = HBufC16::NewL( KMatchingBufferLength ) ); + TBool wildchar = EFalse; + if ( error == KErrNone ) + { + TInt itemStringLength = aItemString.Length(); + TInt searchTextLength = aSearchText.Length(); + + if ( searchTextLength < KMatchingBufferLength ) + { + searchText->Des().Append( aSearchText ); + } + else + { + searchText->Des().Append( aSearchText.Left(KMatchingBufferLength-1) ); + } + + // To disable the wildchar matching provided by MatchC + if ( aSearchText.Locate( KLitQuestion ) != KErrNotFound || + aSearchText.Locate( KLitStar ) != KErrNotFound ) + { + wildchar = IsAdaptiveFindMatchClassic( aItemString, aSearchText ); + if ( wildchar == EFalse ) + { + delete searchText; + return wildchar; + } + else + { + TInt val; + searchText->Des().Append( KLitStar ); + for( TInt i = 0; i < itemStringLength; i++ ) + { + if ( i == 0 || IsFindWordSeparator( aItemString[i-1] ) ) + { + val = MyFindC( aItemString, aSearchText ); + if( (val == i) && (i < (itemStringLength-searchTextLength))) + { + if( !(IsThaiSpecialCharacter(aItemString[i+searchTextLength])) && !(IsVietnameseSpecialCharacter( aItemString[i+searchTextLength]) )) + { + TRAP_IGNORE( UpdateNextCharsL( aNextChars, aItemString[i+searchTextLength]) ); + } + } + } + } // for + delete searchText; + return wildchar; + } + } + + searchText->Des().Append( KLitStar ); + searchText->Des().UpperCase(); + + TBool isCommonChars = EFalse; + TInt all_result = KErrNotFound; + + TLanguage lang = User::Language(); + + for( TInt i = 0; i < itemStringLength; i++ ) + { + if ( i == 0 || IsFindWordSeparator( aItemString[i-1] ) ) + { + TInt result = KErrNotFound; + //Some vowels of Thai can not be searched with MatchC(). + if( aDigraphs.Length() != 0 || lang == ELangThai ) + { + result = aItemString.Mid(i).Match( searchText->Des() ); + } + else + { + result = aItemString.Mid(i).MatchC( searchText->Des() ); + } + + if( result != KErrNotFound ) + { + all_result = result; + if( i < (itemStringLength-searchTextLength) ) + { + if( !(IsThaiSpecialCharacter( aItemString[i+searchTextLength])) && !(IsVietnameseSpecialCharacter( aItemString[i+searchTextLength]) )) + { + TRAP_IGNORE( UpdateNextCharsL( aNextChars, aItemString[i+searchTextLength]) ); + + if ( aDigraphs.Length() != 0 ) + { + TBuf<2> digraph; + digraph.Append( aItemString[i+searchTextLength-1] ); + digraph.Append( aItemString[i+searchTextLength] ); + + if( searchTextLength == 1 ) + { + if( aDigraphs.Find( digraph ) == KErrNotFound ) + { + isCommonChars = ETrue; + } + } + else + { + TBuf<3> trigraph; + trigraph.Append( aItemString.Mid(i+searchTextLength-2,3) ); + if( digraph[0] == KLitSpace + || ( aDigraphs.Find( digraph ) == KErrNotFound + && aDigraphs.Find( trigraph ) == KErrNotFound ) ) + { + isCommonChars = ETrue; + } + } + } + } + } + else + { + isCommonChars = ETrue; + } + } + } // if (i==0 ..) + } // for + + if(aDigraphs.Length() != 0 && !isCommonChars ) + { + all_result = KErrNotFound; + } + + if( all_result != KErrNotFound ) + { + delete searchText; + return ETrue; + } + else + { + delete searchText; + return EFalse; + } + + } // if (error == KErrNone) + delete searchText; + return EFalse; + } + +// ----------------------------------------------------------------------------- +// For Devanagari AS +// Checks if @c aItemText matches @c aSearchText. +// @param aItemText list box item text. +// @param aSearchText search text. +// @param aNextChars reference to the next characters for the adaptive search grid +// @return @c ETrue if list box item text matches EFalse otherwise. +// ----------------------------------------------------------------------------- +// +inline TBool IsIndicAdaptiveFindMatch( const TDesC& aItemString, + const TDesC& aSearchText, HBufC*& aNextChars, TInt /*aInputLang*/ ) + { + HBufC16* searchText(NULL); + TRAPD( error, searchText = HBufC16::NewL( KMatchingBufferLength ) ); + if ( error == KErrNone ) + { + TInt itemStringLength = aItemString.Length(); + TInt searchTextLength = aSearchText.Length(); + + if ( searchTextLength < KMatchingBufferLength ) + { + searchText->Des().Append( aSearchText ); + } + else + { + searchText->Des().Append( aSearchText.Left(KMatchingBufferLength-1) ); + } + + TInt indicSyllableCount = -1; + if( aSearchText.Length()>0 ) + { + //This will replace all placeholder '-' symbols with '*' + indicSyllableCount = IndicSyllableCount( searchText, searchTextLength ); + } + + //Append '*' to the end if not already present. + if ( (*searchText)[searchText->Length() - 1] != KLitStar) + { + searchText->Des().Append( KLitStar ); + } + + TInt result = KErrNotFound; + + //check if the search string is found in the item string + for( TInt index = 0; index < itemStringLength; index++ ) + { + if ( index==0 || IsFindWordSeparator( aItemString[index-1] ) ) + { + TUint flag = ( TCollationMethod::EFoldCase | TCollationMethod::EIgnoreNone | TCollationMethod::EIgnoreCombining);//TCollationMethod::EIgnoreNone | + TCollationMethod collationMethod = *Mem::GetDefaultMatchingTable(); + collationMethod.iFlags |= flag; + + result = aItemString.Mid(index).MatchC( (*searchText), &collationMethod ); + + if( result != KErrNotFound ) + { + if( index <= (itemStringLength-searchTextLength) ) + { + //search for the last character in the string + //We use a TBuf instead of TChar since a special ligature is + //represented by 3 characters. Last char would be the '*' wildchar. + TBuf<4> lastChar; + TInt modifiedStrLength = searchText->Length(); + if( (*searchText)[modifiedStrLength-1] == KLitStar ) + { + //is this a special ligature? + if ( modifiedStrLength > 3 && + IsSpecialIndicLigature( (*searchText).Mid(modifiedStrLength-4) ) ) + { + lastChar = (*searchText).Mid(modifiedStrLength-4); + } + else + { + lastChar = (*searchText).Mid(modifiedStrLength-2); + } + } + else + { + //No wildchar here + lastChar = (*searchText).Mid(modifiedStrLength-1); + } + + lastChar.UpperCase(); //For latin characters as adaptive grid is always in upper case + TInt charPos = result; //aItemString.Mid(index).MatchC( searchText->Des(), &collationMethod ); + //if found position is not within the substring to be searched, return EFalse. + if( charPos == KErrNotFound) + { + delete searchText; + return EFalse; + } + + TInt tempPos = charPos; + + TInt startCount = -1 , endCount = -1; + + //TInt tempIndex(0); + //Get the position of the next syllable to be checked + IndicSyllableBoundary(startCount, endCount, indicSyllableCount, aItemString.Mid(index)); + tempPos = aItemString.Mid(index+startCount).MatchC( lastChar, &collationMethod ); + + if ( + //if found position is not within the next syllable to be searched, + //return EFalse. + ( tempPos != 0 ) + //Also check if character to be searched is a single unicode while + //the match is at the start of a special ligature + || ( !IsSpecialIndicLigature( lastChar ) && + IsSpecialIndicLigature( aItemString.Mid(index+startCount) ) ) + ) + { + delete searchText; + return EFalse; + } + + //else, continue - find the next characters to be displayed on the grid + tempPos = index + endCount + 1; + + do { + if(charPos!=KErrNotFound && (tempPos) < itemStringLength ) + { + TRAP_IGNORE( UpdateNextCharsL( aNextChars, aItemString.Mid(tempPos) ) ); + } + + //Is the found next character a consonent/independent-vowel/non-Indic character? + if ( IsValidNextChars( *aNextChars ) ) + { + //found a valid character for displaying on the grid - return from here + delete searchText; + return ETrue; + } + else //we found an invalid valid character - keep searching + { + TPtr ptr = aNextChars->Des(); + ptr.Delete(aNextChars->Length()-1,1); + //Is this a fallback rendered character? + if ( IsFallbackRenderedCharacter(aItemString, tempPos) ) + { + //Keep the entry but don't show any more characters from this word + delete searchText; + return ETrue; + } + } + } + //keep looping till we find a valid nextChar or we reach the end of the string + while(tempPos < itemStringLength ); + + } + + } // if( result != KErrNotFound ) + } // if (index==0 ..) + } // for loop + + if( result != KErrNotFound ) + { + delete searchText; + return ETrue; + } + else + { + delete searchText; + return EFalse; + } + + } // if (error == KErrNone) + delete searchText; + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CFindUtilWestern::MatchAdaptiveRefineL +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +TBool CFindUtilWestern::MatchAdaptiveRefineL( const TDesC& aItemString, + const TDesC& aSearchText, HBufC*& aNextChars ) + { + if ( aItemString.Length() == 0 ) + { + return EFalse; + } + if ( aSearchText.Length() == 0 ) + { + UpdateNextCharsFromString( aNextChars, aItemString ); + return ETrue; + } + + if( iDigraphChars == NULL ) + { + iDigraphChars = StringLoader::LoadL( R_QTN_ADS_DIGRAPH ); + TPtr digraph = iDigraphChars->Des(); + digraph.UpperCase(); + + _LIT( KMissing,"#MISSING" ); + if( digraph.CompareC(KMissing()) == 0 ) + { + digraph = KNullDesC; + } + } + + TBuf itemString(aItemString); + itemString.UpperCase(); + + //AS does not show tone marks and diacritics when language is Thai. + TLanguage lang = User::Language(); + if ( lang == ELangThai ) + { + for(TInt i=0; i < itemString.Length(); i++) + { + if(IsThaiSpecialCharacter( itemString[i] )) + { + itemString.Delete(i,1); + } + } + } + + if ( IsIndicWord(aItemString) ) + { + // itemString contains Devanagari letters + return IsIndicAdaptiveFindMatch( itemString, aSearchText, aNextChars, iInputLanguage ); + } + else + { + return IsAdaptiveFindMatch( itemString, aSearchText, aNextChars, iInputLanguage, iDigraphChars->Des() ); + } + } + +// --------------------------------------------------------- +// Match arithmetic for accurate search, special conversion +// for aItemString is implemented with MFindStringConverter +// before the final match +// --------------------------------------------------------- +// +TBool CFindUtilWestern::MatchRefineL( const TDesC& /*aItemString*/, const TDesC& /*aSearchText*/, + TMatchPolicy /*aPolicy*/, MFindStringConverter* /*aConverter*/) + { + return EFalse; + } + +// ========================== OTHER EXPORTED FUNCTIONS ========================= + +// ----------------------------------------------------------------------------- +// FindUtilFactoryFunctionL +// Factory function at first ordinal +// Returns: MFindUtil: It returns MFindUtil I/F. +// ----------------------------------------------------------------------------- +// +// Factory function at first ordinal +EXPORT_C MFindUtil* FindUtilFactoryFunctionL() + { + return new( ELeave ) CFindUtilWestern(); + } + +// end of file