diff -r 61bc0f252b2b -r bac7acad7cb3 camerauis/cameraapp/generic/src/CamBurstThumbnailGridModel.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/camerauis/cameraapp/generic/src/CamBurstThumbnailGridModel.cpp Wed Sep 01 12:30:54 2010 +0100 @@ -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 +#include +#include + +#include +#include +#include +#include + + +#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