diff -r d189ee25cf9d -r 3533d4323edc meetingrequest/mrgui/mrfieldbuildercommon/src/cesmrrichtextviewer.cpp --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include // for clipboard copy +#include + +// 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=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 + * 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; + + // 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 +