--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/meetingrequest/mrgui/mrfieldbuildercommon/src/cesmrrichtextviewer.cpp Thu Dec 17 08:39:21 2009 +0200
@@ -0,0 +1,1254 @@
+/*
+* Copyright (c) 2003-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
+*
+*/
+
+#include "cesmrrichtextviewer.h"
+
+#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 <esmrgui.rsg>
+#include <commonphoneparser.h>
+#include <finditemengine.h>
+#include <txtrich.h>
+#include <AknsUtils.h>
+#include <eikenv.h>
+#include <data_caging_path_literals.hrh>
+#include <baclipb.h> // for clipboard copy
+#include <aknlongtapdetector.h>
+#include <touchfeedback.h>
+
+#ifndef FF_CMAIL_INTEGRATION
+#include <txtclipboard.h>
+#endif // FF_CMAIL_INTEGRATION
+
+// DEBUG
+#include "emailtrace.h"
+
+// <cmail> Removed profiling. </cmail>
+
+// Unnamed namespace for local definitions
+namespace{ // codescanner::namespace
+
+const TInt KArrowUpperMargin (2);
+const TInt KArrowRightMargin (5);
+
+}//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 ( );
+ delete iActionMenuIcon;
+ delete iActionMenuIconMask;
+ iESMRStatic.Close ( );
+ delete iLongTapDetector;
+ }
+
+// -----------------------------------------------------------------------------
+// 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;
+ }
+
+ if ( IsFocused() )
+ {
+ if( iLayout )
+ {
+ TRAP_IGNORE( SetFontColorL( ETrue ) );
+ }
+
+ if ( iCurrentLinkIndex == KErrNotFound )
+ {
+ 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 ( );
+ }
+ }
+ }
+ else
+ {
+ const CESMRRichTextLink* link = GetSelectedLink ( );
+ HighlightLink( *link );
+ DrawDeferred();
+ }
+ }
+
+ if (!IsFocused())
+ {
+ // losing focus
+ // <cmail> codescanner
+ TRAP_IGNORE(SetSelectionL(CursorPos(), CursorPos()));
+ if( iLayout )
+ {
+ TRAP_IGNORE(SetFontColorL( EFalse ));
+ }
+ // </cmail>
+ TRAP_IGNORE( TextView()->SetDocPosL( 0 ));
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// 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;
+ }
+ }
+
+ iCurrentLinkIndex = KErrNotFound;
+ return linkRow;
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::ValidLinkForFocusing
+// -----------------------------------------------------------------------------
+//
+TInt CESMRRichTextViewer::ValidLinkForFocusing(
+ TInt aIndex,
+ TCursorPosition::TMovementType aDirection,
+ TInt aStartRow,
+ TInt aEndRow )
+ {
+ FUNC_LOG;
+
+
+ if(iLinkList.Count() > aIndex)
+ {
+ TInt pos = iLinkList[aIndex]->StartPos();
+
+ TInt checkRow = TextLayout()->GetLineNumber( pos );
+
+ if ( checkRow >= aStartRow && checkRow <= ( aEndRow ) )
+ {
+ if ( aDirection == TCursorPosition::EFLineDown &&
+ aIndex > iCurrentLinkIndex ||
+ aDirection == TCursorPosition::EFLineUp &&
+ ( aIndex < iCurrentLinkIndex ||
+ iCurrentLinkIndex == KErrNotFound ))
+ {
+ iCurrentLinkIndex = aIndex;
+
+ // link found between next scroll area.
+ return checkRow;
+ }
+ }
+ }
+ return KErrNotFound;
+ }
+
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TKeyResponse CESMRRichTextViewer::OfferKeyEventL(
+ const TKeyEvent &aKeyEvent,
+ TEventCode aType )
+ {
+ FUNC_LOG;
+ // Handle only event keys
+ if ( aType == EEventKey )
+ {
+ if ( iObserver ) // only description field has observer set.
+ {
+ // fetch the current line number:
+ TInt currentLineNumber = TextLayout()->GetLineNumber( CursorPos() );
+
+ if ( aKeyEvent.iCode == EKeyDownArrow && aType == EEventKey )
+ {
+ if ( !iObserver->IsFieldBottomVisible() &&
+ SetHighLightToNextLinkL(
+ TCursorPosition::EFLineDown,
+ currentLineNumber,
+ currentLineNumber + KMaxAddressFieldLines) )
+ {
+ return EKeyWasConsumed;
+ }
+ else if ( iObserver->IsFieldBottomVisible() )
+ {
+ if ( SetHighLightToNextLinkL(TCursorPosition::EFLineDown,
+ currentLineNumber,
+ iNumberOfLines) )
+ {
+ return EKeyWasConsumed;
+ }
+ // means that the whole control is visible:
+ // and we can skip to next field
+ return EKeyWasNotConsumed;
+ }
+
+ 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 );
+ }
+
+ return EKeyWasConsumed;
+ }
+ else if ( aKeyEvent.iCode == EKeyUpArrow && aType == EEventKey )
+ {
+ if (iPosition.iY < 0 &&
+ SetHighLightToNextLinkL(
+ TCursorPosition::EFLineUp,
+ currentLineNumber - KMaxAddressFieldLines,
+ currentLineNumber))
+ {
+ return EKeyWasConsumed;
+ }
+ if ( iPosition.iY > 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 );
+ }
+
+ currentLineNumber =
+ TextLayout()->GetLineNumber( CursorPos() );
+ return EKeyWasConsumed;
+ }
+ }
+ }
+ 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;
+ }
+ }
+ if ( aKeyEvent.iCode == EKeyLeftArrow )
+ {
+ const CESMRRichTextLink* link = GetSelectedLink();
+ if ( link )
+ {
+ return EKeyWasConsumed;
+ }
+ }
+ 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;
+ }
+ }
+ }
+ }
+
+ return EKeyWasNotConsumed;
+ }
+
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::ScrollViewL
+// -----------------------------------------------------------------------------
+//
+void CESMRRichTextViewer::ScrollViewL(
+ TInt aNumberOfRows,
+ TCursorPosition::TMovementType aDirection)
+ {
+ FUNC_LOG;
+ for( TInt i=0; i < aNumberOfRows; i++ )
+ {
+ MoveCursorL( aDirection, EFalse);
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::SetMargins
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CESMRRichTextViewer::SetMargins( TInt sMargin )
+ {
+ // Set new value for left and right margins
+ if ( TextView() )
+ {
+ 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
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CESMRRichTextViewer::SetTextL(
+ const TDesC* aText,
+ TBool aSearchLinks )
+ {
+ FUNC_LOG;
+ iCurrentLinkIndex = KErrNotFound;
+ iLinkList.ResetAndDestroy ( );
+
+ // Clear edwin text
+ CEikEdwin::SetCursorPosL( 0, EFalse );
+
+ // text lenght plus one to ensure the formatting
+ // used is full, not band formatting.
+ SetUpperFullFormattingLength( aText->Length() + 1 );
+
+ // Set new edwin text
+ 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);
+ }
+
+ // first row is 0, so let's add one...
+ iNumberOfLines = TextLayout()->GetLineNumber( TextLength() ) + 1;
+ }
+
+// -----------------------------------------------------------------------------
+// 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( iFormat,
+ iFormatMask,
+ aLink->StartPos(),
+ aLink->Length() );
+
+ // Append aLink to link list. Space has been reserved, so this cannot fail.
+ iLinkList.AppendL( aLink );
+
+ if ( highlight )
+ {
+ HighlightLink( *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( iFormat,
+ iFormatMask,
+ 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 )
+ {
+ HighlightLink( *aLink );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::GetSelectedLink
+// -----------------------------------------------------------------------------
+//
+EXPORT_C const CESMRRichTextLink* CESMRRichTextViewer::GetSelectedLink( ) const
+ {
+ FUNC_LOG;
+ if (iCurrentLinkIndex >= 0 && iCurrentLinkIndex < iLinkList.Count ( ) )
+ {
+ return iLinkList[iCurrentLinkIndex];
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::GetLinkTextL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C HBufC* CESMRRichTextViewer::GetLinkTextL(
+ const CESMRRichTextLink& aLink ) const
+ {
+ FUNC_LOG;
+ return RichText()->Read( aLink.StartPos ( ), aLink.Length ( ) ).AllocL();
+ }
+
+// -----------------------------------------------------------------------------
+// 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;
+ return iNumberOfLines;
+ }
+// -----------------------------------------------------------------------------
+// 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::CESMRRichTextViewer
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CESMRRichTextViewer::SetActionMenuStatus( TBool aStatus )
+ {
+ FUNC_LOG;
+ iActionMenuStatus = aStatus;
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::CESMRRichTextViewer
+// -----------------------------------------------------------------------------
+//
+CESMRRichTextViewer::CESMRRichTextViewer( )
+: iActionMenuStatus( ETrue ), iActionMenuOpen( EFalse )
+ {
+ 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 );
+
+ 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;
+
+ 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));
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::DrawRightClickIconL
+// -----------------------------------------------------------------------------
+//
+void CESMRRichTextViewer::DrawRightClickIconL(
+ const CESMRRichTextLink& aLink ) const
+ {
+ 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 ) );
+ }
+ else
+ {
+ TextView()->SetPendingSelection( selection );
+ }
+
+ if ( error == KErrNone )
+ {
+ TRAP( error, SetValueL( aLink ) );
+ if ( error != KErrNone )
+ {
+ CEikonEnv::Static()->// codescanner::eikonenvstatic
+ HandleError( error );
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// 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:
+ {
+ // Set this as command observer.
+ // Commands from contact menu handler are
+ // processed in ProcessCommandL and forwarded
+ // as field command events
+ // <cmail>
+ //iCntMenuHdlr->SetCommandObserver( this );
+ // </cmail>
+ iCntMenuHdlr->SetValueL( aLink.Value(),
+ CESMRContactMenuHandler::EValueTypeAttachment );
+ 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;
+
+ // Remove unsupported characters from phone number
+ TPtr phonePtr = valueBuf->Des ( );
+ CommonPhoneParser::ParsePhoneNumber (phonePtr,
+ CommonPhoneParser::EContactCardNumber );
+ 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();
+
+ if( link )
+ {
+ HBufC* clipBoardText = GetLinkTextL(*link);
+
+ 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 );
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::CopyCurrentLinkValueToClipBoardL
+// -----------------------------------------------------------------------------
+EXPORT_C void CESMRRichTextViewer::CopyCurrentLinkValueToClipBoardL() const
+ {
+ FUNC_LOG;
+ const CESMRRichTextLink* link = GetSelectedLink();
+
+ if( link )
+ {
+ TDesC& clipBoardText = link->Value();
+
+ 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 );
+ }
+ }
+
+
+// -----------------------------------------------------------------------------
+// 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 )
+ {
+ iActionMenuOpen = ETrue;
+ switch ( link->TriggerKey() )
+ {
+ case CESMRRichTextLink::ETriggerKeyRight:
+ {
+ if ( !iLinkObserver ||
+ !iLinkObserver->HandleRichTextLinkSelection(link) )
+ {
+ iCntMenuHdlr->ShowActionMenuL();
+ }
+ linkSelected = ETrue;
+ break;
+ }
+ case CESMRRichTextLink::ETriggerKeyOk:
+ {
+ if (iLinkObserver &&
+ iLinkObserver->HandleRichTextLinkSelection (link ) )
+ {
+ linkSelected = ETrue;
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ iActionMenuOpen = EFalse;
+ }
+
+ 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();
+
+ // 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() )
+ {
+ HighlightLink( *GetSelectedLink() );
+ DrawDeferred();
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::HandlePointerEventL
+// -----------------------------------------------------------------------------
+//
+void CESMRRichTextViewer::HandlePointerEventL(const TPointerEvent& aPointerEvent)
+ {
+ 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; i<iLinkList.Count(); i++)
+ {
+ link = iLinkList[ i ];
+ TInt linkStart = link->StartPos();
+ TInt linkEnd = link->StartPos() + link->Length() - 1;
+ if ( tappedPos >= linkStart && tappedPos <= linkEnd )
+ {
+ // link tapped
+ linkTapped = ETrue;
+ iCurrentLinkIndex = i;
+ break;
+ }
+ }
+
+ if ( aPointerEvent.iType == TPointerEvent::EButton1Down )
+ {
+ if ( linkTapped )
+ {
+ // tactile feedback
+ MTouchFeedback* feedback = MTouchFeedback::Instance();
+ if ( feedback )
+ {
+ feedback->InstantFeedback( this, ETouchFeedbackBasic );
+ }
+
+ TPointerEvent pointerEvent = aPointerEvent;
+ pointerEvent.iParentPosition = pointerEvent.iPosition
+ + DrawableWindow()->AbsPosition();
+ iLongTapDetector->PointerEventL( pointerEvent );
+ HighlightLink( *link );
+ if ( Parent() )
+ {
+ Parent()->DrawDeferred();
+ }
+ else
+ {
+ DrawDeferred();
+ }
+ }
+ }
+ 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();
+ }
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CESMRRichTextViewer::HandleLongTapEventL
+// -----------------------------------------------------------------------------
+//
+void CESMRRichTextViewer::HandleLongTapEventL( const TPoint& /*aPenEventLocation*/,
+ const TPoint& /*aPenEventScreenLocation*/ )
+ {
+ if ( !iActionMenuOpen )
+ {
+ LinkSelectedL();
+ }
+ }
+// EOF
+