/*
* Copyright (c) 2004 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "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 implementation for the FileSelectionBox skin, the skin being
* the displayed element within the rendered XHTML page.
*
*/
// INCLUDE FILES
#include <e32std.h>
#include <AknBidiTextUtils.h>
#include <AknUtils.h>
#include <webkit.rsg>
#include "BrCtl.h"
#include "BrsrStatusCodes.h"
#include "GDIDevicecontext.h"
#include "GDIFont.h"
#include "MVCShell.h"
#include "MVCView.h"
#include "nw_fbox_fileselectionbox.h"
#include "nw_fbox_fileselectionboxskin.h"
#include "nw_fbox_fileselectionboxskini.h"
#include "nw_fbox_formboxutils.h"
#include "nw_fbox_skini.h"
#include "nw_gdi_types.h"
#include "nw_image_epoc32cannedimage.h"
#include "nw_lmgr_imgcontainerboxi.h"
#include "nw_lmgr_rootbox.h"
// EXTERNAL DATA STRUCTURES
// EXTERNAL FUNCTION PROTOTYPES
// CONSTANTS
// Arbitrary limit, specified in bytes, on amount of tolerated wasted space
// within file-name buffer. If the wasted space exceeds this amount, the buffer
// is reallocated. Must not be less than 2 (size of a 2-byte NULL terminator).
const TInt KFileNameWasteThreshold = 50;
// Amount of padding in between text and icon.
const TUint KImageHorizontalPadding = 2;
// MACROS
// LOCAL CONSTANTS AND MACROS
// MODULE DATA STRUCTURES
const
NW_FBox_FileSelectionBoxSkin_Class_t NW_FBox_FileSelectionBoxSkin_Class =
{
{ /* NW_Object_Core */
/* super */ &NW_FBox_Skin_Class,
/* queryInterface */ _NW_Object_Base_QueryInterface
},
{ /* NW_Object_Base */
/* interfaceList */ NULL
},
{ /* NW_Object_Dynamic */
/* instanceSize */ sizeof ( NW_FBox_FileSelectionBoxSkin_t ),
/* construct */ _NW_FBox_FileSelectionBoxSkin_Construct,
/* destruct */ _NW_FBox_FileSelectionBoxSkin_Destruct
},
{ /* NW_FBox_Skin */
/* draw */ _NW_FBox_FileSelectionBoxSkin_Draw,
/* getSize */ _NW_FBox_FileSelectionBoxSkin_GetSize
},
{ /* NW_FBox_FileSelectionBoxSkin */
/* getBaseline */ _NW_FBox_FileSelectionBoxSkin_GetBaseline,
/* reset */ _NW_FBox_FileSelectionBoxSkin_Reset,
/* setActive */ _NW_FBox_FileSelectionBoxSkin_SetActive,
/* split */ _NW_FBox_FileSelectionBoxSkin_Split
}
};
// LOCAL FUNCTION PROTOTYPES
// FORWARD DECLARATIONS
// ============================= LOCAL FUNCTIONS ===============================
// ============================ MEMBER FUNCTIONS ===============================
/* ------------------------------------------------------------------------- *
private methods
* ------------------------------------------------------------------------- */
// -----------------------------------------------------------------------------
// NW_FBox_FileSelectionBoxSkin::GetDirection
// Gets the layout direction, LTR or RTL.
// @param aLmgrBox Ptr to the parent LMgr OOC box class for this skin's box object.
// @param aDir Ptr to desitination into which direction is returned.
// -----------------------------------------------------------------------------
//
static
void
NW_FBox_FileSelectionBoxSkin_GetDirection(
NW_LMgr_Box_t* aLmgrBox,
NW_GDI_FlowDirection_t* aDir )
{
NW_LMgr_Property_t dirProp;
// Parameter assertion block.
NW_ASSERT( aLmgrBox );
NW_ASSERT( aDir );
dirProp.type = NW_CSS_ValueType_Token;
dirProp.value.token = NW_CSS_PropValue_ltr;
NW_LMgr_Box_GetProperty( aLmgrBox, NW_CSS_Prop_textDirection, &dirProp );
*aDir = ( dirProp.value.token == NW_CSS_PropValue_ltr )
? NW_GDI_FlowDirection_LeftRight : NW_GDI_FlowDirection_RightLeft;
}
// -----------------------------------------------------------------------------
// NW_FBox_FileSelectionBoxSkin::GetDisplayText
// Extract the name and extension, no path, from the filename and truncate that
// to fit within the displayable area.
// @param aThisObj Ptr to the OOC class structure for this class.
// @param aDir Text direction.
// @param aImageSize Ptr to image size.
// @param aFont Font being used to display the text.
// @param aInnerRectangle Ptr to rectangle of the box available for text & icon.
// @param aDisplayText Ptr to destination into which the allocated text buffer
// for the display text is returned, which if not NULL, the caller is
// responsible for taking ownership and deallocating when appropriate.
// @return Browser status code:
// KBrsrSuccess if no errors
// KBrsrOutOfMemory if not enough memory
// KBrsrFailure for all other failure conditions
// -----------------------------------------------------------------------------
//
static
TBrowserStatusCode
NW_FBox_FileSelectionBoxSkin_GetDisplayText(
NW_FBox_FileSelectionBoxSkin_t* aThisObj,
NW_GDI_FlowDirection_t aDir,
NW_GDI_Dimension3D_t* aImageSize,
const CFont& aFont,
NW_GDI_Rectangle_t* aInnerRectangle,
HBufC** aDisplayText )
{
// Parameter assertion block.
NW_ASSERT( aThisObj );
NW_ASSERT( aImageSize );
NW_ASSERT( aInnerRectangle );
NW_ASSERT( aDisplayText );
*aDisplayText = NULL;
// If no name yet, then nothing left to do.
if ( aThisObj->iFileNameAndExt.Length() == 0 )
{
return KBrsrSuccess;
}
// Determine the maxiumum width available for the text.
TInt maxWidthInPixels = aInnerRectangle->dimension.width - aImageSize->width
- KImageHorizontalPadding;
// Must be at least 2 pixels wide to display any text.
if ( maxWidthInPixels < 2 )
{
return KBrsrSuccess;
}
// Get text direction.
AknBidiTextUtils::TParagraphDirectionality directionality =
(aDir == NW_GDI_FlowDirection_LeftRight)
? AknBidiTextUtils::ELeftToRight : AknBidiTextUtils::ERightToLeft;
// Allocate buffer for the truncated text.
HBufC* truncatedText = HBufC::New( aThisObj->iFileNameAndExt.Length()
+ KAknBidiExtraSpacePerLine + 1 ); // +1 for NULL terminator
if ( !truncatedText )
{
return KBrsrOutOfMemory;
}
// The buffer is an HBufC, which is a 'constant' class. However, it is
// on the heap and is modifiable if accessed through its pointer.
TPtr ptrTruncatedText( truncatedText->Des() );
// Truncate.
AknBidiTextUtils::ConvertToVisualAndClip( aThisObj->iFileNameAndExt,
ptrTruncatedText, aFont, maxWidthInPixels, maxWidthInPixels,
directionality );
// Make sure it is NULL terminated for legacy text handling.
ptrTruncatedText.ZeroTerminate();
// Return the pointer to the truncated text.
*aDisplayText = truncatedText;
return KBrsrSuccess;
}
// -----------------------------------------------------------------------------
// NW_FBox_FileSelectionBoxSkin::GetImageSize
// Gets the size of the icon used for indicating file-browse.
// @param aFileSelectionBox Ptr to OOC box to which this skin belongs.
// @param aImageSize Ptr to destination for returned image size.
// @return Browser status code, indicating status of operation.
// -----------------------------------------------------------------------------
//
static
TBrowserStatusCode
NW_FBox_FileSelectionBoxSkin_GetImageSize(
NW_FBox_FileSelectionBox_t* aFileSelectionBox,
NW_GDI_Dimension3D_t* aImageSize )
{
NW_LMgr_RootBox_t* rootBox;
const NW_Image_AbstractImage_t* image;
// Parameter assertion block.
NW_ASSERT( aFileSelectionBox );
NW_ASSERT( aImageSize );
NW_TRY( status )
{
// Get root box.
rootBox = NW_LMgr_Box_GetRootBox( NW_LMgr_BoxOf( aFileSelectionBox ) );
NW_ASSERT( rootBox );
// Get image from set of canned images.
NW_ASSERT( rootBox->cannedImages );
image = CONST_CAST( NW_Image_AbstractImage_t*,
NW_Image_CannedImages_GetImage(
rootBox->cannedImages, NW_Image_SelectFile ) );
NW_THROW_ON_NULL( image, status, KBrsrFailure );
// Get image size.
status = NW_Image_AbstractImage_GetSize( image, aImageSize );
_NW_THROW_ON_ERROR( status );
}
// status = KBrsrSuccess; // set by NW_CATCH
NW_CATCH( status )
{
}
NW_FINALLY
{
return status;
}
NW_END_TRY
}
// -----------------------------------------------------------------------------
// NW_FBox_FileSelectionBoxSkin::GetMaxCharExtent
// Gets the max extents (width & height) of a character for the current font.
// @param aFileSelectionBox Ptr to OOC box to which this skin belongs.
// @param aDeviceContext Ptr to GDI device context from which the current font
// and its extents are obtained.
// @param aExtent Ptr to destination into which the extents are returned.
// @return Browser status code, indicating status of operation.
// -----------------------------------------------------------------------------
//
static
TBrowserStatusCode
NW_FBox_FileSelectionBoxSkin_GetMaxCharExtent(
NW_FBox_FileSelectionBox_t* aFileSelectionBox,
CGDIDeviceContext* aDeviceContext,
NW_GDI_Dimension2D_t* aExtent )
{
CFont* font;
CGDIFont* gdiFont;
// Parameter assertion block.
NW_ASSERT( aFileSelectionBox );
NW_ASSERT( aDeviceContext );
NW_ASSERT( aExtent );
// Get the box font.
gdiFont = NW_LMgr_Box_GetFont( NW_LMgr_BoxOf( aFileSelectionBox ) );
NW_ASSERT( gdiFont );
font = ( CFont* )aDeviceContext->GetScaledCFont( gdiFont );
NW_ASSERT( font );
// Get character extents.
aExtent->width = (NW_GDI_Metric_t)font->MaxNormalCharWidthInPixels();
aExtent->height = (NW_GDI_Metric_t)font->HeightInPixels();
return KBrsrSuccess;
}
// -----------------------------------------------------------------------------
// NW_FBox_FileSelectionBoxSkin::DrawText
// Draws the text in the box, the text being the file name selected, if any.
// @param aThisObj Ptr to the OOC class structure for this class.
// @param aFileSelectionBox Ptr to OOC box to which this skin belongs.
// @param aDeviceContect Ptr to GDI device context to use for drawing.
// @param aImageSize Ptr to image size.
// @param aDir Direction of drawing, LTR or RTL.
// @return Browser status code, indicating status of operation.
// -----------------------------------------------------------------------------
//
static
TBrowserStatusCode
NW_FBox_FileSelectionBoxSkin_DrawText(
NW_FBox_FileSelectionBoxSkin_t* aThisObj,
NW_FBox_FileSelectionBox_t* aFileSelectionBox,
CGDIDeviceContext* aDeviceContext,
NW_GDI_Dimension3D_t* aImageSize,
NW_GDI_FlowDirection_t aDir )
{
NW_GDI_Point2D_t start;
const CFont* font;
CGDIFont* gdiFont;
NW_GDI_Rectangle_t innerRect;
NW_LMgr_PropertyValue_t colorVal;
NW_GDI_Color_t oldFgColor;
NW_GDI_Dimension2D_t extent;
HBufC* displayText = NULL;
NW_Text_t* legacyText = NULL;
// Parameter assertion block.
NW_ASSERT( aThisObj );
NW_ASSERT( aFileSelectionBox );
NW_ASSERT( aDeviceContext );
NW_ASSERT( aImageSize );
// Get ALL items that will need to be restored in the "FINALLY" clause:
oldFgColor = aDeviceContext->ForegroundColor();
NW_TRY( status )
{
NW_LMgr_Box_t* lmgrBox = NW_LMgr_BoxOf( aFileSelectionBox );
// Get box's font.
gdiFont = NW_LMgr_Box_GetFont( lmgrBox );
NW_ASSERT( gdiFont );
font = (CFont*)aDeviceContext->GetScaledCFont( gdiFont );
NW_ASSERT( font );
// Get and set the box foreground color.
colorVal.integer = 0;
NW_LMgr_Box_GetPropertyValue( lmgrBox, NW_CSS_Prop_color,
NW_CSS_ValueType_Color, &colorVal );
aDeviceContext->SetForegroundColor( ( NW_GDI_Color_t ) colorVal.integer );
// Get start coordinates.
NW_LMgr_Box_GetInnerRectangle( lmgrBox, &innerRect );
start = innerRect.point;
// Text set every time in order to truncate according to current
// settings. Note, GetDisplayText() may need to allocate a new
// buffer for the truncated text. If that happens, the returned
// descriptor will point to the new buffer, which will need to be
// deallocated below when it is no longer needed.
status = NW_FBox_FileSelectionBoxSkin_GetDisplayText( aThisObj,
aDir, aImageSize, *font, &innerRect, &displayText );
_NW_THROW_ON_ERROR( status );
if ( displayText )
{
if ( displayText->Length() )
{
// Convert from Symbian data structure to legacy data
// structure. For efficiency, this was delayed as long as
// possible but now it's needed. Unfortunately, this will
// allocate another buffer for the text.
legacyText = (NW_Text_t*)NW_Text_UCS2_New(
(NW_Ucs2*)(displayText->Ptr()),
displayText->Length(),
NW_Text_Flags_NullTerminated );
NW_THROW_OOM_ON_NULL( legacyText, status );
// Get extents.
status = aDeviceContext->GetTextExtent( legacyText, gdiFont, 0, aDir, &extent );
_NW_THROW_ON_ERROR( status );
// If RTL, change drawing coordinates.
if ( aDir == NW_GDI_FlowDirection_RightLeft )
{
start.x = innerRect.point.x + innerRect.dimension.width - extent.width;
}
status = aDeviceContext->DrawText( &start, legacyText, gdiFont, 0,
NW_GDI_TextDecoration_None, aDir, extent.width );
_NW_THROW_ON_ERROR( status );
}
}
}
// status = KBrsrSuccess; // set by NW_CATCH
NW_CATCH( status )
{
}
NW_FINALLY
{
// Free any allocated resources.
delete displayText;
NW_Object_Delete( legacyText );
// Restore fg color.
aDeviceContext->SetForegroundColor( oldFgColor );
return status;
}
NW_END_TRY
}
/* ------------------------------------------------------------------------- *
virtual methods
* ------------------------------------------------------------------------- */
// -----------------------------------------------------------------------------
// NW_FBox_FileSelectionBoxSkin::NW_FBox_FileSelectionBoxSkin
// OOC constructor.
// -----------------------------------------------------------------------------
//
TBrowserStatusCode
_NW_FBox_FileSelectionBoxSkin_Construct(
NW_Object_Dynamic_t* aDynamicObject,
va_list* aArgp )
{
TBrowserStatusCode status;
NW_FBox_FileSelectionBoxSkin_t* thisObj;
// For convenience.
thisObj = NW_FBox_FileSelectionBoxSkinOf( aDynamicObject );
// Invoke superclass constructor.
status = _NW_FBox_Skin_Construct( aDynamicObject, aArgp );
if ( status != KBrsrSuccess )
{
return status;
}
// Init member variables.
thisObj->iFullFileName = NULL;
thisObj->iFileNameAndExt.Set( NULL, 0 );
return KBrsrSuccess;
}
// Destructor
void
_NW_FBox_FileSelectionBoxSkin_Destruct( NW_Object_Dynamic_t* aDynamicObject )
{
NW_FBox_FileSelectionBoxSkin_t* thisObj;
// For convenience.
thisObj = NW_FBox_FileSelectionBoxSkinOf( aDynamicObject );
delete thisObj->iFullFileName;
thisObj->iFullFileName = NULL;
thisObj->iFileNameAndExt.Set( NULL, 0 );
}
// -----------------------------------------------------------------------------
// NW_FBox_FileSelectionBoxSkin::Draw
// Draws the box, including border, icon, and text of file name.
// (Other items are commented in header.)
// -----------------------------------------------------------------------------
//
TBrowserStatusCode
_NW_FBox_FileSelectionBoxSkin_Draw(
NW_FBox_Skin_t* aSkin,
NW_LMgr_Box_t* aLmgrBox,
CGDIDeviceContext* aDeviceContext,
NW_Uint8 aHasFocus )
{
NW_FBox_FileSelectionBox_t* fileSelectionBox;
NW_FBox_FileSelectionBoxSkin_t* thisObj;
NW_GDI_Rectangle_t innerRectangle;
NW_GDI_Point2D_t imagePoint;
NW_GDI_Dimension3D_t imageSize;
NW_LMgr_RootBox_t* rootBox;
NW_Image_AbstractImage_t* image;
NW_GDI_FlowDirection_t dir;
// Parameter assertion block.
NW_ASSERT( NW_Object_IsInstanceOf( aSkin, &NW_FBox_FileSelectionBoxSkin_Class ) );
NW_ASSERT( NW_Object_IsInstanceOf( aLmgrBox, &NW_FBox_FileSelectionBox_Class ) );
NW_ASSERT( aDeviceContext );
// For convenience.
fileSelectionBox = NW_FBox_FileSelectionBoxOf( aLmgrBox );
NW_ASSERT( fileSelectionBox );
thisObj = NW_FBox_FileSelectionBoxSkinOf( aSkin );
NW_ASSERT( thisObj );
NW_TRY( status )
{
// Standard paint mode.
aDeviceContext->SetPaintMode( NW_GDI_PaintMode_Copy );
// Let base class draw the box -- borders, padding, background color, etc.
status = _NW_LMgr_Box_Draw( aLmgrBox, aDeviceContext, aHasFocus );
_NW_THROW_ON_ERROR( status );
// Get root box.
rootBox = NW_LMgr_Box_GetRootBox( NW_LMgr_BoxOf( fileSelectionBox ) );
NW_ASSERT( rootBox );
// Get image from set of canned images.
NW_ASSERT( rootBox->cannedImages );
image = CONST_CAST( NW_Image_AbstractImage_t*,
NW_Image_CannedImages_GetImage(
rootBox->cannedImages, NW_Image_SelectFile ) );
NW_THROW_ON_NULL( image, status, KBrsrFailure );
// Get image size.
status = NW_Image_AbstractImage_GetSize( image, &imageSize );
_NW_THROW_ON_ERROR( status );
// Get current direction.
NW_FBox_FileSelectionBoxSkin_GetDirection( aLmgrBox, &dir );
// Draw text first.
status = NW_FBox_FileSelectionBoxSkin_DrawText( thisObj, fileSelectionBox,
aDeviceContext, &imageSize, dir );
_NW_THROW_ON_ERROR( status );
// ==========================================
// Position image within the inner rectangle.
// ==========================================
// Get inner rectangle.
status = NW_LMgr_Box_GetInnerRectangle( aLmgrBox, &innerRectangle );
_NW_THROW_ON_ERROR( status );
// In x dimension, position image to either side; depends on direction.
if ( dir == NW_GDI_FlowDirection_RightLeft )
{
imagePoint.x = innerRectangle.point.x;
}
else
{
imagePoint.x = ( NW_GDI_Metric_t ) ( innerRectangle.point.x
+ innerRectangle.dimension.width - imageSize.width );
}
// In y dimension, center image.
if ( innerRectangle.dimension.height > imageSize.height )
{
imagePoint.y = ( NW_GDI_Metric_t ) ( innerRectangle.point.y
+ ((innerRectangle.dimension.height - imageSize.height) / 2) );
}
else
{
imagePoint.y = ( NW_GDI_Metric_t ) innerRectangle.point.y;
}
// Draw image.
status = NW_Image_AbstractImage_Draw( image, aDeviceContext, &imagePoint );
_NW_THROW_ON_ERROR( status );
}
// status = KBrsrSuccess; // set by NW_CATCH
NW_CATCH( status )
{
}
NW_FINALLY
{
return status;
}
NW_END_TRY
}
// -----------------------------------------------------------------------------
// NW_FBox_FileSelectionBoxSkin::GetBaseline
// Gets the baseline for the content of this box.
// (Other items are commented in header.)
// -----------------------------------------------------------------------------
//
NW_GDI_Metric_t
_NW_FBox_FileSelectionBoxSkin_GetBaseline(NW_FBox_FileSelectionBoxSkin_t* aThisObj,
NW_LMgr_Box_t* aLmgrBox )
{
TBrowserStatusCode status;
CGDIFont* font;
NW_GDI_Metric_t baseline;
NW_REQUIRED_PARAM( aThisObj );
// Parameter assertion block.
NW_ASSERT( NW_Object_IsInstanceOf( aThisObj, &NW_FBox_FileSelectionBoxSkin_Class ) );
NW_ASSERT( NW_Object_IsInstanceOf( aLmgrBox, &NW_FBox_FileSelectionBox_Class ) );
// Set font to match parent.
font = NW_LMgr_Box_GetFont( aLmgrBox );
if ( font )
{
TGDIFontInfo fontInfo;
NW_LMgr_FrameInfo_t padding;
NW_LMgr_FrameInfo_t borderWidth;
NW_GDI_Dimension3D_t imageSize;
status = font->GetFontInfo( &fontInfo );
NW_ASSERT( status == KBrsrSuccess );
// Get padding and border width.
NW_LMgr_Box_GetPadding( aLmgrBox, &padding, ELMgrFrameTop );
NW_LMgr_Box_GetBorderWidth( aLmgrBox, &borderWidth, ELMgrFrameTop );
// Get size of file-selection icon.
status = NW_FBox_FileSelectionBoxSkin_GetImageSize(
NW_FBox_FileSelectionBoxOf( aLmgrBox ), &imageSize );
NW_ASSERT( status == KBrsrSuccess );
if ( status == KBrsrSuccess )
{
// Use bigger of font baseline or image height and then adjust
// for border and padding.
baseline = (NW_GDI_Metric_t)((fontInfo.baseline > imageSize.height)
? fontInfo.baseline : imageSize.height) + borderWidth.top + padding.top;
}
else
{
// Unable to get icon size so font baseline is used, adjusted
// for border and padding.
baseline = fontInfo.baseline + borderWidth.top + padding.top;
}
}
else
{
// Unable to get FontInfo so box height is used.
baseline = NW_LMgr_Box_GetFormatBounds( aLmgrBox ).dimension.height;
}
return baseline;
}
// -----------------------------------------------------------------------------
// NW_FBox_FileSelectionBoxSkin::GetSize
// Gets the size (width & height) needed for the content. The returned width is
// bounded by the display width, adjusted for padding.
// (Other items are commented in header.)
// -----------------------------------------------------------------------------
//
TBrowserStatusCode
_NW_FBox_FileSelectionBoxSkin_GetSize(
NW_FBox_Skin_t* aSkin,
NW_LMgr_Box_t* aLmgrBox,
NW_GDI_Dimension3D_t* aSize )
{
NW_FBox_FileSelectionBox_t* fileSelectionBox;
NW_Uint16 desiredTextAreaWidthInChars;
NW_GDI_Metric_t maxWidth;
NW_GDI_Metric_t desiredTextAreaWidthInPixels;
NW_GDI_Dimension2D_t charExtent;
NW_GDI_Dimension3D_t imageSize;
CGDIDeviceContext* deviceContext;
const NW_GDI_Rectangle_t* rectangle;
NW_LMgr_FrameInfo_t padding;
NW_LMgr_FrameInfo_t borderWidth;
NW_REQUIRED_PARAM( aSkin );
// Parameter assertion block.
NW_ASSERT( aSkin );
NW_ASSERT( aSize );
NW_ASSERT( NW_Object_IsInstanceOf( aLmgrBox, &NW_FBox_FileSelectionBox_Class ) );
NW_TRY( status )
{
// For convenience.
fileSelectionBox = NW_FBox_FileSelectionBoxOf( aLmgrBox );
// Set to zero as default in case error occurs.
aSize->width = 0;
aSize->height = 0;
// Get device context.
deviceContext = NW_LMgr_RootBox_GetDeviceContext( NW_LMgr_Box_GetRootBox( aLmgrBox ) );
NW_ASSERT( deviceContext );
// Get display bounds.
rectangle = deviceContext->DisplayBounds();
// Get max char extents.
status = NW_FBox_FileSelectionBoxSkin_GetMaxCharExtent(
fileSelectionBox, deviceContext, &charExtent );
_NW_THROW_ON_ERROR( status );
// Get size of file-selection icon.
status = NW_FBox_FileSelectionBoxSkin_GetImageSize(
fileSelectionBox, &imageSize );
_NW_THROW_ON_ERROR( status );
// Get padding and border width.
NW_LMgr_Box_GetPadding( aLmgrBox, &padding, ELMgrFrameLeft|ELMgrFrameRight );
NW_LMgr_Box_GetBorderWidth( aLmgrBox, &borderWidth, ELMgrFrameLeft|ELMgrFrameRight );
aSize->height = ( NW_GDI_Metric_t ) ( charExtent.height );
// Height must not be smaller than the icon height.
if ( aSize->height < imageSize.height )
{
aSize->height = imageSize.height;
}
// Max width is bounded by display width, adjusted for padding and borders.
maxWidth = rectangle->dimension.width - padding.left - padding.right
- borderWidth.left - borderWidth.right;
// Determine the width based on desired width. A desired width of 0
// indicates to use width of the display, adjusted for borders, etc.
desiredTextAreaWidthInChars =
NW_FBox_FileSelectionBox_GetDesiredTextAreaWidthInChars( fileSelectionBox );
CGDIFont* font = NW_LMgr_Box_GetFont(aLmgrBox);
desiredTextAreaWidthInPixels = (NW_GDI_Metric_t)desiredTextAreaWidthInChars
* font->GetAverageCharWidthInPixels();
if ( desiredTextAreaWidthInPixels )
{
aSize->width = desiredTextAreaWidthInPixels + KImageHorizontalPadding
+ imageSize.width;
if ( aSize->width > maxWidth )
{
aSize->width = maxWidth;
}
}
else
{
aSize->width = maxWidth;
}
}
NW_CATCH( status )
{
}
NW_FINALLY
{
return status;
}
NW_END_TRY
}
// -----------------------------------------------------------------------------
// NW_FBox_FileSelectionBoxSkin::Reset
// Resets this box; i.e., resets the value of the filename to an empty string
// but does not redraw the field.
// (Other items are commented in header.)
// -----------------------------------------------------------------------------
//
TBrowserStatusCode
_NW_FBox_FileSelectionBoxSkin_Reset( NW_FBox_FileSelectionBoxSkin_t* aThisObj )
{
// Parameter assertion block.
NW_ASSERT( NW_Object_IsInstanceOf( aThisObj, &NW_FBox_FileSelectionBoxSkin_Class ) );
// Clear the field.
if ( aThisObj->iFullFileName )
{
TPtr ptrBuf( aThisObj->iFullFileName->Des() );
ptrBuf.Zero();
// For legacy text handling, always keep a null on end of string.
ptrBuf.ZeroTerminate();
}
aThisObj->iFileNameAndExt.Set( NULL, 0 );
return KBrsrSuccess;
}
// -----------------------------------------------------------------------------
// NW_FBox_FileSelectionBoxSkin::SetActive
// Sets this box to be the active box, which launches the file-selection dialogs.
// (Other items are commented in header.)
// -----------------------------------------------------------------------------
//
TBrowserStatusCode
_NW_FBox_FileSelectionBoxSkin_SetActive( NW_FBox_FileSelectionBoxSkin_t* aThisObj )
{
TInt err = KErrNone;
TBool selected = EFalse;
TBool useNewBuf;
HBufC* buf = NULL;
TPtrC ptrPath( NULL, 0 );
TPtrC ptrRoot( NULL, 0 );
TPtrC ptrMostRecentPath( NULL, 0 );
// Parameter assertion block.
NW_ASSERT( NW_Object_IsInstanceOf( aThisObj, &NW_FBox_FileSelectionBoxSkin_Class ) );
NW_FBox_FileSelectionBox_t* fileSelectionBox = NW_FBox_FileSelectionBoxSkin_GetFileSelectionBox( aThisObj );
NW_FBox_FormLiaison_t* formLiaison = NW_FBox_FormBox_GetFormLiaison(fileSelectionBox);
NW_TRY( status )
{
// If there is already a file selected for this field then use that as
// starting point.
if ( aThisObj->iFullFileName && aThisObj->iFileNameAndExt.Length() )
{
ptrMostRecentPath.Set( aThisObj->iFullFileName->Des() );
}
// Else check for existing form-liaison path.
else
{
NW_FBox_FileSelectionBox_t* fileSelectionBox =
NW_FBox_FileSelectionBoxSkin_GetFileSelectionBox( aThisObj );
NW_FBox_FormLiaison_t* formLiaison =
NW_FBox_FormBox_GetFormLiaison( fileSelectionBox );
status = NW_FBox_FormLiaison_GetMostRecentFileSelectionPath(
formLiaison, ptrMostRecentPath );
_NW_THROW_ON_ERROR( status );
}
// If a recent path exists, use that as the starting point.
if ( ptrMostRecentPath.Length() )
{
TParsePtrC fileNameParser( ptrMostRecentPath );
ptrPath.Set( fileNameParser.DriveAndPath() );
}
// Get dialog provider.
NW_LMgr_Box_t* lmgrBox = NW_LMgr_BoxOf( fileSelectionBox );
NW_LMgr_RootBox_t* rootBox = NW_LMgr_Box_GetRootBox( lmgrBox );
MBoxTreeListener* listener = NW_LMgr_RootBox_GetBoxTreeListener( rootBox );
NW_ASSERT(listener);
MBrCtlDialogsProvider* dialogProvider = ((CView*)listener)->BrCtl()->brCtlDialogsProvider();
// Launch the file-selection dialog.
TRAP( err,
selected = dialogProvider->DialogFileSelectLC(
ptrPath, ptrRoot, buf );
if ( buf )
CleanupStack::Pop(); // buf
else
CleanupStack::PopAndDestroy();
);
if ( err )
{
// Map the system error to browser error: out-of-memory or failure.
NW_THROW_STATUS( status, ((err == KErrNoMemory) ? KBrsrOutOfMemory : KBrsrFailure ) );
}
// Delegate the ECMA onBlur event when the file selection dialog is closed.
// Note, error is ignored. But why?!!!
(void)NW_FBox_FormLiaison_DelegateEcmaEvent( formLiaison,
NW_FBox_FormBox_GetFormCntrlID(fileSelectionBox),
NW_Ecma_Evt_OnBlur );
// _NW_THROW_ON_ERROR( status );
// If no file selected, nothing else to do. The value is unchanged.
if ( selected == EFalse )
{
NW_THROW_STATUS( status, KBrsrSuccess );
}
// The buffer is an HBufC, which is a 'constant' class. However, it is
// on the heap and is modifiable if accessed through its pointer.
TPtr ptrNewBuf( buf->Des() );
// If the user selected the same file as the last time (i.e., the value
// hasn't changed) then nothing else to do.
if ( aThisObj->iFullFileName )
{
if ( ptrNewBuf.Compare( aThisObj->iFullFileName->Des() ) == 0 )
{
NW_THROW_STATUS( status, KBrsrSuccess );
}
}
// =============================
// Conserve on memory usage.
// =============================
// Clear file name and extension for now.
aThisObj->iFileNameAndExt.Set( NULL, 0 );
// Re-use old file-name buffer if it is big enough.
useNewBuf = ETrue; // assume using a new buffer
if ( aThisObj->iFullFileName )
{
TPtr ptrOldBuf( aThisObj->iFullFileName->Des() );
if ( ptrOldBuf.MaxSize() >= ptrNewBuf.Size() )
{
useNewBuf = EFalse;
// Copy newly selected file-name into old buffer.
ptrOldBuf.Copy( ptrNewBuf );
}
}
// If using new buffer, delete old one and save reference to new one.
if ( useNewBuf )
{
delete aThisObj->iFullFileName;
aThisObj->iFullFileName = buf;
buf = NULL;
}
// Re-allocate buffer that is in use if it's wasting too much space.
TPtr tmp( aThisObj->iFullFileName->Des() );
if ( (tmp.MaxSize() - tmp.Size()) > KFileNameWasteThreshold )
{
// +2 for 2-byte NULL terminator
aThisObj->iFullFileName = aThisObj->iFullFileName->ReAlloc( tmp.Size() + 2 );
NW_THROW_OOM_ON_NULL( aThisObj->iFullFileName, status );
}
TPtr tmpNew( aThisObj->iFullFileName->Des() );
// Always zero terminate in order to allow for legacy text handling.
tmpNew.ZeroTerminate();
// Extract the name and extension from the fully-qualified file name.
TPtrC ptr( aThisObj->iFullFileName->Des() );
TParsePtrC fileNameParser( ptr );
aThisObj->iFileNameAndExt.Set( fileNameParser.NameAndExt() );
// =============================
// Re-draw.
// =============================
CGDIDeviceContext* deviceContext =
NW_LMgr_RootBox_GetDeviceContext( rootBox );
// Have the skin class draw the box, passing TRUE to indicate focus.
status = _NW_FBox_FileSelectionBoxSkin_Draw(
NW_FBox_SkinOf( aThisObj ), lmgrBox, deviceContext, NW_TRUE );
_NW_THROW_ON_ERROR( status );
// Make the draw happen now.
deviceContext->PostDraw( ETrue );
// Delegate the ECMA onChange event when a different file is selected.
status = NW_FBox_FormLiaison_DelegateEcmaEvent( formLiaison,
NW_FBox_FormBox_GetFormCntrlID(fileSelectionBox),
NW_Ecma_Evt_OnChange );
_NW_THROW_ON_ERROR( status );
}
// status = KBrsrSuccess; // set by NW_CATCH
NW_CATCH( status )
{
}
NW_FINALLY
{
delete buf;
return status;
}
NW_END_TRY
}
// -----------------------------------------------------------------------------
// NW_FBox_FileSelectionBoxSkin::Split
// Checks to see if this box needs to be split and if so, "splits" it; however,
// this box cannot be split. It is moved to a new line if not already on one.
// That is the best that can be done to split this box.
// (Other items are commented in header.)
// -----------------------------------------------------------------------------
//
TBrowserStatusCode
_NW_FBox_FileSelectionBoxSkin_Split(
NW_FBox_FileSelectionBoxSkin_t* aThisObj,
NW_GDI_Metric_t aSpace,
NW_LMgr_Box_t** aSplitBox,
NW_Uint8 aFlags )
{
NW_LMgr_Box_t* lmgrBox;
NW_FBox_FormBox_t* formBox;
// Parameter assertion block.
NW_ASSERT( NW_Object_IsInstanceOf( aThisObj, &NW_FBox_FileSelectionBoxSkin_Class ) );
NW_ASSERT( aSplitBox );
formBox = NW_FBox_Skin_GetFormBox( NW_FBox_SkinOf( aThisObj ) );
NW_ASSERT( formBox );
lmgrBox = NW_LMgr_BoxOf( formBox );
NW_ASSERT( NW_Object_IsInstanceOf( lmgrBox, &NW_FBox_FileSelectionBox_Class ) );
*aSplitBox = NULL;
// If box does not fit in the space and the box is not on the new line then
// the input box needs to be pushed on the new line.
NW_GDI_Rectangle_t boxBounds = NW_LMgr_Box_GetFormatBounds( lmgrBox );
if ( ( boxBounds.dimension.width > aSpace )
&& !( aFlags & NW_LMgr_Box_SplitFlags_AtNewLine ) )
{
return KBrsrLmgrNoSplit;
}
if ( boxBounds.dimension.width <= aSpace )
{
return KBrsrSuccess;
}
boxBounds.dimension.width = aSpace;
NW_LMgr_Box_SetFormatBounds( lmgrBox, boxBounds );
return KBrsrSuccess;
}
/* ------------------------------------------------------------------------- *
convenience methods
* ------------------------------------------------------------------------- */
// -----------------------------------------------------------------------------
// NW_FBox_FileSelectionBoxSkin::New
// Creates a new instance of this box skin class.
// (Other items are commented in header.)
// -----------------------------------------------------------------------------
//
NW_FBox_FileSelectionBoxSkin_t*
NW_FBox_FileSelectionBoxSkin_New( NW_FBox_FormBox_t* aFormBox )
{
NW_ASSERT( aFormBox );
return ( NW_FBox_FileSelectionBoxSkin_t* )
NW_Object_New( &NW_FBox_FileSelectionBoxSkin_Class, aFormBox );
}