photosgallery/viewframework/medialists/src/glxnavigablelist.cpp
changeset 0 4e91876724a2
child 18 bcb43dc84c44
child 20 d1bdfdf534bd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/photosgallery/viewframework/medialists/src/glxnavigablelist.cpp	Thu Dec 17 08:45:44 2009 +0200
@@ -0,0 +1,956 @@
+/*
+* Copyright (c) 2008-2009 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:    List of media items, which has focus
+*
+*/
+
+
+
+
+// my include
+#include "glxnavigablelist.h"
+
+// system includes
+#include <mpxcollectionpath.h>
+#include <glxtracer.h>
+#include <glxlog.h>
+
+// user includes
+#include "glxlistutils.h"
+#include "glxmedia.h"
+#include "glxstaticitemlist.h"
+#include "mglxnavigablelistobserver.h"
+
+using namespace NGlxNavigableList;
+
+namespace NGlxNavigableList
+    {
+    
+    /** 
+     * Strategy to process selection indexes
+     */ 
+    class MSelectionIndexStrategy 
+        {
+    public:
+        /** 
+         * Process a single selection index
+         * @param aSelectedItemIndex index in selected item index array to process
+         */ 
+        virtual void Process( TInt aSelectedItemIndex ) = 0;
+        };
+        
+    /** 
+     * Strategy to remove selection indexes
+     */ 
+    NONSHARABLE_CLASS( TRemoveSelectedItemIndexStrategy ) : 
+            public MSelectionIndexStrategy
+        {
+    public:
+        /**
+         * Constructor
+         * @param aSelectedItemIndices Selected item index array
+         */
+        TRemoveSelectedItemIndexStrategy( RArray< TInt>& aSelectedItemIndices )
+                : iSelectedItemIndices( aSelectedItemIndices )
+            {
+            }
+
+        /** See @ref MSelectionIndexStrategy */
+        void Process( TInt aSelectedItemIndex )
+            {
+            iSelectedItemIndices.Remove( aSelectedItemIndex );
+            }
+
+    private:
+        /// Selected item indexes
+        RArray< TInt>& iSelectedItemIndices; 
+        };
+
+    /** 
+     * Strategy to move selection indexes
+     */ 
+    NONSHARABLE_CLASS( TMoveSelectedItemIndexStrategy ) : 
+            public MSelectionIndexStrategy
+        {
+    public:
+        /** 
+         * Constructor 
+         * @param aMoveCount a number of items to move index by
+         */
+        TMoveSelectedItemIndexStrategy( RArray< TInt>& aSelectedItemIndices, 
+            TInt aMoveCount )
+                : iSelectedItemIndices( aSelectedItemIndices )
+            {
+            iMoveCount = aMoveCount;
+            }
+            
+        /** See @ref MSelectionIndexStrategy */
+        void Process( TInt aSelectedItemIndex )
+            {
+            iSelectedItemIndices[ aSelectedItemIndex ] += iMoveCount;
+            }
+        
+    private: 
+        /// The count of items to move by
+        TInt iMoveCount;
+        /// Selected item indexes
+        RArray< TInt>& iSelectedItemIndices; 
+        };
+    
+    } // namespace NGlxNavigableList
+    
+// -----------------------------------------------------------------------------
+// Two-phase constructor
+// -----------------------------------------------------------------------------
+//
+CGlxNavigableList* CGlxNavigableList::NewL( const TGlxIdSpaceId& aIdSpaceId,
+        MGlxNavigableListObserver& aObserver, MGlxMediaUser& aMediaUser )
+    {
+    TRACER("CGlxNavigableList::NewL");
+            
+    CGlxNavigableList* self = new (ELeave) CGlxNavigableList( aObserver );
+    CleanupStack::PushL( self );
+    self->ConstructL( aIdSpaceId, aMediaUser );
+    CleanupStack::Pop( self );
+    return self;
+    }
+    
+// -----------------------------------------------------------------------------
+// Constructor
+// -----------------------------------------------------------------------------
+//
+CGlxNavigableList::CGlxNavigableList( MGlxNavigableListObserver& aObserver ) :
+        iFocusInitialPosition( NGlxListDefs::EFocusFirst ),
+        iObserver( aObserver )
+    {
+    TRACER("CGlxNavigableList::CGlxNavigableList");
+    
+    iFocusIndex = KErrNotFound;
+    }
+
+// -----------------------------------------------------------------------------
+// Second-phase constructor
+// -----------------------------------------------------------------------------
+//
+void CGlxNavigableList::ConstructL( const TGlxIdSpaceId& aIdSpaceId,
+        MGlxMediaUser& aMediaUser )
+    {
+    TRACER("CGlxNavigableList::ConstructL");
+    
+    iItemList = CGlxStaticItemList::NewL( aIdSpaceId, *this, aMediaUser );
+    
+
+    }
+
+// -----------------------------------------------------------------------------
+// Destructor
+// -----------------------------------------------------------------------------
+//
+CGlxNavigableList::~CGlxNavigableList()
+    {
+    TRACER( "CGlxNavigableList::~CGlxNavigableList" );
+    iSelectedItemIndices.Close();
+    delete iItemList;
+
+    
+    }
+
+// -----------------------------------------------------------------------------
+// return id space id
+// -----------------------------------------------------------------------------
+// 
+const TGlxIdSpaceId& CGlxNavigableList::IdSpaceId() const
+    {
+    TRACER( "CGlxNavigableList::IdSpaceId");
+    
+    return iItemList->IdSpaceId();
+    }
+
+// -----------------------------------------------------------------------------
+// Synchronise contents of the list with the collection path
+// -----------------------------------------------------------------------------
+//
+void CGlxNavigableList::SetContentsL( const CMPXCollectionPath& aPath,
+        const MGlxMediaPool& aMediaPool )
+    {
+    TRACER( "CGlxNavigableList::SetContentsL" );
+    iItemList->SetContentsL( aPath, aMediaPool );
+    }
+
+// -----------------------------------------------------------------------------
+// Re-orders contents of the list with the collection path
+// -----------------------------------------------------------------------------
+//
+void CGlxNavigableList::ReorderContentsL( const CMPXCollectionPath& aPath, 
+        const MGlxMediaPool& aMediaPool )
+    {
+    TRACER( "CGlxNavigableList::ReorderContentsL" );
+    __TEST_INVARIANT;
+
+    // List contents have been reordered. If we called SetContentsL directly,
+    // the client would get semi-random (but correct) sequence of added/removed
+    // notifications. To provide a cleaner notification, send only "all removed"
+    // and "all added" notifications. 
+    
+    // store the focus and selection temporarily for restoring later-
+    // (store ids; cannot store index, since indexes may change upon reorder)
+    TGlxMediaId focusedItemId = FocusId();
+
+    RArray< TGlxMediaId > selectedItemIds;
+    CleanupClosePushL( selectedItemIds );
+    SelectionL( selectedItemIds );
+
+    // send notification "all items removed"
+    ClearContentsL( aMediaPool );
+
+    // set contents to reordered list, this removes focus and selection.
+    // send notification of "all items added" (in new order)
+    SetContentsL( aPath, aMediaPool );
+
+    // restore focus and selection
+    SetFocus( focusedItemId ); 
+    SelectL( selectedItemIds );
+
+    CleanupStack::PopAndDestroy( &selectedItemIds );
+
+    __TEST_INVARIANT;
+    }
+
+// -----------------------------------------------------------------------------
+// Remove an item form the list
+// -----------------------------------------------------------------------------
+//
+void CGlxNavigableList::Remove( const TGlxIdSpaceId& aIdSpaceId, 
+        const TGlxMediaId& aItemId )
+    {
+    TRACER( "CGlxNavigableList::Remove" );
+    iItemList->Remove( aIdSpaceId, aItemId );
+    }
+
+// -----------------------------------------------------------------------------
+// Remove any pointers to the media object at the specified index
+// -----------------------------------------------------------------------------
+//
+void CGlxNavigableList::RemoveReference( TInt aIndex )
+    {
+    TRACER( "CGlxNavigableList::RemoveReference" );
+    iItemList->RemoveReference( aIndex );
+    }
+    
+// -----------------------------------------------------------------------------
+// Add a static item
+// -----------------------------------------------------------------------------
+//
+void CGlxNavigableList::AddStaticItemL( CGlxMedia* aStaticItem, 
+        NGlxListDefs::TInsertionPosition aTargetPosition )
+    {
+    TRACER( "CGlxNavigableList::AddStaticItemL" );
+    iItemList->AddStaticItemL( aStaticItem, aTargetPosition );
+    }
+        
+// -----------------------------------------------------------------------------
+// Enable/disable static items
+// -----------------------------------------------------------------------------
+//
+void CGlxNavigableList::SetStaticItemsEnabled( TBool aEnabled )
+    {
+    TRACER( "CGlxNavigableList::SetStaticItemsEnabled" );
+    iItemList->SetStaticItemsEnabled( aEnabled );
+    }
+    
+// -----------------------------------------------------------------------------
+// return ETrue if static items are enabled
+// -----------------------------------------------------------------------------
+//
+TBool CGlxNavigableList::IsStaticItemsEnabled() const
+    {
+    TRACER( "CGlxNavigableList::IsStaticItemsEnabled");
+    
+    return iItemList->IsStaticItemsEnabled();
+    }
+    
+// -----------------------------------------------------------------------------
+// Return count
+// -----------------------------------------------------------------------------
+//
+TInt CGlxNavigableList::Count( NGlxListDefs::TCountType aType ) const
+    {
+    TRACER( "CGlxNavigableList::Count");
+    
+    return iItemList->Count( aType );
+    }
+
+// -----------------------------------------------------------------------------
+// Sets the initial focus position, first or last item
+// -----------------------------------------------------------------------------
+//
+void CGlxNavigableList::SetFocusInitialPosition(NGlxListDefs::TFocusInitialPosition aFocusInitialPosition)
+    {
+    TRACER( "CGlxNavigableList::SetFocusInitialPosition");
+    
+    iFocusInitialPosition = aFocusInitialPosition;
+    SetInitialFocus();
+    }
+    
+// -----------------------------------------------------------------------------
+// Return focus index
+// -----------------------------------------------------------------------------
+//
+TInt CGlxNavigableList::FocusIndex() const 
+    {
+    TRACER( "CGlxNavigableList::FocusIndex");
+    
+    return iFocusIndex;
+    }
+
+// -----------------------------------------------------------------------------
+// Set focus index
+// -----------------------------------------------------------------------------
+//
+void CGlxNavigableList::SetFocus( NGlxListDefs::TFocusSetType aType, TInt aValue )
+    {
+    TRACER( "CGlxNavigableList::SetFocus");
+    GLX_LOG_INFO1( "CGlxNavigableList::SetFocus: Entry: %d", aValue );
+    
+    __TEST_INVARIANT;
+
+    // Observer callback needs to know the focus change type
+    NGlxListDefs::TFocusChangeType type = NGlxListDefs::EUnknown;
+    
+    TInt oldIndex = iFocusIndex;
+
+    switch ( aType )
+        {
+        case NGlxListDefs::EAbsolute:
+            type = SetFocus( aValue );
+            break;
+            
+        case NGlxListDefs::ERelative:
+            type = MoveFocus( aValue );
+            break;
+            
+        default:
+            Panic( EGlxPanicIllegalArgument ); // Unsupported focus change type
+            break;
+        }
+
+
+
+    // notify observer if focus changed
+    NotifyFocusChange( type, oldIndex,  iFocusIndex != oldIndex );
+
+    __TEST_INVARIANT;
+    GLX_LOG_INFO( "CGlxNavigableList::SetFocusL: Exit" );
+    }
+
+// -----------------------------------------------------------------------------
+// Set focus by id
+// inline private member function only in cpp file, so will be inlined in arm
+// (ok as long as called only once)
+// -----------------------------------------------------------------------------
+//
+inline void CGlxNavigableList::SetFocus( const TGlxMediaId& aItemId )
+    {
+    TRACER( "CGlxNavigableList::SetFocus");
+    
+    TInt index = Index( IdSpaceId(), aItemId );
+    if ( KErrNotFound != index )
+        {
+        // Focus the item if it still exists in the new list
+        SetFocus( NGlxListDefs::EAbsolute, index );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// Set focus index
+// -----------------------------------------------------------------------------
+//
+NGlxListDefs::TFocusChangeType CGlxNavigableList::SetFocus( TInt aIndex )
+    {
+    TRACER( "CGlxNavigableList::SetFocus");
+    __ASSERT_ALWAYS( aIndex >= 0 && aIndex < Count(), Panic( EGlxPanicIllegalArgument ) );
+
+    iFocusIndex = aIndex;
+
+    // it is not possible to know which direction focus was moving, since
+    // client did not specify it. Looping of the list makes it impossible to 
+    // compare the old and new index. 
+    return NGlxListDefs::EUnknown;
+    }
+
+// -----------------------------------------------------------------------------
+// Move focus index
+// inline private member function only in cpp file, so will be inlined in arm
+// (ok as long as called only once)
+// -----------------------------------------------------------------------------
+//
+inline NGlxListDefs::TFocusChangeType CGlxNavigableList::MoveFocus( TInt aDelta )
+    {
+    TRACER( "CGlxNavigableList::MoveFocus");
+    
+    // Moving focus in not possible when the list is empty
+    if ( KErrNotFound != iFocusIndex )
+        {
+        // Move focus index
+        iFocusIndex += aDelta;
+        
+        // wrap back into the loop
+        iFocusIndex = GlxListUtils::NormalizedIndex( iFocusIndex, Count() );
+
+        // determine direction of focus change
+        if ( aDelta > 0 )
+            {
+            return NGlxListDefs::EForward;
+            }
+        // client won't be notified if aDelta is 0, so it is suitable
+        // to return EBackward, even if focus does not move
+        return NGlxListDefs::EBackward;
+        }
+        
+    return NGlxListDefs::EUnknown;
+    }
+
+// -----------------------------------------------------------------------------
+// Notify observers of focus change
+// -----------------------------------------------------------------------------
+//
+void CGlxNavigableList::NotifyFocusChange( NGlxListDefs::TFocusChangeType aType, 
+        TInt aOldIndex, TBool aNotify )
+    {
+    TRACER( "CGlxNavigableList::NotifyFocusChange");
+    
+    if ( aNotify )
+        {
+        iObserver.HandleFocusChanged( aType, iFocusIndex, aOldIndex );
+        }
+    }
+    
+// -----------------------------------------------------------------------------
+// Sets the initial focus
+// -----------------------------------------------------------------------------
+//
+void CGlxNavigableList::SetInitialFocus()
+    {
+    TRACER( "CGlxNavigableList::SetInitialFocus");
+    
+    // Only need to set focus if there are some items
+    if ( Count() )
+        {
+        if ( iFocusInitialPosition == NGlxListDefs::EFocusFirst )
+            {
+            iFocusIndex = 0;
+            }
+        else // iFocusInitialPosition == NGlxListDefs::EFocusLast
+            {
+            iFocusIndex = Count() - 1;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// Resets the focus to the initial position
+// -----------------------------------------------------------------------------
+//
+void CGlxNavigableList::ResetFocus()
+    {
+    TRACER( "CGlxNavigableList::ResetFocus");
+    
+    TInt oldFocusIndex = iFocusIndex;
+
+    SetInitialFocus();
+
+    // notify of focus change after resetting focus
+    // Only need to notify if there are some items
+    if( Count() )
+    	{
+    NotifyFocusChange( NGlxListDefs::EUnknown, oldFocusIndex, ETrue );
+    	}
+    }
+
+// -----------------------------------------------------------------------------
+// Return item by index
+// -----------------------------------------------------------------------------
+//
+TGlxMedia& CGlxNavigableList::Item( TInt aIndex )
+    {
+    TRACER( "CGlxNavigableList::Item");
+    
+    return iItemList->Item( aIndex );
+    }
+
+// -----------------------------------------------------------------------------
+// Return index by id
+// -----------------------------------------------------------------------------
+//
+TInt CGlxNavigableList::Index(const TGlxIdSpaceId& aIdSpaceId, const TGlxMediaId& aId ) const
+    {
+    TRACER( "CGlxNavigableList::Index");
+    
+    return iItemList->Index(aIdSpaceId, aId );
+    }
+
+// -----------------------------------------------------------------------------
+// Return whether item at index is selected
+// -----------------------------------------------------------------------------
+//
+TBool CGlxNavigableList::IsSelected(TInt aIndex) const
+    {
+    TRACER( "CGlxNavigableList::IsSelected");
+    
+    return ( KErrNotFound != iSelectedItemIndices.FindInOrder( aIndex ) );
+    }
+
+// -----------------------------------------------------------------------------
+// Select/deselect item
+// -----------------------------------------------------------------------------
+//
+void CGlxNavigableList::SetSelectedL( TInt aIndex, TBool aSelected )
+    {
+    TRACER( "CGlxNavigableList::SetSelectedL");    
+    GLX_LOG_INFO2( "CGlxNavigableList::SetSelectedL: index %d selected %b", 
+            aIndex, aSelected );
+    __TEST_INVARIANT;
+    
+    if ( aSelected )
+        {
+        SelectL( aIndex );
+        }
+    else
+        {
+        Deselect( aIndex );
+        }
+
+    __TEST_INVARIANT;
+    }
+
+// -----------------------------------------------------------------------------
+// Return id of focused item or KGlxIdNone
+// inline private member function only in cpp file, so will be inlined in arm
+// (ok as long as called only once)
+// -----------------------------------------------------------------------------
+//
+inline TGlxMediaId CGlxNavigableList::FocusId() const
+    {
+    TRACER( "CGlxNavigableList::FocusId");
+    
+    if ( KErrNotFound != iFocusIndex )
+        {
+        return iItemList->Item( iFocusIndex ).Id();
+        }
+    return KGlxIdNone;
+    }
+
+// -----------------------------------------------------------------------------
+// Return id of focused item or KGlxIdNone
+// inline private member function only in cpp file, so will be inlined in arm
+// (ok as long as called only once)
+// -----------------------------------------------------------------------------
+//
+inline void CGlxNavigableList::SelectionL( RArray< TGlxMediaId >& aItemIds ) const
+    {
+    TRACER( "CGlxNavigableList::SelectionL");
+    
+    aItemIds.Reset();
+
+    // Reserve full required space to avoid reallocations during loop
+    aItemIds.ReserveL( iSelectedItemIndices.Count() );
+
+    TInt count = iSelectedItemIndices.Count();
+    for ( TInt i = 0; i < count; ++i )
+        {
+        aItemIds.AppendL( iItemList->Item( iSelectedItemIndices[ i ] ).Id() );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// Clear list contents
+// inline private member function only in cpp file, so will be inlined in arm
+// (ok as long as called only once)
+// -----------------------------------------------------------------------------
+//
+inline void CGlxNavigableList::ClearContentsL( const MGlxMediaPool& aMediaPool )
+    {
+    TRACER( "CGlxNavigableList::ClearContentsL");
+    
+    // Create a path with no items in order to empty the list
+    CMPXCollectionPath* emptyPath = CMPXCollectionPath::NewL();
+    CleanupStack::PushL( emptyPath );
+
+    iItemList->SetContentsL( *emptyPath, aMediaPool );
+
+    CleanupStack::PopAndDestroy( emptyPath );
+    }
+
+// -----------------------------------------------------------------------------
+// Select items by id
+// inline private member function only in cpp file, so will be inlined in arm
+// (ok as long as called only once)
+// -----------------------------------------------------------------------------
+//
+inline void CGlxNavigableList::SelectL( const RArray< TGlxMediaId >& aItemIds ) 
+    {
+    TRACER( "CGlxNavigableList::SelectL");
+    
+    // Reserve free space for the full selection, so that the operation can
+    // be atomic
+    ReserveFreeSpaceInSelectionL( aItemIds.Count() );
+
+    // pick id space id locally to avoid re-retrieving during the loop
+    TGlxIdSpaceId idSpaceId = IdSpaceId();
+
+    // Select the requested items     
+    TInt count = aItemIds.Count();
+    for ( TInt i = 0; i < count; i++ )
+        {
+        TInt index = Index( idSpaceId, aItemIds[ i ] );
+        if ( index != KErrNotFound )
+            {
+            Select( index );
+            }
+        }    
+    }
+    
+// -----------------------------------------------------------------------------
+// Select item
+// inline private member function only in cpp file, so will be inlined in arm
+// (ok as long as called only once)
+// -----------------------------------------------------------------------------
+//
+inline void CGlxNavigableList::SelectL( TInt aIndex )
+    {
+    TRACER( "CGlxNavigableList::SelectL");
+    
+    // Don't allow static items to be selected
+    if ( !Item( aIndex ).IsStatic() )
+        {
+        ReserveFreeSpaceInSelectionL( 1 );
+        Select( aIndex );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// Select item. Must call ReserveFreeSpaceInSelectionL before
+// -----------------------------------------------------------------------------
+//
+void CGlxNavigableList::Select( TInt aIndex )
+    {
+    TRACER( "CGlxNavigableList::Select");
+    
+    __ASSERT_DEBUG( _iSelectionReserveCount > 0, Panic( EGlxPanicNoReservation ) ); // No reservation made
+    __DEBUG_ONLY( _iSelectionReserveCount-- );
+    
+    // returns KErrNone if inserted successfully, KErrAlreadyExists if already exists
+    if ( KErrNone == iSelectedItemIndices.InsertInOrder( aIndex ) )
+        {
+        iObserver.HandleItemSelected( aIndex, ETrue );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// Reserve free space is selected item indexes array
+// -----------------------------------------------------------------------------
+//
+inline void CGlxNavigableList::ReserveFreeSpaceInSelectionL( TInt aCount )
+    {
+    TRACER( "CGlxNavigableList::ReserveFreeSpaceInSelectionL");
+    
+    iSelectedItemIndices.ReserveL( iSelectedItemIndices.Count() + aCount );
+    
+    // store reservation count so can protect agains Select(...) being called
+    // without reservation
+    __DEBUG_ONLY( _iSelectionReserveCount = aCount );
+    }
+        
+// -----------------------------------------------------------------------------
+// Deselect item
+// inline private member function only in cpp file, so will be inlined in arm
+// (ok as long as called only once)
+// -----------------------------------------------------------------------------
+//
+inline void CGlxNavigableList::Deselect( TInt aIndex )
+    {
+    TRACER( "CGlxNavigableList::Deselect");
+    
+    // item has been deselected, remove if found
+    TInt selectionArrayIndex = iSelectedItemIndices.FindInOrder( aIndex );
+    if ( KErrNotFound != selectionArrayIndex )
+        {
+        // remove from array of selected items
+        iSelectedItemIndices.Remove( selectionArrayIndex );
+        
+        // free unused memory from selected item indexes array
+        // (this call may be a performance bottleneck if executing unmark all
+        //  in a list of many thousands of items when most of them are marked.
+        //  if it is proved to be a performance bottleneck, it may be sensible
+        //  to count how many times Deselect has been called, an only
+        //  compress every x times.)
+        //iSelectedItemIndices.Compress();
+        
+        // selection has changed, notify observer
+        iObserver.HandleItemSelected( aIndex, EFalse );
+        }
+    // else: ignore if item was not selected
+    }
+
+// -----------------------------------------------------------------------------
+// Return selected items
+// -----------------------------------------------------------------------------
+//
+const TArray< TInt > CGlxNavigableList::SelectedItemIndices() const
+    {
+    TRACER( "CGlxNavigableList::SelectedItemIndices");
+    
+    return iSelectedItemIndices.Array();
+    }
+
+// -----------------------------------------------------------------------------
+// Handle items being added
+// -----------------------------------------------------------------------------
+//
+void CGlxNavigableList::HandleItemsAdded( TInt aFirstInsertedIndex, 
+        TInt aCount )
+    {
+    TRACER( "CGlxNavigableList::HandleItemsAdded" );
+
+    // Do not test invariant in the beginning of this function. Right now,
+    // the state is not valid, since iItemList's state has already changed, and
+    // this function will align the state of this object with iItemList.
+
+    // Move selection indexes from insertion point 
+    TMoveSelectedItemIndexStrategy moveStrategy( iSelectedItemIndices, aCount );
+    ProcessSelectionItemIndicesBetweenIndexes( aFirstInsertedIndex, 
+        Count( NGlxListDefs::ECountAll ), moveStrategy );
+
+    // move focus
+    TInt oldFocusIndex = iFocusIndex;
+    TInt notifyOfFocusChange = UpdateFocusAfterInsertion( aFirstInsertedIndex, aCount );
+
+    // Adjust index by amount of static items
+    iObserver.HandleItemsAdded( aFirstInsertedIndex, aCount );
+    
+    // notify of focus change after having notified of items being added,
+    // so that focus index points to the correct real item on client side
+    NotifyFocusChange( NGlxListDefs::EUnknown, oldFocusIndex, 
+            notifyOfFocusChange );
+    __TEST_INVARIANT;
+    }
+
+// -----------------------------------------------------------------------------
+// Move focus after items have been inserted
+// inline private member function only in cpp file, so will be inlined in arm
+// (ok as long as called only once)
+// -----------------------------------------------------------------------------
+//
+inline TInt CGlxNavigableList::UpdateFocusAfterInsertion( TInt aInsertionIndex, 
+        TInt aInsertionCount )  
+    {
+     TRACER( "CGlxNavigableList::UpdateFocusAfterInsertion" );
+     
+    // Move focus if index is changed.
+    TBool notifyObserver = MoveFocusIfIndexChanged( aInsertionIndex, aInsertionCount );
+        
+    // Set focus to initial focus position if not previously set. Test also that count larger 
+    // than zero, just to be safe for future maintenance of other classes
+    if ( KErrNotFound == iFocusIndex && Count( NGlxListDefs::ECountAll ) > 0 )
+        {
+        GLX_LOG_INFO("iFocusIndex is KErrNotFound");
+
+        // Set initial focus position
+        SetInitialFocus();
+
+        notifyObserver = ETrue;
+        }
+    
+    return notifyObserver;
+    }
+
+// -----------------------------------------------------------------------------
+// Move focus if index is changed.
+// -----------------------------------------------------------------------------
+//
+TBool CGlxNavigableList::MoveFocusIfIndexChanged( TInt aChangedIndex, TInt aMoveBy )  
+    {
+    TRACER( "CGlxNavigableList::MoveFocusIfIndexChanged" );
+    
+    if ( iFocusIndex >= aChangedIndex )
+       {
+	       iFocusIndex += aMoveBy;
+	       return ETrue; // notify observer
+       }
+       
+       return EFalse; // don't notify observer
+    }
+
+// -----------------------------------------------------------------------------
+// Handle items being removed
+// -----------------------------------------------------------------------------
+//
+void CGlxNavigableList::HandleItemsRemoved( TInt aRemovedFromIndex, TInt aCount )  
+    {
+    TRACER( "CGlxNavigableList::HandleItemsRemoved" );
+
+    // Do not test invariant in the beginning of this function. Right now,
+    // the state is not valid, since iItemList's state has already changed, and
+    // this function will align the state of this object with iItemList.
+
+    // update selection
+    UpdateSelectionAfterRemove( aRemovedFromIndex, aCount );
+    TInt oldFocusIndex = iFocusIndex;
+    TBool notifyOfFocusChange = UpdateFocusAfterRemoval( aRemovedFromIndex, 
+        aCount );
+    
+    // notify observer
+    iObserver.HandleItemsRemoved( aRemovedFromIndex, aCount );
+    
+    // notify of focus change after having notified of items being removed,
+    // so that focus index points to the correct real item on client side
+    NotifyFocusChange( NGlxListDefs::EUnknown, oldFocusIndex, 
+                notifyOfFocusChange );
+    __TEST_INVARIANT;
+    }
+
+// -----------------------------------------------------------------------------
+// Update selection after remove
+// inline private member function only in cpp file, so will be inlined in arm
+// (ok as long as called only once)
+// -----------------------------------------------------------------------------
+//
+inline void CGlxNavigableList::UpdateSelectionAfterRemove( TInt aRemovedFromIndex, 
+        TInt aRemovedCount )
+    {
+    TRACER( "CGlxNavigableList::UpdateSelectionAfterRemove");
+    
+    // remove items from selected list that were removed
+    TRemoveSelectedItemIndexStrategy removeStrategy( iSelectedItemIndices );
+    ProcessSelectionItemIndicesBetweenIndexes( aRemovedFromIndex, 
+        aRemovedFromIndex + aRemovedCount, removeStrategy );
+    
+    // move selection indexes from removal point 
+    TMoveSelectedItemIndexStrategy moveStrategy( iSelectedItemIndices, -aRemovedCount );
+    ProcessSelectionItemIndicesBetweenIndexes( aRemovedFromIndex + aRemovedCount, 
+        KMaxTInt, moveStrategy );
+    }
+
+// -----------------------------------------------------------------------------
+// Move focus after items have been removed
+// inline private member function only in cpp file, so will be inlined in arm
+// (ok as long as called only once)
+// -----------------------------------------------------------------------------
+//
+inline TBool CGlxNavigableList::UpdateFocusAfterRemoval( TInt aRemovedFromIndex, 
+        TInt aRemovedCount )  
+    {
+    TRACER( "CGlxNavigableList::UpdateFocusAfterRemoval");
+    
+    // Assume focus will be changed (simplifies code below)
+    TBool notifyObserver = EFalse;   
+    
+    // move focus if it is after the last removed item (incl. list has become empty)
+    if ( iFocusIndex >= aRemovedFromIndex + aRemovedCount )
+        {
+        iFocusIndex -= aRemovedCount;        
+        // although the focus did not logically change in this case, notify
+        // anyway to simplify client code
+        notifyObserver = ETrue;
+        }
+    // move focus if it is on removed items
+    else if ( iFocusIndex >= aRemovedFromIndex )
+        {
+        iFocusIndex = Min( aRemovedFromIndex, Count() - 1 );
+        notifyObserver = ETrue;
+        }
+    // else focus is before removed items, so do nothing       
+
+    return notifyObserver;
+    }
+
+// -----------------------------------------------------------------------------
+// Remove selection indices between two indexes
+// -----------------------------------------------------------------------------
+//
+void CGlxNavigableList::ProcessSelectionItemIndicesBetweenIndexes( 
+        TInt aFromIndex, TInt aToIndex, MSelectionIndexStrategy& aStrategy )
+    {
+    TRACER("CGlxNavigableList::ProcessSelectionItemIndicesBetweenIndexes");
+    
+    // Find first selection item index that points to an index larger or equal
+    // than aFromIndex
+    TInt selectedItemIndex = FindFirstSelectedItemIndexBefore( aToIndex );
+    // Process until finds a selection item index pointing to an item smaller 
+    // than aFromIndex
+    while ( selectedItemIndex >= 0 && 
+            iSelectedItemIndices[ selectedItemIndex ] >= aFromIndex ) 
+        {
+        aStrategy.Process( selectedItemIndex );
+        selectedItemIndex--;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// Return first selection item index on or after
+// -----------------------------------------------------------------------------
+//
+inline TInt CGlxNavigableList::FindFirstSelectedItemIndexBefore( TInt aMaxIndex )
+    {
+    TRACER( "CGlxNavigableList::FindFirstSelectedItemIndexBefore");
+    
+    // Find first selection item index that points to an index larger or equal
+    // than aAtLeastIndex
+    TInt i = iSelectedItemIndices.Count() - 1;
+    while ( i >= 0 )
+        {
+        if ( iSelectedItemIndices[i] < aMaxIndex )
+            {
+            break;
+            }
+        i--;
+        }
+    
+    // KErrNotFound == -1, which will be returned if the loop did not break
+    return i; 
+    }
+
+// ---------------------------------------------------------------------------
+// Test invariant
+// ---------------------------------------------------------------------------
+void CGlxNavigableList::__DbgTestInvariant() const
+    {
+    TRACER( "CGlxNavigableList::__DbgTestInvariant");
+    
+    #if 0
+    //def _DEBUG
+
+    // focus index must be KErrNotFound if list is empty
+    __ASSERT_DEBUG( iFocusIndex == KErrNotFound || iItemList->Count( NGlxListDefs::ECountAll ), Panic( EGlxPanicIllegalState ) ); 
+    // focus index must be between 0 and count if list is not empty
+    __ASSERT_DEBUG( ( iFocusIndex >= 0 && 
+                      iFocusIndex < iItemList->Count( NGlxListDefs::ECountAll ) ) || 
+                      !iItemList->Count( NGlxListDefs::ECountAll ), 
+                      Panic( EGlxPanicIllegalState ) ); 
+    // max count amount of items can be selected
+    __ASSERT_DEBUG( iSelectedItemIndices.Count() <= iItemList->Count( NGlxListDefs::ECountAll ), Panic( EGlxPanicIllegalState ) ); 
+    // test selection item index array
+    TInt previousSelectedIndex = -1;
+    for ( TInt i = 0; i < iSelectedItemIndices.Count(); i++ )
+        {
+        // index must be between zero and count
+        __ASSERT_DEBUG( iSelectedItemIndices[ i ] >= 0 && iSelectedItemIndices[ i ] < iItemList->Count( NGlxListDefs::ECountAll ), Panic( EGlxPanicIllegalState ) ); 
+        // index must not be in order
+        __ASSERT_DEBUG( iSelectedItemIndices[ i ] > previousSelectedIndex, Panic( EGlxPanicIllegalState ) ); 
+        // prepare next round
+        previousSelectedIndex = iSelectedItemIndices[ i ];
+        }
+    
+    #endif // _DEBUG
+    }