/*
* Copyright (c) 2000 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:
*
*/
#include <e32def.h> // First to avoid NULL redefine warning (no #ifndef NULL).
#include <calslbs.h> // for Latin.... font methods
#include <nwx_string.h>
#include "nw_fbox_formbox.h"
#include "nw_evt_ecmaevent.h"
#include "nw_fbox_epoc32inputskini.h"
#include "nw_wml1x_wml_1_3_tokens.h"
#include "nw_fbox_inputbox.h"
#include "nw_fbox_textareabox.h"
#include "nw_fbox_passwordbox.h"
#include "nw_fbox_passwordboxi.h"
#include "nw_lmgr_box.h"
#include "nw_lmgr_textbox.h"
#include "nw_lmgr_rootbox.h"
#include "LMgrBoxTreeListener.h"
#include "GDIDevicecontext.h"
#include "nw_fbox_formboxutils.h"
#include "BrsrStatusCodes.h"
#include "nw_lmgr_statictablecellbox.h"
const NW_GDI_Dimension2D_t extraPadding = {2,2};
/* ------------------------------------------------------------------------- *
private methods
* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
static
TBrowserStatusCode
NW_FBox_Epoc32InputSkin_GetMaxCharExtent(NW_FBox_InputBox_t* inputBox,
NW_GDI_Dimension2D_t* extent)
{
CFont* epocCFont;
CGDIFont* font;
CGDIDeviceContext* deviceContext;
NW_LMgr_RootBox_t* rootBox = NULL;
/* parameter assertion block */
NW_ASSERT(inputBox!=NULL);
NW_ASSERT(NW_Object_IsInstanceOf(inputBox, &NW_FBox_InputBox_Class));
NW_ASSERT(extent!=NULL);
/* get device context */
rootBox = NW_LMgr_Box_GetRootBox (NW_LMgr_BoxOf (inputBox));
NW_ASSERT (rootBox != NULL);
deviceContext = NW_LMgr_RootBox_GetDeviceContext (rootBox);
NW_ASSERT (deviceContext != NULL);
/* get the box font */
font = NW_LMgr_Box_GetFont (NW_LMgr_BoxOf(inputBox));
NW_ASSERT (font != NULL);
epocCFont = (CFont*)
deviceContext->GetScaledCFont( font );
/* get character extents */
extent->width = (NW_GDI_Metric_t)epocCFont->MaxNormalCharWidthInPixels();
extent->height = (NW_GDI_Metric_t)epocCFont->HeightInPixels();
return KBrsrSuccess;
}
/* ------------------------------------------------------------------------- */
static
TBrowserStatusCode
NW_FBox_Epoc32InputSkin_TruncateText(NW_FBox_Epoc32InputSkin_t* thisObj,
NW_GDI_Metric_t wrapWidth,
CGDIDeviceContext* deviceContext,
NW_Text_t* text,
CGDIFont* font,
NW_GDI_FlowDirection_t dir)
{
NW_GDI_Dimension2D_t extent;
NW_Text_Length_t valueLength = 0;
NW_Text_Length_t displayLength = 0;
NW_Ucs2* displayStorage = NULL;
NW_Ucs2* valueStorage = NULL;
NW_TRY(status)
{
status = deviceContext->GetTextExtent(text,
font,
0,
dir,
&extent);
NW_THROW_ON_ERROR(status);
/* Line fits in the space */
if (extent.width - 1 <= wrapWidth)
{
NW_ADT_DynamicVector_InsertAt (thisObj->textList, &text, NW_ADT_Vector_AtEnd);
NW_THROW_SUCCESS(status);
}
/* Line does not fit - truncate it */
valueStorage = NW_Text_GetUCS2Buffer(text, 0, &valueLength, NULL);
NW_THROW_ON_NULL(valueStorage, status, KBrsrFailure);
status = NW_FBox_FormBoxUtils_GetDisplayLength( deviceContext,
text,
font,
valueLength,
(NW_Uint16)wrapWidth,
&displayLength,
NW_FALSE);
NW_THROW_ON_ERROR (status);
displayStorage = NW_Str_New(displayLength + NW_FBox_FormBoxUtils_Truncate_len);
NW_THROW_OOM_ON_NULL(displayStorage, status);
NW_Mem_memcpy(displayStorage, valueStorage, displayLength*sizeof(NW_Ucs2));
NW_Mem_memcpy(displayStorage + displayLength, NW_FBox_FormBoxUtils_Truncate,
NW_FBox_FormBoxUtils_Truncate_len*sizeof(NW_Ucs2));
displayLength += NW_FBox_FormBoxUtils_Truncate_len;
status = NW_Text_SetStorage(text, displayStorage, displayLength, NW_TRUE);
NW_THROW_ON_ERROR (status);
NW_ADT_DynamicVector_InsertAt (thisObj->textList, &text, NW_ADT_Vector_AtEnd);
}
NW_CATCH(status)
{
if (displayStorage)
{
NW_Mem_Free(displayStorage);
}
}
NW_FINALLY
{
return status;
}
NW_END_TRY
}
/* ------------------------------------------------------------------------- */
// NW_FBox_Epoc32GetInnerRectangle
// param: NW_LMgr_Box_t* - pointer to input box
// param: NW_GDI_Rectangle_t* - returns x,y and height,width of inner rectangle
// returns: KBrsrSuccess
// Very similar to LMgrBox.cpp / NW_LMgr_Box_GetInnerRectangle() this routine
// is different in that GetFormatBounds is used here, instead of GetDisplayBounds.
//
static
TBrowserStatusCode
NW_FBox_Epoc32GetInnerRectangle(NW_LMgr_Box_t* box,
NW_GDI_Rectangle_t* innerRectangle)
{
NW_GDI_Rectangle_t bounds;
NW_LMgr_FrameInfo_t padding;
NW_LMgr_FrameInfo_t borderWidth;
/* Get all margin, border and padding settings */
bounds = (NW_LMgr_Box_GetFormatBounds(box));
NW_LMgr_Box_GetPadding(box, &padding, ELMgrFrameAll );
NW_LMgr_Box_GetBorderWidth(box, &borderWidth, ELMgrFrameAll );
innerRectangle->point.x =
(NW_GDI_Metric_t)(bounds.point.x + borderWidth.left + padding.left);
innerRectangle->point.y =
(NW_GDI_Metric_t)(bounds.point.y + borderWidth.top + padding.top);
innerRectangle->dimension.height = (NW_GDI_Metric_t)(bounds.dimension.height -
(borderWidth.top + borderWidth.bottom + padding.top + padding.bottom));
innerRectangle->dimension.width = (NW_GDI_Metric_t)(bounds.dimension.width -
(borderWidth.left + borderWidth.right + padding.left + padding.right));
return KBrsrSuccess;
}
/* ------------------------------------------------------------------------- */
static
TBrowserStatusCode
NW_FBox_Epoc32InputSkin_SplitText(NW_FBox_InputSkin_t* skin,
NW_FBox_InputBox_t* inputBox,
NW_Text_t* text)
{
NW_FBox_Epoc32InputSkin_t* thisObj;
NW_Text_t* splitText = NULL;
CGDIFont *font = NULL;
NW_Text_Length_t length;
NW_LMgr_RootBox_t* rootBox;
CGDIDeviceContext* deviceContext;
NW_GDI_Metric_t wrapWidth;
NW_GDI_Dimension2D_t maxCharExtent;
NW_GDI_Rectangle_t innerRect;
NW_ADT_Vector_Metric_t numTexts = 0;
NW_ADT_Vector_Metric_t numSplits = 0;
NW_LMgr_Property_t prop;
NW_GDI_FlowDirection_t dir;
NW_TRY(status)
{
prop.type = NW_CSS_ValueType_Token;
prop.value.token = NW_CSS_PropValue_ltr;
NW_LMgr_Box_GetProperty(NW_LMgr_BoxOf(inputBox), NW_CSS_Prop_textDirection, &prop);
dir = (prop.value.token == NW_CSS_PropValue_ltr) ? NW_GDI_FlowDirection_LeftRight : NW_GDI_FlowDirection_RightLeft;
/* we're going to need the deviceContext to do text extent calculations */
rootBox = NW_LMgr_Box_GetRootBox(NW_LMgr_BoxOf(inputBox));
NW_ASSERT (rootBox != NULL);
deviceContext = NW_LMgr_RootBox_GetDeviceContext (rootBox);
NW_ASSERT (deviceContext != NULL);
status = NW_FBox_Epoc32InputSkin_GetMaxCharExtent(inputBox, &maxCharExtent);
NW_THROW_ON_ERROR(status);
/* Set the font to match the parent. TODO: this may not be the best policy */
font = NW_LMgr_Box_GetFont (NW_LMgr_BoxOf(inputBox));
NW_ASSERT(font != NULL);
thisObj = NW_FBox_Epoc32InputSkinOf(skin);
/* Get the box info */
NW_FBox_Epoc32GetInnerRectangle(NW_LMgr_BoxOf(inputBox), &innerRect);
innerRect.dimension.height -= extraPadding.height;
innerRect.dimension.width -= extraPadding.width;
numTexts = NW_FBox_InputBox_GetHeight(inputBox);
// one extra character reserved so that EdWin looks good when wrapping
wrapWidth = innerRect.dimension.width;
/* Munch until we have consumed the whole text */
while ((numSplits < numTexts) && (splitText != text))
{
if (numSplits == (numTexts - 1))
{
status = NW_FBox_Epoc32InputSkin_TruncateText( thisObj,
wrapWidth,
deviceContext,
text,
font,
dir);
NW_THROW_ON_ERROR(status);
break;
}
/* try to split at the newline if newline char is within the width */
status = deviceContext->SplitText (text,
font,
wrapWidth, 0,
dir,
&length,
NW_GDI_SplitMode_Newline);
if(status == KBrsrLmgrNoSplit)
{ /* Failed */
/* try to split at space to fit within current line */
status = deviceContext->SplitText ( text,
font,
wrapWidth,
0,
dir,
&length,
NW_GDI_SplitMode_WordWrap );
if(status == KBrsrLmgrNoSplit)
{ /* Failed */
status = deviceContext->SplitText ( text,
font,
wrapWidth,
0,
dir,
&length,
NW_GDI_SplitMode_Clip );
if(status == KBrsrLmgrNoSplit)
{
return KBrsrFailure;
}
}
}
if (status == KBrsrOutOfMemory)
{
return status;
}
if (length != NW_Text_GetCharCount(text))
{
splitText = NW_Text_Split(text, length);
if (splitText == NULL)
{
return KBrsrOutOfMemory;
}
}
else
{
splitText = text;
}
numSplits++;
NW_ADT_DynamicVector_InsertAt (thisObj->textList, &splitText, NW_ADT_Vector_AtEnd);
}
}
NW_CATCH(status)
{
}
NW_FINALLY
{
return KBrsrSuccess;
}
NW_END_TRY
}
/* ------------------------------------------------------------------------- */
void
NW_FBox_Epoc32InputSkin_ClearTextList(NW_FBox_Epoc32InputSkin_t* thisObj)
{
NW_ADT_Vector_Metric_t index;
NW_ADT_Vector_Metric_t size;
NW_Text_t* text;
size = NW_ADT_Vector_GetSize(NW_ADT_VectorOf(thisObj->textList));
/* release the dynamic objects pointed by the object array */
for (index = 0; index < size; index++)
{
text = *(NW_Text_t**)
NW_ADT_Vector_ElementAt(NW_ADT_VectorOf(thisObj->textList), 0);
NW_ADT_DynamicVector_RemoveAt(thisObj->textList, 0);
NW_ASSERT(text);
NW_Object_Delete(text);
}
thisObj->textList->size = 0;
}
/* ------------------------------------------------------------------------- */
static
TBrowserStatusCode
NW_FBox_Epoc32InputSkin_RecreateTextList(NW_FBox_Epoc32InputSkin_t* thisObj)
{
NW_FBox_InputBox_t* inputBox = NULL;
NW_FBox_InputSkin_t* inputSkin = NULL;
NW_Text_t* text = NULL;
TBrowserStatusCode status;
/* parameter assertion block */
NW_ASSERT(NW_Object_IsInstanceOf(thisObj, &NW_FBox_InputSkin_Class));
/* for convenience */
inputSkin = NW_FBox_InputSkinOf(thisObj);
/* get input box */
inputBox = NW_FBox_InputSkin_GetInputBox(inputSkin);
NW_ASSERT(inputBox!=NULL);
/* clears the list of texts */
NW_FBox_Epoc32InputSkin_ClearTextList(thisObj);
/* Now we try to get the text to be displayed */
/* In case of password box, the following code, converts inputbox value
to * and stores it in InputSkin */
if (NW_Object_IsClass(inputBox, &NW_FBox_PasswordBox_Class))
{
status = _NW_FBox_PasswordBox_SetObscureDisplayText(inputBox, NW_TRUE);
if (status != KBrsrSuccess){
return status;
}
if (inputSkin->displayText){
text = NW_Text_Copy(inputSkin->displayText, NW_FALSE);
}
}
else
{
if (inputBox->value){
text = NW_Text_Copy(inputBox->value, NW_FALSE);
}
}
if (text == NULL){
return KBrsrSuccess;
}
/* input text does not fit within the space, input box is on new line,
we need to split the text into multiple rows */
status = NW_FBox_Epoc32InputSkin_SplitText(inputSkin, inputBox, text);
if (status != KBrsrSuccess){
return status;
}
return KBrsrSuccess;
}
/* ------------------------------------------------------------------------- */
static
TBrowserStatusCode
NW_FBox_InputSkin_VKBCallback (void *timerData)
{
NW_FBox_Epoc32InputSkin_t* thisObj = NW_FBox_Epoc32InputSkinOf(timerData);
//retrieve the epoc32 input box
if (thisObj && thisObj->cppEpoc32InputBox)
{
thisObj->cppEpoc32InputBox->ActivateVKB();
}
if (thisObj->vkbTimer != NULL) {
NW_Object_Delete (thisObj->vkbTimer);
thisObj->vkbTimer = NULL;
}
return KBrsrSuccess;
}
/* ------------------------------------------------------------------------- *
global data
* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
const
NW_FBox_Epoc32InputSkin_Class_t NW_FBox_Epoc32InputSkin_Class = {
{ /* NW_Object_Core */
/* super */ &NW_FBox_InputSkin_Class,
/* queryInterface */ _NW_Object_Base_QueryInterface
},
{ /* NW_Object_Base */
/* interfaceList */ NULL
},
{ /* NW_Object_Dynamic */
/* instanceSize */ sizeof (NW_FBox_Epoc32InputSkin_t),
/* construct */ _NW_FBox_Epoc32InputSkin_Construct,
/* destruct */ _NW_FBox_Epoc32InputSkin_Destruct
},
{ /* NW_FBox_Skin */
/* NW_FBox_Skin_Draw */ _NW_FBox_InputSkin_Draw,
/* NW_FBox_Skin_GetSize */ _NW_FBox_Epoc32InputSkin_GetSize
},
{ /* NW_FBox_InputSkin */
/* drawText */ _NW_FBox_Epoc32InputSkin_DrawText,
/* moveCursorLeft */ NULL,
/* moveCursorRight */ NULL,
/* clearLastChar */ NULL,
/* setDisplayText */ _NW_FBox_Epoc32InputSkin_SetDisplayText,
/* setActive */ _NW_FBox_Epoc32InputSkin_SetActive,
/* setFocus */ _NW_FBox_Epoc32InputSkin_SetFocus,
/* detailsDialog */ NULL,
/* split */ _NW_FBox_Epoc32InputSkin_Split,
/* vkb */_NW_FBox_Epoc32InputSkin_SetVKB
},
{ /* NW_FBox_Epoc32InputSkin */
/* unused */ NW_Object_Unused
}
};
/* ------------------------------------------------------------------------- *
virtual methods
* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
TBrowserStatusCode
_NW_FBox_Epoc32InputSkin_Construct (NW_Object_Dynamic_t* dynamicObject,
va_list* argp)
{
TBrowserStatusCode status;
NW_FBox_Epoc32InputSkin_t* thisObj;
/* avoid "unreferenced formal parameter" warnings */
(void) argp;
/* for convenience */
thisObj = NW_FBox_Epoc32InputSkinOf (dynamicObject);
/* invoke our superclass constructor */
status = _NW_FBox_InputSkin_Construct (dynamicObject, argp);
if (status != KBrsrSuccess) {
return status;
}
/* create the TextBox and insert it into our parent */
thisObj->textList = (NW_ADT_DynamicVector_t*)
NW_ADT_ResizableVector_New(sizeof(NW_Text_t*), 3,3);
if (thisObj->textList == NULL){
return KBrsrOutOfMemory;
}
thisObj->cppEpoc32InputBox = NULL;
/* successful completion */
return KBrsrSuccess;
}
/* --------------------------------------------------------------------------*/
void
_NW_FBox_Epoc32InputSkin_Destruct (NW_Object_Dynamic_t* dynamicObject)
{
NW_FBox_Epoc32InputSkin_t* thisObj;
/* for convenience */
thisObj = NW_FBox_Epoc32InputSkinOf (dynamicObject);
/* destroy edwin */
delete thisObj->cppEpoc32InputBox;
thisObj->cppEpoc32InputBox = NULL;
if (thisObj->vkbTimer != NULL) {
NW_Object_Delete (thisObj->vkbTimer);
thisObj->vkbTimer = NULL;
}
NW_FBox_Epoc32InputSkin_ClearTextList(thisObj);
if (thisObj->textList){
NW_Object_Delete(thisObj->textList);
}
}
/* ------------------------------------------------------------------------- */
TBrowserStatusCode
_NW_FBox_Epoc32InputSkin_GetSize(NW_FBox_Skin_t* skin,
NW_LMgr_Box_t* box,
NW_GDI_Dimension3D_t* size)
{
NW_FBox_InputBox_t* inputBox;
NW_GDI_Dimension2D_t charExtent;
NW_LMgr_PropertyValue_t sizeVal;
NW_GDI_Metric_t defaultHeight;
NW_REQUIRED_PARAM (skin);
/* parameter assertion block */
NW_ASSERT (NW_Object_IsInstanceOf (box, &NW_FBox_InputBox_Class));
NW_ASSERT (size!=NULL);
/* for convenience */
inputBox = NW_FBox_InputBoxOf (box);
NW_TRY(status)
{
status = NW_FBox_Epoc32InputSkin_GetMaxCharExtent(inputBox, &charExtent);
NW_THROW_ON_ERROR (status);
/* set width and height basing on the size of the input box */
NW_GDI_Metric_t boxWidth = NW_FBox_InputBox_GetWidth(inputBox);
size->width = (NW_GDI_Metric_t) 0;
if (boxWidth > 0)
{
size->width = (NW_GDI_Metric_t)
((NW_FBox_InputBox_GetWidth(inputBox)+1)*charExtent.width);
}
defaultHeight = (NW_GDI_Metric_t)
(NW_FBox_InputBox_GetHeight(inputBox)*
(charExtent.height + NW_FBOX_INPUTBOX_LINE_SPACING_IN_PIXELS));
size->height = defaultHeight;
/* J-Sky extensions: if width or height properties specified use those. */
status = NW_LMgr_Box_GetPropertyValue(box, NW_CSS_Prop_width, NW_CSS_ValueType_Px, &sizeVal);
if (status == KBrsrSuccess)
size->width = sizeVal.integer;
/* Zero height input box defaults to the height of the line */
status = NW_LMgr_Box_GetPropertyValue(box, NW_CSS_Prop_height, NW_CSS_ValueType_Px, &sizeVal);
if (status == KBrsrSuccess && sizeVal.integer > defaultHeight)
size->height = sizeVal.integer;
if (size->width == 0)
{
NW_LMgr_RootBox_t* rootBox = NW_LMgr_Box_GetRootBox(NW_LMgr_BoxOf(inputBox));
NW_ASSERT(rootBox);
CGDIDeviceContext* deviceContext = NW_LMgr_RootBox_GetDeviceContext (rootBox);
NW_ASSERT(deviceContext);
const NW_GDI_Rectangle_t* rectangle = deviceContext->DisplayBounds();
size->width = rectangle->dimension.width;
NW_LMgr_Box_t* tableBox = NW_LMgr_BoxOf(inputBox);
while (tableBox != NULL)
{
if (NW_Object_IsClass(tableBox, &NW_LMgr_StaticTableCellBox_Class))
{
break;
}
tableBox = (NW_LMgr_Box_t*) NW_LMgr_Box_GetParent(tableBox);
}
if (tableBox != NULL)
{
size->width = size->width / 3;
}
}
/* In case of password box, the following code, converts inputbox value
to * and stores it in InputSkin */
if (NW_Object_IsClass(inputBox, &NW_FBox_PasswordBox_Class))
{
status = _NW_FBox_PasswordBox_SetObscureDisplayText(inputBox, NW_TRUE);
}
}
NW_CATCH (status)
{
}
NW_FINALLY
{
return status;
}
NW_END_TRY
}
/* ------------------------------------------------------------------------- */
TBrowserStatusCode
_NW_FBox_Epoc32InputSkin_Split(NW_FBox_InputSkin_t* inputSkin,
NW_GDI_Metric_t space,
NW_LMgr_Box_t* *splitBox,
NW_Uint8 flags)
{
NW_LMgr_PropertyValue_t sizeVal;
TBrowserStatusCode status;
NW_LMgr_Box_t* box;
NW_FBox_FormBox_t* formBox;
formBox = NW_FBox_Skin_GetFormBox(NW_FBox_SkinOf(inputSkin));
box = NW_LMgr_BoxOf(formBox);
*splitBox = NULL;
/* If box does not fit in the space and the box is not
on the new line the input box needs to be pushed on the new line */
NW_GDI_Rectangle_t boxBounds = NW_LMgr_Box_GetFormatBounds( box );
if ((boxBounds.dimension.width > space) && !(flags & NW_LMgr_Box_SplitFlags_AtNewLine))
{
return KBrsrLmgrNoSplit;
}
if(boxBounds.dimension.width <= space)
{
return KBrsrSuccess;
}
/* if width was specified we do not want to change it */
status = NW_LMgr_Box_GetPropertyValue(box, NW_CSS_Prop_width, NW_CSS_ValueType_Px, &sizeVal);
if (status == KBrsrSuccess){
return status;
}
boxBounds.dimension.width = space;
NW_LMgr_Box_SetFormatBounds( box, boxBounds );
return KBrsrSuccess;
}
/* ------------------------------------------------------------------------- */
TBrowserStatusCode
_NW_FBox_Epoc32InputSkin_DrawText (NW_FBox_InputSkin_t* skin,
CGDIDeviceContext* deviceContext)
{
NW_FBox_Epoc32InputSkin_t* thisObj;
NW_ADT_Vector_Metric_t numTexts;
NW_ADT_Vector_Metric_t index;
NW_GDI_Point2D_t start;
NW_FBox_InputBox_t* inputBox;
CGDIFont* font;
TGDIFontInfo fontInfo;
NW_GDI_Rectangle_t innerRect;
NW_LMgr_PropertyValue_t colorVal;
NW_GDI_Color_t fgColor;
NW_LMgr_Property_t prop;
NW_GDI_FlowDirection_t dir;
/* parameter assertion block */
NW_ASSERT(NW_Object_IsInstanceOf(skin, &NW_FBox_InputSkin_Class));
inputBox = NW_FBox_InputSkin_GetInputBox(skin);
NW_ASSERT(NW_Object_IsInstanceOf(inputBox, &NW_FBox_InputBox_Class));
thisObj = NW_FBox_Epoc32InputSkinOf(skin);
NW_TRY(status) {
/* Get the box font */
font = NW_LMgr_Box_GetFont (NW_LMgr_BoxOf(inputBox));
NW_ASSERT(font != NULL);
/* Get info */
(void)font->GetFontInfo ( &fontInfo);
/* Get the old foreground color */
fgColor = deviceContext->ForegroundColor ();
/* Get and set the box fg color */
colorVal.integer = 0;
NW_LMgr_Box_GetPropertyValue(NW_LMgr_BoxOf(inputBox), NW_CSS_Prop_color, NW_CSS_ValueType_Color, &colorVal);
deviceContext->SetForegroundColor ( (NW_GDI_Color_t)colorVal.integer);
/* Get the start coordinates */
NW_LMgr_Box_GetInnerRectangle(NW_LMgr_BoxOf(inputBox), &innerRect);
innerRect.dimension.height -= extraPadding.height;
innerRect.dimension.width -= extraPadding.width;
start = innerRect.point;
/* Set number of rows to be displayed */
numTexts = NW_ADT_Vector_GetSize(NW_ADT_VectorOf(thisObj->textList));
/* maybe we didn't split the texts */
if (numTexts == 0)
{
status = NW_FBox_InputSkin_SetDisplayText(skin);
NW_THROW_ON_ERROR (status);
numTexts = NW_ADT_Vector_GetSize(NW_ADT_VectorOf(thisObj->textList));
}
if (numTexts > NW_FBox_InputBox_GetHeight(inputBox))
{
numTexts = NW_FBox_InputBox_GetHeight(inputBox);
}
prop.type = NW_CSS_ValueType_Token;
prop.value.token = NW_CSS_PropValue_ltr;
NW_LMgr_Box_GetProperty(NW_LMgr_BoxOf(inputBox), NW_CSS_Prop_textDirection, &prop);
dir = (prop.value.token == NW_CSS_PropValue_ltr) ? NW_GDI_FlowDirection_LeftRight : NW_GDI_FlowDirection_RightLeft;
if (dir == NW_GDI_FlowDirection_RightLeft && start.x > 0)
{
innerRect.dimension.width -= extraPadding.width;
}
/* draw Text */
for (index = 0; index < numTexts; index++)
{
NW_Text_t* text;
NW_Text_t* convertedText;
/* the index of the row to be drawn */
text = *(NW_Text_t**)
NW_ADT_Vector_ElementAt(thisObj->textList, index);
NW_ASSERT (NW_Object_IsInstanceOf (text, &NW_Text_UCS2_Class));
convertedText = NW_FBox_Skin_NonprintableToSpace (text);
NW_THROW_OOM_ON_NULL (convertedText, status);
status = deviceContext->DrawText ( &start,
convertedText, font, 0, NW_GDI_TextDecoration_None, dir, innerRect.dimension.width);
NW_THROW_ON_ERROR (status);
if(convertedText != text)
{
NW_Object_Delete(convertedText);
}
start.y = (NW_GDI_Metric_t)(start.y +
fontInfo.height + NW_FBOX_INPUTBOX_LINE_SPACING_IN_PIXELS);
}
deviceContext->SetForegroundColor ( fgColor);
}
NW_CATCH (status)
{
}
NW_FINALLY
{
return status;
}
NW_END_TRY
}
/* ------------------------------------------------------------------------- */
TBrowserStatusCode
_NW_FBox_Epoc32InputSkin_SetDisplayText(NW_FBox_InputSkin_t* skin)
{
NW_FBox_Epoc32InputSkin_t* epoc32InputSkin;
epoc32InputSkin = NW_FBox_Epoc32InputSkinOf(skin);
return NW_FBox_Epoc32InputSkin_RecreateTextList(epoc32InputSkin);
}
/* ------------------------------------------------------------------------- */
TBrowserStatusCode
_NW_FBox_Epoc32InputSkin_DetailsDialog (NW_FBox_InputSkin_t* thisObj)
{
NW_REQUIRED_PARAM(thisObj);
return KBrsrSuccess;
}
/* ------------------------------------------------------------------------- */
TBrowserStatusCode
_NW_FBox_Epoc32InputSkin_SetVKB(NW_FBox_InputSkin_t* aSkin)
{
NW_FBox_Epoc32InputSkin_t* thisObj = NW_FBox_Epoc32InputSkinOf(aSkin);
//retrieve the epoc32 input box
if (thisObj && thisObj->cppEpoc32InputBox)
{
thisObj->cppEpoc32InputBox->ActivateVKB();
}
// also try to launch async in case dialog is up
if (thisObj->vkbTimer == NULL)
{
thisObj->vkbTimer = NW_System_Timer_New (NW_FBox_InputSkin_VKBCallback,
thisObj, 4000, NW_FALSE);
}
return KBrsrSuccess;
}
/* ------------------------------------------------------------------------- */
TBrowserStatusCode
_NW_FBox_Epoc32InputSkin_SetActive (NW_FBox_InputSkin_t* aSkin)
{
NW_FBox_InputSkin_t* skin = (NW_FBox_InputSkin_t*)aSkin;
NW_GDI_Rectangle_t innerRect;
NW_LMgr_FrameInfo_t padding;
TMargins8 margins;
NW_Uint32 version; /* WBXML encoded to WAPFORUM WML spec version 1.x */
NW_LMgr_Property_t prop;
NW_FBox_Epoc32InputSkin_t* thisObj = NW_FBox_Epoc32InputSkinOf(skin);
/* parameter assertion block */
NW_ASSERT(NW_Object_IsInstanceOf(skin, &NW_FBox_Epoc32InputSkin_Class));
NW_TRY(status)
{
/* for convenience */
status = NW_FBox_Epoc32InputSkin_Redraw(thisObj);
NW_FBox_InputBox_t* inputBox = NW_FBox_InputSkin_GetInputBox (skin);
NW_ASSERT(inputBox);
/* get form liaison - required for WBXML version */
NW_FBox_FormLiaison_t* formLiaison = NW_FBox_FormBox_GetFormLiaison(inputBox);
NW_ASSERT(formLiaison);
/* get device context */
NW_LMgr_RootBox_t* rootBox = NW_LMgr_Box_GetRootBox(NW_LMgr_BoxOf(inputBox));
NW_ASSERT(rootBox);
CGDIDeviceContext* deviceContext = NW_LMgr_RootBox_GetDeviceContext (rootBox);
NW_ASSERT(deviceContext);
/* get the container */
MBoxTreeListener* listener = NW_LMgr_RootBox_GetBoxTreeListener(rootBox);
NW_ASSERT(listener);
CCoeControl* container = (CCoeControl*)listener->GetParentWindow();
NW_ASSERT(container);
/* get the epoc32rect */
NW_LMgr_Box_GetInnerRectangle(NW_LMgr_BoxOf(inputBox), &innerRect);
innerRect.dimension.height -= extraPadding.height;
innerRect.dimension.width -= extraPadding.width;
NW_GDI_Point2D_t origin = *(deviceContext->Origin());
NW_GDI_Rectangle_t bounds = NW_LMgr_Box_GetDisplayBounds( NW_LMgr_BoxOf( inputBox ) );
TRect epoc32Rect( TPoint( bounds.point.x - origin.x, bounds.point.y - origin.y),
TSize( bounds.dimension.width, bounds.dimension.height) );
/* get format and emptyok properties */
NW_FBox_Validator_EmptyOk_t isEmptyOk = NW_FBox_Validator_EmptyOk_None;
const NW_Ucs2* formatBuffer = NULL;
NW_FBox_Validator_Mode_t mode = NW_FBox_Validator_Mode_None;
NW_Text_Length_t formatBufferLength = 0;
if ( inputBox->validator )
{
status = NW_FBox_Validator_GetFormat(inputBox->validator, &formatBuffer, &mode, &isEmptyOk);
_NW_THROW_ON_ERROR(status);
if (formatBuffer)
{
formatBufferLength = (NW_Text_Length_t) NW_Str_Strlen( formatBuffer );
}
}
/* get initial text from */
NW_Ucs2* initialStringBuffer=NULL;
NW_Text_Length_t initialStringLength=0;
if ( inputBox->value )
{
initialStringBuffer = (NW_Ucs2*)inputBox->value->storage;
initialStringLength = inputBox->value->characterCount;
}
/* get isSecret parameter */
TBool isSecret = EFalse;
if(NW_Object_IsInstanceOf(inputBox, &NW_FBox_PasswordBox_Class))
{
isSecret = ETrue;
}
/* get font */
CGDIFont* font = NW_LMgr_Box_GetFont( NW_LMgr_BoxOf( inputBox ) );
NW_THROW_OOM_ON_NULL(font, status);
CFont* epocFont = (CFont*)
deviceContext->GetScaledCFont( font );
/* get max char extent */
NW_GDI_Dimension2D_t maxCharExtent;
status = NW_FBox_Epoc32InputSkin_GetMaxCharExtent(inputBox, &maxCharExtent);
_NW_THROW_ON_ERROR(status);
/* Get box info */
NW_LMgr_Box_GetPadding(NW_LMgr_BoxOf(inputBox), &padding, ELMgrFrameAll );
margins.iLeft = (TInt8)(padding.left+1);
margins.iTop = (TInt8)(padding.top+1);
margins.iRight = (TInt8)padding.right;
margins.iBottom = (TInt8)padding.bottom;
/* if there's one line only - wrap width is one char more to
* avoid jumping while resizing */
TInt wrapWidth = innerRect.dimension.width;
status = NW_FBox_FormLiaison_GetWBXMLVersion(formLiaison, &version);
_NW_THROW_ON_ERROR(status);
prop.type = NW_CSS_ValueType_Token;
prop.value.token = NW_CSS_PropValue_ltr;
NW_LMgr_Box_GetProperty(NW_LMgr_BoxOf(inputBox), NW_CSS_Prop_textDirection, &prop);
/* create CEpoc32InputBox */
TRAPD( err, thisObj->cppEpoc32InputBox =
CEpoc32InputBox::NewL (
container,
thisObj,
epoc32Rect,
margins,
wrapWidth,
TPtrC( initialStringBuffer, initialStringLength ),
TPtrC( formatBuffer, formatBufferLength ),
mode,
isSecret,
isEmptyOk,
version,
NW_FBox_InputBox_GetMaxChars( inputBox ),
*epocFont,
(prop.value.token == NW_CSS_PropValue_ltr) ? ELayoutAlignLeft : ELayoutAlignRight) );
if (err == KErrNoMemory)
{
NW_THROW_STATUS(status, KBrsrOutOfMemory);
}
if (err!=KErrNone)
{
NW_THROW_STATUS(status, KBrsrFailure);
}
(void) NW_FBox_FormLiaison_DelegateEcmaEvent (formLiaison,
NW_FBox_FormBox_GetFormCntrlID(inputBox),
NW_Ecma_Evt_OnClick);
}
NW_CATCH(status) { }
NW_FINALLY
{
return status;
}
NW_END_TRY
}
/* ------------------------------------------------------------------------- */
TBrowserStatusCode
_NW_FBox_Epoc32InputSkin_SetFocus( NW_FBox_InputSkin_t* aSkin, NW_Bool setFocus )
{
TBrowserStatusCode status = KBrsrSuccess;
NW_FBox_InputSkin_t* skin = ( NW_FBox_InputSkin_t* ) aSkin;
/* parameter assertion block */
NW_ASSERT(NW_Object_IsInstanceOf( skin, &NW_FBox_Epoc32InputSkin_Class ) );
/* for convenience */
NW_FBox_InputBox_t* inputBox = NW_FBox_InputSkin_GetInputBox( skin );
NW_ASSERT( inputBox );
if( setFocus && !inputBox->focus )
{
inputBox->focus = NW_TRUE;
/* get form liaison - required for WBXML version */
NW_FBox_FormLiaison_t* formLiaison =
NW_FBox_FormBox_GetFormLiaison( inputBox );
NW_ASSERT(formLiaison);
// generate focus event
status = NW_FBox_FormLiaison_DelegateEcmaEvent(
formLiaison,
NW_FBox_FormBox_GetFormCntrlID( inputBox ),
NW_Ecma_Evt_OnFocus );
}
else if ( !setFocus && inputBox->focus )
inputBox->focus = NW_FALSE;
return status;
}
/* ------------------------------------------------------------------------- *
final methods
* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
void
NW_FBox_Epoc32InputSkin_Scroll(NW_FBox_Epoc32InputSkin_t* thisObj, TInt deltaY)
{
NW_GDI_Point2D_t origin;
NW_FBox_InputBox_t* inputBox;
NW_LMgr_RootBox_t* rootBox;
CGDIDeviceContext* deviceContext;
/* parameter assertion block */
NW_ASSERT (NW_Object_IsInstanceOf (thisObj, &NW_FBox_Epoc32InputSkin_Class));
/* get the device context */
inputBox = NW_FBox_InputSkin_GetInputBox (thisObj);
NW_ASSERT(inputBox);
rootBox = NW_LMgr_Box_GetRootBox(NW_LMgr_BoxOf(inputBox));
NW_ASSERT(rootBox);
deviceContext = NW_LMgr_RootBox_GetDeviceContext (rootBox);
NW_ASSERT(deviceContext);
origin = *(deviceContext->Origin());
origin.y = (NW_GDI_Metric_t) (origin.y - deltaY);
deviceContext->SetOrigin( &origin );
}
/* ------------------------------------------------------------------------- */
TBrowserStatusCode
NW_FBox_Epoc32InputSkin_GetViewRect(NW_FBox_Epoc32InputSkin_t* thisObj, TRect& viewRect)
{
NW_GDI_Rectangle_t viewBounds;
NW_FBox_InputBox_t* inputBox;
NW_LMgr_RootBox_t* rootBox;
CGDIDeviceContext* deviceContext;
/* parameter assertion block */
NW_ASSERT (NW_Object_IsInstanceOf (thisObj, &NW_FBox_Epoc32InputSkin_Class));
NW_TRY(status)
{
/* get the device context */
inputBox = NW_FBox_InputSkin_GetInputBox (thisObj);
NW_THROW_OOM_ON_NULL(inputBox, status);
rootBox = NW_LMgr_Box_GetRootBox(NW_LMgr_BoxOf(inputBox));
NW_ASSERT(rootBox);
deviceContext = NW_LMgr_RootBox_GetDeviceContext (rootBox);
NW_ASSERT(deviceContext);
viewBounds = *(deviceContext->DisplayBounds());
viewRect.iTl.iX = viewBounds.point.x;
viewRect.iTl.iY = viewBounds.point.y;
viewRect.iBr.iX = viewBounds.point.x + viewBounds.dimension.width;
viewRect.iBr.iY = viewBounds.point.y + viewBounds.dimension.height;
}
NW_CATCH(status) {}
NW_FINALLY
{
return status;
}
NW_END_TRY
}
/* ------------------------------------------------------------------------- */
static
void NW_FBox_Epoc32InputSkin_SaveTextAndCloseEdwin(NW_FBox_Epoc32InputSkin_t* thisObj)
{
NW_FBox_InputBox_t* inputBox; /* pointer to associated InputBox class */
HBufC* buf = NULL;
HBufC* newBuf = NULL;
/* parameter assertion block */
NW_ASSERT(NW_Object_IsInstanceOf(thisObj, &NW_FBox_Epoc32InputSkin_Class));
NW_TRY(status)
{
thisObj->posCursorValue = thisObj->cppEpoc32InputBox->CurPos();
thisObj->reallyEdited = NW_TRUE;
inputBox = NW_FBox_InputSkin_GetInputBox (thisObj);
NW_THROW_OOM_ON_NULL(inputBox, status);
/* get text from edwin and save it to the form liaison */
buf = thisObj->cppEpoc32InputBox->ReadableText();
NW_THROW_OOM_ON_NULL(buf, status);
/* deactivate input box */
NW_FBox_InputBox_SetActive (inputBox, NW_FALSE);
/* SetActive doesn't return error status, so make sure that we're not active */
if (NW_FBox_InputBox_IsActive(inputBox)==NW_FALSE)
{
/* destroy edwin */
delete thisObj->cppEpoc32InputBox;
thisObj->cppEpoc32InputBox = NULL;
/* replace all NW_TEXT_UCS2_PARASEP with NW_TEXT_UCS2_CR and NW_TEXT_UCS2_LF */
TInt pos = 0;
TPtr ptr = buf->Des();
TInt len = buf->Length();
// count how many NW_TEXT_UCS2_PARASEP so we know how big buffer we need
TInt count = 0;
while ( pos < len )
{
if ( ptr[pos++] == NW_TEXT_UCS2_PARASEP )
{
count++;
}
}
if (count == 0)
{
status=NW_FBox_Epoc32InputSkin_SetValue(thisObj,
buf->Des().Ptr(),
(NW_Text_Length_t)buf->Length() );
}
else
{
// alloc the new buffer
newBuf = HBufC::NewL( len + count);
NW_THROW_OOM_ON_NULL(newBuf, status);
TPtr newPtr(newBuf->Des());
newPtr.Copy(ptr);
pos = 0;
_LIT(Lf, "\n"); // For NW_TEXT_UCS2_LF
while ( (pos=newPtr.Locate(TChar(NW_TEXT_UCS2_PARASEP))) != KErrNotFound )
{
newPtr[pos++] = NW_TEXT_UCS2_CR;
newPtr.Insert(pos, Lf);
}
status=NW_FBox_Epoc32InputSkin_SetValue(thisObj,
newBuf->Des().Ptr(),
(NW_Text_Length_t)newBuf->Length() );
delete newBuf;
}
NW_THROW_ON_ERROR(status);
/* update value to the form liaison */
status=NW_FBox_InputBox_SetFormLiaisonVal(inputBox);
NW_THROW_ON_ERROR(status);
if(status == KBrsrSuccess)
{
NW_FBox_FormLiaison_t* formLiaison = NW_FBox_FormBox_GetFormLiaison(inputBox);
(void) NW_FBox_FormLiaison_DelegateEcmaEvent (formLiaison,
NW_FBox_FormBox_GetFormCntrlID(inputBox),
NW_Ecma_Evt_OnChange);
}
status=NW_FBox_Epoc32InputSkin_Redraw(thisObj);
NW_THROW_ON_ERROR(status);
}
}
NW_CATCH(status) {}
NW_FINALLY
{
delete buf;
}
NW_END_TRY
}
/* ------------------------------------------------------------------------- */
TBrowserStatusCode
NW_FBox_Epoc32InputSkin_TryExitEditMode(NW_FBox_Epoc32InputSkin_t* thisObj, NW_Bool saveText)
{
NW_FBox_InputBox_t* inputBox; /* pointer to associated InputBox class */
/* parameter assertion block */
NW_ASSERT(NW_Object_IsInstanceOf(thisObj, &NW_FBox_Epoc32InputSkin_Class));
/* for convenience */
NW_TRY(status)
{
inputBox = NW_FBox_InputSkin_GetInputBox (thisObj);
NW_THROW_OOM_ON_NULL(inputBox, status);
NW_THROW_ON_NULL(thisObj->cppEpoc32InputBox, status, KBrsrFailure);
/* if user wants to save his input */
if (saveText == NW_TRUE)
{
/* make sure that input is correct, so we can save it */
if (thisObj->cppEpoc32InputBox->OkToExit())
{
NW_FBox_Epoc32InputSkin_SaveTextAndCloseEdwin( thisObj );
NW_FBox_FormLiaison_t* formLiaison = NW_FBox_FormBox_GetFormLiaison(inputBox);
(void) NW_FBox_FormLiaison_DelegateEcmaEvent (formLiaison,
NW_FBox_FormBox_GetFormCntrlID(inputBox),
NW_Ecma_Evt_OnBlur);
}
else
NW_THROW_STATUS(status, KBrsrFailure);
}
else
{
/* restore original value from the form liaison */
NW_Text_t* buffer = NULL;
NW_FBox_FormLiaison_t* formLiaison = NW_FBox_FormBox_GetFormLiaison(inputBox);
NW_THROW_OOM_ON_NULL(formLiaison, status);
void* controlId = NW_FBox_FormBox_GetFormCntrlID(inputBox);
NW_Bool dummy = NW_FALSE; /* Not used here, but informs us if "value" attribute used */
status = NW_FBox_FormLiaison_GetStringValue(formLiaison, controlId, &buffer, &dummy);
NW_THROW_ON_ERROR(status);
status = NW_FBox_InputBox_SetDefaultVal(inputBox, buffer);
NW_THROW_ON_ERROR(status);
/* restore previous cursor position when cancel input */
thisObj->posCursorValue = thisObj->prevCursorValue;
// if NO static characters involved in format - cancel means NOT REALLY EDITED.
// if static characters are involved - "reallyEdited" will determine what action
// - read, "what initial value" will be displayed by CEpoc32InputBox::SetInitialTextL.
if (!thisObj->cppEpoc32InputBox->IsStaticCharInvolved())
{
thisObj->reallyEdited = NW_FALSE;
}
NW_FBox_InputBox_SetActive(inputBox, NW_FALSE);
/* SetActive doesn't return error status, so make sure that we're not active */
if (NW_FBox_InputBox_IsActive(inputBox)==NW_FALSE)
{
/* destroy edwin */
delete thisObj->cppEpoc32InputBox;
thisObj->cppEpoc32InputBox = NULL;
}
/* text has changed - relayout required */
status = NW_FBox_InputSkin_SetDisplayText(NW_FBox_InputSkinOf(thisObj));
NW_THROW_ON_ERROR(status);
}
}
NW_CATCH(status){
}
NW_FINALLY {
return status;
}
NW_END_TRY
}
/* ------------------------------------------------------------------------- */
NW_Bool
NW_FBox_Epoc32InputSkin_TextChanged(NW_FBox_Epoc32InputSkin_t* thisObj,
const NW_Ucs2* string)
{
const NW_Ucs2* storage;
NW_Text_Length_t length;
NW_Bool freeNeeded;
NW_Int32 ret;
NW_FBox_InputBox_t* inputBox = NW_FBox_InputSkin_GetInputBox (thisObj);
if (inputBox->value == NULL){
return NW_TRUE;
}
storage = NW_Text_GetUCS2Buffer (inputBox->value, 0, &length, &freeNeeded) ;
if (storage == NULL) {
return NW_TRUE;
}
ret = NW_Str_Stricmp(storage, string);
if (freeNeeded){
NW_Mem_Free((NW_Ucs2*)storage);
}
if (ret == 0){
return NW_FALSE;
}
return NW_TRUE;
}
/* ------------------------------------------------------------------------- */
TBrowserStatusCode
NW_FBox_Epoc32InputSkin_SetValue(NW_FBox_Epoc32InputSkin_t* thisObj,
const NW_Ucs2* string,
NW_Text_Length_t length)
{
NW_FBox_InputBox_t* inputBox = NW_FBox_InputSkin_GetInputBox (thisObj);
if (inputBox->value == NULL)
{
inputBox->value = (NW_Text_t*)
NW_Text_UCS2_New((void*)string, length, NW_Text_Flags_Copy);
if (inputBox->value == NULL)
{
return KBrsrOutOfMemory;
}
return KBrsrSuccess;
}
TBrowserStatusCode status = NW_Text_SetStorage(inputBox->value, (void*)string, length, NW_Text_Flags_Copy);
return status;
}
/* ------------------------------------------------------------------------- */
TBrowserStatusCode
NW_FBox_Epoc32InputSkin_Redraw(NW_FBox_Epoc32InputSkin_t* thisObj)
{
NW_FBox_InputBox_t* inputBox = NW_FBox_InputSkin_GetInputBox (thisObj);
NW_ASSERT(inputBox);
return NW_LMgr_Box_Refresh(NW_LMgr_BoxOf(inputBox));
}
/* ------------------------------------------------------------------------- */
TBrowserStatusCode
NW_FBox_Epoc32InputSkin_RedrawScreen(NW_FBox_Epoc32InputSkin_t* thisObj)
{
NW_LMgr_RootBox_t* rootBox;
MBoxTreeListener* boxTreeListener;
NW_FBox_InputBox_t* inputBox = NW_FBox_InputSkin_GetInputBox (thisObj);
NW_ASSERT (inputBox != NULL);
/* we're going to need the deviceContext to redraw the box */
rootBox = NW_LMgr_Box_GetRootBox(NW_LMgr_BoxOf(inputBox));
NW_ASSERT (rootBox != NULL);
boxTreeListener = NW_LMgr_RootBox_GetBoxTreeListener(rootBox);
NW_ASSERT (boxTreeListener != NULL);
return boxTreeListener->RedrawDisplay (NW_TRUE);
}
/* ------------------------------------------------------------------------- *
convenience methods
* ------------------------------------------------------------------------- */
NW_FBox_InputSkin_t*
NW_FBox_InputSkin_New (NW_FBox_FormBox_t* formBox)
{
return (NW_FBox_InputSkin_t*)
NW_Object_New (&NW_FBox_Epoc32InputSkin_Class, formBox);
}