diff -r 000000000000 -r 3ee3dfdd8d69 extras/converter/Ui/Src/CCnvMainForm.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extras/converter/Ui/Src/CCnvMainForm.cpp Mon Jan 18 20:20:33 2010 +0200 @@ -0,0 +1,1259 @@ +/* +* Copyright (c) 2002 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: +* This is the implementation of the class defined in CCnvMainForm.h +* +*/ + + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include "Converter.hrh" +#include "CCnvApplication.h" +#include "CCnvMainForm.h" +#include "CCnvRatesForm.h" + +#include +#include +#include + +_LIT( KCnvPlusSign, "+" ); +_LIT( KCnvMinusSign, "-" ); +_LIT( KCnvExponentSign, "E" ); +_LIT( KCnvDotSign, "." ); + +_LIT( KCnvMinusInTheMiddle, "?*-?*" ); +_LIT( KCnvPlusInTheMiddle, "?*+?*" ); +_LIT( KCnvExponentInTheMiddle, "?*E?*" ); +_LIT( KCnvExponentInTheMiddleAndEnd, "?*E?*E?" ); + + _LIT( KConverterFilename,"UnitConverter.ini"); + _LIT(KDelimiter, ":"); + +CCnvMainForm::CCnvMainForm( TBool &aAlreadyDead ) +: iIsFullyConstructed( EFalse ), +iHasNotifiedDiscFull( EFalse ), +iLastUsedEditorId( EConverterEditor1 ), +iHistoryTypeCategory( -1 ), +iHistoryUnit1Category( -1 ), +iHistoryUnit2Category( -1 ), +iAlreadyDead( aAlreadyDead ) + { + } + +CCnvMainForm::~CCnvMainForm() + { + if( iIsFullyConstructed ) + { + SaveState(); + } + delete iModel; + delete iConversionTimer; + delete iErrorUI; + iAlreadyDead = ETrue; + + //remove the edwin observers + CEikFloatingPointEditor* editor1 = + static_cast< CEikFloatingPointEditor* >( Control( EConverterEditor1 ) ); + editor1->RemoveEdwinObserver(this); + + CEikFloatingPointEditor* editor2 = + static_cast< CEikFloatingPointEditor* >( Control( EConverterEditor2 ) ); + editor2->RemoveEdwinObserver(this); + + } + +void CCnvMainForm::ConstructL() + { + CAknDialog::ConstructL( R_CNV_MAINFORM_MENUBAR ); + + iErrorUI = CErrorUI::NewL( *iCoeEnv ); + + TResourceReader reader; + iEikonEnv->CreateResourceReaderLC( reader, R_CNV_MODEL ); + iModel = CCnvConverter::NewL( reader ); + CleanupStack::PopAndDestroy(); // reader + + iConversionTimer = CPeriodic::NewL( CActive::EPriorityStandard ); + + iCurrencyCategoryId = iModel->CurrencyCategoryId(); + iIsFullyConstructed = ETrue; + isEdwinUpdateText = EFalse; + + TFileName path; + iEikonEnv->FsSession().PrivatePath(path); + iEikonEnv->FsSession().MkDirAll(path); + + } + +void CCnvMainForm::GetHelpContext( TCoeHelpContext& aContext ) const + { + aContext.iMajor = KUidCnv; + aContext.iContext = KCNV_HLP_MAIN_STATE; + } + +// Handle commands from Options menu +void CCnvMainForm::ProcessCommandL( TInt aCommandId ) + { + // this hides the options menu etc. + CAknForm::ProcessCommandL( aCommandId ); + + switch( aCommandId ) + { + case ECmdSetType: + { + CmdSetTypeL(); + break; + } + + case ECmdSetUnit: // FLOWTHROUGH + case ECmdSetCurrency: + { + CmdSetUnitL(); + break; + } + + case ECmdRates: + { + CmdRatesL(); + break; + } + case EAknCmdHelp: + { + iEikonEnv->EikAppUi()->HandleCommandL( EAknCmdHelp ); + break; + } + case EEikCmdExit: + { + OkToExitL( EAknSoftkeyExit ); + break; + } + + default: + { + break; + } + } + } + +// Takes any action required when the current line is changed to aControlId. +void CCnvMainForm::LineChangedL( TInt aControlId ) + { + + CEikButtonGroupContainer& cba = ButtonGroupContainer(); + cba.SetCommandSetL(R_CNV_MAINFORM_SOFTKEYS); + + if( ( aControlId == EConverterEditor1 ) || + ( aControlId == EConverterEditor2 ) ) + { + CEikFloatingPointEditor* editor = + static_cast< CEikFloatingPointEditor* >( Control( aControlId ) ); + + // don't clear the selection if there is only '0' in the editor + TBuf editorText; + editor->GetText(editorText); + + SynchronousConversionL(); + // iActiveEditorChanged = EFalse; + } + else if(aControlId == EConverterUnit1Popup || + aControlId == EConverterUnit2Popup) + { + + + // if focus is moved to unit popup from amount field + // then try to do the conversion. + // IsEditorValueValidL shows invalid value note if value is not valid + TBool editorValueValid = IsEditorValueValidL(iLastUsedEditorId); + if (editorValueValid && AreRatesValidL(ETrue)) + { + SynchronousConversionL(); + } + } + if(aControlId == EConverterUnit1Popup || + aControlId == EConverterUnit2Popup || + aControlId == EConverterTypePopup) + { + //Makes the MSK visible + + cba.MakeCommandVisible(EAknSoftkeyChange,ETrue); + + + } + else if(aControlId ==EConverterEditor1 || + aControlId ==EConverterEditor2) + { + + + //makes the MSK invisible + + cba.MakeCommandVisible(EAknSoftkeyChange,EFalse); + + } + cba.DrawNow(); + } + +void CCnvMainForm::DynInitMenuPaneL( TInt aResourceId, + CEikMenuPane* aMenuPane ) + { + // When click on LSK(option), the invalid value should be set to 0. + TInt controlId( IdOfFocusControl() ); + if ( ( controlId == EConverterEditor1 ) || ( controlId == EConverterEditor2 ) ) + { + if ( EditorValueCausesHold( controlId ) || !IsVaildNumberEntered( controlId ) ) + { + SetFloatEditorValueL( controlId, 0.0 ); + } + SynchronousConversionL( EFalse ); + } + + TUint currentType( iTypeCategory.CurrentValueIndex() ); + + if( aResourceId == R_CNV_MAINFORM_MENUPANE ) + { + if (!FeatureManager::FeatureSupported(KFeatureIdHelp)) + { + aMenuPane->SetItemDimmed(EAknCmdHelp, ETrue); + } + + if( currentType == iCurrencyCategoryId ) + { + aMenuPane->SetItemDimmed( ECmdRates, EFalse ) ; + } + + switch( IdOfFocusControl() ) + { + case EConverterUnit1Popup: + case EConverterUnit2Popup: + { + if( currentType == iCurrencyCategoryId ) + { + aMenuPane->SetItemDimmed( ECmdSetCurrency, EFalse ) ; + } + else + { + aMenuPane->SetItemDimmed( ECmdSetUnit, EFalse ) ; + } + break; + } + default: + { + break; + } + } + } + } + +// Handles events to the three pop lists +void CCnvMainForm::HandleControlEventL( CCoeControl* /*aControl*/, + TCoeEvent aEventType ) + { + // We are interested only about EEventStateChanged events + if( aEventType != EEventStateChanged ) + { + return; + } + + TInt controlId( IdOfFocusControl() ); + + if( !HasReallyChanged( controlId ) ) + { + return; + } + + switch( controlId ) + { + case EConverterTypePopup: + { + HandleCategoryChangedL(); + break; + } + case EConverterUnit1Popup: + case EConverterUnit2Popup: + { + HandleUnitChangedL(); + break; + } + //These have been moved to OfferKeyEventL + case EConverterEditor1: + case EConverterEditor2: + { + iLastUsedEditorId = controlId; + if( (iActiveEditorChanged)&& + ( isEdwinNavigated == EFalse || isEdwinUpdateText ) ) // Is there any navigation (or selection) + //happening on the editor + { + AsynchronousConversion(); + } + isEdwinNavigated = EFalse; //make the boolean false + iActiveEditorChanged = ETrue; + break; + } + + default: + { + break; + } + } + } + +TBool CCnvMainForm::SaveFormData() + { + // Always allow exit (data is saved in the destructor) + return ETrue; + } + +TBool CCnvMainForm::OkToExitL( TInt aButtonId ) + { + TBool status( CAknDialog::OkToExitL( aButtonId ) ); + TInt controlId( IdOfFocusControl() ); + if( status && ( aButtonId == EAknSoftkeyExit ) ) + { + iEikonEnv->EikAppUi()->HandleCommandL( EAknCmdExit ); + } + else if(aButtonId == EAknSoftkeyChange) + { + if (controlId == EConverterTypePopup) + { + CmdSetTypeL(); + status = EFalse; + } + else if ((controlId == EConverterUnit1Popup) ||(controlId == EConverterUnit2Popup)) + { + CmdSetUnitL(); + status = EFalse; + } + } + else + { + status = EFalse; + } + return status; + } + +void CCnvMainForm::PreLayoutDynInitL() + { + // Store pointers to the popup list controls + // (makes further access easier/faster) + iTypePopupCtrl = + static_cast< CAknPopupField* >( Control( EConverterTypePopup ) ); + iUnit1PopupCtrl = + static_cast< CAknPopupField* >( Control( EConverterUnit1Popup ) ); + iUnit2PopupCtrl = + static_cast< CAknPopupField* >( Control( EConverterUnit2Popup ) ); + + + // Set values for the unit category popup control + iModel->GetCategorylistAccessor( iTypeCategory ); + iTypePopupCtrl->SetQueryValueL( &iTypeCategory ); + + // Load user selections from file (if any) + LoadStateL(); + + // Set initial values for the popup lists + HandleCategoryChangedL(); + + InitialiseChangeHistory(); + + if (iUnit1Category.UnitFactor(iUnit1Category.CurrentValueIndex()) != 0.0 && + iUnit2Category.UnitFactor(iUnit2Category.CurrentValueIndex()) != 0.0) + { + SynchronousConversionL(); + } + + //Add wdwin observers for the two editors so that they can capture the Navigation + //events and not do asynchronous conversion + CEikFloatingPointEditor* editor1 = + static_cast< CEikFloatingPointEditor* >( Control( EConverterEditor1 ) ); + + CEikFloatingPointEditor* editor2 = + static_cast< CEikFloatingPointEditor* >( Control( EConverterEditor2 ) ); + + editor1->AddEdwinObserverL(this); + editor2->AddEdwinObserverL(this); + + + } + +TBool CCnvMainForm::HasReallyChanged( TInt controlId ) + { + TBool changed( EFalse ); + + switch( controlId ) + { + case EConverterTypePopup: + { + if( iTypeCategory.CurrentValueIndex() != iHistoryTypeCategory ) + { + changed = ETrue; + iHistoryTypeCategory = iTypeCategory.CurrentValueIndex(); + + // renew iHistoryUnit1Category and iHistoryUnit2Category + iModel->GetCategoryAccessor( iUnit1Category, iHistoryTypeCategory ); + TUint HistoryUnit1Category; + TUint HistoryUnit2Category; + iUnit1Category.GetDefaultUnits( HistoryUnit1Category , HistoryUnit2Category ); + iHistoryUnit1Category = HistoryUnit1Category; + iHistoryUnit2Category = HistoryUnit2Category; + } + break; + } + case EConverterUnit1Popup: + { + if( iUnit1Category.CurrentValueIndex() != iHistoryUnit1Category ) + { + changed = ETrue; + iHistoryUnit1Category = iUnit1Category.CurrentValueIndex(); + } + break; + } + case EConverterUnit2Popup: + { + if( iUnit2Category.CurrentValueIndex() != iHistoryUnit2Category ) + { + changed = ETrue; + iHistoryUnit2Category = iUnit2Category.CurrentValueIndex(); + } + break; + } + + case EConverterEditor1: + case EConverterEditor2: + { + changed = ETrue; + break; + } + + default: + { + break; + } + } + + return changed; + } + +void CCnvMainForm::InitialiseChangeHistory() + { + iHistoryTypeCategory = iTypeCategory.CurrentValueIndex(); + iHistoryUnit1Category = iUnit1Category.CurrentValueIndex(); + iHistoryUnit2Category = iUnit2Category.CurrentValueIndex(); + } + +void CCnvMainForm::HandleCategoryChangedL() + { + TInt categoryId = iTypeCategory.CurrentValueIndex(); + iModel->GetCategoryAccessor( iUnit1Category, categoryId ); + iModel->GetCategoryAccessor( iUnit2Category, categoryId ); + + TUint srcUnit, dstUnit; + iUnit1Category.GetDefaultUnits( srcUnit, dstUnit ); + iUnit1Category.SetCurrentValueIndex( srcUnit ); + iUnit2Category.SetCurrentValueIndex( dstUnit ); + + // Set arrays to popup lists and redraw them + iUnit1PopupCtrl->SetQueryValueL( &iUnit1Category ); + iUnit2PopupCtrl->SetQueryValueL( &iUnit2Category ); + iUnit1PopupCtrl->DrawNow(); + iUnit2PopupCtrl->DrawNow(); + + // Reset amount fields + TReal zero( 0.0 ); + SetFloatingPointEditorValueL( EConverterEditor1, &zero ); + SetFloatingPointEditorValueL( EConverterEditor2, &zero ); + + // when category's type is temperature the editor's value can't simply set to zero + AsynchronousConversion(); + + iLastUsedEditorId = EConverterEditor1; + } + +void CCnvMainForm::HandleUnitChangedL() + { + iUnit1Category.SetDefaultUnits( iUnit1Category.CurrentValueIndex(), + iUnit2Category.CurrentValueIndex() ); + SynchronousConversionL(); + } + +TBool CCnvMainForm::AreRatesValidL(TBool aShowNote) + { + TInt numInvalid( 0 ); + if( iUnit1Category.UnitFactor( iUnit1Category.CurrentValueIndex() ) + == 0.0 ) + { + numInvalid++; + SetFloatEditorValueL( EConverterEditor1, 0.0 ); + } + if( iUnit2Category.UnitFactor( iUnit2Category.CurrentValueIndex() ) + == 0.0 ) + { + numInvalid++; + SetFloatEditorValueL( EConverterEditor2, 0.0 ); + } + + if(numInvalid) + { + CancelConversion(); + + if (aShowNote) + { + TBool isPlural( EFalse ); + if( numInvalid > 1 ) + { + isPlural = ETrue; + } + + TInt resourceId(R_CNV_MAINFORM_NORATE ); + if( isPlural ) + { + resourceId = R_CNV_MAINFORM_NORATE_PLURAL; + } + HBufC* label = iCoeEnv->AllocReadResourceLC( resourceId ); + CAknErrorNote* note = new( ELeave ) CAknErrorNote; + note->ExecuteLD( *label ); + CleanupStack::PopAndDestroy(); // label; + } + return EFalse; + } + else + { + return ETrue; + } + } + +void CCnvMainForm::ShowInvalidValueNoteL(TInt aEditorId) + { + CancelConversion(); + + SetFloatEditorValueL( aEditorId, 0.0 ); + + HBufC* label = iCoeEnv->AllocReadResourceLC( + R_CNV_MAINFORM_INVALIDVALUE ); + CAknErrorNote* note = new( ELeave ) CAknErrorNote; + note->ExecuteLD( *label ); + CleanupStack::PopAndDestroy(); // label; + + SynchronousConversionL(); + } + +TBool CCnvMainForm::IsEditorValueValidL( TUint aEditorId ) + { + TReal amount( FloatingPointEditorValue( aEditorId ) ); + + TReal minimum; + if( aEditorId == EConverterEditor1 ) + { + minimum = iUnit1Category.UnitMinimum( + iUnit1Category.CurrentValueIndex() ); + } + else + { + minimum = iUnit2Category.UnitMinimum( + iUnit2Category.CurrentValueIndex() ); + } + + if( amount < minimum ) + { + ShowInvalidValueNoteL(aEditorId); + return EFalse; + } + else + { + return ETrue; + } + } + +TBool CCnvMainForm::EditorValueCausesHold( TUint aEditorId ) + { + CEikFloatingPointEditor* editor = + static_cast< CEikFloatingPointEditor* >( Control( aEditorId ) ); + + if( editor->TextLength() == 0 ) + { + return ETrue; + } + + TBuf< 12 > content; + TLocale locale; + + // Not all the countries use '.' to express radix point, some use ','. + // So use locale.DecimalSeparator() to get local symbol. + TBuf<1> decimal; + decimal.Append( locale.DecimalSeparator() ); + editor->Text()->Extract( content, 0, 12 ); + TInt contentLength( content.Length() ); + if ( !content.Compare( KCnvPlusSign ) ) + { + return ETrue; + } + else if ( !content.Compare( KCnvMinusSign ) ) + { + return ETrue; + } + + else if ( !content.Compare( decimal ) ) + { + return ETrue; + } + else if( contentLength > 1 && + content[ contentLength - 1 ] == KCnvExponentSign()[ 0 ] && + IsDigit( content[ contentLength - 2 ] ) && + content.Match( KCnvExponentInTheMiddle ) == KErrNotFound && + content.Match( KCnvMinusInTheMiddle ) == KErrNotFound && + content.Match( KCnvPlusInTheMiddle ) == KErrNotFound) + { + // If content ends with E with no minus, plus or exponent + // sign in the middle + return ETrue; + } + else if( contentLength > 2 && + ( content[ contentLength - 1 ] == KCnvMinusSign()[ 0 ] || + content[ contentLength - 1 ] == KCnvPlusSign()[ 0 ] ) && + content[ contentLength - 2 ] == KCnvExponentSign()[ 0 ] && + IsDigit( content[ contentLength - 3 ] ) && + content.Match( KCnvExponentInTheMiddleAndEnd ) == KErrNotFound && + content.Match( KCnvMinusInTheMiddle ) == KErrNotFound && + content.Match( KCnvPlusInTheMiddle ) == KErrNotFound ) + { + // If content ends with E[+|-] with no minus, plus or exponent + // sign in the middle + return ETrue; + } + else if(contentLength > 12 && + content.Locate(locale.DecimalSeparator()) == contentLength - 1) + { + // content ends with decimal separator and there is no other + // decimal separator + return ETrue; + } + + + return EFalse; + } + +void CCnvMainForm::CmdRatesL() + { + TBool wantsRelaunch; + TBool shouldExit( EFalse ); + TBool needsSave( EFalse ); + do + { + wantsRelaunch = EFalse; + TCnvCategory currencies; + iModel->GetCategoryAccessor( currencies, iCurrencyCategoryId ); + + CCnvRatesForm* rates = new( ELeave ) CCnvRatesForm( &wantsRelaunch, + &shouldExit, &needsSave, currencies); + + CleanupStack::PushL( rates ); + rates->ConstructL(); + CleanupStack::Pop(); // rates + rates->ExecuteLD( R_CNV_RATESFORM ); + } + while( wantsRelaunch ); + + if( needsSave ) + { + SaveState(); + } + + if( !shouldExit ) + { + // Reset the form (there might be changes in unit names..) + HandleCategoryChangedL(); + + DrawNow(); + } + else + { + TryExitL( EAknSoftkeyExit ); + } + } + +void CCnvMainForm::CmdSetTypeL() + { + TryChangeFocusToL( EConverterTypePopup ); + iTypePopupCtrl->ActivateSelectionListL(); + } + +void CCnvMainForm::CmdSetUnitL() + { + switch ( IdOfFocusControl() ) + { + case EConverterUnit1Popup: + { + iUnit1PopupCtrl->ActivateSelectionListL(); + break; + } + + case EConverterUnit2Popup: + { + iUnit2PopupCtrl->ActivateSelectionListL(); + break; + } + + default: + { + break; + } + } + } + +void CCnvMainForm::LoadStateL() + { + RFileReadStream in; + + TFileName filePath; + TBuf<1> tempDes; + TChar driveChar; + User::LeaveIfError(iEikonEnv->FsSession().PrivatePath(filePath)); + iEikonEnv->FsSession().DriveToChar(KDefaultDrive, driveChar); + tempDes.Append(driveChar); + filePath.Insert(0,KDelimiter); + filePath.Insert(0,tempDes); + filePath.Append(KConverterFilename); + + TInt err( in.Open( iEikonEnv->FsSession(), filePath, + EFileRead ) ); + + if( !err ) + { + TRAP( err, iModel->InternalizeL( in ) ); + if( !err ) + { + TRAP( err, iTypeCategory.SetCurrentValueIndex( in.ReadInt8L() ) ); + } + in.Close(); + } + } + +void CCnvMainForm::SaveState() + { + RFileWriteStream out; + + TFileName filePath; + TBuf<1> tempDes; + TChar driveChar; + TRAPD(errd, iEikonEnv->FsSession().PrivatePath(filePath)); + iEikonEnv->FsSession().DriveToChar(KDefaultDrive, driveChar); + tempDes.Append(driveChar); + if(!errd) + { + + filePath.Insert(0,KDelimiter); + filePath.Insert(0,tempDes); + filePath.Append(KConverterFilename); + } + + TInt err( out.Replace( iEikonEnv->FsSession(), filePath, + EFileWrite ) ); + + if( !err ) + { + TRAP( err, iModel->ExternalizeL( out ) ); + if( !err ) + { + TRAP( err, out.WriteInt8L( iTypeCategory.CurrentValueIndex() ) ); + } + out.Close(); + } + + if( err && !iHasNotifiedDiscFull ) + { + TRAP_IGNORE(iErrorUI->ShowGlobalErrorNoteL( err ) ); + iHasNotifiedDiscFull = ETrue; + } + } + +void CCnvMainForm::SynchronousConversionL( TBool aShowRateInvalideNote ) + { + // Don't report an "invalid value" error. Cancel conversion. + // if the field is empty (i.e. the user has used delete/backspace) etc. + if( EditorValueCausesHold( iLastUsedEditorId ) ) + { + // if one Editor is blank, set the other to 0. + CEikFloatingPointEditor* editor = + static_cast< CEikFloatingPointEditor* >( Control( iLastUsedEditorId ) ); + if( editor->TextLength() == 0 ) + { + if( iLastUsedEditorId == EConverterEditor1) + { + SetFloatEditorValueL( EConverterEditor2, 0.0 ); + } + if( iLastUsedEditorId == EConverterEditor2) + { + SetFloatEditorValueL( EConverterEditor1, 0.0 ); + } + } + return; + } + + if ( !IsVaildNumberEntered( iLastUsedEditorId ) ) + { + ShowInvalidValueNoteL( iLastUsedEditorId ); + } + + + // PrepareForFocusLossL leaves if the component is not able to + // parse the content. We trap it so that IsEditorValueValidL() + // can check and report the situation correctly. + TRAP_IGNORE( Control( iLastUsedEditorId )->PrepareForFocusLossL() ); + TInt CurrentControlId( IdOfFocusControl() ); + if( CurrentControlId == EConverterUnit1Popup ) + { + IsEditorValueValidL( EConverterEditor1 ); + } + else if (CurrentControlId == EConverterUnit2Popup) + { + IsEditorValueValidL( EConverterEditor2 ); + } + else if (CurrentControlId == EConverterEditor2 ) + { + if ( !IsVaildNumberEntered( EConverterEditor2 ) ) + { + iLastUsedEditorId = CurrentControlId; + ShowInvalidValueNoteL( EConverterEditor2 ); + } + } + else if (CurrentControlId == EConverterEditor1 ) + { + if ( !IsVaildNumberEntered( EConverterEditor1 ) ) + { + iLastUsedEditorId = CurrentControlId; + ShowInvalidValueNoteL( EConverterEditor1 ); + } + } + TReal result( 0.0 ); + + // send an argument to notify the AreRatesValidL() display a note dialog or not + if (IsEditorValueValidL(iLastUsedEditorId)) + { + if (AreRatesValidL(aShowRateInvalideNote)) + { + TReal amount(FloatingPointEditorValue(iLastUsedEditorId)); + TUint unit1(iUnit1Category.CurrentValueIndex()); + TUint unit2(iUnit2Category.CurrentValueIndex()); + + // RAPD( ignored, Control( iLastUsedEditorId )->PrepareForFocusLossL() ); + + + // do not reset the touch UI to standby state + // CCoeEnv::Static()->SyncNotifyFocusObserversOfChangeInFocus(); + + + // Do the calculation and change the value for the related edit field + ValueCalculationL(unit1, unit2, amount); + + CEikFloatingPointEditor* editor = + static_cast (Control( + iLastUsedEditorId)); + TBuf editorText; + editor->GetText(editorText); + + // Use local value for different area + TBuf<1> localeZero; + localeZero.AppendNum(0); + AknTextUtils::LanguageSpecificNumberConversion(localeZero); + if (editorText.Length() > 1 && editorText[0] == localeZero[0]) + { + TCursorSelection sel = editor->Selection(); + TInt removedZeroes = 0; + // remove all leading zeroes + while (editorText.Length() > 0 && editorText[0] + == localeZero[0]) + { + editorText.Delete(0, 1); + ++removedZeroes; + } + // if too many zeroes removed, insert one. + TLocale locale; + if (editorText.Length() == 0 || TChar(editorText[0]) + == locale.DecimalSeparator()) + { + editorText.Insert(0, localeZero); + --removedZeroes; + } + editor->SetTextL(&editorText); + + // adjust the selection accroding to removed zeroes + TInt anchor = + (sel.iAnchorPos - removedZeroes > 0) ? sel.iAnchorPos + - removedZeroes : 0; + TInt cursor = + (sel.iCursorPos - removedZeroes > 0) ? sel.iCursorPos + - removedZeroes : 0; + editor->SetSelectionL(cursor, anchor); + + if ( !IsVaildNumberEntered( iLastUsedEditorId ) ) + { + ShowInvalidValueNoteL( iLastUsedEditorId ); + } + // notify the touch window + editor->SetCursorPosL(cursor, ETrue); + editor->DrawNow(); + } + } + } + } + +void CCnvMainForm::AsynchronousConversion() + { + CancelConversion(); + TCallBack cb( TimerCallback, this ); + iConversionTimer->Start( 750000, 0, cb ); + } + +void CCnvMainForm::CancelConversion() + { + iConversionTimer->Cancel(); + } + +TInt CCnvMainForm::TimerCallback( TAny* aMainForm ) + { + + CCnvMainForm* form = reinterpret_cast< CCnvMainForm* >( aMainForm ); + + TRAP_IGNORE(form->SynchronousConversionL() ); + + form->CancelConversion(); + + return KErrNone; + } + + + +// ---------------------------------------------------- +// CCnvMainForm::OfferKeyEventL +// Keyevent process. +// ---------------------------------------------------- +// +TKeyResponse CCnvMainForm::OfferKeyEventL(const TKeyEvent& aKeyEvent, + TEventCode aType) + { + + if ( !IsFocused() ) + { + if (aKeyEvent.iCode == EKeyEscape) + { + return CAknForm::OfferKeyEventL( aKeyEvent, aType ); + } + return EKeyWasNotConsumed; + } + + TInt controlId( IdOfFocusControl() ); + + TBool hashKeyPressed = EFalse; + + // Use decimalChar instead of 46 + TLocale locale; + TChar decimalChar = locale.DecimalSeparator(); + if ( aKeyEvent.iScanCode == EStdKeyHash || decimalChar == TChar( aKeyEvent.iCode ) ) + { + hashKeyPressed = ETrue; + } + + if( hashKeyPressed ) + { + // If inputting through VKB or HWR, the event can be done only when aType is equal to EEventKey. + // Besides, only when inputting the dot in VKB or HWR, aKeyEvent.iScanCode is equal to decimalChar. + TBool VKBdotKeyPressed = EFalse; + if ( ( aKeyEvent.iScanCode == decimalChar ) ) + { + VKBdotKeyPressed = ETrue; + } + if ( ( aType == EEventKey) && ( !VKBdotKeyPressed ) ) + { + return EKeyWasConsumed; + } + else if( aType == EEventKeyUp) + { + TKeyEvent keyevent( aKeyEvent ); + aType = EEventKey; + keyevent.iCode = decimalChar; + keyevent.iModifiers = 0; + keyevent.iScanCode = 0; + keyevent.iRepeats = 0; + return static_cast< CEikFloatingPointEditor* >( Control( controlId ) ) + ->OfferKeyEventL(keyevent,aType); + } + else + {// + } + } + + //Not a key event this case handles the menu and exit keys + //when an invalid value is entered in the amount field + if(aType == EEventKeyDown) + { + if( ( EConverterEditor1 == controlId )|| + ( EConverterEditor2 == controlId ) ) + { + + if( (aKeyEvent.iScanCode == EStdKeyDevice0) ||//menu Key + (aKeyEvent.iScanCode == EStdKeyDevice1) )//Exit key + { + if( EditorValueCausesHold( controlId ) || + !IsVaildNumberEntered( controlId ) ) + { + SetFloatEditorValueL( controlId, 0.0); + } + //return EKeyWasNotConsumed; + } + } + } + + if ( aType != EEventKey ) + { + // Return EKeyWasNotConsumed if OfferKeyEventL() does not handle any event. + return EKeyWasNotConsumed; + } + + if( ( EConverterEditor1 == controlId )|| + ( EConverterEditor2 == controlId ) ) + { + //Just to see that -9E-99 doesnt appear when an invalid number is editor is + //entered in the editor + + if(aKeyEvent.iScanCode == EStdKeyUpArrow || + aKeyEvent.iScanCode == EStdKeyDownArrow ) + { + CancelConversion(); + if( EditorValueCausesHold( controlId ) ) + { + SetFloatEditorValueL( controlId, 0.0); + } + if( !IsVaildNumberEntered( controlId ) ) + { + ShowInvalidValueNoteL( controlId ); + } + } + + iLastUsedEditorId = controlId; + + //For arrow keys asynchronous conversion not required + // if (iActiveEditorChanged) + // { + /*if( ( aKeyEvent.iScanCode != EStdKeyRightArrow )&& + ( aKeyEvent.iScanCode != EStdKeyLeftArrow )&& + ( aKeyEvent.iScanCode != EStdKeyUpArrow )&& + ( aKeyEvent.iScanCode != EStdKeyDownArrow )&& + ( isEditKey == EFalse ) ) + { + AsynchronousConversion(); + }*/ + //} + + //iActiveEditorChanged = ETrue; + + } + return CAknForm::OfferKeyEventL(aKeyEvent, aType); + + } + + +// ---------------------------------------------------- +// CCnvMainForm::IsVaildNumberEntered +// Checks if a valid number is entered in the editor field and returns +// ETrue if a vaild number is entered and +// EFalse if an invalid number is entered +// ---------------------------------------------------- +// + +TBool CCnvMainForm::IsVaildNumberEntered( TInt aEditorId ) + { + CEikFloatingPointEditor* editor = + static_cast< CEikFloatingPointEditor* >( Control( aEditorId ) ); + + if ( editor->TextLength() == 0 ) + { + return EFalse; + } + + TReal real; + CAknNumericEdwin::TValidationStatus validationStatus = editor->GetValueAsReal( real ); + + // The enter number is not valid if GetValueAsReal function's return value is not EValueValid + if ( validationStatus != CAknNumericEdwin::EValueValid /*&& validationStatus != CAknNumericEdwin::EValueTooLarge*/ ) + { + return EFalse; + } + return ETrue; + } + + + +// ---------------------------------------------------- +// CCnvMainForm::HandleEdwinEventL +// Checks the Navigation events on the editor +// ---------------------------------------------------- +// + +void CCnvMainForm::HandleEdwinEventL(CEikEdwin* /*aEdwin*/,TEdwinEvent aEventType) + { + if(EEventNavigation == aEventType) + { + isEdwinNavigated = ETrue; + } + if( aEventType == EEventTextUpdate ) + { + isEdwinUpdateText = ETrue; + } + + } + +// ---------------------------------------------------- +// CCnvMainForm::IsDigit +// Converts the digit from any digit mode (devangiri or arabic) +// to western digit and checks whether it is a valid digit or not. +// ---------------------------------------------------- +// +TBool CCnvMainForm::IsDigit(TUint aChar) + { + TBuf<1> digit; + digit.Append(aChar); + + AknTextUtils::ConvertDigitsTo(digit , EDigitTypeWestern); + + TChar ch = digit[0]; + return ch.IsDigit(); + } + +// ---------------------------------------------------- +// CCnvMainForm::PrepareForFocusTransitionL +// The Uikon framework calls this function immediately before focus move. +// ---------------------------------------------------- +// +void CCnvMainForm::PrepareForFocusTransitionL() + { + TInt controlId( IdOfFocusControl() ); + if ( ( EConverterEditor1 == controlId ) || ( EConverterEditor2 == controlId ) ) + { + + // record the last use editor id + iLastUsedEditorId = controlId; + CancelConversion(); + if ( EditorValueCausesHold( controlId ) ) + { + SetFloatEditorValueL( controlId, 0.0 ); + } + + // Delete the radix point when there is no number behind it. + else if ( IsVaildNumberEntered( controlId ) ) + { + CEikFloatingPointEditor* editor = + static_cast ( Control( controlId ) ); + TBuf editorText; + editor->GetText( editorText ); + TLocale locale; + TInt editorLength = editorText.Length(); + + // Check if the last character is radix point. + if ( editorText[ editorLength - 1 ] == locale.DecimalSeparator() ) + { + editorText.Delete( editorLength - 1, 1 ); + editor->SetTextL( &editorText ); + } + } + } + } + +// ---------------------------------------------------- +// CCnvMainForm::ValueCalculation +// Do the calculation and change the value for the related edit field +// ---------------------------------------------------- +// +void CCnvMainForm::ValueCalculationL( TUint aUnit1Popup, TUint aUnit2Popup, TReal aMount ) + { + TReal result( 0.0 ); + // Use "LastUnit1" and "LastUnit2" to insure that the second amount don't change if the last used editor + // is the second and the category's units do not change. + static TInt LastUnit1 = -1; + static TInt LastUnit2 = -1; + + // According to the UI Spec: + // 1. If the first conversion unit field is changed, a new conversion is calculated to the + // second amount field of units, or vice versa. + // 2. If the first edit field is changed, a new conversion is calculated to the second + // edit field, or vice versa. + if ( iLastUsedEditorId == EConverterEditor1 ) + { + //the first unit is changed + if ( ( ( IdOfFocusControl() != EConverterEditor1 ) && ( LastUnit1 != aUnit1Popup ) ) + || ( IdOfFocusControl() == EConverterTypePopup ) ) + { + aMount = FloatingPointEditorValue( EConverterEditor1 ); + result = iUnit1Category.Convert( aUnit1Popup, aUnit2Popup, aMount ); + SetFloatEditorValueL( EConverterEditor2, result ); + } + //the second unit is changed + else if ( ( IdOfFocusControl() != EConverterEditor1 ) && ( LastUnit2 != aUnit2Popup ) ) + { + aMount = FloatingPointEditorValue( EConverterEditor2 ); + result = iUnit1Category.Convert( aUnit2Popup, aUnit1Popup, aMount ); + SetFloatEditorValueL( EConverterEditor1, result ); + } + //the first amount field is changed + else + { + result = iUnit1Category.Convert( aUnit1Popup, aUnit2Popup, aMount ); + SetFloatEditorValueL( EConverterEditor2, result ); + } + } + else + { + //the first unit is changed + if ( ( ( IdOfFocusControl() != EConverterEditor2 ) && ( LastUnit1 != aUnit1Popup ) ) + || ( IdOfFocusControl() == EConverterTypePopup )) + { + aMount = FloatingPointEditorValue( EConverterEditor1 ); + result = iUnit1Category.Convert( aUnit1Popup, aUnit2Popup, aMount ); + SetFloatEditorValueL( EConverterEditor2, result ); + } + //the second unit is changed + else if ( ( IdOfFocusControl() != EConverterEditor2 ) && ( LastUnit2 != aUnit2Popup ) ) + { + aMount = FloatingPointEditorValue( EConverterEditor2 ); + result = iUnit1Category.Convert( aUnit2Popup, aUnit1Popup, aMount ); + SetFloatEditorValueL( EConverterEditor1, result ); + } + //the second amount field is changed + else + { + result = iUnit1Category.Convert( aUnit2Popup, aUnit1Popup, aMount ); + SetFloatEditorValueL( EConverterEditor1, result ); + } + } + + // record units of the category at this time. + LastUnit1 = aUnit1Popup; + LastUnit2 = aUnit2Popup; + } +//End of file