diff -r 41a7f70b3818 -r 5266b1f337bd phoneuis/dialer/src/cdialerkeypadlabelmanager.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/phoneuis/dialer/src/cdialerkeypadlabelmanager.cpp Wed Sep 01 12:30:10 2010 +0100 @@ -0,0 +1,659 @@ +/* +* Copyright (c) 2009, 2010 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: Helper class to handle virtual keypad text labels +* +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cdialerkeypadlabelmanager.h" +#include "dialercommon.h" + +// CONSTANTS +const TInt KKeyCount( 12 ); + +_LIT( KDialerButton1NumLabel, "1" ); +_LIT( KDialerButton2NumLabel, "2" ); +_LIT( KDialerButton3NumLabel, "3" ); +_LIT( KDialerButton4NumLabel, "4" ); +_LIT( KDialerButton5NumLabel, "5" ); +_LIT( KDialerButton6NumLabel, "6" ); +_LIT( KDialerButton7NumLabel, "7" ); +_LIT( KDialerButton8NumLabel, "8" ); +_LIT( KDialerButton9NumLabel, "9" ); +_LIT( KDialerButton10NumLabel, "*+" ); +_LIT( KDialerButton11NumLabel, "0" ); +_LIT( KDialerButton12NumLabel, "#" ); + +_LIT( KDialerKeypadResourceFile, "z:\\resource\\dialerkeypad" ); +_LIT( KDialerKeypadResourceFileExt, ".rsc" ); +_LIT( KDialerKeypadVariantExtSeparator, "_" ); + +_LIT( KScriptLatin, "latin" ); +_LIT( KScriptCyrillic, "cyrillic" ); +_LIT( KScriptGreek, "greek" ); +_LIT( KScriptHebrew, "hebrew" ); +_LIT( KScriptArabic, "arabic" ); +_LIT( KScriptFarsi, "farsi" ); +_LIT( KScriptUrdu, "urdu" ); +_LIT( KScriptThai, "thai" ); +_LIT( KScriptDevanagari, "devanagari" ); +_LIT( KScriptChnPinyin, "chn_pinyin" ); +_LIT( KScriptChnZhuyin, "chn_zhuyin" ); +_LIT( KScriptChnStroke, "chn_stroke" ); +_LIT( KScriptChnCangjie, "chn_cangjie" ); + +enum TScript + { + EScriptLatin = 0, + EScriptCyrillic, + EScriptGreek, + EScriptHebrew, + EScriptArabic, + EScriptFarsi, + EScriptUrdu, + EScriptThai, + EScriptDevanagari, + EScriptChinese, // generic value for all Chinese input modes + EScriptChnPinyin, + EScriptChnZhuyin, + EScriptChnStroke, + EScriptChnCangjie + }; + +struct TLanguageScriptMapping + { + TLanguage iLang; + TScript iScript; + }; + +// Following table maps non-Latin languages to corresponding scripts. +// Rest of the languages are asumed to use Latin script. +// The data of the table has been extracted from the header +// \sf\mw\inputmethods\textinput\peninputgenericitut\inc\peninputgenericitutdata.h +const TLanguageScriptMapping KScriptMap[] = + { + {ELangRussian, EScriptCyrillic}, + {ELangBulgarian, EScriptCyrillic}, + {ELangUkrainian, EScriptCyrillic}, + + {ELangGreek, EScriptGreek}, + {ELangCyprusGreek, EScriptGreek}, + + {ELangHebrew, EScriptHebrew}, + + {ELangArabic, EScriptArabic}, + + {ELangFarsi, EScriptFarsi}, + + {ELangUrdu, EScriptUrdu}, + + {ELangThai, EScriptThai}, + + {ELangHindi, EScriptDevanagari}, + {ELangMarathi, EScriptDevanagari}, + + {ELangTaiwanChinese, EScriptChinese}, + {ELangHongKongChinese, EScriptChinese}, + {ELangPrcChinese, EScriptChinese} + }; +const TInt KScriptMapCount = sizeof( KScriptMap ) / sizeof( TLanguageScriptMapping ); + +// Values for Chinese adaptive search modes, as documented in AvkonInternalCRKeys.h +enum TChinesePrcMode + { + EChnPrcPinyin = 0, + EChnPrcStroke = 1 + }; +enum TChineseTwMode + { + EChnTwZhuyin = 0, + EChnTwStroke = 1 + }; +enum TChineseHkMode + { + EChnHkStroke = 0, + EChnHkCangjie = 1 + }; + + +// LOCAL FUNCTION DECLARATIONS +static TScript ScriptForLang( TLanguage aLang ); +static const TDesC& ScriptName( TScript aScriptCode ); +static TBool ScriptCanSubstituteLatin( TScript aScript ); + + +// MEMBER FUNCTION DEFINITIONS + +// --------------------------------------------------------------------------- +// CDialerKeyPadLabelManager::CDialerKeyPadLabelManager +// +// --------------------------------------------------------------------------- +// +CDialerKeyPadLabelManager::CDialerKeyPadLabelManager( CCoeEnv& aCoeEnv, + MDialerKeyPadLabelManagerCallback& aObserver ) + : iCoeEnv( aCoeEnv ), iObserver( aObserver ) + { + // No implementation required + } + +// --------------------------------------------------------------------------- +// CDialerKeyPadLabelManager::~CDialerKeyPadLabelManager +// +// --------------------------------------------------------------------------- +// +CDialerKeyPadLabelManager::~CDialerKeyPadLabelManager() + { + delete iPtiEngine; + + delete iAknFepRepository; + delete iAvkonRepository; + + if ( iEnvChangeNotifier ) + { + iEnvChangeNotifier->Cancel(); + delete iEnvChangeNotifier; + } + + delete iKeypadNumLabelArray; + delete iKeypadFirstLabelArray; + delete iKeypadSecondLabelArray; + + if ( iResourceOffset ) + { + iCoeEnv.DeleteResourceFile( iResourceOffset ); + } + } + +// --------------------------------------------------------------------------- +// CDialerKeyPadLabelManager::NewLC +// +// --------------------------------------------------------------------------- +// +CDialerKeyPadLabelManager* CDialerKeyPadLabelManager::NewLC( CCoeEnv& aCoeEnv, + MDialerKeyPadLabelManagerCallback& aObserver ) + { + CDialerKeyPadLabelManager* self = + new (ELeave) CDialerKeyPadLabelManager( aCoeEnv, aObserver ); + CleanupStack::PushL( self ); + self->ConstructL(); + return self; + } + +// --------------------------------------------------------------------------- +// CDialerKeyPadLabelManager::NewL +// +// --------------------------------------------------------------------------- +// +CDialerKeyPadLabelManager* CDialerKeyPadLabelManager::NewL( CCoeEnv& aCoeEnv, + MDialerKeyPadLabelManagerCallback& aObserver ) + { + CDialerKeyPadLabelManager* self = + CDialerKeyPadLabelManager::NewLC( aCoeEnv, aObserver ); + CleanupStack::Pop( self ); + return self; + } + +// --------------------------------------------------------------------------- +// CDialerKeyPadLabelManager::ConstructL +// +// --------------------------------------------------------------------------- +// +void CDialerKeyPadLabelManager::ConstructL() + { + iPtiEngine = CPtiEngine::NewL(); + + iAknFepRepository = CDialerCenRepWrapper::NewL( *this, KCRUidAknFep ); + iAvkonRepository = CDialerCenRepWrapper::NewL( *this, KCRUidAvkon ); + + TCallBack envChangeCallback( EnvChangeCallback, this ); + iEnvChangeNotifier = CEnvironmentChangeNotifier::NewL( + CActive::EPriorityStandard, envChangeCallback ); + iEnvChangeNotifier->Start(); + + iKeypadNumLabelArray = new ( ELeave ) CDesCArrayFlat( KKeyCount ); + iKeypadFirstLabelArray = new ( ELeave ) CDesCArrayFlat( KKeyCount ); + iKeypadSecondLabelArray = new ( ELeave ) CDesCArrayFlat( KKeyCount ); + + UpdateNumLabelsL(); + UpdateTextLabelsL(); + } + +// --------------------------------------------------------------------------- +// CDialerKeyPadLabelManager::ButtonNumLabel +// +// --------------------------------------------------------------------------- +// +TPtrC CDialerKeyPadLabelManager::ButtonNumLabel( TInt aIndex ) const + { + __ASSERT_DEBUG( aIndex < iKeypadNumLabelArray->Count(), DialerPanic(EDialerPanicLabelNotFound) ); + + TPtrC label( KNullDesC ); + if ( aIndex < iKeypadNumLabelArray->Count() ) + { + label.Set( (*iKeypadNumLabelArray)[ aIndex ] ); + } + return label; + } + +// --------------------------------------------------------------------------- +// CDialerKeyPadLabelManager::ButtonFirstAlphaLabel +// +// --------------------------------------------------------------------------- +// +TPtrC CDialerKeyPadLabelManager::ButtonFirstAlphaLabel( TInt aIndex ) const + { + __ASSERT_DEBUG( aIndex < iKeypadFirstLabelArray->Count(), DialerPanic(EDialerPanicLabelNotFound) ); + + TPtrC label( KNullDesC ); + if ( aIndex < iKeypadFirstLabelArray->Count() ) + { + label.Set( (*iKeypadFirstLabelArray)[ aIndex ] ); + } + return label; + } + +// --------------------------------------------------------------------------- +// CDialerKeyPadLabelManager::ButtonSecondAlphaLabel +// +// --------------------------------------------------------------------------- +// +TPtrC CDialerKeyPadLabelManager::ButtonSecondAlphaLabel( TInt aIndex ) const + { + __ASSERT_DEBUG( aIndex < iKeypadSecondLabelArray->Count(), DialerPanic(EDialerPanicLabelNotFound) ); + + TPtrC label( KNullDesC ); + if ( aIndex < iKeypadSecondLabelArray->Count() ) + { + label.Set( (*iKeypadSecondLabelArray)[ aIndex ] ); + } + return label; + } + +// --------------------------------------------------------------------------- +// CDialerKeyPadLabelManager::UpdateTextLabelsL +// +// --------------------------------------------------------------------------- +// +void CDialerKeyPadLabelManager::HandleRepositoryChange( + TUid aRepository, TUint32 aId ) + { + if ( (aRepository == KCRUidAknFep && aId == KAknFepInputTxtLang) || + (aRepository == KCRUidAvkon && aId == KAknAdaptiveSearchChinesePRC) || + (aRepository == KCRUidAvkon && aId == KAknAdaptiveSearchChineseTW) || + (aRepository == KCRUidAvkon && aId == KAknAdaptiveSearchChineseHongkong) ) + { + // Check if alpabet labels need to be changed + TInt scriptToUse( EScriptLatin ); + TRAP_IGNORE( scriptToUse = LabelScriptToUseL() ); + if ( iLabelScriptInUse != scriptToUse ) + { + TRAP_IGNORE( UpdateTextLabelsL() ); + iObserver.KeyLabelsChanged(); + } + } + } + +// --------------------------------------------------------------------------- +// CDialerKeyPadLabelManager::HandleEnvChange +// +// --------------------------------------------------------------------------- +// +void CDialerKeyPadLabelManager::HandleEnvChange() + { + if ( iEnvChangeNotifier->Change() & EChangesLocale ) + { + TLocale locale; + if ( locale.DigitType() != iDigitTypeInUse ) + { + TRAP_IGNORE( UpdateNumLabelsL() ); + iObserver.KeyLabelsChanged(); + } + } + } + +// --------------------------------------------------------------------------- +// CDialerKeyPadLabelManager::EnvChangeCallback +// +// --------------------------------------------------------------------------- +// +TInt CDialerKeyPadLabelManager::EnvChangeCallback( TAny* aSelfPtr ) + { + CDialerKeyPadLabelManager* self = + static_cast< CDialerKeyPadLabelManager* >( aSelfPtr ); + self->HandleEnvChange(); + return KErrNone; + } + +// --------------------------------------------------------------------------- +// CDialerKeyPadLabelManager::UpdateTextLabelsL +// +// --------------------------------------------------------------------------- +// +void CDialerKeyPadLabelManager::UpdateTextLabelsL() + { + iKeypadFirstLabelArray->Reset(); + iKeypadSecondLabelArray->Reset(); + + // Load the correct keypad resource file + TFileName resourceName; + GetResourceFileNameL( resourceName ); + iResourceOffset = iCoeEnv.AddResourceFileL( resourceName ); + + // Read keypad labels from the resource + TResourceReader reader; + iCoeEnv.CreateResourceReaderLC( reader, R_DIALER_KEYPAD ); + + TInt16 count = reader.ReadInt16(); + + for ( TInt i = 0 ; i < count ; ++i ) + { + TPtrC firstRow = reader.ReadTPtrC(); + iKeypadFirstLabelArray->AppendL( firstRow ); + TPtrC secondRow = reader.ReadTPtrC(); + iKeypadSecondLabelArray->AppendL( secondRow ); + } + + CleanupStack::PopAndDestroy(); // reader + + // Free resource as it's not usually needed anymore. Ensure that destructor + // won't free it again. + iCoeEnv.DeleteResourceFile( iResourceOffset ); + iResourceOffset = 0; + } + +// --------------------------------------------------------------------------- +// CDialerKeyPadLabelManager::UpdateNumLabelsL +// +// --------------------------------------------------------------------------- +// +void CDialerKeyPadLabelManager::UpdateNumLabelsL() + { + // Save digit type used. This is to allow us update number labels + // only when digit type is changed and not on all locale changes. + TLocale locale; + iDigitTypeInUse = locale.DigitType(); + + iKeypadNumLabelArray->Reset(); + + // Fill number labels array + iKeypadNumLabelArray->AppendL( KDialerButton1NumLabel ); + iKeypadNumLabelArray->AppendL( KDialerButton2NumLabel ); + iKeypadNumLabelArray->AppendL( KDialerButton3NumLabel ); + iKeypadNumLabelArray->AppendL( KDialerButton4NumLabel ); + iKeypadNumLabelArray->AppendL( KDialerButton5NumLabel ); + iKeypadNumLabelArray->AppendL( KDialerButton6NumLabel ); + iKeypadNumLabelArray->AppendL( KDialerButton7NumLabel ); + iKeypadNumLabelArray->AppendL( KDialerButton8NumLabel ); + iKeypadNumLabelArray->AppendL( KDialerButton9NumLabel ); + iKeypadNumLabelArray->AppendL( KDialerButton10NumLabel ); + iKeypadNumLabelArray->AppendL( KDialerButton11NumLabel ); + iKeypadNumLabelArray->AppendL( KDialerButton12NumLabel ); + + // Convert num labels to current global number mode + for ( TInt i = 0 ; i < iKeypadNumLabelArray->Count() ; ++i ) + { + // A bit of magic is needed to get a modifiable pointer + // descriptor which points to string within the array. + TPtrC roPtr = (*iKeypadNumLabelArray)[i]; + TPtr ptr( const_cast( roPtr.Ptr() ), roPtr.Length(), roPtr.Length() ); + + AknTextUtils::LanguageSpecificNumberConversion( ptr ); + } + } + +// --------------------------------------------------------------------------- +// CDialerKeyPadLabelManager::GetResourceFileNameL +// +// --------------------------------------------------------------------------- +// +void CDialerKeyPadLabelManager::GetResourceFileNameL( TDes& aFileName ) + { + TFileName resName; + + iLabelScriptInUse = LabelScriptToUseL(); + // Try to get variated resource name if necessary + if ( iLabelScriptInUse != EScriptLatin ) + { + const TDesC& scriptName = ScriptName( static_cast(iLabelScriptInUse) ); + resName.Copy( KDialerKeypadResourceFile ); + resName.Append( KDialerKeypadVariantExtSeparator ); + resName.Append( scriptName ); + resName.Append( KDialerKeypadResourceFileExt ); + + BaflUtils::NearestLanguageFile( iCoeEnv.FsSession(), resName ); + if ( !BaflUtils::FileExists( iCoeEnv.FsSession(), resName ) ) + { + // resource not found, fall back to Latin + iLabelScriptInUse = EScriptLatin; + } + } + + // Get the default resource name if Latin script was selected or + // resource file for the selected script was not found. + if ( iLabelScriptInUse == EScriptLatin ) + { + resName.Copy( KDialerKeypadResourceFile ); + resName.Append( KDialerKeypadResourceFileExt ); + BaflUtils::NearestLanguageFile( iCoeEnv.FsSession(), resName ); + } + + aFileName.Copy( resName ); + } + +// --------------------------------------------------------------------------- +// CDialerKeyPadLabelManager::LabelScriptToUseL +// +// --------------------------------------------------------------------------- +// +TInt CDialerKeyPadLabelManager::LabelScriptToUseL() const + { + TInt lang( ELangEnglish ); + + // Get current input language + TInt err = iAknFepRepository->Get( KAknFepInputTxtLang, lang ); + __ASSERT_DEBUG( !err, DialerPanic(err) ); + + TInt script = ScriptForLang( static_cast(lang) ); + + // Distinct logic is used to select labels when current input language + // is any version of Chinese. PCS uses different algorith for Chinese. + if ( script == EScriptChinese ) + { + script = ChineseScriptToUseL(); + } + // If current input language is written in Latin script, then we check + // if some other script of the device could also be shown on the labels. + // Most variated labels include Latin characters as well. + else if ( script == EScriptLatin ) + { + RArray availableLanguages; + CleanupClosePushL( availableLanguages ); + iPtiEngine->GetAvailableLanguagesL( availableLanguages ); + + // Scirpt of the current UI language is preferred option for + // alternative script. Ensure it's considered first. + TLanguage uiLang = User::Language(); + TInt pos = availableLanguages.Find( uiLang ); + if ( pos != KErrNotFound ) + { + availableLanguages.Remove( pos ); + availableLanguages.InsertL( uiLang, 0 ); + } + + TInt langCount = availableLanguages.Count(); + for ( TInt i = 0 ; i < langCount ; ++i ) + { + TLanguage altLang = static_cast( availableLanguages[i] ); + TScript altScript = ScriptForLang( altLang ); + if ( altScript != EScriptLatin && ScriptCanSubstituteLatin(altScript) ) + { + // Suitable alternative script found. Use its labels + // instead of showing only Latin alphabets. + script = altScript; + i = langCount; // to break out + } + } + + CleanupStack::PopAndDestroy( &availableLanguages ); + } + + return script; + } + +// --------------------------------------------------------------------------- +// CDialerKeyPadLabelManager::ChineseScriptToUseL +// +// --------------------------------------------------------------------------- +// +TInt CDialerKeyPadLabelManager::ChineseScriptToUseL() const + { + TInt script( EScriptLatin ); + + TInt lang( ELangPrcChinese ); + TInt chnSearchMode( 0 ); + + TInt err = iAknFepRepository->Get( KAknFepInputTxtLang, lang ); + __ASSERT_DEBUG( !err, DialerPanic(EDialerPanicChineseScriptError) ); + + switch ( lang ) + { + case ELangPrcChinese: + { + err = iAvkonRepository->Get( KAknAdaptiveSearchChinesePRC, chnSearchMode ); + script = ( chnSearchMode == EChnPrcPinyin ? EScriptChnPinyin : EScriptChnStroke ); + } + break; + case ELangTaiwanChinese: + { + err = iAvkonRepository->Get( KAknAdaptiveSearchChineseTW, chnSearchMode ); + script = ( chnSearchMode == EChnTwZhuyin ? EScriptChnZhuyin : EScriptChnStroke ); + } + break; + case ELangHongKongChinese: + { + err = iAvkonRepository->Get( KAknAdaptiveSearchChineseHongkong, chnSearchMode ); + script = ( chnSearchMode == EChnHkStroke ? EScriptChnStroke : EScriptChnCangjie ); + } + break; + default: + { + err = KErrUnknown; + } + break; + } + __ASSERT_DEBUG( !err, DialerPanic(EDialerPanicChineseScriptError) ); + + return script; + } + + +// LOCAL FUNCTION DEFINITIONS + +// --------------------------------------------------------------------------- +// ScriptForLang +// +// --------------------------------------------------------------------------- +// +static TScript ScriptForLang( TLanguage aLang ) + { + TScript script( EScriptLatin ); + for ( TInt i = 0 ; i < KScriptMapCount ; ++i ) + { + if ( aLang == KScriptMap[i].iLang ) + { + script = KScriptMap[i].iScript; + i = KScriptMapCount; // to break out + } + } + return script; + } + +// --------------------------------------------------------------------------- +// ScriptName +// +// --------------------------------------------------------------------------- +// +static const TDesC& ScriptName( TScript aScriptCode ) + { + // Convert script ID to script name + switch ( aScriptCode ) + { + case EScriptLatin: + return KScriptLatin; + case EScriptCyrillic: + return KScriptCyrillic; + case EScriptGreek: + return KScriptGreek; + case EScriptHebrew: + return KScriptHebrew; + case EScriptArabic: + return KScriptArabic; + case EScriptFarsi: + return KScriptFarsi; + case EScriptUrdu: + return KScriptUrdu; + case EScriptThai: + return KScriptThai; + case EScriptDevanagari: + return KScriptDevanagari; + case EScriptChnPinyin: + return KScriptChnPinyin; + case EScriptChnZhuyin: + return KScriptChnZhuyin; + case EScriptChnStroke: + return KScriptChnStroke; + case EScriptChnCangjie: + return KScriptChnCangjie; + default: + __ASSERT_DEBUG( EFalse, DialerPanic(EDialerPanicUnknownScript) ); + } + return KNullDesC; + } + +// --------------------------------------------------------------------------- +// ScriptCanSubstituteLatin +// Return ETrue if labels of given script can be used instead of Latin labels +// when current input language is written with Latin script. This requires +// that the labels include also Latin characters and that labels don't contain +// any characters which would only make sense in some specific input mode. +// --------------------------------------------------------------------------- +// +static TBool ScriptCanSubstituteLatin( TScript aScript ) + { + // It would be better to figure this out from the resources but that would + // require opening and parsing several resource files. + return !( aScript == EScriptArabic || + aScript == EScriptUrdu || + aScript == EScriptFarsi || + aScript == EScriptChinese || + aScript == EScriptChnPinyin || + aScript == EScriptChnZhuyin || + aScript == EScriptChnStroke || + aScript == EScriptChnCangjie ); + } + +// end of file +