diff -r 000000000000 -r 8466d47a6819 meetingrequest/mrgui/mrfieldbuildercommon/src/cesmrrichtextviewer.cpp --- /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 +#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); + +}//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 + // codescanner + TRAP_IGNORE(SetSelectionL(CursorPos(), CursorPos())); + if( iLayout ) + { + TRAP_IGNORE(SetFontColorL( EFalse )); + } + // + 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=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 + // + //iCntMenuHdlr->SetCommandObserver( this ); + // + 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 + * foundItems = itemEngine->ItemArray ( ); + + // For each found item + for (TInt i=0; iCount ( ); ++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; iStartPos(); + 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 +