/*
* Copyright (c) 2002 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
// System includes
#include <calslbs.h>
#include <eikenv.h>
#include <eikedwin.h>
#include <e32std.h>
#include <PtiDefs.h>
#ifndef SYMBIAN_ENABLE_SPLIT_HEADERS
#include <txtrich.h>
#else
#include <txtrich.h>
#include <txtclipboard.h>
#endif
#include <bautils.h>
#include <webkit.rsg>
#include <PUAcodes.hrh>
#include <FeatMgr.h>
#include <baclipb.h>
#include <aknedsts.h>
// User includes
#include "nw_fbox_WmlFormattedEditor.h"
// CONSTANTS
static const TInt KWmlDefaultTextColor = 215; ///< black (plain text)
static const TInt KWmlFormattedInputErrorColor = 35; ///< TEMP : should be clarified!
const TInt KFullFormattingUpperThreshold=2000;
// ================= MEMBER FUNCTIONS =======================
// C++ default constructor can NOT contain any code, that
// might leave.
//
CWmlFormattedEditor::CWmlFormattedEditor( TBool aIsSecret ) : CEikRichTextEditor()
, iDefaultColour( AKN_LAF_COLOR( KWmlDefaultTextColor ) )
, iErrorColour( AKN_LAF_COLOR( KWmlFormattedInputErrorColor ) )
, iPosAtEnd(EFalse)
, iEventKeyEntered(EFalse)
, iDuplicateEvent(EFalse)
, iVkbState(NULL)
{
SetAknEditorPermittedCaseModes( EAknEditorAllCaseModes );
UpdateInputModeState(EAknEditorTextInputMode, EAknEditorAllInputModes);
TUint flags( EAknEditorFlagDefault |
EAknEditorFlagUseSCTNumericCharmap |
EAknEditorFlagNoT9 | EAknEditorFlagMTAutoOverwrite );
// NOTE: Use of "variant" indicator will be removed in near term - code will be changed
// allowing simpler conditional as EAknEditorFlagLatinInputModesOnly will be allowed
// in European and Apac builds.
EVariantFlag variant = AknLayoutUtils::Variant();
if (aIsSecret && variant == EApacVariant)
{
UpdateFlagsState( flags | EAknEditorFlagLatinInputModesOnly );
SetAknEditorCase( EAknEditorLowerCase );
}
else
{
UpdateFlagsState( flags );
SetAknEditorCase( EAknEditorTextCase );
}
SetBorder(TGulBorder::EDeepSunkenWithOutline);
iWmlEdNavigation = EWmlEditorNavigateRight ;
iPenEnabled = AknLayoutUtils::PenEnabled();
}
// ---------------------------------------------------------
// CWmlFormattedEditor::InitializeL
// ---------------------------------------------------------
//
void CWmlFormattedEditor::InitializeL
( CWmlFormatHandler* aHandler, TBool aSecret, TWmlMode aMode )
{
iHandler = aHandler;
iSecret = aSecret;
if ( iSecret && !iHandler ) // T9 must be disabled in password editor
{
iPassword = HBufC::NewL( 1 );
}
iMode = aMode;
iPrevMode = EWmlModeNone;
/*lint -e{40} Undeclared identifier 'KFeatureIdJapanese'*/
if (!FeatureManager::FeatureSupported(KFeatureIdJapanese))
{
iMode = EWmlModeNone;
}
}
// ---------------------------------------------------------
// CWmlFormattedEditor::SetDefaultColour
// ---------------------------------------------------------
//
void CWmlFormattedEditor::SetDefaultColour( TRgb aDefaultColour )
{
iDefaultColour = aDefaultColour;
}
// ---------------------------------------------------------
// CWmlFormattedEditor::SetErrorColour
// ---------------------------------------------------------
//
void CWmlFormattedEditor::SetErrorColour( TRgb aErrorColour )
{
iErrorColour = aErrorColour;
}
// ---------------------------------------------------------
// CWmlFormattedEditor::EnableT9
// ---------------------------------------------------------
//
void CWmlFormattedEditor::EnableT9( TBool aEnable, TBool aIsSecret )
{
iT9 = aEnable;
TUint flags = iT9 ? EAknEditorFlagDefault |
EAknEditorFlagUseSCTNumericCharmap | EAknEditorFlagMTAutoOverwrite
: EAknEditorFlagDefault |
EAknEditorFlagUseSCTNumericCharmap |
EAknEditorFlagNoT9 | EAknEditorFlagMTAutoOverwrite;
EVariantFlag variant = AknLayoutUtils::Variant();
if (aIsSecret && variant == EApacVariant)
{
UpdateFlagsState( flags | EAknEditorFlagLatinInputModesOnly );
}
else
{
UpdateFlagsState( flags );
}
}
// ---------------------------------------------------------
// CWmlFormattedEditor::IsSecret
// ---------------------------------------------------------
//
TBool CWmlFormattedEditor::IsSecret() const
{
return iSecret;
}
// ---------------------------------------------------------
// CWmlFormattedEditor::ReadableTextL
// ---------------------------------------------------------
//
HBufC* CWmlFormattedEditor::ReadableTextL() const
{
HBufC* result = ReadableTextLC();
CleanupStack::Pop(); // result
return result;
}
// ---------------------------------------------------------
// CWmlFormattedEditor::ReadableTextLC
// ---------------------------------------------------------
//
HBufC* CWmlFormattedEditor::ReadableTextLC() const
{
HBufC* result = NULL;
if ( iHandler ) // formatted?
{
result = iHandler->TextLC(); // zeroterminated
}
else
{
if ( iPassword ) // secret?
{
/*lint --e{1058} nitializing a non-const reference */
// make a zeroterminated copy
result = HBufC::NewLC( iPassword->Length() + 1);
result->Des() = *iPassword;
result->Des().ZeroTerminate();
}
else
{
// make a zeroterminated copy
result = HBufC::NewLC( TextLength() + 1 );
TPtr ptr = result->Des();
if (TextLength() > 0)
{
GetText( ptr );
}
result->Des().ZeroTerminate();
}
}
return result;
}
// ---------------------------------------------------------
// CWmlFormattedEditor::MarkInvalidCharsL
// ---------------------------------------------------------
//
void CWmlFormattedEditor::MarkInvalidCharsL()
{
if ( iHandler )
{
// make character format
TCharFormat charFormat;
charFormat.iFontPresentation.iTextColor = iDefaultColour;
TCharFormatMask charFormatMask;
charFormatMask.SetAttrib( EAttColor );
// unmark all, by colouring to default
RichText()->ApplyCharFormatL
( charFormat, charFormatMask, 0, iText->DocumentLength() );
charFormat.iFontPresentation.iTextColor = iErrorColour;
const CArrayFixFlat<TInt>* errors = iHandler->ValidateTextLC();
TInt endIndex = errors->Count() - 1;
for ( ; endIndex > -1; ) // loop through the errors
{
// find a block of errors
TInt startIndex = endIndex - 1;
TInt endPos = errors->At( endIndex );
for ( ;
startIndex > -1 &&
endPos - errors->At( startIndex ) ==
endIndex - startIndex;
startIndex-- )
{ // find the lower border of error block
}
TInt blockLength = endIndex - startIndex;
RichText()->ApplyCharFormatL // colour that block
( charFormat,
charFormatMask,
errors->At( startIndex + 1 ),
blockLength );
endIndex = startIndex;
}
CleanupStack::PopAndDestroy(); // errors
}
UpdateColour(iDefaultColour);
NotifyNewFormatL(); // redraws editor
}
// ---------------------------------------------------------
// CWmlFormattedEditor::UpdateColour(TRgb aDefaultColour)
// ---------------------------------------------------------
//
void CWmlFormattedEditor::UpdateColour(TRgb aDefaultColour)
{
// make character format
TCharFormat charFormat;
charFormat.iFontPresentation.iTextColor = aDefaultColour;
TCharFormatMask charFormatMask;
charFormatMask.SetAttrib( EAttColor );
RichText()->ApplyCharFormatL(charFormat, charFormatMask, CursorPos(), 0);
}
// ---------------------------------------------------------
// CWmlFormattedEditor::FreePassword
// ---------------------------------------------------------
//
void CWmlFormattedEditor::FreePassword()
{
delete iPassword;
iPassword = NULL;
}
// ---------------------------------------------------------
// CWmlFormattedEditor<Editor>::T9Enabled
// ---------------------------------------------------------
//
TBool CWmlFormattedEditor::T9Enabled() const
{
return iT9;
}
// ---------------------------------------------------------
// CWmlFormattedEditor<Editor>::SetiCursorPos
// Note: when switching modes to and from T9 this will
// prevent duplication of characters when switch from T9 to
// multi-tap input.
// ---------------------------------------------------------
//
void CWmlFormattedEditor::SetiCursorPos()
{
iCursorPos = CursorPos();
}
// ---------------------------------------------------------
// CWmlFormattedEditor<Editor>::ResetFlagEventKeyEntered
// Resets flag used to indicate input via EVENTKEY event handling.
// ---------------------------------------------------------
//
void CWmlFormattedEditor::ResetFlagEventKeyEntered()
{
iEventKeyEntered = EFalse;
}
// ---------------------------------------------------------
// CWmlFormattedEditor<Editor>::IsEventKeyEntered
// Returns iEventKeyEntered, a flag used to indicate when
// key data received via EVENTKEY event handling.
// ---------------------------------------------------------
//
TBool CWmlFormattedEditor::IsEventKeyEntered()
{
return iEventKeyEntered;
}
// ---------------------------------------------------------
// CWmlFormattedEditor::SpecialHandlingPasswordL
// ---------------------------------------------------------
//
void CWmlFormattedEditor::SpecialHandlingPasswordL()
{
TInt cursorPos( CursorPos() );
TInt length( CursorPos() - iCursorPos +1);
if (length <= 0)
{
length = 1;
}
TInt firstEmpty( TextLength() );
if (iHandler && iHandler->NumberOfStatic() > 0)
{
firstEmpty = iHandler->FirstEmpty();
}
if ( (iFirstEmpty <= firstEmpty ) )
{ // insert character into storage place
if ( IsEventKeyEntered() )
{
return; // already added by iEditor->OfferKey
}
HBufC* newText = HBufC::NewLC( length );
TPtr ptr = newText->Des();
Text()->Extract( ptr, iCursorPos, length );
if ( iHandler )
{
iHandler->InsertL( iCursorPos, *newText );
iWmlEdNavigation = EWmlEditorNavigateRight;
}
else
{
if ( iPassword )
{
TInt newLength( iPassword->Length() + length );
if ( newLength > iPassword->Des().MaxLength() )
{
iPassword = iPassword->ReAllocL( newLength + 1);
}
iPassword->Des().Insert( iCursorPos, *newText );
iWmlEdNavigation = EWmlEditorNavigateRight;
}
}
CleanupStack::PopAndDestroy(); // newText
}
else
{ // remove character from storage place
if ( iHandler )
{
iHandler->Delete( cursorPos, 1 ); // cursorPos already is actual cursor - 1
SetCursorPosL( 0 );
iText->Reset();
CEikRichTextEditor::SetTextL( iHandler->TextLC() );
CleanupStack::PopAndDestroy(); // for return value of iHandler->TextLC
SetCursorPosL( cursorPos );
}
else
{
if ( iPassword && cursorPos >= 0 )
{
iPassword->Des().Delete( cursorPos, 1 );
}
}
}
}
// ---------------------------------------------------------
// CWmlFormattedEditor::SpecialStaticHandlingL
// ---------------------------------------------------------
//
void CWmlFormattedEditor::SpecialStaticHandlingL()
{
TInt pos = CursorPos();
TBool adjustPosFlag = EFalse; // if static char in proximity, adjust cursor to get input character.
// There is no special handling if a DELETE (clear/backspace) has been done.
// We now distinguish between a "NavigateLeft" and a "NavigateDelete".
if ( iWmlEdNavigation == EWmlEditorNavigateDelete )
{
// reset
iWmlEdNavigation = EWmlEditorNavigateRight;
return;
}
// This is compensation code for Avkon taking control of cursor movement when looping from last
// char position to first position and Avkon does not send browser input an indication that this is
// happening.
if (iCursorPos > pos)
{
iCursorPos = pos;
if (pos > 0)
{
iCursorPos = pos - 1;
}
}
// If an input box with static text, prep the text to use
// asking if we are doing an insertion
if ( !IsEventKeyEntered() && iHandler && iHandler->NumberOfStatic())
{
HBufC* text = NULL;
TInt length = pos - iCursorPos;
if (length > 0)
{
text = HBufC::NewLC( length );
}
if ( iWmlEdNavigation == EWmlEditorNavigateLeft )
{
iCursorPos = pos; // adjust now
if (iCursorPos > 0)
{
--iCursorPos;
}
iWmlEdNavigation = EWmlEditorNavigateRight;
}
// When a static char is reached during input, the iCursorPos and CursorPos() values indicate the
// correct NEXT location, but edwin seems to ignore where it SHOULD be and the cursor remains on the
// static character location. This code is to compensate in part for this with respect to inserting
// the new character into the saved input area. There is still an issue however
// with edwin / commitinput() re-setting the cursor position to an improper location - that is - it's
// not ahead of the newly inserted character, but behind it.
if ( (pos - 1 >= 0) && iHandler->IsPosStatic( pos - 1 ))
{
--pos;
adjustPosFlag = ETrue;
}
if ( text ) // with whatever info was obtained, store it into iHandler
{
TPtr ptr = text->Des();
Text()->Extract( ptr, iCursorPos, length );
if (adjustPosFlag)
{
iCursorPos = pos;
}
iHandler->InsertL( iCursorPos, *text );
++ iNumberOfCharsInStaticInputBox;
CleanupStack::PopAndDestroy(); // text
}
iCursorPos = pos;
}
}
// ---------------------------------------------------------
// CWmlFormattedEditor::SpecialCharHandlingL
// ---------------------------------------------------------
//
void CWmlFormattedEditor::SpecialCharHandlingL()
{
if (IsSecret() || ( iHandler && iHandler->NumberOfStatic()) )
{
if ( IsSecret() )
{
SpecialHandlingPasswordL();
}
// if secret (that is, type password) -and- static text in format do additional handling
// otherwise if static text in format only (input field is -not- a password type)
// do the additional handling
if (iHandler && iHandler->NumberOfStatic())
{
SpecialStaticHandlingL();
}
UpdateStateL( iWmlEdNavigation, ETrue, ETrue );
}
else
{
if (iHandler)
{
HBufC* text;
text = GetTextInHBufL();
if ( text )
{ // add the new char entry to locally held storage. If there was a shift in input mode
// from char to numeric, it may have been possible for a char to slip in before the new
// input mode may have taken effect in Avkon - so for right now, remove it.
TInt pos = CursorPos();
TWmlFormatChar format = iHandler->GetFormat( pos );
if ( TWmlFormatChar::EWmlNumericCase == format.ForcedCase() )
{
// really want to delete the inadvertantly added char and add the number for "scancode"
text->Des().Delete(text->Length(), 1);
}
CleanupStack::PushL( text );
//iHandler->SetTextL( *text, EFalse ); // removes static stuff and stores chars in iHandler.iDynamic
// For VKB we want all chars to show so we shut off validation.
// Validation will still happen when you try to exit the input box.
iHandler->SetTextL( *text, iPenEnabled ); // removes static stuff and stores chars in iHandler.iDynamic
CleanupStack::PopAndDestroy(); // text
}
else
{
iHandler->SetTextL( KNullDesC(), ETrue );
}
}
}
TInt tempPos = CursorPos();
UpdateEditingParameters( tempPos );
if ( IsEventKeyEntered() && !iInputFormatProcess )
{
ResetFlagEventKeyEntered();
}
}
// ---------------------------------------------------------
// CWmlFormattedEditor::HandleEdwinEventL
// ---------------------------------------------------------
//
void CWmlFormattedEditor::HandleEdwinEventL
( CEikEdwin* /*aEdwin*/, MEikEdwinObserver::TEdwinEvent aEventType )
{
switch ( aEventType )
{
case MEikEdwinObserver::EEventNavigation: // navigation
// Event navigation cannot be done before the text update .
{
// keep cursor away from invalid positions
//SetCursorPosL(iCursorPos);
//CEikEdwin::DrawContents();
//UpdateStateL( EWmlEditorNavigateRight );
break;
}
case MEikEdwinObserver::EEventTextUpdate: // updating
{
if (iDuplicateEvent) // ignore extraneous TextUpdate event - this flag is reset when next "EventKey-X" received in OfferKeyEvent
{
return;
}
iDuplicateEvent = ETrue; // set trap to ignore extraneous TextUpdate events
SpecialCharHandlingL();
break;
}
default:
break;
}
}
// ---------------------------------------------------------
// CWmlFormattedEditor::InputCapabilities
// ---------------------------------------------------------
//
TCoeInputCapabilities CWmlFormattedEditor::InputCapabilities() const
{
return CEikRichTextEditor::IsFocused() ?
CEikRichTextEditor::InputCapabilities() :
TCoeInputCapabilities( TCoeInputCapabilities::ENone );
}
// ---------------------------------------------------------
// CWmlFormattedEditor::OfferKeyEventL
// ---------------------------------------------------------
//
TKeyResponse CWmlFormattedEditor::OfferKeyEventL
( const TKeyEvent& aKeyEvent, TEventCode aType )
{
UpdateColour(iDefaultColour);
TInt newCursorPos = 0; // used below in left/right arrow key handling
TWmlEdNavigation naviType = EWmlEditorNavigateRight;
TKeyResponse response = EKeyWasNotConsumed;
iShift = // filters out the popping up of shift menu
aKeyEvent.iCode && aKeyEvent.iModifiers & EModifierShift;
iDuplicateEvent = EFalse; // reset "trap" for extraneous multi-tap TextUpdate edwin events as we are
// now working on another input (makes no difference if control/numeric/multi-tap).
if (aType != EEventKey)
{
return response;
}
TInt pos( CursorPos() );
switch ( aKeyEvent.iCode )
{
// "short key press" of clear key for deleting numbers - in mixed formats - but be aware
// deletion of chars (and most nums, depending upon format) is now based upon receiving "EventKeyDown" event (see further down).
// If a default format char/number, deletion of numbers is based upon KeyEvent. Also, special handling
// For cursorPos=0, this case is invoked.
case EKeyBackspace:
{
// When pointing to a static character to delete, adjust the cursor position to preserve the
// static character.
TBool doBackspace = ETrue;
if (iHandler && iHandler->NumberOfStatic())
{
doBackspace = HandleClearKeyL( pos );
}
if (doBackspace)
{
response = CEikRichTextEditor::OfferKeyEventL( aKeyEvent, aType );
SpecialCharHandlingL();
}
}
break;
case EKeyLeftArrow:
{
response = CEikRichTextEditor::OfferKeyEventL( aKeyEvent, aType );
newCursorPos = CursorPos();
naviType = EWmlEditorNavigateLeft;
// "iShift" set to 1 indicates a COPY (ie, CCPU) operation is in progress. If that is the case,
// do not adjust cursor position.
if (!iShift && iHandler && iHandler->NumberOfStatic() > 0 && iHandler->IsPosStatic( newCursorPos) )
{
TInt adjustedCursor = iHandler->PreviousNonStatic( newCursorPos );
if (adjustedCursor >= 0)
{
SetCursorPosL( adjustedCursor );
}
//else - positioned next to static chars from pos 0 - change cursor pos to end of input
else
{
adjustedCursor = iHandler->FirstEmpty();
SetCursorPosL( adjustedCursor );
}
iCursorPos = adjustedCursor;
}
}
break;
case EKeyDownArrow:
case EKeyUpArrow:
{
response = CEikRichTextEditor::OfferKeyEventL( aKeyEvent, aType );
}
break;
case EKeyRightArrow:
{
if (iHandler && iHandler->NumberOfStatic() > 0 && iHandler->FirstEmpty() == pos)
{
SetCursorPosL( 0 );
return EKeyWasConsumed;
}
response = CEikRichTextEditor::OfferKeyEventL( aKeyEvent, aType );
newCursorPos = CursorPos();
// "iShift" set to 1 indicates a COPY (ie, CCPU) operation is in progress. If that is the case,
// do not adjust cursor position.
if (!iShift && iHandler && iHandler->NumberOfStatic() > 0 && iHandler->IsPosStatic( newCursorPos))
{
newCursorPos = iHandler->NextNonStatic( newCursorPos );
SetCursorPosL( newCursorPos );
}
}
iCursorPos = newCursorPos;
naviType = EWmlEditorNavigateRight;
break;
default:
{
iEventKeyEntered = ETrue;
iInputFormatProcess = ETrue;
TInt maxLength = iHandler ? iHandler->MaxLength() : KInfiniteLength;
if ( maxLength == KInfiniteLength ||
maxLength > MaxLength() ) // is iHandler and iEditor maxlength different?
{
maxLength = MaxLength();
}
// if the input box is NOT read only and the character in question is NOT a "non character",
// then add the character to the data structure (iDynamic) maintained by class WmlFormatHandler.
if ( !(aKeyEvent.iCode & ENonCharacterKeyBase) && !IsReadOnly() )
{
if ( iHandler && (iHandler->NumberOfStatic() || iSecret) )
{
if (iHandler->FirstEmpty() < maxLength )
{
if ( (TInt)aKeyEvent.iCode == EPtiKey0 && aKeyEvent.iRepeats == 1)
{
iHandler->Delete( pos, 1);
}
iHandler->InsertL( pos, aKeyEvent.iCode );
if(iHandler->MaxLength() == iHandler->TextLC(ETrue)->Length() && pos < iHandler->MaxLength())
{
SetCursorPosL(pos+1);// set it to next cursor pos but not > max length
}
CleanupStack::PopAndDestroy();//iHandler->TextLC
naviType = EWmlEditorNavigateRight;
}
}
else
{
if ( iPassword && pos < MaxLength() )
{
TInt length = iPassword->Length();
if ( length == iPassword->Des().MaxLength() )
{
iPassword =
iPassword->ReAllocL( length + 1 );
}
TBuf<1> currentChar;
currentChar.Append( aKeyEvent.iCode );
// long press on KeyPad0, results in calling HandleEdwinEventL and OfferKeyEvent
// so replace the character
if ( (TInt)aKeyEvent.iCode == EPtiKey0 && aKeyEvent.iRepeats == 1)
{
iPassword->Des().Replace( pos, 1, currentChar );
}
else
{
iPassword->Des().Insert( pos, currentChar );
}
}
}
}
CEikRichTextEditor::OfferKeyEventL( aKeyEvent, aType );
SpecialCharHandlingL();
response = EKeyWasConsumed;
if (IsEventKeyEntered())
{
ResetFlagEventKeyEntered();
}
iInputFormatProcess = EFalse;
break;
}
}
if ( !iShift)
{
CEikEdwin::DrawContents();
}
iWmlEdNavigation = naviType;
return response;
}
// ---------------------------------------------------------
// CWmlFormattedEditor::HandleClearKeyL
// ---------------------------------------------------------
//
TBool CWmlFormattedEditor::HandleClearKeyL( const TInt aCursorPos )
{
TInt pos = aCursorPos;
TBool clearKeyWorked = ETrue;
if (!iHandler || !iHandler->NumberOfStatic())
{
return clearKeyWorked; // if no iHandler, no special handling necessary
}
if ( pos <= 0 ) // if there are no user entered chars left, return
{
return !clearKeyWorked;
}
if ( (pos > 0 || Selection().Length() > 0) && !IsReadOnly() )
{
TInt startDeletingFrom;
TInt charsToDelete;
// if there's a selection - delete it
if ( Selection().Length() )
{
startDeletingFrom = Selection().LowerPos();
charsToDelete = Selection().Length();
}
else
{
startDeletingFrom = pos - 1;
charsToDelete = 1;
}
iHandler->Delete( startDeletingFrom, charsToDelete );
}
else
{
if ( iPassword && pos > 0 )
{
iPassword->Des().Delete( pos - 1, 1 );
}
}
iWmlEdNavigation = EWmlEditorNavigateDelete;
return clearKeyWorked;
}
// ---------------------------------------------------------
// CWmlFormattedEditor::HandleTextPastedL
// ---------------------------------------------------------
//
void CWmlFormattedEditor::HandleTextPastedL( TInt aStartPos, TInt& aLength )
{
// aLength == length of selected text, not what is in copy buffer
// aStartPos == starting position in input box (0 based), and includes static text
if (aLength < 1 || aStartPos < 0)
{
return;
}
HBufC* copiedText = HBufC::NewLC( aLength );
TPtr ptr = copiedText->Des();
// get what is in the clipboard and should be pasted
Text()->Extract( ptr, aStartPos, aLength );
// if there is a format, there is a iHandler, so get the stored text
// from iHandler.iDynamic and manipulate it. Importantly, with this method, we
// don't care if there are static characters in the way when we do
// the pasting.
if ( iHandler )
{
TInt adjustedSelectedLength = 0;
TInt numberStatics = 0;
if (iSelection.Length())
{
TInt temp = iSelection.LowerPos();
// if any static chars in selection, account for them in the length to delete
// from iHandler.iDynamic
for (;temp < iSelection.HigherPos(); ++temp)
{
if (iHandler->IsPosStatic( temp ))
{
++numberStatics;
}
}
adjustedSelectedLength = iSelection.Length() - numberStatics;
iHandler->Delete( iSelection.LowerPos(), adjustedSelectedLength );
// if clipboard is giving us more than selected text will allow, accounting for static chars,
// adjust length
if ( aLength > adjustedSelectedLength )
{
ptr.SetLength( adjustedSelectedLength ); // set lengh of "copiedText" if cannot take all clipboard
}
}
iHandler->InsertL( aStartPos, *copiedText );
}
else
{ // if no iHandler, are we dealing with a password input box & no format
if ( iPassword )
{
TInt newLength( iPassword->Length() + aLength );
if ( newLength > iPassword->Des().MaxLength() )
{
iPassword =
iPassword->ReAllocL( newLength + 1 );
}
iPassword->Des().Insert( aStartPos, *copiedText );
}
}
iCursorPos = aStartPos; // save for possible use by UpdateState if eikedwin does not set up cursorpos correctly
CleanupStack::PopAndDestroy(); // copiedText
}
// ---------------------------------------------------------
// CWmlFormattedEditor::SetTextL
// ---------------------------------------------------------
//
void CWmlFormattedEditor::SetTextL( const TDesC* aDes )
{
TInt pos = 0, length = iText->DocumentLength();
if ( iHandler )
{
/*lint -e{62} Incompatible types (basic) for operator ':' */
iHandler->SetTextL( aDes ? *aDes : KNullDesC );
HBufC* text = iHandler->TextLC( !iSecret );
if ( text->Length() )
{
iText->InsertL( 0, text->Des() );
pos += text->Length();
}
CleanupStack::PopAndDestroy(); // text
}
else
{
if ( aDes && aDes->Length() )
{
const TInt len = aDes->Length();
if ( iPassword )
{
HBufC* newPwd = aDes->AllocL();
// make illegible copy
HBufC* illegibleText = HBufC::NewLC( len );
illegibleText->Des().Fill( KObscuringChar()[ 0 ], len );
iText->InsertL( 0, *illegibleText );
pos += len;
CleanupStack::PopAndDestroy(); // illegibleText
delete iPassword; // replace password with new one
iPassword = newPwd;
}
else
{
iText->InsertL( 0, *aDes );
pos += len;
}
}
}
if ( length )
{
RichText()->DelSetInsertCharFormatL( pos, length );
}
}
// ---------------------------------------------------------
// CWmlFormattedEditor::CcpuCanCut
// ---------------------------------------------------------
//
TBool CWmlFormattedEditor::CcpuCanCut() const
{
// not formatted nor password and doesn't contain static text
return CEikRichTextEditor::CcpuCanCut() &&
!iSecret &&
( !iHandler || !iHandler->NumberOfStatic() );
}
// ---------------------------------------------------------
// CWmlFormattedEditor::CcpuCutL
// ---------------------------------------------------------
//
void CWmlFormattedEditor::CcpuCutL()
{
TCursorSelection selection = Selection();
CEikRichTextEditor::CcpuCutL();
if ( iHandler )
{
iHandler->Delete( selection.LowerPos(), selection.Length() );
}
}
// ---------------------------------------------------------
// CWmlFormattedEditor::CcpuCanCopy
// ---------------------------------------------------------
//
TBool CWmlFormattedEditor::CcpuCanCopy() const
{
return CEikRichTextEditor::CcpuCanCopy() && !iSecret;
}
// ---------------------------------------------------------
// CWmlFormattedEditor::CcpuCanPaste
//
// "TRAPD" use adapted from EIKEDWIN.CPP function CcpuCanPaste
// ---------------------------------------------------------
//
TBool CWmlFormattedEditor::CcpuCanPaste() const
{
if (!iHandler)
{
return ETrue; // if no active format - nothing to check
}
TRAPD(err, DoCanPasteL());
return err == KErrNone;
}
// ---------------------------------------------------------
// CWmlFormattedEditor::DoCanPaste
//
// Adapted from EIKEDWIN.CPP function, DoCcpuCanPasteL().
// It is assumed that iHandler EXISTS for the input box
// under consideration. If it does not exist, then it can be
// assumed that the paste operation may proceed.
// This routine retrieves clipboard info and calls
// CheckPasteAllowedCharsL to see if a paste operation is
// allowed - based upon a comparison with the input box
// format.
// ---------------------------------------------------------
//
void CWmlFormattedEditor::DoCanPasteL() const
{
if (!SelectionLength() && (iTextLimit && (TextLength() >= iTextLimit)))
User::Leave(KErrNotFound);
CClipboard* cb=CClipboard::NewForReadingL(iCoeEnv->FsSession());
CleanupStack::PushL(cb);
TBool richText = ETrue;
TStreamId streamId=cb->StreamDictionary().At(KClipboardUidTypeRichText);
if (streamId==KNullStreamId)
{
streamId=cb->StreamDictionary().At(KClipboardUidTypePlainText);
richText = EFalse;
}
if (streamId==KNullStreamId)
User::Leave(KErrNotFound);
User::LeaveIfError(CheckPasteAllowedCharsL(*cb, richText));
CleanupStack::PopAndDestroy(1); // cb
}
// ---------------------------------------------------------
// CWmlFormattedEditor::CheckPasteAllowedCharsL
//
// Adapted from EIKEDWIN.CPP function, CheckAllowedCharsL,
// this routine validates the characters selected in the
// clipboard against the input box format, if applicable.
// ---------------------------------------------------------
//
TInt CWmlFormattedEditor::CheckPasteAllowedCharsL(CClipboard& aClipboard, TBool aRichText) const
{
CPlainText* txtStore;
CRichText* richText = STATIC_CAST(CRichText*, Text());
if (aRichText && richText)
{
const CParaFormatLayer* paraFormatLayer=richText->GlobalParaFormatLayer();
const CCharFormatLayer* charFormatLayer=richText->GlobalCharFormatLayer();
txtStore = CRichText::NewL(paraFormatLayer, charFormatLayer);
}
else
{
txtStore = CPlainText::NewL();
}
CleanupStack::PushL(txtStore);
txtStore->PasteFromStoreL(aClipboard.Store(), aClipboard.StreamDictionary(), 0);
TPtrC text = txtStore->Read(0);
TInt cursorPos = CursorPos();
TInt length( text.Length() );
if (length > 0)
{
--length; // in the debugger, clipboard length seems to be 1 greater than it should be
}
TInt adjustedPosition = 0;
TInt err = KErrNone;
for ( TInt i = 0; i < length; i++ )
{
TChar ch = text[i];
adjustedPosition = CheckCursorPositionForNextNonStatic(i + cursorPos);
if (adjustedPosition == KNotFound) // assumed the current cursor position is a static character
{
err = KErrNotFound;
break;
}
else if ( ! iHandler->ValidateChar( ch, iHandler->GetFormat( adjustedPosition ) ) )
{
err = KErrNotFound;
break;
}
}
CleanupStack::PopAndDestroy(txtStore);
return err;
}
// ---------------------------------------------------------
// CWmlFormattedEditor::CheckCursorPositionForNextNonStatic
//
// Only interested in checking the current cursor position
// to see if it is a static character. If it is, search for
// the next NON-STATIC cursor position and return that pos.
// If run out of format length, return KNotFound.
// NOTE: The difference between this function and
// CWmlFormatHandler::NextNonStatic is internal input box
// content (iHandler->iDynamic) is not referenced. At this
// point, only interested in what the format mask directs.
// That is why only CWmlFormatHandler::IsPosStatic is used.
// ---------------------------------------------------------
//
TInt CWmlFormattedEditor::CheckCursorPositionForNextNonStatic( TInt aCursorPos ) const
{
if (!iHandler)
{
return aCursorPos;
}
TInt i = 0;
TBool found = ETrue;
TInt length = iHandler->MaxLength(); // quantity of chars entered so far in box considered as maxlength
if (length == KInfiniteLength)
{
length = KFullFormattingUpperThreshold;
}
while ((aCursorPos + i) < length)
{
if (iHandler->IsPosStatic( aCursorPos + i ))
{
++ i;
found = EFalse;
}
else
{
found = ETrue;
break;
}
}
if (!found)
{
return KNotFound;
}
return (aCursorPos + i);
}
// ---------------------------------------------------------
// CWmlFormattedEditor::CcpuPasteL
// ---------------------------------------------------------
//
void CWmlFormattedEditor::CcpuPasteL()
{
// selection is cancelled before HandleTextPastedL is called back, so get value now.
iSelection = iTextView->Selection();
CEikRichTextEditor::CcpuPasteL();
if ( iHandler )
{
UpdateStateL( EWmlEditorNavigateRight );
}
else
{
if ( iPassword )
{
UpdateStateL( EWmlEditorNavigateRight, EFalse );
}
}
}
// ---------------------------------------------------------
// CWmlFormattedEditor::UpdateStateL
// ---------------------------------------------------------
//
void CWmlFormattedEditor::UpdateStateL( TWmlEdNavigation aNaviType,
TBool aUpdateEditingParameters,
TBool aTextChanged )
{
TInt pos( CursorPos() );
if ( iHandler )
{
if (pos > iHandler->FirstEmpty()) // if eikedwin does not set cursor pos correctly
{
pos = iCursorPos;
}
HBufC* tempText = ReadableTextL();
if (iHandler->NumberOfStatic())
{
iFirstEmpty = iHandler->FirstEmpty(); // iHandler->MaxLength();
}
else
{
iFirstEmpty = tempText->Length();
}
delete tempText;
if ( aNaviType != EWmlEditorNavigateRight )
{
for ( ; pos > 0 && iHandler->GetFormat( pos ).Static(); --pos )
;
}
if ( iHandler->GetFormat( pos ).Static() ||
aNaviType == EWmlEditorNavigateRight )
{
for ( ; pos < iFirstEmpty && iHandler->GetFormat( pos ).Static()
; ++pos )
;
}
SetCursorPosL( 0 );
iText->Reset();
CEikRichTextEditor::SetTextL( iHandler->TextLC());
CleanupStack::PopAndDestroy(); // return value of iHandler->TextLC
if ( iSecret && aNaviType == EWmlEditorNavigateRight )
{
SetCursorPosL( pos );
CEikRichTextEditor::SetTextL( iHandler->TextLC( EFalse ) );
CleanupStack::PopAndDestroy(); // return value of iHandler->TextLC
}
}
else
{ // no format involved, so simply use the length of text entered so far
iFirstEmpty = TextLength();
if ( iSecret ) // if password input, update what Avkon with changes
{
HBufC* text = GetTextInHBufL();
if ( text )
{
CleanupStack::PushL( text );
text->Des().Fill( KObscuringChar()[ 0 ] );
CEikRichTextEditor::SetTextL( text );
CleanupStack::PopAndDestroy(); // text
}
}
}
// set editor cursor to correct position
if ( pos != CursorPos() )
{
TCursorSelection selection = Selection();
if ( aTextChanged || selection.LowerPos() == selection.HigherPos())
{
if (iHandler && iHandler->PosIncludingStatic( iHandler->FirstEmpty() ) < pos)
{
pos = iHandler->PosIncludingStatic( iHandler->FirstEmpty() );
}
SetSelectionL( pos, pos );
}
else
{
if (aNaviType == EWmlEditorNavigateRight)
// Set the selection from right most selection point to the current cursor pos.
SetSelectionL ( pos , iHandler->IsPosStatic(selection.LowerPos()) ? selection.LowerPos() + 1 : selection.LowerPos() );
else
// Set the selection from current cursor pos to left most selection point
SetSelectionL (pos , iHandler->IsPosStatic(selection.HigherPos()) ? selection.HigherPos() - 1 : selection.HigherPos());
}
}
iSelection = Selection();
iCursorPos = pos;
iOverwrite = EFalse;
if ( aUpdateEditingParameters )
{
UpdateEditingParameters( pos ); // Change parameters
}
SetCursorPosL(pos);
CEikEdwin::ReportEdwinEventL(MEikEdwinObserver::EEventTextUpdate);
CEikEdwin::DrawContents();
}
// ---------------------------------------------------------
// CWmlFormattedEditor::UpdateEditingParameters
// ---------------------------------------------------------
//
TBool CWmlFormattedEditor::UpdateEditingParameters( TInt aDocPos )
{
if (aDocPos < 0)
{
aDocPos = 0;
iFormat = TWmlFormatChar(0,0);
}
TUint inputMode( EAknEditorNullInputMode );
TUint allowedInputModes( EAknEditorAllInputModes );
TUint fepCase( EAknEditorAllCaseModes );
TUint flags( EAknEditorFlagDefault );
TBool needsChange( EFalse );
TUint alphaInputModes;
TUint numericInputModes;
EVariantFlag variant = AknLayoutUtils::Variant();
if (variant == EApacVariant)
{
alphaInputModes = EAknEditorTextInputMode |
EAknEditorHalfWidthTextInputMode | EAknEditorFullWidthTextInputMode |
EAknEditorKatakanaInputMode | EAknEditorFullWidthKatakanaInputMode |
EAknEditorHiraganaKanjiInputMode | EAknEditorHiraganaInputMode;
numericInputModes = EAknEditorNumericInputMode | EAknEditorFullWidthNumericInputMode;
}
else
{
alphaInputModes = EAknEditorTextInputMode;
numericInputModes = EAknEditorNumericInputMode;
}
if ( iT9 )
{
inputMode = EAknEditorTextInputMode;
}
else
{
flags |= EAknEditorFlagNoT9;
if ( ! iHandler )
{
inputMode = EAknEditorTextInputMode;
}
}
if ( iHandler )
{
TWmlFormatChar format = iHandler->GetFormat( aDocPos );
if ( iFormat.Char() != format.Char() )
{
if ( format.Char() || iT9 )
{
needsChange = ETrue;
}
if ( format.SuggestedCase() == TWmlFormatChar::EWmlUpperCase )
{
fepCase = EAknEditorUpperCase;
}
if (format.SpecialAllowed())
{
flags |= EAknEditorFlagUseSCTNumericCharmap ;
}
if ( format.ForcedCase() != TWmlFormatChar::EWmlNone )
{
flags |= EAknEditorFlagFixedCase;
}
if ( format.NumericAllowed() )
{
inputMode = EAknEditorNumericInputMode;
}
else
{
allowedInputModes &= ~numericInputModes;
}
if ( format.AlphaAllowed() )
{
inputMode = EAknEditorTextInputMode;
}
else
{
allowedInputModes &= ~alphaInputModes;
}
iFormat = format;
}
}
else
{
flags |= EAknEditorFlagUseSCTNumericCharmap ;
// WML format takes precedence over JSky mode or istyle,
// but if no wml format is defined look at JSky attributes.
if ( iMode != iPrevMode )
{
needsChange = ETrue;
switch ( iMode )
{
case EWmlModeAlphabet:
{
inputMode = EAknEditorTextInputMode;
break;
}
case EWmlModeNumeric:
{
inputMode = EAknEditorNumericInputMode;
break;
}
case EWmlModeHiragana:
{
inputMode = EAknEditorHiraganaKanjiInputMode;
break;
}
case EWmlModeKatakana:
{
inputMode = EAknEditorFullWidthKatakanaInputMode;
break;
}
case EWmlModeHankakukana:
{
inputMode = EAknEditorKatakanaInputMode;
break;
}
default:
break;
}
iPrevMode = iMode;
}
}
if (iSecret)
{
EVariantFlag variant = AknLayoutUtils::Variant();
if (variant == EApacVariant)
{
flags |= EAknEditorFlagLatinInputModesOnly;
}
UpdateCaseState(fepCase, fepCase);
}
else
{
allowedInputModes &= ~EAknEditorSecretAlphaInputMode;
}
if (!allowedInputModes)
{
inputMode = EAknEditorNullInputMode;
}
if (iHandler)
{
iOverwrite = iHandler->PreviousStatic(iHandler->MaxLength()) > CursorPos();
}
if ( needsChange )
{
UpdateInputModeState(inputMode,
( inputMode != EAknEditorNullInputMode ? allowedInputModes : EAknEditorAllInputModes ));
UpdateFlagsState( iOverwrite
? flags | EAknEditorFlagMTAutoOverwrite
: flags &~ EAknEditorFlagMTAutoOverwrite );
UpdateCaseState(fepCase, fepCase);
}
else
{
TBool overWrite( AknEdwinFlags() & EAknEditorFlagMTAutoOverwrite );
if ( !overWrite && iOverwrite ||
overWrite && !iOverwrite )
{ // iOverwrite is changed, flags must be updated
UpdateFlagsState( iOverwrite
? flags | EAknEditorFlagMTAutoOverwrite
: flags &~ EAknEditorFlagMTAutoOverwrite );
needsChange = ETrue;
}
}
return needsChange;
}
// ---------------------------------------------------------
// CWmlFormattedEditor::SetEditorCurentCase()
// ---------------------------------------------------------
//
void CWmlFormattedEditor::SetEditorCurentCase()
{
TUint fepCase = EAknEditorTextCase;
if (iHandler)
{
TWmlFormatChar format = iHandler->GetFormat(CursorPos());
TWmlFormatChar::TWmlCase caseFormat = format.SuggestedCase();
switch( caseFormat )
{
case TWmlFormatChar::EWmlUpperCase :
fepCase = EAknEditorUpperCase;
break;
case TWmlFormatChar::EWmlLowerCase :
fepCase = EAknEditorLowerCase;
break;
default :
fepCase = EAknEditorTextCase;
break;
}
}
UpdateCaseState( fepCase, EAknEditorAllCaseModes );
}
// ---------------------------------------------------------
// CWmlFormattedEditor::Draw
// ---------------------------------------------------------
//
void CWmlFormattedEditor::Draw(const TRect& /*aRect*/) const
{
CGraphicsContext& gc = SystemGc();
TRect internalRect = Rect();
internalRect.Shrink( 1, 1 );
iBorder.Draw( gc, internalRect );
const TRect viewRect = iTextView->ViewRect();
if (IsDimmed())
gc.SetBrushColor(iEikonEnv->ControlColor(EColorControlDimmedBackground, *this));
else
gc.SetBrushColor(iEikonEnv->ControlColor(EColorControlBackground, *this));
DrawUtils::ClearBetweenRects(gc, iBorder.InnerRect(internalRect), viewRect);
TrappedDraw(viewRect);
}
void CWmlFormattedEditor::DrawContents()
{
CEikEdwin::DrawContents();
}
// -----------------------------------------------------------------------------
// UpdateFlagsState
//
//
// -----------------------------------------------------------------------------
void CWmlFormattedEditor::UpdateFlagsState(TUint flags)
{
SetAknEditorFlags( flags );
if (iVkbState)
{
iVkbState->SetFlags(flags | EAknEditorFlagUseSCTNumericCharmap);
iVkbState->ReportAknEdStateEventL(MAknEdStateObserver::EAknEdwinStateFlagsUpdate);
}
}
// -----------------------------------------------------------------------------
// UpdateInputModeState
//
//
// -----------------------------------------------------------------------------
void CWmlFormattedEditor::UpdateInputModeState(TUint inputMode, TUint permittedInputModes)
{
SetAknEditorNumericKeymap( EAknEditorPlainNumberModeKeymap );
SetAknEditorAllowedInputModes( permittedInputModes );
SetAknEditorInputMode( inputMode );
if (iVkbState)
{
if (permittedInputModes != EAknEditorNumericInputMode) {
EVariantFlag variant = AknLayoutUtils::Variant();
if (variant == EApacVariant) {
permittedInputModes |= EAknEditorTextInputMode |
EAknEditorHalfWidthTextInputMode | EAknEditorFullWidthTextInputMode |
EAknEditorKatakanaInputMode | EAknEditorFullWidthKatakanaInputMode |
EAknEditorHiraganaKanjiInputMode | EAknEditorHiraganaInputMode;
}
}
iVkbState->SetDefaultInputMode(inputMode);
iVkbState->SetCurrentInputMode(inputMode);
iVkbState->SetPermittedInputModes(permittedInputModes);
iVkbState->SetNumericKeymap(static_cast<TAknEditorNumericKeymap>(EAknEditorPlainNumberModeKeymap));
iVkbState->ReportAknEdStateEventL(MAknEdStateObserver::EAknEdwinStateInputModeUpdate);
}
}
// -----------------------------------------------------------------------------
// UpdateCaseState
//
//
// -----------------------------------------------------------------------------
void CWmlFormattedEditor::UpdateCaseState(TUint currentCase, TUint permittedCase)
{
SetAknEditorCurrentCase( currentCase );
if (iVkbState)
{
iVkbState->SetDefaultCase(currentCase);
iVkbState->SetCurrentCase(currentCase);
iVkbState->SetPermittedCases(permittedCase);
iVkbState->ReportAknEdStateEventL(MAknEdStateObserver::EAknEdwinStateCaseModeUpdate);
}
}
void CWmlFormattedEditor::SetCursorPosL( TInt aPos )
{
CEikRichTextEditor::SetCursorPosL( aPos, EFalse );
TextView()->SetDocPosL(aPos);
}
// End of File