diff -r 0396474f30f5 -r 4ce476e64c59 meetingrequest/mrgui/mrfieldbuildercommon/src/cesmrrichtextviewer.cpp --- a/meetingrequest/mrgui/mrfieldbuildercommon/src/cesmrrichtextviewer.cpp Mon Mar 15 12:39:10 2010 +0200 +++ b/meetingrequest/mrgui/mrfieldbuildercommon/src/cesmrrichtextviewer.cpp Wed Mar 31 21:08:33 2010 +0300 @@ -1,5 +1,5 @@ /* -* Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies). +* Copyright (c) 2009 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" @@ -12,6 +12,7 @@ * Contributors: * * Description : CEikRichTextEditor based Rich Text viewer +* Version : %version: e002sa32#36 % * */ @@ -20,39 +21,47 @@ #include "mesmrlistobserver.h"// SCROLLING_MOD: List observer header #include "esmrconfig.hrh" #include "esmrhelper.h" -#include "cesmriconfield.h" #include "cesmrfieldcommandevent.h" #include "mesmrfieldeventqueue.h" -#include "cesmrlayoutmgr.h" #include "cesmrrichtextlink.h" #include "cesmrcontactmenuhandler.h" #include "nmrbitmapmanager.h" +#include "nmrcolormanager.h" +#include "esmrfieldbuilderdef.h" +#include "cesmrfield.h" #include #include #include #include -#include +#include +#include +#include #include #include #include // for clipboard copy -#include -#include - -#ifndef FF_CMAIL_INTEGRATION #include -#endif // FF_CMAIL_INTEGRATION // DEBUG #include "emailtrace.h" -// Removed profiling. - // Unnamed namespace for local definitions namespace{ // codescanner::namespace -const TInt KArrowUpperMargin (2); -const TInt KArrowRightMargin (5); +#ifdef _DEBUG + enum TPanic + { + EParaFormatNotInitialised = 1 + }; + void Panic( TPanic aPanic ) + { + _LIT( KCategory, "CESMRRichTextViewer" ); + User::Panic( KCategory(), aPanic ); + } +#endif // DEBUG + +// Side margin in twips, needed because not possible to set it in pixels +const TInt KDefaultTextSideMargin( 1 ); }//namespace @@ -81,10 +90,8 @@ { FUNC_LOG; iLinkList.ResetAndDestroy ( ); - delete iActionMenuIcon; - delete iActionMenuIconMask; iESMRStatic.Close ( ); - delete iLongTapDetector; + delete iParaFormat; } // ----------------------------------------------------------------------------- @@ -116,61 +123,41 @@ return; } - if ( IsFocused() ) + // Check the current selection. + // If a link has been highlighted, don't change it. + TCursorSelection selection = Selection(); + + // Gaining focus + if ( IsFocused() + && iLinkList.Count() > 0 + && selection.Length() == 0 ) { - if( iLayout ) - { - TRAP_IGNORE( SetFontColorL( ETrue ) ); - } + // We need the field indexes, cast required + CESMRField* parent = static_cast< CESMRField* >( Parent() ); - if ( iCurrentLinkIndex == KErrNotFound ) + iCntMenuHdlr->SetContactMenuObserver( this ); + // Focus coming from above ... + if( parent->CurrentItemIndex() > parent->PreItemIndex() ) { - TInt linkRow = KErrNotFound; - if ( CursorPos() == 0 ) - { - // focus is coming from field above: - linkRow = FindTextLinkBetweenNextScrollArea( - 0, 1, TCursorPosition::EFLineDown ); - } - else - { - linkRow = FindTextLinkBetweenNextScrollArea( - LineCount()-2, - LineCount()-1, - TCursorPosition::EFLineUp); - } - if ( linkRow != KErrNotFound ) - { - const CESMRRichTextLink* link = GetSelectedLink ( ); - if (link ) - { - HighlightLink (*link ); - DrawDeferred ( ); - } - } + // ... Highlight first link + TRAP_IGNORE( HighlightLinkL( *( iLinkList[0] ) ) ); } + // Focus coming from below ... else { - const CESMRRichTextLink* link = GetSelectedLink ( ); - if ( link ) - { - HighlightLink( *link ); - DrawDeferred(); - } + // ... Highlight last link + TRAP_IGNORE( HighlightLinkL( *( iLinkList[iLinkList.Count() - 1 ] ) ) ); } + DrawDeferred(); } - if (!IsFocused()) + // Losing focus + if ( !IsFocused() ) { - // losing focus - // codescanner - TRAP_IGNORE(SetSelectionL(CursorPos(), CursorPos())); - if( iLayout ) - { - TRAP_IGNORE(SetFontColorL( EFalse )); - } - // - TRAP_IGNORE( TextView()->SetDocPosL( 0 )); + TRAP_IGNORE( + SetSelectionL( CursorPos(), CursorPos() ); + ResetActionMenuL(); + ); } } @@ -208,7 +195,6 @@ } } - iCurrentLinkIndex = KErrNotFound; return linkRow; } @@ -224,23 +210,26 @@ { FUNC_LOG; + if ( iLinkList.Count() > aIndex) + { + TInt currPos( KErrNotFound ); + const CESMRRichTextLink* currentLink = GetSelectedLink(); + if ( currentLink ) + { + currPos = currentLink->StartPos(); + } - if(iLinkList.Count() > aIndex) - { - TInt pos = iLinkList[aIndex]->StartPos(); + TInt pos = iLinkList[ aIndex ]->StartPos(); TInt checkRow = TextLayout()->GetLineNumber( pos ); - if ( checkRow >= aStartRow && checkRow <= ( aEndRow ) ) + if ( checkRow >= aStartRow && checkRow <= aEndRow ) { if ( aDirection == TCursorPosition::EFLineDown && - aIndex > iCurrentLinkIndex || + pos > currPos || aDirection == TCursorPosition::EFLineUp && - ( aIndex < iCurrentLinkIndex || - iCurrentLinkIndex == KErrNotFound )) + ( pos < currPos || currPos == KErrNotFound ) ) { - iCurrentLinkIndex = aIndex; - // link found between next scroll area. return checkRow; } @@ -250,60 +239,6 @@ } // ----------------------------------------------------------------------------- -// CESMRRichTextViewer::SetHighLightToNextLinkL -// ----------------------------------------------------------------------------- -// -TBool CESMRRichTextViewer::SetHighLightToNextLinkL( - TCursorPosition::TMovementType aDirection, - TInt aStartRow, - TInt aEndRow ) - { - FUNC_LOG; - TBool ret( EFalse ); - - TInt currentLineNumber = TextLayout()->GetLineNumber( CursorPos() ); - - // check is there a link before next scroll point: - TInt linkRow = FindTextLinkBetweenNextScrollArea( - aStartRow , aEndRow, aDirection); - - if ( linkRow != KErrNotFound && iCurrentLinkIndex != KErrNotFound ) - { - const CESMRRichTextLink* link = GetSelectedLink ( ); - if (link ) - { - HighlightLink (*link ); - - if ( iObserver && linkRow != currentLineNumber ) - { - TInt endOfLink = link->StartPos()+link->Length(); - TInt line = TextLayout()->GetLineNumber( endOfLink ); - if ( aDirection == TCursorPosition::EFLineUp ) // moving up: - { - iObserver->MoveListAreaDownL( - RowHeight() * ( currentLineNumber - line )); - } - else - { - iObserver->MoveListAreaUpL( - RowHeight() * ( line - currentLineNumber )); - } - } - - DrawDeferred ( ); - ret = ETrue; - } - } - else - { - // no link are focused, do reset work to refresh the option menu. - ResetActionMenuL(); - } - - return ret; - } - -// ----------------------------------------------------------------------------- // CESMRRichTextViewer::OfferKeyEventL // ----------------------------------------------------------------------------- // @@ -312,167 +247,160 @@ TEventCode aType ) { FUNC_LOG; - // Handle only event keys - if ( aType == EEventKey ) + TKeyResponse response( EKeyWasNotConsumed ); + + // Handle only event keys. + if( aType != EEventKey ) { - if ( iObserver ) // only description field has observer set. + return response; + } + + /* + * Handles scrolling between rich text links. + */ + const CESMRRichTextLink* selectedLink = GetSelectedLink(); + TInt linkCount = iLinkList.Count(); + + // If a link is selected, it means that we are operating within + // the field and can move focus between the links. + if( linkCount && selectedLink ) + { + TInt selectedLinkIndex = iLinkList.Find( selectedLink ); + + switch ( aKeyEvent.iCode ) { - // fetch the current line number: - TInt currentLineNumber = TextLayout()->GetLineNumber( CursorPos() ); - - if ( aKeyEvent.iCode == EKeyDownArrow && aType == EEventKey ) + case EKeyLeftArrow: + case EKeyUpArrow: { - if ( !iObserver->IsFieldBottomVisible() && - SetHighLightToNextLinkL( - TCursorPosition::EFLineDown, - currentLineNumber, - currentLineNumber + KMaxAddressFieldLines) ) - { - return EKeyWasConsumed; - } - else if ( iObserver->IsFieldBottomVisible() ) + // If possible and exists ... + if( selectedLinkIndex > 0 && + selectedLinkIndex < linkCount ) { - if ( SetHighLightToNextLinkL(TCursorPosition::EFLineDown, - currentLineNumber, - iNumberOfLines) ) - { - return EKeyWasConsumed; - } - // means that the whole control is visible: - // and we can skip to next field - return EKeyWasNotConsumed; - } + // ...Highlight previous link. + HighlightLinkL( *( iLinkList[ selectedLinkIndex - 1 ] ) ); + response = EKeyWasConsumed; - if ( currentLineNumber == iNumberOfLines ) - { - // the end of text has been reached - return EKeyWasConsumed; - } - - // move three lines... - ScrollViewL( KMaxAddressFieldLines, - TCursorPosition::EFLineDown); - - - SetSelectionL( CursorPos(), CursorPos() ); - iCurrentLinkIndex = KErrNotFound; - if ( iObserver ) - { - iObserver->MoveListAreaUpL( - RowHeight() * KMaxAddressFieldLines ); + // View update required, for example if link is out of + // viewable area. + UpdateViewL( aKeyEvent ); } - return EKeyWasConsumed; + break; } - else if ( aKeyEvent.iCode == EKeyUpArrow && aType == EEventKey ) + case EKeyRightArrow: + case EKeyDownArrow: { - if (iPosition.iY < 0 && - SetHighLightToNextLinkL( - TCursorPosition::EFLineUp, - currentLineNumber - KMaxAddressFieldLines, - currentLineNumber)) - { - return EKeyWasConsumed; - } - if ( iPosition.iY > 0 ) + // If possible and exists ... + if( selectedLinkIndex + 1 < linkCount && + selectedLinkIndex >= 0 ) { - // before changing the focus the field above, - // check is there any links in rest of text - if (SetHighLightToNextLinkL(TCursorPosition::EFLineUp, - 0, - currentLineNumber)) - { - return EKeyWasConsumed; - } - - // means that the whole control is visible: - // and we can skip to next field - return EKeyWasNotConsumed; - } - else - { - TInt currentLineNumber = - TextLayout()->GetLineNumber( CursorPos() ); - // move three lines... - ScrollViewL( KMaxAddressFieldLines, - TCursorPosition::EFLineUp); - - SetSelectionL( CursorPos(), CursorPos()); - iCurrentLinkIndex = KErrNotFound; - - if ( iObserver ) - { - iObserver->MoveListAreaDownL( - RowHeight() * KMaxAddressFieldLines ); - } + // ...Highlight next link. + HighlightLinkL( *( iLinkList[ selectedLinkIndex + 1 ] ) ); + response = EKeyWasConsumed; - currentLineNumber = - TextLayout()->GetLineNumber( CursorPos() ); - return EKeyWasConsumed; + // View update required, for example if link is out of + // viewable area. + UpdateViewL( aKeyEvent ); } - } - } - if ( aKeyEvent.iCode == EKeyRightArrow || - aKeyEvent.iCode == EKeyDevice3 || - aKeyEvent.iCode == EKeyDevice4 || - aKeyEvent.iCode == EKeyEnter ) - { - // Show right click menu (action menu) - const CESMRRichTextLink* link = GetSelectedLink(); - if (link && - link->TriggerKey ( )== CESMRRichTextLink::ETriggerKeyRight ) - { - if ( !iLinkObserver || - !iLinkObserver->HandleRichTextLinkSelection(link) ) - { - iCntMenuHdlr->ShowActionMenuL(); - } - return EKeyWasConsumed; + + break; } - } - if ( aKeyEvent.iCode == EKeyLeftArrow ) - { - const CESMRRichTextLink* link = GetSelectedLink(); - if ( link ) + case EKeyDevice3: // Selection key { - return EKeyWasConsumed; + // No implementation. Non-MSK devices might require this. + break; } - } - if ( aKeyEvent.iCode == EKeyDevice3 || - aKeyEvent.iCode == EKeyDevice4 || - aKeyEvent.iCode == EKeyEnter ) - { - // Select link - const CESMRRichTextLink* link = GetSelectedLink ( ); - if (link && - link->TriggerKey ( )== CESMRRichTextLink::ETriggerKeyOk ) - { - if (iLinkObserver && - iLinkObserver->HandleRichTextLinkSelection (link ) ) - { - return EKeyWasConsumed; - } - } + default: + break; } } - return EKeyWasNotConsumed; + return response; } - // ----------------------------------------------------------------------------- -// CESMRRichTextViewer::ScrollViewL +// CESMRRichTextViewer::HandlePointerEventL // ----------------------------------------------------------------------------- // -void CESMRRichTextViewer::ScrollViewL( - TInt aNumberOfRows, - TCursorPosition::TMovementType aDirection) +void CESMRRichTextViewer::HandlePointerEventL( const TPointerEvent& aPointerEvent ) { - FUNC_LOG; - for( TInt i=0; i < aNumberOfRows; i++ ) + if ( Rect().Contains( aPointerEvent.iPosition) ) { - MoveCursorL( aDirection, EFalse); + TBool linkFound( EFalse ); + + switch ( aPointerEvent.iType ) + { + case TPointerEvent::EButton1Down: + case TPointerEvent::EDrag: + { + RRegion linkArea; + CleanupClosePushL( linkArea ); + + // Find matching link + TInt count = iLinkList.Count(); + + for ( TInt i = 0; i < count; ++i ) + { + CESMRRichTextLink* link = iLinkList[ i ]; + GetLinkAreaL( linkArea, *link ); + + if ( linkArea.Contains( aPointerEvent.iPosition ) ) + { + if ( link != GetSelectedLink() ) + { + iCntMenuHdlr->SetContactMenuObserver( this ); + HighlightLinkL( *link ); + DrawDeferred(); + } + + linkFound = ETrue; + break; + } + } + + CleanupStack::PopAndDestroy( &linkArea ); + + break; + } + + case TPointerEvent::EButton1Up: + { + const CESMRRichTextLink* link = GetSelectedLink(); + + TBool menuAvailable = iCntMenuHdlr->OptionsMenuAvailable(); + + if ( link + && ( menuAvailable + || link->Type() == CESMRRichTextLink::ETypeLocationUrl + || link->Type() == CESMRRichTextLink::ETypeAttachment ) ) + { + linkFound = ETrue; + + LinkSelectedL(); + } + else if ( link && !menuAvailable ) + { + linkFound = ETrue; + iOpenActionMenu = ETrue; + } + break; + } + default: + { + break; + } + } + + if ( !linkFound ) + { + // Tap on plain text + TextView()->ClearSelectionL(); + ResetActionMenuL(); + DrawDeferred(); + } + } + } // ----------------------------------------------------------------------------- @@ -482,88 +410,10 @@ EXPORT_C void CESMRRichTextViewer::SetMargins( TInt sMargin ) { // Set new value for left and right margins - if ( TextView() ) - { - TextView()->SetMarginWidths( sMargin ,0); - } + TextView()->SetMarginWidths( sMargin ,0); } // ----------------------------------------------------------------------------- -// CESMRRichTextViewer::SetFontL -// ----------------------------------------------------------------------------- -// -EXPORT_C void CESMRRichTextViewer::SetFontL( const CFont* aFont, - CESMRLayoutManager* aLayout ) - { - FUNC_LOG; - // These pointers are stored to able font color changing when losing or - // gaining focus - iLayout = aLayout; - iFont = aFont; - - SetFontColorL( IsFocused() ); - - // This forces CEikEdwin::OnReformatL to notify observer - // through HandleEdwinSizeEventL about changed size. - // It is notified only if linecount changes. - CEikEdwin::iNumberOfLines = 0; - CEikEdwin::FormatTextL(); - } - -// ----------------------------------------------------------------------------- -// CESMRRichTextViewer::SetFontColor -// ----------------------------------------------------------------------------- -// -void CESMRRichTextViewer::SetFontColorL( TBool aFocused ) - { - FUNC_LOG; - // all this stuff is needed to be set, otherwise the - // font loses its antialiasing drawing - - TFontSpec fontSpec = iFont->FontSpecInTwips(); - - CParaFormat paraFormat; - TParaFormatMask paraFormatMask; - paraFormat.iLineSpacingControl = CParaFormat::ELineSpacingExactlyInPixels; - - paraFormatMask.SetAttrib( EAttLineSpacing ); - paraFormat.iHorizontalAlignment = CParaFormat::ELeftAlign; - paraFormatMask.SetAttrib( EAttAlignment ); - - TCharFormat charFormat; - TCharFormatMask formatMask; - charFormat.iFontSpec = fontSpec; - - formatMask.SetAttrib( EAttFontTypeface ); - formatMask.SetAttrib( EAttFontHeight ); - formatMask.SetAttrib( EAttFontPosture ); - formatMask.SetAttrib( EAttFontStrokeWeight ); - - if( aFocused ) - { - charFormat.iFontPresentation.iTextColor = - iLayout->ViewerListAreaHighlightedTextColor(); - } - else - { - charFormat.iFontPresentation.iTextColor = KRgbBlack; - } - formatMask.SetAttrib( EAttColor ); - - CParaFormatLayer* paraFormatLayer = - CParaFormatLayer::NewL( ¶Format, paraFormatMask ); - CleanupStack::PushL( paraFormatLayer ); - - CCharFormatLayer* charFormatLayer = - CCharFormatLayer::NewL( charFormat, formatMask ); - - SetParaFormatLayer( paraFormatLayer ); - SetCharFormatLayer( charFormatLayer ); - - CleanupStack::Pop( paraFormatLayer ); - } - -// ----------------------------------------------------------------------------- // CESMRRichTextViewer::SetTextL // ----------------------------------------------------------------------------- // @@ -572,34 +422,37 @@ TBool aSearchLinks ) { FUNC_LOG; - iCurrentLinkIndex = KErrNotFound; - iLinkList.ResetAndDestroy ( ); + + iLinkList.ResetAndDestroy(); + + TextView()->SetMarginWidths( KDefaultTextSideMargin ,0); // Clear edwin text CEikEdwin::SetCursorPosL( 0, EFalse ); + CEikRichTextEditor::SetTextL( &KNullDesC ); + RichText()->Reset(); // text lenght plus one to ensure the formatting // used is full, not band formatting. SetUpperFullFormattingLength( aText->Length() + 1 ); // Set new edwin text + CEikEdwin::SetTextLimit( aText->Length ( ) ); CEikRichTextEditor::SetTextL( aText ); //Make sure cursor is invisible and selection visible - TextView()->SetCursorVisibilityL (TCursor::EFCursorInvisible, + TextView()->SetCursorVisibilityL( + TCursor::EFCursorInvisible, TCursor::EFCursorInvisible ); - TextView()->SetSelectionVisibilityL (ETrue ); + TextView()->SetSelectionVisibilityL( ETrue ); // Search text for links (highlights) - if (aSearchLinks ) + if ( aSearchLinks ) { SearchLinksL( *aText ); // find first link. FindTextLinkBetweenNextScrollArea(0, KMaxAddressFieldLines, TCursorPosition::EFLineDown); } - - // first row is 0, so let's add one... - iNumberOfLines = TextLayout()->GetLineNumber( TextLength() ) + 1; } // ----------------------------------------------------------------------------- @@ -626,8 +479,8 @@ // Reserve space for new link iLinkList.ReserveL( iLinkList.Count() + 1 ); - RichText()->ApplyCharFormatL( iFormat, - iFormatMask, + RichText()->ApplyCharFormatL( iRichTextLinkFormat, + iRichTextLinkFormatMask, aLink->StartPos(), aLink->Length() ); @@ -636,7 +489,7 @@ if ( highlight ) { - HighlightLink( *aLink ); + HighlightLinkL( *aLink ); } } @@ -654,8 +507,8 @@ // Reserve space for new link iLinkList.ReserveL( iLinkList.Count() + 1 ); - RichText()->ApplyCharFormatL( iFormat, - iFormatMask, + RichText()->ApplyCharFormatL( iRichTextLinkFormat, + iRichTextLinkFormatMask, aLink->StartPos(), aLink->Length() ); @@ -665,7 +518,7 @@ if ( highlight ) { - HighlightLink( *aLink ); + HighlightLinkL( *aLink ); } } @@ -676,25 +529,38 @@ EXPORT_C const CESMRRichTextLink* CESMRRichTextViewer::GetSelectedLink( ) const { FUNC_LOG; - if (iCurrentLinkIndex >= 0 && iCurrentLinkIndex < iLinkList.Count ( ) ) + CESMRRichTextLink* link( NULL ); + + TCursorSelection currentSelection = Selection(); + + for ( TInt i = 0; i < iLinkList.Count(); ++i ) { - return iLinkList[iCurrentLinkIndex]; + CESMRRichTextLink* tempLink = iLinkList[i]; + TInt startPos = tempLink->StartPos(); + TInt length = tempLink->Length(); + + TCursorSelection linkSelection( startPos, startPos + length ); + + if( currentSelection.iCursorPos == linkSelection.iCursorPos && + currentSelection.iAnchorPos == linkSelection.iAnchorPos ) + { + link = tempLink; + break; + } } - else - { - return NULL; - } + + return link; } // ----------------------------------------------------------------------------- // CESMRRichTextViewer::GetLinkTextL // ----------------------------------------------------------------------------- // -EXPORT_C HBufC* CESMRRichTextViewer::GetLinkTextL( +EXPORT_C HBufC* CESMRRichTextViewer::GetLinkTextLC( const CESMRRichTextLink& aLink ) const { FUNC_LOG; - return RichText()->Read( aLink.StartPos ( ), aLink.Length ( ) ).AllocL(); + return RichText()->Read( aLink.StartPos(), aLink.Length() ).AllocLC(); } // ----------------------------------------------------------------------------- @@ -729,7 +595,9 @@ EXPORT_C TInt CESMRRichTextViewer::LineCount() { FUNC_LOG; - return iNumberOfLines; + + // First row is 0, so let's add one... + return ( TextLayout()->GetLineNumber( TextLength() ) + 1 ); } // ----------------------------------------------------------------------------- // CESMRRichTextViewer::CurrentLineNumber @@ -743,13 +611,133 @@ } // ----------------------------------------------------------------------------- -// CESMRRichTextViewer::CESMRRichTextViewer +// CESMRRichTextViewer::SetFontL +// ----------------------------------------------------------------------------- +// +EXPORT_C void CESMRRichTextViewer::SetFontL( const CFont* aFont ) + { + FUNC_LOG; + // iFont is stored for changing font color when losing or + // gaining focus + iFont = aFont; + if ( !iParaFormat ) + { + iParaFormat = new ( ELeave ) CParaFormat(); + } + + // All this required, otherwise the font loses its + // antialiasing drawing. + iParaFormat->iLineSpacingControl = CParaFormat::ELineSpacingExactlyInPixels; + + iParaFormatMask.SetAttrib( EAttLineSpacing ); + iParaFormat->iHorizontalAlignment = CParaFormat::ELeftAlign; + iParaFormat->iVerticalAlignment = CParaFormat::ECenterAlign; + iParaFormatMask.SetAttrib( EAttAlignment ); + iParaFormatMask.SetAttrib( EAttVerticalAlignment ); + + iCharFormat.iFontSpec = iFont->FontSpecInTwips(); + + iCharFormatMask.SetAttrib( EAttFontTypeface ); + iCharFormatMask.SetAttrib( EAttFontHeight ); + iCharFormatMask.SetAttrib( EAttFontPosture ); + iCharFormatMask.SetAttrib( EAttFontStrokeWeight ); + + iCharFormat.iFontPresentation.iTextColor = + NMRColorManager::Color( NMRColorManager::EMRMainAreaTextColor ); + + iCharFormatMask.SetAttrib( EAttColor ); + } + +// ----------------------------------------------------------------------------- +// CESMRRichTextViewer::SetLineSpacingL +// ----------------------------------------------------------------------------- +// +EXPORT_C void CESMRRichTextViewer::SetLineSpacingL( TInt aLineSpacingInTwips ) + { + __ASSERT_DEBUG( iParaFormat, Panic( EParaFormatNotInitialised ) ); + iParaFormatMask.SetAttrib( EAttLineSpacing ); + iParaFormatMask.SetAttrib( EAttLineSpacingControl ); + iParaFormat->iLineSpacingControl = + CParaFormat::ELineSpacingExactlyInPixels; + + iParaFormat->iLineSpacingInTwips = aLineSpacingInTwips; + } + +// ----------------------------------------------------------------------------- +// CESMRRichTextViewer::ApplyLayoutChanges // ----------------------------------------------------------------------------- // -EXPORT_C void CESMRRichTextViewer::SetActionMenuStatus( TBool aStatus ) +EXPORT_C void CESMRRichTextViewer::ApplyLayoutChangesL() + { + __ASSERT_DEBUG( iParaFormat, Panic( EParaFormatNotInitialised ) ); + CRichText* richtext = RichText(); + TInt paraCount( richtext->ParagraphCount() ); + // Go through each paragraph and apply the same format + for( TInt i = 0; i < paraCount; ++i ) + { + TInt paraLen( 0 ); // Length of paragraph + TInt fiChPos( 0 ); // First character position of paragraph + // Get the length of the paragraph + fiChPos = richtext->CharPosOfParagraph( paraLen, i ); + richtext->ApplyParaFormatL( + iParaFormat, iParaFormatMask, fiChPos, paraLen ); + richtext->ApplyCharFormatL( + iCharFormat, iCharFormatMask, fiChPos, paraLen ); + } + // This forces CEikEdwin::OnReformatL to notify observer + // through HandleEdwinSizeEventL about changed size. + // It is notified only if linecount changes. + CEikEdwin::iNumberOfLines = 0; + CEikEdwin::FormatTextL(); + } + + +// ----------------------------------------------------------------------------- +// CESMRRichTextViewer::SetSelectedLink +// ----------------------------------------------------------------------------- +// +EXPORT_C void CESMRRichTextViewer::SetFocusLink( TInt aLinkIndex ) + { + if ( ( aLinkIndex >= 0 ) && ( aLinkIndex < iLinkList.Count() ) ) + { + TRAP_IGNORE( HighlightLinkL( *( iLinkList[aLinkIndex] ) ) ); + DrawDeferred(); + } + } + +// ----------------------------------------------------------------------------- +// CESMRRichTextViewer::GetSelectedLink +// ----------------------------------------------------------------------------- +// +EXPORT_C TInt CESMRRichTextViewer::GetFocusLink( ) const { FUNC_LOG; - iActionMenuStatus = aStatus; + // "-1" stand for no link be selected now. + TInt linkIndex( KErrNotFound ); + if ( 0 == iLinkList.Count() ) + { + return linkIndex; + } + + TCursorSelection currentSelection = Selection(); + + for ( TInt i = 0; i < iLinkList.Count(); ++i ) + { + CESMRRichTextLink* tempLink = iLinkList[i]; + TInt startPos = tempLink->StartPos(); + TInt length = tempLink->Length(); + + TCursorSelection linkSelection( startPos, startPos + length ); + + if( currentSelection.iCursorPos == linkSelection.iCursorPos && + currentSelection.iAnchorPos == linkSelection.iAnchorPos ) + { + linkIndex = i; + break; + } + } + + return linkIndex; } // ----------------------------------------------------------------------------- @@ -757,7 +745,6 @@ // ----------------------------------------------------------------------------- // CESMRRichTextViewer::CESMRRichTextViewer( ) -: iActionMenuStatus( ETrue ), iActionMenuOpen( EFalse ) { FUNC_LOG; } @@ -779,103 +766,40 @@ flags |= CEikEdwin::EOwnsWindow; } - CEikRichTextEditor::ConstructL (aParent, 1, 1, flags ); - SetSuppressBackgroundDrawing (ETrue ); - - User::LeaveIfError( - NMRBitmapManager::GetSkinBasedBitmap( - NMRBitmapManager::EMRBitmapRightClickArrow, iActionMenuIcon, - iActionMenuIconMask, KIconSize ) ); - - iESMRStatic.ConnectL ( ); - iCntMenuHdlr = &iESMRStatic.ContactMenuHandlerL(); - iCurrentLinkIndex = KErrNotFound; - iFormatMask.SetAttrib( EAttFontUnderline ); - iFormat.iFontPresentation.iUnderline = EUnderlineOn; - iFormatMask.SetAttrib( EAttColor ); - iFormat.iFontPresentation.iTextColor = KRgbBlue; + CEikRichTextEditor::ConstructL( aParent, 1, 1, flags ); + SetSuppressBackgroundDrawing( ETrue ); - iLongTapDetector = CAknLongTapDetector::NewL(this); - } - -// ----------------------------------------------------------------------------- -// CESMRRichTextViewer::Draw -// ----------------------------------------------------------------------------- -// -void CESMRRichTextViewer::Draw( const TRect& aRect ) const - { - FUNC_LOG; - CEikEdwin::Draw( aRect ); - if (IsFocused ( ) && iActionMenuStatus ) - { - const CESMRRichTextLink* link = GetSelectedLink ( ); - if (link && link->TriggerKey ( )== CESMRRichTextLink::ETriggerKeyRight ) - { - TRAP_IGNORE(DrawRightClickIconL(*link)); - } - } + iESMRStatic.ConnectL(); + iCntMenuHdlr = &iESMRStatic.ContactMenuHandlerL(); + iRichTextLinkFormatMask.SetAttrib( EAttFontUnderline ); + iRichTextLinkFormat.iFontPresentation.iUnderline = EUnderlineOn; + iRichTextLinkFormatMask.SetAttrib( EAttColor ); + iRichTextLinkFormat.iFontPresentation.iTextColor = + NMRColorManager::Color( + NMRColorManager::EMRCutCopyPasteHighlightColor ); } // ----------------------------------------------------------------------------- -// CESMRRichTextViewer::DrawRightClickIconL +// CESMRRichTextViewer::HighlightLinkL // ----------------------------------------------------------------------------- // -void CESMRRichTextViewer::DrawRightClickIconL( - const CESMRRichTextLink& aLink ) const +void CESMRRichTextViewer::HighlightLinkL(const CESMRRichTextLink& aLink ) { FUNC_LOG; - TTmDocPosSpec posSpec; - TTmPosInfo2 posInfo; - - posSpec.iPos = aLink.StartPos ( )+ aLink.Length ( ); - posSpec.iType = TTmDocPosSpec::ETrailing; - - if (TextView()->FindDocPosL (posSpec, posInfo ) ) - { - TPoint pt = posInfo.iEdge; - pt -= iActionMenuIcon->SizeInPixels ( ); - - pt.iY = pt.iY + KArrowUpperMargin; - pt.iX = Parent()->Rect().iBr.iX - - iActionMenuIcon->SizeInPixels().iWidth - KArrowRightMargin; - TRect dst(pt, iActionMenuIcon->SizeInPixels ( )); - TRect src(TPoint (0, 0 ), iActionMenuIcon->SizeInPixels ( )); - - CWindowGc& gc = SystemGc ( ); - gc.DrawBitmapMasked (dst, iActionMenuIcon, src, iActionMenuIconMask, - EFalse ); - } - } - -// ----------------------------------------------------------------------------- -// CESMRRichTextViewer::HighlightLink -// ----------------------------------------------------------------------------- -// -void CESMRRichTextViewer::HighlightLink(const CESMRRichTextLink& aLink ) - { - FUNC_LOG; - TInt error = KErrNone; TCursorSelection selection( aLink.StartPos(), aLink.StartPos() + aLink.Length() ); // If TextView is not constructed yet. if ( !TextView() ) { - TRAP( error, SetSelectionL( selection.iCursorPos, selection.iAnchorPos ) ); + SetSelectionL( selection.iCursorPos, selection.iAnchorPos ); } else { TextView()->SetPendingSelection( selection ); } - if ( error == KErrNone ) - { - TRAP( error, SetValueL( aLink ) ); - if ( error != KErrNone ) - { - CEikonEnv::Static()->// codescanner::eikonenvstatic - HandleError( error ); - } - } + SetValueL( aLink ); + ChangeMiddleSoftkeyL( aLink ); } // ----------------------------------------------------------------------------- @@ -908,15 +832,7 @@ } case CESMRRichTextLink::ETypeAttachment: { - // Set this as command observer. - // Commands from contact menu handler are - // processed in ProcessCommandL and forwarded - // as field command events - // - //iCntMenuHdlr->SetCommandObserver( this ); - // - iCntMenuHdlr->SetValueL( aLink.Value(), - CESMRContactMenuHandler::EValueTypeAttachment ); + break; } default: @@ -1005,68 +921,42 @@ // ----------------------------------------------------------------------------- // CESMRRichTextViewer::CopyCurrentLinkToClipBoardL // ----------------------------------------------------------------------------- +// EXPORT_C void CESMRRichTextViewer::CopyCurrentLinkToClipBoardL() const { FUNC_LOG; const CESMRRichTextLink* link = GetSelectedLink(); - - if( link ) - { - HBufC* clipBoardText = GetLinkTextL(*link); + HBufC* clipBoardText = NULL; - if ( clipBoardText ) - { - CleanupStack::PushL( clipBoardText ); - CClipboard* cb = - CClipboard::NewForWritingLC( CCoeEnv::Static()->FsSession() ); - cb->StreamDictionary().At( KClipboardUidTypePlainText ); - CPlainText* plainText = CPlainText::NewL(); - CleanupStack::PushL( plainText ); - plainText->InsertL( 0 , *clipBoardText); - plainText->CopyToStoreL( cb->Store(), - cb->StreamDictionary(), 0, plainText->DocumentLength()); - CleanupStack::PopAndDestroy( plainText ); - cb->CommitL(); - CleanupStack::PopAndDestroy( cb ); - CleanupStack::PopAndDestroy( clipBoardText ); - } - } - } + if ( link ) + { + clipBoardText = GetLinkTextLC( *link ); + } -// ----------------------------------------------------------------------------- -// CESMRRichTextViewer::CopyCurrentLinkValueToClipBoardL -// ----------------------------------------------------------------------------- -EXPORT_C void CESMRRichTextViewer::CopyCurrentLinkValueToClipBoardL() const - { - FUNC_LOG; - const CESMRRichTextLink* link = GetSelectedLink(); - - if( link ) + if ( clipBoardText ) { - TDesC& clipBoardText = link->Value(); - - CClipboard* cb = + CClipboard* cb = CClipboard::NewForWritingLC( CCoeEnv::Static()->FsSession() ); cb->StreamDictionary().At( KClipboardUidTypePlainText ); CPlainText* plainText = CPlainText::NewL(); CleanupStack::PushL( plainText ); - plainText->InsertL( 0 , clipBoardText); + plainText->InsertL( 0 , *clipBoardText); plainText->CopyToStoreL( cb->Store(), - cb->StreamDictionary(), 0, plainText->DocumentLength()); + cb->StreamDictionary(), 0, plainText->DocumentLength()); CleanupStack::PopAndDestroy( plainText ); cb->CommitL(); CleanupStack::PopAndDestroy( cb ); + CleanupStack::PopAndDestroy( clipBoardText ); } } - // ----------------------------------------------------------------------------- // CESMRRichTextViewer::ResetActionMenu // ----------------------------------------------------------------------------- EXPORT_C void CESMRRichTextViewer::ResetActionMenuL() const // codescanner::LFunctionCantLeave { FUNC_LOG; - if(iCntMenuHdlr) + if ( iCntMenuHdlr ) { iCntMenuHdlr->Reset(); } @@ -1095,7 +985,6 @@ const CESMRRichTextLink* link = GetSelectedLink(); if ( link ) { - iActionMenuOpen = ETrue; switch ( link->TriggerKey() ) { case CESMRRichTextLink::ETriggerKeyRight: @@ -1103,7 +992,7 @@ if ( !iLinkObserver || !iLinkObserver->HandleRichTextLinkSelection(link) ) { - iCntMenuHdlr->ShowActionMenuL(); + ShowContextMenuL(); } linkSelected = ETrue; break; @@ -1111,7 +1000,7 @@ case CESMRRichTextLink::ETriggerKeyOk: { if (iLinkObserver && - iLinkObserver->HandleRichTextLinkSelection (link ) ) + iLinkObserver->HandleRichTextLinkSelection( link ) ) { linkSelected = ETrue; } @@ -1122,13 +1011,11 @@ break; } } - iActionMenuOpen = EFalse; } return linkSelected; } - // ----------------------------------------------------------------------------- // CESMRRichTextViewer::ProcessCommandL // ----------------------------------------------------------------------------- @@ -1157,101 +1044,198 @@ FUNC_LOG; CEikRichTextEditor::ActivateL(); - // Make sure correct font color is in use. - SetFontColorL( IsFocused() ); - // CEikEdwin::ActivateL removes selection, re-set highlight // if focused and there's a selected link. - if ( IsFocused() && GetSelectedLink() ) + const CESMRRichTextLink* link = GetSelectedLink(); + if ( link && IsFocused() ) { - HighlightLink( *GetSelectedLink() ); + HighlightLinkL( *link ); DrawDeferred(); } } // ----------------------------------------------------------------------------- -// CESMRRichTextViewer::HandlePointerEventL +// CESMRRichTextViewer::ContactActionQueryComplete // ----------------------------------------------------------------------------- // -void CESMRRichTextViewer::HandlePointerEventL(const TPointerEvent& aPointerEvent) +void CESMRRichTextViewer::ContactActionQueryComplete() { - TBool linkTapped( EFalse ); - CESMRRichTextLink* link = NULL; - // fetch the current line number: - TInt currentLineNumber = TextLayout()->GetLineNumber( CursorPos() ); - // find out tapped position - TPoint touchPoint = aPointerEvent.iPosition; - - TInt tappedPos = TextView()->XyPosToDocPosL( touchPoint ); - for (TInt i = 0; iStartPos(); - TInt linkEnd = link->StartPos() + link->Length() - 1; - if ( tappedPos >= linkStart && tappedPos <= linkEnd ) - { - // link tapped - linkTapped = ETrue; - iCurrentLinkIndex = i; - break; - } + // Activate link as actions have been discovered + TRAP_IGNORE( LinkSelectedL() ); } - if ( aPointerEvent.iType == TPointerEvent::EButton1Down ) + // Reset menu observer + iCntMenuHdlr->SetContactMenuObserver( NULL ); + iOpenActionMenu = EFalse; + } + +// ----------------------------------------------------------------------------- +// CESMRRichTextViewer::ShowContextMenuL +// ----------------------------------------------------------------------------- +// +void CESMRRichTextViewer::ShowContextMenuL() + { + FUNC_LOG; + iOpenActionMenu = EFalse; + ProcessCommandL( EAknSoftkeyContextOptions ); + } + +// ----------------------------------------------------------------------------- +// CESMRRichTextViewer::GetLinkAreaL +// ----------------------------------------------------------------------------- +// +void CESMRRichTextViewer::GetLinkAreaL( + TRegion& aRegion, + const CESMRRichTextLink& aLink ) const + { + FUNC_LOG; + TTmDocPosSpec posSpec; + TTmPosInfo2 posInfo; + + posSpec.iPos = aLink.StartPos(); + posSpec.iType = TTmDocPosSpec::ELeading; + + aRegion.Clear(); + + if ( TextView()->FindDocPosL( posSpec, posInfo ) ) { - if ( linkTapped ) - { - // tactile feedback - MTouchFeedback* feedback = MTouchFeedback::Instance(); - if ( feedback ) - { - feedback->InstantFeedback( this, ETouchFeedbackBasic ); - } + TRect linkRect( 0, 0, 0, 0 ); + + // Create link surrounding rectangle + HBufC* text = GetLinkTextLC( aLink ); + TInt textWidth = AknBidiTextUtils::MeasureTextBoundsWidth( + *iFont, + *text, + CFont::TMeasureTextInput::EFVisualOrder ); - TPointerEvent pointerEvent = aPointerEvent; - pointerEvent.iParentPosition = pointerEvent.iPosition - + DrawableWindow()->AbsPosition(); - iLongTapDetector->PointerEventL( pointerEvent ); - HighlightLink( *link ); - if ( Parent() ) + TPoint tl( posInfo.iEdge ); + + if ( AknLayoutUtils::LayoutMirrored() ) + { + // move top left x to end of text + tl.iX -= textWidth; + } + + tl.iY -= iFont->FontMaxAscent(); + TPoint br( tl.iX + textWidth, tl.iY + iFont->FontMaxHeight() ); + + TRect rect( Rect() ); + + while ( ( tl.iX < rect.iTl.iX || br.iX > rect.iBr.iX ) + && !aRegion.CheckError() ) + { + // Link on multiple lines + + tl.iX = Max( rect.iTl.iX, tl.iX ); + br.iX = Min( br.iX, rect.iBr.iX ); + linkRect.SetRect( tl, br ); + aRegion.AddRect( linkRect ); + + TPtrC remainder( text->Mid( posSpec.iPos - aLink.StartPos() ) ); + TInt numChars = iFont->TextCount( remainder, + linkRect.Width() ); + posSpec.iPos += numChars; + remainder.Set( remainder.Mid( numChars) ); + + if ( TextView()->FindDocPosL( posSpec, posInfo ) ) { - Parent()->DrawDeferred(); - } - else - { - DrawDeferred(); + textWidth = AknBidiTextUtils::MeasureTextBoundsWidth( + *iFont, + remainder, + CFont::TMeasureTextInput::EFVisualOrder ); + + tl = posInfo.iEdge; + + if ( AknLayoutUtils::LayoutMirrored() ) + { + // move top left x to end of text + tl.iX -= textWidth; + } + + tl.iY -= iFont->FontMaxAscent(); + br.SetXY( tl.iX + textWidth, tl.iY + iFont->FontMaxHeight() ); } } - } - else - { - TPointerEvent pointerEvent = aPointerEvent; - pointerEvent.iParentPosition = pointerEvent.iPosition - + DrawableWindow()->AbsPosition(); - iLongTapDetector->PointerEventL( pointerEvent ); - if ( aPointerEvent.iType == TPointerEvent::EButton1Up ) - { - if ( linkTapped && !iActionMenuOpen ) - { - // tapped highlighted field, execute action - LinkSelectedL(); - } - } + linkRect.SetRect( tl, br ); + aRegion.AddRect( linkRect ); + + CleanupStack::PopAndDestroy( text ); } } // ----------------------------------------------------------------------------- -// CESMRRichTextViewer::HandleLongTapEventL +// CESMRRichTextViewer::ChangeMiddleSoftkeyL +// ----------------------------------------------------------------------------- +// +void CESMRRichTextViewer::ChangeMiddleSoftkeyL( const CESMRRichTextLink& aLink ) + { + FUNC_LOG; + CESMRField* field = static_cast< CESMRField* >( Parent() ); + + if ( field ) + { + field->ChangeMiddleSoftKeyL( aLink.MSKCommand(), aLink.MSKText() ); + } + } + +// ----------------------------------------------------------------------------- +// CESMRRichTextViewer::UpdateViewL // ----------------------------------------------------------------------------- // -void CESMRRichTextViewer::HandleLongTapEventL( const TPoint& /*aPenEventLocation*/, - const TPoint& /*aPenEventScreenLocation*/ ) +void CESMRRichTextViewer::UpdateViewL( const TKeyEvent &aKeyEvent ) { - if ( !iActionMenuOpen ) + FUNC_LOG; + const CESMRRichTextLink* selectedLink = GetSelectedLink(); + + if( !selectedLink ) + { + return; + } + + RRegion linkRegion; + CleanupClosePushL( linkRegion ); + + GetLinkAreaL( linkRegion, *selectedLink ); + TRect linkRect = linkRegion.BoundingRect(); + + CleanupStack::PopAndDestroy( &linkRegion ); + + TRect viewableAreaRect = iObserver->ViewableAreaRect(); + + + switch ( aKeyEvent.iCode ) { - LinkSelectedL(); + case EKeyLeftArrow: + case EKeyUpArrow: + { + if( linkRect.iTl.iY < viewableAreaRect.iTl.iY ) + { + // Move fields down + iObserver->RePositionFields( + -( linkRect.iTl.iY - viewableAreaRect.iTl.iY ) ); + } + + break; + } + case EKeyRightArrow: + case EKeyDownArrow: + { + if( linkRect.iBr.iY > viewableAreaRect.iBr.iY ) + { + // Move fields up + iObserver->RePositionFields( + -( linkRect.iBr.iY - viewableAreaRect.iBr.iY ) ); + } + break; + } + default: + break; } } + // EOF