--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tsrc/consoleplayer/common/testappbase.cpp Fri Sep 03 19:37:02 2010 -0500
@@ -0,0 +1,1330 @@
+/*
+ * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * This component and the accompanying materials are made available
+ * under the terms of "Eclipse Public License v1.0"
+ * which accompanies this distribution, and is available
+ * at the URL "http://www.eclipse.org/legal/epl-v10.html".
+ *
+ * Initial Contributors:
+ * Nokia Corporation - initial contribution.
+ *
+ * Contributors:
+ *
+ * Description:
+ * Source file containing common test app functionality.
+ *
+ */
+
+#include <f32file.h>
+#include <remconcoreapitarget.h>
+#include <remconinterfaceselector.h>
+
+#include "testappbase.h"
+
+const TInt KLeftSoftKeyCode = EKeyDevice0;
+const TInt KRightSoftKeyCode = EKeyDevice1;
+
+const TInt KHelpWindowBorderPixels = 20;
+const TInt KHelpWindowSpaceBetweenColumns = 25;
+const TInt KHelpWindowSpaceBetweenRows = 2;
+
+struct TKeyListEntry
+ {
+ TInt keyCode;
+ const TText* keyName;
+ };
+
+const TKeyListEntry KSupportedKeys[KSupportedKeysCount] =
+ {
+ {EKeyEnter, STR("Enter")},
+ {EKeyUpArrow, STR("Up")},
+ {EKeyDownArrow, STR("Down")},
+ {EKeyLeftArrow, STR("Left")},
+ {EKeyRightArrow, STR("Right")},
+ {'0', STR("0")},
+ {'1', STR("1")},
+ {'2', STR("2")},
+ {'3', STR("3")},
+ {'4', STR("4")},
+ {'5', STR("5")},
+ {'6', STR("6")},
+ {'7', STR("7")},
+ {'8', STR("8")},
+ {'9', STR("9")},
+ {'*', STR("*")},
+ {'#', STR("#")}
+ };
+
+static TPtrC KeyName( TInt aIndex )
+ {
+ return TPtrC(KSupportedKeys[aIndex].keyName);
+ }
+
+// Portable app implementation
+
+CTestAppBase::CTestAppBase( TInt aFontSize ) :
+ CActive( EPriorityStandard ),
+ iFontSize( aFontSize ),
+ iHelpSemitransparentBackgroundActive( true )
+ {
+ CActiveScheduler::Add(this);
+ }
+
+CTestAppBase::~CTestAppBase()
+ {
+ delete iInterfaceSelector;
+ delete iHelpWindow;
+ delete iSelectionWindow;
+ delete iGc;
+ delete iWindowGroup;
+ delete iScreenDevice;
+ delete iTypefaceStore;
+ iWs.Close();
+ iFs.Close();
+ iFileHistory.ResetAndDestroy();
+ }
+
+void CTestAppBase::BaseConstructL( const TOperationsPage* aKeyMap, TInt aPageCount )
+ {
+ iKeyMap = aKeyMap;
+ iPageCount = aPageCount;
+
+ User::LeaveIfError( iFs.Connect() );
+
+ User::LeaveIfError( iWs.Connect() );
+
+ iScreenDevice = new(ELeave) CWsScreenDevice( iWs );
+ User::LeaveIfError( iScreenDevice->Construct() );
+ iDisplaySize = iScreenDevice->SizeInPixels();
+
+ User::LeaveIfError( iScreenDevice->CreateContext(iGc) );
+
+ iWindowGroup = new(ELeave) RWindowGroup( iWs );
+ User::LeaveIfError( iWindowGroup->Construct( KNullWsHandle ) );
+
+ iSelectionWindow = new(ELeave) RWindow( iWs );
+ User::LeaveIfError( iSelectionWindow->Construct( *iWindowGroup, KNullWsHandle ) );
+ iSelectionWindow->SetVisible(false);
+ iSelectionWindow->Activate();
+
+ // Load the font to be used for all text operations.
+ TFontSpec fontSpec;
+ fontSpec.iHeight = iFontSize;
+ iTypefaceStore = CFbsTypefaceStore::NewL(NULL);
+
+ User::LeaveIfError( iTypefaceStore->GetNearestFontToDesignHeightInPixels(iFont, fontSpec) );
+
+ CalculateHelpWindowSize();
+
+ iHelpWindowTopRight = TPoint(iDisplaySize.iWidth/2 - iHelpWindowSize.iWidth/2,
+ iDisplaySize.iHeight/2 - iHelpWindowSize.iHeight/2);
+
+ iHelpWindow = new(ELeave) RWindow( iWs );
+ User::LeaveIfError( iHelpWindow->Construct( *iWindowGroup, KNullWsHandle ) );
+ iHelpWindow->SetExtent( iHelpWindowTopRight, iHelpWindowSize );
+ iHelpWindow->SetTransparencyAlphaChannel();
+ iHelpWindow->SetBackgroundColor(KRgbTransparent);
+ iHelpWindow->SetVisible(false);
+ iHelpWindow->Activate();
+ iHelpWindow->PointerFilter(EPointerFilterDrag, 0);
+
+ // Initialize soft key indices
+ for( TInt i = 0; i < aPageCount; i++ )
+ {
+ iSoftkeyIndices[i] = iKeyMap[i].defaultSoftkeyIndex;
+ }
+
+ // Only need to draw the help text when the options page is changed. Window is displayed later by
+ // toggling the visibility of the window.
+ DrawHelpText();
+
+ // THE FOLLOWING CODE IS COMMENTED OUT BECAUSE IT CAUSES A CRASH IN NCP BUILDS.
+ // THIS CAN BE ENABLED IN DFS BUILDS, TO ALLOW FOR TWO BUTTON OPERATION USING THE VOLUME KEYS.
+ //
+ // Since some phone have no keyboard or soft keys, treat the volume keys like the soft keys.
+ // SetupVolumeKeysL();
+ }
+
+void CTestAppBase::SetupVolumeKeysL()
+ {
+ iInterfaceSelector = CRemConInterfaceSelector::NewL();
+ iCoreTarget = CRemConCoreApiTarget::NewL(*iInterfaceSelector, *this);
+ iInterfaceSelector->OpenTargetL();
+ }
+
+void CTestAppBase::StartMonitoringWindowEvents()
+ {
+ // Request notification for windows server events, to detect key presses.
+ SetActive();
+ iWs.EventReady( &iStatus );
+ }
+
+TInt CTestAppBase::CurrentPageNumber()
+ {
+ return iCurrentPage+1;
+ }
+
+TPtrC CTestAppBase::CurrentPageName()
+ {
+ return TPtrC(iKeyMap[iCurrentPage].pageName);
+ }
+
+TPtrC CTestAppBase::CurrentSoftkeyName()
+ {
+ return TPtrC(iKeyMap[iCurrentPage].mapping[iSoftkeyIndices[iCurrentPage]].text);
+ }
+
+TPtrC CTestAppBase::KeyMapText( TInt aIndex, TInt aPage )
+ {
+ return TPtrC(iKeyMap[aPage].mapping[aIndex].text);
+ }
+
+TInt CTestAppBase::KeyMapOperation(TInt aIndex, TInt aPage )
+ {
+ return iKeyMap[aPage].mapping[aIndex].operation;
+ }
+
+void CTestAppBase::IncrementKeymapIndex( TInt& aIndex, TInt aPage )
+ {
+ aIndex = (aIndex + 1) % KSupportedKeysCount;
+ while( iKeyMap[aPage].mapping[aIndex].operation == KOperation_None )
+ {
+ aIndex = (aIndex + 1) % KSupportedKeysCount;
+ }
+ }
+
+void CTestAppBase::DecrementKeymapIndex( TInt& aIndex, TInt aPage )
+ {
+ aIndex = (aIndex + KSupportedKeysCount - 1) % KSupportedKeysCount;
+ while( iKeyMap[aPage].mapping[aIndex].operation == KOperation_None )
+ {
+ aIndex = (aIndex + KSupportedKeysCount - 1) % KSupportedKeysCount;
+ }
+ }
+
+void CTestAppBase::CalculateHelpWindowSize()
+ {
+ iHelpWindowColumn1Width = 0;
+ iHelpWindowColumn2Width = 0;
+
+ // Find the widest strings for each column to determine the width of the window.
+ for( TInt index = 0; index < KSupportedKeysCount; index++ )
+ {
+ TInt width = iFont->TextWidthInPixels(KeyName(index));
+ if( width > iHelpWindowColumn1Width )
+ {
+ iHelpWindowColumn1Width = width;
+ }
+
+ for( TInt index2 = 0; index2 < iPageCount; index2++ )
+ {
+ width = iFont->TextWidthInPixels(KeyMapText(index,index2));
+ if( width > iHelpWindowColumn2Width )
+ {
+ iHelpWindowColumn2Width = width;
+ }
+ }
+ }
+
+ iHelpWindowSize.iWidth = 2*KHelpWindowBorderPixels + iHelpWindowColumn1Width +
+ KHelpWindowSpaceBetweenColumns + iHelpWindowColumn2Width;
+
+ iHelpWindowSize.iHeight = 2*KHelpWindowBorderPixels + iFontSize*KSupportedKeysCount +
+ KHelpWindowSpaceBetweenRows*(KSupportedKeysCount-1);
+ }
+
+void CTestAppBase::StartReceivingPointerEvents()
+ {
+ iRoutePointerEventsToApp = true;
+ }
+
+void CTestAppBase::StopReceivingPointerEvents()
+ {
+ iRoutePointerEventsToApp = false;
+ }
+
+//virtual void HandlePointerEvent( const TPointerEvent& aEvent ) {}
+
+CTestAppBase::TTestAppPointerEvent CTestAppBase::CharacterizePointerEvent( const TAdvancedPointerEvent& event )
+ {
+ TTestAppPointerEvent returnValue = EPointerEvent_None;
+
+ RDebug::Printf( "POINTER EVENT:" );
+ RDebug::Printf( "iType=%i", event.iType );
+ RDebug::Printf( "iModifiers=%x", event.iModifiers );
+ RDebug::Printf( "iPosition=%i,%i", event.iPosition.iX, event.iPosition.iY );
+ RDebug::Printf( "iParentPosition=%i,%i", event.iParentPosition.iX, event.iParentPosition.iY );
+ RDebug::Printf( "PointerNumber=%i", event.PointerNumber() );
+ RDebug::Printf( "Proximity=%i", event.Proximity() );
+ RDebug::Printf( "Pressure=%i", event.Pressure() );
+ RDebug::Printf( "ProximityAndPressure=%i", event.ProximityAndPressure() );
+ RDebug::Printf( "Position3D=%i,%i,%i", event.Position3D().iX, event.Position3D().iY, event.Position3D().iZ );
+ RDebug::Printf( "Pressure3D=%i,%i,%i", event.Pressure3D().iX, event.Pressure3D().iY, event.Pressure3D().iZ );
+ RDebug::Printf( "PositionAndPressure3D=%i,%i,%i", event.PositionAndPressure3D().iX, event.PositionAndPressure3D().iY, event.PositionAndPressure3D().iZ );
+
+ switch( event.iType )
+ {
+ case TPointerEvent::EButton1Down:
+ {
+ iPointerDownPosition = event.iPosition;
+ break;
+ }
+ case TPointerEvent::EButton1Up:
+ {
+ TInt xDelta = event.iPosition.iX - iPointerDownPosition.iX;
+ TInt yDelta = event.iPosition.iY - iPointerDownPosition.iY;
+
+ TInt xMagnitude = xDelta;
+ if( xMagnitude < 0 )
+ {
+ xMagnitude = -xMagnitude;
+ }
+
+ TInt yMagnitude = yDelta;
+ if( yMagnitude < 0 )
+ {
+ yMagnitude = -yMagnitude;
+ }
+
+ const TInt KTapThreshold = 30;
+
+ if( yMagnitude > xMagnitude )
+ {
+ if( yMagnitude < KTapThreshold )
+ {
+ RDebug::Printf( "POINTER EVENT ENTER x=%i y=%i", xDelta, yDelta );
+ returnValue = EPointerEvent_Select;
+ }
+ else if( yDelta < 0 )
+ {
+ RDebug::Printf( "POINTER EVENT UP x=%i y=%i", xDelta, yDelta );
+ returnValue = EPointerEvent_Up;
+ }
+ else
+ {
+ RDebug::Printf( "POINTER EVENT DOWN x=%i y=%i", xDelta, yDelta );
+ returnValue = EPointerEvent_Down;
+ }
+ }
+ else
+ {
+ if( xMagnitude < KTapThreshold )
+ {
+ RDebug::Printf( "POINTER EVENT ENTER x=%i y=%i", xDelta, yDelta );
+ returnValue = EPointerEvent_Select;
+ }
+ else if( xDelta < 0 )
+ {
+ RDebug::Printf( "POINTER EVENT LEFT x=%i y=%i", xDelta, yDelta );
+ returnValue = EPointerEvent_Left;
+ }
+ else
+ {
+ RDebug::Printf( "POINTER EVENT RIGHT x=%i y=%i", xDelta, yDelta );
+ returnValue = EPointerEvent_Right;
+ }
+ }
+ break;
+ }
+ }
+
+ return returnValue;
+ }
+
+void CTestAppBase::RunL()
+ {
+ if( iWait.IsStarted() )
+ {
+ // This is an event during synchronous list selection. Stop the nested scheduler.
+ iWait.AsyncStop();
+ return;
+ }
+
+ TWsEvent event;
+ iWs.GetEvent(event);
+
+ TInt operationIndex = -1;
+
+ TInt keyCode = 0;
+ bool processKeyCode = false;
+
+ TInt operation = KOperation_None;
+
+ // Other potentially useful events are EEventKeyUp and EEventKeyDown.
+
+ if( event.Type() == EEventKey )
+ {
+ keyCode = event.Key()->iCode;
+
+ RDebug::Printf( "key event keyCode=%x/%c scanCode=%x/%c", keyCode, keyCode, event.Key()->iScanCode, event.Key()->iScanCode );
+
+ // Allow subclasses a chance to consume the key event directly. If that happens, then
+ // do not handle the key as normal.
+ if( !ConsumeKeyEvent( keyCode ) )
+ {
+ processKeyCode = true;
+ }
+ }
+ else if( event.Type() == EEventPointer )
+ {
+ TAdvancedPointerEvent* p = event.Pointer();
+
+ if( iRoutePointerEventsToApp )
+ {
+ HandlePointerEvent( *p );
+ }
+ else
+ {
+ TTestAppPointerEvent pointerEvent = CharacterizePointerEvent( *p );
+
+ switch( pointerEvent )
+ {
+ case EPointerEvent_None:
+ // Do nothing.
+ break;
+ case EPointerEvent_Up:
+ operation = KOperation_PreviousOption;
+ break;
+ case EPointerEvent_Down:
+ operation = KOperation_NextOption;
+ break;
+ case EPointerEvent_Left:
+ operation = KOperation_PreviousOptionPage;
+ break;
+ case EPointerEvent_Right:
+ operation = KOperation_NextOptionPage;
+ break;
+ case EPointerEvent_Select:
+ operation = KOperation_ExecuteOption;
+ break;
+ }
+ }
+ }
+ else
+ {
+ RDebug::Printf( "other event, type=%i", event.Type() );
+ }
+
+ if( processKeyCode )
+ {
+ // If one of the softkeys were pressed then take the appropriate action.
+ // This is to support a two button touch device with no numeric keypad.
+ // Support 'A' and 'B' also, for the NCP emulator where a keyboard is
+ // not displayed.
+ switch( keyCode )
+ {
+ case KLeftSoftKeyCode:
+ case 'a':
+ case 'A':
+ {
+ operation = KOperation_NextOption;
+ break;
+ }
+ case KRightSoftKeyCode:
+ case 'b':
+ case 'B':
+ {
+ // Execute softkey function.
+ operation = KOperation_ExecuteOption;
+ break;
+ }
+ default:
+ {
+ // Search for keycode in keymap. If not found then the key was not a valid
+ // key, so ignore.
+ TInt index = 0;
+ while( (index < KSupportedKeysCount) && (operationIndex == -1))
+ {
+ if( KSupportedKeys[index].keyCode == keyCode )
+ {
+ // Found!
+ operationIndex = index;
+ }
+ else
+ {
+ index++;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if( operation == KOperation_ExecuteOption )
+ {
+ operationIndex = iSoftkeyIndices[iCurrentPage];
+ }
+
+ if( operationIndex >= 0 )
+ {
+ operation = KeyMapOperation(operationIndex, iCurrentPage);
+ }
+
+ if( operation != KOperation_None )
+ {
+ // Valid operation.
+
+ switch( operation )
+ {
+ case KOperation_Exit:
+ {
+ CActiveScheduler::Stop();
+ break;
+ }
+ case KOperation_PreviousOption:
+ {
+ // Change softkey function.
+ DecrementKeymapIndex( iSoftkeyIndices[iCurrentPage], iCurrentPage );
+
+ // Redraw help text, since a new function should now be underlined.
+ DrawHelpText();
+
+ // Notify subclass that softkey function has been updated.
+ SoftkeyFunctionUpdated();
+ break;
+ }
+ case KOperation_NextOption:
+ {
+ // Change softkey function.
+ IncrementKeymapIndex( iSoftkeyIndices[iCurrentPage], iCurrentPage );
+
+ // Redraw help text, since a new function should now be underlined.
+ DrawHelpText();
+
+ // Notify subclass that softkey function has been updated.
+ SoftkeyFunctionUpdated();
+ break;
+ }
+ case KOperation_PreviousOptionPage:
+ {
+ iCurrentPage = (iCurrentPage + iPageCount - 1) % iPageCount;
+ DrawHelpText();
+ SoftkeyFunctionUpdated();
+ break;
+ }
+ case KOperation_NextOptionPage:
+ {
+ iCurrentPage = (iCurrentPage + 1) % iPageCount;
+ DrawHelpText();
+ SoftkeyFunctionUpdated();
+ break;
+ }
+ case KOperation_ToggleHelpVisibility:
+ {
+ // Toggle help text on/off.
+ iHelpActive = !iHelpActive;
+ iHelpWindow->SetVisible(iHelpActive);
+ break;
+ }
+ case KOperation_ToggleHelpTransparency:
+ {
+ iHelpSemitransparentBackgroundActive = !iHelpSemitransparentBackgroundActive;
+ if( iHelpSemitransparentBackgroundActive )
+ {
+ // Turn on help if it is currently off.
+ iHelpActive = true;
+ iHelpWindow->SetVisible(true);
+ }
+ DrawHelpText();
+ break;
+ }
+ default:
+ {
+ // Pass operation to subclass.
+ TPtrC operatioName( KeyMapText(operationIndex, iCurrentPage) );
+ ExecuteOperation( operation, operatioName );
+ break;
+ }
+ }
+ }
+
+ SetActive();
+ iWs.EventReady( &iStatus );
+ }
+
+void CTestAppBase::DoCancel()
+ {
+ iWs.EventReadyCancel();
+ }
+
+// TODO: ALLOW SUBCLASS TO SPECIFY COLOR SELECTIONS
+
+TInt CTestAppBase::SelectFromListL( TPoint aTopLeft,
+ TSize aSize,
+ const TDesC& aHeaderText,
+ RPointerArray<TDesC>& aSelectionList,
+ TInt aInitialSelectionIndex )
+ {
+ iSelectionWindow->SetExtent( aTopLeft, aSize );
+ iSelectionWindow->SetVisible( true );
+
+ const TInt KRowIncrement = iFontSize + 2;
+
+ TInt entriesPerPage = aSize.iHeight / KRowIncrement - 4;
+
+ TInt returnValue = -2;
+ TInt startIndex = 0;
+ TInt selected = aInitialSelectionIndex;
+
+ while( returnValue == -2 )
+ {
+ iGc->Activate(*iSelectionWindow);
+
+ iSelectionWindow->Invalidate();
+ iSelectionWindow->BeginRedraw();
+
+ iGc->Reset();
+
+ iGc->UseFont(iFont);
+ iGc->SetBrushColor(KRgbDarkBlue);
+
+ iGc->Clear();
+
+ // KRgbWhite seems to be having problems (0xffffff) in some emulators,
+ // but 0xfefefe is working, so use that instead of white.
+ iGc->SetPenColor(0xfefefe);
+
+ const TInt KHeaderColumn = 5;
+ const TInt KEntryColumn = 15;
+
+ TInt row = KRowIncrement;
+
+ iGc->SetUnderlineStyle(EUnderlineOff);
+
+ iGc->DrawText( aHeaderText, TPoint(KHeaderColumn, row) );
+ row += (KRowIncrement + 5);
+
+ TBool again = true;
+ TInt backIndex = -1;
+ TInt forwardIndex = -1;
+ TInt offset = 0;
+
+ while( again )
+ {
+ if( selected == offset )
+ {
+ iGc->SetUnderlineStyle(EUnderlineOn);
+ }
+ else
+ {
+ iGc->SetUnderlineStyle(EUnderlineOff);
+ }
+
+ if( (offset < entriesPerPage) && (startIndex+offset < aSelectionList.Count()) )
+ {
+ iGc->DrawText( *aSelectionList[startIndex+offset], TPoint(KEntryColumn, row) );
+ row += KRowIncrement;
+
+ offset++;
+ }
+ else
+ {
+ again = false;
+ if( startIndex + offset < aSelectionList.Count() )
+ {
+ iGc->DrawText( _L("<page down>"), TPoint(KEntryColumn, row) );
+ row += KRowIncrement;
+
+ forwardIndex = offset;
+ offset++;
+ }
+ if( startIndex > 0 )
+ {
+ if( selected == offset )
+ {
+ iGc->SetUnderlineStyle(EUnderlineOn);
+ }
+ else
+ {
+ iGc->SetUnderlineStyle(EUnderlineOff);
+ }
+
+ iGc->DrawText( _L("<page up>"), TPoint(KEntryColumn, row) );
+ row += KRowIncrement;
+
+ backIndex = offset;
+ offset++;
+ }
+ }
+ }
+
+ iSelectionWindow->EndRedraw();
+
+ iGc->Deactivate();
+
+ TInt keyCode = WaitForAnyKey();
+
+ switch( keyCode )
+ {
+ case EKeyUpArrow:
+ if( selected == 0 )
+ {
+ selected = offset-1;
+ }
+ else
+ {
+ selected -= 1;
+ }
+ break;
+
+ case EKeyDownArrow:
+ case KLeftSoftKeyCode:
+ case 'a':
+ case 'A':
+ selected += 1;
+ if( selected == offset )
+ {
+ selected = 0;
+ }
+ break;
+
+ case EKeyLeftArrow:
+ if( backIndex >= 0 )
+ {
+ startIndex -= entriesPerPage;
+ selected = 0;
+ }
+ else
+ {
+ returnValue = -1;
+ again = false;
+ }
+ break;
+
+ case EKeyRightArrow:
+ if( forwardIndex >= 0 )
+ {
+ startIndex += entriesPerPage;
+ selected = 0;
+ }
+ break;
+
+ case EKeyEnter:
+ case KRightSoftKeyCode:
+ case 'b':
+ case 'B':
+ if( selected == forwardIndex )
+ {
+ startIndex += entriesPerPage;
+ selected = 0;
+ }
+ else if( selected == backIndex )
+ {
+ startIndex -= entriesPerPage;
+ selected = 0;
+ }
+ else
+ {
+ returnValue = startIndex+selected;
+ }
+ break;
+ }
+ }
+
+ iSelectionWindow->SetVisible( false );
+
+ return returnValue;
+ }
+
+TInt CTestAppBase::SelectFromListL( TPoint aTopLeft,
+ TSize aSize,
+ const TDesC& aHeaderText,
+ RPointerArray<HBufC>& aSelectionList,
+ TInt aInitialSelectionIndex )
+ {
+ RPointerArray<TDesC> aSelectionList2;
+
+ for( TInt index = 0; index < aSelectionList.Count(); index++ )
+ {
+ aSelectionList2.Append( aSelectionList[index]);
+ }
+
+ TInt returnValue = SelectFromListL( aTopLeft, aSize, aHeaderText, aSelectionList2, aInitialSelectionIndex );
+
+ aSelectionList2.Close();
+
+ return returnValue;
+ }
+
+void CTestAppBase::BuildDriveListL( RPointerArray<HBufC>& aDrives )
+ {
+ TDriveList driveList;
+ TInt err = iFs.DriveList( driveList );
+
+ for( TInt index = 0; index < driveList.Length(); index++ )
+ {
+ if( driveList[index] != 0 )
+ {
+ HBufC* drive = HBufC::NewL( 2 );
+ drive->Des().Format( _L("%c:"), 'A' + index);
+ aDrives.Append( drive );
+ }
+ }
+ }
+
+bool CTestAppBase::SelectDriveL( TPoint aTopLeft,
+ TSize aWindowSize,
+ const TDesC& aHeaderText,
+ TDes& aDrive )
+ {
+ RPointerArray<HBufC> drives;
+ BuildDriveListL( drives );
+
+ TInt index = SelectFromListL( aTopLeft, aWindowSize, aHeaderText, drives );
+
+ bool returnValue = false;
+
+ if( index >= 0 )
+ {
+ returnValue = true;
+ aDrive.Copy( *(drives[index]) );
+ aDrive.Append( _L("\\") );
+ }
+
+ drives.ResetAndDestroy();
+
+ return returnValue;
+ }
+
+bool CTestAppBase::SelectFileL( TPoint aTopLeft,
+ TSize aWindowSize,
+ const TDesC& aHeaderText,
+ const TDesC& aDrive,
+ TDes& aFullFilename )
+ {
+ TFileName directory;
+
+ DoSelectFileL( aTopLeft, aWindowSize, aHeaderText, aDrive, 0, directory, aFullFilename );
+
+ aFullFilename.Insert( 0, directory );
+
+ return aFullFilename.Length() > 0;
+ }
+
+bool CTestAppBase::SelectFileWithHistoryL( TPoint aTopLeft,
+ TSize aSize,
+ TDes& aFullFilename,
+ const TDesC& aHistoryFilename,
+ TInt aMaxHistoryEntries,
+ const TDesC& aPrompt )
+ {
+ RPointerArray<HBufC> drives;
+ BuildDriveListL( drives );
+
+ RPointerArray<TDesC> selections;
+
+ for( TInt index = 0; index < drives.Count(); index++ )
+ {
+ selections.Append( drives[index]);
+ }
+ TInt drivesBaseIndex = 0;
+
+ // Add file history to the end of the drive list. Newest files are last, so add in reverse order.
+ // For convenience, add the last history entry at the top, before the drive list.
+ ReadFileHistory( aHistoryFilename );
+ if( iFileHistory.Count() > 0 )
+ {
+ selections.Insert( iFileHistory[iFileHistory.Count()-1], 0 );
+ drivesBaseIndex++;
+ }
+ for(TInt index = iFileHistory.Count()-2; index >= 0; index-- )
+ {
+ selections.Append( iFileHistory[index]);
+ }
+
+ bool done = false;
+ bool selected = true;
+
+ while( !done )
+ {
+ TInt index = SelectFromListL( aTopLeft, aSize, aPrompt, selections );
+
+ if( index < 0 )
+ {
+ selected = false;
+ done = true;
+ }
+ else if( (index >= drivesBaseIndex) && (index - drivesBaseIndex < drives.Count()) )
+ {
+ TBuf<10> drive;
+ drive.Copy( *(selections[index]) );
+ drive.Append( _L("\\") );
+
+ done = SelectFileL( aTopLeft, aSize, aPrompt, drive, aFullFilename );
+ }
+ else
+ {
+ // Remove the selected file from the history, so that it will pop up to the top of the list
+ // as the most recently selected file.
+ TInt historyIndex;
+ if( index == 0 )
+ {
+ historyIndex = iFileHistory.Count() - 1;
+ }
+ else
+ {
+ historyIndex = iFileHistory.Count() - index + drives.Count() - 1;
+ }
+ aFullFilename.Copy( *(selections[index]) );
+ delete iFileHistory[historyIndex];
+ iFileHistory.Remove( historyIndex );
+
+ done = true;
+ }
+ }
+
+ if( selected )
+ {
+ AddToFileHistory( aFullFilename, aHistoryFilename, aMaxHistoryEntries );
+ }
+
+ selections.Reset();
+ drives.ResetAndDestroy();
+
+ return selected;
+ }
+
+bool CTestAppBase::SelectIntegerL( TPoint aTopLeft,
+ TSize aSize,
+ const TDesC& aHeaderText,
+ TInt aMin,
+ TInt aMax,
+ TInt& aSelection )
+ {
+ // currently no way to exit out of this selection
+
+ iSelectionWindow->SetExtent( aTopLeft, aSize );
+ iSelectionWindow->SetVisible( true );
+
+ bool done = false;
+
+ while( !done )
+ {
+ iGc->Activate(*iSelectionWindow);
+
+ iSelectionWindow->Invalidate();
+ iSelectionWindow->BeginRedraw();
+
+ iGc->Reset();
+
+ iGc->UseFont(iFont);
+ iGc->SetBrushColor(KRgbDarkBlue);
+
+ iGc->Clear();
+
+ // KRgbWhite seems to be having problems (0xffffff) in some emulators,
+ // but 0xfefefe is working, so use that instead of white.
+ iGc->SetPenColor(0xfefefe);
+
+ TBuf<120> buffer;
+ buffer.Copy( aHeaderText );
+ buffer.AppendFormat( _L(" %i"), aSelection );
+
+ iGc->DrawText( buffer, TPoint(5, iFontSize+2) );
+
+ iSelectionWindow->EndRedraw();
+
+ iGc->Deactivate();
+
+ TInt keyCode = WaitForAnyKey();
+
+ switch( keyCode )
+ {
+ case EKeyUpArrow:
+ aSelection -= 10;
+ break;
+
+ case EKeyDownArrow:
+ case KLeftSoftKeyCode:
+ case 'a':
+ case 'A':
+ aSelection += 10;
+ break;
+
+ case EKeyLeftArrow:
+ aSelection--;
+ break;
+
+ case EKeyRightArrow:
+ aSelection++;
+ break;
+
+ case EKeyEnter:
+ case KRightSoftKeyCode:
+ case 'b':
+ case 'B':
+ done = true;
+ break;
+ }
+
+ if( aSelection > aMax )
+ {
+ aSelection = aMin;
+ }
+ else if( aSelection < aMin )
+ {
+ aSelection = aMax;
+ }
+ }
+
+ iSelectionWindow->SetVisible( false );
+
+ return true;
+ }
+
+TInt CTestAppBase::WaitForAnyKey()
+ {
+ TInt returnValue = 0;
+
+ bool done = false;
+
+ while( !done )
+ {
+ // Have to use this tricky nested active scheduler technique to allow the active object
+ // used to remap volume keys to run.
+ SetActive();
+ iWs.EventReady( &iStatus );
+ iWait.Start();
+
+ TWsEvent event;
+ iWs.GetEvent(event);
+
+ // Other potentially useful events are EEventKeyUp and EEventKeyDown.
+
+ if( event.Type() == EEventKey )
+ {
+ done = true;
+ returnValue = event.Key()->iCode;
+ }
+ else if( event.Type() == EEventPointer )
+ {
+ TAdvancedPointerEvent* p = event.Pointer();
+
+ TTestAppPointerEvent pointerEvent = CharacterizePointerEvent( *p );
+
+ switch( pointerEvent )
+ {
+ case EPointerEvent_None:
+ // Do nothing.
+ break;
+ case EPointerEvent_Up:
+ returnValue = EKeyUpArrow;
+ done = true;
+ break;
+ case EPointerEvent_Down:
+ returnValue = EKeyDownArrow;
+ done = true;
+ break;
+ case EPointerEvent_Left:
+ returnValue = EKeyLeftArrow;
+ done = true;
+ break;
+ case EPointerEvent_Right:
+ returnValue = EKeyRightArrow;
+ done = true;
+ break;
+ case EPointerEvent_Select:
+ returnValue = EKeyEnter;
+ done = true;
+ break;
+ }
+ }
+ }
+
+ return returnValue;
+ }
+
+TInt CTestAppBase::ReadFile( const TDesC& aFilename, RPointerArray<HBufC>& aContents )
+ {
+ RFile inputFile;
+ TInt err = inputFile.Open(iFs, aFilename, EFileShareReadersOnly | EFileStream | EFileRead );
+
+ if( err == KErrNone )
+ {
+ TInt fileSize;
+ inputFile.Size( fileSize );
+
+ RBuf8 contents;
+ contents.Create( fileSize );
+
+ inputFile.Read( contents, fileSize );
+
+ inputFile.Close();
+
+ TPtrC8 remaining( contents );
+
+ while( remaining.Length() > 0 )
+ {
+ // Removing leading CR/LFs, if any.
+ while( remaining.Length() > 0 && (remaining[0] == '\n' || remaining[0] == '\r') )
+ {
+ remaining.Set(remaining.Right(remaining.Length()-1));
+ }
+
+ if( remaining.Length() == 0 )
+ {
+ break;
+ }
+
+ // Find next CR/LF, or end of string.
+ TInt separatorIndex = 1;
+ while( (separatorIndex < remaining.Length()) &&
+ (remaining[separatorIndex] != '\n') &&
+ (remaining[separatorIndex] != '\r'))
+ {
+ separatorIndex++;
+ }
+
+ HBufC* line = HBufC::NewL( separatorIndex );
+ TPtrC8 line8 = remaining.Left( separatorIndex );
+ line->Des().Copy( line8 );
+
+ aContents.Append( line );
+
+ TInt remainingLength = remaining.Length() - separatorIndex;
+
+ remaining.Set(remaining.Right(remainingLength));
+ }
+
+ contents.Close();
+ }
+
+ return err;
+ }
+
+void CTestAppBase::ReadFileHistory( const TDesC& aHistoryFilename )
+ {
+ iFileHistory.ResetAndDestroy();
+
+ ReadFile( aHistoryFilename, iFileHistory );
+ }
+
+void CTestAppBase::AddToFileHistory( const TDesC& aFilename, const TDesC& aHistoryFilename, TInt aMaxHistoryEntries )
+ {
+ HBufC* filename = HBufC::NewL( aFilename.Length() );
+ filename->Des().Copy( aFilename );
+ iFileHistory.Append( filename );
+
+ while( iFileHistory.Count() > aMaxHistoryEntries )
+ {
+ delete iFileHistory[0];
+ iFileHistory.Remove( 0 );
+ }
+
+ RFile historyFile;
+ TInt err = historyFile.Create(iFs, aHistoryFilename, EFileStream | EFileWrite );
+ if( err == KErrAlreadyExists )
+ {
+ err = historyFile.Open(iFs, aHistoryFilename, EFileStream | EFileWrite );
+ historyFile.SetSize(0);
+ }
+
+ if( err == KErrNone )
+ {
+ for( TInt index = 0; index < iFileHistory.Count(); index++ )
+ {
+ TBuf8<KMaxFileName> filename8;
+ filename8.Copy( iFileHistory[index]->Des() );
+ historyFile.Write( filename8 );
+ historyFile.Write( _L8("\n") );
+ }
+ }
+
+ historyFile.Close();
+ }
+
+void CTestAppBase::DoSelectFileL( TPoint aTopRight,
+ TSize aWindowSize,
+ const TDesC& aHeaderText,
+ const TFileName& aDirectory,
+ TInt aDirectoryLevel,
+ TDes& aSelectedDirectory,
+ TDes& aSelectedFilename )
+ {
+ RPointerArray<TDesC> fileNames;
+
+ ReadDirectoryEntriesL( aDirectory, fileNames );
+
+ TInt initialSelectionIndex = 0;
+
+ _LIT( KUp, ".." );
+ if( aDirectoryLevel > 0 )
+ {
+ TFileName* newEntry = new(ELeave) TFileName;
+ newEntry->Copy( KUp );
+ fileNames.Insert( newEntry, 0 );
+ initialSelectionIndex++;
+ }
+
+ bool done = false;
+
+ while( !done && (aSelectedFilename.Length() == 0) )
+ {
+ TInt index = SelectFromListL( aTopRight, aWindowSize, aHeaderText, fileNames, initialSelectionIndex );
+
+ if( index < 0 || index >= fileNames.Count() )
+ {
+ done = true;
+ }
+ else if( fileNames[index]->Compare(KUp) == 0 )
+ {
+ // Go up one directory. Return to caller without setting aFilename
+ break;
+ }
+ else if( (*fileNames[index])[fileNames[index]->Length()-1] == '\\' )
+ {
+ // Directory selected.
+ TFileName directory;
+ directory.Copy( aDirectory );
+ directory.Append( *fileNames[index] );
+ DoSelectFileL( aTopRight, aWindowSize, aHeaderText, directory, aDirectoryLevel+1, aSelectedDirectory, aSelectedFilename );
+ }
+ else
+ {
+ // File selected.
+ aSelectedDirectory.Copy( aDirectory );
+ aSelectedFilename.Copy( *fileNames[index] );
+ done = true;
+ }
+
+ }
+
+ fileNames.ResetAndDestroy();
+ }
+
+void CTestAppBase::ReadDirectoryEntriesL( const TFileName& aDirectoryName, RPointerArray<TDesC>& aFileNames )
+ {
+ aFileNames.ResetAndDestroy();
+
+ RDir dir;
+ User::LeaveIfError( dir.Open( iFs, aDirectoryName, KEntryAttNormal|KEntryAttDir) );
+
+ TEntryArray entries;
+ TInt err = KErrNone;
+ TInt directoryCount = 0;
+ while( err == KErrNone )
+ {
+ err = dir.Read( entries );
+
+ for( TInt index = 0; index < entries.Count(); index++ )
+ {
+ // It was observed that not all devices sorted the list by default, so do an
+ // insertion sort here.
+ TFileName* newEntry = new(ELeave) TFileName;
+ newEntry->Copy( entries[index].iName );
+
+ // Put the directories first in the list.
+ if( entries[index].IsDir())
+ {
+ newEntry->Append( _L("\\") );
+
+ TInt insertionIndex = 0;
+ while( insertionIndex < directoryCount && newEntry->CompareF(*aFileNames[insertionIndex]) > 0 )
+ {
+ insertionIndex++;
+ }
+ aFileNames.Insert( newEntry, insertionIndex );
+
+ directoryCount++;
+ }
+ else
+ {
+ TInt insertionIndex = directoryCount;
+ while( insertionIndex < aFileNames.Count() && newEntry->CompareF(*aFileNames[insertionIndex]) > 0 )
+ {
+ insertionIndex++;
+ }
+ aFileNames.Insert( newEntry, insertionIndex );
+ }
+ }
+ }
+
+ dir.Close();
+ }
+
+void CTestAppBase::DrawHelpText()
+ {
+ iGc->Activate(*iHelpWindow);
+
+ iHelpWindow->Invalidate();
+ iHelpWindow->BeginRedraw();
+
+ iGc->Reset();
+
+ iGc->UseFont(iFont);
+ iGc->SetBrushColor(KRgbTransparent);
+
+ iGc->Clear();
+
+ if( iHelpSemitransparentBackgroundActive )
+ {
+ iGc->SetPenColor(KRgbTransparent);
+ iGc->SetBrushStyle(CWindowGc::ESolidBrush);
+ iGc->SetBrushColor( TRgb(0x7f7f7faf) );
+ iGc->DrawRect( TRect(iHelpWindowSize) );
+ }
+
+ // KRgbWhite seems to be having problems (0xffffff) in some emulators,
+ // but 0xfefefe is working, so use that instead of white.
+ iGc->SetPenColor(0xfefefe);
+
+ const TInt KColumn1 = KHelpWindowBorderPixels;
+ const TInt KColumn2 = KColumn1 + iHelpWindowColumn1Width + KHelpWindowSpaceBetweenColumns;
+ const TInt KRowIncrement = iFontSize + KHelpWindowSpaceBetweenRows;
+
+ TInt row = iFontSize + KHelpWindowBorderPixels;
+
+ for( TInt index = 0; index < KSupportedKeysCount; index++ )
+ {
+ iGc->SetUnderlineStyle(EUnderlineOff);
+
+ TPtrC text = KeyMapText( index, iCurrentPage );
+
+ iGc->DrawText( KeyName(index), TPoint(KColumn1, row) );
+
+ if( index == iSoftkeyIndices[iCurrentPage] )
+ {
+ iGc->SetUnderlineStyle(EUnderlineOn);
+ }
+ else
+ {
+ iGc->SetUnderlineStyle(EUnderlineOff);
+ }
+
+ iGc->DrawText( text, TPoint(KColumn2, row) );
+
+ row += KRowIncrement;
+ }
+
+ iHelpWindow->EndRedraw();
+
+ iGc->Deactivate();
+ }
+
+void CTestAppBase::MrccatoCommand( TRemConCoreApiOperationId aOperationId,
+ TRemConCoreApiButtonAction /*aButtonAct*/ )
+ {
+ // Treat volume up like the right soft key, and volume down like the left soft key.
+ TKeyEvent keyEvent;
+ keyEvent.iCode = 0;
+ keyEvent.iScanCode = 0;
+ keyEvent.iModifiers = 0;
+ keyEvent.iRepeats = 0;
+
+ switch (aOperationId)
+ {
+ case ERemConCoreApiVolumeUp:
+ keyEvent.iCode = KRightSoftKeyCode;
+ iWs.SimulateKeyEvent(keyEvent);
+ iWs.Flush();
+ break;
+ case ERemConCoreApiVolumeDown:
+ keyEvent.iCode = KLeftSoftKeyCode;
+ iWs.SimulateKeyEvent(keyEvent);
+ iWs.Flush();
+ break;
+ default:
+ break;
+ }
+ }