/*
* Copyright (c) 2002-2004 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:  Implementation for wrapper for a menu
*
*/

// System includes
#include <utf.h>
#include <aknappui.h>
#include <e32base.h>
#include <coecntrl.h>
#include <eikbtgpc.h>
#include <eikcba.h>
#include <barsread.h>
#include <eiksoftkeyimage.h>
#include <aknlayoutscalable_avkon.cdl.h>
#include <layoutmetadata.cdl.h>

#include <AknStatuspaneUtils.h>
#include <AknUtils.h>
#include <AknIconUtils.h>
#include <eikspane.h>
#include <AknSgcc.h>
#include <aknview.h>
#include <AknsConstants.h>

// User includes
#include "xnnodepluginif.h"
#include "xntype.h"
#include "xnproperty.h"

#include "xndompropertyvalue.h"
#include "xndomproperty.h"
#include "xndomlist.h"

#include "xnuienginepluginif.h"
#include "xncomponent.h"

#include "xnappuiadapter.h"
#include "xnbitmap.h"
#include "xnmenuadapter.h"
#include "xncomponentnodeimpl.h"
#include "c_xnutils.h"

#undef _AVKON_CBA_LSC

_LIT8( KEditMode, "Menu/EditMode" );
_LIT8( KNormalMode, "Menu/NormalMode" );
_LIT8( KContextEditMode, "ContextMenu/EditMode" );
_LIT8( KContextNormalMode, "ContextMenu/NormalMode" );
_LIT8( KAlwaysShown, "Menu/AlwaysShown" );

_LIT8( KHsShowHelp, "hs_show_help" );

const TInt KMenuCommandFirst         = 6000;
const TInt KMenuCommandLast          = 6199;
const TInt KCBACommandFirst          = EAknSoftkeyOptions;
const TInt KCBACommandSecond         = EAknSoftkeyBack;
const TInt KCBACommandMiddle         = EAknSoftkeyDialler; 

const TInt KXnMenuArrayGranularity   = 6;
const TInt KWideScreenWidth          = 640;

using namespace XnPropertyNames;

static CXnNodePluginIf* FindChildL(CXnNodePluginIf& aNode, 
    const TDesC8& aType, const TDesC8& aTarget = KNullDesC8);
	
class CXnSoftkeyItem: public CBase
    { 
public:           
    CXnSoftkeyItem() 
    : iNode( NULL ),         
      iPosition( 0 ), 
      iCommandId( 0 ),      
      iLabel( NULL ),
      iBitmap( NULL ),
      iMask( NULL ),
      iImageOn( EFalse ),  
      iInvertMask( EFalse ),
      iPreserveAspectRatio( EFalse ),            
      iUpdateAppearance( ETrue ),
      iOwnBitmaps( ETrue ),
      iDefault( EFalse ),
      iId( KAknsIIDQsnIconColors ),
      iBmpFile( NULL ),
      iBmp( 0 ),
      iBmpM( 0 )
        {
        }  
                              
    ~CXnSoftkeyItem()
        {
        Reset();            
        }
        
    void Reset()
        {
        delete iLabel;
        iLabel = NULL;        
        if ( iOwnBitmaps )
            {
            delete iBitmap;
            iBitmap = NULL;
            delete iMask;            
            iMask = NULL;            
            }
        else
            {
            iBitmap = NULL;
            iMask = NULL;
            }
        
        iImageOn = EFalse;        
        iInvertMask = EFalse;
        iPreserveAspectRatio = EFalse;
        delete iBmpFile;
        iBmpFile = NULL;
        }        
        
    CXnNodePluginIf* iNode;
    TInt             iPosition;
    TInt             iCommandId;    
    HBufC*           iLabel;
    CFbsBitmap*      iBitmap;
    CFbsBitmap*      iMask;    
    TBool            iImageOn;
    TBool            iInvertMask;
    TBool            iPreserveAspectRatio;    
    TBool            iUpdateAppearance;
    TBool            iOwnBitmaps;
    TBool            iDefault;
    TAknsItemID      iId;
    HBufC*           iBmpFile;
    TInt32           iBmp;
    TInt32           iBmpM;
    };


inline TAknWindowComponentLayout DoCompose( TAknWindowComponentLayout aLine1, 
    TAknWindowComponentLayout aLine2 ) 
    { 
    return TAknWindowComponentLayout::Compose( aLine1, aLine2 ); 
    }

inline TAknTextComponentLayout DoComposeText( TAknWindowComponentLayout aLine1, 
    TAknTextComponentLayout aLine2 ) 
    { 
    return TAknWindowComponentLayout::ComposeText( aLine1, aLine2 ); 
    }

// -----------------------------------------------------------------------------
// IsNodeVisibleL
// 
// -----------------------------------------------------------------------------
//
static TBool IsNodeVisibleL(CXnNodePluginIf& aNode)
    {          
    CXnProperty* propVisibility = aNode.VisibilityL();
    
    if( propVisibility )
        {
        const TDesC8& visibility = propVisibility->StringValue();
    
        if( visibility == XnPropertyNames::style::common::visibility::KHidden )
            {
            return EFalse;
            }    
        }
        
    CXnProperty* propDisplay = aNode.DisplayL();
    
    if( propDisplay )
        {
        const TDesC8& display = propDisplay->StringValue();
        
        if( display == XnPropertyNames::style::common::display::KNone )
            {
            return EFalse;
            }
        }
        
    CXnProperty* propDisabled = aNode.GetPropertyL( XnPropertyNames::common::KDisabled );
    
    if( propDisabled )
        {
        const TDesC8& disabled = propDisabled->StringValue();
        
        if( disabled == XnPropertyNames::KTrue )
            {
            return EFalse;
            }
        }
        
    return ETrue;
    }

#ifdef _AVKON_CBA_LSC
// -----------------------------------------------------------------------------
// 
// Calculate touch sensitive softkey area for Top button (landscape)
// -----------------------------------------------------------------------------         
static TRect SoftkeyRectTopTouch()
    {
    TRect screen;
    AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::EScreen, screen );

    TAknLayoutRect layoutRect;

    TAknWindowComponentLayout rightAreaLayout(
            AknLayoutScalable_Avkon::area_side_right_pane( 0 ) );


    layoutRect.LayoutRect( screen, DoCompose( rightAreaLayout,
            AknLayoutScalable_Avkon::sctrl_sk_top_pane() ).LayoutLine() );
    TRect topSKRect( layoutRect.Rect() );
    
    layoutRect.LayoutRect( topSKRect, 
                    AknLayoutScalable_Avkon::aid_touch_sctrl_top().LayoutLine() );
    return layoutRect.Rect();
    }

// -----------------------------------------------------------------------------
// 
// Calculate touch sensitive softkey area for right button (portrait)
// -----------------------------------------------------------------------------         
static TRect SoftkeyRectRightTouch()
    {
    TRect screen;
    AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::EScreen, screen );

    TAknLayoutRect layoutRect;

    TAknWindowComponentLayout bottomAreaLayout(
            AknLayoutScalable_Avkon::area_bottom_pane( 0 ) );


    layoutRect.LayoutRect( screen, DoCompose( bottomAreaLayout,
            AknLayoutScalable_Avkon::control_bg_pane() ).LayoutLine() );
    TRect rightSKRect( layoutRect.Rect() );
    layoutRect.LayoutRect(
    		rightSKRect,
            AknLayoutScalable_Avkon::aid_touch_ctrl_right().LayoutLine() );
    return layoutRect.Rect();
    }

// -----------------------------------------------------------------------------
// 
// Calculate touch sensitive softkey area for left button (portrait)
// -----------------------------------------------------------------------------         
static TRect SoftkeyRectLeftTouch()
    {
    TRect screen;
    AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::EScreen, screen );

    TAknLayoutRect layoutRect;

    TAknWindowComponentLayout bottomAreaLayout(
            AknLayoutScalable_Avkon::area_bottom_pane( 0 ) );


    layoutRect.LayoutRect( screen, DoCompose( bottomAreaLayout,
            AknLayoutScalable_Avkon::control_bg_pane() ).LayoutLine() );
    TRect leftSKRect( layoutRect.Rect() );
    layoutRect.LayoutRect(
    		leftSKRect,
            AknLayoutScalable_Avkon::aid_touch_ctrl_left().LayoutLine() );
 
    return layoutRect.Rect();

    }

// -----------------------------------------------------------------------------
// 
// Calculate touch sensitive softkey area for Bottom button (landscape)
// -----------------------------------------------------------------------------         
static TRect SoftkeyRectBottomTouch()
    {
    TRect screen;
    AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::EScreen, screen );
    
    TAknLayoutRect layoutRect;
        
    TAknWindowComponentLayout rightAreaLayout( AknLayoutScalable_Avkon::area_side_right_pane( 0 ) );
        
    layoutRect.LayoutRect( screen, DoCompose( rightAreaLayout,
                    AknLayoutScalable_Avkon::sctrl_sk_bottom_pane() ).LayoutLine() );
    TRect bottomSKRect( layoutRect.Rect() );
            
    layoutRect.LayoutRect( bottomSKRect,
                    AknLayoutScalable_Avkon::aid_touch_sctrl_bottom().LayoutLine() );
    return layoutRect.Rect();
    }
#endif
// -----------------------------------------------------------------------------
// 
// Calculate (whole) softkey area for Bottom button (landscape)
// -----------------------------------------------------------------------------         
static TBool HDLayoutActive()
    {
    TInt resourceId = 0;
    CEikStatusPaneBase* statusPane = CEikStatusPaneBase::Current();
    
    if ( statusPane ) // Return the resource ID of app statuspane if it exists.
        {
        resourceId = statusPane->CurrentLayoutResId();
        }
    else // If this app does not have statuspane, then we ask the layout from AknCapServer.
        {
        resourceId = CAknSgcClient::CurrentStatuspaneResource();
        }    
    
    TBool retVal = EFalse;
    
    if ( Layout_Meta_Data::IsLandscapeOrientation() )
        {
        // Can be widescreen only in landscape orientation.
        retVal = ( resourceId == R_AVKON_WIDESCREEN_PANE_LAYOUT_USUAL ||
                   resourceId == R_AVKON_WIDESCREEN_PANE_LAYOUT_IDLE  ||
                   resourceId == R_AVKON_WIDESCREEN_PANE_LAYOUT_USUAL_FLAT ||
                   resourceId == R_AVKON_WIDESCREEN_PANE_LAYOUT_IDLE_FLAT );
        }
        
    return retVal;
    }

// -----------------------------------------------------------------------------
// 
// Calculate softkey image graphics area for Bottom button (landscape)
// -----------------------------------------------------------------------------         
static TRect SoftkeyRectBottomGraphics()
    {
    TRect screen;
    AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::EScreen, screen );

    TAknWindowComponentLayout rightAreaLayout(
        AknLayoutScalable_Avkon::area_side_right_pane( 0 ) );
        
    TAknWindowComponentLayout bottomSKLayout(
        DoCompose( rightAreaLayout,
                   AknLayoutScalable_Avkon::sctrl_sk_bottom_pane() ) );

    // Calculate softkey rects.
    // Left (bottom in landscape) softkey layout.
    TAknLayoutRect leftSoftkeyLayoutRect;
    leftSoftkeyLayoutRect.LayoutRect( screen,
                                      bottomSKLayout.LayoutLine() );
    TRect leftSoftKeyButtonRect( leftSoftkeyLayoutRect.Rect() );

    // Calculate softkey image layout.
    // Left (bottom in landscape) softkey layout.
    TAknWindowLineLayout leftSoftkeyImageLayout( 
        DoCompose(
            bottomSKLayout,
            AknLayoutScalable_Avkon::sctrl_sk_bottom_pane_g1() ).LayoutLine() );
            

    TAknLayoutRect qgn_graf_sk_left;
    qgn_graf_sk_left.LayoutRect( screen, leftSoftkeyImageLayout );
    
    return qgn_graf_sk_left.Rect();    
    }

// -----------------------------------------------------------------------------
// 
// Calculate softkey image graphics area for Top button (landscape)
// -----------------------------------------------------------------------------         
static TRect SoftkeyRectTopGraphics()
    {
    TRect screen;
    AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::EScreen, screen );

    TAknWindowComponentLayout rightAreaLayout(
        AknLayoutScalable_Avkon::area_side_right_pane( 0 ) );
        
    TAknWindowComponentLayout topSKLayout(
        DoCompose( rightAreaLayout,
                   AknLayoutScalable_Avkon::sctrl_sk_top_pane() ) );
        
    // Calculate softkey rects.
    // Right (top in landscape) softkey layout.
    TAknLayoutRect rightSoftkeyLayoutRect;
    rightSoftkeyLayoutRect.LayoutRect( screen,
                                       topSKLayout.LayoutLine() );
    TRect rightSoftKeyButtonRect( rightSoftkeyLayoutRect.Rect() );
    
    // Left (bottom in landscape) softkey layout.
    // Right (top in landscape) softkey layout.
    TAknWindowLineLayout rightSoftkeyImageLayout( 
        DoCompose(
            topSKLayout,
            AknLayoutScalable_Avkon::sctrl_sk_top_pane_g1() ).LayoutLine() );
            
    TAknLayoutRect qgn_graf_sk_right;
    qgn_graf_sk_right.LayoutRect( screen, rightSoftkeyImageLayout );
    return qgn_graf_sk_right.Rect();    
    }
    

// -----------------------------------------------------------------------------
// SoftkeyRectL
// Calculate soft key rect
// -----------------------------------------------------------------------------             
static TRect SoftkeyRectL( CEikButtonGroupContainer& aContainer, TInt aPos, TBool aImageOn )
    {
    TRect rect;
    
    if( AknStatuspaneUtils::StaconPaneActive() )   
        {
        TInt variety( 0 );
                        
        if( AknStatuspaneUtils::StaconSoftKeysLeft() )
            {
            variety = 1;
            }
        
        TRect parentRect( iAvkonAppUi->ApplicationRect() );
                                                                              
        switch( aPos )
            {
            case CEikButtonGroupContainer::ELeftSoftkeyPosition:
                {
                TAknWindowComponentLayout layout0( AknLayoutScalable_Avkon::area_bottom_pane( 2 ) );
                TAknWindowComponentLayout layout1( AknLayoutScalable_Avkon::stacon_bottom_pane() );

                // If clock is shown in stacon, cba area is smaller.
                TInt bottomCbaVariety( variety );
                
                if( AknStatuspaneUtils::ExtendedStaconPaneActive() )
                    {
                    bottomCbaVariety += 2;
                    }

                TAknWindowComponentLayout layout2( AknLayoutScalable_Avkon::control_bottom_pane_stacon( bottomCbaVariety ) );    
                                                                                                                       
                if( aImageOn ) 
                    {
                    // Icon layout
                    TAknWindowComponentLayout iconLayout( AknLayoutScalable_Avkon::control_bottom_pane_stacon_g1() );
                                            
                    TAknWindowComponentLayout lskIconLayout( DoCompose( layout0, 
                        DoCompose( layout1, DoCompose( layout2, iconLayout ) ) ) );
                        
                    TAknWindowLineLayout lskIcon( lskIconLayout.LayoutLine() );                    
                    
                    TAknLayoutRect qgn_icon_lsk;
                    
                    qgn_icon_lsk.LayoutRect( parentRect, lskIcon );
                    
                    rect = qgn_icon_lsk.Rect();
                    }
                else
                    {
                    // Text layout
                    TAknTextComponentLayout textLayout( AknLayoutScalable_Avkon::control_bottom_pane_stacon_t1( variety ) );
                    
                    TAknTextComponentLayout lskTextLayout( DoComposeText( layout0, 
                        DoComposeText( layout1, DoComposeText( layout2, textLayout ) ) ) );
                                                                                         
                    TAknTextLineLayout lskText( lskTextLayout.LayoutLine() );                
                    
                    TAknLayoutText qgn_text_lsk;
                    
                    qgn_text_lsk.LayoutText( parentRect, lskText );
                    
                    rect = qgn_text_lsk.TextRect();
                    }                       
                }
                break;
            case CEikButtonGroupContainer::ERightSoftkeyPosition:
                {                                            
                TAknWindowComponentLayout layout0( AknLayoutScalable_Avkon::area_top_pane( 2 ) );
                TAknWindowComponentLayout layout1( AknLayoutScalable_Avkon::stacon_top_pane() );
                        
                TInt topCbaVariety( variety );
                
                if( AknStatuspaneUtils::ExtendedStaconPaneActive() )
                    {
                    topCbaVariety += 4;
                    }
                
                TAknWindowComponentLayout layout2( AknLayoutScalable_Avkon::control_top_pane_stacon( topCbaVariety ) );    
                          
                if( aImageOn ) 
                    {
                    // Icon layout
                    TAknWindowComponentLayout iconLayout( AknLayoutScalable_Avkon::control_top_pane_stacon_g1() );
                                            
                    TAknWindowComponentLayout rskIconLayout( DoCompose( layout0, 
                        DoCompose( layout1, DoCompose( layout2, iconLayout ) ) ) );
                        
                    TAknWindowLineLayout rskIcon( rskIconLayout.LayoutLine() );                    
                    
                    TAknLayoutRect qgn_icon_rsk;
                    
                    qgn_icon_rsk.LayoutRect( parentRect, rskIcon );
                    
                    rect = qgn_icon_rsk.Rect();
                    }
                else
                    {
                    // Text layout                                                          
                    TAknTextComponentLayout textLayout( AknLayoutScalable_Avkon::control_top_pane_stacon_t1( variety ) );
                    
                    TAknTextComponentLayout rskTextLayout( DoComposeText( layout0, 
                        DoComposeText( layout1, DoComposeText( layout2, textLayout ) ) ) );
                                                                                         
                    TAknTextLineLayout rskText( rskTextLayout.LayoutLine() );                
                                       
                    TAknLayoutText qgn_text_rsk;
                    
                    qgn_text_rsk.LayoutText( parentRect, rskText );
                    
                    rect = qgn_text_rsk.TextRect();
                    }      
                }
                break;
            default:
                User::Leave( KErrNotSupported );
                break;
                
            }                                  
        }
    else
        {        
        TInt textVariety( 0 );
        TInt graphVariety( 0 );
        
        TBool mskEnabled( AknLayoutUtils::MSKEnabled() && Layout_Meta_Data::IsMSKEnabled() );
        
        if ( mskEnabled )            
            {
            textVariety = Layout_Meta_Data::IsLandscapeOrientation() ? 2 : 3;
            graphVariety = Layout_Meta_Data::IsLandscapeOrientation() ? 2 : 4;
            }
        else
            {
            textVariety = Layout_Meta_Data::IsLandscapeOrientation() ? 2 : 0;
            graphVariety = Layout_Meta_Data::IsLandscapeOrientation() ? 2 : 4;
            }

        CEikCba* cba( static_cast< CEikCba* >( aContainer.ButtonGroup() ) );
        
        TRect parentRect( cba->Rect() );
        
        switch( aPos )
            {
            case CEikButtonGroupContainer::ELeftSoftkeyPosition:
                {                                
                if( aImageOn )
                    {
                    if ( HDLayoutActive() &&
                         AKN_LAYOUT_WINDOW_screen.iW == KWideScreenWidth )
                        {
                        rect = SoftkeyRectBottomGraphics();
                        }
                     else
                        {
                            
                        TAknLayoutRect qgn_icon_lsk;
                        
                        qgn_icon_lsk.LayoutRect( parentRect,
                            AknLayoutScalable_Avkon::control_pane_g1( graphVariety ).LayoutLine() );
                            
                        rect = qgn_icon_lsk.Rect();
                        }
                    }
                else
                    {
                    TAknLayoutText qgn_text_lsk;
                    
                    qgn_text_lsk.LayoutText( parentRect,                     
                        AknLayoutScalable_Avkon::control_pane_t1( textVariety ).LayoutLine() );
                    
                    rect = qgn_text_lsk.TextRect();
                    }  
                }
                break;
            case CEikButtonGroupContainer::ERightSoftkeyPosition:
                {                                
                if( aImageOn )
                    {
                    if ( HDLayoutActive() &&
                         AKN_LAYOUT_WINDOW_screen.iW == KWideScreenWidth )
                        {
                        rect = SoftkeyRectTopGraphics();
                        }
                     else
                        {
                        TAknLayoutRect qgn_icon_rsk;
                        
                        qgn_icon_rsk.LayoutRect( parentRect,
                            AknLayoutScalable_Avkon::control_pane_g2( graphVariety ).LayoutLine() );                       
                            
                        rect = qgn_icon_rsk.Rect();
                        }
                    }
                else
                    {
                    TAknLayoutText qgn_text_rsk;
                    
                    qgn_text_rsk.LayoutText( parentRect,                     
                        AknLayoutScalable_Avkon::control_pane_t2( textVariety ).LayoutLine() );                   
                    
                    rect = qgn_text_rsk.TextRect();
                    }    
                }
                break;
            case CEikButtonGroupContainer::EMiddleSoftkeyPosition:
                {                                
                if( !mskEnabled || aImageOn )
                    {
                    // No msk, or asking image size for msk
                    User::Leave( KErrNotSupported );
                    }
                else
                    {
                    TAknLayoutText qgn_text_msk;
                    
                    qgn_text_msk.LayoutText( parentRect,                     
                        AknLayoutScalable_Avkon::control_pane_t3( textVariety ).LayoutLine() );
                    
                    rect = qgn_text_msk.TextRect();
                    }    
                }
                break;                                                                                                        
            default:
                User::Leave( KErrNotFound );
                break;
            }                
        }        
        
    return rect;                       
    }
// -----------------------------------------------------------------------------
// Get softkey image rect
// -----------------------------------------------------------------------------
static TRect SoftkeyImageRect(CEikButtonGroupContainer& aContainer, TInt aPosition)
    {
    TRect ret;
#ifndef _AVKON_CBA_LSC    
    TAknLayoutRect softkeyImg;
    CEikCba* cba( static_cast< CEikCba* >( aContainer.ButtonGroup() ) );
    TRect parentRect( cba->Rect() );
    
    if(Layout_Meta_Data::IsLandscapeOrientation())
        {
        if(aPosition == CEikButtonGroupContainer::ELeftSoftkeyPosition)
            {
            TAknWindowComponentLayout wcl = AknLayoutScalable_Avkon::control_pane_g1(2);
            softkeyImg.LayoutRect(parentRect,wcl.LayoutLine() ); 
            }
        else if(aPosition == CEikButtonGroupContainer::ERightSoftkeyPosition)
            {
            TAknWindowComponentLayout wcl = AknLayoutScalable_Avkon::control_pane_g2(2);
            softkeyImg.LayoutRect(parentRect,wcl.LayoutLine() );     
            }
        }
    else
        {
        if(aPosition == CEikButtonGroupContainer::ELeftSoftkeyPosition)
            {
            TAknWindowComponentLayout wcl = AknLayoutScalable_Avkon::control_pane_g1(4);
            softkeyImg.LayoutRect(parentRect,wcl.LayoutLine() );  
            }
        else if(aPosition == CEikButtonGroupContainer::ERightSoftkeyPosition)
            {
            TAknWindowComponentLayout wcl = AknLayoutScalable_Avkon::control_pane_g2(4);
            softkeyImg.LayoutRect(parentRect,wcl.LayoutLine() );  
       
            }
        }
    ret = softkeyImg.Rect();
#else
    if ( Layout_Meta_Data::IsLandscapeOrientation() )
        {
        if(aPosition == CEikButtonGroupContainer::ELeftSoftkeyPosition)
            {
            ret = SoftkeyRectTopTouch();
            }
        else if(aPosition == CEikButtonGroupContainer::ERightSoftkeyPosition)
            {
            ret = SoftkeyRectBottomTouch();
            }
        }
    else // portrait
        {
        if(aPosition == CEikButtonGroupContainer::ELeftSoftkeyPosition)
           {
           ret = SoftkeyRectLeftTouch();
           }
       else if(aPosition == CEikButtonGroupContainer::ERightSoftkeyPosition)
           {
           ret = SoftkeyRectRightTouch();
           }
        }
#endif    
    return ret; 
    }
    
// -----------------------------------------------------------------------------
// CopyBitmapLC
// Copy bitmap
// -----------------------------------------------------------------------------         
static CFbsBitmap* CopyBitmapL( const CFbsBitmap* aBitmap ) 
    {   
    CFbsBitmap* copy = new ( ELeave ) CFbsBitmap;
    CleanupStack::PushL( copy );
    
    copy->Create( aBitmap->SizeInPixels(), aBitmap->DisplayMode() );

    CFbsBitmapDevice* dev = CFbsBitmapDevice::NewL( copy );
    CleanupStack::PushL( dev );
    
    CFbsBitGc* gc = CFbsBitGc::NewL();
    CleanupStack::PushL( gc );
    
    gc->Activate( dev );
    gc->BitBlt( TPoint( 0, 0 ), aBitmap );

    CleanupStack::PopAndDestroy( 2 ); // gc, dev
    
    CleanupStack::Pop( copy );
    
    return copy;
    }
       
// -----------------------------------------------------------------------------
// MenuTypeL
// This is used to deactivate "active applications" menu item using the theme
// Get the "menutype" property from menubar and check if it has value
// "menuoptions" (default) or "menuoptionsnotaskswapper" and return
// correct menu type.
// -----------------------------------------------------------------------------     
static CEikMenuBar::TMenuType MenuTypeL( CXnNodePluginIf& aMenubarNode )
    {
    CEikMenuBar::TMenuType menuType( CEikMenuBar::EMenuOptions );
    
    CXnProperty* property( aMenubarNode.GetPropertyL( XnPropertyNames::menu::KMenuType ) );
                                        
    if( property )
        {                
        if( property->StringValue() == XnPropertyNames::menu::menutype::KMenuOptionsNoTaskSwapper )
            {
            menuType = CEikMenuBar::EMenuOptionsNoTaskSwapper;
            }
        }

    return menuType;
    }
    
// -----------------------------------------------------------------------------
// FindChildL
// 
// -----------------------------------------------------------------------------
static CXnNodePluginIf* FindChildL( CXnNodePluginIf& aNode, 
    const TDesC8& aType, const TDesC8& aTarget )    
    {
    RPointerArray<CXnNodePluginIf> children( aNode.ChildrenL() );
    CleanupClosePushL( children );
    
    CXnNodePluginIf* retval( NULL );

    for( TInt i = 0; i < children.Count(); i++ )
        {
        CXnNodePluginIf* child( children[i] );
        
        if( child->Type()->Type() == aType )
            {
            if( aTarget == KNullDesC8 )
                {
                retval = child;
                break;
                }
            else
                {
                CXnProperty* target( child->GetPropertyL( KXnTarget ) );
                
                if( target && target->StringValue() == aTarget )
                    {
                    retval = child;
                    break;
                    }       
                
                CXnProperty* source( child->GetPropertyL( KXnSource ) );
                                               
                if( source && source->StringValue() == aTarget )
                    {
                    retval = child;
                    break;
                    }                               
                }
            }
        }
    
    CleanupStack::PopAndDestroy( &children );
    
    return retval;
    }

// -----------------------------------------------------------------------------
// FindWidgetElementL
// 
// -----------------------------------------------------------------------------
//
static CXnNodePluginIf* FindWidgetElementL( CXnNodePluginIf& aPluginNode )
    {
    CXnNodePluginIf* retval( NULL );
    
    RPointerArray< CXnNodePluginIf > children( aPluginNode.ChildrenL() );
    CleanupClosePushL( children );
  
    for ( TInt i = 0; i < children.Count(); i++ )
        {
        CXnNodePluginIf* node( children[i] );
        
        if ( node->AppIfL().InternalDomNodeType() == XnPropertyNames::KWidget )
            {
            retval = node;
            break;
            }
        }
    
    CleanupStack::PopAndDestroy( &children );
    
    return retval;
    }

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

// -----------------------------------------------------------------------------
// CXnMenuAdapter::NewL
// Symbian static 1st phase constructor
// -----------------------------------------------------------------------------
//
CXnMenuAdapter* CXnMenuAdapter::NewL( CXnControlAdapter* aParent, CXnNodePluginIf& aNode )
    {
	CXnMenuAdapter* self = new( ELeave ) CXnMenuAdapter;

    CleanupStack::PushL( self );
    self->ConstructL( aParent, aNode );
    CleanupStack::Pop( self );

    return self;	
    }

// -----------------------------------------------------------------------------
// CXnMenuAdapter::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CXnMenuAdapter::ConstructL( CXnControlAdapter* /*aParent*/, CXnNodePluginIf& aNode )
    {
    iRootNode = &aNode;      
    
    CXnControlAdapter::ConstructL( aNode );        
    
    iUiEngine = iRootNode->UiEngineL();
    
    CAknAppUi* appui( iAvkonAppUi );
    
    iPreviousMenuPaneId = appui->StatusPane()->CurrentLayoutResId();
    
    CEikMenuBar* current( iEikonEnv->AppUiFactory()->SwapMenuBar( NULL ) );    
    appui->RemoveFromStack( current );                
	
    delete current;
	current = NULL;
		   
    InitSoftkeyItemsL();
    }
    
// -----------------------------------------------------------------------------
// CXnMenuAdapter::CXnMenuAdapter
// C++ default constructor
// -----------------------------------------------------------------------------
//
CXnMenuAdapter::CXnMenuAdapter(): 
    iMenuItems( KXnMenuArrayGranularity ), 
    iIdCounter( KMenuCommandFirst )
    {
    }

// -----------------------------------------------------------------------------
// CXnMenuAdapter::~CXnMenuAdapter
// C++ destructor
// -----------------------------------------------------------------------------
//
CXnMenuAdapter::~CXnMenuAdapter()
    {
    StopDisplayingMenu();

    if ( iAvkonAppUi )
        {
        iAvkonAppUi->RemoveFromStack( iMenuBar );
        }

    if ( iMenuBar )
        {
        delete iMenuBar;
        }

    iSoftkeyItems.ResetAndDestroy();
    iMenuItems.Reset();
    }

// -----------------------------------------------------------------------------
// Create scaled bitmap from source bitmap.
// -----------------------------------------------------------------------------
//
void CreateScaledBitmapL(
    const TRect& aRect,
    CFbsBitmap*& aTrgBitmap, 
    CFbsBitmap* aSrcBitmap,
    TBool aPreserveAspectRatio )    
    {
    TRect destRect = aRect;
        
    if( aPreserveAspectRatio )
    	{
	    // Calculate the bitmap image dimensions so that it uses maximum space 
	    // of the given rectangle and maintains aspect ratio.
    	TInt srcHeight = aSrcBitmap->SizeInPixels().iHeight;
    	TInt srcWidth = aSrcBitmap->SizeInPixels().iWidth;
    	TReal scaleRatio( 1 ); //no scale as defaul

		// If any dimension is 0, then we do not bother to scale
    	if( aRect.Width() > 0 && aRect.Height() > 0 )
    		{
	    	TReal xRatio = ( (TReal )srcWidth / ( TReal )aRect.Width() );
	    	TReal yRatio = ( ( TReal )srcHeight / ( TReal )aRect.Height() );
	    	
	    	//Find out appropriate scaling factor
	   		xRatio > yRatio ? ( scaleRatio = xRatio ) : ( scaleRatio = yRatio );
    		}
    	
    	// Scale the size for target bitmap
    	destRect.SetHeight( srcHeight / scaleRatio );
		destRect.SetWidth( srcWidth / scaleRatio );
    	}

    aTrgBitmap = new ( ELeave ) CFbsBitmap;
    CleanupStack::PushL( aTrgBitmap );
    
    // It is allowed to create zero height or width bitmap.    
    TInt err( aTrgBitmap->Create( destRect.Size(), aSrcBitmap->DisplayMode() ) );

    if( err == KErrNone )
        {
		CXnUtils::ScaleBitmapL( destRect, aTrgBitmap, aSrcBitmap );
        }

    // we do not own the bitmap so just Pop.
    CleanupStack::Pop( aTrgBitmap );
    }    

// -----------------------------------------------------------------------------
// CXnMenuAdapter::PrepareSoftkeyImageL
// Make a copy of originals and scale them to right size.
// Finally place the scaled icon to right position of drawing area.
// -----------------------------------------------------------------------------         
CEikImage* CXnMenuAdapter::PrepareSoftkeyImageL( const CXnSoftkeyItem& aItem, const TSize& aSize )
    {                         
    CFbsBitmap* bitmap( NULL );
    CFbsBitmap* mask( NULL );
    
    // Start from bitmap
    CFbsBitmap* source( aItem.iBitmap );    
        
    TInt count( 0 );
           
    // Go through bitmap and mask
    for( TInt i = 0; i < 2; i++ )
        {
        if( !source )
            {
            source = aItem.iMask;
            continue;
            }
            
        CFbsBitmap* scaled( NULL );            

        TScaleMode mode( aItem.iPreserveAspectRatio ? EAspectRatioPreserved : EAspectRatioNotPreserved );
            
        if( AknIconUtils::IsMifIcon( source ) )
            {                       
            AknIconUtils::SetSize( source, aSize, mode );
            
            scaled = CopyBitmapL( source );
            }
        else
            {                            
            CreateScaledBitmapL( TRect( aSize ), scaled, source, mode == EAspectRatioPreserved );        
            }

        CleanupStack::PushL( scaled );                
        
        if( !aItem.iPreserveAspectRatio )                        
            {                          
            count++;
                                 
            if( i == 0 )
                {                
                bitmap = scaled;                                
                }
            else
                {
                mask = scaled;
                }                                                                         
            }
        else
            {                        
            CFbsBitmap* target = new ( ELeave ) CFbsBitmap;
            CleanupStack::PushL( target );

            // Target is size of whole draw area
            User::LeaveIfError( target->Create( aSize, source->DisplayMode() ) );
        	
    	    CFbsBitmapDevice* dev = CFbsBitmapDevice::NewL( target );
    	    CleanupStack::PushL( dev );
    	    
    	    CFbsBitGc* gc = CFbsBitGc::NewL();
    	    CleanupStack::PushL( gc );
    	    
    	    gc->Activate( dev );
    	    
    	    gc->SetBrushStyle( CGraphicsContext::ESolidBrush );
    	    gc->SetPenStyle( CGraphicsContext::ENullPen );
    	    
    	    if( aItem.iInvertMask )
    	        {
        	    // White, with full transparent alpha channel
        	    gc->SetBrushColor( TRgb( 0x00FFFFFF, 0 ) );	       
    	        }
            else
                {
        	    // Black, with full transparent alpha channel
        	    gc->SetBrushColor( TRgb( 0x00000000, 0 ) );
                }	        
    	    
    	    // Make whole target area transparent
    	    gc->DrawRect( TRect( aSize ) );
    	   
    	   	TPoint iconPos;
    	   	
    	   	switch( AknLayoutUtils::CbaLocation() )
    	   	    {	   	    
    	   	    case AknLayoutUtils::EAknCbaLocationBottom:
    	   	        // Rsk must be moved to right, lsk is in correct place by default	   	        
    	   	        if ( aItem.iPosition != CEikButtonGroupContainer::ELeftSoftkeyPosition )
    	   	            {
    	   	            iconPos.iX = aSize.iWidth - scaled->SizeInPixels().iWidth;
    	   	            }
    	   	        break;	   	    	   	   
    	   	    case AknLayoutUtils::EAknCbaLocationRight:
    	   	        // Rsk and lsk must be moved to right	   	       
    	   	        iconPos.iX = aSize.iWidth - scaled->SizeInPixels().iWidth;
    	   	        break;
    	   	    case AknLayoutUtils::EAknCbaLocationLeft:
    	   	        // Already in correct position
    	   	    default:    	   	        
    	   	        break;    
    	   	    }
    	   	
    	   	// Align horizontally to center
            iconPos.iY = iconPos.iX ? 0 : ( ( aSize.iHeight - scaled->SizeInPixels().iHeight ) / 2 );
    	   		   	
    	   	gc->SetBrushStyle( CGraphicsContext::ENullBrush );
    	   			   	
    	   	// Blit image to correct position
    	   	gc->BitBlt( iconPos, scaled );    	

    		CleanupStack::PopAndDestroy( 2, dev );    		    		    		    		
    		
    		CleanupStack::Pop( target );
    		
    		CleanupStack::PopAndDestroy( scaled );
    		
    		CleanupStack::PushL( target );
            count++;                		    		
            
    		if( i == 0 )
    		    {
    		    bitmap = target;    		        		    
    		    }
            else
                {
                mask = target;
                }    		        		      
                
            
        	}                  
        
        // Go with mask next
        source = aItem.iMask;
        }    
        
    // Takes ownership of scaled bitmap and mask
    CEikImage* image = new ( ELeave ) CEikImage;
    
    image->SetPictureOwnedExternally( EFalse );
    image->SetPicture( bitmap, mask );        
                       
    CleanupStack::Pop( count ); 
    
    return image;
    }

// -----------------------------------------------------------------------------
// CXnMenuAdapter::SetSoftkeyAppearanceL
// 
// -----------------------------------------------------------------------------
//
void CXnMenuAdapter::SetSoftkeyAppearanceL( CXnSoftkeyItem& aItem )
    {
    if( iContainer && IsNodeVisibleL( *aItem.iNode) )
        {
        if( aItem.iImageOn )
            {
            ChangeSoftkeyImageL( aItem );
            }
        else if( aItem.iLabel )// change label
            {
            if ( aItem.iPosition == CEikButtonGroupContainer::ELeftSoftkeyPosition )
                {
                EikSoftkeyImage::SetLabel( iContainer, ETrue );
                }
            else if ( aItem.iPosition == CEikButtonGroupContainer::ERightSoftkeyPosition )
                {
                EikSoftkeyImage::SetLabel( iContainer, EFalse );
                }

            iContainer->SetCommandL( aItem.iPosition, aItem.iCommandId, *aItem.iLabel );
            }
        }
    }

// -----------------------------------------------------------------------------
// CXnMenuAdapter::InitSoftkeyItemsL
// 
// -----------------------------------------------------------------------------
//
void CXnMenuAdapter::InitSoftkeyItemsL()
    {                
    // No layout calulations needed
    iRootNode->SetLayoutCapable( EFalse );       
    
    // create softkeyitems to hold data
    
    RPointerArray< CXnNodePluginIf > children( iRootNode->ChildrenL() );
    CleanupClosePushL( children );
    CXnSoftkeyItem* item(0);
    for(TInt i=0;i<children.Count();++i)
        {
        if(children[i]->Type()->Type() == XnPropertyNames::softkey::KNodeName)
            {
            item = AppendSoftkeyItemL(children[i]);
            if(item)
                {
                item->iDefault = ETrue;
                }
            }
        }
    CleanupStack::PopAndDestroy( &children );
    
   }
    
// -----------------------------------------------------------------------------
// CXnMenuAdapter::InitSoftkeyItemL
// 
// -----------------------------------------------------------------------------
//
void CXnMenuAdapter::InitSoftkeyItemImageL( CXnSoftkeyItem& aItem)
    {
    CXnNodePluginIf* node( aItem.iNode );
    
    // No layout calulations needed
    node->SetLayoutCapable( EFalse );                                                                 

    if ( aItem.iPosition == CEikButtonGroupContainer::EMiddleSoftkeyPosition )
        {
        aItem.iImageOn = ETrue;
        return;
        }

    CXnProperty* pathProp( node->PathL() );
    if( pathProp )
        {     
        HBufC* bitmapPath( NULL );                                  
        HBufC* maskPath( NULL );
        
        bitmapPath = pathProp->StringValueL();
        CleanupStack::PushL( bitmapPath );
        TInt count( 1 );
        
        CXnProperty* maskProp( node->MaskPathL() );
                                        
        if( maskProp )
            {
            maskPath = maskProp->StringValueL();                                
            CleanupStack::PushL( maskPath );
            count++;
            }
                    
        CFbsBitmap* bitmap( NULL );
        CFbsBitmap* mask( NULL );
                                                                    
        // Call base class to get bitmap and mask                        
        GetBitmapAndMask( bitmapPath ? *bitmapPath : KNullDesC(), 
                          maskPath ? *maskPath : KNullDesC(), 
                          bitmap, mask );                            
                    
        aItem.iImageOn = ETrue;
        aItem.iBitmap = bitmap;
        aItem.iMask = mask;
        
        CXnProperty* maskInvertedProp( node->GetPropertyL( XnPropertyNames::image::KMaskInverted ) );
        
        if( maskInvertedProp )
            {                        
            if( maskInvertedProp->StringValue() == XnPropertyNames::KTrue )
                {
                aItem.iInvertMask = ETrue;
                }
            }
        
        CXnProperty* aspectRatioProp( node->GetPropertyL( XnPropertyNames::image::KS60AspectRatio ) );
        
        if( aspectRatioProp )
            {
            if( aspectRatioProp->StringValue() == XnPropertyNames::image::KPreserve )
                {
                aItem.iPreserveAspectRatio = ETrue;
                }
            }
                
        CleanupStack::PopAndDestroy( count ); // path and/or mask
        }    
    }

// -----------------------------------------------------------------------------
// CXnMenuAdapter::IsMskAvailable
// 
// -----------------------------------------------------------------------------
//
TBool CXnMenuAdapter::IsMskAvailable()
    {
    if( AknLayoutUtils::MSKEnabled() && Layout_Meta_Data::IsMSKEnabled() )
        {     
        return ETrue;
        }
    
    return EFalse;                
    }
    
// -----------------------------------------------------------------------------
// CXnMenuAdapter::AddMenuItemL
// 
// -----------------------------------------------------------------------------
//
TInt CXnMenuAdapter::AddMenuItemL( TInt aParentIndex, 
    CXnNodePluginIf* aNode, RPointerArray< const TDesC8 >& aGroups )
    {
    if ( !aNode )
        {
        return 0;
        }
    
    const TDesC8& name( aNode->Type()->Type() );
    
    TInt retval( 0 );
    
    TBool showByGroup( EFalse );
    
    const TDesC8* id( NULL );
    
    CXnProperty* prop( aNode->IdL() );
    
    if( prop )
        {            
        id = &prop->StringValue();
        }
    else
        {
        // If menuitem doesn't have id, group doesn't affect to it
        showByGroup = ETrue;
        }
    
    if( name == KXnMenuItem || 
        name == KXnDynMenuItem || 
        name == KXnWidgetMenuItem )
        {               
        const TDesC8& ns( aNode->Namespace() );
                       
        for( TInt i = 0; !showByGroup && i < aGroups.Count(); i++ )
            {                       
            const TDesC8& groupId( *(aGroups)[i] );
        
            CXnNodePluginIf* group( iUiEngine->FindNodeByIdL( groupId, ns ) );
            
            if( group )
                {
                RPointerArray< CXnNodePluginIf > 
                    children( group->ChildrenL() );
                
                CleanupClosePushL( children );
                
                for( TInt j = 0; j < children.Count(); j++ )
                    {
                    CXnProperty* prop( children[j]->GetPropertyL( 
                            XnPropertyNames::action::KName ) );
                                        
                    if( prop )
                        {
                        const TDesC8& name( prop->StringValue() );
                            
                        if( name == *id )
                            {
                            // The menuitem belongs to defined group
                            showByGroup = ETrue;
                            break;                            
                            }
                        }
                    }
                
                CleanupStack::PopAndDestroy( &children );                
                }            
            }
        
        if( !showByGroup || !IsNodeVisibleL( *aNode ) )
            {
            // Menuitem is invisible  
            return retval;
            }
        }
               
    TXnMenuItem item;

    item.iAutomaticSP = ETrue;
        
    item.iParentIndex = aParentIndex;
    item.iData.iFlags = 0;

    CXnNodePluginIf* menuItem( NULL );
    
    if( name == KXnMenuItem || name == KXnDynMenuItem )
        {
        menuItem = aNode;
        }
    else if( name == KXnWidgetMenuItem )
        {
        TRAP_IGNORE( menuItem = FindWidgetMenuItemL( aNode ) );
        }
    
    if( menuItem )
        {
        const TDesC8& type( menuItem->Type()->Type() );
        
        // check first if label comes from view
        CXnProperty* label( aNode->LabelL() );
        
        if ( !label )
            {
            // get label from widget
            label = menuItem->LabelL();
            }
        
        if( label )
            {
            HBufC* itemLabel = label->StringValueL();
            item.iData.iText.Copy( *itemLabel );
            delete itemLabel;
            }
        else
            {
            item.iData.iText.Copy( KNullDesC );
            }
    
        TBool okToAdd( ETrue );
        
        if( type == KXnDynMenuItem )
            {
            okToAdd = EFalse;
            
            if( iObserver )
                {
                okToAdd = iObserver->DynInitMenuItemL( menuItem->AppIfL() );
                }            
            }
        
        if( okToAdd )
            {
            if ( id && *id == KHsShowHelp )
                {
                // Help command id must be EAknCmdHelp to get editing input options
                // shown correctly  
                item.iData.iCommandId = EAknCmdHelp;
                }
            else
                {
                item.iData.iCommandId = iIdCounter++;
                }
            
            item.iData.iCascadeId = 0;
            item.iNode = menuItem;
            item.iIsCascade = EFalse;
            iMenuItems.AppendL( item );
            
            retval = 1;
            }               
        }
    
    if( name == KXnMenu )
        {
        // main level menu or submenu (cascade)               
        item.iData.iCommandId = iIdCounter++;

        if( aParentIndex == -1 )
            {
            item.iData.iCascadeId = R_AVKON_MENUPANE_EMPTY;
            }
        else
            {
            item.iData.iCascadeId = iIdCounter++;
            }
        
        item.iNode = aNode;
        item.iIsCascade = ETrue;        
        iMenuItems.AppendL( item );

        TInt currentIndex( iMenuItems.Count() - 1 );
        
        RPointerArray< CXnNodePluginIf > children( aNode->ChildrenL() );
        CleanupClosePushL( children );

        TInt count( 0 );
        
        for( TInt i = 0; i < children.Count(); i++ )
            {
            count += AddMenuItemL( currentIndex, children[i], aGroups );
            }
        
        if( aParentIndex != -1 && count == 0 )
            {
            // Empty submenu, don't show it            
            iMenuItems.Delete( currentIndex );
            // Reverse counter as well
            iIdCounter -= 2;
            }
        
        CleanupStack::PopAndDestroy( &children );
        
        retval = count;
        }

    return retval;
    }
    
// -----------------------------------------------------------------------------
// CXnMenuAdapter::PopulateMenuL
// 
// -----------------------------------------------------------------------------
//
void CXnMenuAdapter::PopulateMenuL()
    {
    iMenuItems.Reset();

    iIdCounter = KMenuCommandFirst;
               
    RPointerArray< const TDesC8 > groups;
    CleanupClosePushL( groups );
               
    if ( !iUiEngine->IsTextEditorActive() )
        {  
        if( iUiEngine->EditMode() )        
            {
            groups.AppendL( 
                iContextMenu ? &KContextEditMode : &KEditMode );
            }
        else
            {
            groups.AppendL( 
                iContextMenu ? &KContextNormalMode : &KNormalMode );
            }
        }

    if ( !iContextMenu )
        {
        groups.AppendL( &KAlwaysShown );
        }
            
    // Recursively add menuitems
    AddMenuItemL( -1, iMenuBarNode, groups );
    
    CleanupStack::PopAndDestroy( &groups );
    }
  
// -----------------------------------------------------------------------------
// CXnMenuAdapter::OfferKeyEventL
// -----------------------------------------------------------------------------
//
TKeyResponse CXnMenuAdapter::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
    {    
    TKeyResponse resp( EKeyWasNotConsumed );
    
    if( IsMenuFocused() && aKeyEvent.iScanCode == EStdKeyNo )
        {
        StopDisplayingMenu();            
        
        iKeyEventNode = NULL;
        
        return resp;
        }        
    
    TInt pos( KErrNotFound );
           
    if( aKeyEvent.iScanCode == EStdKeyDevice0 )
        {
        pos = CEikButtonGroupContainer::ELeftSoftkeyPosition;
        }
    else if( aKeyEvent.iScanCode == EStdKeyDevice1 )
        {
        pos = CEikButtonGroupContainer::ERightSoftkeyPosition;
        }
    else if( aKeyEvent.iScanCode == EStdKeyDevice3 )
        {
        pos = CEikButtonGroupContainer::EMiddleSoftkeyPosition;
        }            
    
    CXnSoftkeyItem* softkey( NULL );
    
    if ( pos != KErrNotFound )
        {
        softkey = SoftkeyItemL( pos );
        }
        
    if ( softkey )
        {
        CXnNodePluginIf* node( softkey->iNode );
        
        if( aType == EEventKeyDown )
            {                                  
            iKeyEventNode = node;           
            }
                       
        if( node && node == iKeyEventNode )
            {
            // Let base class handle the event           
            resp = CXnControlAdapter::OfferKeyEventL( aKeyEvent, aType );                                        
            }            
        }
            
    if( aType == EEventKeyUp )
        {
        iKeyEventNode = NULL;
        }
        
    return resp;
    }
    
// -----------------------------------------------------------------------------
// CXnMenuAdapter::HandlePointerEventL
// -----------------------------------------------------------------------------
//
void CXnMenuAdapter::HandlePointerEventL( const TPointerEvent& aPointerEvent )
    {          
    CXnNodePluginIf* node( FindSoftkeyItemByPosition( aPointerEvent.iParentPosition ) );
    
    if( aPointerEvent.iType  == TPointerEvent::EButton1Down )
        {
        // The sofkey node which received the button down event
        iPointerEventNode = node;        
        }
        
    if( node && node == iPointerEventNode )
        {
        iUiEngine->DisableRenderUiLC();
        
        // Handle event if location is in the grabbing node's area    
        CXnControlAdapter::HandlePointerEventL( aPointerEvent );
        
        CleanupStack::PopAndDestroy();
        }
            
    if( aPointerEvent.iType  == TPointerEvent::EButton1Up )
        {
        // Reset grabbing node after the up event
        iPointerEventNode = NULL;
        }    
    }

// -----------------------------------------------------------------------------
// CXnMenuAdapter::DoEnterPowerSaveModeL
// Enter power save mode
// -----------------------------------------------------------------------------
void CXnMenuAdapter::DoEnterPowerSaveModeL(TModeEvent /*aEvent*/)
    {
    }
    
// -----------------------------------------------------------------------------
// CXnMenuAdapter::DoExitPowerSaveModeL
// Enter power save mode
// -----------------------------------------------------------------------------
void CXnMenuAdapter::DoExitPowerSaveModeL(TModeEvent /*aEvent*/)
    {
    } 
       
// -----------------------------------------------------------------------------
// CXnMenuAdapter::RestoreMenuL
// -----------------------------------------------------------------------------
//
void CXnMenuAdapter::RestoreMenuL( CCoeControl* aMenuControl, TInt aResourceId,        
    TMenuType aType )
    {
    // let all menu pane resources propogate to default implementation,
    // otherwise panic when trying to display menu
    if ( aType == MEikMenuObserver::EMenuPane )
        {
        if ( !( KMenuCommandFirst <= aResourceId && 
                aResourceId <= KMenuCommandLast ) 
            && aResourceId != R_AVKON_MENUPANE_EMPTY  )
            {
            MEikMenuObserver::RestoreMenuL( aMenuControl,aResourceId, aType );
            }
        else
            {
            AddItemsToMenuPaneL( ( CEikMenuPane* )aMenuControl, aResourceId );            
            }
        }  
    }

// -----------------------------------------------------------------------------
// CXnMenuAdapter::DynInitMenuPaneL
// -----------------------------------------------------------------------------
//
void CXnMenuAdapter::DynInitMenuPaneL( TInt aResourceId, 
    CEikMenuPane* aMenuPane )
    {
    if ( aResourceId == R_AVKON_MENUPANE_EMPTY )
        {
        RestoreMenuL( aMenuPane, aResourceId, MEikMenuObserver::EMenuPane );
        }    
    }
    
// -----------------------------------------------------------------------------
// CXnMenuAdapter::SetEmphasis
// -----------------------------------------------------------------------------
//
void CXnMenuAdapter::SetEmphasis( CCoeControl* aMenuControl, 
    TBool aEmphasis )
    {
    if ( iMenuBar && aMenuControl == iMenuBar )
        {   
        CXnAppUiAdapter* appui( 
            static_cast< CXnAppUiAdapter* >( iAvkonAppUi ) );

        if ( aEmphasis && !iMenuShown )
            {
            iMenuShown = ETrue;

            TRAP_IGNORE( appui->AddToStackL( appui->View(),
                                             iMenuBar,
                                             ECoeStackPriorityMenu ) );

            iMenuBar->MakeVisible( ETrue );
            }
        else if ( !aEmphasis && iMenuShown )
            {
            iMenuShown = EFalse;
         
            appui->RemoveFromStack( iMenuBar );
            
            iMenuBar->MakeVisible( EFalse );
            }
        }
    }

// -----------------------------------------------------------------------------
// CXnMenuAdapter::ProcessCommandL
// -----------------------------------------------------------------------------
//
void CXnMenuAdapter::ProcessCommandL( TInt aCommand )
    {     
    if ( ( KMenuCommandFirst <= aCommand && aCommand <= KMenuCommandLast ) || 
        aCommand == EAknCmdHelp )
        {
        // find item for this command
        for ( TInt i = 0; i< iMenuItems.Count(); i++ )
            {
            if ( iMenuItems[i].iData.iCommandId == aCommand )
                {
                CXnNodePluginIf* node( iMenuItems[i].iNode );
                
                if ( node )
                    {
                    StopDisplayingMenu();
                    
                    iUiEngine->DisableRenderUiLC();
                    
                    node->SetStateL( XnPropertyNames::style::common::KActive );
                    
                    CleanupStack::PopAndDestroy();                 
                    
                    break;
                    }                                    
                }
            }        
        }
    else
        {
        StopDisplayingMenu();

        if( aCommand == EEikCmdEditPaste )
            {
            // Paste event for AknCcpuSupport
            TKeyEvent pasteEvent = 
                { EKeyF18, EEikCmdEditPaste, EModifierCtrl, 1 };  
            
            iCoeEnv->SimulateKeyEventL( pasteEvent, EEventKey );
            }
        }
    }

// -----------------------------------------------------------------------------
// CXnMenuAdapter::SetContainerL
// 
// -----------------------------------------------------------------------------
//
void CXnMenuAdapter::SetContainerL( CEikButtonGroupContainer& aContainer )
    {    
    User::LeaveIfNull( &aContainer );
    
    TBool updateNeeded( EFalse );
    
    TInt statusPaneId( iAvkonAppUi->StatusPane()->CurrentLayoutResId() );
    
    if(iPreviousMenuPaneId != statusPaneId)
        {
        updateNeeded = ETrue;
        iPreviousMenuPaneId = statusPaneId;
        }
    
 	if((&aContainer) && (iContainer != &aContainer || updateNeeded))
        {
        iUpdateLskAppearance = ETrue;
        iUpdateMskAppearance = ETrue;
        iUpdateRskAppearance = ETrue;
        }
 	
	iContainer = &aContainer;
	
    CEikCba* cba( static_cast< CEikCba* >( aContainer.ButtonGroup() ) );
    cba->SetButtonGroupFlags( cba->ButtonGroupFlags() | EEikCbaFlagSemiTransparent );

    UpdateSoftkeyAppearancesL();	    
    }

//--------------------------------------------------------------
// CXnMenuAdapter::IsMenuFocused
// ------------------------------------------------------------        
TBool CXnMenuAdapter::IsMenuFocused()
    {
    return iMenuShown;
    }

// -----------------------------------------------------------------------------
// CXnMenuAdapter::TryDisplayingMenuL
// Displays options menu 
// -----------------------------------------------------------------------------
//
void CXnMenuAdapter::TryDisplayingMenuL( const TDesC& aMenuNodeId, 
    TBool aContextMenu )
    {
    HBufC8* id = CnvUtfConverter::ConvertFromUnicodeToUtf8L( aMenuNodeId );
    CleanupStack::PushL( id );
    CXnNodePluginIf* node( iUiEngine->FindNodeByIdL( *id, iRootNode->Namespace() ) );
    CleanupStack::PopAndDestroy( id );
    
    iContextMenu = aContextMenu;
    
    if( node && node->Type()->Type() == KXnMenu )
        {
        TryDisplayingMenuL();
        }
    }

// -----------------------------------------------------------------------------
// CXnMenuAdapter::TryDisplayingMenuL
// Displays options menu if it is defined for the softkey item
// -----------------------------------------------------------------------------
//
void CXnMenuAdapter::TryDisplayingMenuL()
    {
    StopDisplayingMenu();
    
    CreateMenuBarL();    
    
    if ( iMenuBar )
        {    
        CEikMenuBarTitle* title = new( ELeave ) CEikMenuBarTitle;
        CleanupStack::PushL( title );
            
        title->iData.iMenuPaneResourceId = R_AVKON_MENUPANE_EMPTY;    
        title->iTitleFlags = 0;
        
        // this cannot be done earlyer, than this callback
        iMenuBar->TitleArray()->AddTitleL( title );
        CleanupStack::Pop( title );
        
        iMenuBar->TryDisplayMenuBarL();
        }    
    }

// -----------------------------------------------------------------------------
// CXnMenuAdapter::StopDisplayingMenu
// -----------------------------------------------------------------------------
//
void CXnMenuAdapter::StopDisplayingMenu()
    {       
    if( iMenuBar )
        {
        iMenuBar->StopDisplayingMenuBar();
        }
    }

// ---------------------------------------------------------------------------
// CXnMenuAdapter::CreateMenuBarL
// ---------------------------------------------------------------------------
//
void CXnMenuAdapter::CreateMenuBarL()
    {
    if ( iMenuBar )
        {
        // All ready created
        return;
        }
    
    // Create
    RPointerArray< CXnNodePluginIf > children( iRootNode->ChildrenL() );
    CleanupClosePushL( children );
      
    for( TInt i = 0; i < children.Count(); i++ )
        {       
        CXnNodePluginIf* node( children[i] );
        
        TPtrC8 type( node->Type()->Type() );
                                                       
        // Currently only one menubar is allowed,
        // but it can be assigned to any of the CBAs
        // To change this, we have to create and maintain a list of menubars 
        if( type == KXnMenu )
            {
            iMenuBarNode = node;
            
            iMenuBar = new ( ELeave ) CEikMenuBar;
            iMenuBar->ConstructL( this );
            iMenuBar->SetMenuType( MenuTypeL( *iRootNode ) );
                        
            // All done
            break;
            }
        }
    CleanupStack::PopAndDestroy( &children );
    }

//--------------------------------------------------------------
// CXnMenuAdapter::HandleResourceChange
// Handles a change to the control's resources of type aType
// ------------------------------------------------------------    
void CXnMenuAdapter::HandleResourceChange( TInt aType )
    {	
    if( iMenuBar )
        {
        iMenuBar->HandleResourceChange( aType );
        }   	
    }
   
// -----------------------------------------------------------------------------
// CXnMenuAdapter::SetSoftKeyImageL
// 
// -----------------------------------------------------------------------------
//
void CXnMenuAdapter::SetSoftKeyImageL(
    CFbsBitmap* aBitmap, 
    CFbsBitmap* aMask, 
    XnMenuInterface::MXnMenuInterface::TSoftKeyPosition aPos, 
    CXnNodeAppIf* aNode,
    TBool aPreserveAspectRatio, TBool aInvertMask,
    TBool aTransferOwnership)
    {        
    if( ( !aBitmap && !aMask ) || aPos == XnMenuInterface::MXnMenuInterface::ECenter )
        {
        // No images present and image can be set only to lsk or rsk         
        User::Leave( KErrArgument );
        }

    CXnSoftkeyItem* softkey(NULL);
    
    if( aPos == XnMenuInterface::MXnMenuInterface::ELeft)
        {
        if( aNode )
            {
            softkey = SoftkeyItemL( aNode );
            }
        else
            {
            softkey = SoftkeyItemL(CEikButtonGroupContainer::ELeftSoftkeyPosition);
            }
        iUpdateLskAppearance = ETrue;
        }
    else if(aPos == XnMenuInterface::MXnMenuInterface::ERight)
        {
        if( aNode )
            {
            softkey = SoftkeyItemL( aNode );
            }
        else
            {
            softkey = SoftkeyItemL(CEikButtonGroupContainer::ERightSoftkeyPosition);
            }
        iUpdateRskAppearance = ETrue;
        }
    
    if(softkey)
        {
        softkey->Reset();
        softkey->iImageOn = ETrue;
                                                                    
        // Save new icon data
        softkey->iBitmap = aBitmap;
        softkey->iMask = aMask;
        softkey->iPreserveAspectRatio = aPreserveAspectRatio;
        softkey->iInvertMask = aInvertMask;
        softkey->iOwnBitmaps = aTransferOwnership;
        // Image set, mark node as dirty
        softkey->iNode->SetDirtyL();
                
        }
    }

// -----------------------------------------------------------------------------
// CXnMenuAdapter::SetSoftKeyImageL
// 
// -----------------------------------------------------------------------------
//
void CXnMenuAdapter::SetSoftKeyImageL( const TAknsItemID& aId,
    const TDesC& aBmpFile,
    const TInt32 aBmp,
    const TInt32 aBmpM,
    XnMenuInterface::MXnMenuInterface::TSoftKeyPosition aPos, 
    TBool /*aEnable*/ )
    {
    CXnSoftkeyItem* softkey( NULL );

    switch( aPos )
        {
        case XnMenuInterface::MXnMenuInterface::ECenter:
            {
            softkey = SoftkeyItemL( CEikButtonGroupContainer::EMiddleSoftkeyPosition );           
            iUpdateMskAppearance = ETrue;
            break;
            }
        // Currently only MSK icon updating supported here
        case XnMenuInterface::MXnMenuInterface::ELeft:
        case XnMenuInterface::MXnMenuInterface::ERight:
        default:
            {
            break;
            }
        }

    if( softkey )
        {
        softkey->Reset();
        softkey->iImageOn = ETrue;

        // Save new icon data
        softkey->iBitmap = NULL;
        softkey->iMask = NULL;
        softkey->iPreserveAspectRatio = EFalse;
        softkey->iInvertMask = EFalse;
        softkey->iOwnBitmaps = ETrue;
        delete softkey->iBmpFile;
        softkey->iBmpFile = NULL;
        softkey->iBmpFile = aBmpFile.AllocL();
        softkey->iId.Set( aId );
        softkey->iBmp = aBmp;
        softkey->iBmpM = aBmpM;

        // Image set, mark node as dirty
        softkey->iNode->SetDirtyL();
        }
    }

// -----------------------------------------------------------------------------
// CXnMenuAdapter::SetSoftKeyTextL
// 
// -----------------------------------------------------------------------------
//
void CXnMenuAdapter::SetSoftKeyTextL( const TDesC& aText, 
    XnMenuInterface::MXnMenuInterface::TSoftKeyPosition aPos )
    {       
    CXnSoftkeyItem* softkey(NULL);
    
    switch( aPos )
        {
        case XnMenuInterface::MXnMenuInterface::ELeft:
            softkey = SoftkeyItemL(CEikButtonGroupContainer::ELeftSoftkeyPosition);
            iUpdateLskAppearance = ETrue;
            break;
        case XnMenuInterface::MXnMenuInterface::ERight:
            softkey = SoftkeyItemL(CEikButtonGroupContainer::ERightSoftkeyPosition);
            iUpdateRskAppearance = ETrue;
            break;
        case XnMenuInterface::MXnMenuInterface::ECenter:  
            softkey = SoftkeyItemL(CEikButtonGroupContainer::EMiddleSoftkeyPosition);           
            iUpdateMskAppearance = ETrue;
            break;
        default:     
            break;
        }
    if(softkey)
        {
        softkey->Reset();
                                              
        softkey->iImageOn = EFalse;    
                                              
        softkey->iLabel = aText.AllocL();
        // Text set, mark parent as dirty
        softkey->iNode->SetDirtyL();
       }
    }

// -----------------------------------------------------------------------------
// CXnMenuAdapter::SetSoftKeyL
// 
// -----------------------------------------------------------------------------
//
void CXnMenuAdapter::SetSoftKeyL( CXnNodePluginIf* aSoftkeyNode, 
    XnMenuInterface::MXnMenuInterface::TSoftKeyPosition aPos )
    {

    CXnSoftkeyItem* item = AppendSoftkeyItemL(aSoftkeyNode);
    switch(aPos)
        {
        case XnMenuInterface::MXnMenuInterface::ELeft:
            if(item)
                {
                iVisibleLSK = item;
                }
            else
                {
                iVisibleLSK = NULL;                
                }
            iUpdateLskAppearance = ETrue;
            break;
        case XnMenuInterface::MXnMenuInterface::ECenter:
            if(item)
                {
                iVisibleMSK = item;
                }
            else
                {
                iVisibleMSK = NULL;                
                }
            iUpdateMskAppearance = ETrue;
            break;
        case XnMenuInterface::MXnMenuInterface::ERight:
            if(item)
                {
                iVisibleRSK = item;
                }
            else
                {
                iVisibleRSK = NULL;                
                }
            iUpdateRskAppearance = ETrue;
            break;
        }
    }

// -----------------------------------------------------------------------------
// CXnMenuAdapter::SoftKeyL
// 
// -----------------------------------------------------------------------------
//
CXnNodePluginIf* CXnMenuAdapter::SoftKeyL( XnMenuInterface::MXnMenuInterface::TSoftKeyPosition aPos )
    {
    CXnNodePluginIf* node(NULL);
    CXnSoftkeyItem* item = SoftkeyItemL(aPos);
    if(item)
        {
        node = item->iNode;
        }
    return node;
    }

// -----------------------------------------------------------------------------
// CXnMenuAdapter::KeyEventNode
// 
// -----------------------------------------------------------------------------
//
CXnNodePluginIf* CXnMenuAdapter::KeyEventNode()
    {
    return iKeyEventNode;
    }

// -----------------------------------------------------------------------------
// CXnMenuAdapter::HandleScreenDeviceChangedL
// 
// -----------------------------------------------------------------------------
//
void CXnMenuAdapter::HandleScreenDeviceChangedL()
    {
    CXnSoftkeyItem* left = 
        SoftkeyItemL(CEikButtonGroupContainer::ELeftSoftkeyPosition);
    
    CXnSoftkeyItem* middle = 
            SoftkeyItemL(CEikButtonGroupContainer::EMiddleSoftkeyPosition);
    CXnSoftkeyItem* right = 
            SoftkeyItemL(CEikButtonGroupContainer::ERightSoftkeyPosition);
            
    if(left && left->iImageOn)
        {
        iUpdateLskAppearance = ETrue;
        left->iNode->SetDirtyL();
        }
    if(right && right->iImageOn)
        {
        iUpdateRskAppearance = ETrue;
        right->iNode->SetDirtyL();
        }
    if(middle && middle->iImageOn)
        {
        iUpdateMskAppearance = ETrue;
        middle->iNode->SetDirtyL();
        }
    CXnControlAdapter::HandleScreenDeviceChangedL();
    } 
      
// -----------------------------------------------------------------------------
// CXnMenuAdapter::HandleMenuPropertyChangeL
// Change softkey appearance
// -----------------------------------------------------------------------------
//    
void CXnMenuAdapter::HandleMenuPropertyChangeL(CXnNodePluginIf* aNode, CXnProperty* aProperty)
    {
    if ( !aNode || !aProperty )
        {
        return;
        }
           
    const TDesC8& type( aNode->Type()->Type() ); 
    
    if ( type != softkey::KNodeName)
        {
        return;
        }
            
    // Find target softkey
    CXnSoftkeyItem* softkey( SoftkeyItemL( aNode ) );
        
    if ( !softkey )
        {
        return;
        }
    
    SetUpdateAppearanceL( softkey );  
    
    const TDesC8* name( &KNullDesC8() );
    
    if ( aProperty )
        {
        name = &aProperty->Property()->Name();
        }
    
    if ( *name == menu::KLabel )
       {             
       softkey->Reset();
       softkey->iImageOn = EFalse;    
       softkey->iLabel = aProperty->StringValueL();              
       }
    else if ( *name == style::common::KDisplay )
        {        
        if ( aProperty->StringValue() == XnPropertyNames::style::common::display::KNone )
            {
            if ( softkey->iPosition == CEikButtonGroupContainer::ELeftSoftkeyPosition ) 
                {
                EikSoftkeyImage::SetLabel( iContainer,ETrue );
                iContainer->SetCommandL( CEikButtonGroupContainer::ELeftSoftkeyPosition,KCBACommandFirst, KNullDesC );                
                }
            else if ( softkey->iPosition == CEikButtonGroupContainer::ERightSoftkeyPosition )
                {
                EikSoftkeyImage::SetLabel( iContainer,EFalse );
                iContainer->SetCommandL( CEikButtonGroupContainer::ERightSoftkeyPosition,KCBACommandSecond, KNullDesC );                
                }
            else if ( softkey->iPosition == CEikButtonGroupContainer::EMiddleSoftkeyPosition )
                {
                iContainer->SetCommandL( CEikButtonGroupContainer::EMiddleSoftkeyPosition,KCBACommandMiddle, KNullDesC );                
                }
            }
        }
    }    

// -----------------------------------------------------------------------------
// CXnMenuAdapter::SetObserver
// 
// -----------------------------------------------------------------------------
//    
void CXnMenuAdapter::SetObserver( XnMenuInterface::MXnMenuObserver& aObserver )   
    {
    iObserver = &aObserver;
    }

// -----------------------------------------------------------------------------
// CXnMenuAdapter::RemoveObserver
// 
// -----------------------------------------------------------------------------
//    
void CXnMenuAdapter::RemoveObserver()   
    {
    iObserver = NULL;
    }

// ---------------------------------------------------------------------------
// CXnMenuAdapter::FindSoftKeyNodeByPosition
// ---------------------------------------------------------------------------
//
TBool CXnMenuAdapter::FindSoftKeyNodeByPosition( 
    const TPoint& aPosition, 
    CXnNodePluginIf*& aNode )
    {
    CXnNodePluginIf* ret = FindSoftkeyItemByPosition(aPosition);
    aNode = ret;
    return (ret?ETrue:EFalse);
    }
// ---------------------------------------------------------------------------
// CXnMenuAdapter::ButtonTouchableRectByPosition
// Gets a CBA button rectangle. Touchable are is larger than controls rect
// ---------------------------------------------------------------------------
//
TRect CXnMenuAdapter::ButtonTouchableRectByPosition( TInt aPosition)
    {
    TRect rect( 0, 0, 0, 0 );
    
    TRect button1Rect( 0, 0, 0, 0 );
    TRect button2Rect( 0, 0, 0, 0 );
    TRect buttonMSKRect( 0, 0, 0, 0 );
     
    // In touch layouts the button areas are read from the
    // layout data because they are larger than the actual
    // control size.
#ifndef _AVKON_CBA_LSC
    CCoeControl* container = iContainer->ButtonGroup()->AsControl();
    TRect containerRect(container->PositionRelativeToScreen(),container->Size());
    TAknLayoutRect layoutRect;
    layoutRect.LayoutRect(
        containerRect,
        AknLayoutScalable_Avkon::control_pane_g6( 0 ).LayoutLine() );
    button1Rect = layoutRect.Rect();
    
    layoutRect.LayoutRect(
        containerRect,
        AknLayoutScalable_Avkon::control_pane_g8( 0 ).LayoutLine() );
    button2Rect = layoutRect.Rect();

    layoutRect.LayoutRect(
        containerRect,
        AknLayoutScalable_Avkon::control_pane_g7( 0 ).LayoutLine() );
    buttonMSKRect = layoutRect.Rect();
#else           
    if ( Layout_Meta_Data::IsLandscapeOrientation() )
        {
        button1Rect = SoftkeyRectTopTouch();
        button2Rect= SoftkeyRectBottomTouch();
        
        }
    else // portrait
        {
        button1Rect = SoftkeyRectLeftTouch();
        button2Rect = SoftkeyRectRightTouch();
        }
#endif
    
    switch ( aPosition )
        {
        case CEikButtonGroupContainer::ELeftSoftkeyPosition:
            {
            rect = button1Rect;
            break;
            }

        case CEikButtonGroupContainer::ERightSoftkeyPosition:
            {
            rect = button2Rect;
            break;
            }

        case CEikButtonGroupContainer::EMiddleSoftkeyPosition:
            {
            rect = buttonMSKRect;
            break;
            }

        default:
            {
            break;
            }
        }
        
        
    return rect;
    }

// ---------------------------------------------------------------------------
// CXnMenuAdapter::FindSoftkeyNodeL
// ---------------------------------------------------------------------------
//
CXnNodePluginIf* CXnMenuAdapter::FindSoftkeyNodeL(const TDesC8& aNodeType)
    {
    CXnNodePluginIf* ret(0);
    
    RPointerArray< CXnNodePluginIf > children( iRootNode->ChildrenL() );
    CleanupClosePushL( children );
    for(TInt i=0;i<children.Count();++i)
        {
        if(children[i]->Type()->Type() == XnPropertyNames::softkey::KNodeName)
            {
            if( SoftkeyPlaceL(*children[i]) == aNodeType 
                && IsNodeVisibleL( *children[i]) )
                {
                ret = children[i];
                break;
                }
            
            }
        }
    CleanupStack::PopAndDestroy( &children );
    return ret;
    }

// ---------------------------------------------------------------------------
// CXnMenuAdapter::UpdateSoftkeyAppearancesL
// ---------------------------------------------------------------------------
//
void CXnMenuAdapter::UpdateSoftkeyAppearancesL()
    {
    
    if(iUpdateLskAppearance)
        {
        CXnSoftkeyItem* left = 
            SoftkeyItemL(CEikButtonGroupContainer::ELeftSoftkeyPosition);
        if( left )
            {
            SetSoftkeyAppearanceL(*left);
            }
        iUpdateLskAppearance = EFalse;
        }
    if(iUpdateRskAppearance)
        {
        CXnSoftkeyItem* right = 
            SoftkeyItemL(CEikButtonGroupContainer::ERightSoftkeyPosition);
        if(right)
            {
            SetSoftkeyAppearanceL(*right);            
            }
        iUpdateRskAppearance = EFalse;
        }
    if(iUpdateMskAppearance)
        {
        CXnSoftkeyItem* middle = 
            SoftkeyItemL(CEikButtonGroupContainer::EMiddleSoftkeyPosition);
        if(middle)
            {
            SetSoftkeyAppearanceL(*middle);                
            }
        iUpdateMskAppearance = EFalse;
        }
    }
// ---------------------------------------------------------------------------
// CXnMenuAdapter::ChangeSoftkeyImageL
// ---------------------------------------------------------------------------
//
void CXnMenuAdapter::ChangeSoftkeyImageL(const CXnSoftkeyItem& aSoftkey)
    {
    if ( aSoftkey.iPosition == CEikButtonGroupContainer::ELeftSoftkeyPosition || 
            aSoftkey.iPosition == CEikButtonGroupContainer::ERightSoftkeyPosition )
        {
        TSize size;
        if(AknLayoutUtils::PenEnabled())
            {
            size = SoftkeyImageRect(*iContainer,aSoftkey.iPosition).Size();
            }
        else
            {
            size = SoftkeyRectL( *iContainer,aSoftkey.iPosition, aSoftkey.iImageOn ).Size();
            }

        CEikImage* image( PrepareSoftkeyImageL( aSoftkey, size ) );
        TBool left(ETrue);

        if(aSoftkey.iPosition != CEikButtonGroupContainer::ELeftSoftkeyPosition)
            {
            left = EFalse;
            }
        EikSoftkeyImage::SetImage( iContainer, *image, left );
        }
    else if ( aSoftkey.iBmpFile )
        {
        CEikCba* cba = static_cast< CEikCba* >( iContainer->ButtonGroup() );
        // use iAvkonAppUi
        CAknAppUi* appUi = static_cast<CAknAppUi*>( CEikonEnv::Static()->AppUi() );
        cba->UpdateMSKIconL(
                aSoftkey.iId,
                aSoftkey.iBmpFile->Des(),
                aSoftkey.iBmp,
                aSoftkey.iBmpM,
                ETrue );
        }
    }

// ---------------------------------------------------------------------------
// CXnMenuAdapter::AddItemsToMenuPaneL
// ---------------------------------------------------------------------------
//
void CXnMenuAdapter::AddItemsToMenuPaneL(CEikMenuPane* aMenuPane, TInt aResourceId)
    {   
   TInt parentIndexForNotification( 0 );
   
   for ( TInt i = 0; i< iMenuItems.Count(); i++ )
       {
       // find items belong to this pane
       TInt parent( iMenuItems[i].iParentIndex );
       
       if ( parent >= 0 )
           {
           TInt cid( iMenuItems[parent].iData.iCascadeId );
           
           if ( cid == aResourceId )
               {
               if ( parent > 0 )
                   {
                   parentIndexForNotification = parent;
                   break;
                   }
               }
           }
       }
   
   TBool selectionEnabled( EFalse );
   TBool isRadio( EFalse );            
   
   if ( parentIndexForNotification != 0 )
       {
       CXnNodePluginIf* node( iMenuItems[parentIndexForNotification].iNode );
       
       CXnProperty* property( node->GetPropertyL( _L8( "selectiontype" ) ) );
       
       if ( property && property->StringValue() == _L8( "multi" ) )
           {
           selectionEnabled = ETrue;
           }
       else if ( property && property->StringValue() == _L8( "single" ) )
           {
           selectionEnabled = ETrue;
           isRadio = ETrue;
           }
           
       node->SetStateL( XnPropertyNames::style::common::KActive );
       node->UnsetStateL( XnPropertyNames::style::common::KActive );
       }
       
   PopulateMenuL();        
   
   for ( TInt i = 0; i< iMenuItems.Count(); i++ )
       {
       // find items belong to this pane
       TInt parent( iMenuItems[i].iParentIndex );
       
       if ( parent >= 0 )
           {
           TInt cid( iMenuItems[parent].iData.iCascadeId );
           
           if ( cid == aResourceId )
               {
               if ( selectionEnabled )
                   {
                   if ( !isRadio )
                       {
                       iMenuItems[i].iData.iFlags |= 
                           EEikMenuItemCheckBox;
                       }
                   else
                       {
                       iMenuItems[i].iData.iFlags |= 
                           EEikMenuItemRadioStart|
                           EEikMenuItemRadioMiddle|
                           EEikMenuItemRadioEnd;
                       }
                   }
                   
               aMenuPane->AddMenuItemL( iMenuItems[i].iData );
               
               if ( selectionEnabled )
                   {
                   CXnProperty* property( 
                       iMenuItems[i].iNode->GetPropertyL( XnPropertyNames::menu::KChecked ) );                           
                   
                   if ( property && property->StringValue() == XnPropertyNames::KTrue )
                       {
                       aMenuPane->SetItemButtonState(
                           iMenuItems[i].iData.iCommandId, EEikMenuItemSymbolOn );                                         
                       }
                   }
               }
           }
       } // for end      
    }

// ---------------------------------------------------------------------------
// CXnMenuAdapter::AppendSoftkeyItemL
// ---------------------------------------------------------------------------
//
CXnSoftkeyItem* CXnMenuAdapter::AppendSoftkeyItemL(CXnNodePluginIf* aNode)
    {
    if(!aNode)
        {
        return NULL;
        }
    CXnProperty* property = 
        aNode->GetPropertyL( XnPropertyNames::softkey::KTypeAttribute );     
    if(!property)
        {
        return NULL;
        }
    const TDesC8& skType = property->StringValue();
    if( skType != XnPropertyNames::softkey::type::KRight &&
        skType != XnPropertyNames::softkey::type::KLeft &&
        skType != XnPropertyNames::softkey::type::KMiddle )
        {
        return NULL;
        }
    for( TInt i=0; i<iSoftkeyItems.Count(); i++ )
        {
        if( iSoftkeyItems[i]->iNode == aNode )
            {
            return iSoftkeyItems[i];
            }
        }        
    CXnSoftkeyItem* softkey(0);
    softkey = new (ELeave) CXnSoftkeyItem;
    CleanupStack::PushL(softkey);
    
    if ( skType == XnPropertyNames::softkey::type::KRight )
       {
       softkey->iPosition = CEikButtonGroupContainer::ERightSoftkeyPosition;
       softkey->iCommandId = KCBACommandSecond;
       }
    else if ( skType == XnPropertyNames::softkey::type::KLeft )
       {
       softkey->iPosition = CEikButtonGroupContainer::ELeftSoftkeyPosition;
       softkey->iCommandId = KCBACommandFirst;
       }
    else 
        {
        softkey->iPosition = CEikButtonGroupContainer::EMiddleSoftkeyPosition;
        softkey->iCommandId = KCBACommandMiddle;
        }

    softkey->iNode = aNode;
    
    CXnProperty* labelProp( aNode->LabelL() );
    CXnProperty* targetProp( aNode->GetPropertyL(KXnTarget) );

    if(labelProp)
       {
       softkey->iImageOn = EFalse;
       softkey->iLabel = labelProp->StringValueL();
       }
    else if(targetProp)
        {
        softkey->iImageOn = EFalse;
        softkey->iLabel = FindSoftkeyLabelL(aNode);        
        }
    else
       {
       InitSoftkeyItemImageL( *softkey );
       }

    softkey->iUpdateAppearance = ETrue;
    iSoftkeyItems.AppendL(softkey);
    CleanupStack::Pop(softkey);
    return softkey;
    }
// ---------------------------------------------------------------------------
// CXnMenuAdapter::SoftkeyPlaceL
// ---------------------------------------------------------------------------
//
const TDesC8& CXnMenuAdapter::SoftkeyPlaceL(CXnNodePluginIf& aNode)
    {
    CXnProperty* property = 
        aNode.GetPropertyL( XnPropertyNames::softkey::KTypeAttribute );                           
                      
    if( property)
        {
        return property->StringValue();
        }
    return KNullDesC8;                  
    
    }

// -----------------------------------------------------------------------------
// CXnMenuAdapter::FindSoftkeyItemByPosition
// 
// -----------------------------------------------------------------------------
CXnNodePluginIf* CXnMenuAdapter::FindSoftkeyItemByPosition( const TPoint& aPosition )
    {
    CXnNodePluginIf* softkey(0);            
    TRAP_IGNORE( softkey = DoFindSoftkeyItemByPositionL( aPosition ) );    
    return softkey;
    }
    
// -----------------------------------------------------------------------------
// CXnMenuAdapter::DoFindSoftkeyItemByPositionL
// 
// -----------------------------------------------------------------------------
CXnNodePluginIf* CXnMenuAdapter::DoFindSoftkeyItemByPositionL( const TPoint& aPosition )
    {            
    TRect lsk( ButtonTouchableRectByPosition(CEikButtonGroupContainer::ELeftSoftkeyPosition) );
    TRect rsk( ButtonTouchableRectByPosition(CEikButtonGroupContainer::ERightSoftkeyPosition) );
    TRect msk( ButtonTouchableRectByPosition(CEikButtonGroupContainer::EMiddleSoftkeyPosition) );
    
    CXnNodePluginIf* softkey(NULL);
    CXnSoftkeyItem* item(NULL);
    if ( lsk.Contains(aPosition) )
        {
        item = SoftkeyItemL(CEikButtonGroupContainer::ELeftSoftkeyPosition);
        }
    else if(msk.Contains(aPosition))
        {
        item = SoftkeyItemL(CEikButtonGroupContainer::EMiddleSoftkeyPosition);
        }
    else if( rsk.Contains(aPosition) )
        {
        item = SoftkeyItemL(CEikButtonGroupContainer::ERightSoftkeyPosition);
        }
    if(item)
        {
        softkey = item->iNode;
        }        
    return softkey;
    }

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
CXnSoftkeyItem* CXnMenuAdapter::SoftkeyItemL(TInt aPosition)
    {
    CXnSoftkeyItem* softkeyItem(0);
    if(iVisibleLSK && aPosition == CEikButtonGroupContainer::ELeftSoftkeyPosition)
        {
        return iVisibleLSK;
        }
    else if(iVisibleRSK && aPosition == CEikButtonGroupContainer::ERightSoftkeyPosition)
        {
        return iVisibleRSK;
        }
    else if(iVisibleMSK && aPosition == CEikButtonGroupContainer::EMiddleSoftkeyPosition)
        {
        return iVisibleMSK;
        }

    // return default
    for(TInt i=0;i<iSoftkeyItems.Count();++i)
        {
        softkeyItem = iSoftkeyItems[i];
        if(softkeyItem->iPosition == aPosition &&
           softkeyItem->iDefault && 
           IsNodeVisibleL(*softkeyItem->iNode))
            {
            return softkeyItem; 
            }
        }
    return NULL;
    }

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
CXnSoftkeyItem* CXnMenuAdapter::SoftkeyItemL(CXnNodePluginIf* aNode)
    {
    CXnSoftkeyItem* softkeyItem(0);
    for(TInt i=0;i<iSoftkeyItems.Count();++i)
       {
       softkeyItem = iSoftkeyItems[i];
       if(softkeyItem->iNode == aNode)
           {
           return softkeyItem; 
           }
       }
    return NULL;
    }

CXnSoftkeyItem* CXnMenuAdapter::SoftkeyItemL(CXnNodeAppIf* aNode)
    {
    CXnSoftkeyItem* softkeyItem(0);
    for(TInt i=0;i<iSoftkeyItems.Count();++i)
       {
       softkeyItem = iSoftkeyItems[i];
       if(&(softkeyItem->iNode->AppIfL()) == aNode)
           {
           return softkeyItem; 
           }
       }
    return NULL;
    }
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

void CXnMenuAdapter::SetUpdateAppearanceL(CXnSoftkeyItem* aItem)
    {
    if ( aItem && IsNodeVisibleL( *aItem->iNode ) )
        {
        aItem->iNode->SetDirtyL();
                
        switch ( aItem->iPosition )
            {
            case CEikButtonGroupContainer::ELeftSoftkeyPosition:
                iUpdateLskAppearance = ETrue;
                iVisibleLSK = NULL;
                break;
            case CEikButtonGroupContainer::EMiddleSoftkeyPosition:
                iUpdateMskAppearance = ETrue;
                iVisibleMSK = NULL;
                break;
            case CEikButtonGroupContainer::ERightSoftkeyPosition:
                iUpdateRskAppearance = ETrue;
                iVisibleRSK = NULL;
                break;
            }
        }
    }

// -----------------------------------------------------------------------------
// CXnMenuAdapter::FindWidgetMenuItemL
// 
// -----------------------------------------------------------------------------
CXnNodePluginIf* CXnMenuAdapter::FindWidgetMenuItemL( CXnNodePluginIf* aNode )
    {    
    CXnNodePluginIf* focusedNode( iUiEngine->FocusedNodeL() );

    CXnNodePluginIf* menuItem( NULL );
    
    if ( focusedNode && aNode )
        {
        // Get <plugin> element
        CXnNodePluginIf& pluginNode( iUiEngine->PluginNodeL( focusedNode ) );
        
        CXnNodePluginIf* widget( FindWidgetElementL( pluginNode ) );
                
        CXnNodePluginIf* widgetExtNode( NULL );
        
        if( widget )
            {            
            widgetExtNode = FindChildL( *widget, KXnMenuExtension );
            }
                                                 
        if( !widgetExtNode )
            {
            widgetExtNode = focusedNode;
            }
        
        if ( widgetExtNode )
            {
            CXnProperty* prop( aNode->GetPropertyL( KXnSource ) );
            
            if ( prop )
                {
                const TDesC8& source( prop->StringValue() );
                
                // Try to find <menuitem>
                menuItem = FindChildL( *widgetExtNode, 
                                       KXnMenuItem, 
                                       source );
                
                if ( !menuItem )
                    {
                    // Try to find <dynmenuitem>
                    menuItem = FindChildL( *widgetExtNode, 
                                           KXnDynMenuItem, 
                                           source );
                    }
                }
            }                
        }
    
    if( menuItem && IsNodeVisibleL( *menuItem ) )
        {
        return menuItem;    
        }
    
    return NULL;
    }

// -----------------------------------------------------------------------------
// CXnMenuAdapter::FindSoftkeyLabelL
// 
// -----------------------------------------------------------------------------
HBufC* CXnMenuAdapter::FindSoftkeyLabelL( CXnNodePluginIf* aNode )
    {
    if( !aNode )
        {
        return NULL;
        }
    
    CXnProperty* targerProp( aNode->GetPropertyL( KXnTarget ) );
    
    if ( targerProp && iRootNode )
        {
        CXnNodePluginIf* widgetSoftkeyNode( 
                FindChildL( *iRootNode,               
                            KXnWidgetSoftkey, 
                            targerProp->StringValue() ) ); 
                          
        if ( widgetSoftkeyNode )
            {
            CXnProperty* label( widgetSoftkeyNode->LabelL() );
            
            if( label )
                {
                return label->StringValueL();
                }
            }
        }
    
    return NULL;;
    }

//end of file
