diff -r 000000000000 -r f72a12da539e idlehomescreen/xmluirendering/uiengine/src/xnkeyeventdispatcher.cpp --- /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 + +// 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() + { + // 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