idlehomescreen/xmluirendering/uiengine/src/xnkeyeventdispatcher.cpp
changeset 0 f72a12da539e
child 1 5315654608de
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/idlehomescreen/xmluirendering/uiengine/src/xnkeyeventdispatcher.cpp	Thu Dec 17 08:40:49 2009 +0200
@@ -0,0 +1,724 @@
+/*
+* 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:  Event dispatcher
+*
+*/
+
+// System includes
+#include <AknUtils.h>
+
+// User includes
+#include "xnappuiadapter.h"
+#include "xnfocuscontrol.h"
+#include "xnkeyeventdispatcher.h"
+#include "xntype.h"
+#include "xncomponentnodeimpl.h"
+#include "xnproperty.h"
+#include "xnuiengine.h"
+#include "xnodt.h"
+#include "xndomdocument.h"
+#include "xndomnode.h"
+#include "xnmenuadapter.h"
+#include "xneditmode.h"
+#include "xnviewmanager.h"
+#include "xnviewdata.h"
+#include "xnnode.h"
+
+// Local macros
+#define IS_ARROW_KEY( k ) \
+    ( k == EStdKeyLeftArrow || k == EStdKeyRightArrow || \
+      k == EStdKeyUpArrow || k == EStdKeyDownArrow ) 
+
+// -----------------------------------------------------------------------------
+// SetInitialFocusL
+// -----------------------------------------------------------------------------
+//
+static void SetInitialFocusL( RPointerArray< CXnNode >& aArray )
+    {
+    for ( TInt i = 0; i < aArray.Count(); i++ )
+        {
+        CXnNode* node( aArray[i] );
+
+        node->SetStateWithoutNotificationL(
+            XnPropertyNames::style::common::KFocus );
+
+        if ( node->IsStateSet( XnPropertyNames::style::common::KFocus ) )
+            {
+            break;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// BuildTriggerNodeL
+// Builds a trigger node
+// -----------------------------------------------------------------------------
+//
+static CXnNode* BuildTriggerNodeL(
+    CXnUiEngine& aUiEngine,
+    const TDesC8& aTriggerName )
+    {
+    CXnNode* node = CXnNode::NewL();
+    CleanupStack::PushL( node );
+
+    CXnType* type = CXnType::NewL( XnPropertyNames::action::KTrigger );
+    CleanupStack::PushL( type );
+
+    CXnNodeImpl* impl = CXnNodeImpl::NewL( type );
+
+    CleanupStack::Pop( type );
+
+    node->SetImpl( impl );
+    node->SetUiEngine( aUiEngine );
+
+    CXnDomPropertyValue* nameValue =
+        CXnDomPropertyValue::NewL( aUiEngine.ODT()->DomDocument().StringPool() );
+
+    CleanupStack::PushL( nameValue );
+
+    nameValue->SetStringValueL( CXnDomPropertyValue::EString, aTriggerName );
+
+    CXnProperty* name =
+        CXnProperty::NewL( XnPropertyNames::action::trigger::KName, nameValue,
+                           aUiEngine.ODT()->DomDocument().StringPool() );
+
+    CleanupStack::Pop( nameValue );
+    CleanupStack::PushL( name );
+    node->SetPropertyL( name );
+    CleanupStack::Pop( name );
+
+    CleanupStack::Pop( node );
+
+    return node;
+    }
+
+// -----------------------------------------------------------------------------
+// MenuAdapter
+// Gets menuadapter from node, NULL if not available
+// -----------------------------------------------------------------------------
+//
+static CXnMenuAdapter* MenuAdapter( CXnNode* aNode )
+    {
+    if ( aNode )
+        {        
+        return static_cast< CXnMenuAdapter* >( aNode->Control() );
+        }
+
+    return NULL;
+    }
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CXnKeyEventDispatcher::NewL
+// Two-phased constructor. Can leave.
+// -----------------------------------------------------------------------------
+//
+CXnKeyEventDispatcher* CXnKeyEventDispatcher::NewL( CXnUiEngine& aUiEngine )
+    {
+    CXnKeyEventDispatcher* self = new ( ELeave ) CXnKeyEventDispatcher( aUiEngine );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop();
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CXnKeyEventDispatcher::~CXnKeyEventDispatcher
+// Destructor.
+// -----------------------------------------------------------------------------
+//
+CXnKeyEventDispatcher::~CXnKeyEventDispatcher()
+    {
+    iCoeEnv->RemoveMessageMonitorObserver( *this );
+    
+    iUiEngine.ViewManager()->RemoveObserver( *this );
+    
+    delete iLoseFocus;
+    delete iGainFocus;
+    iPassiveFocusedNodes.Reset();
+    }
+
+// -----------------------------------------------------------------------------
+// CXnKeyEventDispatcher::CXnKeyEventDispatcher
+// C++ default constructor. Must not leave.
+// -----------------------------------------------------------------------------
+//
+CXnKeyEventDispatcher::CXnKeyEventDispatcher( CXnUiEngine& aUiEngine )
+    : iUiEngine( aUiEngine )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CXnKeyEventDispatcher::ConstructL
+// 2nd phase constructor. Can leave.
+// -----------------------------------------------------------------------------
+//
+void CXnKeyEventDispatcher::ConstructL()
+    {
+    MakeVisible( EFalse );
+
+    iUiEngine.ViewManager()->AddObserver( *this );
+           
+    iCoeEnv->AddMessageMonitorObserverL( *this );    
+    }
+
+// -----------------------------------------------------------------------------
+// CXnKeyEventDispatcher::MonitorWsMessage
+// 
+// -----------------------------------------------------------------------------
+//
+void CXnKeyEventDispatcher::MonitorWsMessage( const TWsEvent& aEvent )
+    {
+    TInt type( aEvent.Type() );
+    
+    if ( type == EEventPointer && AknLayoutUtils::PenEnabled() )
+        {    
+        const TUint handle( aEvent.Handle() );
+        
+        CCoeControl* destination = reinterpret_cast< CCoeControl* >( handle );        
+                                       
+        TPointerEvent& event( *aEvent.Pointer() );
+                
+        if ( iCbaContainer )
+            {
+            CEikCba* cba = 
+                static_cast< CEikCba* >( iCbaContainer->ButtonGroup() ); 
+                    
+            if ( destination == cba && iCbaContainer->IsVisible() )
+                {
+                CXnMenuAdapter* adapter( MenuAdapter( iMenuNode ) );
+                
+                if ( adapter )
+                    {
+                    TRAP_IGNORE( 
+                        adapter->HandlePointerEventL( *aEvent.Pointer() ) );
+                    }
+                }
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CXnKeyEventDispatcher::OfferKeyEventL
+// Handles key events.
+// -----------------------------------------------------------------------------
+//
+TKeyResponse CXnKeyEventDispatcher::OfferKeyEventL(
+    const TKeyEvent& aKeyEvent,
+    TEventCode aType )
+    {
+    TKeyResponse resp( EKeyWasNotConsumed );
+    
+    iEventCode = aType;
+    
+    CXnNode* node( NULL );
+    
+    TBool keyYesNoApps( EFalse );
+    
+    if ( iUiEngine.IsMenuDisplaying() ||
+         aKeyEvent.iScanCode == EStdKeyDevice0 ||
+         aKeyEvent.iScanCode == EStdKeyDevice1 )
+        {
+        iFocusChanged = EFalse;
+        // When menu is focused or LSK/RSK is pressed,
+        // then forward events to menuadapter.
+        // Note that MSK is handled directly in the base class as it used only
+        // for activating
+        node = iMenuNode;
+        }
+    else if ( aKeyEvent.iScanCode == EStdKeyApplication0 ||
+              aKeyEvent.iScanCode == EStdKeyYes ||
+              aKeyEvent.iScanCode == EStdKeyNo )
+        {
+        keyYesNoApps = ETrue;
+        
+        iFocusChanged = EFalse;
+        // AppsKey, YesKey, NoKey events must be always handled, and if we don't
+        // have a focused node, then let the view node do the job
+        node = ( !iNode ) ? iUiEngine.ActiveView() : iNode;
+        }
+    else
+        {
+        CXnAppUiAdapter& appui( iUiEngine.AppUiAdapter() );
+        
+        if ( IS_ARROW_KEY( aKeyEvent.iScanCode ) && aType == EEventKey )
+            {
+            if ( !appui.FocusShown() )
+                {
+                appui.ShowFocus();
+                
+                if ( !iNode )
+                    {
+                    // Find initial location for focus
+                    ResolveAndSetFocusL(); 
+                                            
+                    return EKeyWasConsumed;
+                    }
+                }
+            }
+        
+        CCoeControl* editmode( iUiEngine.EditMode() );
+        
+        if ( editmode->OfferKeyEventL( aKeyEvent, aType ) == EKeyWasConsumed )
+            {
+            return EKeyWasConsumed;
+            }
+        
+        // Offer keyevent to the focused node        
+        node = iNode;
+
+        if ( aType == EEventKeyDown )
+            {
+            // Reset state
+            iFocusChanged = EFalse;
+            iKeyEventNode = iNode;
+            }
+
+        if ( iFocusChanged && ( aType == EEventKeyUp ) )
+            {
+            // Pass keyup event to
+            // previously focused node
+            node = iKeyEventNode;
+            }
+        }
+
+    if ( !keyYesNoApps )
+        {
+        if ( iEventCode == EEventNull && aType != EEventKeyDown )
+            {    
+            // We are waiting for down event
+            return resp;
+            }        
+        }
+        
+    if ( !node )
+        {
+        return resp;
+        }
+
+    iUiEngine.DisableRenderUiLC();
+    
+    CXnControlAdapter* adapter( node->Control() );
+
+    if( adapter && adapter->IsVisible() )                            
+        {
+        resp = adapter->OfferKeyEventL( aKeyEvent, aType );
+        }
+
+    if ( aType != EEventKeyUp && iKeyEventNode != iNode )
+        {
+        // Focused node is changed during keyevent
+        iFocusChanged = ETrue;
+        }
+    
+    if ( aType == EEventKeyUp )
+        {
+        iEventCode = EEventNull;
+        }
+
+    iUiEngine.RenderUIL();
+    CleanupStack::PopAndDestroy(); // DisableRenderUiLC
+    
+    return resp;
+    }
+
+// -----------------------------------------------------------------------------
+// CXnKeyEventDispatcher::SetNode
+// -----------------------------------------------------------------------------
+//
+void CXnKeyEventDispatcher::SetNodeL( CXnNode* aNode, TInt aSource )
+    {
+    if ( iNode == aNode )
+        {
+        return;
+        }
+
+    iPreviousNode = iNode;
+    iNode = aNode;
+
+    SetNodeL( iPreviousNode, iNode, ETrue, aSource );
+    }
+
+// -----------------------------------------------------------------------------
+// CXnKeyEventDispatcher::SetNodeWithoutNotificationL
+// -----------------------------------------------------------------------------
+//
+void CXnKeyEventDispatcher::SetNodeWithoutNotificationL( CXnNode* aNode )
+    {
+    if ( iNode == aNode )
+        {
+        return;
+        }
+
+    iPreviousNode = iNode;
+    iNode = aNode;
+
+    SetNodeL( iPreviousNode, iNode, EFalse );
+    }
+
+// -----------------------------------------------------------------------------
+// SetNodeL
+// Changes focused node, runs gain focus/lose focus triggers if needed
+// -----------------------------------------------------------------------------
+//
+void CXnKeyEventDispatcher::SetNodeL( CXnNode* aToLose, CXnNode* aToGain,
+    TBool aNotify, TInt aSource )
+    {
+    if ( aToLose )
+        {
+        aToLose->SetDirtyL( XnDirtyLevel::ERender );
+
+        aToLose->UnsetStateL( XnPropertyNames::style::common::KFocus );
+        aToLose->UnsetStateL( XnPropertyNames::style::common::KHold );
+        aToLose->UnsetStateL( XnPropertyNames::style::common::KActive );
+
+        if ( aNotify )
+            {
+            if ( !iLoseFocus )
+                {
+                iLoseFocus = BuildTriggerNodeL( iUiEngine,
+                    XnPropertyNames::action::trigger::name::KLoseFocus );
+                }
+
+            aToLose->ReportXuikonEventL( *iLoseFocus );
+            }
+
+        CXnControlAdapter* adapter( aToLose->Control() );
+
+        if ( adapter )
+            {
+            adapter->SetFocus( EFalse );
+            }
+        }
+
+    if ( aToGain )
+        {
+        aToGain->SetDirtyL( XnDirtyLevel::ERender );
+
+        if ( aNotify )
+            {
+            if ( !iGainFocus )
+                {
+                iGainFocus = BuildTriggerNodeL( iUiEngine,
+                        XnPropertyNames::action::trigger::name::KGainFocus );
+                }
+
+            aToGain->ReportXuikonEventL( *iGainFocus, aSource );
+            }
+
+        CXnControlAdapter* adapter( aToGain->Control() );
+
+        if ( adapter )
+            {
+            adapter->SetFocus( ETrue );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CXnKeyEventDispatcher::FocusedNode
+// -----------------------------------------------------------------------------
+//
+CXnNode* CXnKeyEventDispatcher::FocusedNode() const
+    {
+    if ( iNode && iNode->IsStateSet( XnPropertyNames::style::common::KFocus ) )
+        {
+        return iNode;
+        }
+
+    return NULL;
+    }
+
+// -----------------------------------------------------------------------------
+// CXnKeyEventDispatcher::RefreshMenu
+// -----------------------------------------------------------------------------
+//
+void CXnKeyEventDispatcher::RefreshMenuL()
+    {
+    CXnMenuAdapter* menuAdapter( MenuAdapter( iMenuNode ) );
+
+    if ( menuAdapter )
+        {
+        menuAdapter->SetContainerL( *iCbaContainer );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CXnKeyEventDispatcher::SetMenuNode
+// -----------------------------------------------------------------------------
+//
+void CXnKeyEventDispatcher::SetMenuNodeL( CXnNode* aNode )
+    {
+    CXnMenuAdapter* menuAdapter( MenuAdapter( aNode ) );
+    
+    iCbaContainer = iAvkonAppUi->Cba();
+
+    if ( menuAdapter )
+        {
+        iMenuNode = aNode;
+                
+        menuAdapter->SetContainerL( *iCbaContainer );
+
+        CXnProperty* prop( iMenuNode->DisplayL() );
+
+        if ( prop && prop->StringValue() == 
+            XnPropertyNames::style::common::display::KNone )
+            {
+            iCbaContainer->MakeVisible( EFalse );
+            }
+        else
+            {
+            iCbaContainer->MakeVisible( ETrue );
+            }
+        }
+    else
+        {
+        iCbaContainer->MakeVisible( EFalse );
+
+        // The node passed in wasn't a valid menu node
+        ResetMenuNodeL();
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CXnKeyEventDispatcher::ResetMenuNodeL
+// -----------------------------------------------------------------------------
+//
+void CXnKeyEventDispatcher::ResetMenuNodeL()
+    {
+    iMenuNode = NULL;
+
+    iCbaContainer = NULL;
+    }
+
+// -----------------------------------------------------------------------------
+// CXnKeyEventDispatcher::IsMenuFocused
+// -----------------------------------------------------------------------------
+//
+TBool CXnKeyEventDispatcher::IsMenuFocused() const
+    {
+    CXnMenuAdapter* menuAdapter( MenuAdapter( iMenuNode ) );
+
+    if ( menuAdapter )
+        {
+        return menuAdapter->IsMenuFocused();
+        }
+
+    return EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CXnKeyEventDispatcher::AddPassiveFocusedNode
+// -----------------------------------------------------------------------------
+//
+void CXnKeyEventDispatcher::AddPassiveFocusedNodeL( CXnNode* aNode )
+    {
+    if ( !aNode->IsStateSet( XnPropertyNames::style::common::KFocus ) &&
+         !aNode->IsStateSet( XnPropertyNames::style::common::KPassiveFocus ) )
+        {
+        iPassiveFocusedNodes.AppendL( aNode );
+        aNode->SetStateL( XnPropertyNames::style::common::KPassiveFocus );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CXnKeyEventDispatcher::RemovePassiveFocusedNode
+// -----------------------------------------------------------------------------
+//
+void CXnKeyEventDispatcher::RemovePassiveFocusedNodeL( CXnNode* aNode )
+    {
+    for ( TInt i = 0; i < iPassiveFocusedNodes.Count(); i++ )
+        {
+        CXnNode* node( iPassiveFocusedNodes[i] );
+
+        if ( node == aNode )
+            {
+            iPassiveFocusedNodes.Remove( i );
+            
+            aNode->UnsetStateL( 
+                    XnPropertyNames::style::common::KPassiveFocus );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CXnKeyEventDispatcher::AddPassiveFocusedNode
+// -----------------------------------------------------------------------------
+//
+void CXnKeyEventDispatcher::ClearPassiveFocusedNodesL()
+    {
+    for ( TInt i = 0; i < iPassiveFocusedNodes.Count(); i++ )
+        {
+        iPassiveFocusedNodes[i]->UnsetStateL(
+            XnPropertyNames::style::common::KPassiveFocus );
+        }
+
+    iPassiveFocusedNodes.Reset();
+    }
+
+// -----------------------------------------------------------------------------
+// CXnKeyEventDispatcher::NotifyViewActivatedL
+// -----------------------------------------------------------------------------
+//
+void CXnKeyEventDispatcher::NotifyViewActivatedL(
+    const CXnViewData& /*aViewData*/ )
+    {    
+    }
+
+// -----------------------------------------------------------------------------
+// CXnKeyEventDispatcher::NotifyViewDeactivatedL
+// -----------------------------------------------------------------------------
+//
+void CXnKeyEventDispatcher::NotifyViewDeactivatedL(
+    const CXnViewData& /*aViewData*/ )
+    {    
+    iMenuNode = NULL;
+    ClearPassiveFocusedNodesL();
+    ClearStateL();
+    
+    iUiEngine.AppUiAdapter().HideFocus();
+    }
+
+// -----------------------------------------------------------------------------
+// CXnKeyEventDispatcher::NotifyWidgetAdditionL
+// -----------------------------------------------------------------------------
+//
+void CXnKeyEventDispatcher::NotifyWidgetAdditionL(
+    const CXnPluginData& aPluginData )
+    {
+    if ( aPluginData.Active() )
+        {               
+        iUiEngine.AppUiAdapter().ShowFocus();
+        
+        RPointerArray< CXnNode > initial;
+        CleanupClosePushL( initial );
+        
+        if ( iUiEngine.IsEditMode() )
+            {
+            initial.AppendL( aPluginData.Owner()->LayoutNode() );
+            }
+        else
+            {
+            aPluginData.InitialFocusNodesL( initial );
+            }
+        
+        SetInitialFocusL( initial );
+        
+        CleanupStack::PopAndDestroy( &initial );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CXnKeyEventDispatcher::NotifyWidgetRemovalL
+// -----------------------------------------------------------------------------
+//
+void CXnKeyEventDispatcher::NotifyWidgetRemovalL(
+    const CXnPluginData& aPluginData )
+    {
+    if ( aPluginData.Active() )
+        {
+        ClearPassiveFocusedNodesL();
+
+        if ( iNode )
+            {                              
+            CXnViewData& activeViewData(
+                iUiEngine.ViewManager()->ActiveViewData() );
+    
+            const CXnPluginData& pluginData(
+                activeViewData.Plugin( iNode ) );
+    
+            if ( &pluginData == &aPluginData )
+                {
+                // The plugin is removed which was holding focus
+                ClearStateL();
+                }
+            }
+        }    
+    }
+
+// -----------------------------------------------------------------------------
+// CCXnKeyEventDispatcher::NotifyConfigureWidgetL
+// -----------------------------------------------------------------------------
+//
+void CXnKeyEventDispatcher::NotifyConfigureWidgetL( 
+    const CHsContentInfo& /*aContentInfo*/, CXnPluginData& /*aPluginData*/ )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CXnKeyEventDispatcher::ResolveAndSetFocusL
+// Used to bring focus visible in the initial location when focus is invisible
+// -----------------------------------------------------------------------------
+//
+void CXnKeyEventDispatcher::ResolveAndSetFocusL() 
+    {
+    // <plugin> elements are always kept in appearance order
+    RPointerArray< CXnNode >& list( *iUiEngine.Plugins() );
+    
+    if ( iUiEngine.IsEditMode() )
+        {               
+        SetInitialFocusL( list );        
+        }
+    else
+        {
+        RPointerArray< CXnNode > initial;
+        CleanupClosePushL( initial );
+        
+        CXnViewData& activeView( iUiEngine.ViewManager()->ActiveViewData() );
+
+        // first, search only in plugins which have popup window open
+        for ( TInt i = 0; i < list.Count(); i++ )
+            {
+            CXnPluginData& plugin( activeView.Plugin( list[i] ) );
+            if ( plugin.IsDisplayingPopup() )
+                {
+                plugin.InitialFocusNodesL( initial );
+                }
+            }
+        
+        // if no inital focus nodes were found in plugins with
+        // open popups, search again with all plugins
+        if ( initial.Count() == 0 )
+            {        
+            for ( TInt i = 0; i < list.Count(); i++ )
+                {
+                CXnPluginData& plugin( activeView.Plugin( list[i] ) );
+                plugin.InitialFocusNodesL( initial );
+                }
+            }
+        
+        // set initial focus
+        SetInitialFocusL( initial );
+        
+        CleanupStack::PopAndDestroy( &initial );        
+        }    
+    }
+
+// -----------------------------------------------------------------------------
+// CXnKeyEventDispatcher::ClearStateL
+// -----------------------------------------------------------------------------
+//
+void CXnKeyEventDispatcher::ClearStateL()
+    {
+    SetNodeL( NULL );
+    
+    iNode = NULL;
+    iPreviousNode = NULL;
+    iKeyEventNode = NULL;
+    iFocusChanged = EFalse;
+    iEventCode = EEventNull;
+    }
+
+// End of file