diff -r 000000000000 -r 15bf7259bb7c uiacceltk/hitchcock/Client/src/alfroster.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uiacceltk/hitchcock/Client/src/alfroster.cpp Tue Feb 02 07:56:43 2010 +0200 @@ -0,0 +1,807 @@ +/* +* Copyright (c) 2006 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: Roster. +* +*/ + + + +#include "alf/alfroster.h" +#include "alf/alfdisplay.h" +#include "alf/alfcontrolgroup.h" +#include "alf/alfcontrol.h" +#include "alf/alfenv.h" +#include "alfclient.h" +#include "alf/alfevent.h" +#include "alflogger.h" +#include "alfpanic.h" + +#include + +// Private data + +struct CAlfRoster::TPrivateData + { + CAlfDisplay* iDisplay; // Not owned. + RPointerArray iEntries; // Not owned. Kept in order. + CAlfControl* iInputFocus; // Not owned. + RPointerArray iControlGroupOrderChangedObservers; // Not owned. + }; + + +// ======== MEMBER FUNCTIONS ======== + +// --------------------------------------------------------------------------- +// Constructor +// --------------------------------------------------------------------------- +// +CAlfRoster::CAlfRoster() + { + } + + +// --------------------------------------------------------------------------- +// ConstructL +// --------------------------------------------------------------------------- +// +void CAlfRoster::ConstructL(CAlfDisplay* aDisplay) + { + iData = new (ELeave) TPrivateData; + iData->iDisplay = aDisplay; + iData->iInputFocus = NULL; + } + +// --------------------------------------------------------------------------- +// Destructor +// --------------------------------------------------------------------------- +// +CAlfRoster::~CAlfRoster() + { + if ( iData ) + { + iData->iEntries.Close(); + iData->iControlGroupOrderChangedObservers.Close(); + } + + delete iData; + iData = NULL; + } + + +// --------------------------------------------------------------------------- +// Shows given control group. +// --------------------------------------------------------------------------- +// +EXPORT_C void CAlfRoster::ShowL(CAlfControlGroup& aGroup, TInt aWhere ) + { + // If the group is already shown on the display, just adjust its + // position according to the parameters. + if(Find(aGroup) != KErrNotFound) + { + // It is already shown. Only adjust position. + TInt newPos = aWhere; + if(newPos == KAlfRosterShowAtTop) + { + newPos = Count() - 1; + } + else if(newPos == KAlfRosterShowAtBottom) + { + newPos = 0; + } + else + { + // for PC lint + } + + // Move the control group to a new position in the roster. + const TBool lWasMoved = Move(aGroup, newPos); + + // Move on the server side + iData->iDisplay->Env().Client().RosterShow( + aGroup.Identifier(), + aWhere, + iData->iDisplay->ServerHandle() ); + + //fix for bug "ESMA-7L3H7F". Notification is moved from Move() to here. + // Notify control group order changed observers about changed control group order + + if(lWasMoved) + { + NotifyControlGroupOrderChangedObservers(); + } + + return; + } + + if(aWhere == KAlfRosterShowAtTop) + { + // Put the group on top of the roster. + AppendL(aGroup); + } + else if(aWhere == KAlfRosterShowAtBottom) + { + InsertL(aGroup, 0); + } + else + { + InsertL(aGroup, aWhere); + } + + + // The group will automatically accept input events once shown. + aGroup.SetAcceptInput(ETrue); + + // Show all the controls of the group. + for(TInt i = 0; i < aGroup.Count(); ++i) + { + aGroup.Control(i).ShowL(*iData->iDisplay); + } + + // Bind the control group to the correct display. + aGroup.BindDisplay(iData->iDisplay); + + // Show on the server side + TInt err = + iData->iDisplay->Env().Client().RosterShow( + aGroup.Identifier(), + aWhere, + iData->iDisplay->ServerHandle() ); + + // hide on error + if ( err != KErrNone ) + { + // There is no window group ID if we are not running this from a + // Symbian application. Therefore the roster::show returns an error. + // -> only concider this to be an error if the CCoeEnv is present. + if ( err == KErrNotFound && !CCoeEnv::Static() ) + { + __ALFLOGSTRING1( "CAlfRoster::ShowL ignore error %d (no CCoeEnv)", err ) + return; + } + + // Hide all the controls of the group. + for(TInt i = 0; i < aGroup.Count(); ++i) + { + aGroup.Control(i).Hide(*iData->iDisplay); + } + + // Unbind the control group from the display. + aGroup.BindDisplay(NULL); + + __ALFLOGSTRING1( "CAlfRoster::ShowL leave error %d", err ) + User::Leave( err ); + } + + // Notify control group order changed observers about changed control group order + NotifyControlGroupOrderChangedObservers(); + } + +// --------------------------------------------------------------------------- +// Hides given control group +// --------------------------------------------------------------------------- +// +EXPORT_C void CAlfRoster::Hide(CAlfControlGroup& aGroup) + { + // Hide on the server side + TInt err = + iData->iDisplay->Env().Client().RosterHide( + aGroup.Identifier(), + iData->iDisplay->ServerHandle() ); + + if ( err != KErrNone ) + { + __ALFLOGSTRING1( "CAlfRoster::Hide panic error %d", err ) + USER_INVARIANT(); + } + + // Hide all the controls of the group. + for(TInt i = 0; i < aGroup.Count(); ++i) + { + aGroup.Control(i).Hide(*iData->iDisplay); + } + + // Unbind the control group from the display. + aGroup.BindDisplay(NULL); + + // Investigate whether control group was shown + TBool wasShown = (Find(aGroup) == KErrNotFound) ? EFalse : ETrue; + + Remove(&aGroup); + + // Notify control group order changed observers about changed control group order + // if control group was shown before. + if(wasShown) + { + NotifyControlGroupOrderChangedObservers(); + } + } + +// --------------------------------------------------------------------------- +// Returns index of the given group +// --------------------------------------------------------------------------- +// +EXPORT_C TInt CAlfRoster::Find(const CAlfControlGroup& aGroup) const + { + return iData->iEntries.Find( &aGroup ); + } + +// --------------------------------------------------------------------------- +// Removes group +// --------------------------------------------------------------------------- +// +void CAlfRoster::Remove(CAlfControlGroup* aGroup) + { + if ( aGroup ) + { + TInt index = Find(*aGroup); + if(index != KErrNotFound) + { + iData->iEntries.Remove(index); + } + } + } + +// --------------------------------------------------------------------------- +// Number of control groups +// --------------------------------------------------------------------------- +// +EXPORT_C TInt CAlfRoster::Count() const + { + return iData->iEntries.Count(); + } + +// --------------------------------------------------------------------------- +// Moves group. +// --------------------------------------------------------------------------- +// +TBool CAlfRoster::Move(CAlfControlGroup& aGroup, TInt aPos) + { + TInt index = Find(aGroup); + TInt k = 0; + + if(index != KErrNotFound && index != aPos) + { + CAlfControlGroup* moving = iData->iEntries[index]; + + if(aPos > index) + { + for(k = index; k < aPos; ++k) + { + iData->iEntries[k] = iData->iEntries[k + 1]; + } + } + else + { + for(k = index; k > aPos; --k) + { + iData->iEntries[k] = iData->iEntries[k - 1]; + } + } + iData->iEntries[aPos] = moving; + return ETrue; + } + return EFalse; + } + +// --------------------------------------------------------------------------- +// Appends new group +// --------------------------------------------------------------------------- +// +void CAlfRoster::AppendL(CAlfControlGroup& aGroup) + { + User::LeaveIfError(iData->iEntries.Append(&aGroup)); + } + +// --------------------------------------------------------------------------- +// Inserts new group +// --------------------------------------------------------------------------- +// +void CAlfRoster::InsertL(CAlfControlGroup& aGroup, TInt aPos) + { + if(Find(aGroup) != KErrNotFound) + { + User::Leave(KErrAlreadyExists); + } + + User::LeaveIfError(iData->iEntries.Insert(&aGroup, aPos)); + } + +// --------------------------------------------------------------------------- +// Handles received event +// --------------------------------------------------------------------------- +// +TBool CAlfRoster::HandleEventL(const TAlfEvent& aEvent) + { + TInt i = 0; + TInt k = 0; + + if(iData->iDisplay) + { + iData->iDisplay->Env().ContinueRefresh(); + } + + if(aEvent.IsPointerEvent()) + { + // The order pointer events are offered in depends on the visuals. + + for(i = iData->iEntries.Count() - 1; i >= 0; --i) + { + CAlfControlGroup& group = *iData->iEntries[i]; + + if(!group.AcceptInput()) + { + // The group will not be receiving input events. + continue; + } + + for(k = group.Count() - 1; k >= 0; --k) + { + CAlfControl& control = group.Control(k); + if(control.HitTest(aEvent.PointerEvent().iPosition)) + { + if(control.OfferEventL(aEvent)) + { + // The event was consumed, now it can't be handled by + // anyone else. + return ETrue; + } + } + } + } + } + else + { + // First offer to the input control. + if(aEvent.IsKeyEvent() && iData->iInputFocus && iData->iInputFocus->AcceptInput()) + { + // check if the focus control has a host + CAlfControl* focusRoot = iData->iInputFocus; + while ( focusRoot->Host() ) + { + focusRoot = focusRoot->Host(); + } + + if(focusRoot->OfferEventL(aEvent)) + { + return ETrue; + } + } + + // Iterate through the groups and controls in priority order. + for(i = iData->iEntries.Count() - 1; i >= 0; --i) + { + CAlfControlGroup& group = *iData->iEntries[i]; + + if(!group.AcceptInput()) + { + // The group will not be receiving input events. + continue; + } + + for(k = 0 ; k < group.Count() ; k++ ) + { + CAlfControl& control = group.Control(k); + if(control.OfferEventL(aEvent)) + { + // The event was consumed, now it can't be handled by + // anyone else. + return ETrue; + } + } + // Notify observer that group didn't handle event? + } + } + + return EFalse; + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +EXPORT_C CAlfControlGroup& CAlfRoster::ControlGroup(TInt aIndex) const + { + return *iData->iEntries[aIndex]; + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +EXPORT_C CAlfControl* CAlfRoster::FindControl(TInt aControlId) const + { + for(TInt i = 0; i < iData->iEntries.Count(); ++i) + { + CAlfControl* control = + iData->iEntries[i]->FindControl(aControlId); + if(control) + { + return control; + } + } + return NULL; + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +EXPORT_C void CAlfRoster::SetFocus(CAlfControl& aControl) + { + TRAP_IGNORE(ShowL( *aControl.ControlGroup(), KAlfRosterShowAtTop)) + + // Something needs to change if these are not the same + if ( &aControl != iData->iInputFocus ) + { + ChangeInputFocus( &aControl ); + } + } + +// --------------------------------------------------------------------------- +// Clears the input focus so that no control has focus. +// No change is implied for the visibility of the control group +// --------------------------------------------------------------------------- +// +EXPORT_C void CAlfRoster::ClearFocus() + { + // Only do something if not cleared already + if ( iData->iInputFocus != NULL ) + { + ChangeInputFocus(NULL); + } + } + +// --------------------------------------------------------------------------- +// The main job of this routine is to change iData->iInputFocus, and perform the +// necessary co-ordinated activities. This should be the only place to change this +// member datum. +// --------------------------------------------------------------------------- +// +void CAlfRoster::ChangeInputFocus( CAlfControl* aControl ) + { + // This method will always do something except when both old value and new are NULL + // If they are non-null and identical, then focus will be removed and then re-applied. + // That is, any optimizations need to be done by the caller. + + // The policy of whether focus is altered in the AlfControl is maintained uniformly by storing the cone focus + // state at the beginning of the routine + // Current implementation is for one display/roster. If multiple displays added then this will have to be reconsidered + TBool displayIsInitiallyFocused = iData->iDisplay ? iData->iDisplay->IsFocused() : EFalse; + + // There can be a latent focus only if display is unfocused. + TBool latentFocus = ((iData->iInputFocus != NULL) && (!iData->iInputFocus->Focus())); + __ASSERT_DEBUG((latentFocus ? !displayIsInitiallyFocused : ETrue), User::Panic(_L("UIAcceltkClient"), EAlfRosterPanicFocusAnomaly)); + + CAlfControl* oldFocusedControl = iData->iInputFocus; + + // Remove focus from the currently focused control + if ( iData->iInputFocus ) + { + // Remove focus from the control + // Only need to change actual focus if the roster is focused + if ( displayIsInitiallyFocused ) + { + // This control should be focused at the moment or then there is a latent focus that we are manipulating. + __ASSERT_DEBUG( iData->iInputFocus->Focus(), User::Panic(_L("UIAcceltkClient"),EAlfRosterPanicFocusAnomaly )); + + CAlfDisplay* display = iData->iInputFocus->Display(); + if ( display ) + { + // SetFocus should cause the control to perform any required changes its visuals. + iData->iInputFocus->SetFocus( *display, EFalse); + } + } + + // Still change the iInputFocus even if actual focus has not been removed + if ( !aControl ) + { + iData->iInputFocus = NULL; + } + } + + if ( aControl ) + { + // Check that the control switched to is in this Roster. Ignore it if not. + CAlfControl* control = FindControl(aControl->Id()); + if( control == aControl ) + { + iData->iInputFocus = aControl; + // This control should not be focused at the moment + __ASSERT_DEBUG( !(iData->iInputFocus->Focus()), User::Panic(_L("UIAcceltkClient"),EAlfRosterPanicFocusAnomaly )); + + // Only manipulate actual focus if the roster is focused + if ( displayIsInitiallyFocused ) + { + CAlfDisplay* display2 = iData->iInputFocus->Display(); + if ( display2 ) + { + iData->iInputFocus->SetFocus( *display2, ETrue); + } + } + } + } + + ReportHostsAboutChangingInputFocus( oldFocusedControl, aControl ); + } + +// --------------------------------------------------------------------------- +// Inform host containers for the change +// --------------------------------------------------------------------------- +// +void CAlfRoster::ReportHostsAboutChangingInputFocus( + CAlfControl* aOldFocusControl, + CAlfControl* aNewFocusControl ) + { + // collect new focused control host tree + RPointerArray gainingHostControls; + if ( aNewFocusControl ) + { + CAlfControl* hostTmp = aNewFocusControl->Host(); + while ( hostTmp ) + { + (void)gainingHostControls.Append( hostTmp ); + hostTmp = hostTmp->Host(); + } + } + + // Go through the hosts + // 1. starting from the losing leaf host + // 2. continue to the losing root or combined host + // 3. start from the gaining root or combined host + // 4. end to the gaining leaf host + + TInt combinedIndex = KErrNotFound; + // 1 + if ( aOldFocusControl ) + { + CAlfControl* losingHostTmp = aOldFocusControl->Host(); + while ( losingHostTmp && (combinedIndex == KErrNotFound ) ) // 2 + { + combinedIndex = gainingHostControls.Find( losingHostTmp ); + if ( combinedIndex == KErrNotFound ) + { + losingHostTmp->FocusChainChanged( EFalse ); + losingHostTmp = losingHostTmp->Host(); + } + } + } + + // 3 + TInt gainingStartIndex = gainingHostControls.Count() - 1; + if ( combinedIndex != KErrNotFound ) + { + gainingStartIndex = combinedIndex - 1; // If we want to inform the combined host, remove the '-1' + } + + if ( gainingStartIndex >= 0 ) + { + for ( TInt gainingHostIndex = gainingStartIndex ; gainingHostIndex >= 0 ; gainingHostIndex-- ) // 4 + { + gainingHostControls[gainingHostIndex]->FocusChainChanged( ETrue ); + } + } + + gainingHostControls.Close(); + } + +// --------------------------------------------------------------------------- +// Notifies registered control group order changed observers about changed +// order in control group relative order. +// --------------------------------------------------------------------------- +// +void CAlfRoster::NotifyControlGroupOrderChangedObservers() + { + for(TInt i = 0; i < iData->iControlGroupOrderChangedObservers.Count(); i++) + { + iData->iControlGroupOrderChangedObservers[i]->NotifyControlGroupOrderChanged(); + } + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +EXPORT_C void CAlfRoster::ShowVisualL(CAlfVisual& aVisual) + { + TInt err = + iData->iDisplay->Env().Client().RosterShowVisual( + aVisual.Identifier(), + iData->iDisplay->ServerHandle() ); + + if ( err != KErrNone ) + { + __ALFLOGSTRING1( "CAlfRoster::ShowVisualL leave error %d", err ) + User::Leave( err ); + } + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +EXPORT_C void CAlfRoster::HideVisual(CAlfVisual& aVisual) + { + TInt err = + iData->iDisplay->Env().Client().RosterHideVisual( + aVisual.Identifier(), + iData->iDisplay->ServerHandle() ); + + if ( err != KErrNone ) + { + __ALFLOGSTRING1( "CAlfRoster::HideVisual ignore error %d", err ) + } + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +EXPORT_C void CAlfRoster::MoveVisualToFront(CAlfVisual& aRootVisual) + { + TInt err = + iData->iDisplay->Env().Client().RosterMoveVisualToFront( + aRootVisual.Identifier(), + iData->iDisplay->ServerHandle() ); + + if ( err != KErrNone ) + { + __ALFLOGSTRING1( "CAlfRoster::MoveVisualToFront ignore error %d", err ) + } + } + +// --------------------------------------------------------------------------- +// Adds a pointer event observer +// --------------------------------------------------------------------------- +// +EXPORT_C TInt CAlfRoster::AddPointerEventObserver( + TAlfPointerEventFlags aObserver, + CAlfControl& aControl ) + { + switch ( aObserver ) + { + case EAlfPointerEventReportDrag: + case EAlfPointerEventReportLongTap: + case EAlfPointerEventReportUnhandled: + break; + default: + USER_INVARIANT(); + break; + } + + TInt err = + iData->iDisplay->Env().Client().RosterAddPointerEventObserver( + aObserver, + aControl.Identifier(), + iData->iDisplay->ServerHandle() ); + + return err; + } + +// --------------------------------------------------------------------------- +// Removes a pointer event observer +// --------------------------------------------------------------------------- +// +EXPORT_C TInt CAlfRoster::RemovePointerEventObserver( + TAlfPointerEventFlags aObserver, + CAlfControl& aControl ) + { + switch ( aObserver ) + { + case EAlfPointerEventReportDrag: + case EAlfPointerEventReportLongTap: + case EAlfPointerEventReportUnhandled: + break; + default: + USER_INVARIANT(); + break; + } + + TInt err = + iData->iDisplay->Env().Client().RosterRemovePointerEventObserver( + aObserver, + aControl.Identifier(), + iData->iDisplay->ServerHandle() ); + + return err; + } + +// --------------------------------------------------------------------------- +// Sets pointer event observer flags. +// --------------------------------------------------------------------------- +// +EXPORT_C TInt CAlfRoster::SetPointerEventObservers( + TUint aPointerEventFlags, + CAlfControl& aControl ) + { + TInt err = + iData->iDisplay->Env().Client().RosterSetPointerEventObservers( + aPointerEventFlags, + aControl.Identifier(), + iData->iDisplay->ServerHandle() ); + + return err; + } + +void CAlfRoster::DisplayFocusChanged( CAlfDisplay& aDisplay, TBool aNewFocus ) + { + // This method should only be called during a real transition of display focus. If there is a + // roster focused control then alter it's focus state. + if ( iData->iInputFocus ) + { + iData->iInputFocus->SetFocus( aDisplay, aNewFocus ); + + if (aNewFocus) + { + ReportHostsAboutChangingInputFocus( NULL, iData->iInputFocus ); + } + else + { + ReportHostsAboutChangingInputFocus( iData->iInputFocus, NULL ); + } + + } + } + +CAlfControl* CAlfRoster::FocusedControl() const + { + return iData->iInputFocus; + } + +EXPORT_C TInt CAlfRoster::SetPointerDragThreshold(const CAlfControl& aControl, const TAlfXYMetric& aXYMetric) + { + TInt err = + iData->iDisplay->Env().Client().RosterSetPointerDragTreshold( + aControl.Identifier(), + aXYMetric, + iData->iDisplay->ServerHandle() ); + + return err; + } + +EXPORT_C TInt CAlfRoster::DisableLongTapEventsWhenDragging(const CAlfControl& aControl, TBool aDisable) + { + TInt err = + iData->iDisplay->Env().Client().RosterDisableLongTapEventsWhenDragging( + aControl.Identifier(), + aDisable, + iData->iDisplay->ServerHandle() ); + + return err; + } + +// --------------------------------------------------------------------------- +// Adds a control group order change observer into the observers array. +// --------------------------------------------------------------------------- +// +EXPORT_C void CAlfRoster::AddControlGroupOrderChangedObserverL(MAlfControlGroupOrderChangedObserver& aObserver) + { + if(iData->iControlGroupOrderChangedObservers.Find(&aObserver) != KErrNotFound) + { + return; + } + iData->iControlGroupOrderChangedObservers.AppendL(&aObserver); + } + +// --------------------------------------------------------------------------- +// Removes a control group order change observer from the observers array. +// --------------------------------------------------------------------------- +// +EXPORT_C void CAlfRoster::RemoveControlGroupOrderChangedObserver(MAlfControlGroupOrderChangedObserver& aObserver) + { + TInt index = iData->iControlGroupOrderChangedObservers.Find(&aObserver); + if(index != KErrNotFound) + { + iData->iControlGroupOrderChangedObservers.Remove(index); + } + }