diff -r ebe688cedc25 -r 7fdbb852d323 messagingappbase/msgeditor/viewsrc/MsgExpandableControlEditor.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/messagingappbase/msgeditor/viewsrc/MsgExpandableControlEditor.cpp Wed Sep 01 12:31:54 2010 +0100 @@ -0,0 +1,1318 @@ +/* +* 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 "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: MsgExpandableControlEditor implementation +* +*/ + + + +// ========== INCLUDE FILES ================================ + +#include // for CEikAppUi +#include // for CEikonEnv +#include // for CRichText +#include // for CClipboard +#include // for TLogicalFont +#include // for AknUtils +#include // for TResourceReader +#include // for automatic highlight + +#include +#include +#include +#include +#include // LAF +#include +#include +#include // FrameBackgroundControlContext +#include + +#include "MsgEditorCommon.h" // +#include "MsgExpandableControlEditor.h" // for CMsgExpandableControlEditor +#include "MsgExpandableControl.h" // for CMsgExpandableControl +#include "MsgBaseControl.h" // for TMsgEditPermissionFlags +#include "MsgBaseControlObserver.h" // for MMsgBaseControlObserver +#include "MsgEditorPanic.h" // for MsgEditor panics +#include "MsgEditorLogging.h" +#include "MsgEditorCustomDraw.h" // for CMsgEditorCustomDraw + +// ========== EXTERNAL DATA STRUCTURES ===================== + +// ========== EXTERNAL FUNCTION PROTOTYPES ================= + +// ========== CONSTANTS ==================================== + +// ========== MACROS ======================================= + +// ========== LOCAL CONSTANTS AND MACROS =================== +// OPEN: +const TInt KEdwinTopMargin = 0; +const TInt KEdwinBottomMargin = 0; +const TInt KEdwinLeftMargin = 0; +const TInt KEdwinRightMargin = 0; +const TInt KExpFullFormattingLength = 500; + +// ========== MODULE DATA STRUCTURES ======================= + +// ========== LOCAL FUNCTION PROTOTYPES ==================== + +// ========== LOCAL FUNCTIONS ============================== + +// ========== MEMBER FUNCTIONS ============================= + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::CMsgExpandableControlEditor +// +// Constructor. +// --------------------------------------------------------- +// +EXPORT_C CMsgExpandableControlEditor::CMsgExpandableControlEditor( + TUint32& aFlags, + MMsgBaseControlObserver* aBaseControlObserver) + : + CEikRichTextEditor( TGulBorder::ENone ), + iFlags( aFlags ), + iBaseControlObserver( aBaseControlObserver ) + { + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::CMsgExpandableControlEditor +// +// Constructor. +// --------------------------------------------------------- +// +EXPORT_C CMsgExpandableControlEditor::CMsgExpandableControlEditor( + const CCoeControl* aParent, + TUint32& aFlags, + MMsgBaseControlObserver* aBaseControlObserver ) + : + CEikRichTextEditor( TGulBorder::ENone ), + iParentControl( aParent ), + iFlags( aFlags ), + iBaseControlObserver( aBaseControlObserver ), + iFindItemEventReceived( EFalse ) + { + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::~CMsgExpandableControlEditor +// +// Destructor. +// --------------------------------------------------------- +// +EXPORT_C CMsgExpandableControlEditor::~CMsgExpandableControlEditor() + { + delete iItemFinder; + delete iFrameBgContext; + delete iCustomDraw; + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::ConstructL +// +// Constructs and initializes this editor. +// --------------------------------------------------------- +// +EXPORT_C void CMsgExpandableControlEditor::ConstructL() + { + TInt edwinFlags = ENoHorizScrolling | + ENoAutoSelection | + EWidthInPixels | + EAllowUndo | + EResizable | + EPasteAsPlainText; + + iFlags = EMsgControlModeDoNotDrawFrameBgContext; + ResolveLayouts(); + + /*if ( iBaseControlObserver && + !iBaseControlObserver->ViewInitialized() ) + { + SetSuppressFormatting( ETrue ); + }*/ + + TInt numberOfLines( 0 ); + + if ( iFlags & EMsgControlModeSizeFixedToOneLine ) + { + // make control fixed size and allow horizontal scrolling. + edwinFlags &= ~EResizable; + edwinFlags &= ~ENoHorizScrolling; + numberOfLines = 1; + } + + CEikRichTextEditor::ConstructL( + iParentControl, + numberOfLines, + iMaxNumberOfChars, + edwinFlags ); + + // Emoticon support for MMS Subject field + AddFlagToUserFlags(EAvkonEnableSmileySupport); + + // Both global text editor and edwin have it's own formatting layers. + // CEikRichTextEditor::ConstructL call will set global formatting layers + // into use for text. This is not correct as edwin formatting layers + // will hold correct formatting values. Below calls will set edwin + // formatting layers into use and prevent client based formatting from + // being based on incorrect formatting layer. + SetParaFormatLayer( iEikonEnv->SystemParaFormatLayerL()->CloneL() ); + SetCharFormatLayer( iEikonEnv->SystemCharFormatLayerL()->CloneL() ); + + SetUpperFullFormattingLength( KExpFullFormattingLength ); + + SetMaximumHeight( MsgEditorCommons::MaxBodyHeight() ); + + // Set the wrap width to be that of the current header text pane. + // This will make the formatting of text safer if it is performed + // before the editor has ever had SetSize() called. WrapWidth is + // usually set in HandleSizeChanged() + if ( iLayout ) + { + iLayout->SetWrapWidth( iTextLayout.TextRect().Width() ); + } + + // TODO: Get from LAF or something... Currently + // all of these are zero. OK?! + TMargins8 edwinMargins; + edwinMargins.iTop = KEdwinTopMargin; + edwinMargins.iBottom = KEdwinBottomMargin; + edwinMargins.iLeft = KEdwinLeftMargin; + edwinMargins.iRight = KEdwinRightMargin; + SetBorderViewMargins( edwinMargins ); + + iBgContext = AknsDrawUtils::ControlContext( this ); + + // NOTE: iItemFinder can be created by derived class if needed. + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::ConstructFromResourceL +// --------------------------------------------------------- +// +EXPORT_C void CMsgExpandableControlEditor::ConstructFromResourceL( + TResourceReader& aReader ) + { + // This used to be font id. Not used anymore. Have to read it, though. + /*TInt fontId =*/ aReader.ReadInt32(); + + ConstructL(); + + if ( !IsReadOnly() ) + { + ReadAknResourceL( aReader ); + } + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::SetAndGetSizeL +// +// Sets size for this editor. Height of given size aSize may change if the +// editor contains text. +// --------------------------------------------------------- +// +EXPORT_C void CMsgExpandableControlEditor::SetAndGetSizeL( TSize& aSize ) + { + TSize controlSize( aSize.iWidth, aSize.iHeight ); + + if( TextLayout() && TextLayout()->IsFormattingBand() ) + { + // Partial formatting on-going -> needs whole body height + //controlSize.iHeight = MaximumHeight(); + } + else + { + TInt position( 0 ); + AknLayoutUtils::GetEdwinVerticalPositionAndHeightFromLines( + controlSize.iHeight, + AknLayoutScalable_Apps::msg_header_pane_t2( 0 ).LayoutLine(), + MsgEditorCommons::MsgBaseLineDelta(), + iNumberOfLines, + position, + controlSize.iHeight ); + } + controlSize.iHeight +=iEditortop; + if ( controlSize != iSize ) + { + // This may change the height if the content has changed. + SetSize( controlSize ); + } + + aSize = controlSize; + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::CheckEditPermission +// +// Checks and returns control's edit permissions. +// --------------------------------------------------------- +// +EXPORT_C TUint32 CMsgExpandableControlEditor::CheckEditPermission() const + { + TUint32 editPermission( CMsgBaseControl::EMsgEditNone ); + + if ( CanUndo() ) + { + editPermission |= CMsgBaseControl::EMsgEditUndo; + } + + if ( Selection().Length() ) + { + // Selection is on + editPermission |= CMsgBaseControl::EMsgEditCopy; + if ( !IsReadOnly() ) + { + editPermission |= CMsgBaseControl::EMsgEditCut; + } + if ( Selection().Length() == TextLength() ) + { + editPermission |= CMsgBaseControl::EMsgEditUnSelectAll; + } + } + + if ( TextLength() ) + { + editPermission |= CMsgBaseControl::EMsgEditSelectAll; + } + + editPermission |= CMsgBaseControl::EMsgEditPaste; + + return editPermission; + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::CursorInFirstLine +// +// Checks if the cursor is on the first line and return ETrue if it is. +// --------------------------------------------------------- +// +EXPORT_C TBool CMsgExpandableControlEditor::CursorInFirstLine() + { + TBool cursorOnFirstLine = EFalse; + TBool posFormatted = iLayout->PosIsFormatted( 0 ); + if ( iTextView && posFormatted ) + { + TTmDocPos docPos; + iTextView->GetCursorPos( docPos ); + TTmDocPosSpec docPosSpec( docPos ); + TTmPosInfo2 posInfo; + TTmLineInfo lineInfo; + if ( iLayout->FindDocPos( docPosSpec, posInfo, &lineInfo ) ) + { + cursorOnFirstLine = ( lineInfo.iLineNumber == 0 ); + } + } + return cursorOnFirstLine; + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::CursorInLastLine +// +// Checks if the cursor is on the last line and return ETrue if it is. +// --------------------------------------------------------- +// +EXPORT_C TBool CMsgExpandableControlEditor::CursorInLastLine() + { + TBool cursorOnLastLine = EFalse; + TBool posFormatted = iLayout->PosIsFormatted( TextLength() ); + + if ( iTextView && posFormatted ) + { + TInt numOfLines = iLayout->NumFormattedLines(); + if ( numOfLines ) + { + TTmDocPos docPos; + iTextView->GetCursorPos( docPos ); + TTmDocPosSpec docPosSpec( docPos ); + TTmPosInfo2 posInfo; + TTmLineInfo lineInfo; + if ( iLayout->FindDocPos( docPosSpec, posInfo, &lineInfo ) ) + { + cursorOnLastLine = ( lineInfo.iLineNumber == numOfLines - 1 ); + } + } + else + { + // Editor is empty. + cursorOnLastLine = ETrue; + } + } + + return cursorOnLastLine; + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::IsFirstLineVisible +// +// Checks if first text line is visible. +// --------------------------------------------------------- +// +EXPORT_C TBool CMsgExpandableControlEditor::IsFirstLineVisible() + { + if( TextLayout() ) + { + TPoint dummy; + if( TextLayout()->PosInBand( 0, dummy ) ) + { + if( iTextView ) + { + TTmDocPos docPos( 0, ETrue ); + TTmDocPosSpec docPosSpec( docPos ); + TTmPosInfo2 posInfo; + TTmLineInfo lineInfo; + + if ( iLayout->FindDocPos( docPosSpec, posInfo, &lineInfo ) ) + { + // posInfo.iEdge specifies coordinate position of + // intersection of the character edge with the baseline. + TInt fontTop = posInfo.iEdge.iY - TextFont()->AscentInPixels(); + return ( fontTop >= 0 && fontTop <= MsgEditorCommons::EditorViewHeigth() ); + } + } + else + { + return ETrue; + } + } + return EFalse; + } + + return ETrue; + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::IsLastLineVisible +// +// Checks if last text line is visible. +// --------------------------------------------------------- +// +EXPORT_C TBool CMsgExpandableControlEditor::IsLastLineVisible() + { + if( TextLayout() ) + { + TPoint dummy; + if( TextLayout()->PosInBand( TextLength(),dummy ) ) + { + if ( iTextView ) + { + TTmDocPos docPos( TextLength(), EFalse ); + TTmDocPosSpec docPosSpec( docPos ); + TTmPosInfo2 posInfo; + TTmLineInfo lineInfo; + + if ( iLayout->FindDocPos( docPosSpec, posInfo, &lineInfo ) ) + { + return ( posInfo.iEdge.iY >= 0 && + posInfo.iEdge.iY <= MsgEditorCommons::EditorViewHeigth() ); + } + } + else + { + return ETrue; + } + } + return EFalse; + } + + return ETrue; + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::CurrentLineRect +// +// Returns the current control rect. +// --------------------------------------------------------- +// +EXPORT_C TRect CMsgExpandableControlEditor::CurrentLineRectL() + { + if ( !iTextView ) + { + User::Leave( KErrGeneral ); + } + + TTmDocPos docPos; + iTextView->GetCursorPos( docPos ); + iTextView->FinishBackgroundFormattingL(); + + TInt cursorPos = Min( docPos.iPos, TextLength() ); + + if ( !iLayout->PosIsFormatted( cursorPos ) ) + { + iTextView->SetDocPosL( cursorPos, Selection().Length() ); // after this cursorPos should be formatted + ForceScrollBarUpdateL(); + } + + TRect cursorPosRect; + + if ( iTextView->IsPictureFrameSelected( cursorPosRect, cursorPos ) ) + { + cursorPosRect.Move( TPoint( 0, -iTextView->ViewRect().iTl.iY ) ); + } + else + { + TTmDocPosSpec docPosSpec( docPos ); + TTmPosInfo2 posInfo; + TTmLineInfo lineInfo; + if ( iLayout->FindDocPos( docPosSpec, posInfo, &lineInfo ) ) + { + cursorPosRect = lineInfo.iInnerRect; + } + //TODO: else what?! We should never get to else branch... + } + + return cursorPosRect; + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::DefaultHeight +// +// Returns a default one line height of the editor. +// --------------------------------------------------------- +// +EXPORT_C TInt CMsgExpandableControlEditor::DefaultHeight() const + { + return DefaultHeight( EFalse ); + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::ClipboardL +// +// Handles a clipboard operation. +// --------------------------------------------------------- +// +void CMsgExpandableControlEditor::ClipboardL( + CEikEdwin::TClipboardFunc aClipboardFunc ) + { + __ASSERT_DEBUG( iTextView, Panic( EMsgNoTextView ) ); + + CEikRichTextEditor::ClipboardL( aClipboardFunc ); + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::CcpuCanCut +// --------------------------------------------------------- +// +EXPORT_C TBool CMsgExpandableControlEditor::CcpuCanCut() const + { + TUint32 editPermission = CheckEditPermission(); + + if ( iBaseControlObserver ) + { + TRAP_IGNORE( + { + if ( iBaseControlObserver->HandleEditObserverEventRequestL( this, EMsgDenyCut ) ) + { + editPermission &= ~CMsgBaseControl::EMsgEditCut; + } + } ); + } + + return editPermission & CMsgBaseControl::EMsgEditCut; + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::CcpuCanCopy +// --------------------------------------------------------- +// +EXPORT_C TBool CMsgExpandableControlEditor::CcpuCanCopy() const + { + TUint32 editPermission = CheckEditPermission(); + + if (iBaseControlObserver) + { + TRAP_IGNORE( + { + if ( iBaseControlObserver->HandleEditObserverEventRequestL( this, EMsgDenyCopy ) ) + { + editPermission &= ~CMsgBaseControl::EMsgEditCopy; + } + } ); + } + + return editPermission & CMsgBaseControl::EMsgEditCopy; + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::CcpuCanPaste +// --------------------------------------------------------- +// +EXPORT_C TBool CMsgExpandableControlEditor::CcpuCanPaste() const + { + TUint32 editPermission = CheckEditPermission(); + + if ( !CEikEdwin::CcpuCanPaste() ) + { + editPermission &= ~CMsgBaseControl::EMsgEditPaste; + } + + if ( iBaseControlObserver ) + { + TRAP_IGNORE( + { + if ( iBaseControlObserver->HandleEditObserverEventRequestL( this, EMsgDenyPaste ) ) + { + editPermission &= ~CMsgBaseControl::EMsgEditPaste; + } + } ); + } + + return editPermission & CMsgBaseControl::EMsgEditPaste; + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::CcpuCanUndo +// --------------------------------------------------------- +// +EXPORT_C TBool CMsgExpandableControlEditor::CcpuCanUndo() const + { + return CheckEditPermission() & CMsgBaseControl::EMsgEditUndo; + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::CcpuCutL +// --------------------------------------------------------- +// +EXPORT_C void CMsgExpandableControlEditor::CcpuCutL() + { + CEikRichTextEditor::ClipboardL( ECut ); + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::CcpuCopyL +// --------------------------------------------------------- +// +EXPORT_C void CMsgExpandableControlEditor::CcpuCopyL() + { + CEikRichTextEditor::ClipboardL( ECopy ); + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::CcpuPasteL +// --------------------------------------------------------- +// +EXPORT_C void CMsgExpandableControlEditor::CcpuPasteL() + { + CEikRichTextEditor::ClipboardL( EPaste ); + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::CcpuUndoL +// --------------------------------------------------------- +// +EXPORT_C void CMsgExpandableControlEditor::CcpuUndoL() + { + UndoL(); + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::SetMaxNumberOfChars +// +// Sets maximun number of characters. +// --------------------------------------------------------- +// +void CMsgExpandableControlEditor::SetMaxNumberOfChars( TInt aMaxNumberOfChars ) + { + iMaxNumberOfChars = aMaxNumberOfChars; + if ( Text() ) + { + SetTextLimit( iMaxNumberOfChars ); + } + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::SetTextContentL +// +// Sets aText content for the editor. +// --------------------------------------------------------- +// +EXPORT_C void CMsgExpandableControlEditor::SetTextContentL( CRichText& aText ) + { + MEBLOGGER_ENTERFN("CMsgExpandableControlEditor::SetTextContentL"); + + MEBLOGGER_WRITE("#1"); + MEBLOGGER_WRITE_TIMESTAMP(""); + + if ( IsPlainTextMode() ) + { + CRichText* richText = RichText(); + + MEBLOGGER_WRITEF( _L( "MEB: SetTextContentL: Copying text, length %d" ), aText.DocumentLength() ); + + // Ignore the original formatting on plain text mode and set the + // new rich text object to use current formatting parameters. + aText.SetGlobalParaFormat( richText->GlobalParaFormatLayer() ); + aText.SetGlobalCharFormat( richText->GlobalCharFormatLayer() ); + + CEikEdwin::CopyDocumentContentL( aText, *richText ); + TInt documentLength = richText->DocumentLength(); + + MEBLOGGER_WRITEF( _L( "MEB: SetTextContentL: Copied text, length %d" ), documentLength ); + + if ( iMaxNumberOfChars && + documentLength > iMaxNumberOfChars ) + { + richText->DeleteL( iMaxNumberOfChars, documentLength - iMaxNumberOfChars ); + documentLength = richText->DocumentLength(); + } + + const TChar LF( 0x0A ); + const TChar CR( 0x0D ); + + TInt i = 0; + while ( i < documentLength ) + { + TPtrC ptr = richText->Read( i, 1 ); + TInt remove = 0; + TBool addParDeli = EFalse; + if ( ptr.Locate( CEditableText::EPictureCharacter ) != KErrNotFound ) + { + remove++; + } + else if ( ptr.Locate( CR ) != KErrNotFound ) + { + // "CR" + remove++; + addParDeli = ETrue; + if ( i < documentLength - 1 && + aText.Read( i + 1, 1 ).Locate( LF ) != KErrNotFound ) + { + // "CR+LF" + remove++; + } + } + else if ( ptr.Locate( LF ) != KErrNotFound ) + { + // "LF" + remove++; + addParDeli = ETrue; + } + + if ( remove ) + { + MEBLOGGER_WRITEF( _L( "MEB: SetTextContentL: removing %d characters" ), remove ); + richText->DeleteL( i, remove ); + MEBLOGGER_WRITEF( _L( "MEB: SetTextContentL: removed %d characters" ), remove ); + documentLength -= remove; + if ( addParDeli ) + { + MEBLOGGER_WRITEF( _L( "MEB: SetTextContentL: Inserting paragraph delimeter" ) ); + richText->InsertL( i, CEditableText::EParagraphDelimiter ); + MEBLOGGER_WRITEF( _L( "MEB: SetTextContentL: Inserted paragraph delimeter" ) ); + documentLength++; + i++; + } + } + else + { + i++; + } + } + } + else + { + CopyDocumentContentL( aText, *GlobalText() ); + } + + SetAmountToFormatL( ETrue ); + + MEBLOGGER_WRITE("#2"); + MEBLOGGER_WRITE_TIMESTAMP(""); + + MEBLOGGER_LEAVEFN("CMsgExpandableControlEditor::SetTextContentL"); + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::MinimumDefaultHeight +// +// Returns a minimum one line height of the editor. +// --------------------------------------------------------- +// +TInt CMsgExpandableControlEditor::MinimumDefaultHeight() const + { + return DefaultHeight( ETrue ); + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::Reset +// +// Clear contents. +// --------------------------------------------------------- +// +EXPORT_C void CMsgExpandableControlEditor::Reset() + { + if ( iTextView ) + { + TInt documentLength = RichText()->DocumentLength(); + + RichText()->Reset(); + + iTextView->SetPendingSelection( TCursorSelection( 0, 0 ) ); + TRAP_IGNORE( iTextView->HandleInsertDeleteL( TCursorSelection( 0, 0 ), + documentLength ) ); + } + else + { + RichText()->Reset(); + } + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::SetBaseControlObserver +// +// Sets base control observer. +// --------------------------------------------------------- +// +EXPORT_C void CMsgExpandableControlEditor::SetBaseControlObserver( + MMsgBaseControlObserver& aBaseControlObserver ) + { + iBaseControlObserver = &aBaseControlObserver; + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::OfferKeyEventL +// +// Handles key event. +// --------------------------------------------------------- +// +EXPORT_C TKeyResponse CMsgExpandableControlEditor::OfferKeyEventL( + const TKeyEvent& aKeyEvent, TEventCode aType) + { + if ( IsReadOnly() ) + { + TCursorPosition::TMovementType movetype; + + switch ( aKeyEvent.iCode ) + { + case EKeyUpArrow: + movetype = TCursorPosition::EFPageUp; + break; + + case EKeyDownArrow: + movetype = TCursorPosition::EFPageDown; + break; + + default: + return CEikRichTextEditor::OfferKeyEventL( aKeyEvent, aType ); + } + + iTextView->MoveCursorL( movetype, EFalse ); + + return EKeyWasConsumed; + } + else + { + return CEikRichTextEditor::OfferKeyEventL( aKeyEvent, aType ); + } + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::HandleResourceChange +// +// Sets correct highlight extension. +// --------------------------------------------------------- +// +void CMsgExpandableControlEditor::HandleResourceChange( TInt aType ) + { + if ( aType == KEikDynamicLayoutVariantSwitch ) + { + ResolveLayouts(); + LayoutEdwin(); + + TRAP_IGNORE( + { + if ( iTextView ) + { + TCursorSelection currentSelection = iTextView->Selection() ; + + if ( currentSelection.Length() > 0 ) + { + iTextView->SetSelectionL( currentSelection ); + } + else + { + iTextView->SetDocPosL( currentSelection.iCursorPos, EFalse ); + } + } + } ); + } + + CEikRichTextEditor::HandleResourceChange( aType ); + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::IsPlainTextMode +// +// Checks if the plain text mode is on and returns ETrue if it is. +// --------------------------------------------------------- +// +TBool CMsgExpandableControlEditor::IsPlainTextMode() const + { + return iFlags & EMsgControlModePlainTextMode; + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::LayoutEdwin +// --------------------------------------------------------- +// +void CMsgExpandableControlEditor::LayoutEdwin() + { + TAknLayoutRect msgTextPane; + msgTextPane.LayoutRect( MsgEditorCommons::MsgDataPane(), + AknLayoutScalable_Apps::msg_text_pane( 0 ).LayoutLine() ); + + TAknLayoutRect msgHeaderPane; + msgHeaderPane.LayoutRect( msgTextPane.Rect(), + AknLayoutScalable_Apps::msg_header_pane().LayoutLine() ); + + TRect parentRect( msgHeaderPane.Rect() ); + parentRect.Move( 0, iParentControl->Position().iY ); + + DoLayoutEdwin( parentRect, + AknLayoutScalable_Apps::msg_header_pane_t2( 0 ).LayoutLine() ); + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::DoLayoutEdwin +// +// Performs the layout setting for edwin according to the given +// parameters. Used from LayoutEdwin or some of it's derived versions. +// --------------------------------------------------------- +// +void CMsgExpandableControlEditor::DoLayoutEdwin( const TRect& aEdwinParent, + const TAknTextLineLayout& aLayout ) + { + TPoint position( iPosition ); + + // Layout edwin as two lines to get the base line delta override activated. + TInt lineNumber( 0 ); + AknLayoutUtils::LayoutEdwin( this, + aEdwinParent, + aLayout, + 2, + MsgEditorCommons::MsgBaseLineDelta(), + EAknsCIQsnTextColorsCG6, + lineNumber ); + + // Resize the edwin to the correct size. Also set the original position. + TInt notUsed( 0 ); + TInt height( 0 ); + AknLayoutUtils::GetEdwinVerticalPositionAndHeightFromLines( + aEdwinParent.Size().iHeight, + aLayout, + MsgEditorCommons::MsgBaseLineDelta(), + iNumberOfLines, + notUsed, + height ); + + TRect editorRect( position, TSize( iSize.iWidth, height ) ); + SetRect( editorRect ); + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::AdjustLineHeightL +// --------------------------------------------------------- +// +EXPORT_C void CMsgExpandableControlEditor::AdjustLineHeightL() + { + // nop + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::TextFont +// --------------------------------------------------------- +// +EXPORT_C const CFont* CMsgExpandableControlEditor::TextFont() const + { + return iTextLayout.Font(); + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::DefaultHeight +// --------------------------------------------------------- +// +TInt CMsgExpandableControlEditor::DefaultHeight( TBool /*aOneToOne*/ ) const + { + return TextFont()->HeightInPixels(); + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::VirtualHeight +// +// Returns approximate height of text. In band formatting mode +// we have to calculate the average chars per line and +// average line in view values by ourself as we might get called +// in a callback when edwin does not contain up-to-date values. +// --------------------------------------------------------- +// +EXPORT_C TInt CMsgExpandableControlEditor::VirtualHeight() + { + TInt heightInPixels( 0 ); + TInt msgBaseLineDelta( MsgEditorCommons::MsgBaseLineDelta() ); + + if ( iLayout->IsFormattingBand() ) + { + TInt docLength = iLayout->DocumentLength(); + + TInt avgCharsPerLine = iLayout->FormattedLength() / iLayout->NumFormattedLines(); + TInt avgLinesInViewRect= Max( 1, iTextView->ViewRect().Height() * + iLayout->NumFormattedLines() / + iLayout->FormattedHeightInPixels() ); + + const TInt approxTotalLines = Max( docLength / avgCharsPerLine, + iText->ParagraphCount() ); + const TInt approxLineHeight = iTextView->ViewRect().Height() / avgLinesInViewRect; + heightInPixels = approxTotalLines * approxLineHeight; + } + else + { + if ( iTextView ) + { + // Force formatting to complete so that + // correct height can be retrieved. + TRAP_IGNORE( iTextView->FinishBackgroundFormattingL() ); + } + + heightInPixels = iLayout->FormattedHeightInPixels(); + } + + heightInPixels = Max( heightInPixels, iLayout->FormattedHeightInPixels() ); + MsgEditorCommons::RoundToPreviousLine( heightInPixels, msgBaseLineDelta ); + + return heightInPixels; + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::VirtualVisibleTop +// +// Returns a topmost visible text position. In band formatting mode +// we have to calculate the average chars per line value +// by ourself as we might get called in a callback when edwin +// does not contain up-to-date value. +// --------------------------------------------------------- +// +EXPORT_C TInt CMsgExpandableControlEditor::VirtualVisibleTop() + { + TInt ret( 0 ); + + TInt msgBaseLineDelta( MsgEditorCommons::MsgBaseLineDelta() ); + + if ( iLayout->IsFormattingBand() ) + { + TInt avgCharsPerLine = iLayout->FormattedLength() / iLayout->NumFormattedLines(); + + TInt topLeftDocPos = iLayout->FirstDocPosFullyInBand(); + TInt approxTopVisibleLine = topLeftDocPos / avgCharsPerLine; + + if ( approxTopVisibleLine == 0 && + topLeftDocPos > 0 ) + { + ret = iLayout->PixelsAboveBand(); + } + else + { + TInt avgLinesInViewRect= Max( 1, iTextView->ViewRect().Height() * + iLayout->NumFormattedLines() / + iLayout->FormattedHeightInPixels() ); + + TInt approxLineHeight = iTextView->ViewRect().Height() / avgLinesInViewRect; + ret = approxTopVisibleLine * approxLineHeight; + } + } + else + { + // Round to the last full line height. Division removes the fraction since + // result is integer (i.e. non floating point value). + ret = iLayout->PixelsAboveBand(); + } + + ret = Max( ret, iLayout->PixelsAboveBand() ); + MsgEditorCommons::RoundToPreviousLine( ret, msgBaseLineDelta ); + + return ret; + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::ActivateL +// --------------------------------------------------------- +// +EXPORT_C void CMsgExpandableControlEditor::ActivateL() + { + if ( IsActivated() ) + { + return; + } + + TInt cursorPos = 0; + + if ( iTextView ) + { + cursorPos = CursorPos(); + } + + LayoutEdwin(); + SetTextSkinColorIdL(); + + CEikRichTextEditor::ActivateL(); + + iTextView->SetDocPosL( cursorPos ); + if ( !iCustomDraw ) + { + // Swap the custom drawer to our own to show text lines. + const MFormCustomDraw* customDraw = TextLayout()->CustomDraw(); + + iCustomDraw = CMsgEditorCustomDraw::NewL( customDraw, this, iControlType); + + TextLayout()->SetCustomDraw( iCustomDraw ); + } + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::ItemFinder +// --------------------------------------------------------- +// +EXPORT_C CItemFinder* CMsgExpandableControlEditor::ItemFinder() const + { + return iItemFinder; + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::FocusChanged +// --------------------------------------------------------- +// +EXPORT_C void CMsgExpandableControlEditor::FocusChanged( TDrawNow aDrawNow ) + { + CEikEdwin::FocusChanged( aDrawNow ); + + TRAP_IGNORE( DoFocusChangedL() ); + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::DoFocusChangedL +// --------------------------------------------------------- +// +void CMsgExpandableControlEditor::DoFocusChangedL() + { + SetTextSkinColorIdL(); + + if( ! ( iFlags & EMsgControlModeDoNotDrawFrameBgContext ) && + ! static_cast( iParentControl )->IsReadOnly() ) + { + if( IsFocused( ) ) + { + // The focus arrives so lets so the frame + // It is drawn between the outer and inner rects + TRect outer, inner; + OuterAndInnerRects( outer, inner ); + + if( !iFrameBgContext ) + { + iFrameBgContext = + CAknsFrameBackgroundControlContext::NewL( KAknsIIDQsnFrInput, + outer, + inner, + EFalse ); + iFrameBgContext->SetParentContext( iBgContext ); + } + else + { + iFrameBgContext->SetFrameRects( outer, inner ); + } + SetSkinBackgroundControlContextL( iFrameBgContext ); + } + else + { // Focus leaves so lets remove the skin bg control contex + SetSkinBackgroundControlContextL( iBgContext ); + } + } + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::HandleFrameSizeChangeL +// --------------------------------------------------------- +// +void CMsgExpandableControlEditor::HandleFrameSizeChangeL() + { + if( IsFocused( ) ) + { + // We have focus so lets resize the frame context + if( ! (iFlags & EMsgControlModeDoNotDrawFrameBgContext ) && + ! static_cast( iParentControl )->IsReadOnly() ) + { + // The size of the frame has changed so lets find out + // the outer and inner rects again + TRect outer, inner; + OuterAndInnerRects( outer, inner ); + + if( !iFrameBgContext ) + { + iFrameBgContext = + CAknsFrameBackgroundControlContext::NewL( KAknsIIDQsnFrInput, + outer, + inner, + EFalse ); + iFrameBgContext->SetParentContext( iBgContext ); + } + + iFrameBgContext->SetFrameRects( outer, inner ); + SetSkinBackgroundControlContextL( iFrameBgContext ); + } + } + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::OuterAndInnerRects +// --------------------------------------------------------- +// +void CMsgExpandableControlEditor::OuterAndInnerRects( TRect& aOuter, TRect& aInner ) + { + TRect rect( Rect( ) ); + TRect focused ( iParentControl->Rect( ) ); + + // If we are out of screen, start it just from the baseline offset + TInt top = MsgEditorCommons::MsgBaseLineOffset(); + if ( focused.iTl.iY < top ) + { + focused.iTl.iY = top; + } + TInt maxBodyHeight( MsgEditorCommons::EditorViewHeigth() ); + if ( focused.iBr.iY > maxBodyHeight ) + { + focused.iBr.iY = maxBodyHeight; + } + + aOuter.SetRect( rect.iTl.iX-1, + focused.iTl.iY, + rect.iBr.iX, + focused.iBr.iY ); + + TAknLayoutRect tl; + TAknLayoutRect br; + tl.LayoutRect( aOuter, AknLayoutScalable_Avkon::input_focus_pane_g2().LayoutLine() ); + br.LayoutRect( aOuter, AknLayoutScalable_Avkon::input_focus_pane_g5().LayoutLine() ); + + aInner.SetRect( aOuter.iTl.iX - 1, + aOuter.iTl.iY + tl.Rect().Height(), + aOuter.iBr.iX, + aOuter.iBr.iY - br.Rect().Height() ); + } + + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::ResolveLayouts +// +// +// --------------------------------------------------------- +// +void CMsgExpandableControlEditor::ResolveLayouts() + { + TAknLayoutRect msgTextPane; + msgTextPane.LayoutRect( MsgEditorCommons::MsgDataPane(), + AknLayoutScalable_Apps::msg_text_pane( 0 ).LayoutLine() ); + + TAknLayoutRect msgHeaderPane; + msgHeaderPane.LayoutRect( msgTextPane.Rect(), + AknLayoutScalable_Apps::msg_header_pane().LayoutLine() ); + + iTextLayout.LayoutText( msgHeaderPane.Rect(), + AknLayoutScalable_Apps::msg_header_pane_t2( 0 ).LayoutLine() ); + TRect dataPane = MsgEditorCommons::MsgDataPane(); + + + TAknTextLineLayout editorLineLayout; + TAknLayoutText editorLayout; + + editorLineLayout = AknLayoutScalable_Apps::msg_header_pane_t2( 0 ).LayoutLine(); + + editorLayout.LayoutText( msgHeaderPane.Rect(), editorLineLayout ); + + iEditortop = editorLayout.TextRect().iTl.iY - msgHeaderPane.Rect().iTl.iY; + if ( iCustomDraw ) + { + iCustomDraw->ResolveLayouts(); + } + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::PrepareForReadOnlyL +// --------------------------------------------------------- +// +void CMsgExpandableControlEditor::PrepareForReadOnlyL( TBool aReadOnly ) + { + if ( IsReadOnly() == aReadOnly ) + { + return; + } + + SetReadOnly( aReadOnly ); + SetTextSkinColorIdL(); + + if ( aReadOnly ) + { + AddFlagToUserFlags( CEikEdwin::EAvkonDisableCursor ); + } + else + { + RemoveFlagFromUserFlags( CEikEdwin::EAvkonDisableCursor ); + } + + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::SetTextSkinColorIdL +// --------------------------------------------------------- +// +void CMsgExpandableControlEditor::SetTextSkinColorIdL() + { + CEikEdwin::SetTextSkinColorIdL( EAknsCIQsnTextColorsCG6 ); + } + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::IsCursorVisibleL +// --------------------------------------------------------- +// +TBool CMsgExpandableControlEditor::IsCursorVisibleL() + { + TBool result = EFalse; + if ( iTextView ) + { + TPoint cursorPos; + + if ( iTextView->DocPosToXyPosL( CursorPos(), cursorPos ) && + iTextView->ViewRect().Contains( cursorPos ) ) + { + result = ETrue; + } + } + return result; + } +// --------------------------------------------------------- +// CMsgExpandableControlEditor::MsgEditorCustomDraw +// --------------------------------------------------------- +// +CMsgEditorCustomDraw* CMsgExpandableControlEditor::MsgEditorCustomDraw() const + { + return iCustomDraw; + } + + +// --------------------------------------------------------- +// CMsgExpandableControlEditor::SetControlType +// --------------------------------------------------------- +// +void CMsgExpandableControlEditor::SetControlType(TInt actrltype) + { + iControlType = actrltype; + } +// End of File