uiacceltk/hitchcock/Client/src/alfroster.cpp
changeset 0 15bf7259bb7c
--- /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 <uiacceltk/HuiUtil.h>
+
+// Private data
+    
+struct CAlfRoster::TPrivateData
+    {
+    CAlfDisplay* iDisplay;                      // Not owned.
+    RPointerArray<CAlfControlGroup> iEntries;    // Not owned. Kept in order.
+    CAlfControl* iInputFocus;                   // Not owned.
+    RPointerArray<MAlfControlGroupOrderChangedObserver> 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<CAlfControl> 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);
+	    }
+    }