javauis/lcdui_akn/lcdui/src/CMIDMenuHandler.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 15 Jul 2010 18:31:06 +0300
branchRCL_3
changeset 59 e5618cc85d74
parent 19 04becd199f91
child 60 6c158198356e
permissions -rw-r--r--
Revision: v2.1.32 Kit: 2010127

/*
* Copyright (c) 2003-2008 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:  Menu pane handling, common across all Displayables.
*
*/


// INCLUDE FILES
// CEikonEnv API for iEkonEnv :
// - to retrieving CEikAppUi
// - to obtain device screen size
#include <eikenv.h>
// API for iAppUi
#include <eikappui.h>
// API for iMenuBar
#include <eikmenub.h>
#include <e32cmn.h>
#include <AknUtils.h>
// using constants for soft keys
#include <avkon.hrh>
// mocros for avkon resources
#include <avkon.rsg>
// macros for resources
#include <lcdui.rsg>
// API needed for iDisplayable and iDefaultDisplayable members
#include "CMIDDisplayable.h"
#include "CMIDCanvas.h"
#include "CMIDMenuHandler.h"
// CMIDTickerController API for iTickerController (stored in tls structure)
#include "CMIDTicker.h"
// for setting key decoder in tls
#include "CMIDKeyDecoder.h"
#include "lcdui.h"
#include <j2me/jdebug.h>
#include "CMIDUIManager.h"


const TInt KResolutionStringLength = 4;

// ============================ MEMBER FUNCTIONS ===============================


// -----------------------------------------------------------------------------
// CMIDMenuHandler::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CMIDMenuHandler* CMIDMenuHandler::NewL(MMIDEnv& aEnv)
{
    CMIDMenuHandler* self = new(ELeave) CMIDMenuHandler(aEnv);
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(self);

    return self;
}

// -----------------------------------------------------------------------------
// CMIDMenuHandler::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CMIDMenuHandler::ConstructL()
{
    iAppUi = iEikEnv.EikAppUi();
    iMenuBar = new(ELeave) CEikMenuBar;
    iMenuBar->ConstructL(this, 0, R_MIDP_MENUBAR_DEFAULT);

    iCba = CEikButtonGroupContainer::NewL(CEikButtonGroupContainer::ECba,
                                          CEikButtonGroupContainer::EHorizontal,
                                          this,
                                          R_AVKON_SOFTKEYS_EMPTY);
#ifdef RD_JAVA_S60_RELEASE_9_2
    static_cast<CEikCba*>(iCba->ButtonGroup())->EnableItemSpecificSoftkey(EFalse);
#endif
    const TSize screenSize = iEikEnv.ScreenDevice()->SizeInPixels();
    iCba->SetBoundingRect(TRect(screenSize));
    iViewRect = iAppUi->ClientRect();
    iCba->ReduceRect(iViewRect);
    iAppUi->AddToStackL(iMenuBar,ECoeStackPriorityMenu,ECoeStackFlagRefusesFocus);
    SetScalingFactors();
}


void CMIDMenuHandler::HideMenuIfVisible()
{
    if (iMenuBar->IsDisplayed())
    {
        iMenuBar->StopDisplayingMenuBar();
    }
}

void CMIDMenuHandler::UpdateMenuIfVisibleL()
{
    if (iMenuBar->IsDisplayed())
    { // Menu is currently displayed

        iMenuBar->StopDisplayingMenuBar();

        ShowMenuL(iMenuType);
    }
}


// C++ default constructor
CMIDMenuHandler::CMIDMenuHandler(MMIDEnv& aEnv)
        : iEnv(aEnv)
        ,iEikEnv(*(CEikonEnv::Static()))
{
}

// Destructor
CMIDMenuHandler::~CMIDMenuHandler()
{
    HideMenuIfVisible();
    if (iAppUi)
    {
        iAppUi->RemoveFromStack(iMenuBar);
    }
    delete iMenuBar;
    delete iCba;
    iMenuItems.Reset();
}

// -----------------------------------------------------------------------------
// CMIDMenuHandler::ShowMenuL
//
// @see DynInitMenuPaneL()
// -----------------------------------------------------------------------------
//
void CMIDMenuHandler::ShowMenuL(const TMenuType& aType)
{
    if (iDisplayable && aType != ENoMenu && !iAttemptingToDisplayMenu)
    {
        iMenuType = aType;
        iDisplayable->CreateMenuItemsL(iMenuType, iMenuItems);

        // Set the CEikMenuBar type according to internal type
        if (aType == EOptionsMenu)
        {
            iMenuBar->SetMenuType(CEikMenuBar::EMenuOptions);
        }
        else if (aType == EOkMenu || aType == EHelpMenu || aType == EScreenAndHelpMenu)
        {
            iMenuBar->SetMenuType(CEikMenuBar::EMenuContext);
        }

        // If there is anything to show, open the menu
        if (iMenuItems.Count() > 0 && !iMenuBar->IsDisplayed())
        {
            iAttemptingToDisplayMenu = ETrue;
            iMenuBar->TryDisplayMenuBarL();
        }
        // Reset the menu type always to options menu just in case
        iMenuBar->SetMenuType(CEikMenuBar::EMenuOptions);
    }
}

// -----------------------------------------------------------------------------
// CMIDMenuHandler::MenuItemsCount
//
//
// -----------------------------------------------------------------------------
//
TUint CMIDMenuHandler::MenuItemsCount() const
{
    return iMenuItems.Count();
}

// -----------------------------------------------------------------------------
// CMIDMenuHandler::SetDisplayable
//
//
// -----------------------------------------------------------------------------
//
void CMIDMenuHandler::SetDisplayable(CMIDDisplayable* aDisplayable)
{
    iDisplayable = aDisplayable;

    if (iDisplayable)
    {
        SendMultipleKeyPressedEvent();
    }
}
// -----------------------------------------------------------------------------
// CMIDMenuHandler::SendMultipleKeyPressedEventL
//
//
// -----------------------------------------------------------------------------
//
void CMIDMenuHandler::SendMultipleKeyPressedEvent()
{
    ASSERT(iDisplayable);

    RWsSession  wsSession = CCoeEnv::Static()->WsSession();
    TWsEvent event;

    // Check the current Display type if it is canvas enable the
    // multiple key events, other wise disable it.
    MMIDComponent* component = iDisplayable->Component();
    MMIDComponent::TType type = component->Type();

    if (type == MMIDComponent::ECanvas)
        event.SetType(EEnableMultipleKeyPressedEvent); // set event type enable multiple key pressed event
    else
        event.SetType(EDisableMultipleKeyPressedEvent); // set event type disable multiple key pressed event
    event.SetTimeNow(); // set the event time
    event.SetHandle(wsSession.WsHandle()); // set window server handle
    wsSession.SendEventToAllWindowGroups(event);
}


// -----------------------------------------------------------------------------
// CMIDMenuHandler::ProcessCommandL
//
//
// -----------------------------------------------------------------------------
//
void CMIDMenuHandler::ProcessCommandL(TInt aCommandId)
{
    HideMenuIfVisible();

    //
    if (aCommandId == EAknSoftkeyExit)
    {
        iAppUi->HandleCommandL(EEikCmdExit);
        return;
    }

    if (aCommandId == EEikCmdCanceled)
    {
        return;
    }

    if (aCommandId == EAknSoftkeyOptions)
    {
        ShowMenuL(EOptionsMenu);
        return;
    }

    if (aCommandId == EStdKeyDevice3)
    {
        ShowMenuL(EOkMenu);
        return;
    }

    if (iDisplayable)
    {
        iDisplayable->ProcessCommandL(aCommandId);
    }
}

// -----------------------------------------------------------------------------
// CMIDMenuHandler::SetEmphasis
//
//
// -----------------------------------------------------------------------------
//
void CMIDMenuHandler::SetEmphasis(CCoeControl* aMenuControl,TBool aEmphasis)
{
    if (!iDisplayable)
    {
        return;
    }

    if (aEmphasis)
    {
        if (MMIDComponent::ECanvas == iDisplayable->Component()->Type())
        {
            iEnv.PostMidletEvent(EBackground);
        }
    }
    else
    {
        if (MMIDComponent::ECanvas == iDisplayable->Component()->Type())
        {
            iEnv.PostMidletEvent(EForeground);
        }
    }

    iAppUi->UpdateStackedControlFlags(aMenuControl, aEmphasis? 0: ECoeStackFlagRefusesFocus,
                                      ECoeStackFlagRefusesFocus);
    iAppUi->HandleStackChanged();
}

// -----------------------------------------------------------------------------
// CMIDMenuHandler::DynInitMenuPaneL
//
//
// -----------------------------------------------------------------------------
void CMIDMenuHandler::DynInitMenuPaneL(TInt aResourceId, CEikMenuPane* aMenuPane)
{
    if (aResourceId == R_MIDP_MENUPANE_DISPLAYABLE)
    {
        TInt numItems = iMenuItems.Count();
        for (TInt i = 0; i < numItems; i++)
        {
            aMenuPane->AddMenuItemL(iMenuItems[i]);
        }

        iAttemptingToDisplayMenu = EFalse;
    }

}


/** SetScalingFactors

 Sets MIDlet's original size and target size resolutions if those are defined in JAD or manifest.
 If attribute is missing or it's not defined correctly, the value will be 0,0.
 This value is later used as an "error value".
 @param -
 @return -

 */
void CMIDMenuHandler::SetScalingFactors()
{
    TPtrC orgSize;
    // If JAD attribute Nokia-MIDlet-Original-Display-Size is defined, it will be used to scale Canvas.
    if (iEnv.MidletAttribute(LcduiMidletAttributes::KAttribOrigDisplaySize, orgSize) == KErrNone)
    {
        iOrgMIDletScrSize = DesToTSize(orgSize);
        TPtrC targetSize;
        // If JAD attribute Nokia-MIDlet-Original-Display-Size and Nokia-MIDlet-Target-Display-Size are defined,
        // those will be used to scale Canvas.
        // If Nokia-MIDlet-Target-Display-Size is invalid, Canvas will still be scaled,
        // if Nokia-MIDlet-Original-Display-Size is correct.
        if (iOrgMIDletScrSize.iHeight != 0 && iOrgMIDletScrSize.iWidth != 0 &&
                iEnv.MidletAttribute(LcduiMidletAttributes::KAttribTargetDisplaySize,
                                     targetSize) == KErrNone)
        {
            iTargetMIDletScrSize = DesToTSize(targetSize);
        }

        // Load Nokia-MIDlet-allow-scaling-on-orientation-switch attribute
        // setting. This attribute is valid only when original MIDlet size
        // is defined.
        if (iOrgMIDletScrSize.iHeight != 0 && iOrgMIDletScrSize.iWidth != 0)
        {
            iScaleMIDletOnOrientSwitch = iEnv.MidletAttributeIsSetToVal(
                                             LcduiMidletAttributes::KAttribAllowScalingOnOrientationSwitch,
                                             LcduiMidletAttributeValues::KTrueValue);
        }
    }
}

/** DesToTSize

 Utility to parse TPtrC to TSize.
 This util is made for graphics scaling feature.
 @param TPtrC
 @return TSize

 */
TSize CMIDMenuHandler::DesToTSize(TPtrC scrSize)
{
    TSize newSize;
    TSize errorSize(0, 0);
    TInt newIntWidth;
    TInt newIntHeight;
    // Assumed max. 9999 pixels in width.
    TBuf<KResolutionStringLength> newWidth;
    // Assumed max. 9999 pixels in height.
    TBuf<KResolutionStringLength> newHeight;
    TChar tmpChar;
    _LIT(lComma, ",");
    TChar comma(',');

    // The digits of width and height must be divided by comma
    if (scrSize.Find(lComma) != KErrNotFound)
    {
        TLex16 lex(scrSize);
        while (lex.Peek() != comma)
        {
            tmpChar = lex.Get();
            if (tmpChar.IsDigit() && newWidth.Length() < KResolutionStringLength)
            {
                newWidth.Append(tmpChar);
            }
            else if (!tmpChar.IsSpace())
            {
                // If character is not digit or space
                return errorSize;
            }
        }
        lex.Get();
        while (!lex.Eos())
        {
            tmpChar = lex.Get();
            if (tmpChar.IsDigit() && newHeight.Length() < KResolutionStringLength)
            {
                newHeight.Append(tmpChar);
            }
            else if (!tmpChar.IsSpace())
            {
                // If character is not digit or space
                return errorSize;
            }
        }

        // Width and height must have at least one digit each
        if (newWidth.Length() > 0 && newHeight.Length() > 0)
        {
            TLex16 widthLex(newWidth);
            widthLex.Val(newIntWidth);
            TLex16 heightLex(newHeight);
            heightLex.Val(newIntHeight);
            newSize.SetSize(TInt(newIntWidth), TInt(newIntHeight));
            return newSize;
        }
    }
    // If there is no comma between the digits or there is no digits in width or height
    return errorSize;
}

TSize CMIDMenuHandler::GetScreenSize() const
{
    // It get size of screen from iEikEnv's screen device.
    const CEikonEnv* env = &iEikEnv;
    return env->ScreenDevice()->SizeInPixels();
}

TBool CMIDMenuHandler::IsScalingEnabled() const
{
    //If iOrgMIDletScrSize has been initialized then scaling is on.
    //It's enough to check either height or width only.
    return (iOrgMIDletScrSize.iHeight != 0);
}

TBool CMIDMenuHandler::IsScalingEffectiveInCurrentScreen() const
{
    if (IsScalingEnabled())
    {
        TRect screen;
        AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EScreen, screen);
        TSize screenSize = screen.Size();

        TSize origResolution = iOrgMIDletScrSize;
        if (iScaleMIDletOnOrientSwitch)
        {
            // ensure that origResolution and screenSize are in portrait
            origResolution = TSize(Min(iOrgMIDletScrSize.iHeight, iOrgMIDletScrSize.iWidth),
                                   Max(iOrgMIDletScrSize.iHeight, iOrgMIDletScrSize.iWidth));
            screenSize = TSize(Min(screen.Height(), screen.Width()),
                               Max(screen.Height(), screen.Width()));
        }

        // If origResolution and screenSize are different, then
        // scaling is effective.
        return (screenSize.iHeight != origResolution.iHeight ||
                screenSize.iWidth != origResolution.iWidth);
    }
    else
    {
        return EFalse;
    }
}
// End of File