camerauis/cameraapp/generic/src/CamBurstThumbnailGridModel.cpp
changeset 0 1ddebce53859
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/camerauis/cameraapp/generic/src/CamBurstThumbnailGridModel.cpp	Thu Jan 07 16:18:56 2010 +0200
@@ -0,0 +1,1327 @@
+/*
+* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies). 
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  Class to model the contents of the burst post-capture view*
+*/
+
+
+
+// INCLUDE FILES
+#include <fbs.h>     
+#include <barsread.h>
+#include <eikenv.h>
+
+#include <cameraapp.rsg>
+#include <vgacamsettings.rsg>
+#include <StringLoader.h>
+#include <aknnotewrappers.h>
+
+ 
+#include "CamBurstThumbnailGridModel.h"
+#include "CamBurstThumbnailGrid.h"
+#include "CamBurstCaptureArray.h"
+#include "camlogging.h"
+#include "CamPanic.h"
+
+// Uncommenting the define below will allow wrapping of the grid from the first
+// element of the grid to the very last, and vice-versa.
+#define ALLOW_GRID_WRAPPING
+
+
+// ============================= LOCAL FUNCTIONS ===============================
+
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+CCamBurstThumbnailGridModel::CCamBurstThumbnailGridModel() 
+    {
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCamBurstCaptureItem::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CCamBurstThumbnailGridModel* CCamBurstThumbnailGridModel::NewL()
+    {
+    CCamBurstThumbnailGridModel* self = new( ELeave ) CCamBurstThumbnailGridModel();
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop();
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CCamBurstThumbnailGridModel::ConstructL()
+    {
+    iThumbSize.iWidth = 0;
+    iThumbSize.iHeight = 0;
+
+    iGridSizer = CCamThumbnailGridSizer::NewL( this, iThumbSize );        
+    iTopLeftIndex = 0;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::GridItem
+// Returns pointer to the requested item, or NULL if index is invalid
+// -----------------------------------------------------------------------------
+//
+CThumbnailGridItem* CCamBurstThumbnailGridModel::GridItem( TInt aIndex )
+    {
+    if ( aIndex >= iValidThumbGrid.Count() )
+        {
+        return NULL;
+        }
+    else 
+        {
+        return iValidThumbGrid[ aIndex ];
+        }
+    }
+
+// Note: Returns ONLY non-deleted cells
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::Snapshot
+// Returns pointer to the requested item, or NULL if index is invalid
+// -----------------------------------------------------------------------------
+//
+const CFbsBitmap* CCamBurstThumbnailGridModel::Snapshot( TInt aIndex )
+    {
+    if ( aIndex >= iValidThumbGrid.Count() )
+        {
+        return NULL;
+        }
+    else 
+        {        
+        TInt ind = ConvertFromValidToGlobalIndex( aIndex );
+        if ( ind != KErrNotFound )
+            {
+            return iBurstArray->Snapshot( ind );
+            }
+        else 
+            {
+            return NULL;
+            }
+        }
+    }
+
+// Destructor
+CCamBurstThumbnailGridModel::~CCamBurstThumbnailGridModel()
+  {
+  PRINT( _L("Camera => ~CCamBurstThumbnailGridModel") );
+
+  if ( iGridSizer )
+      {
+      iGridSizer->Cancel();
+      }
+  delete iGridSizer;
+  
+  // Delete the array and the objects pointed to
+  iAllThumbGrid.ResetAndDestroy();
+
+  // Note: As this points to the same thing as the array above, just 
+  // delete the array, not the objects
+  iValidThumbGrid.Reset();
+
+  // Do NOT destroy the objects pointed to, just the list.
+  iThumbObserver.Reset();     
+  iHighlightObserver.Reset();
+  iDeleteObserver.Reset();
+  PRINT( _L("Camera <= ~CCamBurstThumbnailGridModel") );
+  }
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::AddCellL
+// Adds the cell to the internal structures.  Takes ownership of the cell.
+// -----------------------------------------------------------------------------
+//
+void CCamBurstThumbnailGridModel::AddCellL( CThumbnailGridItem* aCell )
+    {
+    // Add to the master list of grid items
+    User::LeaveIfError( iAllThumbGrid.Append( aCell ) );
+
+    // Add to the list of VALID (non deleted) grid items
+    User::LeaveIfError( iValidThumbGrid.Append( aCell ) );
+    }
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::StartThumbnailL
+// -----------------------------------------------------------------------------
+//
+void CCamBurstThumbnailGridModel::StartThumbnailL( TInt aIndex )
+    {        
+    // Burst array may be released by the app when swicthing
+    // views so do a check that it is still valid
+    if ( iBurstArray )
+        {
+        const CFbsBitmap* source = iBurstArray->Snapshot( aIndex );
+        if ( source )
+            {
+            iGridSizer->StartScaleL( *source, iThumbSize, aIndex );
+            }
+        }
+    }
+    
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::CancelThumbnails
+// Cancels any outstanding thumbnail generation operation
+// -----------------------------------------------------------------------------
+//
+void CCamBurstThumbnailGridModel::CancelThumbnails()
+    {
+    if ( iGridSizer->IsActive() )
+        {
+        iGridSizer->Cancel();
+        }
+    }    
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::ImageFilesDeletedL
+// -----------------------------------------------------------------------------
+//
+void CCamBurstThumbnailGridModel::ImageFilesDeleted()
+    {
+    
+    TBool highlightDeleted = EFalse;
+    
+    TInt highlightIndex = ConvertFromValidToGlobalIndex( iCurrHighlight );
+    
+    for ( TInt i = 0; i < iBurstArray->Count(); i++ )
+        {
+        if ( iBurstArray->IsDeleted( i ) )
+            {
+            if ( highlightIndex == i )
+                {
+                highlightDeleted = ETrue;
+                }
+            
+            TRAPD( error, DeleteItemL( i ) );
+            
+            // DeleteItemL() leaves only when file can't be deleted and that should never
+            // happen here as the files are already deleted
+            __ASSERT_DEBUG( error == KErrNone, CamPanic( ECamPanicUi ) );
+            error++; // remove compile warnings
+            }
+        }
+    
+    DoPostDeleteGridCheck( highlightDeleted );
+    }
+
+// -----------------------------------------------------------------------------
+// CCamThumbnailGridSizer::SetThumbnailSize
+// -----------------------------------------------------------------------------
+//
+void CCamBurstThumbnailGridModel::SetThumbnailSize( const TSize aThumbSize )
+    {
+    
+    if ( aThumbSize != iThumbSize )
+        {
+        iThumbSize = aThumbSize;
+		iGridSizer->SetSize( iThumbSize );
+        // delete all thumbs because size has changed and they need to be regenerated
+        TInt imagesRemaining = iBurstArray->ImagesRemaining();
+        for ( TInt i = 0; i < imagesRemaining; i++ )
+            {
+            // delete display thumbnail
+            delete iValidThumbGrid[i]->iDisplayThumb;
+            iValidThumbGrid[i]->iDisplayThumb = NULL;   
+            }
+
+        // recalculate needed thumbs
+        RecalculateThumbs();
+
+        }
+    }
+
+
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::BitmapScaleCompleteL
+// Callback called when a bitmap scaling operation has completed.
+// We take ownership of the 'aBitmap' object
+// -----------------------------------------------------------------------------
+//
+void CCamBurstThumbnailGridModel::BitmapScaleCompleteL( TInt aErr, CFbsBitmap* aBitmap, TInt32 aInfo )
+    {
+    if ( aErr == KErrNone )
+        {       
+        // Update internal structure
+        CThumbnailGridItem* item = iAllThumbGrid[aInfo];
+        item->iDisplayThumb = aBitmap;
+
+        // Inform observer(s) to ensure the screen is updated     
+        NotifyModelObserver( EModelEventThumb );
+        }    
+    }      
+    
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::RecalculateThumbs
+// Called to check which thumbnails need creating, and start the procedure
+// -----------------------------------------------------------------------------
+//
+void CCamBurstThumbnailGridModel::RecalculateThumbs()
+    {        
+    // If in the grid below, items 3-8 were visible in the screen grid, 
+    // items 0-2 and 9-11 would also have thumbnails generated to attempt
+    // to reduce visible artifacts from calculating on the fly.
+    //    [ 0 ][ 1 ][ 2 ]   <= Row above (not visible)
+    //    [ 3 ][ 4 ][ 5 ]   <= First visible row
+    //    [ 6 ][ 7 ][ 8 ]   <= Second visible row
+    //    [ 9 ][ 10][ 11]   <= Row below (not visible)
+    //
+    
+    // If we get to recalculate thumbnails, we need to cancel any outstanding 
+    // rescale operation
+    CancelThumbnails();
+    
+    // Work out the top left index. This is the top-left cell of the VIEWABLE
+    // grid, less one row (which serves as a thumbnail cache)        
+    TInt topLeftIndex = iTopLeftIndex - KGridWidth;
+    if ( topLeftIndex < 0 )
+        {
+        topLeftIndex = 0;
+        }
+
+    // Work out the bottom right index. This is the bottom-right cell of the 
+    // VIEWABLE grid, plus one row (which serves as a thumbnail cache)
+    TInt botRightIndex = iTopLeftIndex + ( KGridWidth * iGridHeight ) - 1 + KGridWidth;
+    if ( botRightIndex > iValidThumbGrid.Count() - 1 )
+        {
+        botRightIndex = iValidThumbGrid.Count() - 1;
+        }
+    
+    // Delete the thumbnails for cells that are not immediately visible, and are
+    // not in the next or last row.
+    TInt i;
+    TInt imagesRemaining = iBurstArray->ImagesRemaining();
+    for ( i = 0; i < imagesRemaining; i++ )
+        {
+        if ( ( i < topLeftIndex || i > botRightIndex ) &&
+            iValidThumbGrid[i]->iDisplayThumb ) 
+            {
+            // delete display thumbnail
+            delete iValidThumbGrid[i]->iDisplayThumb;
+            iValidThumbGrid[i]->iDisplayThumb = NULL;   
+            }
+        }
+    
+    // Queue up the thumbnails that need to be resized
+    TRAPD( ignore, QueueThumbnailsL() );
+    if ( ignore )
+        { 
+        // Do nothing ( removes build warning )
+        }                   
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::QueueThumbnailsL
+// Queues the thumbnails to be resized as needed
+// -----------------------------------------------------------------------------
+//
+void CCamBurstThumbnailGridModel::QueueThumbnailsL()
+    {
+    //    [ 0 ][ 1 ][ 2 ]   <= Row above (not visible)
+    //    [ 3 ][ 4 ][ 5 ]   <= First visible row
+    //    [ 6 ][ 7 ][ 8 ]   <= Second visible row
+    //    [ 9 ][ 10][ 11]   <= Row below (not visible)
+    //    
+    TInt start = iTopLeftIndex;
+    TInt index = KErrNotFound; 
+    TInt max = iTopLeftIndex + KGridSize;
+    if ( max > iValidThumbGrid.Count() )
+        {
+        max = iValidThumbGrid.Count();
+        }
+    
+    // Top priority is the set of thumbs visible AT THIS MOMENT
+    TInt i;
+    for ( i = start; i < max ; i++ )
+        {
+        if ( !iValidThumbGrid[i]->iDisplayThumb )
+            {
+            // If we get here, then 'i' is the index to the VALID set of items.
+            // Need to convert this to the index in the GLOBAL set of items
+            index = ConvertFromValidToGlobalIndex( i );
+            StartThumbnailL( index );
+            }
+        }
+
+    // SECOND top priority is the set of thumbs BELOW the visible set
+    if ( iValidThumbGrid.Count() >= iTopLeftIndex + KGridSize ) 
+        {
+        start = iTopLeftIndex+KGridSize;
+        max = i + KGridWidth;
+        if ( max > iValidThumbGrid.Count() )
+            {
+            max = iValidThumbGrid.Count();
+            }
+
+        // If we have got here, we can cache the row *below* the 2nd visible row
+        for ( i = start; i < max; i++ )
+            {
+            if ( !iValidThumbGrid[i]->iDisplayThumb )
+                {
+                // If we get here, then 'i' is the index to the VALID set of items.
+                // Need to convert this to the index in the GLOBAL set of items
+                index = ConvertFromValidToGlobalIndex( i );
+                StartThumbnailL( index );
+                }
+            }
+        }
+
+    // THIRD priority is the set of thumbs ABOVE the visible set
+    if ( iTopLeftIndex >= KGridWidth ) // ONLY if there IS a previous row
+        {
+        start = iTopLeftIndex - KGridWidth;
+        max = iTopLeftIndex;
+        // If we have got here, we can cache the row *above* this one.
+        for ( i = start; i < max; i++ )
+            {
+            if ( !iValidThumbGrid[i]->iDisplayThumb )
+                {
+                // If we get here, then 'i' is the index to the VALID set of items.
+                // Need to convert this to the index in the GLOBAL set of items
+                index = ConvertFromValidToGlobalIndex( i );
+                StartThumbnailL( index );
+                }
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::ConvertFromValidToGlobalIndex
+// Converts from a valid-index (non-deleted only) to global (del & non-del) index
+// -----------------------------------------------------------------------------
+//
+TInt CCamBurstThumbnailGridModel::ConvertFromValidToGlobalIndex( TInt aValidIndex )   
+    {       
+    if ( aValidIndex < iValidThumbGrid.Count() )
+        {
+        CThumbnailGridItem* item = iValidThumbGrid[aValidIndex];
+        return iAllThumbGrid.Find( item );    
+        }
+    else
+        {
+        return KErrNotFound;
+        }
+    }      
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::SetBurstArrayL
+// -----------------------------------------------------------------------------
+//
+void CCamBurstThumbnailGridModel::SetBurstArrayL( CCamBurstCaptureArray* aArray )
+    {
+    PRINT( _L("Camera => CCamBurstThumbnailGridModel::SetBurstArrayL") );
+
+    // If we've not been initialised yet, and have no data, then use the array
+    // just passed in.  
+    if ( iAllThumbGrid.Count() == 0 )
+        {
+        iBurstArray = aArray;
+        
+        // Build up model to match burst array
+        if ( iBurstArray )
+            {
+            TInt i;
+            TInt count = iBurstArray->Count();
+            PRINT1( _L("Camera <> got %d thumbnails"), count );
+            
+            // Create a set of items to match the number in the burst array
+            for ( i = 0; i < count; i++ )
+                {
+                CThumbnailGridItem* item = new ( ELeave ) CThumbnailGridItem();
+
+                CleanupStack::PushL( item );
+                item->iDisplayThumb = NULL;
+                item->iMarked = EFalse;
+                AddCellL( item );
+                CleanupStack::Pop( item );
+
+                if ( !iBurstArray->Snapshot( i ) )
+                    {
+                    DeleteItemL( i );
+                    }
+                }
+
+            // Setup the base grid height based on the number of items
+            if ( NoOfValidCells() <= KSmallGridCellCount )
+                {
+                iGridHeight = KSmallGridHeight;
+                }
+            else 
+                {
+                iGridHeight = KLargeGridHeight;
+                }
+            
+            // Start the generation of thumbnails
+            RecalculateThumbs();
+            }
+        }
+    PRINT( _L("Camera <= CCamBurstThumbnailGridModel::SetBurstArrayL") );
+    }
+
+
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::AddModelObserverL
+// -----------------------------------------------------------------------------
+//
+void CCamBurstThumbnailGridModel::AddModelObserverL( MThumbModelObserver* aObserver, TInt aMask )
+    {
+    if ( aMask & EModelEventHighlight )
+        {
+        User::LeaveIfError( iHighlightObserver.Append( aObserver ) );
+        }
+
+    if ( aMask & EModelEventDeleted )
+        {
+        User::LeaveIfError( iDeleteObserver.Append( aObserver ) );
+        }
+
+    if ( aMask & EModelEventThumb )
+        {
+        User::LeaveIfError( iThumbObserver.Append( aObserver ) );
+        }   
+    }
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::RemoveModelObserver
+// -----------------------------------------------------------------------------
+//
+void CCamBurstThumbnailGridModel::RemoveModelObserver( MThumbModelObserver* aObserver, TInt aMask )
+    {
+    TInt pos;
+    if ( aMask & EModelEventHighlight )
+        {
+        pos = iHighlightObserver.Find( aObserver );
+        if ( pos != KErrNotFound )
+            {
+            iHighlightObserver.Remove( pos );
+            }
+        }
+    if ( aMask & EModelEventDeleted )
+        {
+        pos = iDeleteObserver.Find( aObserver );
+        if ( pos != KErrNotFound )
+            {
+            iDeleteObserver.Remove( pos );
+            }
+        }
+    if ( aMask & EModelEventThumb )
+        {
+        pos = iThumbObserver.Find( aObserver );
+        if ( pos != KErrNotFound )
+            {
+            iThumbObserver.Remove( pos );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::NotifyModelObserver
+// -----------------------------------------------------------------------------
+//
+void CCamBurstThumbnailGridModel::NotifyModelObserver( TModelEvent aEvent, TInt /*aParam*/ )
+    {
+    TInt i;
+    TInt count; 
+
+    switch ( aEvent )        
+        {        
+        case EModelEventHighlight:
+            {
+            count = iHighlightObserver.Count();
+            for ( i = 0; i < count; i++ )  
+                {
+                iHighlightObserver[i]->HighlightChanged();
+                }
+            break;
+            }
+            
+        case EModelEventDeleted:
+            {
+            count = iDeleteObserver.Count();
+            for ( i = 0; i < count; i++ )  
+                {
+                iDeleteObserver[i]->ImagesDeleted();
+                }    
+            break;
+            }
+
+        case EModelEventThumb:
+            {
+            count = iThumbObserver.Count();
+            for ( i = 0; i < count; i++ )  
+                {
+                iThumbObserver[i]->ThumbnailGenerated();
+                }
+            break;
+            }
+        default:
+            break;  
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::NoOfValidCells
+// -----------------------------------------------------------------------------
+//
+TInt CCamBurstThumbnailGridModel::NoOfValidCells()
+    {
+    //return iBurstArray->ImagesRemaining();
+    return iValidThumbGrid.Count();
+    }
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::MoveHighlight
+// Tries to move the selection.  If no change is made, returns EFalse.
+// If change is made, returns ETrue (to inform of a redraw)
+// -----------------------------------------------------------------------------
+//
+TBool CCamBurstThumbnailGridModel::MoveHighlight( TMoveSelect aDir )
+    {
+    TInt oldTopLeft = iTopLeftIndex;
+    TInt oldHighlight = iCurrHighlight;
+
+    // cellX and cellY store the cell position in the X and Y axis as seen on 
+    // the screen
+    TInt cellX = ( iCurrHighlight - iTopLeftIndex ) % KGridWidth; // 0 - 2
+    TInt cellY = ( iCurrHighlight - iTopLeftIndex ) / KGridWidth; // 0 - 1
+
+    switch ( aDir )
+        {
+        case EMoveSelectLeft:
+            {
+            if ( iCurrHighlight > 0 )
+                {
+                iCurrHighlight --;
+
+                if ( cellX == 0 && cellY == 0 ) // At top left entry
+                    {
+                    iTopLeftIndex -= KGridWidth;
+                    }
+                }
+#ifdef ALLOW_GRID_WRAPPING
+            else 
+                {
+                TInt cells = iValidThumbGrid.Count();
+                TInt bottomX = ( cells ) % KGridWidth;
+                TInt bottomY = ( cells ) / KGridWidth;
+                // If over the allowed number of rows, and bottom row is full
+                if ( bottomY >= iGridHeight && bottomX == 0 )  
+                    {
+                    iTopLeftIndex = ( bottomY - iGridHeight ) * KGridWidth;    // 
+                    }
+                else if ( bottomY >= ( iGridHeight - 1 ) ) // Over 1 row, 
+                    {
+                    iTopLeftIndex = ( bottomY - ( iGridHeight - 1 ) ) * KGridWidth;    
+                    }
+                else // Only one (incomplete) row
+                    { 
+                    iTopLeftIndex = ( bottomY  ) * KGridWidth;    
+                    }
+                
+                iCurrHighlight = cells - 1; // Last entry
+                }
+#endif // ALLOW_GRID_WRAPPING
+            break;
+            }
+
+        case EMoveSelectRight:
+            {
+            if ( iCurrHighlight < ( iBurstArray->ImagesRemaining() - 1 ) )
+                {
+                iCurrHighlight ++;
+
+                if ( cellX == ( KGridWidth - 1 ) && cellY == ( iGridHeight - 1 ) ) 
+                    {
+                    iTopLeftIndex += KGridWidth;
+                    }
+                }
+#ifdef ALLOW_GRID_WRAPPING
+            else 
+                {
+                iCurrHighlight = 0; // Top left entry
+                iTopLeftIndex = 0;
+                }
+#endif // ALLOW_GRID_WRAPPING
+
+            break;
+            }
+
+        case EMoveSelectUp:
+            {
+            if ( iCurrHighlight >= KGridWidth )
+                {
+                iCurrHighlight -= KGridWidth;
+
+                // if in TOP row, and we CAN move up, shift viewpoint up
+                if ( cellY == 0 ) 
+                    {
+                    iTopLeftIndex -= KGridWidth;
+                    }
+                }
+#ifdef ALLOW_GRID_WRAPPING
+            else // Then we need to wrap to the bottom of the previous grid
+                {
+                TInt cells = iValidThumbGrid.Count();
+
+                // startX holds the "x" value of initial selection
+                TInt startX = ( iCurrHighlight ) % KGridWidth; 
+                TInt bottomY = ( cells ) / KGridWidth; 
+
+                // If not in left-most grid, we'll be moving left and to bottom
+                if ( startX > 0 )
+                    {
+                    startX --;                    
+                    }
+                else // Else in left most grid, so "jump" to right most.
+                    {
+                    if ( cells < KGridWidth )
+                        {
+                        startX = cells - 1;
+                        }
+                    else
+                        {
+                        startX = KGridWidth - 1;
+                        }                    
+                    }
+
+                // If all rows are full (so modulus is 0) bottomY division will
+                // be one too great, so compensate
+                if ( cells % KGridWidth == 0 )
+                    { 
+                    bottomY -- ;
+                    }
+                iCurrHighlight = ( bottomY * KGridWidth ) + startX;
+                
+                // Check this item is filled in, if not, move "up" a row
+                if ( iCurrHighlight >= cells )
+                    { 
+                    // If more than one rows worth of items, can move to second to last row
+                    if ( cells > KGridWidth )
+                        {
+                        bottomY --;
+                        }
+                    else // If only one row (or less)
+                        {
+                        startX = cells % KGridWidth;
+                        }                    
+
+                    // Will need to recalculate curr highlight following changes
+                    iCurrHighlight = ( bottomY * KGridWidth ) + startX;
+                    }
+                UpdateViewableGrid( EFalse );
+                }
+#endif // ALLOW_GRID_WRAPPING
+            break;
+            }
+
+        case EMoveSelectDown:
+            {
+            if ( ( iCurrHighlight + KGridWidth ) <= ( iBurstArray->ImagesRemaining() - 1 ) )
+                {
+                iCurrHighlight += KGridWidth;
+
+                if ( cellY == ( iGridHeight-1 ) ) // if in BOTTOM row, and we CAN move down, shift viewpoint down
+                    {
+                    iTopLeftIndex += KGridWidth;
+                    }
+                }
+#ifdef ALLOW_GRID_WRAPPING
+            else // Then we need to wrap to the top of the next grid
+                {
+                TInt startX = ( iCurrHighlight ) % KGridWidth; 
+                TInt cells = iValidThumbGrid.Count();
+                TInt rightMostGrid;
+
+                if ( cells < KGridWidth )
+                    {
+                    rightMostGrid = cells;
+                    }
+                else
+                    {
+                    rightMostGrid = KGridWidth;
+                    }
+                
+                // If not in left-most grid, we'll be moving left and to bottom
+                if ( startX < ( rightMostGrid - 1 )  )
+                    {                    
+                    // Check we don't have less-than-a-row of cells left
+                    if ( startX < ( cells - 1 ) )
+                        {
+                        startX ++;                    
+                        }
+                    else // If that is the case, move to the last one.
+                        {
+                        startX = cells - 1;
+                        }
+                    
+                    }
+                else // Else in left most grid, so "jump" to right most.
+                    {
+                    startX = 0;
+                    }                
+
+                // Calculate new highlight poisition.
+                iCurrHighlight = startX;
+
+                UpdateViewableGrid( ETrue );
+                }
+#endif // ALLOW_GRID_WRAPPING
+            break;
+            }
+        }
+        
+    // Work out if the viewed items has changed.  If so, check whether we need 
+    // to calculate any new thumbnails for display.
+    if ( oldTopLeft != iTopLeftIndex )
+        {
+        RecalculateThumbs();
+        }
+
+    // Notify observers of the change
+    NotifyModelObserver( EModelEventHighlight );    
+
+    if ( iCurrHighlight != oldHighlight )
+        {
+        return ETrue;   // Highlight HAS changed
+        }
+    else 
+        {
+        return EFalse;  // No change
+        }    
+    }
+
+// Sets the higlighted burst item
+// informs model observer about the change
+// returns ETrue if highlight changed
+// returns EFalse if highlight was not changed
+TBool CCamBurstThumbnailGridModel::SetHighlight( TInt aIndex )
+	{
+	PRINT1( _L("Camera => CCamBurstThumbnailGridModel::SetHighlight( %d )"), aIndex );
+	
+	TInt oldHighlight = iCurrHighlight;
+	iCurrHighlight = aIndex;  
+
+    PRINT( _L("Camera <= CCamBurstThumbnailGridModel::SetHighlight()") );
+    
+    if ( iCurrHighlight != oldHighlight )
+        {
+        return ETrue;   // Highlight HAS changed
+        }
+    else 
+        {
+        return EFalse;  // No change
+        }  
+
+	}
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::UpdateViewableGrid
+// -----------------------------------------------------------------------------
+//
+void CCamBurstThumbnailGridModel::UpdateViewableGrid( TBool aMovingUp )
+    {          
+    if ( NoOfValidCells() <= KBurstGridMaxVisibleThumbnails )
+        {
+        // no need to update if there are less cells than fit to screen at once
+        return;
+        }
+    
+    TInt posY = iCurrHighlight / KGridWidth; 
+
+    // If moving up, when adjust the viewable area, the highlighted grid is 
+    // in the top-most row.
+    if ( aMovingUp )
+        {        
+        if ( posY >= ( iGridHeight - 1 ) )
+            {
+            iTopLeftIndex = ( posY - ( iGridHeight - 1 ) ) * KGridWidth;    
+            }
+        else // Only one (incomplete) row
+            { 
+            iTopLeftIndex = ( posY ) * KGridWidth;    
+            }
+        }
+    // If moving down, when adjust the viewable area, the highlighted grid item
+    // is in the bottom-most row
+    else
+        {   
+        if ( posY >= ( iGridHeight - 1 ) )
+            {
+            iTopLeftIndex = ( posY - ( iGridHeight - 1 ) ) * KGridWidth;    
+            }
+        else // Only one (incomplete) row
+            { 
+            iTopLeftIndex = ( posY ) * KGridWidth;    
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::HighlightedGridIndex
+// -----------------------------------------------------------------------------
+//
+TInt CCamBurstThumbnailGridModel::HighlightedGridIndex()
+    {
+    return iCurrHighlight;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::TopLeftGridIndex
+// -----------------------------------------------------------------------------
+//
+TInt CCamBurstThumbnailGridModel::TopLeftGridIndex()
+    {   
+    return iTopLeftIndex;
+    }  
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::HighlightedBurstIndex
+// As used for getting the index in the CONTROLLER's array, which contains
+// both non-deleted AND DELETED items in the array.
+// -----------------------------------------------------------------------------
+//
+TInt CCamBurstThumbnailGridModel::HighlightedBurstIndex()
+    {
+    TInt index = -1;
+    if ( iCurrHighlight != KErrNotFound )
+        {
+        // The "Current Highlight" is the index to the VALID array (non-deleted only)
+        // Need to find the equivalent index in the GLOBAL array (del and non-del)
+        index = ConvertFromValidToGlobalIndex( iCurrHighlight );
+        }    
+
+    return index;
+    }
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::HighlightedImageName
+// -----------------------------------------------------------------------------
+//
+TPtrC CCamBurstThumbnailGridModel::HighlightedImageName()
+    {
+    if ( iCurrHighlight != KErrNotFound )
+        {
+        // The "Current Highlight" is the index to the VALID array (non-deleted only)
+        // Need to find the equivalent index in the GLOBAL array (del and non-del)
+        TInt index = ConvertFromValidToGlobalIndex( iCurrHighlight );
+        if ( index != KErrNotFound )
+            {
+            return iBurstArray->ImageName( index );
+            }
+        }    
+    return TPtrC();
+    }
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::ImageName
+// Returns the image name (no path or extension) of an item.
+// -----------------------------------------------------------------------------
+//
+TPtrC CCamBurstThumbnailGridModel::ImageName( TInt aIndex )
+    {
+    // The "Current Highlight" is the index to the VALID array (non-deleted only)
+    // Need to find the equivalent index in the GLOBAL array (del and non-del)
+    TInt index = ConvertFromValidToGlobalIndex( aIndex );
+    if ( index != KErrNotFound )
+        {
+        return iBurstArray->ImageName( index );
+        }
+    return TPtrC();
+    }
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::ImageFullName
+// Returns the image name (with path and extension) of an item.
+// -----------------------------------------------------------------------------
+//
+TPtrC CCamBurstThumbnailGridModel::ImageFileName( TInt aIndex ) const
+    {
+    return iBurstArray->FileName( aIndex );
+    }
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::RefreshL
+// -----------------------------------------------------------------------------
+//
+void CCamBurstThumbnailGridModel::RefreshL()
+    {
+    // If this function is called, it is to check whether the currently 
+    // highlighted image has not been deleted yet.  This may occur if it has
+    // been viewed and deleted in the post-capture view.
+
+    // Get the global index for the highlighted item
+    TInt index = ConvertFromValidToGlobalIndex( iCurrHighlight );
+
+    // Check it's deleted state
+    TBool deleted = iBurstArray->IsDeleted( index );
+
+    // If the item has been deleted from the BurstArray, we need to update
+    // our state, so run the delete highlight code for the GridModel
+    if ( deleted )
+        {
+        // Update internal state accordingly
+        DeleteHighlightL();
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::SetCurrentMark
+// -----------------------------------------------------------------------------
+//
+void CCamBurstThumbnailGridModel::SetCurrentMark( TBool aSet )
+    {    
+    if ( aSet ) // Setting the mark ON
+        {
+        iValidThumbGrid[iCurrHighlight]->iMarked = ETrue;
+        iImagesMarked++;
+        }    
+    else    // Setting the mark OFF
+        {
+        iValidThumbGrid[iCurrHighlight]->iMarked = EFalse;
+        iImagesMarked--;
+        }
+    NotifyModelObserver( EModelEventThumb );   // Force thumbnail redraw
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::MarkAll
+// -----------------------------------------------------------------------------
+//
+void CCamBurstThumbnailGridModel::MarkAll( TBool aMark )
+    {
+    TInt count = iValidThumbGrid.Count();
+    TInt i;
+
+    // Go through each valid (non-deleted) item
+    for ( i = 0; i < count; i++ )
+        {
+        // If it's not already in the required state (marked or unmarked)
+        if ( !( iValidThumbGrid[i]->iMarked == aMark ) )
+            {
+            // ...change the state of the item
+            iValidThumbGrid[i]->iMarked = aMark;
+
+            // ...and update the internal count
+            if ( aMark )
+                {
+                iImagesMarked++;
+                }
+            else
+                {
+                iImagesMarked--;
+                }
+            }
+        }
+    NotifyModelObserver( EModelEventThumb );   // Force thumbnail redraw
+    }
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::NoOfMarkedImages
+// -----------------------------------------------------------------------------
+//
+TInt CCamBurstThumbnailGridModel::NoOfMarkedImages() const
+    {
+    return iImagesMarked;
+    }
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::NoOfImages
+// -----------------------------------------------------------------------------
+//
+TInt CCamBurstThumbnailGridModel::NoOfImages() const
+    {
+    return iAllThumbGrid.Count();
+    }
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::IsMarkedL
+// -----------------------------------------------------------------------------
+//
+TInt CCamBurstThumbnailGridModel::IsMarkedL( TInt aIndex )
+    {
+    if ( aIndex < 0 || aIndex >= iValidThumbGrid.Count() )
+        {
+        User::Leave( KErrArgument );
+        }
+    return iValidThumbGrid[aIndex]->iMarked;
+    }
+
+
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::DeleteMarkedL
+// -----------------------------------------------------------------------------
+//
+void CCamBurstThumbnailGridModel::DeleteMarkedL()
+    {
+    // Keep track of if we've just deleted the highlighted item.  
+    // If so, we'll need to inform the view, later.
+    TBool highlightDeleted =  iValidThumbGrid[iCurrHighlight]->iMarked ;        
+
+    TInt i;
+    TInt count = iAllThumbGrid.Count();
+    TInt error = KErrNone;
+    for ( i = 0; i < count; i++ )
+        {
+        if ( iAllThumbGrid[i]->iMarked )
+            {    
+            TRAP( error, DeleteItemL( i ) );
+            if ( error )
+                {
+                break;
+                }
+            }
+        }
+    
+    // Do the recalculation required to adjust the positioning of items and
+    // the hightlight
+    DoPostDeleteGridCheck( highlightDeleted );
+    
+    if ( error && error != KErrInUse )
+        {
+        User::Leave( error );
+       }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::DeleteHighlightL
+// -----------------------------------------------------------------------------
+//
+void CCamBurstThumbnailGridModel::DeleteHighlightL()
+    {
+    // Gets the global index of the currently highlighted item
+    TInt globalIndex = ConvertFromValidToGlobalIndex( iCurrHighlight );
+
+    // Delete that item
+    
+    TRAPD( error, DeleteItemL( globalIndex ) );
+    
+    
+    // Check the internal state for any adjustments of visible items, new
+    // highlight position etc.
+    DoPostDeleteGridCheck( ETrue );
+    
+    if ( error && error != KErrInUse )
+        {
+        User::Leave( error );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::DeleteItemL
+// Internal function for deleting a particular item
+// -----------------------------------------------------------------------------
+//
+void CCamBurstThumbnailGridModel::DeleteItemL( TInt aGlobalIndex )
+    {
+    PRINT( _L("Camera => CCamBurstThumbnailGridModel::DeleteItemL") );
+    // If this item was marked, clear the mark and adjust internal state
+    TInt err = KErrNone;
+    if ( !iBurstArray->IsDeleted( aGlobalIndex ) )
+        {
+        PRINT( _L("Camera <> iBurstArray->IsDeleted" ))
+        err = iBurstArray->SetDeleted( aGlobalIndex, ETrue );
+        PRINT1( _L("Camera <> CCamBurstThumbnailGridModel::DeleteItemL: First SetDelete returned %d"), err );
+        }
+    if ( err )
+        { 
+        err = iBurstArray->SetDeleted( aGlobalIndex, ETrue );
+        PRINT1( _L("Camera <> CCamBurstThumbnailGridModel::DeleteItemL: Second SetDelete returned %d"), err );
+        if ( err )
+            {
+            if ( err == KErrInUse )
+                {
+                // set error note text
+                const TDesC& fullPath = iBurstArray->FileName( aGlobalIndex );
+                TInt pos = fullPath.LocateReverse( '\\' );
+                TPtrC fileName = fullPath.Right( fullPath.Length() - pos - 1 );
+                HBufC* text = StringLoader::LoadLC( R_QTN_FLDR_CANT_DELETE_FILE_OPEN, fileName );
+                // show error note
+                CAknInformationNote* dlg = new (ELeave) CAknInformationNote(ETrue);
+                dlg->ExecuteLD(text->Des());
+                CleanupStack::PopAndDestroy( text );
+                }
+            User::Leave( err );
+            //return;
+            }
+        }
+    if ( iAllThumbGrid[aGlobalIndex]->iMarked )
+        {            
+        iAllThumbGrid[aGlobalIndex]->iMarked = EFalse;
+        iImagesMarked--;    // No of marked items
+        }
+
+    // Delete the display thumbnail
+    delete iAllThumbGrid[aGlobalIndex]->iDisplayThumb;
+    iAllThumbGrid[aGlobalIndex]->iDisplayThumb = NULL;                
+
+    // Remove from VALID thumb list.            
+    CThumbnailGridItem* item = iAllThumbGrid[aGlobalIndex];
+    TInt index = iValidThumbGrid.Find( item );    
+
+    if ( index != KErrNotFound )
+        {
+        iValidThumbGrid.Remove( index );
+        }
+    PRINT( _L("Camera <= CCamBurstThumbnailGridModel::DeleteItem") );
+    }
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::DoPostDeleteGridCheck
+// Internal function called after an item has been deleted, to ensure the 
+// correct items are visible, the highlight is valid etc.
+// -----------------------------------------------------------------------------
+//
+void CCamBurstThumbnailGridModel::DoPostDeleteGridCheck( TBool /*aHighlightDeleted*/ )
+    {   
+    // Check the "highlighted" item.  If it's now out of range, move the 
+    // index to be the last valid entry.
+    if ( iCurrHighlight >= iValidThumbGrid.Count() )
+        { 
+        iCurrHighlight = iValidThumbGrid.Count() - 1;
+
+        // Required to update the title pane with a new filename
+        NotifyModelObserver( EModelEventHighlight );
+        }
+
+    // Else the highlight after a delete is still within range, so
+    // just inform the observers, so they can update the title pane with the
+    // correct filename
+    else 
+        {
+        NotifyModelObserver( EModelEventHighlight );
+        }
+
+
+    TInt imagesRemaining = iBurstArray->ImagesRemaining();
+    // Check whether the highlighted item is now visible... it may not be.
+    if ( iTopLeftIndex >= imagesRemaining ||
+         imagesRemaining <= KGridWidth * iGridHeight )
+        {
+        // If this has happened it's because the highlighted cell was one of 
+        // a large number of cells that has been deleted.  The "top left" 
+        // visible cell therefore needs to be updated to be the row above the 
+
+        // If over a screens worth of items remaining, move "top left" to show 
+        // the bottom two rows
+        if ( imagesRemaining > ( KGridWidth * iGridHeight ) )
+            {
+            //            =     [ Total number of rows available   ] - [ two rows ]    * [Width]
+            iTopLeftIndex = ( ( ( iCurrHighlight + 1 ) / KGridWidth ) - iGridHeight ) * KGridWidth;            
+            }
+        else // Less than a screen's worth of items left, so set the first row as top left
+            {
+            iTopLeftIndex = 0;
+            }
+        }
+
+    // Notify observers of a deletion.
+    NotifyModelObserver( EModelEventDeleted );
+        
+    // Check the thumbnails to see if any need remaking
+    RecalculateThumbs();
+    }
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::ScrollGrid( TBool aScrollDown )
+// -----------------------------------------------------------------------------
+//
+void CCamBurstThumbnailGridModel::ScrollGrid( TBool aScrollDown, TInt aNewScrollPos )
+    {
+    
+    // scrollPosition tells where the scroll is (new starting row?)
+    
+    // calculate the new iTopLeftIndex
+    
+    iTopLeftIndex = aNewScrollPos * KGridWidth;
+    
+    PRINT1( _L("Camera <> CCamBurstThumbnailGridModel::ScrollGrid - new postition %d"), iTopLeftIndex );
+    
+    
+    }
+
+
+
+// -----------------------------------------------------------------------------
+// CCamBurstThumbnailGridModel::GridHeight
+// Returns the height of the visible grid, typically 2 or 3 cells high.
+// -----------------------------------------------------------------------------
+//
+TInt CCamBurstThumbnailGridModel::GridHeight()
+    {
+    return iGridHeight;
+    }
+// -----------------------------------------------------------------------------
+// MThumbModelObserver::HighlightChanged
+// Default implementation of the function
+// -----------------------------------------------------------------------------
+//
+void MThumbModelObserver::HighlightChanged() 
+    {
+    // intentionally doing nothing
+    }
+
+// -----------------------------------------------------------------------------
+// MThumbModelObserver::ImagesDeleted
+// Default implementation of the function
+// -----------------------------------------------------------------------------
+//
+void MThumbModelObserver::ImagesDeleted() 
+    {
+    // intentionally doing nothing
+    }
+
+// -----------------------------------------------------------------------------
+// MThumbModelObserver::ThumbnailGenerated
+// Default implementation of the function; does nothing.
+// -----------------------------------------------------------------------------
+//
+void MThumbModelObserver::ThumbnailGenerated()
+    {
+    // intentionally doing nothing
+    }
+
+// -----------------------------------------------------------------------------
+// CThumbnailGridItem::CThumbnailGridItem
+// -----------------------------------------------------------------------------
+//
+CThumbnailGridItem::CThumbnailGridItem()
+    {
+    // intentionally doing nothing
+    }
+
+// -----------------------------------------------------------------------------
+// CThumbnailGridItem::~CThumbnailGridItem
+// -----------------------------------------------------------------------------
+//
+CThumbnailGridItem::~CThumbnailGridItem()
+    {   
+    delete iDisplayThumb;        
+    }
+
+
+//  End of File