extras/converter/Ui/Src/CCnvMainForm.cpp
changeset 0 3ee3dfdd8d69
child 6 57ec1f1a7fd2
--- /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 <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