mmserv/sts/tsrc/ststester/src/testappbase.cpp
changeset 14 80975da52420
equal deleted inserted replaced
12:5a06f39ad45b 14:80975da52420
       
     1 /*
       
     2  * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     3  * All rights reserved.
       
     4  * This component and the accompanying materials are made available
       
     5  * under the terms of "Eclipse Public License v1.0"
       
     6  * which accompanies this distribution, and is available
       
     7  * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8  *
       
     9  * Initial Contributors:
       
    10  * Nokia Corporation - initial contribution.
       
    11  *
       
    12  * Contributors:
       
    13  *
       
    14  * Description:
       
    15  * Source file containing common test app functionality.
       
    16  */
       
    17 
       
    18 #include <f32file.h>
       
    19 #include <remconcoreapitarget.h>
       
    20 #include <remconinterfaceselector.h>
       
    21 
       
    22 #include "testappbase.h"
       
    23 
       
    24 const TInt KLeftSoftKeyScanCode = EStdKeyDevice0;
       
    25 const TInt KRightSoftKeyScanCode = EStdKeyDevice1;
       
    26 
       
    27 const TInt KHelpWindowBorderPixels = 20;
       
    28 const TInt KHelpWindowSpaceBetweenColumns = 25;
       
    29 const TInt KHelpWindowSpaceBetweenRows = 2;
       
    30 
       
    31 // TODO: WOULD BE BETTER TO DYNAMICALLY DETECT THE AVAILABLE DRIVES
       
    32 _LIT( KDriveC, "C:" );
       
    33 _LIT( KDriveE, "E:" );
       
    34 _LIT( KDriveF, "F:" );
       
    35 _LIT( KDriveZ, "Z:" );
       
    36 
       
    37 struct TKeyListEntry
       
    38     {
       
    39     TInt scanCode;
       
    40     TInt scanCode2;
       
    41     const TText* keyName;
       
    42     };
       
    43 
       
    44 // Some emulators return '1' when key 1 is pressed and others returned EStdKeyNkp1.
       
    45 // Convert both case into '1'.
       
    46 const TKeyListEntry KSupportedKeys[KSupportedKeysCount] =
       
    47     {
       
    48         {EStdKeyEnter,      EStdKeyNull, STR("Enter")},
       
    49         {EStdKeyUpArrow,    EStdKeyNull, STR("Up")},
       
    50         {EStdKeyDownArrow,  EStdKeyNull, STR("Down")},
       
    51         {EStdKeyLeftArrow,  EStdKeyNull, STR("Left")},
       
    52         {EStdKeyRightArrow, EStdKeyNull, STR("Right")},
       
    53         {'0',               EStdKeyNkp0, STR("0")},
       
    54         {'1',               EStdKeyNkp1, STR("1")},
       
    55         {'2',               EStdKeyNkp2, STR("2")},
       
    56         {'3',               EStdKeyNkp3, STR("3")},
       
    57         {'4',               EStdKeyNkp4, STR("4")},
       
    58         {'5',               EStdKeyNkp5, STR("5")},
       
    59         {'6',               EStdKeyNkp6, STR("6")},
       
    60         {'7',               EStdKeyNkp7, STR("7")},
       
    61         {'8',               EStdKeyNkp8, STR("8")},
       
    62         {'9',               EStdKeyNkp9, STR("9")}
       
    63     };
       
    64 
       
    65 static TPtrC KeyName(TInt aIndex)
       
    66     {
       
    67     //TODO: Check aIndex range
       
    68     return TPtrC(KSupportedKeys[aIndex].keyName);
       
    69     }
       
    70 
       
    71 // Portable app implementation
       
    72 
       
    73 CTestAppBase::CTestAppBase(TInt aFontSize) :
       
    74     CActive(EPriorityStandard), iFontSize(aFontSize),
       
    75             iHelpSemitransparentBackgroundActive(true)
       
    76     {
       
    77     CActiveScheduler::Add(this);
       
    78     }
       
    79 
       
    80 CTestAppBase::~CTestAppBase()
       
    81     {
       
    82     delete iInterfaceSelector;
       
    83     delete iHelpWindow;
       
    84     delete iSelectionWindow;
       
    85     delete iGc;
       
    86     delete iWindowGroup;
       
    87     delete iScreenDevice;
       
    88     delete iTypefaceStore;
       
    89     iWs.Close();
       
    90     iFs.Close();
       
    91     iFileHistory.ResetAndDestroy();
       
    92     }
       
    93 
       
    94 void CTestAppBase::BaseConstructL(const TOperationsPage* aKeyMap,
       
    95         TInt aPageCount)
       
    96     {
       
    97     iKeyMap = aKeyMap;
       
    98     iPageCount = aPageCount;
       
    99 
       
   100     User::LeaveIfError(iFs.Connect());
       
   101 
       
   102     User::LeaveIfError(iWs.Connect());
       
   103 
       
   104     iScreenDevice = new (ELeave) CWsScreenDevice(iWs);
       
   105     User::LeaveIfError(iScreenDevice->Construct());
       
   106     iDisplaySize = iScreenDevice->SizeInPixels();
       
   107 
       
   108     User::LeaveIfError(iScreenDevice->CreateContext(iGc));
       
   109 
       
   110     iWindowGroup = new (ELeave) RWindowGroup(iWs);
       
   111     User::LeaveIfError(iWindowGroup->Construct(KNullWsHandle));
       
   112 
       
   113     iSelectionWindow = new (ELeave) RWindow(iWs);
       
   114     User::LeaveIfError(iSelectionWindow->Construct(*iWindowGroup,
       
   115             KNullWsHandle));
       
   116     iSelectionWindow->SetVisible(false);
       
   117     iSelectionWindow->Activate();
       
   118 
       
   119     // Load the font to be used for all text operations.
       
   120     TFontSpec fontSpec;
       
   121     fontSpec.iHeight = iFontSize;
       
   122     iTypefaceStore = CFbsTypefaceStore::NewL(NULL);
       
   123 
       
   124     User::LeaveIfError(iTypefaceStore->GetNearestFontToDesignHeightInPixels(
       
   125             iFont, fontSpec));
       
   126 
       
   127     CalculateHelpWindowSize();
       
   128 
       
   129     iHelpWindowTopRight = TPoint(iDisplaySize.iWidth / 2
       
   130             - iHelpWindowSize.iWidth / 2, iDisplaySize.iHeight / 2
       
   131             - iHelpWindowSize.iHeight / 2);
       
   132 
       
   133     iHelpWindow = new (ELeave) RWindow(iWs);
       
   134     User::LeaveIfError(iHelpWindow->Construct(*iWindowGroup, KNullWsHandle));
       
   135     iHelpWindow->SetExtent(iHelpWindowTopRight, iHelpWindowSize);
       
   136     iHelpWindow->SetTransparencyAlphaChannel();
       
   137     iHelpWindow->SetBackgroundColor(KRgbTransparent);
       
   138     iHelpWindow->SetVisible(false);
       
   139     iHelpWindow->Activate();
       
   140 
       
   141     iSoftkeyIndex = iKeyMap[iCurrentPage].defaultSoftkeyIndex;
       
   142 
       
   143     // Only need to draw the help text when the options page is changed.  Window is displayed later by
       
   144     // toggling the visibility of the window.
       
   145     DrawHelpText();
       
   146 
       
   147     // THE FOLLOWING CODE IS COMMENTED OUT BECAUSE IT CAUSES A CRASH IN NCP BUILDS.
       
   148     // THIS CAN BE ENABLED IN DFS BUILDS, TO ALLOW FOR TWO BUTTON OPERATION USING THE VOLUME KEYS.
       
   149     //
       
   150     // Since some phone have no keyboard or soft keys, treat the volume keys like the soft keys.
       
   151     // SetupVolumeKeysL();    
       
   152     }
       
   153 
       
   154 void CTestAppBase::SetupVolumeKeysL()
       
   155     {
       
   156     iInterfaceSelector = CRemConInterfaceSelector::NewL();
       
   157     iCoreTarget = CRemConCoreApiTarget::NewL(*iInterfaceSelector, *this);
       
   158     iInterfaceSelector->OpenTargetL();
       
   159     }
       
   160 
       
   161 void CTestAppBase::StartMonitoringWindowEvents()
       
   162     {
       
   163     // Request notification for windows server events, to detect key presses.    
       
   164     SetActive();
       
   165     iWs.EventReady(&iStatus);
       
   166     }
       
   167 
       
   168 TInt CTestAppBase::CurrentPageNumber()
       
   169     {
       
   170     return iCurrentPage + 1;
       
   171     }
       
   172 
       
   173 TPtrC CTestAppBase::CurrentPageName()
       
   174     {
       
   175     return TPtrC(iKeyMap[iCurrentPage].pageName);
       
   176     }
       
   177 
       
   178 TPtrC CTestAppBase::CurrentSoftkeyName()
       
   179     {
       
   180     return TPtrC(iKeyMap[iCurrentPage].mapping[iSoftkeyIndex].text);
       
   181     }
       
   182 
       
   183 TPtrC CTestAppBase::KeyMapText(TInt aIndex, TInt aPage)
       
   184     {
       
   185     return TPtrC(iKeyMap[aPage].mapping[aIndex].text);
       
   186     }
       
   187 
       
   188 TInt CTestAppBase::KeyMapOperation(TInt aIndex, TInt aPage)
       
   189     {
       
   190     return iKeyMap[aPage].mapping[aIndex].operation;
       
   191     }
       
   192 
       
   193 void CTestAppBase::IncrementKeymapIndex(TInt& aIndex, TInt aPage)
       
   194     {
       
   195     aIndex = (aIndex + 1) % KSupportedKeysCount;
       
   196     while (iKeyMap[aPage].mapping[aIndex].operation == KOperation_None)
       
   197         {
       
   198         aIndex = (aIndex + 1) % KSupportedKeysCount;
       
   199         }
       
   200     }
       
   201 
       
   202 void CTestAppBase::DecrementKeymapIndex(TInt& aIndex, TInt aPage)
       
   203     {
       
   204     aIndex = (aIndex + KSupportedKeysCount - 1) % KSupportedKeysCount;
       
   205     while (iKeyMap[aPage].mapping[aIndex].operation == KOperation_None)
       
   206         {
       
   207         aIndex = (aIndex + KSupportedKeysCount - 1) % KSupportedKeysCount;
       
   208         }
       
   209     }
       
   210 
       
   211 void CTestAppBase::CalculateHelpWindowSize()
       
   212     {
       
   213     iHelpWindowColumn1Width = 0;
       
   214     iHelpWindowColumn2Width = 0;
       
   215 
       
   216     // Find the widest strings for each column to determine the width of the window.
       
   217     for (TInt index = 0; index < KSupportedKeysCount; index++)
       
   218         {
       
   219         TInt width = iFont->TextWidthInPixels(KeyName(index));
       
   220         if (width > iHelpWindowColumn1Width)
       
   221             {
       
   222             iHelpWindowColumn1Width = width;
       
   223             }
       
   224 
       
   225         for (TInt index2 = 0; index2 < iPageCount; index2++)
       
   226             {
       
   227             width = iFont->TextWidthInPixels(KeyMapText(index, index2));
       
   228             if (width > iHelpWindowColumn2Width)
       
   229                 {
       
   230                 iHelpWindowColumn2Width = width;
       
   231                 }
       
   232             }
       
   233         }
       
   234 
       
   235     iHelpWindowSize.iWidth = 2 * KHelpWindowBorderPixels
       
   236             + iHelpWindowColumn1Width + KHelpWindowSpaceBetweenColumns
       
   237             + iHelpWindowColumn2Width;
       
   238 
       
   239     iHelpWindowSize.iHeight = 2 * KHelpWindowBorderPixels + iFontSize
       
   240             * KSupportedKeysCount + KHelpWindowSpaceBetweenRows
       
   241             * (KSupportedKeysCount - 1);
       
   242     }
       
   243 
       
   244 CTestAppBase::TTestAppPointerEvent CTestAppBase::CharacterizePointerEvent(
       
   245         TAdvancedPointerEvent& event)
       
   246     {
       
   247     TTestAppPointerEvent returnValue = EPointerEvent_None;
       
   248 
       
   249     RDebug::Printf("POINTER EVENT:");
       
   250     RDebug::Printf("iType=%i", event.iType);
       
   251     RDebug::Printf("iModifiers=%x", event.iModifiers);
       
   252     RDebug::Printf("iPosition=%i,%i", event.iPosition.iX, event.iPosition.iY);
       
   253     RDebug::Printf("iParentPosition=%i,%i", event.iParentPosition.iX,
       
   254             event.iParentPosition.iY);
       
   255     RDebug::Printf("PointerNumber=%i", event.PointerNumber());
       
   256     RDebug::Printf("Proximity=%i", event.Proximity());
       
   257     RDebug::Printf("Pressure=%i", event.Pressure());
       
   258     RDebug::Printf("ProximityAndPressure=%i", event.ProximityAndPressure());
       
   259     RDebug::Printf("Position3D=%i,%i,%i", event.Position3D().iX,
       
   260             event.Position3D().iY, event.Position3D().iZ);
       
   261     RDebug::Printf("Pressure3D=%i,%i,%i", event.Pressure3D().iX,
       
   262             event.Pressure3D().iY, event.Pressure3D().iZ);
       
   263     RDebug::Printf("PositionAndPressure3D=%i,%i,%i",
       
   264             event.PositionAndPressure3D().iX,
       
   265             event.PositionAndPressure3D().iY,
       
   266             event.PositionAndPressure3D().iZ);
       
   267 
       
   268     switch (event.iType)
       
   269         {
       
   270         case TPointerEvent::EButton1Down:
       
   271             {
       
   272             iPointerDownPosition = event.iPosition;
       
   273             break;
       
   274             }
       
   275         case TPointerEvent::EButton1Up:
       
   276             {
       
   277             TInt xDelta = event.iPosition.iX - iPointerDownPosition.iX;
       
   278             TInt yDelta = event.iPosition.iY - iPointerDownPosition.iY;
       
   279 
       
   280             TInt xMagnitude = xDelta;
       
   281             if (xMagnitude < 0)
       
   282                 {
       
   283                 xMagnitude = -xMagnitude;
       
   284                 }
       
   285 
       
   286             TInt yMagnitude = yDelta;
       
   287             if (yMagnitude < 0)
       
   288                 {
       
   289                 yMagnitude = -yMagnitude;
       
   290                 }
       
   291 
       
   292             const TInt KTapThreshold = 30;
       
   293 
       
   294             if (yMagnitude > xMagnitude)
       
   295                 {
       
   296                 if (yMagnitude < KTapThreshold)
       
   297                     {
       
   298                     RDebug::Printf("POINTER EVENT ENTER x=%i y=%i", xDelta,
       
   299                             yDelta);
       
   300                     returnValue = EPointerEvent_Select;
       
   301                     }
       
   302                 else if (yDelta < 0)
       
   303                     {
       
   304                     RDebug::Printf("POINTER EVENT UP x=%i y=%i", xDelta,
       
   305                             yDelta);
       
   306                     returnValue = EPointerEvent_Up;
       
   307                     }
       
   308                 else
       
   309                     {
       
   310                     RDebug::Printf("POINTER EVENT DOWN x=%i y=%i", xDelta,
       
   311                             yDelta);
       
   312                     returnValue = EPointerEvent_Down;
       
   313                     }
       
   314                 }
       
   315             else
       
   316                 {
       
   317                 if (xMagnitude < KTapThreshold)
       
   318                     {
       
   319                     RDebug::Printf("POINTER EVENT ENTER x=%i y=%i", xDelta,
       
   320                             yDelta);
       
   321                     returnValue = EPointerEvent_Select;
       
   322                     }
       
   323                 else if (xDelta < 0)
       
   324                     {
       
   325                     RDebug::Printf("POINTER EVENT LEFT x=%i y=%i", xDelta,
       
   326                             yDelta);
       
   327                     returnValue = EPointerEvent_Left;
       
   328                     }
       
   329                 else
       
   330                     {
       
   331                     RDebug::Printf("POINTER EVENT RIGHT x=%i y=%i", xDelta,
       
   332                             yDelta);
       
   333                     returnValue = EPointerEvent_Right;
       
   334                     }
       
   335                 }
       
   336             break;
       
   337             }
       
   338         }
       
   339 
       
   340     return returnValue;
       
   341     }
       
   342 
       
   343 void CTestAppBase::RunL()
       
   344     {
       
   345     if (iWait.IsStarted())
       
   346         {
       
   347         // This is an event during synchronous list selection.  Stop the nested scheduler.
       
   348         iWait.AsyncStop();
       
   349         return;
       
   350         }
       
   351 
       
   352     TWsEvent event;
       
   353     iWs.GetEvent(event);
       
   354 
       
   355     TInt operationIndex = -1;
       
   356 
       
   357     TInt scanCode = 0;
       
   358     bool processScanCode = false;
       
   359 
       
   360     TInt operation = KOperation_None;
       
   361 
       
   362     // Other potentially useful events are EEventKeyUp and EEventKeyDown.
       
   363 
       
   364     if (event.Type() == EEventKey)
       
   365         {
       
   366         scanCode = event.Key()->iScanCode;
       
   367 
       
   368         RDebug::Printf("key event %x %c", scanCode, scanCode);
       
   369 
       
   370         // Allow subclasses a chance to consume the key event directly.  If that happens, then
       
   371         // do not handle the key as normal.
       
   372         if (!ConsumeKeyEvent(scanCode))
       
   373             {
       
   374             processScanCode = true;
       
   375             }
       
   376         }
       
   377     else if (event.Type() == EEventPointer)
       
   378         {
       
   379         TAdvancedPointerEvent* p = event.Pointer();
       
   380 
       
   381         TTestAppPointerEvent pointerEvent = CharacterizePointerEvent(*p);
       
   382 
       
   383         switch (pointerEvent)
       
   384             {
       
   385             case EPointerEvent_None:
       
   386                 // Do nothing.
       
   387                 break;
       
   388             case EPointerEvent_Up:
       
   389                 operation = KOperation_PreviousOption;
       
   390                 break;
       
   391             case EPointerEvent_Down:
       
   392                 operation = KOperation_NextOption;
       
   393                 break;
       
   394             case EPointerEvent_Left:
       
   395                 operation = KOperation_PreviousOptionPage;
       
   396                 break;
       
   397             case EPointerEvent_Right:
       
   398                 operation = KOperation_NextOptionPage;
       
   399                 break;
       
   400             case EPointerEvent_Select:
       
   401                 operation = KOperation_ExecuteOption;
       
   402                 break;
       
   403             }
       
   404         }
       
   405 
       
   406     if (processScanCode)
       
   407         {
       
   408         // If one of the softkeys were pressed then take the appropriate action.
       
   409         // This is to support a two button touch device with no numeric keypad.
       
   410         // Support 'A' and 'B' also, for the NCP emulator where a keyboard  is
       
   411         // not displayed.
       
   412         switch (scanCode)
       
   413             {
       
   414             case KLeftSoftKeyScanCode:
       
   415             case 'a':
       
   416             case 'A':
       
   417                 {
       
   418                 operation = KOperation_NextOption;
       
   419                 break;
       
   420                 }
       
   421             case KRightSoftKeyScanCode:
       
   422             case 'b':
       
   423             case 'B':
       
   424                 {
       
   425                 // Execute softkey function.
       
   426                 operation = KOperation_ExecuteOption;
       
   427                 break;
       
   428                 }
       
   429             default:
       
   430                 {
       
   431                 // Search for scancode in keymap.  If not found then the key was not a valid
       
   432                 // key, so ignore.                
       
   433                 TInt index = 0;
       
   434                 while ((index < KSupportedKeysCount)
       
   435                         && (operationIndex == -1))
       
   436                     {
       
   437                     if (KSupportedKeys[index].scanCode == scanCode
       
   438                             || KSupportedKeys[index].scanCode2 == scanCode)
       
   439                         {
       
   440                         // Found!
       
   441                         operationIndex = index;
       
   442                         }
       
   443                     else
       
   444                         {
       
   445                         index++;
       
   446                         }
       
   447                     }
       
   448                 break;
       
   449                 }
       
   450             }
       
   451         }
       
   452 
       
   453     if (operation == KOperation_ExecuteOption)
       
   454         {
       
   455         operationIndex = iSoftkeyIndex;
       
   456         }
       
   457 
       
   458     if (operationIndex >= 0)
       
   459         {
       
   460         operation = KeyMapOperation(operationIndex, iCurrentPage);
       
   461         }
       
   462 
       
   463     if (operation != KOperation_None)
       
   464         {
       
   465         // Valid operation.
       
   466 
       
   467         switch (operation)
       
   468             {
       
   469             case KOperation_Exit:
       
   470                 {
       
   471                 CActiveScheduler::Stop();
       
   472                 break;
       
   473                 }
       
   474             case KOperation_PreviousOption:
       
   475                 {
       
   476                 // Change softkey function.
       
   477                 DecrementKeymapIndex(iSoftkeyIndex, iCurrentPage);
       
   478 
       
   479                 // Redraw help text, since a new function should now be underlined.
       
   480                 DrawHelpText();
       
   481 
       
   482                 // Notify subclass that softkey function has been updated.
       
   483                 SoftkeyFunctionUpdated();
       
   484                 break;
       
   485                 }
       
   486             case KOperation_NextOption:
       
   487                 {
       
   488                 // Change softkey function.
       
   489                 IncrementKeymapIndex(iSoftkeyIndex, iCurrentPage);
       
   490 
       
   491                 // Redraw help text, since a new function should now be underlined.
       
   492                 DrawHelpText();
       
   493 
       
   494                 // Notify subclass that softkey function has been updated.
       
   495                 SoftkeyFunctionUpdated();
       
   496                 break;
       
   497                 }
       
   498             case KOperation_PreviousOptionPage:
       
   499                 {
       
   500                 iCurrentPage = (iCurrentPage + iPageCount - 1) % iPageCount;
       
   501                 iSoftkeyIndex = iKeyMap[iCurrentPage].defaultSoftkeyIndex;
       
   502                 DrawHelpText();
       
   503                 SoftkeyFunctionUpdated();
       
   504                 break;
       
   505                 }
       
   506             case KOperation_NextOptionPage:
       
   507                 {
       
   508                 iCurrentPage = (iCurrentPage + 1) % iPageCount;
       
   509                 iSoftkeyIndex = iKeyMap[iCurrentPage].defaultSoftkeyIndex;
       
   510                 DrawHelpText();
       
   511                 SoftkeyFunctionUpdated();
       
   512                 break;
       
   513                 }
       
   514             case KOperation_ToggleHelpVisibility:
       
   515                 {
       
   516                 // Toggle help text on/off.
       
   517                 iHelpActive = !iHelpActive;
       
   518                 iHelpWindow->SetVisible(iHelpActive);
       
   519                 break;
       
   520                 }
       
   521             case KOperation_ToggleHelpTransparency:
       
   522                 {
       
   523                 iHelpSemitransparentBackgroundActive
       
   524                         = !iHelpSemitransparentBackgroundActive;
       
   525                 if (iHelpSemitransparentBackgroundActive)
       
   526                     {
       
   527                     // Turn on help if it is currently off.
       
   528                     iHelpActive = true;
       
   529                     iHelpWindow->SetVisible(true);
       
   530                     }
       
   531                 DrawHelpText();
       
   532                 break;
       
   533                 }
       
   534             default:
       
   535                 {
       
   536                 // Pass operation to subclass.
       
   537                 TPtrC operatioName(KeyMapText(operationIndex, iCurrentPage));
       
   538                 ExecuteOperation(operation, operatioName);
       
   539                 break;
       
   540                 }
       
   541             }
       
   542         }
       
   543 
       
   544     SetActive();
       
   545     iWs.EventReady(&iStatus);
       
   546     }
       
   547 
       
   548 void CTestAppBase::DoCancel()
       
   549     {
       
   550     iWs.EventReadyCancel();
       
   551     }
       
   552 
       
   553 // TODO: ALLOW SUBCLASS TO SPECIFY COLOR SELECTIONS
       
   554 
       
   555 TInt CTestAppBase::SelectFromListL(TPoint aTopLeft, TSize aSize,
       
   556         const TDesC& aHeaderText, RPointerArray<TDesC>& aSelectionList,
       
   557         TInt aInitialSelectionIndex)
       
   558     {
       
   559     iSelectionWindow->SetExtent(aTopLeft, aSize);
       
   560     iSelectionWindow->SetVisible(true);
       
   561 
       
   562     const TInt KRowIncrement = iFontSize + 2;
       
   563 
       
   564     TInt entriesPerPage = aSize.iHeight / KRowIncrement - 4;
       
   565 
       
   566     TInt returnValue = -2;
       
   567     TInt startIndex = 0;
       
   568     TInt selected = aInitialSelectionIndex;
       
   569 
       
   570     while (returnValue == -2)
       
   571         {
       
   572         iGc->Activate(*iSelectionWindow);
       
   573 
       
   574         iSelectionWindow->Invalidate();
       
   575         iSelectionWindow->BeginRedraw();
       
   576 
       
   577         iGc->Reset();
       
   578 
       
   579         iGc->UseFont(iFont);
       
   580         iGc->SetBrushColor(KRgbDarkBlue);
       
   581 
       
   582         iGc->Clear();
       
   583 
       
   584         // KRgbWhite seems to be having problems (0xffffff) in some emulators,
       
   585         // but 0xfefefe is working, so use that instead of white.        
       
   586         iGc->SetPenColor(0xfefefe);
       
   587 
       
   588         const TInt KHeaderColumn = 5;
       
   589         const TInt KEntryColumn = 15;
       
   590 
       
   591         TInt row = KRowIncrement;
       
   592 
       
   593         iGc->SetUnderlineStyle(EUnderlineOff);
       
   594 
       
   595         iGc->DrawText(aHeaderText, TPoint(KHeaderColumn, row));
       
   596         row += (KRowIncrement + 5);
       
   597 
       
   598         TBool again = true;
       
   599         TInt backIndex = -1;
       
   600         TInt forwardIndex = -1;
       
   601         TInt offset = 0;
       
   602 
       
   603         while (again)
       
   604             {
       
   605             if (selected == offset)
       
   606                 {
       
   607                 iGc->SetUnderlineStyle(EUnderlineOn);
       
   608                 }
       
   609             else
       
   610                 {
       
   611                 iGc->SetUnderlineStyle(EUnderlineOff);
       
   612                 }
       
   613 
       
   614             if ((offset < entriesPerPage) && (startIndex + offset
       
   615                     < aSelectionList.Count()))
       
   616                 {
       
   617                 iGc->DrawText(*aSelectionList[startIndex + offset], TPoint(
       
   618                         KEntryColumn, row));
       
   619                 row += KRowIncrement;
       
   620 
       
   621                 offset++;
       
   622                 }
       
   623             else
       
   624                 {
       
   625                 again = false;
       
   626                 if (startIndex + offset < aSelectionList.Count())
       
   627                     {
       
   628                     iGc->DrawText(_L("<page down>"),
       
   629                             TPoint(KEntryColumn, row));
       
   630                     row += KRowIncrement;
       
   631 
       
   632                     forwardIndex = offset;
       
   633                     offset++;
       
   634                     }
       
   635                 if (startIndex > 0)
       
   636                     {
       
   637                     iGc->DrawText(_L("<page up>"), TPoint(KEntryColumn, row));
       
   638                     row += KRowIncrement;
       
   639 
       
   640                     backIndex = offset;
       
   641                     offset++;
       
   642                     }
       
   643                 }
       
   644             }
       
   645 
       
   646         iSelectionWindow->EndRedraw();
       
   647 
       
   648         iGc->Deactivate();
       
   649 
       
   650         TInt scanCode = WaitForAnyKey();
       
   651 
       
   652         switch (scanCode)
       
   653             {
       
   654             case EStdKeyUpArrow:
       
   655                 if (selected == 0)
       
   656                     {
       
   657                     selected = offset - 1;
       
   658                     }
       
   659                 else
       
   660                     {
       
   661                     selected -= 1;
       
   662                     }
       
   663                 break;
       
   664 
       
   665             case EStdKeyDownArrow:
       
   666             case KLeftSoftKeyScanCode:
       
   667             case 'a':
       
   668             case 'A':
       
   669                 selected += 1;
       
   670                 if (selected == offset)
       
   671                     {
       
   672                     selected = 0;
       
   673                     }
       
   674                 break;
       
   675 
       
   676             case EStdKeyLeftArrow:
       
   677                 if (backIndex >= 0)
       
   678                     {
       
   679                     startIndex -= entriesPerPage;
       
   680                     selected = 0;
       
   681                     }
       
   682                 else
       
   683                     {
       
   684                     returnValue = -1;
       
   685                     again = false;
       
   686                     }
       
   687                 break;
       
   688 
       
   689             case EStdKeyRightArrow:
       
   690                 if (forwardIndex >= 0)
       
   691                     {
       
   692                     startIndex += entriesPerPage;
       
   693                     selected = 0;
       
   694                     }
       
   695                 break;
       
   696 
       
   697             case EStdKeyEnter:
       
   698             case KRightSoftKeyScanCode:
       
   699             case 'b':
       
   700             case 'B':
       
   701                 if (selected == forwardIndex)
       
   702                     {
       
   703                     startIndex += entriesPerPage;
       
   704                     selected = 0;
       
   705                     }
       
   706                 else if (selected == backIndex)
       
   707                     {
       
   708                     startIndex -= entriesPerPage;
       
   709                     selected = 0;
       
   710                     }
       
   711                 else
       
   712                     {
       
   713                     returnValue = startIndex + selected;
       
   714                     }
       
   715                 break;
       
   716             }
       
   717         }
       
   718 
       
   719     iSelectionWindow->SetVisible(false);
       
   720 
       
   721     return returnValue;
       
   722     }
       
   723 
       
   724 bool CTestAppBase::SelectDriveL(TPoint aTopLeft, TSize aWindowSize,
       
   725         const TDesC& aHeaderText, TDes& aDrive)
       
   726     {
       
   727     RPointerArray<TDesC> drives;
       
   728 
       
   729     // Select drive letter.
       
   730     drives.Append(&KDriveC);
       
   731     drives.Append(&KDriveE);
       
   732     drives.Append(&KDriveF);
       
   733     drives.Append(&KDriveZ);
       
   734 
       
   735     TInt index = SelectFromListL(aTopLeft, aWindowSize, aHeaderText, drives);
       
   736 
       
   737     bool returnValue = false;
       
   738 
       
   739     if (index >= 0)
       
   740         {
       
   741         returnValue = true;
       
   742         aDrive.Copy(*(drives[index]));
       
   743         aDrive.Append(_L("\\"));
       
   744         }
       
   745 
       
   746     drives.Reset();
       
   747 
       
   748     return returnValue;
       
   749     }
       
   750 
       
   751 bool CTestAppBase::SelectFileL(TPoint aTopLeft, TSize aWindowSize,
       
   752         const TDesC& aHeaderText, const TDesC& aDrive, TDes& aFullFilename)
       
   753     {
       
   754     TFileName directory;
       
   755 
       
   756     DoSelectFileL(aTopLeft, aWindowSize, aHeaderText, aDrive, 0, directory,
       
   757             aFullFilename);
       
   758 
       
   759     aFullFilename.Insert(0, directory);
       
   760 
       
   761     return aFullFilename.Length() > 0;
       
   762     }
       
   763 
       
   764 bool CTestAppBase::SelectFileWithHistoryL(TPoint aTopLeft, TSize aSize,
       
   765         TDes& aFullFilename, const TDesC& aHistoryFilename,
       
   766         TInt aMaxHistoryEntries)
       
   767     {
       
   768     RPointerArray<TDesC> selections;
       
   769 
       
   770     selections.Append(&KDriveC);
       
   771     selections.Append(&KDriveE);
       
   772     selections.Append(&KDriveF);
       
   773     selections.Append(&KDriveZ);
       
   774 
       
   775     // Add file history to the end of the drive list.  Newest files are last, so add in reverse order.
       
   776     ReadFileHistory(aHistoryFilename);
       
   777     for (TInt index = iFileHistory.Count() - 1; index >= 0; index--)
       
   778         {
       
   779         selections.Append(iFileHistory[index]);
       
   780         }
       
   781 
       
   782     bool done = false;
       
   783     bool selected = true;
       
   784 
       
   785     while (!done)
       
   786         {
       
   787         TInt index = SelectFromListL(aTopLeft, aSize,
       
   788                 _L("Select drive or recent file:"), selections);
       
   789 
       
   790         if (index < 0)
       
   791             {
       
   792             selected = false;
       
   793             done = true;
       
   794             }
       
   795         else if (index < 4)
       
   796             {
       
   797             TBuf<10> drive;
       
   798             drive.Copy(*(selections[index]));
       
   799             drive.Append(_L("\\"));
       
   800 
       
   801             done = SelectFileL(aTopLeft, aSize, _L("Select file:"), drive,
       
   802                     aFullFilename);
       
   803             }
       
   804         else
       
   805             {
       
   806             // Remove the selected file from the history, so that it will pop up to the top of the list
       
   807             // as the most recently selected file.
       
   808             TInt historyIndex = iFileHistory.Count() - index + 3;
       
   809             iFileHistory.Remove(historyIndex);
       
   810             aFullFilename.Copy(*(selections[index]));
       
   811 
       
   812             done = true;
       
   813             }
       
   814         }
       
   815 
       
   816     if (selected)
       
   817         {
       
   818         AddToFileHistory(aFullFilename, aHistoryFilename, aMaxHistoryEntries);
       
   819         }
       
   820 
       
   821     selections.Reset();
       
   822 
       
   823     return selected;
       
   824     }
       
   825 
       
   826 bool CTestAppBase::SelectIntegerL(TPoint aTopLeft, TSize aSize,
       
   827         const TDesC& aHeaderText, TInt aMin, TInt aMax, TInt& aSelection)
       
   828     {
       
   829     // currently no way to exit out of this selection
       
   830 
       
   831     iSelectionWindow->SetExtent(aTopLeft, aSize);
       
   832     iSelectionWindow->SetVisible(true);
       
   833 
       
   834     bool done = false;
       
   835 
       
   836     while (!done)
       
   837         {
       
   838         iGc->Activate(*iSelectionWindow);
       
   839 
       
   840         iSelectionWindow->Invalidate();
       
   841         iSelectionWindow->BeginRedraw();
       
   842 
       
   843         iGc->Reset();
       
   844 
       
   845         iGc->UseFont(iFont);
       
   846         iGc->SetBrushColor(KRgbDarkBlue);
       
   847 
       
   848         iGc->Clear();
       
   849 
       
   850         // KRgbWhite seems to be having problems (0xffffff) in some emulators,
       
   851         // but 0xfefefe is working, so use that instead of white.        
       
   852         iGc->SetPenColor(0xfefefe);
       
   853 
       
   854         TBuf<120> buffer;
       
   855         buffer.Copy(aHeaderText);
       
   856         buffer.AppendFormat(_L(" %i"), aSelection);
       
   857 
       
   858         iGc->DrawText(buffer, TPoint(5, iFontSize + 2));
       
   859 
       
   860         iSelectionWindow->EndRedraw();
       
   861 
       
   862         iGc->Deactivate();
       
   863 
       
   864         TInt scanCode = WaitForAnyKey();
       
   865 
       
   866         switch (scanCode)
       
   867             {
       
   868             case EStdKeyUpArrow:
       
   869                 aSelection -= 10;
       
   870                 break;
       
   871 
       
   872             case EStdKeyDownArrow:
       
   873             case KLeftSoftKeyScanCode:
       
   874             case 'a':
       
   875             case 'A':
       
   876                 aSelection += 10;
       
   877                 break;
       
   878 
       
   879             case EStdKeyLeftArrow:
       
   880                 aSelection--;
       
   881                 break;
       
   882 
       
   883             case EStdKeyRightArrow:
       
   884                 aSelection++;
       
   885                 break;
       
   886 
       
   887             case EStdKeyEnter:
       
   888             case KRightSoftKeyScanCode:
       
   889             case 'b':
       
   890             case 'B':
       
   891                 done = true;
       
   892                 break;
       
   893             }
       
   894 
       
   895         if (aSelection > aMax)
       
   896             {
       
   897             aSelection = aMin;
       
   898             }
       
   899         else if (aSelection < aMin)
       
   900             {
       
   901             aSelection = aMax;
       
   902             }
       
   903         }
       
   904 
       
   905     iSelectionWindow->SetVisible(false);
       
   906 
       
   907     return true;
       
   908     }
       
   909 
       
   910 TInt CTestAppBase::WaitForAnyKey()
       
   911     {
       
   912     TInt returnValue = 0;
       
   913 
       
   914     bool done = false;
       
   915 
       
   916     while (!done)
       
   917         {
       
   918         // Have to use this tricky nested active scheduler technique to allow the active object
       
   919         // used to remap volume keys to run.
       
   920         SetActive();
       
   921         iWs.EventReady(&iStatus);
       
   922         iWait.Start();
       
   923 
       
   924         TWsEvent event;
       
   925         iWs.GetEvent(event);
       
   926 
       
   927         // Other potentially useful events are EEventKeyUp and EEventKeyDown.
       
   928 
       
   929         if (event.Type() == EEventKey)
       
   930             {
       
   931             done = true;
       
   932             returnValue = event.Key()->iScanCode;
       
   933             }
       
   934         else if (event.Type() == EEventPointer)
       
   935             {
       
   936             TAdvancedPointerEvent* p = event.Pointer();
       
   937 
       
   938             TTestAppPointerEvent pointerEvent = CharacterizePointerEvent(*p);
       
   939 
       
   940             switch (pointerEvent)
       
   941                 {
       
   942                 case EPointerEvent_None:
       
   943                     // Do nothing.
       
   944                     break;
       
   945                 case EPointerEvent_Up:
       
   946                     returnValue = EStdKeyUpArrow;
       
   947                     done = true;
       
   948                     break;
       
   949                 case EPointerEvent_Down:
       
   950                     returnValue = EStdKeyDownArrow;
       
   951                     done = true;
       
   952                     break;
       
   953                 case EPointerEvent_Left:
       
   954                     returnValue = EStdKeyLeftArrow;
       
   955                     done = true;
       
   956                     break;
       
   957                 case EPointerEvent_Right:
       
   958                     returnValue = EStdKeyRightArrow;
       
   959                     done = true;
       
   960                     break;
       
   961                 case EPointerEvent_Select:
       
   962                     returnValue = EStdKeyEnter;
       
   963                     done = true;
       
   964                     break;
       
   965                 }
       
   966             }
       
   967         }
       
   968 
       
   969     return returnValue;
       
   970     }
       
   971 
       
   972 void CTestAppBase::ReadFileHistory(const TDesC& aHistoryFilename)
       
   973     {
       
   974     iFileHistory.Reset();
       
   975 
       
   976     RFile historyFile;
       
   977     TInt err = historyFile.Open(iFs, aHistoryFilename, EFileShareReadersOnly
       
   978             | EFileStream | EFileRead);
       
   979 
       
   980     if (err == KErrNone)
       
   981         {
       
   982         TInt historyFileSize;
       
   983         historyFile.Size(historyFileSize);
       
   984 
       
   985         RBuf8 contents;
       
   986         contents.Create(historyFileSize);
       
   987 
       
   988         historyFile.Read(contents, historyFileSize);
       
   989 
       
   990         historyFile.Close();
       
   991 
       
   992         TPtrC8 remaining(contents);
       
   993 
       
   994         while (remaining.Length() > 0)
       
   995             {
       
   996             TInt separatorIndex = remaining.Locate('\n');
       
   997 
       
   998             if (separatorIndex < 0)
       
   999                 {
       
  1000                 separatorIndex = remaining.Length();
       
  1001                 }
       
  1002 
       
  1003             HBufC* filename = HBufC::NewL(separatorIndex);
       
  1004             TPtrC8 filename8 = remaining.Left(separatorIndex);
       
  1005             filename->Des().Copy(filename8);
       
  1006 
       
  1007             iFileHistory.Append(filename);
       
  1008 
       
  1009             TInt remainingLength = remaining.Length() - separatorIndex - 1;
       
  1010 
       
  1011             if (remainingLength > 0)
       
  1012                 {
       
  1013                 remaining.Set(remaining.Right(remaining.Length()
       
  1014                         - separatorIndex - 1));
       
  1015                 }
       
  1016             else
       
  1017                 {
       
  1018                 break;
       
  1019                 }
       
  1020             }
       
  1021 
       
  1022         contents.Close();
       
  1023         }
       
  1024     }
       
  1025 
       
  1026 void CTestAppBase::AddToFileHistory(const TDesC& aFilename,
       
  1027         const TDesC& aHistoryFilename, TInt aMaxHistoryEntries)
       
  1028     {
       
  1029     HBufC* filename = HBufC::NewL(aFilename.Length());
       
  1030     filename->Des().Copy(aFilename);
       
  1031     iFileHistory.Append(filename);
       
  1032 
       
  1033     while (iFileHistory.Count() > aMaxHistoryEntries)
       
  1034         {
       
  1035         delete iFileHistory[0];
       
  1036         iFileHistory.Remove(0);
       
  1037         }
       
  1038 
       
  1039     RFile historyFile;
       
  1040     TInt err = historyFile.Create(iFs, aHistoryFilename, EFileStream
       
  1041             | EFileWrite);
       
  1042     if (err == KErrAlreadyExists)
       
  1043         {
       
  1044         err = historyFile.Open(iFs, aHistoryFilename, EFileStream
       
  1045                 | EFileWrite);
       
  1046         historyFile.SetSize(0);
       
  1047         }
       
  1048 
       
  1049     if (err == KErrNone)
       
  1050         {
       
  1051         for (TInt index = 0; index < iFileHistory.Count(); index++)
       
  1052             {
       
  1053             TBuf8<KMaxFileName> filename8;
       
  1054             filename8.Copy(iFileHistory[index]->Des());
       
  1055             historyFile.Write(filename8);
       
  1056             historyFile.Write(_L8("\n"));
       
  1057             }
       
  1058         }
       
  1059 
       
  1060     historyFile.Close();
       
  1061     }
       
  1062 
       
  1063 void CTestAppBase::DoSelectFileL(TPoint aTopRight, TSize aWindowSize,
       
  1064         const TDesC& aHeaderText, const TFileName& aDirectory,
       
  1065         TInt aDirectoryLevel, TDes& aSelectedDirectory,
       
  1066         TDes& aSelectedFilename)
       
  1067     {
       
  1068     RPointerArray<TDesC> fileNames;
       
  1069 
       
  1070     ReadDirectoryEntriesL(aDirectory, fileNames);
       
  1071 
       
  1072     TInt initialSelectionIndex = 0;
       
  1073     _LIT( KUp, ".." );
       
  1074     if (aDirectoryLevel > 0)
       
  1075         {
       
  1076         TFileName* newEntry = new (ELeave) TFileName;
       
  1077         newEntry->Copy(KUp);
       
  1078         fileNames.Insert(newEntry, 0);
       
  1079         initialSelectionIndex++;
       
  1080         }
       
  1081 
       
  1082     bool done = false;
       
  1083 
       
  1084     while (!done && (aSelectedFilename.Length() == 0))
       
  1085         {
       
  1086         TInt index = SelectFromListL(aTopRight, aWindowSize, aHeaderText,
       
  1087                 fileNames, initialSelectionIndex);
       
  1088 
       
  1089         if (index == -1)
       
  1090             {
       
  1091             done = true;
       
  1092             }
       
  1093         else if (fileNames[index]->Compare(KUp) == 0)
       
  1094             {
       
  1095             // Go up one directory.  Return to caller without setting aFilename
       
  1096             break;
       
  1097             }
       
  1098         else if ((*fileNames[index])[fileNames[index]->Length() - 1] == '\\')
       
  1099             {
       
  1100             // Directory selected.
       
  1101             TFileName directory;
       
  1102             directory.Copy(aDirectory);
       
  1103             directory.Append(*fileNames[index]);
       
  1104             DoSelectFileL(aTopRight, aWindowSize, aHeaderText, directory,
       
  1105                     aDirectoryLevel + 1, aSelectedDirectory,
       
  1106                     aSelectedFilename);
       
  1107             }
       
  1108         else
       
  1109             {
       
  1110             // File selected.                            
       
  1111             aSelectedDirectory.Copy(aDirectory);
       
  1112             aSelectedFilename.Copy(*fileNames[index]);
       
  1113             done = true;
       
  1114             }
       
  1115 
       
  1116         }
       
  1117 
       
  1118     fileNames.ResetAndDestroy();
       
  1119     }
       
  1120 
       
  1121 void CTestAppBase::ReadDirectoryEntriesL(const TFileName& aDirectoryName,
       
  1122         RPointerArray<TDesC>& aFileNames)
       
  1123     {
       
  1124     aFileNames.ResetAndDestroy();
       
  1125 
       
  1126     RDir dir;
       
  1127     User::LeaveIfError(dir.Open(iFs, aDirectoryName, KEntryAttNormal
       
  1128             | KEntryAttDir));
       
  1129 
       
  1130     TEntryArray entries;
       
  1131     TInt err = KErrNone;
       
  1132     while (err == KErrNone)
       
  1133         {
       
  1134         err = dir.Read(entries);
       
  1135 
       
  1136         for (TInt index = 0; index < entries.Count(); index++)
       
  1137             {
       
  1138             TFileName* newTail = new (ELeave) TFileName;
       
  1139             newTail->Copy(entries[index].iName);
       
  1140             if (entries[index].IsDir())
       
  1141                 {
       
  1142                 newTail->Append(_L("\\"));
       
  1143                 }
       
  1144             aFileNames.Append(newTail);
       
  1145             }
       
  1146         }
       
  1147 
       
  1148     dir.Close();
       
  1149     }
       
  1150 
       
  1151 void CTestAppBase::DrawHelpText()
       
  1152     {
       
  1153     iGc->Activate(*iHelpWindow);
       
  1154 
       
  1155     iHelpWindow->Invalidate();
       
  1156     iHelpWindow->BeginRedraw();
       
  1157 
       
  1158     iGc->Reset();
       
  1159 
       
  1160     iGc->UseFont(iFont);
       
  1161     iGc->SetBrushColor(KRgbTransparent);
       
  1162 
       
  1163     iGc->Clear();
       
  1164 
       
  1165     if (iHelpSemitransparentBackgroundActive)
       
  1166         {
       
  1167         iGc->SetPenColor(KRgbTransparent);
       
  1168         iGc->SetBrushStyle(CWindowGc::ESolidBrush);
       
  1169         iGc->SetBrushColor(TRgb(0x7f7f7faf));
       
  1170         iGc->DrawRect(TRect(iHelpWindowSize));
       
  1171         }
       
  1172 
       
  1173     // KRgbWhite seems to be having problems (0xffffff) in some emulators,
       
  1174     // but 0xfefefe is working, so use that instead of white.        
       
  1175     iGc->SetPenColor(0xfefefe);
       
  1176 
       
  1177     const TInt KColumn1 = KHelpWindowBorderPixels;
       
  1178     const TInt KColumn2 = KColumn1 + iHelpWindowColumn1Width
       
  1179             + KHelpWindowSpaceBetweenColumns;
       
  1180     const TInt KRowIncrement = iFontSize + KHelpWindowSpaceBetweenRows;
       
  1181 
       
  1182     TInt row = iFontSize + KHelpWindowBorderPixels;
       
  1183 
       
  1184     for (TInt index = 0; index < KSupportedKeysCount; index++)
       
  1185         {
       
  1186         iGc->SetUnderlineStyle(EUnderlineOff);
       
  1187 
       
  1188         TPtrC text = KeyMapText(index, iCurrentPage);
       
  1189 
       
  1190         iGc->DrawText(KeyName(index), TPoint(KColumn1, row));
       
  1191 
       
  1192         if (index == iSoftkeyIndex)
       
  1193             {
       
  1194             iGc->SetUnderlineStyle(EUnderlineOn);
       
  1195             }
       
  1196         else
       
  1197             {
       
  1198             iGc->SetUnderlineStyle(EUnderlineOff);
       
  1199             }
       
  1200 
       
  1201         iGc->DrawText(text, TPoint(KColumn2, row));
       
  1202 
       
  1203         row += KRowIncrement;
       
  1204         }
       
  1205 
       
  1206     iHelpWindow->EndRedraw();
       
  1207 
       
  1208     iGc->Deactivate();
       
  1209     }
       
  1210 
       
  1211 void CTestAppBase::MrccatoCommand(TRemConCoreApiOperationId aOperationId,
       
  1212         TRemConCoreApiButtonAction /*aButtonAct*/)
       
  1213     {
       
  1214     // Treat volume up like the right soft key, and volume down like the left soft key.
       
  1215     TKeyEvent keyEvent;
       
  1216     keyEvent.iCode = 0;
       
  1217     keyEvent.iScanCode = 0;
       
  1218     keyEvent.iModifiers = 0;
       
  1219     keyEvent.iRepeats = 0;
       
  1220 
       
  1221     switch (aOperationId)
       
  1222         {
       
  1223         case ERemConCoreApiVolumeUp:
       
  1224             keyEvent.iScanCode = KRightSoftKeyScanCode;
       
  1225             iWs.SimulateKeyEvent(keyEvent);
       
  1226             iWs.Flush();
       
  1227             break;
       
  1228         case ERemConCoreApiVolumeDown:
       
  1229             keyEvent.iScanCode = KLeftSoftKeyScanCode;
       
  1230             iWs.SimulateKeyEvent(keyEvent);
       
  1231             iWs.Flush();
       
  1232             break;
       
  1233         default:
       
  1234             break;
       
  1235         }
       
  1236     }