extras/converter/Ui/Src/CCnvMainForm.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Mon, 18 Jan 2010 20:20:33 +0200
changeset 0 3ee3dfdd8d69
child 6 57ec1f1a7fd2
permissions -rw-r--r--
Revision: 201001 Kit: 201003

/*
* 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 <barsread.h>
#include <eikenv.h>
#include <eikappui.h>
#include <eikfpne.h>
#include <avkon.hrh>
#include <AknPopupField.h>
#include <aknnotewrappers.h>
#include <eikmenup.h>
#include <s32file.h>
#include <ErrorUI.h>
#include <featmgr.h>

#include <hlplch.h>
#include <csxhelp/cnv.hlp.hrh>

#include <CCnvConverter.h>
#include <TCnvCategory.h>
#include <Converter.rsg>
#include "Converter.hrh"
#include "CCnvApplication.h"
#include "CCnvMainForm.h"
#include "CCnvRatesForm.h"

#include <aknnumed.h> 
#include <f32file.h>
#include <e32std.h>

_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<KEditorTextMaxLength> 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 <digit>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 <digit>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<CEikFloatingPointEditor*> (Control(
							iLastUsedEditorId));
			TBuf<KEditorTextMaxLength> 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<CEikFloatingPointEditor*> ( Control( controlId ) ); 
            TBuf<KEditorTextMaxLength> 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