photosgallery/viewframework/medialists/src/glxlistwindow.cpp
branchRCL_3
changeset 60 5b3385a43d68
equal deleted inserted replaced
59:8e5f6eea9c9f 60:5b3385a43d68
       
     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:    Window to a list of objects
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 
       
    20 
       
    21 #include "glxlistwindow.h"
       
    22 
       
    23 #include "glxpanic.h"
       
    24 #include "glxlistutils.h" //for GlxListUtils
       
    25 #include <glxtracer.h>                 //For logging
       
    26 // -----------------------------------------------------------------------------
       
    27 // -----------------------------------------------------------------------------
       
    28 // CGlxDataWindow 
       
    29 // -----------------------------------------------------------------------------
       
    30 // -----------------------------------------------------------------------------
       
    31 //
       
    32 class CGlxDataWindow : public CBase 
       
    33     {
       
    34     friend class TGlxWindowIterator;
       
    35 public:
       
    36     /** Destructor*/
       
    37     ~CGlxDataWindow()
       
    38         {
       
    39         iObjects.Close();
       
    40         }
       
    41         
       
    42     /** Destroy contents of the window */
       
    43     void Destroy()
       
    44         {
       
    45         iObjects.ResetAndDestroy();
       
    46         }
       
    47         
       
    48     /** Reserve max window size */
       
    49     inline void ReserveL( TInt aMaxCount )
       
    50         {
       
    51         iObjects.ReserveL( aMaxCount );
       
    52         }
       
    53         
       
    54     /** Preparet the window to accept items */
       
    55     void InitializeL( const CGlxListWindow::TRange& aRange, TInt aTotalSize )
       
    56         {
       
    57         __TEST_INVARIANT;
       
    58         
       
    59         iTotalSize = aTotalSize;    
       
    60         // use GlxListUtils::NormalizedIndex instead of Normalize to avoid 
       
    61         // execution-order dependency to the setting of iTotalSize
       
    62         iWindowStartIndex = GlxListUtils::NormalizedIndex( aRange.iStartIndex, iTotalSize );
       
    63         
       
    64         // all existing pointers in the array are NULL, as they have been 
       
    65         // set so by PopulateExistingAndUnuseOld
       
    66         
       
    67         // add sufficient number of new null pointers
       
    68         for ( TInt i = iObjects.Count(); i < aRange.iLength; i++ ) 
       
    69             {
       
    70             // Append cannot fail since reservation has been made
       
    71             ( void ) iObjects.AppendL( NULL );
       
    72             }
       
    73 
       
    74         // remove unnecessary pointers
       
    75         for ( TInt i = iObjects.Count() - 1; i >= aRange.iLength; i-- )
       
    76             {
       
    77             iObjects.Remove( i );
       
    78             }
       
    79             
       
    80         __TEST_INVARIANT;
       
    81         }
       
    82         
       
    83     /** @return an iterator that can iterate throught the items in window */
       
    84     inline TGlxWindowIterator Iterator() const
       
    85         {
       
    86         return TGlxWindowIterator( *this );
       
    87         }
       
    88         
       
    89     /** @return whether the list index is within range */
       
    90     inline TBool InRange( TInt aListIndex ) const
       
    91         {
       
    92         return KErrNotFound != WindowIndex( aListIndex );
       
    93         }
       
    94 
       
    95     inline CBase*& operator[] ( TInt aListIndex )
       
    96         {
       
    97         return iObjects[ WindowIndex( aListIndex ) ];
       
    98         }
       
    99         
       
   100     /** @return the length of the window */
       
   101     inline TInt Size() const
       
   102         {
       
   103         return iObjects.Count();
       
   104         }
       
   105         
       
   106     /** @return the total length of the list */
       
   107     inline TInt TotalSize() const
       
   108         {
       
   109         return iTotalSize;
       
   110         }
       
   111         
       
   112 private:        
       
   113     /** convert a window index to list index */
       
   114     TInt ListIndex( TInt aWindowIndex ) const
       
   115         {
       
   116     	__ASSERT_DEBUG( aWindowIndex >= 0 && aWindowIndex < Size(), Panic( EGlxPanicIllegalArgument ) ); 
       
   117         return Normalize( aWindowIndex + iWindowStartIndex );
       
   118     	}
       
   119 
       
   120     /** convert a list index to window index */
       
   121     /// @todo Make this private
       
   122     TInt WindowIndex( TInt aListIndex ) const
       
   123         {
       
   124         if ( KErrNotFound == aListIndex )
       
   125             {
       
   126             return KErrNotFound;
       
   127             }
       
   128 
       
   129     	__ASSERT_DEBUG( aListIndex >= 0 && aListIndex < iTotalSize, Panic( EGlxPanicIllegalArgument ) );
       
   130     	
       
   131     	// Convert the list index to a window index
       
   132     	TInt windowIndex = Normalize( aListIndex - iWindowStartIndex );
       
   133     	if ( windowIndex >= Size() ) 
       
   134     		{
       
   135     		return KErrNotFound; // Does not fit to the window
       
   136     		}
       
   137     	return windowIndex; 
       
   138     	}
       
   139         
       
   140     /** Normalise index to list length */
       
   141     inline TInt Normalize( TInt aIndex ) const
       
   142         {
       
   143         return GlxListUtils::NormalizedIndex( aIndex, iTotalSize );
       
   144         }
       
   145     
       
   146     /** Test state */
       
   147     void __DbgTestInvariant() const
       
   148         {
       
   149         __ASSERT_DEBUG(iTotalSize >= 0 && iTotalSize < 50000, Panic(EGlxPanicIllegalState)); // Sanity check
       
   150         __ASSERT_DEBUG(iObjects.Count() <= iTotalSize, Panic(EGlxPanicIllegalState));
       
   151         }
       
   152       
       
   153 private:   
       
   154     /// Full size of the list
       
   155 	TInt iTotalSize;
       
   156 	
       
   157 	/// Index of the first object in iWindow in the list,
       
   158 	/// i.e., the list index from which the window starts from
       
   159 	TInt iWindowStartIndex;
       
   160 	
       
   161     /// List of objects in the window, starting from iWindowStartIndex
       
   162     RPointerArray< CBase > iObjects;
       
   163     };
       
   164     
       
   165 // -----------------------------------------------------------------------------
       
   166 // -----------------------------------------------------------------------------
       
   167 // -----------------------------------------------------------------------------
       
   168 
       
   169 // -----------------------------------------------------------------------------
       
   170 // Constructor
       
   171 // -----------------------------------------------------------------------------
       
   172 TGlxWindowIterator::TGlxWindowIterator( const CGlxDataWindow& aWindow )    
       
   173     {
       
   174     TRACER("TGlxWindowIterator::TGlxWindowIterator");
       
   175     
       
   176     iWindow = &aWindow;
       
   177     iWindowIndex = 0;
       
   178     }
       
   179     
       
   180 // -----------------------------------------------------------------------------
       
   181 // Constructor
       
   182 // -----------------------------------------------------------------------------
       
   183 EXPORT_C TGlxWindowIterator::TGlxWindowIterator( const TGlxWindowIterator& aIterator ) 
       
   184     {
       
   185     TRACER("TGlxWindowIterator::TGlxWindowIterator");
       
   186     
       
   187     iWindow = aIterator.iWindow;
       
   188     iWindowIndex = aIterator.iWindowIndex;
       
   189     }
       
   190     
       
   191 // -----------------------------------------------------------------------------
       
   192 // ++
       
   193 // -----------------------------------------------------------------------------
       
   194 EXPORT_C TInt TGlxWindowIterator::operator++( TInt ) 
       
   195     {
       
   196     TRACER("TGlxWindowIterator::operator++");
       
   197     
       
   198     if ( iWindowIndex == iWindow->iObjects.Count() ) 
       
   199         {
       
   200         return KErrNotFound;
       
   201         }
       
   202     return iWindow->ListIndex( iWindowIndex++ );
       
   203     }
       
   204     
       
   205 // -----------------------------------------------------------------------------
       
   206 // -----------------------------------------------------------------------------
       
   207 // -----------------------------------------------------------------------------
       
   208 
       
   209 // -----------------------------------------------------------------------------
       
   210 // TChange
       
   211 // -----------------------------------------------------------------------------
       
   212 //    
       
   213 CGlxListWindow::TChange::TChange( TInt aNewFocusIndex, TInt aNewTotalSize, TChangeType aChangeType, 
       
   214         TInt aFirstChangedIndex, TInt aLastChangedIndex )   
       
   215     {
       
   216     TRACER("TChange::Default Constructor");
       
   217     
       
   218     iNewFocusIndex = aNewFocusIndex;
       
   219     iNewTotalSize = aNewTotalSize;
       
   220     iChangeType = aChangeType;
       
   221     iFirstChangedIndex = aFirstChangedIndex;
       
   222     iLastChangedIndex = aLastChangedIndex;
       
   223     }
       
   224     
       
   225 // -----------------------------------------------------------------------------
       
   226 // Constructor
       
   227 // -----------------------------------------------------------------------------
       
   228 //
       
   229 EXPORT_C CGlxListWindow::CGlxListWindow( MGlxWindowObjectFactory& aObjectFactory ) 
       
   230         : iObjectFactory( aObjectFactory )
       
   231 	{
       
   232 	TRACER("CGlxListWindow::Default Constructor");
       
   233 	
       
   234     iFocusIndex = KErrNotFound; // No items, hence no focus
       
   235 	}
       
   236     
       
   237 // -----------------------------------------------------------------------------
       
   238 // ConstructL
       
   239 // -----------------------------------------------------------------------------
       
   240 //
       
   241 EXPORT_C void CGlxListWindow::ConstructL() 
       
   242 	{
       
   243 	TRACER("CGlxListWindow::ConstructL");
       
   244 	
       
   245     iWorkingWindow = new (ELeave) CGlxDataWindow;
       
   246     iWindow = new (ELeave) CGlxDataWindow;
       
   247     // default range offsets are 0, 0, which means that only the focused item
       
   248     // in in the window by default. Create an object for the focus. This
       
   249     // makes it optional to call SetRangeOffsetsL if range remains 0,0
       
   250     iUnusedObjects.AppendL( iObjectFactory.CreateObjectL() );
       
   251 	}
       
   252     
       
   253 // -----------------------------------------------------------------------------
       
   254 // Destructor
       
   255 // -----------------------------------------------------------------------------
       
   256 //
       
   257 EXPORT_C CGlxListWindow::~CGlxListWindow() 
       
   258 	{
       
   259 	TRACER("CGlxListWindow::Destructor");
       
   260 	
       
   261     // objects may exist in either iWindow or object pool (iUnusedObjects)
       
   262     if ( iWindow )
       
   263         {
       
   264         // this call could be removed, if could call Cleanup here
       
   265         // currently deriving classes implement CleanupObject, so calling it
       
   266         // here is not possible => requires a different object as factory
       
   267         iWindow->Destroy(); 
       
   268         delete iWindow;
       
   269         }
       
   270     iUnusedObjects.ResetAndDestroy();
       
   271     // the working window does not own anything
       
   272     delete iWorkingWindow;
       
   273 	}
       
   274 
       
   275 // -----------------------------------------------------------------------------
       
   276 // Cleans up remaining objects in the window
       
   277 // -----------------------------------------------------------------------------
       
   278 //
       
   279 EXPORT_C void CGlxListWindow::CleanupL() 
       
   280 	{
       
   281 	TRACER("CGlxListWindow::CleanupL");
       
   282 	
       
   283     // make the window empty. this will clean up all remaining objects.
       
   284     UpdateL( TChange( KErrNotFound, 0, EChangeObjectsRemoved, 0, iWindow->TotalSize() - 1 ) );
       
   285 	}
       
   286 	
       
   287 // -----------------------------------------------------------------------------
       
   288 // SetRangeOffsetsL
       
   289 // -----------------------------------------------------------------------------
       
   290 // DEPRECATED
       
   291 EXPORT_C void CGlxListWindow::SetRangeOffsetsL( TInt aFrontOffset, TInt aRearOffset ) 
       
   292 	{
       
   293 	TRACER("CGlxListWindow::SetRangeOffsetsL");
       
   294 	
       
   295     SetRangeOffsetsL( iFocusIndex, iWindow->TotalSize(), aFrontOffset, aRearOffset );
       
   296 	}
       
   297     
       
   298 // -----------------------------------------------------------------------------
       
   299 // SetRangeOffsetsL
       
   300 // -----------------------------------------------------------------------------
       
   301 //
       
   302 EXPORT_C void CGlxListWindow::SetRangeOffsetsL( TInt aFocusIndex, 
       
   303         TInt aTotalSize, TInt aFrontOffset, TInt aRearOffset ) 
       
   304 	{
       
   305 	TRACER("CGlxListWindow::SetRangeOffsetsL");
       
   306 	
       
   307 	__ASSERT_DEBUG( aFrontOffset <= 0 && aRearOffset >= 0, Panic( EGlxPanicIllegalArgument ) );
       
   308 	__ASSERT_DEBUG( ( 0 <= aFocusIndex && aFocusIndex < aTotalSize ) ||
       
   309                     ( KErrNotFound == aFocusIndex && 0 == aTotalSize ), 
       
   310                     Panic( EGlxPanicIllegalArgument ) );
       
   311 	
       
   312 	iFrontOffset = aFrontOffset;
       
   313 	iRearOffset = aRearOffset;
       
   314 	
       
   315     // only ever expand the range. there is no use case to do the otherwise, 
       
   316     // so don't bother optimising that case by freeing unnecessary objects.
       
   317 	
       
   318     // all or no objects may be in use at any time - reserve max count in all arrays
       
   319     TInt maxObjectCount = aRearOffset - aFrontOffset + 1;
       
   320     iWorkingWindow->ReserveL( maxObjectCount );
       
   321     iWindow->ReserveL( maxObjectCount );
       
   322     iUnusedObjects.ReserveL( maxObjectCount );
       
   323     
       
   324     // create enough new objects into the unused objects pool
       
   325     // objects are either in the main window or in the pool
       
   326     for ( TInt i = iWindow->Size() + iUnusedObjects.Count(); i < maxObjectCount; i++ )
       
   327         {
       
   328         // cannot fail since reservation made above
       
   329         ( void )iUnusedObjects.AppendL( iObjectFactory.CreateObjectL() );
       
   330         }
       
   331 	
       
   332 	UpdateL( TChange( aFocusIndex, aTotalSize, EChangeNone, 0, 0 ) );
       
   333 	}
       
   334     
       
   335 // -----------------------------------------------------------------------------
       
   336 // Iterator
       
   337 // -----------------------------------------------------------------------------
       
   338 //
       
   339 EXPORT_C TGlxWindowIterator CGlxListWindow::Iterator() const
       
   340     {
       
   341     TRACER("CGlxListWindow::Iterator");
       
   342     
       
   343     return iWindow->Iterator();
       
   344     }
       
   345 	
       
   346 // -----------------------------------------------------------------------------
       
   347 // SetFocusIndexL
       
   348 // -----------------------------------------------------------------------------
       
   349 // DEPRICATED
       
   350 EXPORT_C void CGlxListWindow::SetFocusIndexL( TInt aFocusIndex ) 
       
   351 	{
       
   352 	TRACER("CGlxListWindow::SetFocusIndexL");
       
   353 	
       
   354 	SetFocusIndexL( aFocusIndex, iWindow->TotalSize() );
       
   355 	}
       
   356 	
       
   357 // -----------------------------------------------------------------------------
       
   358 // SetFocusIndexL
       
   359 // -----------------------------------------------------------------------------
       
   360 //
       
   361 EXPORT_C void CGlxListWindow::SetFocusIndexL( TInt aFocusIndex, TInt aTotalSize ) 
       
   362 	{
       
   363 	TRACER("CGlxListWindow::SetFocusIndexL");
       
   364 	
       
   365 	__ASSERT_DEBUG( ( 0 <= aFocusIndex && aFocusIndex < aTotalSize ) ||
       
   366                     ( KErrNotFound == aFocusIndex && 0 == aTotalSize ), 
       
   367                     Panic( EGlxPanicIllegalArgument ) );
       
   368     __TEST_INVARIANT;
       
   369     
       
   370 	UpdateL( TChange( aFocusIndex, aTotalSize, EChangeNone, 0, 0 ) );
       
   371     
       
   372     __TEST_INVARIANT;
       
   373 	}
       
   374 		
       
   375 // -----------------------------------------------------------------------------
       
   376 // AddObjectsL
       
   377 // -----------------------------------------------------------------------------
       
   378 // DEPRICATED
       
   379 EXPORT_C void CGlxListWindow::AddObjectsL( TInt aFirstNewIndex, TInt aLastNewIndex ) 
       
   380 	{
       
   381 	TRACER("CGlxListWindow::AddObjectsL");
       
   382 	
       
   383 	TInt newItemCount = aLastNewIndex - aFirstNewIndex + 1;
       
   384 	TInt newTotalSize = iWindow->TotalSize() + newItemCount;
       
   385 	
       
   386 	// Check if it is necessary to move focus
       
   387 	TInt newFocusIndex = iFocusIndex;
       
   388 	if ( KErrNotFound == newFocusIndex )
       
   389 		{
       
   390 		// List is empty, so set focus to the first item
       
   391 		__ASSERT_DEBUG(iWindow->TotalSize() == 0, Panic(EGlxPanicIllegalState)); // Must have had an empty list to have no focus
       
   392 		newFocusIndex = 0; 
       
   393 		}
       
   394 	else if (newFocusIndex >= aFirstNewIndex)
       
   395 		{
       
   396 		// Move focus, so that the focus stays on the same item that was 
       
   397 		// focused before items were added
       
   398 		newFocusIndex += newItemCount;
       
   399 		}
       
   400 		
       
   401     AddObjectsL( newFocusIndex, newTotalSize, aFirstNewIndex, aLastNewIndex );
       
   402 	}
       
   403 		
       
   404 // -----------------------------------------------------------------------------
       
   405 // AddObjectsL
       
   406 // -----------------------------------------------------------------------------
       
   407 //
       
   408 EXPORT_C void CGlxListWindow::AddObjectsL( TInt aFocusIndex, 
       
   409         TInt aTotalSize, TInt aFirstNewIndex, TInt aLastNewIndex ) 
       
   410 	{
       
   411 	TRACER("CGlxListWindow::AddObjectsL");
       
   412 	
       
   413     __ASSERT_DEBUG( 0 <= aFirstNewIndex && aFirstNewIndex <= aLastNewIndex && 
       
   414                     aLastNewIndex < aTotalSize &&
       
   415                     0 <= aFocusIndex && aFocusIndex < aTotalSize,
       
   416                     Panic( EGlxPanicIllegalArgument ) ); 
       
   417     __TEST_INVARIANT;
       
   418 	
       
   419 	UpdateL( TChange( aFocusIndex, aTotalSize, EChangeObjectsAdded, 
       
   420         aFirstNewIndex, aLastNewIndex ) );
       
   421 		
       
   422     __TEST_INVARIANT;
       
   423 	}
       
   424 	
       
   425 // -----------------------------------------------------------------------------
       
   426 // RemoveObjectsL
       
   427 // -----------------------------------------------------------------------------
       
   428 // DEPRICATED
       
   429 EXPORT_C void CGlxListWindow::RemoveObjectsL( TInt aFirstRemovedIndex, TInt aLastRemovedIndex ) 
       
   430 	{
       
   431 	TRACER("CGlxListWindow::RemoveObjectsL");
       
   432 	
       
   433 	TInt itemsRemovedCount = aLastRemovedIndex - aFirstRemovedIndex + 1;
       
   434 	TInt newTotalSize = iWindow->TotalSize() - itemsRemovedCount;
       
   435 	TInt newFocusIndex = iFocusIndex;
       
   436 	    
       
   437 	// check number of items left
       
   438 	if (newTotalSize == 0)
       
   439 	    {
       
   440 	    // all items have been removed
       
   441 	    newFocusIndex = KErrNotFound;
       
   442 	    }
       
   443 	else  // still some items in the list
       
   444 	    {
       
   445 	    // Focus should stay on the same item if possible. If not, it should
       
   446 	    // go to the first previous item still existing. If none, it should go to 
       
   447 	    // first (=first next) item.
       
   448 
       
   449         // @todo: Do not maintain focus index in this class, This is broken
       
   450 	    // Update focus if the removal point was before	the focus
       
   451 	    if (aFirstRemovedIndex <= newFocusIndex) 
       
   452 	    	{
       
   453 	    	TInt firstToFocusCount = newFocusIndex - aFirstRemovedIndex + 1;
       
   454 	    	newFocusIndex -= Min(itemsRemovedCount, firstToFocusCount);
       
   455 	    	
       
   456 	    	if (newFocusIndex < 0)
       
   457 	    		{
       
   458 	    		newFocusIndex = 0;
       
   459 	    		}
       
   460 	    	}
       
   461 	    }
       
   462 
       
   463 	RemoveObjectsL( newFocusIndex, newTotalSize, aFirstRemovedIndex, aLastRemovedIndex );
       
   464 	}	
       
   465 
       
   466 // -----------------------------------------------------------------------------
       
   467 // RemoveObjectsL
       
   468 // -----------------------------------------------------------------------------
       
   469 //	
       
   470 EXPORT_C void CGlxListWindow::RemoveObjectsL( TInt aFocusIndex, 
       
   471         TInt aTotalSize, TInt aFirstRemovedIndex, TInt aLastRemovedIndex ) 
       
   472 	{
       
   473 	TRACER("CGlxListWindow::RemoveObjectsL");
       
   474 	
       
   475     __ASSERT_DEBUG( 0 <= aFirstRemovedIndex && aFirstRemovedIndex <= aLastRemovedIndex &&
       
   476                     ( ( 0 <= aFocusIndex && aFocusIndex < aTotalSize ) || 
       
   477                       ( KErrNotFound == aFocusIndex && aTotalSize == 0 ) ),
       
   478                     Panic( EGlxPanicIllegalArgument ) ); 
       
   479     __TEST_INVARIANT;
       
   480     
       
   481 	UpdateL( TChange( aFocusIndex, aTotalSize, EChangeObjectsRemoved, 
       
   482         aFirstRemovedIndex, aLastRemovedIndex ) );
       
   483 
       
   484     __TEST_INVARIANT;
       
   485 	}	
       
   486     
       
   487 // -----------------------------------------------------------------------------
       
   488 // UpdateL
       
   489 // -----------------------------------------------------------------------------
       
   490 //
       
   491 void CGlxListWindow::UpdateL( const TChange& aChange )
       
   492 	{
       
   493 	TRACER("CGlxListWindow::UpdateL");
       
   494 	
       
   495     // (in a list of:  |abcdefghijklm|
       
   496     // iWindow:        |----efghi----|
       
   497     // iWorkingWindow: undefined state
       
   498     // iUnusedObjects: XXX (3 objects, in reality only contains objects if list 
       
   499     //                      is shorter than max window length)
       
   500     
       
   501     // Prepare the working window to accept objects
       
   502     iWorkingWindow->InitializeL( Range( aChange ), aChange.iNewTotalSize );
       
   503 
       
   504     // iWindow:        |----efghi----|
       
   505     // iWorkingWindow: |------00000--|
       
   506     // iUnusedObjects: XXX 
       
   507     
       
   508     // move unused objects to pool, and reusable objects to working window
       
   509     PopulateExistingAndUnuseOldL( aChange );
       
   510 
       
   511     // iWindow:        |----efghi----|
       
   512     // iWorkingWindow: |------ghi00--|
       
   513     // iUnusedObjects: XXXXX (2 objects added, used to be e and f)
       
   514     
       
   515     // set the current window to working window and vice versa.
       
   516     // do this before populating new items, since when the deriving class
       
   517     // is asked to set up the items, it is better to allow it to access the
       
   518     // objects from the window (only objects from main window can be accessed
       
   519     // externally)
       
   520     SwapWindows();
       
   521     iFocusIndex = aChange.iNewFocusIndex;
       
   522     
       
   523     // iWindow:        |------ghi00--|
       
   524     // iWorkingWindow: |----xxxxx----| = undefined
       
   525     // iUnusedObjects: XXXXX 
       
   526 
       
   527     // populate objects in working window that did not exist in current window
       
   528     PopulateNew();
       
   529     
       
   530     // iWindow:        |------ghijk--|
       
   531     // iWorkingWindow: |----xxxxx----| = undefined
       
   532     // iUnusedObjects: XXX (2 objects moved to iWindow)
       
   533 	}
       
   534     
       
   535 // -----------------------------------------------------------------------------
       
   536 // PopulateExistingAndUnuseOldL
       
   537 // -----------------------------------------------------------------------------
       
   538 //	
       
   539 void CGlxListWindow::PopulateExistingAndUnuseOldL( const TChange& aChange ) 
       
   540     {
       
   541     TRACER("CGlxListWindow::PopulateExistingAndUnuseOldL");
       
   542     
       
   543     // move objects that are needed after the change into the working window, 
       
   544     // and objects that are not needed into the object pool
       
   545     TGlxWindowIterator currentWindowIterator = iWindow->Iterator();
       
   546     TInt index = 0;
       
   547     while ( KErrNotFound != ( index = currentWindowIterator++ ) )
       
   548         {
       
   549         // translate to what the list index would be after the change.
       
   550         TInt indexAfterChange = IndexAfterChange( index,  aChange );
       
   551         // item is needed in the new window if it is in the range of the new window
       
   552         if ( iWorkingWindow->InRange( indexAfterChange ) )
       
   553             {
       
   554             // move the object from the current window to the working window
       
   555             ( *iWorkingWindow )[ indexAfterChange ] = ( *iWindow )[ index ];
       
   556             }
       
   557         else 
       
   558             {
       
   559             // ask deriving class to clean up the object (free resources, etc).
       
   560             // do this first, so that the deriving class can access the window 
       
   561             // by index, if needed
       
   562             iObjectFactory.CleanupObject( index, *( *iWindow )[ index ] );
       
   563             // add the object to the unused objects pool
       
   564             // cannot fail since reservation made
       
   565             ( void )iUnusedObjects.AppendL( ( *iWindow )[ index ] );
       
   566             }
       
   567             
       
   568         // clear the pointer in the existing window. it is not strictly necessary
       
   569         // to do here, but saves a loop from doing it in CGlxDataWindow::InitializeL
       
   570         ( *iWindow )[ index ] = NULL;
       
   571         }
       
   572     }
       
   573 
       
   574 // -----------------------------------------------------------------------------
       
   575 // Populate objects that were not reused
       
   576 // -----------------------------------------------------------------------------
       
   577 //	
       
   578 void CGlxListWindow::PopulateNew() 
       
   579     {
       
   580     TRACER("CGlxListWindow::PopulateNew");
       
   581     
       
   582     // iWindow is now partially constructed 
       
   583     // populate all pointers that are null
       
   584     TGlxWindowIterator newWindowIterator = iWindow->Iterator();
       
   585     TInt index = 0;
       
   586     while ( KErrNotFound != ( index = newWindowIterator++ ) )
       
   587         {
       
   588         if ( NULL == ( *iWindow )[ index ] )
       
   589             {
       
   590             CBase* object = UnusedObject();
       
   591             ( *iWindow )[ index ] = object;
       
   592             // configure the object
       
   593         	iObjectFactory.SetupObject( index, *object );
       
   594             }
       
   595         }
       
   596     }
       
   597     
       
   598 // -----------------------------------------------------------------------------
       
   599 // Reuse
       
   600 // -----------------------------------------------------------------------------
       
   601 //	
       
   602 void CGlxListWindow::SwapWindows() 
       
   603     {
       
   604     TRACER("CGlxListWindow::SwapWindows");
       
   605     
       
   606     CGlxDataWindow* temp = iWorkingWindow;
       
   607     iWorkingWindow = iWindow;
       
   608     iWindow = temp;
       
   609     }
       
   610     
       
   611 // -----------------------------------------------------------------------------
       
   612 // Return an object from the pool, and remove it from the pool
       
   613 // -----------------------------------------------------------------------------
       
   614 //
       
   615 CBase* CGlxListWindow::UnusedObject() 
       
   616     {
       
   617     TRACER("CGlxListWindow::UnusedObject");
       
   618     
       
   619     TInt lastObjectIndex = iUnusedObjects.Count() - 1;
       
   620     CBase* object = iUnusedObjects[ lastObjectIndex ];
       
   621     iUnusedObjects.Remove( lastObjectIndex );
       
   622     return object;
       
   623     }
       
   624 
       
   625 // -----------------------------------------------------------------------------
       
   626 // Access object by index
       
   627 // -----------------------------------------------------------------------------
       
   628 //
       
   629 EXPORT_C CBase* CGlxListWindow::At( TInt aIndex )
       
   630 	{ 
       
   631 	TRACER("CGlxListWindow::At");
       
   632 	
       
   633     if ( iWindow->InRange( aIndex ) )
       
   634         {
       
   635         return ( *iWindow )[ aIndex ];
       
   636         }
       
   637     return NULL;
       
   638     }
       
   639 	
       
   640 // -----------------------------------------------------------------------------
       
   641 // Access object by index
       
   642 // -----------------------------------------------------------------------------
       
   643 //
       
   644 EXPORT_C const CBase* CGlxListWindow::At( TInt aIndex ) const 			
       
   645 	{ 
       
   646 	TRACER("CGlxListWindow::At");
       
   647 	
       
   648 	return const_cast< CGlxListWindow* >( this )->At( aIndex ); 
       
   649 	}	
       
   650 
       
   651 // -----------------------------------------------------------------------------
       
   652 // Range
       
   653 // -----------------------------------------------------------------------------
       
   654 //
       
   655 CGlxListWindow::TRange CGlxListWindow::Range( const TChange& aChange ) const
       
   656     {
       
   657     TRACER("CGlxListWindow::Range");
       
   658     
       
   659     TRange range;
       
   660     range.iLength = iRearOffset - iFrontOffset + 1; // Add 1 for focus
       
   661 
       
   662 	// Start index is always zero if the whole list fits into the window
       
   663 	if ( range.iLength >= aChange.iNewTotalSize ) 
       
   664 		{
       
   665 		// All items are within range
       
   666 		range.iStartIndex = 0;
       
   667 		range.iLength = aChange.iNewTotalSize;
       
   668 		}
       
   669 	else 
       
   670 		{
       
   671 		// Not all items in the list fit within the range
       
   672 		range.iStartIndex = GlxListUtils::NormalizedIndex( 
       
   673             aChange.iNewFocusIndex + iFrontOffset, aChange.iNewTotalSize );
       
   674 		
       
   675 		// check that ranges don't ever meet at the other side of the loop
       
   676 		__ASSERT_DEBUG( range.iStartIndex != GlxListUtils::NormalizedIndex( range.iStartIndex + range.iLength, aChange.iNewTotalSize ) 
       
   677             || ( iFrontOffset == 0 && iRearOffset == 0 ), Panic( EGlxPanicLogicError ) ); 
       
   678 		}
       
   679 
       
   680     return range;
       
   681     }
       
   682 
       
   683 // -----------------------------------------------------------------------------
       
   684 // Convert a list index to a list index in a changed list
       
   685 // -----------------------------------------------------------------------------
       
   686 //
       
   687 TInt CGlxListWindow::IndexAfterChange( TInt aIndex, 
       
   688         const TChange& aChange ) const
       
   689 	{
       
   690 	TRACER("CGlxListWindow::IndexAfterChange");
       
   691 	
       
   692 	// Convert the new list index into an old list index
       
   693 	TInt changeCount = aChange.iLastChangedIndex - aChange.iFirstChangedIndex + 1;
       
   694     
       
   695 	TInt indexAfterChange = aIndex;
       
   696 	if ( aChange.iFirstChangedIndex <= aIndex )
       
   697 		{
       
   698 		if ( aChange.iChangeType == EChangeObjectsRemoved )
       
   699 			{
       
   700             //          f l                 (first, last)
       
   701             // old: |---NNN---||||||------|
       
   702             // new: |------||||||------|
       
   703             
       
   704 			// If the index is between the indexes, the change will remove it
       
   705 			if ( aIndex <= aChange.iLastChangedIndex )
       
   706 				{
       
   707 				// The index is one of the new items. It does not exist in the old window
       
   708 				indexAfterChange = KErrNotFound;
       
   709 				}
       
   710 			else 
       
   711 				{
       
   712 				// The index is after the items that will be removed. Adjust the index by "removing" the items.
       
   713 				indexAfterChange -= changeCount;
       
   714 				}
       
   715 			}
       
   716 		else if ( aChange.iChangeType == EChangeObjectsAdded )
       
   717 			{
       
   718 			// Adjust the index by "adding" the items before the index
       
   719             // old: |------||||||------|
       
   720             // new: |---NNN---||||||------|
       
   721             //          f l                 (first, last)
       
   722 			indexAfterChange += changeCount;
       
   723 			}
       
   724 		// if EChangeNone, no adjustment needed
       
   725 		}
       
   726 		// else no adjustment need, since the change happened after the index
       
   727 	
       
   728 	return indexAfterChange;
       
   729 	}
       
   730 
       
   731 // ---------------------------------------------------------------------------
       
   732 // Test invariant
       
   733 // ---------------------------------------------------------------------------
       
   734 EXPORT_C void CGlxListWindow::__DbgTestInvariant() const
       
   735     {
       
   736     TRACER("CGlxListWindow::__DbgTestInvariant");
       
   737     
       
   738     __ASSERT_DEBUG( ( iFocusIndex >= 0 && iFocusIndex < iWindow->TotalSize() ) || 
       
   739                     ( KErrNotFound == iFocusIndex && 0 == iWindow->TotalSize() ), 
       
   740                     Panic( EGlxPanicIllegalState ) );
       
   741     __ASSERT_DEBUG( iFrontOffset <= 0 && iRearOffset >= 0, Panic( EGlxPanicIllegalState ) );
       
   742     }