--- /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