--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/meetingrequest/mrgui/mrfieldbuildercommon/src/cesmrrichtextviewer.cpp Wed Sep 01 12:28:57 2010 +0100
@@ -0,0 +1,1288 @@
+/*
+* 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"
+* 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 : CEikRichTextEditor based Rich Text viewer
+* Version : %version: e002sa33#45.3 %
+*
+*/
+
+#include "cesmrrichtextviewer.h"
+
+#include "mesmrlistobserver.h"// SCROLLING_MOD: List observer header
+#include "esmrconfig.hrh"
+#include "esmrhelper.h"
+#include "cesmrfieldcommandevent.h"
+#include "mesmrfieldeventqueue.h"
+#include "cesmrrichtextlink.h"
+#include "cesmrcontactmenuhandler.h"
+#include "nmrbitmapmanager.h"
+#include "nmrcolormanager.h"
+#include "esmrfieldbuilderdef.h"
+#include "cesmrfield.h"
+
+#include <esmrgui.rsg>
+#include <commonphoneparser.h>
+#include <finditemengine.h>
+#include <txtrich.h>
+#include <AknsUtils.h>
+#include <AknBidiTextUtils.h>
+#include <AknUtils.h>
+#include <eikenv.h>
+#include <data_caging_path_literals.hrh>
+#include <baclipb.h> // for clipboard copy
+#include <txtclipboard.h>
+
+// DEBUG
+#include "emailtrace.h"
+
+// Unnamed namespace for local definitions
+namespace{ // codescanner::namespace
+
+#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
+
+// ======== MEMBER FUNCTIONS ========
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::NewL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CESMRRichTextViewer* CESMRRichTextViewer::NewL(
+ const CCoeControl* aParent)
+ {
+ FUNC_LOG;
+ CESMRRichTextViewer* self = new (ELeave) CESMRRichTextViewer;
+ CleanupStack::PushL ( self );
+ self->ConstructL( aParent );
+ CleanupStack::Pop ( self );
+ return self;
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::~CESMRRichTextViewer
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CESMRRichTextViewer::~CESMRRichTextViewer( )
+ {
+ FUNC_LOG;
+ iLinkList.ResetAndDestroy ( );
+ iESMRStatic.Close ( );
+ delete iParaFormat;
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::PositionChanged
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CESMRRichTextViewer::PositionChanged( )
+ {
+ FUNC_LOG;
+ CTextView* view = TextView ( );
+ if ( view )
+ {
+ view->SetViewRect ( Rect ( ) );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::FocusChanged
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CESMRRichTextViewer::FocusChanged(
+ TDrawNow aDrawNow )
+ {
+ FUNC_LOG;
+ CEikRichTextEditor::FocusChanged( aDrawNow );
+ if ( !TextLayout() || !TextView() )
+ {
+ // not constructed totally:
+ return;
+ }
+
+ // 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 ) )
+ {
+ // We need the field indexes, cast required
+ CESMRField* parent = static_cast< CESMRField* >( Parent() );
+
+ iCntMenuHdlr->SetContactMenuObserver( this );
+ // Focus coming from above ...
+ if( parent->CurrentItemIndex() > parent->PreItemIndex() )
+ {
+ // ... Highlight first link
+ TRAP_IGNORE( HighlightLinkL( *( iLinkList[0] ) ) );
+ }
+ // Focus coming from below ...
+ else
+ {
+ // ... Highlight last link
+ TRAP_IGNORE( HighlightLinkL( *( iLinkList[iLinkList.Count() - 1 ] ) ) );
+ }
+ DrawDeferred();
+ }
+
+ // Losing focus
+ if ( !IsFocused() )
+ {
+ TRAP_IGNORE(
+ SetSelectionL( CursorPos(), CursorPos() );
+ ResetActionMenuL();
+ );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::FindTextLinkBetweenNextScrollArea
+// -----------------------------------------------------------------------------
+//
+TInt CESMRRichTextViewer::FindTextLinkBetweenNextScrollArea(
+ TInt aStartRow,
+ TInt aEndRow,
+ TCursorPosition::TMovementType aDirection)
+ {
+ FUNC_LOG;
+ TInt linkRow(KErrNotFound);
+
+ // fetch the line number where the next link is located:
+ if ( aDirection == TCursorPosition::EFLineDown )
+ {
+ for (TInt i = 0; i<iLinkList.Count(); i++)
+ {
+ linkRow = ValidLinkForFocusing(i, aDirection, aStartRow, aEndRow);
+ if ( linkRow != KErrNotFound)
+ {
+ return linkRow;
+ }
+ }
+ }
+ else
+ for (TInt i = iLinkList.Count()-1; i>=0 ; i--)
+ {
+ linkRow = ValidLinkForFocusing(i, aDirection, aStartRow, aEndRow);
+ if ( linkRow != KErrNotFound)
+ {
+ return linkRow;
+ }
+ }
+
+ return linkRow;
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::ValidLinkForFocusing
+// -----------------------------------------------------------------------------
+//
+TInt CESMRRichTextViewer::ValidLinkForFocusing(
+ TInt aIndex,
+ TCursorPosition::TMovementType aDirection,
+ TInt aStartRow,
+ TInt aEndRow )
+ {
+ FUNC_LOG;
+
+ if ( iLinkList.Count() > aIndex)
+ {
+ TInt currPos( KErrNotFound );
+ const CESMRRichTextLink* currentLink = GetSelectedLink();
+ if ( currentLink )
+ {
+ currPos = currentLink->StartPos();
+ }
+
+ TInt pos = iLinkList[ aIndex ]->StartPos();
+
+ TInt checkRow = TextLayout()->GetLineNumber( pos );
+
+ if ( checkRow >= aStartRow && checkRow <= aEndRow )
+ {
+ if ( aDirection == TCursorPosition::EFLineDown &&
+ pos > currPos ||
+ aDirection == TCursorPosition::EFLineUp &&
+ ( pos < currPos || currPos == KErrNotFound ) )
+ {
+ // link found between next scroll area.
+ return checkRow;
+ }
+ }
+ }
+ return KErrNotFound;
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::OfferKeyEventL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TKeyResponse CESMRRichTextViewer::OfferKeyEventL(
+ const TKeyEvent &aKeyEvent,
+ TEventCode aType )
+ {
+ FUNC_LOG;
+ TKeyResponse response( EKeyWasNotConsumed );
+
+ // Handle only event keys.
+ if( aType != EEventKey )
+ {
+ 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 )
+ {
+ case EKeyLeftArrow:
+ case EKeyUpArrow:
+ {
+ // If possible and exists ...
+ if( selectedLinkIndex > 0 &&
+ selectedLinkIndex < linkCount )
+ {
+ // ...Highlight previous link.
+ HighlightLinkL( *( iLinkList[ selectedLinkIndex - 1 ] ) );
+ response = EKeyWasConsumed;
+
+ // View update required, for example if link is out of
+ // viewable area.
+ UpdateViewL( aKeyEvent );
+ }
+
+ break;
+ }
+ case EKeyRightArrow:
+ case EKeyDownArrow:
+ {
+ // If possible and exists ...
+ if( selectedLinkIndex + 1 < linkCount &&
+ selectedLinkIndex >= 0 )
+ {
+ // ...Highlight next link.
+ HighlightLinkL( *( iLinkList[ selectedLinkIndex + 1 ] ) );
+ response = EKeyWasConsumed;
+
+ // View update required, for example if link is out of
+ // viewable area.
+ UpdateViewL( aKeyEvent );
+ }
+
+ break;
+ }
+ case EKeyDevice3: // Selection key
+ case EKeyEnter:
+ {
+ LinkSelectedL();
+ response = EKeyWasConsumed;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ return response;
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::HandlePointerEventL
+// -----------------------------------------------------------------------------
+//
+void CESMRRichTextViewer::HandlePointerEventL( const TPointerEvent& aPointerEvent )
+ {
+ if ( Rect().Contains( aPointerEvent.iPosition) )
+ {
+ TBool linkFound( EFalse );
+
+ switch ( aPointerEvent.iType )
+ {
+ case TPointerEvent::EButton1Down:
+ {
+ 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->Reset();
+ 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
+ || link->Type() == CESMRRichTextLink::ETypeShowAll ) )
+ {
+ linkFound = ETrue;
+
+ LinkSelectedL();
+ }
+ else if ( link && !menuAvailable )
+ {
+ linkFound = ETrue;
+ iOpenActionMenu = ETrue;
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ if ( !linkFound && TPointerEvent::EDrag != aPointerEvent.iType )
+ {
+ // Tap on plain text
+ TextView()->ClearSelectionL();
+ ResetActionMenuL();
+ DrawDeferred();
+ }
+
+ }
+
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::SetMargins
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CESMRRichTextViewer::SetMargins( TInt sMargin )
+ {
+ // Set new value for left and right margins
+ TextView()->SetMarginWidths( sMargin ,0);
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::SetTextL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CESMRRichTextViewer::SetTextL(
+ const TDesC* aText,
+ TBool aSearchLinks )
+ {
+ FUNC_LOG;
+
+ 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,
+ TCursor::EFCursorInvisible );
+ TextView()->SetSelectionVisibilityL( ETrue );
+
+ // Search text for links (highlights)
+ if ( aSearchLinks )
+ {
+ SearchLinksL( *aText );
+ // find first link.
+ FindTextLinkBetweenNextScrollArea(0, KMaxAddressFieldLines, TCursorPosition::EFLineDown);
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::SetLinkObserver
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CESMRRichTextViewer::SetLinkObserver(
+ MESMRRichTextObserver* aLinkObserver )
+ {
+ FUNC_LOG;
+ iLinkObserver = aLinkObserver;
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::AddLinkL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CESMRRichTextViewer::AddLinkL( CESMRRichTextLink* aLink )
+ {
+ FUNC_LOG;
+ // If this is first link, set it highlighted
+ TBool highlight = IsFocused()&& ( iLinkList.Count() == 0 );
+
+ // Reserve space for new link
+ iLinkList.ReserveL( iLinkList.Count() + 1 );
+
+ RichText()->ApplyCharFormatL( iRichTextLinkFormat,
+ iRichTextLinkFormatMask,
+ aLink->StartPos(),
+ aLink->Length() );
+
+ // Append aLink to link list. Space has been reserved, so this cannot fail.
+ iLinkList.AppendL( aLink );
+
+ if ( highlight )
+ {
+ HighlightLinkL( *aLink );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::InsertLinkL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CESMRRichTextViewer::InsertLinkL( CESMRRichTextLink* aLink,
+ TInt aPosition )
+ {
+ FUNC_LOG;
+ // If this is first link, set it highlighted
+ TBool highlight = IsFocused()&& ( iLinkList.Count() == 0 );
+
+ // Reserve space for new link
+ iLinkList.ReserveL( iLinkList.Count() + 1 );
+
+ RichText()->ApplyCharFormatL( iRichTextLinkFormat,
+ iRichTextLinkFormatMask,
+ aLink->StartPos(),
+ aLink->Length() );
+
+ // Insert aLink to link list. Space has been reserved, so this cannot fail.
+ // InsertL panics if aPosition is illegal.
+ iLinkList.InsertL( aLink, aPosition );
+
+ if ( highlight )
+ {
+ HighlightLinkL( *aLink );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::GetSelectedLink
+// -----------------------------------------------------------------------------
+//
+EXPORT_C const CESMRRichTextLink* CESMRRichTextViewer::GetSelectedLink( ) const
+ {
+ FUNC_LOG;
+ CESMRRichTextLink* link( NULL );
+
+ 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 )
+ {
+ link = tempLink;
+ break;
+ }
+ }
+
+ return link;
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::GetLinkTextL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C HBufC* CESMRRichTextViewer::GetLinkTextLC(
+ const CESMRRichTextLink& aLink ) const
+ {
+ FUNC_LOG;
+ return RichText()->Read( aLink.StartPos(), aLink.Length() ).AllocLC();
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::CESMRRichTextViewer
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CESMRRichTextViewer::SetListObserver(
+ MESMRListObserver* aObserver )
+ {
+ FUNC_LOG;
+ iObserver = aObserver;
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::RowHeight
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CESMRRichTextViewer::RowHeight()
+ {
+ FUNC_LOG;
+ TInt bandHeight = TextLayout()->BandHeight();
+ // Starts from zero, so let's increase the count by one.
+ TInt lineNumberCount = TextLayout()->GetLineNumber( TextLength() ) + 1;
+
+ return ( bandHeight / lineNumberCount );
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::LineCount
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CESMRRichTextViewer::LineCount()
+ {
+ FUNC_LOG;
+
+ // First row is 0, so let's add one...
+ return ( TextLayout()->GetLineNumber( TextLength() ) + 1 );
+ }
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::CurrentLineNumber
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CESMRRichTextViewer::CurrentLineNumber()
+ {
+ FUNC_LOG;
+ // first line is zero, let's increase it by one
+ return TextLayout()->GetLineNumber( CursorPos() ) + 1;
+ }
+
+// -----------------------------------------------------------------------------
+// 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;
+ if ( AknLayoutUtils::LayoutMirrored() )
+ {
+ iParaFormat->iHorizontalAlignment = CParaFormat::ERightAlign;
+ }
+ 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::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;
+ // "-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;
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::PointerEventOccuresOnALinkL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TBool CESMRRichTextViewer::PointerEventOccuresOnALinkL(
+ const TPointerEvent &aPointerEvent )
+ {
+ FUNC_LOG;
+ TBool ret( EFalse );
+
+ 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 ) )
+ {
+ ret = ETrue;
+ break;
+ }
+ }
+
+ CleanupStack::PopAndDestroy( &linkArea );
+
+ return ret;
+ }
+
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::CESMRRichTextViewer
+// -----------------------------------------------------------------------------
+//
+CESMRRichTextViewer::CESMRRichTextViewer( )
+ {
+ FUNC_LOG;
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CESMRRichTextViewer::ConstructL(const CCoeControl* aParent)
+ {
+ FUNC_LOG;
+
+ TInt flags = CEikEdwin::EReadOnly |
+ CEikEdwin::EResizable |
+ CEikEdwin::ENoAutoSelection |
+ CEikEdwin::EAvkonDisableCursor;
+ if( !aParent )
+ {
+ flags |= CEikEdwin::EOwnsWindow;
+ }
+
+ CEikRichTextEditor::ConstructL( aParent, 1, 1, flags );
+ SetSuppressBackgroundDrawing( ETrue );
+
+ iESMRStatic.ConnectL();
+ iCntMenuHdlr = &iESMRStatic.ContactMenuHandlerL();
+ iRichTextLinkFormatMask.SetAttrib( EAttFontUnderline );
+ iRichTextLinkFormat.iFontPresentation.iUnderline = EUnderlineOn;
+ iRichTextLinkFormatMask.SetAttrib( EAttColor );
+ iRichTextLinkFormat.iFontPresentation.iTextColor =
+ NMRColorManager::Color(
+ NMRColorManager::EMRCutCopyPasteHighlightColor );
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::HighlightLinkL
+// -----------------------------------------------------------------------------
+//
+void CESMRRichTextViewer::HighlightLinkL(const CESMRRichTextLink& aLink )
+ {
+ FUNC_LOG;
+ TCursorSelection selection( aLink.StartPos(), aLink.StartPos() + aLink.Length() );
+
+ // If TextView is not constructed yet.
+ if ( !TextView() )
+ {
+ SetSelectionL( selection.iCursorPos, selection.iAnchorPos );
+ }
+ else
+ {
+ TextView()->SetPendingSelection( selection );
+ }
+
+ SetValueL( aLink );
+ ChangeMiddleSoftkeyL( aLink );
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::SetValueL
+// -----------------------------------------------------------------------------
+//
+void CESMRRichTextViewer::SetValueL( const CESMRRichTextLink& aLink )
+ {
+ FUNC_LOG;
+ // Instantiate contact action menu for selected link
+ switch ( aLink.Type() )
+ {
+ case CESMRRichTextLink::ETypeEmail:
+ {
+ iCntMenuHdlr->SetValueL( aLink.Value(),
+ CESMRContactMenuHandler::EValueTypeEmail );
+ break;
+ }
+ case CESMRRichTextLink::ETypePhoneNumber:
+ {
+ iCntMenuHdlr->SetValueL( aLink.Value(),
+ CESMRContactMenuHandler::EValueTypePhoneNumber );
+ break;
+ }
+ case CESMRRichTextLink::ETypeURL:
+ {
+ iCntMenuHdlr->SetValueL( aLink.Value(),
+ CESMRContactMenuHandler::EValueTypeURL );
+ break;
+ }
+ case CESMRRichTextLink::ETypeAttachment:
+ {
+
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::SearchLinksL
+// -----------------------------------------------------------------------------
+//
+void CESMRRichTextViewer::SearchLinksL(const TDesC& aText )
+ {
+ FUNC_LOG;
+ // Search for emails, phone numbers and urls
+ TInt searchCases = CFindItemEngine::EFindItemSearchMailAddressBin |
+ CFindItemEngine::EFindItemSearchPhoneNumberBin |
+ CFindItemEngine::EFindItemSearchURLBin;
+
+ CFindItemEngine* itemEngine =
+ CFindItemEngine::NewL ( aText,
+ ( CFindItemEngine::TFindItemSearchCase ) searchCases );
+ CleanupStack::PushL (itemEngine );
+
+ const CArrayFixFlat<CFindItemEngine::SFoundItem>
+ * foundItems = itemEngine->ItemArray ( );
+
+ // For each found item
+ for (TInt i=0; i<foundItems->Count ( ); ++i )
+ {
+ // iItemType, iStartPos, iLength
+ const CFindItemEngine::SFoundItem& item = foundItems->At (i );
+ HBufC* valueBuf = aText.Mid (item.iStartPos, item.iLength ).AllocL ( );
+ CleanupStack::PushL (valueBuf );
+
+ CESMRRichTextLink::TType type = (CESMRRichTextLink::TType) -1;
+ switch (item.iItemType )
+ {
+ case CFindItemEngine::EFindItemSearchMailAddressBin:
+ {
+ type = CESMRRichTextLink::ETypeEmail;
+ break;
+ }
+ case CFindItemEngine::EFindItemSearchPhoneNumberBin:
+ {
+ type = CESMRRichTextLink::ETypePhoneNumber;
+
+ // patch the symbian level error , 10.120.22.141 this kind of url should not
+ // be recognized to be a phone number.
+ TPtr phonePtr = valueBuf->Des ( );
+ if( phonePtr.Find(_L(".")) == KErrNotFound )
+ {
+ CommonPhoneParser::ParsePhoneNumber (phonePtr,
+ CommonPhoneParser::EContactCardNumber );
+ }
+ else
+ {
+ type = (CESMRRichTextLink::TType) -1 ;
+ }
+ break;
+ }
+ case CFindItemEngine::EFindItemSearchURLBin:
+ {
+ type = CESMRRichTextLink::ETypeURL;
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ if (valueBuf->Length ( )> 0 && type >= 0 )
+ {
+ CESMRRichTextLink* link = CESMRRichTextLink::NewL (item.iStartPos,
+ item.iLength, *valueBuf, type,
+ CESMRRichTextLink::ETriggerKeyRight );
+ CleanupStack::PushL( link );
+ AddLinkL( link );
+ CleanupStack::Pop( link );
+ }
+
+ CleanupStack::PopAndDestroy (valueBuf );
+ }
+
+ // T
+ HandleTextChangedL();
+
+ CleanupStack::PopAndDestroy (itemEngine );
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::CopyCurrentLinkToClipBoardL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CESMRRichTextViewer::CopyCurrentLinkToClipBoardL() const
+ {
+ FUNC_LOG;
+ const CESMRRichTextLink* link = GetSelectedLink();
+ HBufC* clipBoardText = NULL;
+
+ if ( link )
+ {
+ clipBoardText = GetLinkTextLC( *link );
+ }
+
+ if ( 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 );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::ResetActionMenu
+// -----------------------------------------------------------------------------
+EXPORT_C void CESMRRichTextViewer::ResetActionMenuL() const // codescanner::LFunctionCantLeave
+ {
+ FUNC_LOG;
+ if ( iCntMenuHdlr )
+ {
+ iCntMenuHdlr->Reset();
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::SetEventObserver
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CESMRRichTextViewer::SetEventQueue(
+ MESMRFieldEventQueue* aEventQueue )
+ {
+ FUNC_LOG;
+ iEventQueue = aEventQueue;
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::LinkSelectedL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TBool CESMRRichTextViewer::LinkSelectedL()
+ {
+ FUNC_LOG;
+ TBool linkSelected = EFalse;
+
+ const CESMRRichTextLink* link = GetSelectedLink();
+ if ( link )
+ {
+ switch ( link->TriggerKey() )
+ {
+ case CESMRRichTextLink::ETriggerKeyRight:
+ {
+ if ( !iLinkObserver ||
+ !iLinkObserver->HandleRichTextLinkSelection(link) )
+ {
+ ShowContextMenuL();
+ }
+ linkSelected = ETrue;
+ break;
+ }
+ case CESMRRichTextLink::ETriggerKeyOk:
+ {
+ if (iLinkObserver &&
+ iLinkObserver->HandleRichTextLinkSelection( link ) )
+ {
+ linkSelected = ETrue;
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ return linkSelected;
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::ProcessCommandL
+// -----------------------------------------------------------------------------
+//
+void CESMRRichTextViewer::ProcessCommandL( TInt aCommandId )
+ {
+ FUNC_LOG;
+ if ( iEventQueue )
+ {
+ // Forward commands from contact menu handler as command events.
+ // Contact menu handler has the command observer for binary
+ // compatibility reason.
+ CESMRFieldCommandEvent* event =
+ CESMRFieldCommandEvent::NewLC( NULL, aCommandId );
+ iEventQueue->NotifyEventL( *event );
+ CleanupStack::PopAndDestroy( event );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::ActivateL
+// -----------------------------------------------------------------------------
+//
+void CESMRRichTextViewer::ActivateL()
+ {
+ FUNC_LOG;
+ CEikRichTextEditor::ActivateL();
+
+ // CEikEdwin::ActivateL removes selection, re-set highlight
+ // if focused and there's a selected link.
+ const CESMRRichTextLink* link = GetSelectedLink();
+ if ( link && IsFocused() )
+ {
+ HighlightLinkL( *link );
+ DrawDeferred();
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::ContactActionQueryComplete
+// -----------------------------------------------------------------------------
+//
+void CESMRRichTextViewer::ContactActionQueryComplete()
+ {
+ FUNC_LOG;
+ if ( iOpenActionMenu )
+ {
+ // Activate link as actions have been discovered
+ iOpenActionMenu = EFalse;
+ TRAP_IGNORE( LinkSelectedL() );
+ }
+
+ // Reset menu observer
+ iCntMenuHdlr->SetContactMenuObserver( NULL );
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::ShowContextMenuL
+// -----------------------------------------------------------------------------
+//
+void CESMRRichTextViewer::ShowContextMenuL()
+ {
+ FUNC_LOG;
+
+ if ( !iOpenActionMenu )
+ {
+ 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 ) )
+ {
+ TRect linkRect( 0, 0, 0, 0 );
+
+ // Create link surrounding rectangle
+ HBufC* text = GetLinkTextLC( aLink );
+ TInt textWidth = AknBidiTextUtils::MeasureTextBoundsWidth(
+ *iFont,
+ *text,
+ CFont::TMeasureTextInput::EFVisualOrder );
+
+ TPoint tl( posInfo.iEdge );
+ 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 ) )
+ {
+ 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() );
+ }
+ }
+
+ linkRect.SetRect( tl, br );
+ aRegion.AddRect( linkRect );
+
+ CleanupStack::PopAndDestroy( text );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// 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::UpdateViewL( const TKeyEvent &aKeyEvent )
+ {
+ 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 )
+ {
+ 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
+