photosgallery/viewframework/medialists/src/glxnavigablelist.cpp
changeset 0 4e91876724a2
child 18 bcb43dc84c44
child 20 d1bdfdf534bd
equal deleted inserted replaced
-1:000000000000 0:4e91876724a2
       
     1 /*
       
     2 * Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). 
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:    List of media items, which has focus
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 
       
    20 
       
    21 // my include
       
    22 #include "glxnavigablelist.h"
       
    23 
       
    24 // system includes
       
    25 #include <mpxcollectionpath.h>
       
    26 #include <glxtracer.h>
       
    27 #include <glxlog.h>
       
    28 
       
    29 // user includes
       
    30 #include "glxlistutils.h"
       
    31 #include "glxmedia.h"
       
    32 #include "glxstaticitemlist.h"
       
    33 #include "mglxnavigablelistobserver.h"
       
    34 
       
    35 using namespace NGlxNavigableList;
       
    36 
       
    37 namespace NGlxNavigableList
       
    38     {
       
    39     
       
    40     /** 
       
    41      * Strategy to process selection indexes
       
    42      */ 
       
    43     class MSelectionIndexStrategy 
       
    44         {
       
    45     public:
       
    46         /** 
       
    47          * Process a single selection index
       
    48          * @param aSelectedItemIndex index in selected item index array to process
       
    49          */ 
       
    50         virtual void Process( TInt aSelectedItemIndex ) = 0;
       
    51         };
       
    52         
       
    53     /** 
       
    54      * Strategy to remove selection indexes
       
    55      */ 
       
    56     NONSHARABLE_CLASS( TRemoveSelectedItemIndexStrategy ) : 
       
    57             public MSelectionIndexStrategy
       
    58         {
       
    59     public:
       
    60         /**
       
    61          * Constructor
       
    62          * @param aSelectedItemIndices Selected item index array
       
    63          */
       
    64         TRemoveSelectedItemIndexStrategy( RArray< TInt>& aSelectedItemIndices )
       
    65                 : iSelectedItemIndices( aSelectedItemIndices )
       
    66             {
       
    67             }
       
    68 
       
    69         /** See @ref MSelectionIndexStrategy */
       
    70         void Process( TInt aSelectedItemIndex )
       
    71             {
       
    72             iSelectedItemIndices.Remove( aSelectedItemIndex );
       
    73             }
       
    74 
       
    75     private:
       
    76         /// Selected item indexes
       
    77         RArray< TInt>& iSelectedItemIndices; 
       
    78         };
       
    79 
       
    80     /** 
       
    81      * Strategy to move selection indexes
       
    82      */ 
       
    83     NONSHARABLE_CLASS( TMoveSelectedItemIndexStrategy ) : 
       
    84             public MSelectionIndexStrategy
       
    85         {
       
    86     public:
       
    87         /** 
       
    88          * Constructor 
       
    89          * @param aMoveCount a number of items to move index by
       
    90          */
       
    91         TMoveSelectedItemIndexStrategy( RArray< TInt>& aSelectedItemIndices, 
       
    92             TInt aMoveCount )
       
    93                 : iSelectedItemIndices( aSelectedItemIndices )
       
    94             {
       
    95             iMoveCount = aMoveCount;
       
    96             }
       
    97             
       
    98         /** See @ref MSelectionIndexStrategy */
       
    99         void Process( TInt aSelectedItemIndex )
       
   100             {
       
   101             iSelectedItemIndices[ aSelectedItemIndex ] += iMoveCount;
       
   102             }
       
   103         
       
   104     private: 
       
   105         /// The count of items to move by
       
   106         TInt iMoveCount;
       
   107         /// Selected item indexes
       
   108         RArray< TInt>& iSelectedItemIndices; 
       
   109         };
       
   110     
       
   111     } // namespace NGlxNavigableList
       
   112     
       
   113 // -----------------------------------------------------------------------------
       
   114 // Two-phase constructor
       
   115 // -----------------------------------------------------------------------------
       
   116 //
       
   117 CGlxNavigableList* CGlxNavigableList::NewL( const TGlxIdSpaceId& aIdSpaceId,
       
   118         MGlxNavigableListObserver& aObserver, MGlxMediaUser& aMediaUser )
       
   119     {
       
   120     TRACER("CGlxNavigableList::NewL");
       
   121             
       
   122     CGlxNavigableList* self = new (ELeave) CGlxNavigableList( aObserver );
       
   123     CleanupStack::PushL( self );
       
   124     self->ConstructL( aIdSpaceId, aMediaUser );
       
   125     CleanupStack::Pop( self );
       
   126     return self;
       
   127     }
       
   128     
       
   129 // -----------------------------------------------------------------------------
       
   130 // Constructor
       
   131 // -----------------------------------------------------------------------------
       
   132 //
       
   133 CGlxNavigableList::CGlxNavigableList( MGlxNavigableListObserver& aObserver ) :
       
   134         iFocusInitialPosition( NGlxListDefs::EFocusFirst ),
       
   135         iObserver( aObserver )
       
   136     {
       
   137     TRACER("CGlxNavigableList::CGlxNavigableList");
       
   138     
       
   139     iFocusIndex = KErrNotFound;
       
   140     }
       
   141 
       
   142 // -----------------------------------------------------------------------------
       
   143 // Second-phase constructor
       
   144 // -----------------------------------------------------------------------------
       
   145 //
       
   146 void CGlxNavigableList::ConstructL( const TGlxIdSpaceId& aIdSpaceId,
       
   147         MGlxMediaUser& aMediaUser )
       
   148     {
       
   149     TRACER("CGlxNavigableList::ConstructL");
       
   150     
       
   151     iItemList = CGlxStaticItemList::NewL( aIdSpaceId, *this, aMediaUser );
       
   152     
       
   153 
       
   154     }
       
   155 
       
   156 // -----------------------------------------------------------------------------
       
   157 // Destructor
       
   158 // -----------------------------------------------------------------------------
       
   159 //
       
   160 CGlxNavigableList::~CGlxNavigableList()
       
   161     {
       
   162     TRACER( "CGlxNavigableList::~CGlxNavigableList" );
       
   163     iSelectedItemIndices.Close();
       
   164     delete iItemList;
       
   165 
       
   166     
       
   167     }
       
   168 
       
   169 // -----------------------------------------------------------------------------
       
   170 // return id space id
       
   171 // -----------------------------------------------------------------------------
       
   172 // 
       
   173 const TGlxIdSpaceId& CGlxNavigableList::IdSpaceId() const
       
   174     {
       
   175     TRACER( "CGlxNavigableList::IdSpaceId");
       
   176     
       
   177     return iItemList->IdSpaceId();
       
   178     }
       
   179 
       
   180 // -----------------------------------------------------------------------------
       
   181 // Synchronise contents of the list with the collection path
       
   182 // -----------------------------------------------------------------------------
       
   183 //
       
   184 void CGlxNavigableList::SetContentsL( const CMPXCollectionPath& aPath,
       
   185         const MGlxMediaPool& aMediaPool )
       
   186     {
       
   187     TRACER( "CGlxNavigableList::SetContentsL" );
       
   188     iItemList->SetContentsL( aPath, aMediaPool );
       
   189     }
       
   190 
       
   191 // -----------------------------------------------------------------------------
       
   192 // Re-orders contents of the list with the collection path
       
   193 // -----------------------------------------------------------------------------
       
   194 //
       
   195 void CGlxNavigableList::ReorderContentsL( const CMPXCollectionPath& aPath, 
       
   196         const MGlxMediaPool& aMediaPool )
       
   197     {
       
   198     TRACER( "CGlxNavigableList::ReorderContentsL" );
       
   199     __TEST_INVARIANT;
       
   200 
       
   201     // List contents have been reordered. If we called SetContentsL directly,
       
   202     // the client would get semi-random (but correct) sequence of added/removed
       
   203     // notifications. To provide a cleaner notification, send only "all removed"
       
   204     // and "all added" notifications. 
       
   205     
       
   206     // store the focus and selection temporarily for restoring later-
       
   207     // (store ids; cannot store index, since indexes may change upon reorder)
       
   208     TGlxMediaId focusedItemId = FocusId();
       
   209 
       
   210     RArray< TGlxMediaId > selectedItemIds;
       
   211     CleanupClosePushL( selectedItemIds );
       
   212     SelectionL( selectedItemIds );
       
   213 
       
   214     // send notification "all items removed"
       
   215     ClearContentsL( aMediaPool );
       
   216 
       
   217     // set contents to reordered list, this removes focus and selection.
       
   218     // send notification of "all items added" (in new order)
       
   219     SetContentsL( aPath, aMediaPool );
       
   220 
       
   221     // restore focus and selection
       
   222     SetFocus( focusedItemId ); 
       
   223     SelectL( selectedItemIds );
       
   224 
       
   225     CleanupStack::PopAndDestroy( &selectedItemIds );
       
   226 
       
   227     __TEST_INVARIANT;
       
   228     }
       
   229 
       
   230 // -----------------------------------------------------------------------------
       
   231 // Remove an item form the list
       
   232 // -----------------------------------------------------------------------------
       
   233 //
       
   234 void CGlxNavigableList::Remove( const TGlxIdSpaceId& aIdSpaceId, 
       
   235         const TGlxMediaId& aItemId )
       
   236     {
       
   237     TRACER( "CGlxNavigableList::Remove" );
       
   238     iItemList->Remove( aIdSpaceId, aItemId );
       
   239     }
       
   240 
       
   241 // -----------------------------------------------------------------------------
       
   242 // Remove any pointers to the media object at the specified index
       
   243 // -----------------------------------------------------------------------------
       
   244 //
       
   245 void CGlxNavigableList::RemoveReference( TInt aIndex )
       
   246     {
       
   247     TRACER( "CGlxNavigableList::RemoveReference" );
       
   248     iItemList->RemoveReference( aIndex );
       
   249     }
       
   250     
       
   251 // -----------------------------------------------------------------------------
       
   252 // Add a static item
       
   253 // -----------------------------------------------------------------------------
       
   254 //
       
   255 void CGlxNavigableList::AddStaticItemL( CGlxMedia* aStaticItem, 
       
   256         NGlxListDefs::TInsertionPosition aTargetPosition )
       
   257     {
       
   258     TRACER( "CGlxNavigableList::AddStaticItemL" );
       
   259     iItemList->AddStaticItemL( aStaticItem, aTargetPosition );
       
   260     }
       
   261         
       
   262 // -----------------------------------------------------------------------------
       
   263 // Enable/disable static items
       
   264 // -----------------------------------------------------------------------------
       
   265 //
       
   266 void CGlxNavigableList::SetStaticItemsEnabled( TBool aEnabled )
       
   267     {
       
   268     TRACER( "CGlxNavigableList::SetStaticItemsEnabled" );
       
   269     iItemList->SetStaticItemsEnabled( aEnabled );
       
   270     }
       
   271     
       
   272 // -----------------------------------------------------------------------------
       
   273 // return ETrue if static items are enabled
       
   274 // -----------------------------------------------------------------------------
       
   275 //
       
   276 TBool CGlxNavigableList::IsStaticItemsEnabled() const
       
   277     {
       
   278     TRACER( "CGlxNavigableList::IsStaticItemsEnabled");
       
   279     
       
   280     return iItemList->IsStaticItemsEnabled();
       
   281     }
       
   282     
       
   283 // -----------------------------------------------------------------------------
       
   284 // Return count
       
   285 // -----------------------------------------------------------------------------
       
   286 //
       
   287 TInt CGlxNavigableList::Count( NGlxListDefs::TCountType aType ) const
       
   288     {
       
   289     TRACER( "CGlxNavigableList::Count");
       
   290     
       
   291     return iItemList->Count( aType );
       
   292     }
       
   293 
       
   294 // -----------------------------------------------------------------------------
       
   295 // Sets the initial focus position, first or last item
       
   296 // -----------------------------------------------------------------------------
       
   297 //
       
   298 void CGlxNavigableList::SetFocusInitialPosition(NGlxListDefs::TFocusInitialPosition aFocusInitialPosition)
       
   299     {
       
   300     TRACER( "CGlxNavigableList::SetFocusInitialPosition");
       
   301     
       
   302     iFocusInitialPosition = aFocusInitialPosition;
       
   303     SetInitialFocus();
       
   304     }
       
   305     
       
   306 // -----------------------------------------------------------------------------
       
   307 // Return focus index
       
   308 // -----------------------------------------------------------------------------
       
   309 //
       
   310 TInt CGlxNavigableList::FocusIndex() const 
       
   311     {
       
   312     TRACER( "CGlxNavigableList::FocusIndex");
       
   313     
       
   314     return iFocusIndex;
       
   315     }
       
   316 
       
   317 // -----------------------------------------------------------------------------
       
   318 // Set focus index
       
   319 // -----------------------------------------------------------------------------
       
   320 //
       
   321 void CGlxNavigableList::SetFocus( NGlxListDefs::TFocusSetType aType, TInt aValue )
       
   322     {
       
   323     TRACER( "CGlxNavigableList::SetFocus");
       
   324     GLX_LOG_INFO1( "CGlxNavigableList::SetFocus: Entry: %d", aValue );
       
   325     
       
   326     __TEST_INVARIANT;
       
   327 
       
   328     // Observer callback needs to know the focus change type
       
   329     NGlxListDefs::TFocusChangeType type = NGlxListDefs::EUnknown;
       
   330     
       
   331     TInt oldIndex = iFocusIndex;
       
   332 
       
   333     switch ( aType )
       
   334         {
       
   335         case NGlxListDefs::EAbsolute:
       
   336             type = SetFocus( aValue );
       
   337             break;
       
   338             
       
   339         case NGlxListDefs::ERelative:
       
   340             type = MoveFocus( aValue );
       
   341             break;
       
   342             
       
   343         default:
       
   344             Panic( EGlxPanicIllegalArgument ); // Unsupported focus change type
       
   345             break;
       
   346         }
       
   347 
       
   348 
       
   349 
       
   350     // notify observer if focus changed
       
   351     NotifyFocusChange( type, oldIndex,  iFocusIndex != oldIndex );
       
   352 
       
   353     __TEST_INVARIANT;
       
   354     GLX_LOG_INFO( "CGlxNavigableList::SetFocusL: Exit" );
       
   355     }
       
   356 
       
   357 // -----------------------------------------------------------------------------
       
   358 // Set focus by id
       
   359 // inline private member function only in cpp file, so will be inlined in arm
       
   360 // (ok as long as called only once)
       
   361 // -----------------------------------------------------------------------------
       
   362 //
       
   363 inline void CGlxNavigableList::SetFocus( const TGlxMediaId& aItemId )
       
   364     {
       
   365     TRACER( "CGlxNavigableList::SetFocus");
       
   366     
       
   367     TInt index = Index( IdSpaceId(), aItemId );
       
   368     if ( KErrNotFound != index )
       
   369         {
       
   370         // Focus the item if it still exists in the new list
       
   371         SetFocus( NGlxListDefs::EAbsolute, index );
       
   372         }
       
   373     }
       
   374 
       
   375 // -----------------------------------------------------------------------------
       
   376 // Set focus index
       
   377 // -----------------------------------------------------------------------------
       
   378 //
       
   379 NGlxListDefs::TFocusChangeType CGlxNavigableList::SetFocus( TInt aIndex )
       
   380     {
       
   381     TRACER( "CGlxNavigableList::SetFocus");
       
   382     __ASSERT_ALWAYS( aIndex >= 0 && aIndex < Count(), Panic( EGlxPanicIllegalArgument ) );
       
   383 
       
   384     iFocusIndex = aIndex;
       
   385 
       
   386     // it is not possible to know which direction focus was moving, since
       
   387     // client did not specify it. Looping of the list makes it impossible to 
       
   388     // compare the old and new index. 
       
   389     return NGlxListDefs::EUnknown;
       
   390     }
       
   391 
       
   392 // -----------------------------------------------------------------------------
       
   393 // Move focus index
       
   394 // inline private member function only in cpp file, so will be inlined in arm
       
   395 // (ok as long as called only once)
       
   396 // -----------------------------------------------------------------------------
       
   397 //
       
   398 inline NGlxListDefs::TFocusChangeType CGlxNavigableList::MoveFocus( TInt aDelta )
       
   399     {
       
   400     TRACER( "CGlxNavigableList::MoveFocus");
       
   401     
       
   402     // Moving focus in not possible when the list is empty
       
   403     if ( KErrNotFound != iFocusIndex )
       
   404         {
       
   405         // Move focus index
       
   406         iFocusIndex += aDelta;
       
   407         
       
   408         // wrap back into the loop
       
   409         iFocusIndex = GlxListUtils::NormalizedIndex( iFocusIndex, Count() );
       
   410 
       
   411         // determine direction of focus change
       
   412         if ( aDelta > 0 )
       
   413             {
       
   414             return NGlxListDefs::EForward;
       
   415             }
       
   416         // client won't be notified if aDelta is 0, so it is suitable
       
   417         // to return EBackward, even if focus does not move
       
   418         return NGlxListDefs::EBackward;
       
   419         }
       
   420         
       
   421     return NGlxListDefs::EUnknown;
       
   422     }
       
   423 
       
   424 // -----------------------------------------------------------------------------
       
   425 // Notify observers of focus change
       
   426 // -----------------------------------------------------------------------------
       
   427 //
       
   428 void CGlxNavigableList::NotifyFocusChange( NGlxListDefs::TFocusChangeType aType, 
       
   429         TInt aOldIndex, TBool aNotify )
       
   430     {
       
   431     TRACER( "CGlxNavigableList::NotifyFocusChange");
       
   432     
       
   433     if ( aNotify )
       
   434         {
       
   435         iObserver.HandleFocusChanged( aType, iFocusIndex, aOldIndex );
       
   436         }
       
   437     }
       
   438     
       
   439 // -----------------------------------------------------------------------------
       
   440 // Sets the initial focus
       
   441 // -----------------------------------------------------------------------------
       
   442 //
       
   443 void CGlxNavigableList::SetInitialFocus()
       
   444     {
       
   445     TRACER( "CGlxNavigableList::SetInitialFocus");
       
   446     
       
   447     // Only need to set focus if there are some items
       
   448     if ( Count() )
       
   449         {
       
   450         if ( iFocusInitialPosition == NGlxListDefs::EFocusFirst )
       
   451             {
       
   452             iFocusIndex = 0;
       
   453             }
       
   454         else // iFocusInitialPosition == NGlxListDefs::EFocusLast
       
   455             {
       
   456             iFocusIndex = Count() - 1;
       
   457             }
       
   458         }
       
   459     }
       
   460 
       
   461 // -----------------------------------------------------------------------------
       
   462 // Resets the focus to the initial position
       
   463 // -----------------------------------------------------------------------------
       
   464 //
       
   465 void CGlxNavigableList::ResetFocus()
       
   466     {
       
   467     TRACER( "CGlxNavigableList::ResetFocus");
       
   468     
       
   469     TInt oldFocusIndex = iFocusIndex;
       
   470 
       
   471     SetInitialFocus();
       
   472 
       
   473     // notify of focus change after resetting focus
       
   474     // Only need to notify if there are some items
       
   475     if( Count() )
       
   476     	{
       
   477     NotifyFocusChange( NGlxListDefs::EUnknown, oldFocusIndex, ETrue );
       
   478     	}
       
   479     }
       
   480 
       
   481 // -----------------------------------------------------------------------------
       
   482 // Return item by index
       
   483 // -----------------------------------------------------------------------------
       
   484 //
       
   485 TGlxMedia& CGlxNavigableList::Item( TInt aIndex )
       
   486     {
       
   487     TRACER( "CGlxNavigableList::Item");
       
   488     
       
   489     return iItemList->Item( aIndex );
       
   490     }
       
   491 
       
   492 // -----------------------------------------------------------------------------
       
   493 // Return index by id
       
   494 // -----------------------------------------------------------------------------
       
   495 //
       
   496 TInt CGlxNavigableList::Index(const TGlxIdSpaceId& aIdSpaceId, const TGlxMediaId& aId ) const
       
   497     {
       
   498     TRACER( "CGlxNavigableList::Index");
       
   499     
       
   500     return iItemList->Index(aIdSpaceId, aId );
       
   501     }
       
   502 
       
   503 // -----------------------------------------------------------------------------
       
   504 // Return whether item at index is selected
       
   505 // -----------------------------------------------------------------------------
       
   506 //
       
   507 TBool CGlxNavigableList::IsSelected(TInt aIndex) const
       
   508     {
       
   509     TRACER( "CGlxNavigableList::IsSelected");
       
   510     
       
   511     return ( KErrNotFound != iSelectedItemIndices.FindInOrder( aIndex ) );
       
   512     }
       
   513 
       
   514 // -----------------------------------------------------------------------------
       
   515 // Select/deselect item
       
   516 // -----------------------------------------------------------------------------
       
   517 //
       
   518 void CGlxNavigableList::SetSelectedL( TInt aIndex, TBool aSelected )
       
   519     {
       
   520     TRACER( "CGlxNavigableList::SetSelectedL");    
       
   521     GLX_LOG_INFO2( "CGlxNavigableList::SetSelectedL: index %d selected %b", 
       
   522             aIndex, aSelected );
       
   523     __TEST_INVARIANT;
       
   524     
       
   525     if ( aSelected )
       
   526         {
       
   527         SelectL( aIndex );
       
   528         }
       
   529     else
       
   530         {
       
   531         Deselect( aIndex );
       
   532         }
       
   533 
       
   534     __TEST_INVARIANT;
       
   535     }
       
   536 
       
   537 // -----------------------------------------------------------------------------
       
   538 // Return id of focused item or KGlxIdNone
       
   539 // inline private member function only in cpp file, so will be inlined in arm
       
   540 // (ok as long as called only once)
       
   541 // -----------------------------------------------------------------------------
       
   542 //
       
   543 inline TGlxMediaId CGlxNavigableList::FocusId() const
       
   544     {
       
   545     TRACER( "CGlxNavigableList::FocusId");
       
   546     
       
   547     if ( KErrNotFound != iFocusIndex )
       
   548         {
       
   549         return iItemList->Item( iFocusIndex ).Id();
       
   550         }
       
   551     return KGlxIdNone;
       
   552     }
       
   553 
       
   554 // -----------------------------------------------------------------------------
       
   555 // Return id of focused item or KGlxIdNone
       
   556 // inline private member function only in cpp file, so will be inlined in arm
       
   557 // (ok as long as called only once)
       
   558 // -----------------------------------------------------------------------------
       
   559 //
       
   560 inline void CGlxNavigableList::SelectionL( RArray< TGlxMediaId >& aItemIds ) const
       
   561     {
       
   562     TRACER( "CGlxNavigableList::SelectionL");
       
   563     
       
   564     aItemIds.Reset();
       
   565 
       
   566     // Reserve full required space to avoid reallocations during loop
       
   567     aItemIds.ReserveL( iSelectedItemIndices.Count() );
       
   568 
       
   569     TInt count = iSelectedItemIndices.Count();
       
   570     for ( TInt i = 0; i < count; ++i )
       
   571         {
       
   572         aItemIds.AppendL( iItemList->Item( iSelectedItemIndices[ i ] ).Id() );
       
   573         }
       
   574     }
       
   575 
       
   576 // -----------------------------------------------------------------------------
       
   577 // Clear list contents
       
   578 // inline private member function only in cpp file, so will be inlined in arm
       
   579 // (ok as long as called only once)
       
   580 // -----------------------------------------------------------------------------
       
   581 //
       
   582 inline void CGlxNavigableList::ClearContentsL( const MGlxMediaPool& aMediaPool )
       
   583     {
       
   584     TRACER( "CGlxNavigableList::ClearContentsL");
       
   585     
       
   586     // Create a path with no items in order to empty the list
       
   587     CMPXCollectionPath* emptyPath = CMPXCollectionPath::NewL();
       
   588     CleanupStack::PushL( emptyPath );
       
   589 
       
   590     iItemList->SetContentsL( *emptyPath, aMediaPool );
       
   591 
       
   592     CleanupStack::PopAndDestroy( emptyPath );
       
   593     }
       
   594 
       
   595 // -----------------------------------------------------------------------------
       
   596 // Select items by id
       
   597 // inline private member function only in cpp file, so will be inlined in arm
       
   598 // (ok as long as called only once)
       
   599 // -----------------------------------------------------------------------------
       
   600 //
       
   601 inline void CGlxNavigableList::SelectL( const RArray< TGlxMediaId >& aItemIds ) 
       
   602     {
       
   603     TRACER( "CGlxNavigableList::SelectL");
       
   604     
       
   605     // Reserve free space for the full selection, so that the operation can
       
   606     // be atomic
       
   607     ReserveFreeSpaceInSelectionL( aItemIds.Count() );
       
   608 
       
   609     // pick id space id locally to avoid re-retrieving during the loop
       
   610     TGlxIdSpaceId idSpaceId = IdSpaceId();
       
   611 
       
   612     // Select the requested items     
       
   613     TInt count = aItemIds.Count();
       
   614     for ( TInt i = 0; i < count; i++ )
       
   615         {
       
   616         TInt index = Index( idSpaceId, aItemIds[ i ] );
       
   617         if ( index != KErrNotFound )
       
   618             {
       
   619             Select( index );
       
   620             }
       
   621         }    
       
   622     }
       
   623     
       
   624 // -----------------------------------------------------------------------------
       
   625 // Select item
       
   626 // inline private member function only in cpp file, so will be inlined in arm
       
   627 // (ok as long as called only once)
       
   628 // -----------------------------------------------------------------------------
       
   629 //
       
   630 inline void CGlxNavigableList::SelectL( TInt aIndex )
       
   631     {
       
   632     TRACER( "CGlxNavigableList::SelectL");
       
   633     
       
   634     // Don't allow static items to be selected
       
   635     if ( !Item( aIndex ).IsStatic() )
       
   636         {
       
   637         ReserveFreeSpaceInSelectionL( 1 );
       
   638         Select( aIndex );
       
   639         }
       
   640     }
       
   641 
       
   642 // -----------------------------------------------------------------------------
       
   643 // Select item. Must call ReserveFreeSpaceInSelectionL before
       
   644 // -----------------------------------------------------------------------------
       
   645 //
       
   646 void CGlxNavigableList::Select( TInt aIndex )
       
   647     {
       
   648     TRACER( "CGlxNavigableList::Select");
       
   649     
       
   650     __ASSERT_DEBUG( _iSelectionReserveCount > 0, Panic( EGlxPanicNoReservation ) ); // No reservation made
       
   651     __DEBUG_ONLY( _iSelectionReserveCount-- );
       
   652     
       
   653     // returns KErrNone if inserted successfully, KErrAlreadyExists if already exists
       
   654     if ( KErrNone == iSelectedItemIndices.InsertInOrder( aIndex ) )
       
   655         {
       
   656         iObserver.HandleItemSelected( aIndex, ETrue );
       
   657         }
       
   658     }
       
   659 
       
   660 // -----------------------------------------------------------------------------
       
   661 // Reserve free space is selected item indexes array
       
   662 // -----------------------------------------------------------------------------
       
   663 //
       
   664 inline void CGlxNavigableList::ReserveFreeSpaceInSelectionL( TInt aCount )
       
   665     {
       
   666     TRACER( "CGlxNavigableList::ReserveFreeSpaceInSelectionL");
       
   667     
       
   668     iSelectedItemIndices.ReserveL( iSelectedItemIndices.Count() + aCount );
       
   669     
       
   670     // store reservation count so can protect agains Select(...) being called
       
   671     // without reservation
       
   672     __DEBUG_ONLY( _iSelectionReserveCount = aCount );
       
   673     }
       
   674         
       
   675 // -----------------------------------------------------------------------------
       
   676 // Deselect item
       
   677 // inline private member function only in cpp file, so will be inlined in arm
       
   678 // (ok as long as called only once)
       
   679 // -----------------------------------------------------------------------------
       
   680 //
       
   681 inline void CGlxNavigableList::Deselect( TInt aIndex )
       
   682     {
       
   683     TRACER( "CGlxNavigableList::Deselect");
       
   684     
       
   685     // item has been deselected, remove if found
       
   686     TInt selectionArrayIndex = iSelectedItemIndices.FindInOrder( aIndex );
       
   687     if ( KErrNotFound != selectionArrayIndex )
       
   688         {
       
   689         // remove from array of selected items
       
   690         iSelectedItemIndices.Remove( selectionArrayIndex );
       
   691         
       
   692         // free unused memory from selected item indexes array
       
   693         // (this call may be a performance bottleneck if executing unmark all
       
   694         //  in a list of many thousands of items when most of them are marked.
       
   695         //  if it is proved to be a performance bottleneck, it may be sensible
       
   696         //  to count how many times Deselect has been called, an only
       
   697         //  compress every x times.)
       
   698         //iSelectedItemIndices.Compress();
       
   699         
       
   700         // selection has changed, notify observer
       
   701         iObserver.HandleItemSelected( aIndex, EFalse );
       
   702         }
       
   703     // else: ignore if item was not selected
       
   704     }
       
   705 
       
   706 // -----------------------------------------------------------------------------
       
   707 // Return selected items
       
   708 // -----------------------------------------------------------------------------
       
   709 //
       
   710 const TArray< TInt > CGlxNavigableList::SelectedItemIndices() const
       
   711     {
       
   712     TRACER( "CGlxNavigableList::SelectedItemIndices");
       
   713     
       
   714     return iSelectedItemIndices.Array();
       
   715     }
       
   716 
       
   717 // -----------------------------------------------------------------------------
       
   718 // Handle items being added
       
   719 // -----------------------------------------------------------------------------
       
   720 //
       
   721 void CGlxNavigableList::HandleItemsAdded( TInt aFirstInsertedIndex, 
       
   722         TInt aCount )
       
   723     {
       
   724     TRACER( "CGlxNavigableList::HandleItemsAdded" );
       
   725 
       
   726     // Do not test invariant in the beginning of this function. Right now,
       
   727     // the state is not valid, since iItemList's state has already changed, and
       
   728     // this function will align the state of this object with iItemList.
       
   729 
       
   730     // Move selection indexes from insertion point 
       
   731     TMoveSelectedItemIndexStrategy moveStrategy( iSelectedItemIndices, aCount );
       
   732     ProcessSelectionItemIndicesBetweenIndexes( aFirstInsertedIndex, 
       
   733         Count( NGlxListDefs::ECountAll ), moveStrategy );
       
   734 
       
   735     // move focus
       
   736     TInt oldFocusIndex = iFocusIndex;
       
   737     TInt notifyOfFocusChange = UpdateFocusAfterInsertion( aFirstInsertedIndex, aCount );
       
   738 
       
   739     // Adjust index by amount of static items
       
   740     iObserver.HandleItemsAdded( aFirstInsertedIndex, aCount );
       
   741     
       
   742     // notify of focus change after having notified of items being added,
       
   743     // so that focus index points to the correct real item on client side
       
   744     NotifyFocusChange( NGlxListDefs::EUnknown, oldFocusIndex, 
       
   745             notifyOfFocusChange );
       
   746     __TEST_INVARIANT;
       
   747     }
       
   748 
       
   749 // -----------------------------------------------------------------------------
       
   750 // Move focus after items have been inserted
       
   751 // inline private member function only in cpp file, so will be inlined in arm
       
   752 // (ok as long as called only once)
       
   753 // -----------------------------------------------------------------------------
       
   754 //
       
   755 inline TInt CGlxNavigableList::UpdateFocusAfterInsertion( TInt aInsertionIndex, 
       
   756         TInt aInsertionCount )  
       
   757     {
       
   758      TRACER( "CGlxNavigableList::UpdateFocusAfterInsertion" );
       
   759      
       
   760     // Move focus if index is changed.
       
   761     TBool notifyObserver = MoveFocusIfIndexChanged( aInsertionIndex, aInsertionCount );
       
   762         
       
   763     // Set focus to initial focus position if not previously set. Test also that count larger 
       
   764     // than zero, just to be safe for future maintenance of other classes
       
   765     if ( KErrNotFound == iFocusIndex && Count( NGlxListDefs::ECountAll ) > 0 )
       
   766         {
       
   767         GLX_LOG_INFO("iFocusIndex is KErrNotFound");
       
   768 
       
   769         // Set initial focus position
       
   770         SetInitialFocus();
       
   771 
       
   772         notifyObserver = ETrue;
       
   773         }
       
   774     
       
   775     return notifyObserver;
       
   776     }
       
   777 
       
   778 // -----------------------------------------------------------------------------
       
   779 // Move focus if index is changed.
       
   780 // -----------------------------------------------------------------------------
       
   781 //
       
   782 TBool CGlxNavigableList::MoveFocusIfIndexChanged( TInt aChangedIndex, TInt aMoveBy )  
       
   783     {
       
   784     TRACER( "CGlxNavigableList::MoveFocusIfIndexChanged" );
       
   785     
       
   786     if ( iFocusIndex >= aChangedIndex )
       
   787        {
       
   788 	       iFocusIndex += aMoveBy;
       
   789 	       return ETrue; // notify observer
       
   790        }
       
   791        
       
   792        return EFalse; // don't notify observer
       
   793     }
       
   794 
       
   795 // -----------------------------------------------------------------------------
       
   796 // Handle items being removed
       
   797 // -----------------------------------------------------------------------------
       
   798 //
       
   799 void CGlxNavigableList::HandleItemsRemoved( TInt aRemovedFromIndex, TInt aCount )  
       
   800     {
       
   801     TRACER( "CGlxNavigableList::HandleItemsRemoved" );
       
   802 
       
   803     // Do not test invariant in the beginning of this function. Right now,
       
   804     // the state is not valid, since iItemList's state has already changed, and
       
   805     // this function will align the state of this object with iItemList.
       
   806 
       
   807     // update selection
       
   808     UpdateSelectionAfterRemove( aRemovedFromIndex, aCount );
       
   809     TInt oldFocusIndex = iFocusIndex;
       
   810     TBool notifyOfFocusChange = UpdateFocusAfterRemoval( aRemovedFromIndex, 
       
   811         aCount );
       
   812     
       
   813     // notify observer
       
   814     iObserver.HandleItemsRemoved( aRemovedFromIndex, aCount );
       
   815     
       
   816     // notify of focus change after having notified of items being removed,
       
   817     // so that focus index points to the correct real item on client side
       
   818     NotifyFocusChange( NGlxListDefs::EUnknown, oldFocusIndex, 
       
   819                 notifyOfFocusChange );
       
   820     __TEST_INVARIANT;
       
   821     }
       
   822 
       
   823 // -----------------------------------------------------------------------------
       
   824 // Update selection after remove
       
   825 // inline private member function only in cpp file, so will be inlined in arm
       
   826 // (ok as long as called only once)
       
   827 // -----------------------------------------------------------------------------
       
   828 //
       
   829 inline void CGlxNavigableList::UpdateSelectionAfterRemove( TInt aRemovedFromIndex, 
       
   830         TInt aRemovedCount )
       
   831     {
       
   832     TRACER( "CGlxNavigableList::UpdateSelectionAfterRemove");
       
   833     
       
   834     // remove items from selected list that were removed
       
   835     TRemoveSelectedItemIndexStrategy removeStrategy( iSelectedItemIndices );
       
   836     ProcessSelectionItemIndicesBetweenIndexes( aRemovedFromIndex, 
       
   837         aRemovedFromIndex + aRemovedCount, removeStrategy );
       
   838     
       
   839     // move selection indexes from removal point 
       
   840     TMoveSelectedItemIndexStrategy moveStrategy( iSelectedItemIndices, -aRemovedCount );
       
   841     ProcessSelectionItemIndicesBetweenIndexes( aRemovedFromIndex + aRemovedCount, 
       
   842         KMaxTInt, moveStrategy );
       
   843     }
       
   844 
       
   845 // -----------------------------------------------------------------------------
       
   846 // Move focus after items have been removed
       
   847 // inline private member function only in cpp file, so will be inlined in arm
       
   848 // (ok as long as called only once)
       
   849 // -----------------------------------------------------------------------------
       
   850 //
       
   851 inline TBool CGlxNavigableList::UpdateFocusAfterRemoval( TInt aRemovedFromIndex, 
       
   852         TInt aRemovedCount )  
       
   853     {
       
   854     TRACER( "CGlxNavigableList::UpdateFocusAfterRemoval");
       
   855     
       
   856     // Assume focus will be changed (simplifies code below)
       
   857     TBool notifyObserver = EFalse;   
       
   858     
       
   859     // move focus if it is after the last removed item (incl. list has become empty)
       
   860     if ( iFocusIndex >= aRemovedFromIndex + aRemovedCount )
       
   861         {
       
   862         iFocusIndex -= aRemovedCount;        
       
   863         // although the focus did not logically change in this case, notify
       
   864         // anyway to simplify client code
       
   865         notifyObserver = ETrue;
       
   866         }
       
   867     // move focus if it is on removed items
       
   868     else if ( iFocusIndex >= aRemovedFromIndex )
       
   869         {
       
   870         iFocusIndex = Min( aRemovedFromIndex, Count() - 1 );
       
   871         notifyObserver = ETrue;
       
   872         }
       
   873     // else focus is before removed items, so do nothing       
       
   874 
       
   875     return notifyObserver;
       
   876     }
       
   877 
       
   878 // -----------------------------------------------------------------------------
       
   879 // Remove selection indices between two indexes
       
   880 // -----------------------------------------------------------------------------
       
   881 //
       
   882 void CGlxNavigableList::ProcessSelectionItemIndicesBetweenIndexes( 
       
   883         TInt aFromIndex, TInt aToIndex, MSelectionIndexStrategy& aStrategy )
       
   884     {
       
   885     TRACER("CGlxNavigableList::ProcessSelectionItemIndicesBetweenIndexes");
       
   886     
       
   887     // Find first selection item index that points to an index larger or equal
       
   888     // than aFromIndex
       
   889     TInt selectedItemIndex = FindFirstSelectedItemIndexBefore( aToIndex );
       
   890     // Process until finds a selection item index pointing to an item smaller 
       
   891     // than aFromIndex
       
   892     while ( selectedItemIndex >= 0 && 
       
   893             iSelectedItemIndices[ selectedItemIndex ] >= aFromIndex ) 
       
   894         {
       
   895         aStrategy.Process( selectedItemIndex );
       
   896         selectedItemIndex--;
       
   897         }
       
   898     }
       
   899 
       
   900 // -----------------------------------------------------------------------------
       
   901 // Return first selection item index on or after
       
   902 // -----------------------------------------------------------------------------
       
   903 //
       
   904 inline TInt CGlxNavigableList::FindFirstSelectedItemIndexBefore( TInt aMaxIndex )
       
   905     {
       
   906     TRACER( "CGlxNavigableList::FindFirstSelectedItemIndexBefore");
       
   907     
       
   908     // Find first selection item index that points to an index larger or equal
       
   909     // than aAtLeastIndex
       
   910     TInt i = iSelectedItemIndices.Count() - 1;
       
   911     while ( i >= 0 )
       
   912         {
       
   913         if ( iSelectedItemIndices[i] < aMaxIndex )
       
   914             {
       
   915             break;
       
   916             }
       
   917         i--;
       
   918         }
       
   919     
       
   920     // KErrNotFound == -1, which will be returned if the loop did not break
       
   921     return i; 
       
   922     }
       
   923 
       
   924 // ---------------------------------------------------------------------------
       
   925 // Test invariant
       
   926 // ---------------------------------------------------------------------------
       
   927 void CGlxNavigableList::__DbgTestInvariant() const
       
   928     {
       
   929     TRACER( "CGlxNavigableList::__DbgTestInvariant");
       
   930     
       
   931     #if 0
       
   932     //def _DEBUG
       
   933 
       
   934     // focus index must be KErrNotFound if list is empty
       
   935     __ASSERT_DEBUG( iFocusIndex == KErrNotFound || iItemList->Count( NGlxListDefs::ECountAll ), Panic( EGlxPanicIllegalState ) ); 
       
   936     // focus index must be between 0 and count if list is not empty
       
   937     __ASSERT_DEBUG( ( iFocusIndex >= 0 && 
       
   938                       iFocusIndex < iItemList->Count( NGlxListDefs::ECountAll ) ) || 
       
   939                       !iItemList->Count( NGlxListDefs::ECountAll ), 
       
   940                       Panic( EGlxPanicIllegalState ) ); 
       
   941     // max count amount of items can be selected
       
   942     __ASSERT_DEBUG( iSelectedItemIndices.Count() <= iItemList->Count( NGlxListDefs::ECountAll ), Panic( EGlxPanicIllegalState ) ); 
       
   943     // test selection item index array
       
   944     TInt previousSelectedIndex = -1;
       
   945     for ( TInt i = 0; i < iSelectedItemIndices.Count(); i++ )
       
   946         {
       
   947         // index must be between zero and count
       
   948         __ASSERT_DEBUG( iSelectedItemIndices[ i ] >= 0 && iSelectedItemIndices[ i ] < iItemList->Count( NGlxListDefs::ECountAll ), Panic( EGlxPanicIllegalState ) ); 
       
   949         // index must not be in order
       
   950         __ASSERT_DEBUG( iSelectedItemIndices[ i ] > previousSelectedIndex, Panic( EGlxPanicIllegalState ) ); 
       
   951         // prepare next round
       
   952         previousSelectedIndex = iSelectedItemIndices[ i ];
       
   953         }
       
   954     
       
   955     #endif // _DEBUG
       
   956     }