photosgallery/viewframework/medialists/src/glxlistwindow.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:    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 Initialize( 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.Append( 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::Cleanup() 
       
   280 	{
       
   281 	TRACER("CGlxListWindow::Cleanup");
       
   282 	
       
   283     // make the window empty. this will clean up all remaining objects.
       
   284     Update( 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.Append( iObjectFactory.CreateObjectL() );
       
   330         }
       
   331 	
       
   332 	Update( 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::SetFocusIndex( TInt aFocusIndex ) 
       
   351 	{
       
   352 	TRACER("CGlxListWindow::SetFocusIndex");
       
   353 	
       
   354 	SetFocusIndex( aFocusIndex, iWindow->TotalSize() );
       
   355 	}
       
   356 	
       
   357 // -----------------------------------------------------------------------------
       
   358 // SetFocusIndexL
       
   359 // -----------------------------------------------------------------------------
       
   360 //
       
   361 EXPORT_C void CGlxListWindow::SetFocusIndex( TInt aFocusIndex, TInt aTotalSize ) 
       
   362 	{
       
   363 	TRACER("CGlxListWindow::SetFocusIndex");
       
   364 	
       
   365 	__ASSERT_DEBUG( ( 0 <= aFocusIndex && aFocusIndex < aTotalSize ) ||
       
   366                     ( KErrNotFound == aFocusIndex && 0 == aTotalSize ), 
       
   367                     Panic( EGlxPanicIllegalArgument ) );
       
   368     __TEST_INVARIANT;
       
   369     
       
   370 	Update( TChange( aFocusIndex, aTotalSize, EChangeNone, 0, 0 ) );
       
   371     
       
   372     __TEST_INVARIANT;
       
   373 	}
       
   374 		
       
   375 // -----------------------------------------------------------------------------
       
   376 // AddObjects
       
   377 // -----------------------------------------------------------------------------
       
   378 // DEPRICATED
       
   379 EXPORT_C void CGlxListWindow::AddObjects( TInt aFirstNewIndex, TInt aLastNewIndex ) 
       
   380 	{
       
   381 	TRACER("CGlxListWindow::AddObjects");
       
   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     AddObjects( newFocusIndex, newTotalSize, aFirstNewIndex, aLastNewIndex );
       
   402 	}
       
   403 		
       
   404 // -----------------------------------------------------------------------------
       
   405 // AddObjects
       
   406 // -----------------------------------------------------------------------------
       
   407 //
       
   408 EXPORT_C void CGlxListWindow::AddObjects( TInt aFocusIndex, 
       
   409         TInt aTotalSize, TInt aFirstNewIndex, TInt aLastNewIndex ) 
       
   410 	{
       
   411 	TRACER("CGlxListWindow::AddObjects");
       
   412 	
       
   413     __ASSERT_DEBUG( 0 <= aFirstNewIndex && aFirstNewIndex <= aLastNewIndex && 
       
   414                     aLastNewIndex < aTotalSize &&
       
   415                     0 <= aFocusIndex && aFocusIndex < aTotalSize,
       
   416                     Panic( EGlxPanicIllegalArgument ) ); 
       
   417     __TEST_INVARIANT;
       
   418 	
       
   419 	Update( TChange( aFocusIndex, aTotalSize, EChangeObjectsAdded, 
       
   420         aFirstNewIndex, aLastNewIndex ) );
       
   421 		
       
   422     __TEST_INVARIANT;
       
   423 	}
       
   424 	
       
   425 // -----------------------------------------------------------------------------
       
   426 // RemoveObjects
       
   427 // -----------------------------------------------------------------------------
       
   428 // DEPRICATED
       
   429 EXPORT_C void CGlxListWindow::RemoveObjects( TInt aFirstRemovedIndex, TInt aLastRemovedIndex ) 
       
   430 	{
       
   431 	TRACER("CGlxListWindow::RemoveObjects");
       
   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 	    
       
   451 	    // Update focus if the removal point was before	the focus
       
   452 	    if (aFirstRemovedIndex <= newFocusIndex) 
       
   453 	    	{
       
   454 	    	TInt firstToFocusCount = newFocusIndex - aFirstRemovedIndex + 1;
       
   455 	    	newFocusIndex -= Min(itemsRemovedCount, firstToFocusCount);
       
   456 	    	
       
   457 	    	if (newFocusIndex < 0)
       
   458 	    		{
       
   459 	    		newFocusIndex = 0;
       
   460 	    		}
       
   461 	    	}
       
   462 	    }
       
   463 
       
   464 	RemoveObjects( newFocusIndex, newTotalSize, aFirstRemovedIndex, aLastRemovedIndex );
       
   465 	}	
       
   466 
       
   467 // -----------------------------------------------------------------------------
       
   468 // RemoveObjects
       
   469 // -----------------------------------------------------------------------------
       
   470 //	
       
   471 EXPORT_C void CGlxListWindow::RemoveObjects( TInt aFocusIndex, 
       
   472         TInt aTotalSize, TInt aFirstRemovedIndex, TInt aLastRemovedIndex ) 
       
   473 	{
       
   474 	TRACER("CGlxListWindow::RemoveObjects");
       
   475 	
       
   476     __ASSERT_DEBUG( 0 <= aFirstRemovedIndex && aFirstRemovedIndex <= aLastRemovedIndex &&
       
   477                     ( ( 0 <= aFocusIndex && aFocusIndex < aTotalSize ) || 
       
   478                       ( KErrNotFound == aFocusIndex && aTotalSize == 0 ) ),
       
   479                     Panic( EGlxPanicIllegalArgument ) ); 
       
   480     __TEST_INVARIANT;
       
   481     
       
   482 	Update( TChange( aFocusIndex, aTotalSize, EChangeObjectsRemoved, 
       
   483         aFirstRemovedIndex, aLastRemovedIndex ) );
       
   484 
       
   485     __TEST_INVARIANT;
       
   486 	}	
       
   487     
       
   488 // -----------------------------------------------------------------------------
       
   489 // Update
       
   490 // -----------------------------------------------------------------------------
       
   491 //
       
   492 void CGlxListWindow::Update( const TChange& aChange )
       
   493 	{
       
   494 	TRACER("CGlxListWindow::Update");
       
   495 	
       
   496     // (in a list of:  |abcdefghijklm|
       
   497     // iWindow:        |----efghi----|
       
   498     // iWorkingWindow: undefined state
       
   499     // iUnusedObjects: XXX (3 objects, in reality only contains objects if list 
       
   500     //                      is shorter than max window length)
       
   501     
       
   502     // Prepare the working window to accept objects
       
   503     iWorkingWindow->Initialize( Range( aChange ), aChange.iNewTotalSize );
       
   504 
       
   505     // iWindow:        |----efghi----|
       
   506     // iWorkingWindow: |------00000--|
       
   507     // iUnusedObjects: XXX 
       
   508     
       
   509     // move unused objects to pool, and reusable objects to working window
       
   510     PopulateExistingAndUnuseOld( aChange );
       
   511 
       
   512     // iWindow:        |----efghi----|
       
   513     // iWorkingWindow: |------ghi00--|
       
   514     // iUnusedObjects: XXXXX (2 objects added, used to be e and f)
       
   515     
       
   516     // set the current window to working window and vice versa.
       
   517     // do this before populating new items, since when the deriving class
       
   518     // is asked to set up the items, it is better to allow it to access the
       
   519     // objects from the window (only objects from main window can be accessed
       
   520     // externally)
       
   521     SwapWindows();
       
   522     iFocusIndex = aChange.iNewFocusIndex;
       
   523     
       
   524     // iWindow:        |------ghi00--|
       
   525     // iWorkingWindow: |----xxxxx----| = undefined
       
   526     // iUnusedObjects: XXXXX 
       
   527 
       
   528     // populate objects in working window that did not exist in current window
       
   529     PopulateNew();
       
   530     
       
   531     // iWindow:        |------ghijk--|
       
   532     // iWorkingWindow: |----xxxxx----| = undefined
       
   533     // iUnusedObjects: XXX (2 objects moved to iWindow)
       
   534 	}
       
   535     
       
   536 // -----------------------------------------------------------------------------
       
   537 // PopulateExistingAndUnuseOld
       
   538 // -----------------------------------------------------------------------------
       
   539 //	
       
   540 void CGlxListWindow::PopulateExistingAndUnuseOld( const TChange& aChange ) 
       
   541     {
       
   542     TRACER("CGlxListWindow::PopulateExistingAndUnuseOld");
       
   543     
       
   544     // move objects that are needed after the change into the working window, 
       
   545     // and objects that are not needed into the object pool
       
   546     TGlxWindowIterator currentWindowIterator = iWindow->Iterator();
       
   547     TInt index = 0;
       
   548     while ( KErrNotFound != ( index = currentWindowIterator++ ) )
       
   549         {
       
   550         // translate to what the list index would be after the change.
       
   551         TInt indexAfterChange = IndexAfterChange( index,  aChange );
       
   552         // item is needed in the new window if it is in the range of the new window
       
   553         if ( iWorkingWindow->InRange( indexAfterChange ) )
       
   554             {
       
   555             // move the object from the current window to the working window
       
   556             ( *iWorkingWindow )[ indexAfterChange ] = ( *iWindow )[ index ];
       
   557             }
       
   558         else 
       
   559             {
       
   560             // ask deriving class to clean up the object (free resources, etc).
       
   561             // do this first, so that the deriving class can access the window 
       
   562             // by index, if needed
       
   563             iObjectFactory.CleanupObject( index, *( *iWindow )[ index ] );
       
   564             // add the object to the unused objects pool
       
   565             // cannot fail since reservation made
       
   566             ( void ) iUnusedObjects.Append( ( *iWindow )[ index ] );
       
   567             }
       
   568             
       
   569         // clear the pointer in the existing window. it is not strictly necessary
       
   570         // to do here, but saves a loop from doing it in CGlxDataWindow::Initialize
       
   571         ( *iWindow )[ index ] = NULL;
       
   572         }
       
   573     }
       
   574 
       
   575 // -----------------------------------------------------------------------------
       
   576 // Populate objects that were not reused
       
   577 // -----------------------------------------------------------------------------
       
   578 //	
       
   579 void CGlxListWindow::PopulateNew() 
       
   580     {
       
   581     TRACER("CGlxListWindow::PopulateNew");
       
   582     
       
   583     // iWindow is now partially constructed 
       
   584     // populate all pointers that are null
       
   585     TGlxWindowIterator newWindowIterator = iWindow->Iterator();
       
   586     TInt index = 0;
       
   587     while ( KErrNotFound != ( index = newWindowIterator++ ) )
       
   588         {
       
   589         if ( NULL == ( *iWindow )[ index ] )
       
   590             {
       
   591             CBase* object = UnusedObject();
       
   592             ( *iWindow )[ index ] = object;
       
   593             // configure the object
       
   594         	iObjectFactory.SetupObject( index, *object );
       
   595             }
       
   596         }
       
   597     }
       
   598     
       
   599 // -----------------------------------------------------------------------------
       
   600 // Reuse
       
   601 // -----------------------------------------------------------------------------
       
   602 //	
       
   603 void CGlxListWindow::SwapWindows() 
       
   604     {
       
   605     TRACER("CGlxListWindow::SwapWindows");
       
   606     
       
   607     CGlxDataWindow* temp = iWorkingWindow;
       
   608     iWorkingWindow = iWindow;
       
   609     iWindow = temp;
       
   610     }
       
   611     
       
   612 // -----------------------------------------------------------------------------
       
   613 // Return an object from the pool, and remove it from the pool
       
   614 // -----------------------------------------------------------------------------
       
   615 //
       
   616 CBase* CGlxListWindow::UnusedObject() 
       
   617     {
       
   618     TRACER("CGlxListWindow::UnusedObject");
       
   619     
       
   620     TInt lastObjectIndex = iUnusedObjects.Count() - 1;
       
   621     CBase* object = iUnusedObjects[ lastObjectIndex ];
       
   622     iUnusedObjects.Remove( lastObjectIndex );
       
   623     return object;
       
   624     }
       
   625 
       
   626 // -----------------------------------------------------------------------------
       
   627 // Access object by index
       
   628 // -----------------------------------------------------------------------------
       
   629 //
       
   630 EXPORT_C CBase* CGlxListWindow::At( TInt aIndex )
       
   631 	{ 
       
   632 	TRACER("CGlxListWindow::At");
       
   633 	
       
   634     if ( iWindow->InRange( aIndex ) )
       
   635         {
       
   636         return ( *iWindow )[ aIndex ];
       
   637         }
       
   638     return NULL;
       
   639     }
       
   640 	
       
   641 // -----------------------------------------------------------------------------
       
   642 // Access object by index
       
   643 // -----------------------------------------------------------------------------
       
   644 //
       
   645 EXPORT_C const CBase* CGlxListWindow::At( TInt aIndex ) const 			
       
   646 	{ 
       
   647 	TRACER("CGlxListWindow::At");
       
   648 	
       
   649 	return const_cast< CGlxListWindow* >( this )->At( aIndex ); 
       
   650 	}	
       
   651 
       
   652 // -----------------------------------------------------------------------------
       
   653 // Range
       
   654 // -----------------------------------------------------------------------------
       
   655 //
       
   656 CGlxListWindow::TRange CGlxListWindow::Range( const TChange& aChange ) const
       
   657     {
       
   658     TRACER("CGlxListWindow::Range");
       
   659     
       
   660     TRange range;
       
   661     range.iLength = iRearOffset - iFrontOffset + 1; // Add 1 for focus;
       
   662 
       
   663 	// Start index is always zero if the whole list fits into the window
       
   664 	if ( range.iLength >= aChange.iNewTotalSize ) 
       
   665 		{
       
   666 		// All items are within range
       
   667 		range.iStartIndex = 0;
       
   668 		range.iLength = aChange.iNewTotalSize;
       
   669 		}
       
   670 	else 
       
   671 		{
       
   672 		// Not all items in the list fit within the range
       
   673 		range.iStartIndex = GlxListUtils::NormalizedIndex( 
       
   674             aChange.iNewFocusIndex + iFrontOffset, aChange.iNewTotalSize );
       
   675 		
       
   676 		// check that ranges don't ever meet at the other side of the loop
       
   677 		__ASSERT_DEBUG( range.iStartIndex != GlxListUtils::NormalizedIndex( range.iStartIndex + range.iLength, aChange.iNewTotalSize ) 
       
   678             || ( iFrontOffset == 0 && iRearOffset == 0 ), Panic( EGlxPanicLogicError ) ); 
       
   679 		}
       
   680 
       
   681     return range;
       
   682     }
       
   683 
       
   684 // -----------------------------------------------------------------------------
       
   685 // Convert a list index to a list index in a changed list
       
   686 // -----------------------------------------------------------------------------
       
   687 //
       
   688 TInt CGlxListWindow::IndexAfterChange( TInt aIndex, 
       
   689         const TChange& aChange ) const
       
   690 	{
       
   691 	TRACER("CGlxListWindow::IndexAfterChange");
       
   692 	
       
   693 	// Convert the new list index into an old list index
       
   694 	TInt changeCount = aChange.iLastChangedIndex - aChange.iFirstChangedIndex + 1;
       
   695     
       
   696 	TInt indexAfterChange = aIndex;
       
   697 	if ( aChange.iFirstChangedIndex <= aIndex )
       
   698 		{
       
   699 		if ( aChange.iChangeType == EChangeObjectsRemoved )
       
   700 			{
       
   701             //          f l                 (first, last)
       
   702             // old: |---NNN---||||||------|
       
   703             // new: |------||||||------|
       
   704             
       
   705 			// If the index is between the indexes, the change will remove it
       
   706 			if ( aIndex <= aChange.iLastChangedIndex )
       
   707 				{
       
   708 				// The index is one of the new items. It does not exist in the old window
       
   709 				indexAfterChange = KErrNotFound;
       
   710 				}
       
   711 			else 
       
   712 				{
       
   713 				// The index is after the items that will be removed. Adjust the index by "removing" the items.
       
   714 				indexAfterChange -= changeCount;
       
   715 				}
       
   716 			}
       
   717 		else if ( aChange.iChangeType == EChangeObjectsAdded )
       
   718 			{
       
   719 			// Adjust the index by "adding" the items before the index
       
   720             // old: |------||||||------|
       
   721             // new: |---NNN---||||||------|
       
   722             //          f l                 (first, last)
       
   723 			indexAfterChange += changeCount;
       
   724 			}
       
   725 		// if EChangeNone, no adjustment needed
       
   726 		}
       
   727 		// else no adjustment need, since the change happened after the index
       
   728 	
       
   729 	return indexAfterChange;
       
   730 	}
       
   731 
       
   732 // ---------------------------------------------------------------------------
       
   733 // Test invariant
       
   734 // ---------------------------------------------------------------------------
       
   735 void CGlxListWindow::__DbgTestInvariant() const
       
   736     {
       
   737     TRACER("CGlxListWindow::__DbgTestInvariant");
       
   738     
       
   739     __ASSERT_DEBUG( ( iFocusIndex >= 0 && iFocusIndex < iWindow->TotalSize() ) || 
       
   740                     ( KErrNotFound == iFocusIndex && 0 == iWindow->TotalSize() ), 
       
   741                     Panic( EGlxPanicIllegalState ) );
       
   742     __ASSERT_DEBUG( iFrontOffset <= 0 && iRearOffset >= 0, Panic( EGlxPanicIllegalState ) );
       
   743     }