messagingappbase/smartmessaging/richbio/src/CRichBio.cpp
changeset 0 72b543305e3a
child 15 52d61119153d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingappbase/smartmessaging/richbio/src/CRichBio.cpp	Thu Dec 17 08:44:11 2009 +0200
@@ -0,0 +1,631 @@
+/*
+* 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:  
+*     This is a wrapper class for rich text editor.
+*
+*/
+
+
+
+// INCLUDES
+
+#include "CRichBio.h"                       // Own header
+#include <txtrich.h>                        // CRichText
+#include <calslbs.h>                        // Fonts
+#include <MsgExpandableControlEditor.h>     // CMsgExpandableControlEditor
+#include <MsgEditorCommon.h>                // MaxBodyHeight
+#include <AknLayoutDef.h>       // TAknLayoutId
+#include <AknUtils.h>
+
+#include    <applayout.cdl.h> // LAF
+#include    <aknlayoutscalable_apps.cdl.h>
+
+/// panic codes
+enum TRichBioPanicCodes
+    {
+    EPanicCacheProblem1 = 100,
+    EPanicCacheProblem2,
+    EPanicCacheMismatch1,
+    EPanicCacheMismatch2,
+    EPanicCacheMismatch3,
+    EPanicEditorIsNull1,
+    EPanicEditorIsNull2,
+    EPanicNoCache,
+    EPanicConstructedTwice,
+    EPanicNoParent
+    };
+
+// LOCAL CONSTANTS
+
+// Define the margins used in editor here.
+const TInt KMarginTop = 0;
+const TInt KMarginBottom = 0;
+const TInt KMarginLeft = 3;
+const TInt KMarginRight = 1;
+
+// CLASS DECLARATION
+
+/**
+* CRichbio inner class, which implements the observer
+* interface.
+*/
+class CRichBio::CEdwinSizeObserver : public CBase,
+    public MEikEdwinSizeObserver
+    {
+    public: // from MEikEdwinSizeObserver
+
+        /**
+        * Constructor.
+        * @param Reference to the richbio object.
+        */
+        CEdwinSizeObserver( CRichBio& aRichBio );
+
+        /**
+         * Destructor.
+         */
+        ~CEdwinSizeObserver() {};
+
+        /**
+         * Handles edwin size event. Sets new size for this control and
+         * reports the observer if the control editor's size is about to
+         * change. Returns ETrue if size change is allowed.
+         * @param aEdwin Edwin control.
+         * @param aEventType Type of the event.
+         * @param aDesirableEdwinSize control's desired size.
+         * @return Boolean
+         */
+        TBool HandleEdwinSizeEventL(CEikEdwin* aEdwin,
+            TEdwinSizeEvent aEventType,
+            TSize aDesirableEdwinSize);
+    private:
+        /// Reference to the richbio control.
+        CRichBio& iRichBio;
+    };
+
+CRichBio::CEdwinSizeObserver::CEdwinSizeObserver( CRichBio& aRichBio ) :
+    iRichBio( aRichBio )
+    {
+    }
+
+// ---------------------------------------------------------
+// CEdwinSizeObserver::HandleEdwinSizeEventL
+//
+// Handles edwin size event. Sets new size for this control and reports the
+// observer if the control editor's size is about to change. Returns ETrue
+// if size change is allowed.
+// ---------------------------------------------------------
+//
+TBool CRichBio::CEdwinSizeObserver::HandleEdwinSizeEventL(
+    CEikEdwin* /*aEdwin*/,
+    TEdwinSizeEvent aEventType,
+    TSize aDesirableEdwinSize)
+    {
+    if (aEventType == EEventSizeChanging)
+        {
+        TSize thisSize(iRichBio.Size());
+        aDesirableEdwinSize.iHeight = MsgEditorCommons::MaxBodyHeight();
+
+        TInt delta( aDesirableEdwinSize.iHeight - iRichBio.iEditor->Size().iHeight );
+
+        if (delta)
+            {
+            thisSize.iHeight = aDesirableEdwinSize.iHeight;
+            iRichBio.SetSizeWithoutNotification(thisSize);
+            iRichBio.iEditor->SetSize(aDesirableEdwinSize);
+            }
+        return ETrue;
+
+        }
+    return EFalse;
+    }
+
+EXPORT_C CRichBio* CRichBio::NewL(const CCoeControl* aParent,
+    TRichBioMode aMode)
+    {
+    CRichBio* self = new (ELeave) CRichBio( aMode );
+    CleanupStack::PushL( self );
+    self->ConstructL( aParent );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+CRichBio::~CRichBio()
+    {
+    delete iEdwinSizeObserver;
+    delete iEditor;
+    delete iLabelCache;
+    delete iValueCache;
+    }
+
+EXPORT_C void CRichBio::AddItemL(const TDesC& aLabel, const TDesC& aValue)
+    {
+    if (iEditor)
+        {
+        AddItemToRichTextL(aLabel, aValue);
+        }
+    // Items needs to be always cached, because of possible layout changes.
+    CacheItemL(aLabel, aValue);
+    }
+
+EXPORT_C TRect CRichBio::CurrentLineRect()
+    {
+    TRect lineRect(0,0,0,0);
+	// if fails return 0x0 rect
+    // this method is part of public SDK and this cannot be changed to leaveable.
+    TRAP_IGNORE((lineRect = iEditor->CurrentLineRectL()));
+    return lineRect;
+    }
+
+EXPORT_C CEikRichTextEditor& CRichBio::Editor()
+    {
+    __ASSERT_ALWAYS(iEditor, Panic(EPanicEditorIsNull1));
+    return *iEditor;
+    }
+
+EXPORT_C TBool CRichBio::IsEditorBaseMode() const
+    {
+    return (ERichBioModeEditorBase == iMode);
+    }
+
+EXPORT_C void CRichBio::Reset()
+    {
+    iEditor->Reset();
+    iIsFirstItem = ETrue;
+    TRAP_IGNORE(LoadFromCacheL());
+    }
+
+void CRichBio::AddItemToRichTextL(const TDesC& aLabel, const TDesC& aValue)
+    {
+    TCharFormat format;
+    TCharFormatMask mask;
+
+    if ( aLabel.Length() > 0 )
+        {
+        ApplyLabelFormat( format, mask );
+        AppendTextL( aLabel , format, mask );
+        }
+
+    if ( aValue.Length() > 0 )
+        {
+        ApplyValueFormat( format, mask );
+        AppendTextL( aValue , format, mask );
+        }
+    }
+
+void CRichBio::AppendTextL( const TDesC& aText,
+    const TCharFormat& aFormat,
+    const TCharFormatMask& aMask )
+    {
+    // Create the modifiable descriptor
+    HBufC* buf = HBufC::NewLC( aText.Length() );
+    TPtr modifiedText = buf->Des();
+    modifiedText = aText;
+
+	// This is for example for arabic numbers
+	AknTextUtils::DisplayTextLanguageSpecificNumberConversion( modifiedText );
+    TInt pos(0);
+
+    /*
+    We have four cases, where specific character(s) must be
+    converted to the CRichText understandable linebreak character
+    (CEditableText::ELineBreak).
+    1)  Text contains ascii code linefeed (LF) character 0x0A, which
+        is converted to linebreak.
+    2)  Text contains ascii code carrier return (CR) character 0x0D
+    3)  Text contains both LF and CR characters particularly in this order.
+        These two characters must be converted to one linebreak.
+    */
+
+    TUint LF(0x0A); // Linefeed character in ascii set
+    TUint CR(0x0D); // Carriage return character in ascii set
+
+
+	//this implementation won't handle mixed set of CRLF / LFCR / LF / CR 
+	//linefeeds "quite" properly but that situation is not very likely
+	
+    // Case 1 and 3
+    while ( ( pos = modifiedText.Locate( LF ) ) != KErrNotFound ) // Locate LF
+        {
+        if ( pos + 1 < modifiedText.Length() && CR == modifiedText[pos + 1] ) // Is the next CR?
+            {
+            modifiedText.Delete( pos + 1, 1 ); // Delete if CR
+            }
+        modifiedText[pos] = CEditableText::ELineBreak; // Replace LF with linebreak
+        
+        //as added measure we will check the previous character 
+        if ( (pos-1) >= 0 && CR == modifiedText[pos - 1]  ) // Is the previous CR?
+            {
+            modifiedText.Delete( pos -1 , 1 ); // Delete if CR
+            }
+        }
+
+    // Case 2
+    while ( ( pos = modifiedText.Locate( CR ) ) != KErrNotFound ) // Locate CR
+        {
+		if ( pos + 1 < modifiedText.Length() && LF == modifiedText[pos + 1]  ) // Is the next LF?
+            {
+            modifiedText.Delete( pos + 1, 1 ); // Delete if LF
+            }
+        modifiedText[pos] = CEditableText::ELineBreak; // Replace CR with linebreak
+        
+        //as added measure we will check the previous character 
+        if ( (pos-1) >= 0 && LF == modifiedText[pos - 1 ] ) // Is the previous LF?
+            {
+            modifiedText.Delete( pos -1, 1 ); // Delete if LF
+            }
+        }
+
+    // Append the modified text to the richtext.
+    CRichText* rich = iEditor->RichText();
+    User::LeaveIfNull( rich );
+
+    TInt documentPos = rich->DocumentLength();
+
+    // Every time when text is added, the cursor is left at the end of the line.
+    // When the new text is added we must first add linebreak and then the text
+    // linebreak is not added if the text is first item.
+    if ( !iIsFirstItem )
+        {
+        // Append the linebreak to the end of the richtext.
+        rich->InsertL(documentPos, CEditableText::ELineBreak);
+        }
+    else
+        {
+        iIsFirstItem = EFalse;
+        }
+
+    documentPos = rich->DocumentLength();
+    rich->SetInsertCharFormatL(aFormat, aMask, documentPos);
+    rich->InsertL( documentPos, modifiedText );
+
+    rich->CancelInsertCharFormat();
+
+    CleanupStack::PopAndDestroy( buf );
+    }
+
+TKeyResponse CRichBio::OfferKeyEventL(
+    const TKeyEvent& aKeyEvent,TEventCode aType)
+    {
+    return iEditor->OfferKeyEventL(aKeyEvent, aType);
+    }
+
+EXPORT_C void CRichBio::SetAndGetSizeL(TSize& aSize)
+    {
+    TInt maxHeight( MsgEditorCommons::MaxBodyHeight() );
+    iEditor->SetMaximumHeight( maxHeight );
+    
+    iEditor->SetAndGetSizeL( aSize );
+    
+
+    if ( aSize.iHeight > maxHeight )
+        {
+        aSize.iHeight = maxHeight;
+        }
+    SetSizeWithoutNotification( aSize );
+    }
+
+EXPORT_C TInt CRichBio::VirtualHeight()
+    {
+    return iEditor->VirtualHeight();
+    }
+
+EXPORT_C TInt CRichBio::VirtualVisibleTop()
+    {
+    return iEditor->VirtualVisibleTop();
+    }
+
+EXPORT_C TBool CRichBio::IsCursorLocation(TMsgCursorLocation aLocation) const
+    {
+    TBool location(EFalse);
+    switch (aLocation)
+        {
+        case EMsgTop:
+            location = iEditor->CursorInFirstLine();
+            break;
+        case EMsgBottom:
+            location = iEditor->CursorInLastLine();
+            break;
+        default:
+            break;
+        }
+
+    return location;
+    }
+
+void CRichBio::ApplyLabelFormat(TCharFormat& aFormat, TCharFormatMask& aMask)
+    {
+    ApplyFormat(aFormat, aMask, ETrue);
+    }
+
+void CRichBio::ApplyValueFormat(TCharFormat& aFormat, TCharFormatMask& aMask)
+    {
+    ApplyFormat(aFormat, aMask, EFalse);
+    }
+
+void CRichBio::ApplyFormat(TCharFormat& aFormat, TCharFormatMask& aMask, TBool aIsLabel)
+    {
+	if ( aIsLabel )
+		{
+		TAknTextComponentLayout msg_body_pane_t2 =
+			AknLayoutScalable_Apps::msg_body_pane_t2( 0 );
+		TAknTextLineLayout textLayout = msg_body_pane_t2.LayoutLine();//AppLayout::Smart_Messages_Line_1( 0 );
+	    const CFont* labelFont = AknLayoutUtils::FontFromId( textLayout.FontId() );
+		aFormat.iFontSpec = labelFont->FontSpecInTwips();
+		}
+	else
+		{
+		TAknTextComponentLayout msg_body_pane_t3 =
+			AknLayoutScalable_Apps::msg_body_pane_t3( 0 );
+		TAknTextLineLayout editorLayout = msg_body_pane_t3.LayoutLine(); //AppLayout::Smart_Messages_Line_2( 0 );
+		const CFont* editorFont = AknLayoutUtils::FontFromId( editorLayout.FontId() );
+		aFormat.iFontSpec = editorFont->FontSpecInTwips();
+		}
+
+    aMask.ClearAll();
+    aMask.SetAttrib(EAttFontStrokeWeight);
+    aMask.SetAttrib(EAttFontHeight);
+    aMask.SetAttrib(EAttFontTypeface);
+    }
+
+EXPORT_C CRichBio::CRichBio(TRichBioMode aMode) : iMode(aMode)
+    {
+    }
+
+EXPORT_C void CRichBio::ConstructL(const CCoeControl* aParent)
+    {
+    __ASSERT_DEBUG(!iEditor, Panic( EPanicConstructedTwice ));
+    TUint32 flags = 0;
+    iEditor = new (ELeave) CMsgExpandableControlEditor( aParent, flags, NULL);
+    iEditor->ConstructL();
+
+    TAknLayoutText headerTextLayout;
+    TMargins8 edwinMargins;
+    if ( AknLayoutUtils::ScalableLayoutInterfaceAvailable() )
+        {
+        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() );
+        headerTextLayout.LayoutText(
+            msgBodyPane.Rect(),
+            AknLayoutScalable_Apps::msg_body_pane_t2( 0 ).LayoutLine() );
+
+	    edwinMargins.iTop    = KMarginTop;
+	    edwinMargins.iBottom = KMarginBottom;
+	    edwinMargins.iLeft   = headerTextLayout.TextRect().iTl.iX; //KMarginLeft;
+	    edwinMargins.iRight  =
+	    	msgTextPane.Rect().iBr.iX -
+	    	headerTextLayout.TextRect().iBr.iX;// KMarginRight;
+        }
+	else
+		{
+		// use old margins
+		edwinMargins.iTop    = KMarginTop;
+		edwinMargins.iBottom = KMarginBottom;
+		edwinMargins.iLeft   = KMarginLeft;
+		edwinMargins.iRight  = KMarginRight;
+		}
+    iEditor->SetBorderViewMargins(edwinMargins);
+
+    // Create the observer.
+    iEdwinSizeObserver = new (ELeave) CEdwinSizeObserver( *this );
+    iEditor->SetEdwinSizeObserver( iEdwinSizeObserver );
+    iIsFirstItem = ETrue;
+    iEditor->SetReadOnly(ETrue);
+    if (CacheExists())
+        {
+        LoadFromCacheL();
+        }
+    SetContainerWindowL(*aParent);
+    }
+
+TInt CRichBio::CountComponentControls() const
+    {
+    return 1; // iEditor ( created in constructL, so always 1 )
+    }
+
+CCoeControl* CRichBio::ComponentControl(TInt aIndex) const
+    {
+    if (aIndex == 0)
+        {
+        return iEditor;
+        }
+    return NULL;
+    }
+
+void CRichBio::SizeChanged()
+    {
+    iEditor->SetExtent(Position(), iEditor->Size());
+    }
+
+void CRichBio::Panic( TInt aPanic )
+    {
+    _LIT(KDll, "richbio.dll");
+    User::Panic(KDll, aPanic);
+    }
+
+TBool CRichBio::CacheExists()
+    {
+    if (iLabelCache)
+        {
+        __ASSERT_DEBUG(iValueCache, Panic(EPanicCacheProblem1));
+        return ETrue;
+        }
+    __ASSERT_DEBUG(!iValueCache, Panic(EPanicCacheProblem2));
+    return EFalse;
+    }
+
+void CRichBio::LoadFromCacheL()
+    {
+    __ASSERT_DEBUG(iLabelCache && iValueCache, Panic(EPanicNoCache));
+
+    TInt count(iLabelCache->Count());
+    __ASSERT_DEBUG(iValueCache->Count() == count,
+        Panic(EPanicCacheMismatch1));
+    for (TInt n(0); n < count; n++)
+        {
+        AddItemToRichTextL((*iLabelCache)[n], (*iValueCache)[n]);
+        }
+    }
+
+void CRichBio::CacheItemL(const TDesC& aLabel, const TDesC& aValue)
+    {
+    if (!iLabelCache || !iValueCache)
+        {
+        delete iLabelCache;
+        delete iValueCache;
+        iLabelCache = NULL;
+        iValueCache = NULL;
+        iLabelCache = new (ELeave) CDesC16ArrayFlat(10); //granularity of 10
+        iValueCache = new (ELeave) CDesC16ArrayFlat(10); //granularity of 10
+        }
+    iLabelCache->AppendL(aLabel);
+    iValueCache->AppendL(aValue);
+
+    __ASSERT_DEBUG(iLabelCache->Count() == iValueCache->Count(),
+        Panic(EPanicCacheMismatch2));
+    __ASSERT_DEBUG(iLabelCache->Count() > 0, Panic(EPanicCacheMismatch3));
+    }
+    
+void CRichBio::Draw(const TRect& /*aRect*/) const
+    {
+    //removed the clearing of window background,causes flicker
+    }
+
+#ifdef RD_SCALABLE_UI_V2
+EXPORT_C TInt CRichBio::ScrollL( TInt aPixelsToScroll, TMsgScrollDirection aDirection )
+    {
+    TInt pixelsToScroll( 0 );
+    TInt marginPixels( 0 );
+
+    CTextLayout* textLayout = iEditor->TextLayout();
+
+    if ( aDirection == EMsgScrollDown )
+        {
+        TInt pixelsAboveBand( textLayout->PixelsAboveBand() );
+        TInt bandHeight( textLayout->BandHeight() );
+        TInt virtualHeight( iEditor->VirtualHeight() );
+
+        if ( pixelsAboveBand + bandHeight + aPixelsToScroll >= virtualHeight )
+            {
+            pixelsToScroll = -( virtualHeight - ( pixelsAboveBand + bandHeight ) );
+
+            if ( pixelsToScroll != 0 )
+                {
+                // Control has reaches end. Mark margin pixels scrolled.
+                marginPixels = iEditor->Size().iHeight - Size().iHeight;
+                }
+            }
+        else
+            {
+            // Negative pixels means scrolling down.
+            pixelsToScroll = -aPixelsToScroll;
+            }
+        }
+    else
+        {
+        pixelsToScroll = aPixelsToScroll;
+        }
+
+    if ( pixelsToScroll != 0 )
+        {
+		//scrolling to be restricted to full lines
+		//so there will not be any clipping of text on view        
+        textLayout->RestrictScrollToTopsOfLines( ETrue );
+        iEditor->TextView()->ScrollDisplayPixelsL( pixelsToScroll );
+
+        }
+
+    return Abs( pixelsToScroll ) + marginPixels;
+    }
+
+EXPORT_C void CRichBio::NotifyViewEvent( TMsgViewEvent aEvent, TInt /*aParam*/ )
+    {
+    switch ( aEvent )
+        {
+        case EMsgViewEventPrepareFocusTransitionUp:
+            {
+            if ( IsFocused() )
+                {
+                //possible leaves are discarded
+                TRAP_IGNORE( iEditor->ClearSelectionL() );
+                }
+            break;
+            }
+        case EMsgViewEventPrepareFocusTransitionDown:
+            {
+            if ( IsFocused() )
+                {
+                //possible leaves are discarded
+                TRAP_IGNORE( iEditor->ClearSelectionL() );
+                }
+            break;
+            }
+        case EMsgViewEventSetCursorFirstPos:
+            {
+            if ( iEditor->TextView() )
+            	{
+            	if ( iEditor->IsFirstLineVisible()  )
+                    {
+                    //possible leaves are discarded
+            		TRAP_IGNORE( iEditor->SetCursorPosL( 0, EFalse ) );
+					}
+				}
+            break;
+            }
+        case EMsgViewEventSetCursorLastPos:
+            {
+            if ( iEditor->TextView() )
+                {
+                TInt len = iEditor->TextLength();
+
+                if ( iEditor->IsLastLineVisible()  )
+                    {
+                    //possible leaves are discarded
+                    TRAP_IGNORE( iEditor->SetCursorPosL( len, EFalse ) );
+                    }
+                }
+            break;
+            }
+        default:
+            {
+            break;
+            }
+        }
+    }
+    
+#else
+EXPORT_C TInt CRichBio::ScrollL( TInt /*aPixelsToScroll*/, 
+                                 TMsgScrollDirection /*aDirection*/ )
+    {
+    return 0;
+    }
+
+EXPORT_C void CRichBio::NotifyViewEvent( TMsgViewEvent /*aEvent*/,
+                                         TInt /*aParam*/ )
+    {
+    //no op
+    }
+    
+#endif //RD_SCALABLE_UI_V2
+
+
+
+//end of file
+