messagingappbase/msgeditor/viewsrc/MsgBodyControlEditor.cpp
changeset 0 72b543305e3a
child 18 fbb813aef148
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingappbase/msgeditor/viewsrc/MsgBodyControlEditor.cpp	Thu Dec 17 08:44:11 2009 +0200
@@ -0,0 +1,710 @@
+/*
+* Copyright (c) 2002 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:  MsgBodyControlEditor implementation
+*
+*/
+
+
+
+// ========== INCLUDE FILES ================================
+
+#include <eikenv.h>                        // for CEikonEnv
+#include <txtrich.h>                       // for CRichText
+#include <baclipb.h>                       // for CClipboard
+#include <AknUtils.h>                      // for AknUtils
+#include <ItemFinder.h>                    // for automatic highlight
+
+#include <applayout.cdl.h> // LAF
+#include <aknlayoutscalable_apps.cdl.h>
+
+#ifdef RD_TACTILE_FEEDBACK
+#include <touchfeedback.h>
+#endif 
+
+#include "MsgEditorCommon.h"               //
+#include "MsgBodyControlEditor.h"          // for CMsgBodyControlEditor
+#include "MsgBaseControl.h"                // for TMsgEditPermissionFlags
+#include "MsgBaseControlObserver.h"        // for MMsgBaseControlObserver
+#include "MsgEditorCustomDraw.h"           // for CMsgEditorCustomDraw
+
+// ========== EXTERNAL DATA STRUCTURES =====================
+
+// ========== EXTERNAL FUNCTION PROTOTYPES =================
+
+// ========== CONSTANTS ====================================
+
+// ========== MACROS =======================================
+
+// ========== LOCAL CONSTANTS AND MACROS ===================
+
+const TInt KBodyFullFormattingLength = 500;
+
+// ========== MODULE DATA STRUCTURES =======================
+
+// ========== LOCAL FUNCTION PROTOTYPES ====================
+
+// ========== LOCAL FUNCTIONS ==============================
+
+// ========== MEMBER FUNCTIONS =============================
+
+// ---------------------------------------------------------
+// CMsgBodyControlEditor::CMsgBodyControlEditor
+//
+// Constructor.
+// ---------------------------------------------------------
+//
+CMsgBodyControlEditor::CMsgBodyControlEditor( const CCoeControl* aParent,
+                                              TUint32& aFlags,
+                                              MMsgBaseControlObserver* aBaseControlObserver ) :
+    CMsgExpandableControlEditor( aParent, aFlags, aBaseControlObserver ),
+    iPreviousItemStart( -1 ),
+    iPreviousItemLength( -1 )
+    {
+    }
+
+// ---------------------------------------------------------
+// CMsgBodyControlEditor::~CMsgBodyControlEditor
+//
+// Destructor.
+// ---------------------------------------------------------
+//
+CMsgBodyControlEditor::~CMsgBodyControlEditor()
+    {
+ 
+    }
+
+// ---------------------------------------------------------
+// CMsgBodyControlEditor::ConstructL
+//
+//
+// ---------------------------------------------------------
+//
+void CMsgBodyControlEditor::ConstructL()
+    {
+    TInt edwinFlags = ENoHorizScrolling | 
+                      ENoAutoSelection | 
+                      EWidthInPixels | 
+                      EAllowUndo | 
+                      EResizable |
+                      EPasteAsPlainText;
+
+    iFlags |= EMsgControlModeDoNotDrawFrameBgContext;
+    ResolveLayouts();
+    
+    /*if ( iBaseControlObserver &&
+         !iBaseControlObserver->ViewInitialized() )
+        {
+        SetSuppressFormatting( ETrue );
+        }*/
+    
+    iItemFinder = CItemFinder::NewL(  CItemFinder::EUrlAddress | 
+                                      CItemFinder::EEmailAddress | 
+                                      CItemFinder::EPhoneNumber | 
+                                      CItemFinder::EUriScheme );
+
+    iItemFinder->AddObserver( *this );
+    iFocusChangedBeforeParseFinish = EFalse;
+
+    CEikRichTextEditor::ConstructL( iParentControl, 0, iMaxNumberOfChars, edwinFlags );
+    // 107-24185 : Emoticon support for SMS and MMS
+    AddFlagToUserFlags(EAvkonEnableSmileySupport);
+    
+    // Both global text editor and edwin have it's own formatting layers.
+    // CEikRichTextEditor::ConstructL call will set global formatting layers
+    // into use for text. This is not correct as edwin formatting layers
+    // will hold correct formatting values. Below calls will set edwin
+    // formatting layers into use and prevent client based formatting from
+    // being based on incorrect formatting layer.
+    SetParaFormatLayer( iEikonEnv->SystemParaFormatLayerL()->CloneL() );
+    SetCharFormatLayer( iEikonEnv->SystemCharFormatLayerL()->CloneL() );
+    
+    SetUpperFullFormattingLength( KBodyFullFormattingLength );
+    
+    SetMaximumHeight( MsgEditorCommons::MaxBodyHeight() );
+    
+    // Set the wrap width to be that of the current body text pane. 
+    // This will make the formatting of text safer if it is performed 
+    // before the editor has ever had SetSize() called. WrapWidth is 
+    // usually set in HandleSizeChanged()
+    if ( iLayout )
+        {
+        iLayout->SetWrapWidth( iTextLayout.TextRect().Width() );
+        }
+    
+    TRect dataPane = MsgEditorCommons::MsgDataPane();
+    
+    TMargins8 edwinMargins;
+    edwinMargins.iTop = 0;
+    edwinMargins.iBottom = 0;
+    edwinMargins.iLeft = (TInt8)( iTextLayout.TextRect().iTl.iX - dataPane.iTl.iX );
+    edwinMargins.iRight = (TInt8)( dataPane.iBr.iX - iTextLayout.TextRect().iBr.iX );
+    SetBorderViewMargins( edwinMargins );
+    }
+
+// ---------------------------------------------------------
+// CMsgBodyControlEditor::SetAndGetSizeL
+//
+// Calculates and sets the size of the control and returns new size as
+// reference aSize.
+// ---------------------------------------------------------
+//
+void CMsgBodyControlEditor::SetAndGetSizeL( TSize& aSize )
+    {
+    // This may change the heigh if the content has changed
+    SetSize( aSize );
+    aSize = iSize;
+    }
+
+// ---------------------------------------------------------
+// CMsgBodyControlEditor::InsertCharacterL
+//
+// Inserts a character to the editor.
+// ---------------------------------------------------------
+//
+void CMsgBodyControlEditor::InsertCharacterL( const TChar& aCharacter )
+    {
+    	
+    // 107-24185 : Emoticon support for SMS and MMS
+    
+    TBuf<1> text;
+    text.Append( aCharacter );
+    InsertTextL( text );
+
+    //UpdateScrollBarsL();
+    }
+
+// ---------------------------------------------------------
+// CMsgBodyControlEditor::InsertTextL
+//
+// Inserts text to the editor.
+// ---------------------------------------------------------
+//
+void CMsgBodyControlEditor::InsertTextL( const TDesC& aText )
+    {
+    if ( iTextView )
+        {
+        TCursorSelection selection = iTextView->Selection();
+        const TInt selLength = selection.Length();
+        const TInt lower = selection.LowerPos();
+
+        if ( selLength )
+            {
+            // 107-24185 : Emoticon support for SMS and MMS, symbian call
+            InsertDeleteCharsL( lower, aText, selection );
+            }
+        else
+            {
+            InsertDeleteCharsL( selection.iCursorPos, aText, selection );
+            }
+
+        SetCursorPosL( lower + aText.Length(), EFalse );
+
+        NotifyNewFormatL();
+        }
+    else
+        {
+        iText->InsertL( 0, aText );
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgBodyControlEditor::ActivateL
+//
+// This function is needed for overriding
+// CMsgExpandableControlEditor::ActivateL().
+// ---------------------------------------------------------
+//
+void CMsgBodyControlEditor::ActivateL()
+    {
+    if ( IsActivated() )
+        {
+        return;
+        }
+        
+    CMsgExpandableControlEditor::ActivateL();      
+    
+    }
+
+
+// ---------------------------------------------------------
+// CMsgBodyControlEditor::OfferKeyEventL
+//
+//
+// ---------------------------------------------------------
+//
+TKeyResponse CMsgBodyControlEditor::OfferKeyEventL(
+    const TKeyEvent& aKeyEvent, TEventCode aType )
+    {
+    if ( IsReadOnly() )
+        {
+        switch ( aKeyEvent.iCode )
+            {
+            case EKeyUpArrow:
+            case EKeyDownArrow:
+                break;
+
+            default:
+                return CEikRichTextEditor::OfferKeyEventL( aKeyEvent, aType );
+            }
+
+        SetHighlightL( CursorPos(), 
+            ( aKeyEvent.iCode == EKeyUpArrow )
+            ? EMsgFocusUp
+            : EMsgFocusDown );
+        return EKeyWasConsumed;
+        }
+    else
+        {
+        return CEikRichTextEditor::OfferKeyEventL( aKeyEvent, aType );
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgBodyControlEditor::HandlePointerEventL
+//
+// Handles pointer events. 
+// ---------------------------------------------------------
+//
+#ifdef RD_SCALABLE_UI_V2
+void CMsgBodyControlEditor::HandlePointerEventL( const TPointerEvent& aPointerEvent )
+    {
+    TBool forwardRequest( ETrue );
+    
+    if ( IsActivated() &&
+         IsReadOnly() && 
+         ( aPointerEvent.iType == TPointerEvent::EButton1Down ||
+           aPointerEvent.iType == TPointerEvent::EButton1Up ) )
+        {
+        TPoint tapPoint( aPointerEvent.iPosition );
+        TInt docPos( TextView()->XyPosToDocPosL( tapPoint ) );
+        
+        TInt start( 0 );
+        TInt length( 0 );
+        MParser* parser = iItemFinder;
+        
+        TBool tappedOverTag( RichText()->CursorOverTag( docPos, parser, start, length ) );
+            
+        if ( aPointerEvent.iType == TPointerEvent::EButton1Down )
+            {
+            iPreviousItemStart = -1;
+            iPreviousItemLength = -1;
+            
+            if ( tappedOverTag )
+                {
+                TPoint relativeTapPoint( aPointerEvent.iPosition - iPosition );
+                if ( iItemFinder->ItemWasTappedL( relativeTapPoint ) )
+                    {                
+                    iPreviousItemStart = start;
+                    iPreviousItemLength = length;
+                    
+                    forwardRequest = EFalse;
+                    }
+                }
+            else
+                {
+                iItemFinder->ResetCurrentItem();
+                }
+            }
+        else if ( aPointerEvent.iType == TPointerEvent::EButton1Up )
+            {
+            if ( tappedOverTag &&
+                 start >= iPreviousItemStart &&
+                 length <= iPreviousItemLength )
+                {
+                TKeyEvent event;
+                event.iCode = EKeyDevice3;
+                event.iScanCode = EStdKeyDevice3;
+                event.iModifiers = 0;
+                event.iRepeats = 0;
+                
+                iCoeEnv->WsSession().SimulateKeyEvent( event );
+                
+                forwardRequest = EFalse;
+                }
+            }
+        }
+
+    if ( forwardRequest )
+        {
+        CMsgExpandableControlEditor::HandlePointerEventL( aPointerEvent );
+        }                
+#ifdef RD_TACTILE_FEEDBACK         
+    else if(aPointerEvent.iType == TPointerEvent::EButton1Down)
+        {                                
+        MTouchFeedback* feedback = MTouchFeedback::Instance();
+        if ( feedback )
+            {
+            feedback->InstantFeedback( this, ETouchFeedbackBasic );
+            }
+        }
+#endif //  RD_TACTILE_FEEDBACK      
+    }
+#else
+void CMsgBodyControlEditor::HandlePointerEventL( const TPointerEvent& /*aPointerEvent*/ )
+    {
+    }
+#endif // RD_SCALABLE_UI_V2
+
+
+// ---------------------------------------------------------
+// CMsgBodyControlEditor::IsFocusChangePossibleL
+//
+//
+// ---------------------------------------------------------
+//
+TBool CMsgBodyControlEditor::IsFocusChangePossibleL(
+    TMsgFocusDirection aDirection )
+    {
+    CItemFinder::TFindDirection direction = aDirection == EMsgFocusUp
+        ? CItemFinder::ENextUp
+        : CItemFinder::ENextDown;
+
+    TInt cursorPos = CursorPos();
+    iItemFinder->ResolveAndSetItemTypeL( cursorPos );
+    TInt nextItem = iItemFinder->PositionOfNextItem( direction );
+    TPoint dummy;
+
+    if ( nextItem < KErrNone )
+        {
+        // Next item not found.
+        if ( aDirection == EMsgFocusUp )
+            {
+            return TextLayout()->FirstDocPosFullyInBand() == 0;
+            }
+        else
+            {
+            return TextLayout()->PosInBand( TextLength(),dummy );
+            }
+        }
+    else
+        {
+        // Next item found. -> Focus change not allowed.
+        return 0;
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgBodyControlEditor::SetupAutomaticFindAfterFocusChangeL
+//
+//
+// ---------------------------------------------------------
+//
+void CMsgBodyControlEditor::SetupAutomaticFindAfterFocusChangeL( TBool aBeginning )
+    {
+    iInitTop = aBeginning;
+    if ( !iTextParsed )
+        {
+        iFocusChangedBeforeParseFinish = ETrue;
+        }
+    else
+        {
+        if ( aBeginning )
+            {
+            SetHighlightL( 0, EMsgFocusDown, ETrue ); 
+            }
+        else
+            {
+            SetHighlightL( TextLength(), EMsgFocusUp, ETrue ); 
+            }
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgBodyControlEditor::SetHighlightL
+//
+//
+// ---------------------------------------------------------
+//
+void CMsgBodyControlEditor::SetHighlightL(
+    TInt aCursorPos, TMsgFocusDirection aDirection,
+    TBool aInit /*= EFalse*/ )
+    {
+    // Use "link highlight"
+    SetHighlightStyleL( EEikEdwinHighlightLink );
+    TInt textLength = TextLength();
+
+    TCursorPosition::TMovementType movetype = aDirection == EMsgFocusUp
+        ? TCursorPosition::EFPageUp
+        : TCursorPosition::EFPageDown;
+
+    CItemFinder::TFindDirection direction = aDirection == EMsgFocusUp
+        ? CItemFinder::ENextUp
+        : CItemFinder::ENextDown;
+
+    TInt nextItem = KErrNotFound;
+    TPoint dummy;
+    if ( iTextParsed )
+        {
+        if ( aInit )
+            {
+            iItemFinder->NextItemOrScrollL( aCursorPos == 0
+                ? CItemFinder::EInitDown
+                : CItemFinder::EInitUp );
+            }
+        else
+            {
+            nextItem = iItemFinder->PositionOfNextItem( direction );
+            }
+        }
+
+    if ( nextItem > KErrNotFound )
+        {
+        if ( !aInit &&
+            !TextLayout()->PosInBand( nextItem ,dummy ) )
+            {
+            // first move one page and then set selection
+            SetCursorPosL( CursorPos(), EFalse );
+            iTextView->MoveCursorL( movetype, EFalse );
+            }
+
+        if ( TextLayout()->PosInBand( nextItem ,dummy ) )
+            {
+            // next item is visible, just change selection
+            iItemFinder->ResolveAndSetItemTypeL( nextItem );
+
+            TInt selectionLength = iItemFinder->CurrentItemExt().iEnd - iItemFinder->CurrentItemExt().iStart + 1;
+            TCursorSelection cursorSelection;
+            cursorSelection.iCursorPos = nextItem;
+            cursorSelection.iAnchorPos = nextItem + selectionLength;
+            if ( !TextLayout()->PosInBand( nextItem + selectionLength, dummy ) )
+                {
+                // Next item does not fit fully on the screen.
+                // Have to move page first.
+                SetCursorPosL( CursorPos(), EFalse );
+                iTextView->MoveCursorL( movetype, EFalse );
+                }
+
+            iTextView->SetSelectionL( cursorSelection );
+            }
+
+        }
+    else
+        {
+        if ( !aInit )
+            {
+            switch ( aDirection )
+                {
+                case EMsgFocusDown:
+                    if ( !TextLayout()->PosInBand( textLength, dummy) )
+                        {
+                        iTextView->MoveCursorL( movetype, EFalse );
+
+                        // Following is a bit tricky since MoveCursor looses
+                        // selection so we have to set it again if previous
+                        // selection still on the screen.
+                        nextItem = iItemFinder->PositionOfNextItem(
+                            CItemFinder::ENextUp );
+                        if ( nextItem > KErrNotFound )
+                            {
+                            if ( TextLayout()->PosInBand( nextItem ,dummy ) )
+                                {
+                                // next item is visible, change selection
+                                iItemFinder->ResolveAndSetItemTypeL( nextItem );
+
+                                TInt selectionLength = iItemFinder->CurrentItemExt().iEnd - iItemFinder->CurrentItemExt().iStart + 1;
+                                TCursorSelection cursorSelection;
+                                cursorSelection.iCursorPos = nextItem;
+                                cursorSelection.iAnchorPos = nextItem + selectionLength;
+                                iTextView->SetSelectionL( cursorSelection );
+                                }
+                            else
+                                {
+                                nextItem = iItemFinder->PositionOfNextItem(
+                                    CItemFinder::ENextDown );
+                                }
+                            }
+                        }
+                    break;
+                default:
+                case EMsgFocusUp:
+                    if ( !TextLayout()->PosInBand( 0,dummy ) )
+                        {
+                        iTextView->MoveCursorL( movetype, EFalse );
+                        }
+                    break;
+                };
+
+            }
+        }
+
+    }
+
+
+// ---------------------------------------------------------
+// CMsgBodyControlEditor::CursorInLastLine
+//
+//
+// ---------------------------------------------------------
+//
+TBool CMsgBodyControlEditor::CursorInLastLine()
+    {
+    if (IsReadOnly())
+        {
+        TPoint dummy;
+        return ( iItemFinder->PositionOfNextItem( CItemFinder::ENextDown ) == KErrNotFound  
+            && TextLayout()->PosInBand( TextLength(), dummy ) );
+
+        }
+    else
+        {
+        return CMsgExpandableControlEditor::CursorInLastLine();
+        }
+
+    }
+
+// ---------------------------------------------------------
+// CMsgBodyControlEditor::HandleParsingComplete
+// ---------------------------------------------------------
+//
+void CMsgBodyControlEditor::HandleParsingComplete()
+    {
+    TRAP_IGNORE( DoHandleParsingCompleteL() );
+    }
+
+// ---------------------------------------------------------
+// CMsgBodyControlEditor::DoHandleParsingCompleteL
+// ---------------------------------------------------------
+//
+void CMsgBodyControlEditor::DoHandleParsingCompleteL()
+    {
+    iTextParsed = ETrue;
+    // this needs to be changed so that bottom init can also be set
+    if ( iFocusChangedBeforeParseFinish )
+        {
+        iFocusChangedBeforeParseFinish = EFalse; // just to make sure this is done only once
+        if ( iInitTop )
+            {
+            SetHighlightL( 0, EMsgFocusDown, ETrue ); 
+            }
+        else
+            {
+            SetHighlightL( TextLength(), EMsgFocusUp, ETrue ); 
+            }
+        
+        if ( iBaseControlObserver )
+            {
+            iBaseControlObserver->HandleBaseControlEventRequestL( NULL, 
+                                                                  EMsgUpdateScrollbar );
+            }
+        }
+    else
+        {
+        // In some cases the text view is left to some
+        // strange state. Make sure the view is in sync
+        // with cursor position.
+        SetCursorPosL( CursorPos(), EFalse );
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgBodyControlEditor::ResolveLayouts
+//
+//
+// ---------------------------------------------------------
+//
+void CMsgBodyControlEditor::ResolveLayouts()
+    {
+    TRect dataPane = MsgEditorCommons::MsgDataPane();
+    
+    TAknLayoutRect msgTextPane;
+    msgTextPane.LayoutRect(
+        dataPane,
+        AknLayoutScalable_Apps::msg_text_pane( 0 ).LayoutLine() );
+    TAknLayoutRect msgBodyPane;
+    msgBodyPane.LayoutRect(
+            msgTextPane.Rect(),
+            AknLayoutScalable_Apps::msg_body_pane().LayoutLine() );
+
+    if ( IsReadOnly() )
+        {
+        iTextLayout.LayoutText(
+            msgBodyPane.Rect(),
+            AknLayoutScalable_Apps::msg_body_pane_t1( 0 ).LayoutLine() );
+        }
+    else
+        {
+        iTextLayout.LayoutText(
+            msgBodyPane.Rect(),
+            AknLayoutScalable_Apps::msg_body_pane_t1( 1 ).LayoutLine() );            
+        }
+
+    
+    if ( MsgEditorCustomDraw() )
+        {
+        MsgEditorCustomDraw()->ResolveLayouts();
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgBodyControlEditor::LayoutEdwin
+// ---------------------------------------------------------
+//
+void CMsgBodyControlEditor::LayoutEdwin()
+    {
+    TAknLayoutRect msgTextPane;
+    msgTextPane.LayoutRect( MsgEditorCommons::MsgDataPane(),
+                            AknLayoutScalable_Apps::msg_text_pane( 0 ).LayoutLine() );
+                            
+    TAknLayoutRect msgBodyPane;
+    msgBodyPane.LayoutRect( msgTextPane.Rect(),
+                            AknLayoutScalable_Apps::msg_body_pane().LayoutLine() );
+    
+    TRect parentRect( msgBodyPane.Rect() );
+    parentRect.Move( 0, iParentControl->Position().iY );
+    
+    DoLayoutEdwin( parentRect, 
+                   AknLayoutScalable_Apps::msg_body_pane_t1( 0 ).LayoutLine() );
+    }
+
+// ---------------------------------------------------------
+// CMsgBodyControlEditor::PrepareFocusTransition
+//
+// Do not change focus when automatic find parsing has been finished
+// if focus transition out of this control has been performed.
+// ---------------------------------------------------------
+//
+void CMsgBodyControlEditor::PrepareFocusTransition()
+    {
+    if ( IsFocused() )
+        {
+        iFocusChangedBeforeParseFinish = EFalse;
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgBodyControlEditor::SetTextSkinColorIdL
+// ---------------------------------------------------------
+//
+void CMsgBodyControlEditor::SetTextSkinColorIdL()
+    {
+    CEikEdwin::SetTextSkinColorIdL( EAknsCIQsnTextColorsCG6 );
+    }
+
+// ---------------------------------------------------------
+// CMsgBodyControlEditor::HandleResourceChange
+//
+// Sets correct highlight extension.
+// ---------------------------------------------------------
+//
+void CMsgBodyControlEditor::HandleResourceChange( TInt aType )
+    {
+    CMsgExpandableControlEditor::HandleResourceChange( aType );
+    
+    if ( aType == KAknsMessageSkinChange &&  MsgEditorCustomDraw() )
+        {
+         MsgEditorCustomDraw()->SkinChanged();;    
+    	}
+    }
+
+//  End of File