/*
* 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 FILES
#include <AknUtils.h>
#include "nw_fbox_wmlformathandler.h"
#include "NW_Unicode_LetterOther.h"
#include "NW_Unicode_LetterChina.h"
#include "NW_Unicode_LetterThai.h"
// CONSTANTS
static const TUint KWmlFormatNone = 0;
static const TUint KWmlFormatA = 'A';
static const TUint KWmlFormata = 'a';
static const TUint KWmlFormatn = 'n';
static const TUint KWmlFormatN = 'N';
static const TUint KWmlFormatX = 'X';
static const TUint KWmlFormatx = 'x';
static const TUint KWmlFormatm = 'm';
static const TUint KWmlFormatM = 'M';
static const TUint KWmlFormatStatic = '\\';
static const TUint KWmlFormatMultiplier = '*';
// ================= MEMBER FUNCTIONS =======================
// C++ default constructor can NOT contain any code, that
// might leave.
//
TWmlFormatChar::TWmlFormatChar( TUint aChar, TUint aStatic )
: iChar( aChar )
{
iStatic = ( aChar == KWmlFormatStatic ) ? aStatic : 0;
}
// ---------------------------------------------------------
// TWmlFormatChar::ForcedCase
// ---------------------------------------------------------
//
TWmlFormatChar::TWmlCase TWmlFormatChar::ForcedCase() const
{
TWmlCase result;
switch( iChar )
{
case KWmlFormatA :
case KWmlFormatX :
result = EWmlUpperCase;
break;
case KWmlFormata :
case KWmlFormatx :
result = EWmlLowerCase;
break;
case KWmlFormatn :
case KWmlFormatN :
result = EWmlNumericCase;
break;
default:
result = EWmlNone;
break;
}
return result;
}
// ---------------------------------------------------------
// TWmlFormatChar::SuggestedCase
// ---------------------------------------------------------
//
TWmlFormatChar::TWmlCase TWmlFormatChar::SuggestedCase() const
{
TWmlCase result;
switch( iChar )
{
case KWmlFormatA :
case KWmlFormatX :
case KWmlFormatM :
result = EWmlUpperCase;
break;
case KWmlFormata :
case KWmlFormatx :
case KWmlFormatm :
result = EWmlLowerCase;
break;
case KWmlFormatn :
case KWmlFormatN :
result = EWmlNumericCase;
break;
default:
result = EWmlNone;
break;
}
return result;
}
// ---------------------------------------------------------
// TWmlFormatChar::AlphaAllowed
// ---------------------------------------------------------
//
TBool TWmlFormatChar::AlphaAllowed() const
{
TBool result;
switch( iChar )
{
case KWmlFormatA :
case KWmlFormata :
case KWmlFormatX :
case KWmlFormatx :
case KWmlFormatM :
case KWmlFormatm :
case KWmlFormatStatic :
result = ETrue;
break;
default:
result = EFalse;
break;
}
return result;
}
// ---------------------------------------------------------
// TWmlFormatChar::NumericAllowed
// ---------------------------------------------------------
//
TBool TWmlFormatChar::NumericAllowed() const
{
TBool result;
switch( iChar )
{
case KWmlFormatX :
case KWmlFormatx :
case KWmlFormatM :
case KWmlFormatm :
case KWmlFormatn :
case KWmlFormatN :
case KWmlFormatStatic :
result = ETrue;
break;
default:
result = EFalse;
break;
}
return result;
}
// ---------------------------------------------------------
// TWmlFormatChar::SpecialAllowed
// ---------------------------------------------------------
//
TBool TWmlFormatChar::SpecialAllowed() const
{
TBool result;
switch( iChar )
{
case KWmlFormatA :
case KWmlFormata :
case KWmlFormatX :
case KWmlFormatx :
case KWmlFormatM :
case KWmlFormatm :
case KWmlFormatn :
case KWmlFormatStatic :
result = ETrue;
break;
default:
result = EFalse;
break;
}
return result;
}
// ---------------------------------------------------------
// TWmlFormatChar::Char
// ---------------------------------------------------------
//
TUint TWmlFormatChar::Char() const
{
return iChar;
}
// ---------------------------------------------------------
// TWmlFormatChar::Static()
// ---------------------------------------------------------
//
TUint TWmlFormatChar::Static() const
{
return iStatic;
}
// ================= MEMBER FUNCTIONS =======================
// C++ default constructor can NOT contain any code, that
// might leave.
//
TKStaticChar::TKStaticChar( TUint aChar, TInt aPos )
: iChar( aChar )
, iPos( aPos )
{
}
// ---------------------------------------------------------
// TStaticChar::Char
// ---------------------------------------------------------
//
TUint TKStaticChar::Char() const
{
return iChar;
}
// ---------------------------------------------------------
// TStaticChar::Pos
// ---------------------------------------------------------
//
TInt TKStaticChar::Pos() const
{
return iPos;
}
// ================= MEMBER FUNCTIONS =======================
// C++ default constructor can NOT contain any code, that
// might leave.
//
CWmlFormatHandler::CWmlFormatHandler()
: iPostFix( KWmlFormatNone )
{
}
// EPOC default constructor can leave.
void CWmlFormatHandler::ConstructL
( const TDesC& aFormatString, TWapDocType aWapDocType )
{
if ( aWapDocType != EWmlDocType_Wml_1_0 &&
aWapDocType != EWmlDocType_Wml_1_1 &&
aWapDocType != EWmlDocType_Wml_1_2 )
{
// handle unknown types as WML1.3
aWapDocType = EWmlDocType_Wml_1_3;
}
CArrayFixFlat<TInt>* statics = new( ELeave )CArrayFixFlat<TInt>( 3 );
CleanupStack::PushL( statics );
// collect the indexes of static characters
TBool mark = EFalse;
TInt length = aFormatString.Length();
for ( TInt i = 0; i < length; i++ )
{
if ( mark ) // was the previous character prefix?
{
mark = EFalse;
statics->AppendL( i );
}
else
{ // is it prefix?
mark = ( aFormatString[ i ] == KWmlFormatStatic );
}
}
TInt numberOfStatics = statics->Count();
iMinLength = length - numberOfStatics;
iMaxLength = iMinLength;
// *f and nf handling
if ( length > 1 && // longer than one character
( !numberOfStatics || // there are no statics, or it isn't static
statics->At( numberOfStatics - 1 ) != length - 2 ) )
{
if ( aFormatString[ length - 2 ] == KWmlFormatMultiplier ) // *f?
{
iPostFix = aFormatString[ ( --length )-- ];
iMinLength = length - numberOfStatics;
iMaxLength = KInfiniteLength;
}
else
{
TChar n( aFormatString[ length - 2 ] );
if ( n.IsDigit() && n != '0' ) // nf?
{
TInt adjustLength = length;
iPostFix = aFormatString[ ( --adjustLength )-- ];
iMaxLength = adjustLength - numberOfStatics + n.GetNumericValue();
// WML1.0, WML1.1: entry of n characters
// WML1.2, WML1.3: entry of up to n characters
iMinLength = aWapDocType > EWmlDocType_Wml_1_1
? adjustLength - numberOfStatics + 1 : iMaxLength;
}
}
}
// allocate memory for members
iMask = HBufC::NewL( length);
iStatic = new( ELeave )CArrayFixFlat<TKStaticChar>( 3 );
// copy aFormatString to iMask except static text
TInt nextStatic = 0;
for ( TInt j = 0; j < length; j++ )
{
if ( nextStatic < numberOfStatics &&
j == statics->At( nextStatic ) ) // is it static?
{
nextStatic++;
iStatic->AppendL
( TKStaticChar( aFormatString[ j ], j - nextStatic ) );
}
else
{
iMask->Des().Append( aFormatString[ j ] );
}
}
iDynamic = HBufC::NewL( iMinLength );
CleanupStack::PopAndDestroy(); // statics
}
// Two-phased constructor.
CWmlFormatHandler* CWmlFormatHandler::NewLC
( const TDesC& aFormatString, TWapDocType aWapDocType )
{
CWmlFormatHandler* self = new( ELeave )CWmlFormatHandler;
CleanupStack::PushL( self );
self->ConstructL( aFormatString, aWapDocType );
return self;
}
// Two-phased constructor.
CWmlFormatHandler* CWmlFormatHandler::NewL
( const TDesC& aFormatString, TWapDocType aWapDocType )
{
CWmlFormatHandler* self = NewLC( aFormatString, aWapDocType );
CleanupStack::Pop();
return self;
}
// Destructor
CWmlFormatHandler::~CWmlFormatHandler()
{
delete iMask;
delete iStatic;
delete iDynamic;
}
// ---------------------------------------------------------
// CWmlFormatHandler::GetTextOnly
// ---------------------------------------------------------
//
HBufC* CWmlFormatHandler::GetTextOnlyL( )
{
HBufC* newText = HBufC::NewL( iDynamic->Length() );
TPtr ptr = iDynamic->Des();
newText->Des().Copy( ptr );
return newText;
}
// ---------------------------------------------------------
// CWmlFormatHandler::SetTextL
// ---------------------------------------------------------
//
TBool CWmlFormatHandler::SetTextL( const TDesC& aText, TBool aNoValidation )
{
iDynamic->Des().SetLength( 0 ); // ignore previous text
if(AknLayoutUtils::PenEnabled())
{
// ignore validation if VKB is in use
// validation will be done on exit
aNoValidation = ETrue;
}
// insert chars while they are valid
TInt j( 0 );
TInt textLength( aText.Length() );
for ( ;
j < textLength &&
( aNoValidation || ValidateChar( aText[ j ], GetFormat( j ) ) );
j++ )
{
if ( !GetFormat( j ).Static() )
{
InsertL( j, aText[ j ] ); // insert non-static chars
}
}
return j == textLength;
}
// ---------------------------------------------------------
// CWmlFormatHandler::TextLC
// ---------------------------------------------------------
//
HBufC* CWmlFormatHandler::TextLC( TBool aReadable ) const
{
HBufC* text = StaticTextLC(); // get static text
TInt staticLength = text->Length();
TInt dynamicLength = iDynamic->Length();
TInt dynamicPtr( 0 );
TInt staticPtr( 0 );
TInt staticCounter( 0 );
TInt numberOfStatics( iStatic->Count() );
// insert dynamic text into the static text as many as possible
for ( ; dynamicPtr < dynamicLength; ++dynamicPtr, ++staticPtr )
{
// find the next non-static position
while ( staticCounter < numberOfStatics &&
iStatic->At( staticCounter ).Pos() == staticPtr )
{
++staticCounter;
++staticPtr;
}
if ( staticPtr < staticLength ) // is there place for it?
{
/*lint -e{111} Assignment to const object */
text->Des()[ staticPtr ] = aReadable ? ( *iDynamic )[ dynamicPtr ]
: KObscuringChar()[ 0 ];
}
else
{
break;
}
}
if ( dynamicPtr < dynamicLength ) // append the remaining dynamic text
{
HBufC* newText = text->ReAllocL
( staticLength + dynamicLength - dynamicPtr + 1 );
CleanupStack::Pop(); // text
CleanupStack::PushL( newText ); // newText
text = newText;
if ( aReadable )
{
for ( ; dynamicPtr < dynamicLength; dynamicPtr++ )
{
text->Des().Append( ( *iDynamic )[ dynamicPtr ] );
}
}
else
{
for ( ; dynamicPtr < dynamicLength; dynamicPtr++ )
{
text->Des().Append( KObscuringChar );
}
}
}
text->Des().ZeroTerminate();
return text;
}
// ---------------------------------------------------------
// CWmlFormatHandler::InsertL
// ---------------------------------------------------------
//
void CWmlFormatHandler::InsertL( TInt aPos, TChar aChar )
{
TBuf<1> buf;
buf.Append( aChar );
InsertL( aPos, buf );
}
// ---------------------------------------------------------
// CWmlFormatHandler::InsertL
// ---------------------------------------------------------
//
void CWmlFormatHandler::InsertL( TInt aPos, const TDesC& aDes )
{
TInt newPos = PosExludingStatic( aPos );
if ( -1 < newPos && newPos <= iDynamic->Length() )
{
// make sure there's enough space
TInt newLength = iDynamic->Length() + aDes.Length();
if ( iDynamic->Des().MaxLength() < newLength )
{
iDynamic = iDynamic->ReAllocL( newLength );
}
iDynamic->Des().Insert( newPos, aDes );
}
}
// ---------------------------------------------------------
// CWmlFormatHandler::Delete
// ---------------------------------------------------------
//
TBool CWmlFormatHandler::Delete( TInt aPos, TInt aLength )
{
TBool status = EFalse;
TInt newPos = PosExludingStatic( aPos );
if ( -1 < newPos && newPos <= iDynamic->Length() )
{
iDynamic->Des().Delete( newPos, aLength );
status = ETrue;
}
return status;
}
// ---------------------------------------------------------
// CWmlFormatHandler::StaticTextLC
// ---------------------------------------------------------
//
HBufC* CWmlFormatHandler::StaticTextLC() const
{
TInt count = iStatic->Count();
TInt length = ( count ) ? iStatic->At( count - 1 ).Pos() + 1 : 0;
HBufC* empty = HBufC::NewLC( length + 1 );
empty->Des().Fill( ' ', length );
for ( TInt i = 0; i < count; i++ )
{
TKStaticChar staticChar = iStatic->At( i );
/*lint -e{111} Assignment to const object */
empty->Des()[ staticChar.Pos() ] =
STATIC_CAST( TUint16, staticChar.Char() );
}
empty->Des().ZeroTerminate();
return empty;
}
// ---------------------------------------------------------
// CWmlFormatHandler::NumberOfStatic
// ---------------------------------------------------------
//
TInt CWmlFormatHandler::NumberOfStatic() const
{
return iStatic->Count();
}
// ---------------------------------------------------------
// CWmlFormatHandler::GetFormat
// ---------------------------------------------------------
//
TWmlFormatChar CWmlFormatHandler::GetFormat( TInt aIndex ) const
{
TUint code = KWmlFormatNone;
if ( -1 < aIndex )
{
if ( aIndex < iMask->Length() ) // is it in the mask?
{
code = ( *iMask )[ aIndex ];
TChar n( code );
if ( n.IsDigit() || code == KWmlFormatMultiplier ) // nf? *f?
{
++aIndex;
code = ( *iMask )[ aIndex ];
}
}
else
{
if ( aIndex < iMaxLength ||
iMaxLength == KInfiniteLength ) // is it the postfix?
{
code = iPostFix;
}
}
}
TInt staticChar = 0;
if ( code == KWmlFormatStatic ) // is it static?
{
for ( TInt i = iStatic->Count() - 1; i > -1; i-- )
{
if ( iStatic->At( i ).Pos() == aIndex )
{
staticChar = iStatic->At( i ).Char();
break;
}
}
}
return TWmlFormatChar( code, staticChar );
}
// ---------------------------------------------------------
// CWmlFormatHandler::PostFix
// ---------------------------------------------------------
//
TWmlFormatChar CWmlFormatHandler::PostFix() const
{
return iPostFix;
}
// ---------------------------------------------------------
// CWmlFormatHandler::MinLength
// ---------------------------------------------------------
//
TInt CWmlFormatHandler::MinLength() const
{
return iMinLength;
}
// ---------------------------------------------------------
// CWmlFormatHandler::MaxLength
// ---------------------------------------------------------
//
TInt CWmlFormatHandler::MaxLength() const
{
return iMaxLength;
}
// ---------------------------------------------------------
// CWmlFormatHandler::ValidateChar
// ---------------------------------------------------------
//
TBool CWmlFormatHandler::ValidateChar
( TChar aChar, TWmlFormatChar aFormatChar ) const
{
TBool match( EFalse );
if ( aFormatChar.Static() ) // is it static?
{
match = ( aChar == aFormatChar.Static() );
}
else
{
if ( aChar.IsDigit() ) // is it number?
{
match = aFormatChar.NumericAllowed();
}
else
{
if ( aChar.IsAlpha() ) // is it alphabetical?
{
TWmlFormatChar::TWmlCase forcedCase = aFormatChar.ForcedCase();
match = ( forcedCase == TWmlFormatChar::EWmlNone )
? ETrue
: ( aChar.IsUpper() &&
forcedCase == TWmlFormatChar::EWmlUpperCase ) ||
( aChar.IsLower() &&
forcedCase == TWmlFormatChar::EWmlLowerCase );
// If non-western alpha then assume there is no upper and lower case
// - so check for LetterOther or LetterChina/LetterThai (depending upon variant).
// If invalid char for format, value of "match" is retained.
if ( !match && !aChar.IsUpper() && !aChar.IsLower() )
{
NW_Ucs4 uniCompare;
EVariantFlag variant = AknLayoutUtils::Variant();
uniCompare = (NW_Ucs4)aChar;
if (variant == EApacVariant)
{
if ( NW_Unicode_IsLetterChina(uniCompare) )
{
match = ETrue;
}
if ( NW_Unicode_IsLetterThai(uniCompare) )
{
match = ETrue;
}
}
else if ( NW_Unicode_IsLetterOther(uniCompare) )
{
match = ETrue;
}
}
}
else
{ // it's punctuator or symbol
match = aFormatChar.SpecialAllowed();
}
}
}
return match;
}
// ---------------------------------------------------------
// CWmlFormatHandler::ValidateTextLC
// ---------------------------------------------------------
//
CArrayFixFlat<TInt>* CWmlFormatHandler::ValidateTextLC() const
{
CArrayFixFlat<TInt>* errors =
new( ELeave )CArrayFixFlat<TInt>( 3 );
CleanupStack::PushL( errors );
HBufC* text = TextLC();
TInt length( text->Length() );
for ( TInt i = 0; i < length; i++ )
{
if ( !ValidateChar( ( *text )[ i ], GetFormat( i ) ) )
{
errors->AppendL( i );
}
}
CleanupStack::PopAndDestroy(); // text
return errors;
}
// ---------------------------------------------------------
// CWmlFormatHandler::ValidateTextL
// ---------------------------------------------------------
//
TBool CWmlFormatHandler::ValidateTextL() const
{
HBufC* text = TextLC();
TInt length( text->Length() );
TInt i;
for ( i = 0;
i < length && ValidateChar( ( *text )[ i ], GetFormat( i ) );
i++ )
{}
CleanupStack::PopAndDestroy(); // text
return ( i == length );
}
// ---------------------------------------------------------
// CWmlFormatHandler::PosIncludingStatic
// ---------------------------------------------------------
//
TInt CWmlFormatHandler::PosIncludingStatic( TInt aPosExludingStatic )
{
TInt i = 0;
TInt count = iStatic->Count();
for ( ; i < count; i++ )
{
if ( iStatic->At( i ).Pos() <= aPosExludingStatic )
{
aPosExludingStatic++;
}
}
return aPosExludingStatic;
}
// ---------------------------------------------------------
// CWmlFormatHandler::PosExludingStatic
// ---------------------------------------------------------
//
TInt CWmlFormatHandler::PosExludingStatic( TInt aPosIncludingStatic )
{
// find the nearest static character before aPosIncludingStatic
TInt c = iStatic->Count();
TInt i (0);
for ( ;
i < c && aPosIncludingStatic >= iStatic->At( i ).Pos();
i++ )
{
}
return ( aPosIncludingStatic - i );
}
// ---------------------------------------------------------
// CWmlFormatHandler::PreviousNonStatic
// ---------------------------------------------------------
//
TInt CWmlFormatHandler::PreviousNonStatic( TInt aPos )
{
TInt posExludingStatic = PosExludingStatic( aPos );
return ( -1 < posExludingStatic )
? PosIncludingStatic( posExludingStatic )
: KNotFound;
}
// ---------------------------------------------------------
// CWmlFormatHandler::NextNonStatic
// ---------------------------------------------------------
//
TInt CWmlFormatHandler::NextNonStatic( TInt aPos )
{
TInt posExludingStatic = PosExludingStatic( aPos ) + 1;
return ( posExludingStatic < iDynamic->Length() )
? PosIncludingStatic( posExludingStatic )
: KNotFound;
}
// ---------------------------------------------------------
// CWmlFormatHandler::FirstEmpty
// ---------------------------------------------------------
//
TInt CWmlFormatHandler::FirstEmpty()
{
return PosIncludingStatic( iDynamic->Length() );
}
// ---------------------------------------------------------
// CWmlFormatHandler::PreviousStatic
// ---------------------------------------------------------
//
TInt CWmlFormatHandler::PreviousStatic( TInt aPos )
{
TInt prevStaticPos = 0;
TInt i = iStatic->Count() - 1;
for ( ; i >= 0 && iStatic->At( i ).Pos() > aPos; i-- )
{}
if(i >= 0)
{
prevStaticPos = iStatic->At( i ).Pos() ;
}
return prevStaticPos ;
}
// ---------------------------------------------------------
// CWmlFormatHandler::IsPosStatic
// ---------------------------------------------------------
//
TBool CWmlFormatHandler::IsPosStatic( TInt aPos )
{
TInt i = iStatic->Count() - 1;
for ( ; i >= 0 && iStatic->At( i ).Pos() != aPos; i-- )
{}
if(i >= 0)
{
return ETrue;
}
return EFalse;
}
// End of File