wvuing/wvuiave/AppSrc/CCARichTextContainer.cpp
branchRCL_3
changeset 13 a941bc465d9f
parent 0 094583676ce7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wvuing/wvuiave/AppSrc/CCARichTextContainer.cpp	Wed Sep 01 12:31:13 2010 +0100
@@ -0,0 +1,3117 @@
+/*
+* Copyright (c) 2006 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:  Rich text container
+*
+*/
+
+
+
+// INCLUDE FILES
+#include    "CCARichTextContainer.h"
+#include    "CCAMessageWrapper.h"
+#include    "MCATextView.h"
+#include    "ChatDebugAssert.h"
+#include    "IMUtils.h"
+//#include    "IMPSCspAllErrors.h"
+#include    "IMNoteMapper.h"
+#include    "ChatDefinitions.h"
+#include    "ChatDebugPrint.h"
+#include    "IMUtils.h"
+#include    "MCAStoredContacts.h"
+#include    "CCAStorageManagerFactory.h"
+#include    "CCAAppSettingsSAPExt.h"
+
+#include    "CCAPicture.h"
+#include    "ccaappui.h"
+//#include    "ccaengine.h"
+#include    "MCAConversationMessage.h"
+#include    "MCAMessageUtils.h"
+#include    "MCAContentProcessor.h"
+#include    "CCAContentMessage.h"
+#include    "CCAMessageExtensionsHandler.h"
+#include    "impsbuilddefinitions.h"
+
+#include    <chatNG.rsg>
+#include    <AknIconUtils.h>
+#include    <txtrich.h>     // CRichtText
+#include    <AknUtils.h>
+#include    <aknsettingcache.h>
+#include    <aknenv.h>
+#include    <aknconsts.h>
+#include    <finditemengine.h>
+#include    <gulicon.h>
+#include    <barsread.h> // resourcereader
+#include    <stringloader.h>
+#include 	<CAVariationNG.rsg>
+
+#include    <aknsdrawutils.h>
+#include    <aknsutils.h>
+#include    <aknutils.h>
+
+#include	"MCASettingsPC.h"
+#include	"MCAMsgAddedToRichTxtCtrlObserver.h"
+
+#include	"MCAProcessManager.h"
+#include	"MCAGroupPC.h"
+#include    "IMUtils.h"
+
+#include <AknLayoutScalable_Apps.cdl.h>
+#include "TCAChatListBoxLayout.h"
+
+// The Settings have been moved to Cenrep (also retained in the Resource file),
+// so the enums for keys and central repository header is added here
+#include 	"VariantKeys.h"
+
+
+// CONSTANTS
+const TInt KChatHighlightColor = 244;
+const TInt KPixelsBetweenLines = 8;      // pixels between text lines
+const TInt KTimeStampMaxLength = 15;     // max length of timestamp text
+const TInt KUnicodeRLM         = 0x200F; // Right-to-Left Mark
+const TInt KUnicodeLRM         = 0x200E; // Left-to-Right Mark
+const TInt KMaxLength          = 10;    // Max Length for user identity
+_LIT( KSeparator, ": " );
+
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::CCARichTextContainer
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CCARichTextContainer::CCARichTextContainer( MCAAppUi& aAppUi,
+                                            MCASettingsPC& aSettingsPC,
+                                            MCATextView& aTextView,
+                                            CCAMessageExtensionsHandler& aExtensionsHandler,
+                                            CGulIcon*& aFromMe,
+                                            CGulIcon*& aToMe,
+                                            CGulIcon*& aUnsupported,
+                                            CGulIcon*& aCorrupted,
+                                            MGraphicsDeviceMap& aMap,
+                                            TBool aScrollOver,
+                                            MCAMsgAddedToRichTxtCtrlObserver* aAddMsgObserver
+                                          )
+        : iAppUi( aAppUi ),
+        iSettings( aSettingsPC ),
+        iTextView( aTextView ),
+        iFromMe( aFromMe ),
+        iToMe( aToMe ),
+        iUnsupported( aUnsupported ),
+        iCorrupted( aCorrupted ),
+        iItemHighlight( ETrue ),
+        iHighlightState( ENoHighlight ),
+        iExtensionsHandler( aExtensionsHandler ),
+        iMap( aMap ),
+        iScrollOver( aScrollOver ),
+        iAddMsgObserver( aAddMsgObserver )
+    {
+    iThumbSize = TSize( 42, 36 );
+    iMessagesDeleted = EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CCARichTextContainer::ConstructL()
+    {
+    iAppUi.AddLayoutChangeObserver( this );
+
+    // setup layout
+    TAknLayoutId layoutId;
+    CAknEnv::Static()->GetCurrentLayoutId( layoutId );
+
+    AknIconUtils::SetSize( iCorrupted->Bitmap(), iThumbSize );
+    AknIconUtils::SetSize( iUnsupported->Bitmap(), iThumbSize );
+
+    // get icon settings
+    iOwnMsgIcon = IMUtils::IntResourceValueL(
+                      RSC_CHAT_VARIATION_OWN_MSG_ICON );
+
+    iMsgIcon = IMUtils::IntResourceValueL(
+                   RSC_CHAT_VARIATION_MSG_ICON );
+
+    CCAAppUi* appUI = static_cast <CCAAppUi*> ( CCoeEnv::Static()->AppUi() );
+
+    //Removed the ownership of iConnUI from this file and made it a reference
+    //APPUI owns this connection UI instance and shares the same with this component.
+    // get user-defined colors from SAP settings
+    CCAAppSettingsSAPExt* SAPExtension = CCAAppSettingsSAPExt::NewLC( appUI->ConnectionUI() );
+    TInt ownCol( SAPExtension->IntValueL( KIMOwnMessageColourKey ) );
+    TInt otherCol( SAPExtension->IntValueL( KIMOthersMessageColourKey ) );
+    CleanupStack::PopAndDestroy( SAPExtension );
+
+    // Check timestamp setting
+    iShowTimeStamps = iSettings.GetBoolValuePC( TEnumsPC::EShowTimeStamps, NULL );
+
+    if ( ownCol != KErrNotFound )
+        {
+        iOwnMsgColorInUse = ETrue;
+        iOwnMsgColor = ownCol;
+        }
+    if ( otherCol != KErrNotFound )
+        {
+        iMsgColorInUse = ETrue;
+        iMsgColor = otherCol;
+        }
+
+    // check resource colours
+    // The default colours settings is present only in the variation resource file. so we use IntResourceValueFromRssL instead of IntResourceValueL
+    TBool defaultColors = IMUtils::IntResourceValueFromRssL(
+                              RSC_CHAT_DEFAULT_MESSAGE_COLORS );
+    iColorWholeMessage = IMUtils::IntResourceValueFromRssL(
+                             RSC_CHAT_COLOR_WHOLE_MESSAGE );
+
+    if ( !defaultColors && !iMsgColorInUse )
+        {
+        // user-defined color not defined and resource colour in use
+        TResourceReader reader;
+        // Since the color settings is not part of Cenrep, the ID is changed to denote the same.
+        CCoeEnv::Static()->CreateResourceReaderLC( reader,
+                                                   RSC_CHAT_MESSAGE_COLOR );
+        TUint8 red( reader.ReadUint8() );
+        TUint8 green( reader.ReadUint8() );
+        TUint8 blue( reader.ReadUint8() );
+        iMsgColor = TRgb( red, green, blue );
+        iMsgColorInUse = ETrue;
+        CleanupStack::PopAndDestroy(); // reader
+        }
+
+    if ( !defaultColors && !iOwnMsgColorInUse )
+        {
+        // user-defined color not defined and resource colour in use
+        TResourceReader reader;
+        // Since the color settings is not part of Cenrep, the ID is changed to denote the same.
+        CCoeEnv::Static()->CreateResourceReaderLC( reader,
+                                                   RSC_CHAT_OWN_MESSAGE_COLOR );
+        TUint8 red( reader.ReadUint8() );
+        TUint8 green( reader.ReadUint8() );
+        TUint8 blue( reader.ReadUint8() );
+        iOwnMsgColor = TRgb( red, green, blue );
+        iOwnMsgColorInUse = ETrue;
+        CleanupStack::PopAndDestroy(); // reader
+        }
+
+    CHAT_DP( D_CHAT_LIT( " msgColor red=%d, green=%d, blue=%d" ),
+             iMsgColor.Red(), iMsgColor.Green(), iMsgColor.Blue() );
+    CHAT_DP( D_CHAT_LIT( " ownMsgColor red=%d, green=%d, blue=%d" ),
+             iOwnMsgColor.Red(), iOwnMsgColor.Green(), iOwnMsgColor.Blue() );
+
+    iPrimaryFont = AknLayoutUtils::FontFromId( EAknLogicalFontPrimaryFont,
+                                               NULL );
+    iSecondaryFont = AknLayoutUtils::FontFromId( EAknLogicalFontPrimarySmallFont,
+                                                 NULL );
+
+    CParaFormat paraFormat;
+    TParaFormatMask paraFormatMask;
+    paraFormat.iLanguage = CAknEnv::Static()->SettingCache().InputLanguage();
+    paraFormatMask.SetAttrib( EAttParaLanguage );
+
+    paraFormat.iFillColor = KRgbWhite;
+    paraFormatMask.SetAttrib( EAttFillColor );
+
+    paraFormat.iLeftMarginInTwips = 100;
+    paraFormat.iIndentInTwips = -100;
+    paraFormatMask.SetAttrib( EAttLeftMargin );
+    paraFormatMask.SetAttrib( EAttIndent );
+
+    // Create zoom factor object
+    TZoomFactor devicemap( CCoeEnv::Static()->ScreenDevice() );
+    devicemap.SetZoomFactor( TZoomFactor::EZoomOneToOne );
+
+    // Get the line hight and font height
+    TRect mainPaneRect;
+    TAknLayoutRect lineRect;
+    TAknLayoutRect layoutRect;
+
+    AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::EMainPane, mainPaneRect );
+    TAknWindowLineLayout readingPane = AknLayoutScalable_Apps::im_reading_pane( TChatListBoxLayout::EWithoutEditor );
+    layoutRect.LayoutRect( mainPaneRect, readingPane );
+
+    TAknWindowLineLayout lineLayout = AknLayoutScalable_Apps::list_im_single_pane( 0 );
+    lineRect.LayoutRect( layoutRect.Rect(), lineLayout );
+    TInt lineHeight = lineRect.Rect().Height();
+
+    TAknLayoutText text;
+    text.LayoutText( layoutRect.Rect(),
+                     AknLayoutScalable_Apps::list_single_im_pane_t1( 0 ).LayoutLine() );
+
+    // Set line space
+    paraFormat.iLineSpacingControl = CParaFormat::ELineSpacingExactlyInTwips;
+    paraFormatMask.SetAttrib( EAttLineSpacingControl );
+
+    paraFormat.iLineSpacingInTwips = devicemap.VerticalPixelsToTwips( lineHeight );
+    paraFormatMask.SetAttrib( EAttLineSpacing );
+
+    TCharFormat charFormat;
+    TCharFormatMask charFormatMask;
+    charFormat.iFontSpec = iSecondaryFont->FontSpecInTwips();
+    // Set font height
+    charFormat.iFontSpec.iHeight = devicemap.VerticalPixelsToTwips( text.TextRect().Height() );
+    charFormatMask.SetAttrib( EAttFontTypeface );
+    charFormatMask.SetAttrib( EAttFontHeight );
+
+    // Text color
+    TRgb defaultSkinTextColor( KRgbBlack );
+    AknsUtils::GetCachedColor( AknsUtils::SkinInstance(),
+                               defaultSkinTextColor,
+                               KAknsIIDQsnTextColors,
+                               EAknsCIQsnTextColorsCG6 );
+
+    //Store the default masg color
+    iDefaultMsgColor =  defaultSkinTextColor;
+
+    charFormat.iFontPresentation.iTextColor = defaultSkinTextColor;
+    charFormatMask.SetAttrib( EAttColor );
+
+    charFormat.iFontPresentation.iPictureAlignment =
+        TFontPresentation::EAlignTop;
+    charFormatMask.SetAttrib( EAttFontPictureAlignment );
+
+    charFormat.iFontSpec.iFontStyle.SetStrokeWeight( EStrokeWeightNormal );
+    charFormatMask.SetAttrib( EAttFontStrokeWeight );
+
+
+    iParaFormatLayer = CParaFormatLayer::NewL( &paraFormat, paraFormatMask );
+    iCharFormatLayer = CCharFormatLayer::NewL( charFormat, charFormatMask );
+
+    iRichText = CRichText::NewL( iParaFormatLayer, iCharFormatLayer );
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CCARichTextContainer* CCARichTextContainer::NewL(
+    MCAAppUi& aAppUi,
+    MCASettingsPC& aSettingsPC,
+    MCATextView& aTextView,
+    CCAMessageExtensionsHandler& aExtensionsHandler,
+    CGulIcon*& aFromMe,
+    CGulIcon*& aToMe,
+    CGulIcon*& aUnsupported,
+    CGulIcon*& aCorrupted,
+    MGraphicsDeviceMap& aMap,
+    TBool aScrollOver /*= ETrue*/,
+    MCAMsgAddedToRichTxtCtrlObserver* aAddMsgObserver /*= NULL*/
+)
+    {
+    CCARichTextContainer* self = new( ELeave ) CCARichTextContainer(
+        aAppUi,
+        aSettingsPC,
+        aTextView,
+        aExtensionsHandler, aFromMe, aToMe,
+        aUnsupported, aCorrupted,
+        aMap,
+        aScrollOver, aAddMsgObserver
+    );
+
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+
+// Destructor
+CCARichTextContainer::~CCARichTextContainer()
+    {
+    delete iParaFormatLayer;
+    delete iCharFormatLayer;
+    delete iRichText;
+    iMessages.ResetAndDestroy();
+    iAppUi.RemoveLayoutChangeObserver( this );
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::SelectedMessage
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+MCAConversationMessage* CCARichTextContainer::SelectedMessage()
+    {
+    if ( iHighlightState != ENoHighlight )
+        {
+        return &( iMessages[iSelected]->Message() );
+        }
+    else
+        {
+        return NULL;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::SelectedItem
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+HBufC* CCARichTextContainer::SelectedItemL()
+    {
+    if ( iHighlightState == EItemSelected )
+        {
+        TCursorSelection curSel( iMessages[iSelected]->Selection() );
+
+        // calculate item highlight position
+        TCursorSelection itemSel(
+            iMessages[iSelected]->Highlights()[iSelectedItem] );
+
+        TInt messageStart( curSel.LowerPos() );
+        curSel.iAnchorPos = itemSel.iAnchorPos + messageStart;
+        curSel.iCursorPos = itemSel.iCursorPos + messageStart;
+
+        HBufC* text = HBufC::NewMaxL( curSel.Length() );
+        TPtr ptr( text->Des() );
+        iRichText->Extract(	ptr, curSel.LowerPos(), curSel.Length() );
+        return text;
+        }
+    else
+        {
+        return KNullDesC().AllocL();
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::SelectedItemType
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TInt CCARichTextContainer::SelectedItemType()
+    {
+    if ( iHighlightState == EItemSelected )
+        {
+        return iMessages[iSelected]->HighlightTypes()[iSelectedItem];
+        }
+    else
+        {
+        return KErrNotFound;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::RichText
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+MLayDoc* CCARichTextContainer::TextLayout()
+    {
+    return iRichText;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::MoveHighlightL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TInt CCARichTextContainer::MoveHighlightL( THighlightMovement aDirection )
+    {
+    __CHAT_ASSERT_DEBUG( aDirection == EPrevious || aDirection == ENext );
+    TBool up( aDirection == EPrevious );
+    TInt messageCount( iMessages.Count() );
+    if ( messageCount == 0 )
+        {
+        // no messages, nothing to highlight
+        DisableHighlightL();
+        return KErrNotFound;
+        }
+
+    __CHAT_ASSERT_DEBUG( iSelected >= 0 && iSelected < messageCount );
+    TInt highlightCount( iMessages[iSelected]->Highlights().Count() );
+
+    if ( !iItemHighlight )
+        {
+        // if item highlighting is not on, clear the item count
+        highlightCount = 0;
+        }
+
+    // if message is highlighted, but it doesn't fit to screen
+    // scroll it line by line
+    if ( iHighlightState == EMessageTop || iHighlightState == EMessageBottom )
+        {
+        TCursorSelection& sel = iMessages[iSelected]->Selection();
+        if ( up )
+            {
+            // up
+            if ( !iTextView.IsVisible( sel.LowerPos() ) )
+                {
+                // we're scrolling up and top line is not shown,
+                // so scroll messages down by one line
+                iTextView.ScrollLinesL( 1 );
+                return KErrNone;
+                }
+            }
+        else if ( !iTextView.IsVisible( sel.HigherPos() ) )
+            {
+            // we're scrolling down and bottom line is not shown,
+            // so scroll messages up by one line
+            iTextView.ScrollLinesL( -1 );
+            return KErrNone;
+            }
+        }
+
+    // update highlight position
+    switch ( iHighlightState )
+        {
+        case ENoHighlight:  // no highlight, select last  or first message
+            {
+            if ( up )
+                {
+                iSelected = messageCount - 1;
+
+                // Get highlight count of prev message
+                // if item highlighting is on
+                if ( iItemHighlight )
+                    {
+                    highlightCount = iMessages[iSelected]->Highlights().Count();
+                    }
+
+                if ( highlightCount > 0 )
+                    {
+                    // highlight items inside last message (if any)
+                    iHighlightState = EItemSelected;
+                    iSelectedItem = highlightCount - 1;
+                    }
+                else
+                    {
+                    // bottom of last message
+                    iHighlightState = EMessageBottom;
+                    }
+                }
+            else
+                {
+                // top of first message
+                iHighlightState = EMessageTop;
+                iSelected = 0;
+                }
+            break;
+            }
+        case EItemSelected: // highlighting items
+            {
+            if ( up )
+                {
+                // up, previous item
+                --iSelectedItem;
+                if ( iSelectedItem < 0 )
+                    {
+                    // end of highlights, focus message
+                    iHighlightState = EMessageTop;
+                    }
+                }
+            else
+                {
+                // down, next item
+                ++iSelectedItem;
+                if ( iSelectedItem >= highlightCount )
+                    {
+                    // end of highlights
+                    if ( iSelected < messageCount - 1 )
+                        {
+                        // focus next message
+                        ++iSelected;
+                        iHighlightState = EMessageTop;
+                        }
+                    else if ( iScrollOver )
+                        {
+                        // going down from last message,
+                        // disable highlight so editor can take the focus
+                        DisableHighlightL();
+                        return KErrNone;
+                        }
+                    else
+                        {
+                        // Loop back to beginning
+                        iSelected = 0;
+                        iSelectedItem = 0;
+                        iHighlightState = EMessageTop;
+                        }
+
+                    }
+                }
+            break;
+            }
+        case EMessageTop:   // highlighting message ("top" of it)
+            {
+            if ( up )
+                {
+                // up, highlighting previous message
+                if ( iSelected > 0 )
+                    {
+                    // prev
+                    --iSelected;
+
+                    // get highlight count of prev message
+                    // if item highlighting is on
+                    if ( iItemHighlight )
+                        {
+                        highlightCount = iMessages[iSelected]->Highlights().Count();
+                        }
+
+                    if ( highlightCount > 0 )
+                        {
+                        // highlight items inside prev message (if any)
+                        iHighlightState = EItemSelected;
+                        iSelectedItem = highlightCount - 1;
+                        }
+                    else
+                        {
+                        // highlight whole prev message
+                        iHighlightState = EMessageBottom;
+                        }
+                    }
+                else if ( iScrollOver )
+                    {
+                    // going up from first message,
+                    // disable highlight, so editor can take the focus
+                    DisableHighlightL();
+                    return KErrNone;
+                    }
+                else
+                    {
+                    // Loop to last message
+                    iSelected = messageCount - 1;
+                    highlightCount = 0;
+
+                    // Get highlight count of last message
+                    // if item highlighting is on
+                    if ( iItemHighlight )
+                        {
+                        highlightCount =
+                            iMessages[iSelected]->Highlights().Count();
+                        }
+
+                    if ( highlightCount > 0 )
+                        {
+                        // Highlight items inside last message (if any)
+                        iHighlightState = EItemSelected;
+                        iSelectedItem = highlightCount - 1;
+                        }
+                    else
+                        {
+                        // Highlight whole last message
+                        iHighlightState = EMessageBottom;
+                        }
+                    }
+                }
+            else
+                {
+                // down, highlight items inside this message (if any)
+                if ( highlightCount > 0 )
+                    {
+                    iSelectedItem = 0;
+                    iHighlightState = EItemSelected;
+                    }
+                else if ( iSelected < messageCount - 1 )
+                    {
+                    // next
+                    ++iSelected;
+                    iHighlightState = EMessageTop;
+                    }
+                else if ( iScrollOver )
+                    {
+                    // going down from last message,
+                    // disable highlight, so editor can take the focus
+                    DisableHighlightL();
+                    return KErrNone;
+                    }
+                else
+                    {
+                    // Loop back to beginning
+                    iSelected = 0;
+                    iSelectedItem = 0;
+                    iHighlightState = EMessageTop;
+                    }
+                }
+            break;
+            }
+        case EMessageBottom:   // highlighting message ("bottom" of it)
+            {
+            if ( up )
+                {
+                // up, highlight items inside this message (if any)
+                if ( highlightCount > 0 )
+                    {
+                    iSelectedItem = highlightCount - 1;
+                    iHighlightState = EItemSelected;
+                    }
+                else if ( iSelected > 0 )
+                    {
+                    // prev
+                    --iSelected;
+
+                    // get highlight count of prev message
+                    // if item highlighting is on
+                    if ( iItemHighlight )
+                        {
+                        highlightCount = iMessages[iSelected]->Highlights().Count();
+                        }
+
+                    if ( highlightCount > 0 )
+                        {
+                        // highlight items inside prev message (if any)
+                        iHighlightState = EItemSelected;
+                        iSelectedItem = highlightCount - 1;
+                        }
+                    else
+                        {
+                        iHighlightState = EMessageBottom;
+                        }
+                    }
+                else if ( iScrollOver )
+                    {
+                    // going up from first message,
+                    // disable highlight, so editor can take the focus
+                    DisableHighlightL();
+                    return KErrNone;
+                    }
+                else
+                    {
+                    // Loop to last message
+                    iSelected = messageCount - 1;
+                    highlightCount = 0;
+
+                    // Get highlight count of last message
+                    // if item highlighting is on
+                    if ( iItemHighlight )
+                        {
+                        highlightCount =
+                            iMessages[iSelected]->Highlights().Count();
+                        }
+
+                    if ( highlightCount > 0 )
+                        {
+                        // Highlight items inside last message (if any)
+                        iHighlightState = EItemSelected;
+                        iSelectedItem = highlightCount - 1;
+                        }
+                    else
+                        {
+                        // Highlight whole last message
+                        iHighlightState = EMessageBottom;
+                        }
+                    }
+                }
+            else
+                {
+                // down, highlighting next message
+                if ( iSelected < messageCount - 1 )
+                    {
+                    // next
+                    ++iSelected;
+                    iHighlightState = EMessageTop;
+                    }
+                else if ( iScrollOver )
+                    {
+                    // going down from last message,
+                    // disable highlight, so editor can take the focus
+                    DisableHighlightL();
+                    return KErrNone;
+                    }
+                else
+                    {
+                    // Loop back to beginning
+                    iSelected = 0;
+                    iSelectedItem = 0;
+                    iHighlightState = EMessageTop;
+                    }
+                }
+            break;
+            }
+        default:
+            {
+            __CHAT_ASSERT_DEBUG( EFalse );
+            break;
+            }
+        }
+
+    // get the selection
+    TCursorSelection curSel( CurrentSelection() );
+
+    // remove colors from old highlight
+    TInt textLen( iRichText->DocumentLength() );
+    if ( iPrevious.iAnchorPos < textLen &&
+         iPrevious.iCursorPos <= textLen )
+        {
+        BackColorL( iPrevious, KRgbWhite );
+        TextBackColorL( iPrevious, KRgbWhite );
+        }
+
+    // and set new one
+    if ( iHighlightState == EItemSelected )
+        {
+        MAknsSkinInstance* skin = AknsUtils::SkinInstance();
+        TRgb color;
+
+        TInt error = AknsUtils::GetCachedColor( skin,
+                                                color,
+                                                KAknsIIDQsnHighlightColors,
+                                                EAknsCIQsnHighlightColorsCG2 );
+
+        if ( !error )
+            {
+            // No error, use skinned background color
+            TextBackColorL( curSel, color );
+            }
+        else
+            {
+            TextBackColorL( curSel, AKN_LAF_COLOR_STATIC( KChatHighlightColor ) );
+            }
+        }
+    else
+        {
+        MAknsSkinInstance* skin = AknsUtils::SkinInstance();
+        TRgb color;
+
+        TInt error = AknsUtils::GetCachedColor( skin,
+                                                color,
+                                                KAknsIIDQsnHighlightColors,
+                                                EAknsCIQsnHighlightColorsCG2 );
+
+        if ( !error )
+            {
+            // No error, use skinned background color
+            BackColorL( curSel, color );
+            }
+        else
+            {
+            BackColorL( curSel, AKN_LAF_COLOR_STATIC( KChatHighlightColor ) );
+            }
+        }
+
+    // handle changed format
+    TCursorSelection changed( Union( iPrevious, curSel ) );
+
+    iTextView.HandleFormatChangedL( changed );
+
+    iTextView.ScrollVisibleL( curSel, ETrue );
+
+    iPrevious = curSel;
+    return KErrNone;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::DisableHighlightL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCARichTextContainer::DisableHighlightL()
+    {
+    iHighlightState = ENoHighlight;
+
+    TCursorSelection sel( 0, 0 );
+    TInt count( iMessages.Count() );
+    if ( count > 0 )
+        {
+        sel = iMessages[count-1]->Selection();
+        }
+
+    // remove colors from old highlight (if any)
+    TInt textLen( iRichText->DocumentLength() );
+    if ( iPrevious.iAnchorPos < textLen &&
+         iPrevious.iCursorPos <= textLen )
+        {
+        BackColorL( iPrevious, KRgbWhite );
+        TextBackColorL( iPrevious, KRgbWhite );
+        iTextView.HandleFormatChangedL( iPrevious );
+        }
+
+    // set focus to last message
+    iTextView.ScrollVisibleL( sel, EFalse );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::SetItemHighlight
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCARichTextContainer::SetItemHighlight( TBool aItemHighlight )
+    {
+    iItemHighlight = aItemHighlight;
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::Highlighted
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CCARichTextContainer::Highlighted()
+    {
+    return iHighlightState != ENoHighlight;
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::Highlighted
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TInt CCARichTextContainer::HighlightItemAtPosL( TInt aPos )
+    {
+    TInt messageCount = iMessages.Count();
+    if ( messageCount == 0 )
+        {
+        // no messages
+        return KErrNotFound;
+        }
+
+    // Store old values
+    TInt oldSelectedMessage = iSelected;
+    TInt oldSelectedItem = iSelectedItem;
+    THighlightState oldHighlight = iHighlightState;
+
+    // Find message in position aPos
+    TBool found = EFalse;
+    for ( TInt i = 0; i < messageCount; ++i )
+        {
+        TCursorSelection sel = iMessages[ i ]->WholeSelection();
+        if ( aPos >= sel.LowerPos() &&
+             aPos <= sel.HigherPos() )
+            {
+            // Found the message
+            iSelected = i;
+            iHighlightState = EMessageTop;
+            found = ETrue;
+            // stop searching
+            break;
+            }
+        }
+
+    if ( !found )
+        {
+        // not found
+        return KErrNotFound;
+        }
+
+    // Check if there are items inside the message that can be highlighted.
+    if ( iItemHighlight )
+        {
+        TInt hlCount = iMessages[ iSelected ]->Highlights().Count();
+        TInt relativePos =
+            aPos - iMessages[ iSelected ]->WholeSelection().LowerPos();
+
+        for ( TInt i = 0; i < hlCount; ++i )
+            {
+            TCursorSelection sel = iMessages[ iSelected ]->Highlights()[ i ];
+
+            // Highlight's selection is relative to message
+            if ( relativePos >= sel.LowerPos() &&
+                 relativePos <= sel.HigherPos() )
+                {
+                // Found an item
+                iHighlightState = EItemSelected;
+                iSelectedItem = i;
+                // stop searching
+                break;
+                }
+            }
+        }
+
+    // Update UI only if selection has changed
+    if ( iSelected != oldSelectedMessage ||
+         iSelectedItem != oldSelectedItem ||
+         oldHighlight != iHighlightState )
+        {
+        UpdateSelectionL();
+        return KErrNone;
+        }
+    // Already highlighted
+    return KErrAlreadyExists;
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::UpdateSelection
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCARichTextContainer::UpdateSelectionL()
+    {
+    // get the selection
+    TCursorSelection curSel( CurrentSelection() );
+
+    // remove colors from old highlight
+    TInt textLen( iRichText->DocumentLength() );
+    if ( iPrevious.iAnchorPos < textLen &&
+         iPrevious.iCursorPos <= textLen )
+        {
+        BackColorL( iPrevious, KRgbWhite );
+        TextBackColorL( iPrevious, KRgbWhite );
+        }
+
+    // and set new one
+    if ( iHighlightState == EItemSelected )
+        {
+        MAknsSkinInstance* skin = AknsUtils::SkinInstance();
+        TRgb color;
+
+        TInt error = AknsUtils::GetCachedColor( skin,
+                                                color,
+                                                KAknsIIDQsnHighlightColors,
+                                                EAknsCIQsnHighlightColorsCG2 );
+
+        if ( !error )
+            {
+            // No error, use skinned background color
+            TextBackColorL( curSel, color );
+            }
+        else
+            {
+            TextBackColorL( curSel, AKN_LAF_COLOR_STATIC( KChatHighlightColor ) );
+            }
+        }
+    else
+        {
+        MAknsSkinInstance* skin = AknsUtils::SkinInstance();
+        TRgb color;
+
+        TInt error = AknsUtils::GetCachedColor( skin,
+                                                color,
+                                                KAknsIIDQsnHighlightColors,
+                                                EAknsCIQsnHighlightColorsCG2 );
+
+        if ( !error )
+            {
+            // No error, use skinned background color
+            BackColorL( curSel, color );
+            }
+        else
+            {
+            BackColorL( curSel, AKN_LAF_COLOR_STATIC( KChatHighlightColor ) );
+            }
+        }
+
+    // handle changed format
+    TCursorSelection changed( Union( iPrevious, curSel ) );
+    iTextView.HandleFormatChangedL( changed );
+    iTextView.ScrollVisibleL( curSel, ETrue );
+
+    iPrevious = curSel;
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::InsertUserIdentityL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TCursorSelection CCARichTextContainer::InsertUserIdentityL(
+    CCAMessageWrapper& aMessageWrapper )
+    {
+    TInt stampStart = 0;
+    TCursorSelection timeSel( stampStart, stampStart );
+    TInt stampEnd = stampStart;
+    MCAConversationMessage& message = aMessageWrapper.Message();
+    TPtrC sender;
+    TPtrC recipient;
+    MCAStoredContacts* contacts = CCAStorageManagerFactory::ContactListInterfaceL();
+    if ( message.MessagerType() == TEnumsPC::EMessageSent
+         && message.MessageType() != TEnumsPC::EMessageSystem )
+        {
+        sender.Set( contacts->OwnStatus().Identification() );
+        }
+    else
+        {
+        sender.Set( contacts->Identification( message.Sender() ) );
+        }
+    recipient.Set( contacts->Identification( message.Recipient() ) );
+
+    if ( message.MessagerType() == TEnumsPC::EMessageSent &&
+         message.MessageType() == TEnumsPC::EMessagePTOP &&
+         iOwnMsgIcon )
+        {
+        if ( sender.Length() >= KMaxLength )
+            {
+            TPtrC aTempPtr;
+            aTempPtr.Set( sender.Left( 8 ) );
+            TBuf<11> aTruncateSender( aTempPtr );
+            aTruncateSender.Append( _L( ".. " ) );
+            iRichText->InsertL( stampStart, aTruncateSender );
+            stampEnd = stampStart + aTruncateSender.Length();
+            }
+        else
+            {
+            TBuf<10> aTruncateSender( sender );
+            aTruncateSender.Append( KSpace );
+            iRichText->InsertL( stampStart, aTruncateSender );
+            stampEnd = stampStart + aTruncateSender.Length();
+            }
+        }
+    else if ( message.MessageType() == TEnumsPC::EMessagePTOP &&
+              message.MessagerType() == TEnumsPC::EMessageReceived &&
+              iMsgIcon )
+        {
+        if ( recipient.Length() >= KMaxLength )
+            {
+            TPtrC aTempPtr;
+            aTempPtr.Set( recipient.Left( 8 ) );
+            TBuf<11> aTruncateRecipient( aTempPtr );
+            aTruncateRecipient.Append( _L( ".. " ) );
+            iRichText->InsertL( stampStart, aTruncateRecipient );
+            stampEnd = stampStart + aTruncateRecipient.Length();
+            }
+        else
+            {
+            TBuf<10> aTruncateRecipient( recipient );
+            aTruncateRecipient.Append( KSpace );
+            //CEikonEnv::Static()->InfoMsg(aTruncateRecipient);
+            iRichText->InsertL( stampStart, aTruncateRecipient );
+            stampEnd = stampStart + aTruncateRecipient.Length();
+            }
+        }
+    timeSel.SetSelection( stampStart, stampEnd - 1 );
+
+    // bold the User Identity
+    if ( timeSel.Length() > 0 )
+        {
+        BoldL( timeSel );
+        }
+
+    return timeSel;
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::InsertTimeStampL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TCursorSelection CCARichTextContainer::InsertTimeStampL(
+    CCAMessageWrapper& aMessageWrapper )
+    {
+    TInt start = 0;
+    TCursorSelection timeSel( start, start );
+
+    if ( !iSettings.GetBoolValuePC( TEnumsPC::EShowTimeStamps, NULL ) ||
+         aMessageWrapper.Message().SystemMessageType() ==
+         TEnumsPC::ESystemMessageDateChange )
+        {
+        // 1. Setting for time stamp is OFF
+        // 2. Special case: date change don't have time stamp.
+        return timeSel;
+        }
+
+    // format time
+    HBufC* timeStamp = HBufC::NewLC( KTimeStampMaxLength + KSpace().Length() );
+    TPtr timePtr( timeStamp->Des() );
+
+    HBufC* timeStampFormat = NULL;
+    timeStampFormat = StringLoader::LoadLC( R_QTN_TIME_USUAL_WITH_ZERO );
+
+    TTime time = aMessageWrapper.Message().TimeStamp();
+    TRAPD( err, time.FormatL( timePtr, *timeStampFormat ) );
+    if ( err == KErrOverflow )
+        {
+        // Reserved text space was not enough.
+        // Adjust the KTimeStampMaxLength
+        __CHAT_ASSERT_DEBUG( EFalse );
+
+        // in release builds return without timestamp
+        CleanupStack::PopAndDestroy( 2, timeStamp ); // timeStamp, timeStampFormat
+        return timeSel;
+        }
+
+    // Convert numbers to local language
+    AknTextUtils::LanguageSpecificNumberConversion( timePtr );
+
+    // Set Alignment of Pm/Am from local setting
+    // This keeps the am/pm text close to the time.
+    timePtr.Append( AknLayoutUtils::LayoutMirrored() ?
+                    KUnicodeRLM : KUnicodeLRM );
+
+    //	IM client UI customization, phase 2
+    //  Based on Variation flag, changes Time Stamp format in conversation view.
+    //  where Time Stamp should appear in brackets.
+
+    // read variation flag values
+    TInt requireUserIdentity = IMUtils::IntResourceValueL( RSC_CHAT_VARIATION_SHOW_USER_IDENTITY );
+    // and check dynamic features
+    if ( requireUserIdentity )
+        {
+        timePtr.Insert( 0, _L( "(" ) );
+        timePtr.Append( _L( ")" ) );
+        timePtr.Append( KSpace );
+        }
+    else
+        {
+        timePtr.Append( KSpace );
+        }
+
+    iRichText->InsertL( start, timePtr );
+
+    CleanupStack::PopAndDestroy( 2, timeStamp ); // timeStamp, timeStampFormat
+    timeSel.SetSelection( start, timePtr.Length() - 1 );
+
+    // bold the time
+    if ( timeSel.Length() > 0 )
+        {
+        BoldL( timeSel );
+        }
+
+    return timeSel;
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::InsertContentL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TInt CCARichTextContainer::InsertContentL( CCAMessageWrapper& aMessageWrapper )
+    {
+    MCAConversationMessage& message = aMessageWrapper.Message();
+
+    TEnumsPC::TContentType type( message.ContentType() );
+    switch ( type )
+        {
+        case TEnumsPC::EContentText:
+            {
+            TInt oldLen = iRichText->DocumentLength();
+
+            // Insert text
+            TPtrC msg( message.Text() );
+
+            HBufC* tempMsg = NULL;
+
+            TInt paraBreak = msg.Locate( CEditableText::EParagraphDelimiter );
+            // Replace all paragraph delimiters with line breaks
+            // to keep alingment consistent
+            if ( paraBreak != KErrNotFound )
+                {
+                tempMsg = msg.AllocLC();
+                TPtr ptr( tempMsg->Des() );
+                ptr.Zero();
+
+                ReplaceParaDelimsWithLineBreaks( msg, ptr );
+                msg.Set( ptr );
+                }
+
+            HBufC* numberConv = NULL;
+
+            // Convert numerals to local language
+            // 1) date item
+            if ( aMessageWrapper.Message().SystemMessageType() ==
+                 TEnumsPC::ESystemMessageDateChange )
+                {
+                // Don't touch the original message
+                numberConv = msg.AllocLC();
+                TPtr ptr( numberConv->Des() );
+                AknTextUtils::LanguageSpecificNumberConversion( ptr );
+                msg.Set( ptr );
+                }
+
+            iRichText->InsertL( 0, msg );
+
+            TInt textEnd = msg.Length();
+
+            // Check for extensions (smileys)
+            TCursorSelection selection( 0, textEnd );
+            TInt bfrConv = iRichText->DocumentLength();
+            iExtensionsHandler.ConvertSelectionToExtensionL( *iRichText,
+                                                             selection );
+
+            // Move textEnd index if extensions were found
+            textEnd -= ( bfrConv - iRichText->DocumentLength() );
+
+            // Add nbs to preserve formatting
+            iRichText->InsertL( textEnd,
+                                CEditableText::EZeroWidthNoBreakSpace );
+
+            // If this is system message, it should be bold
+            if ( message.MessageType() == TEnumsPC::EMessageSystem )
+                {
+                TCursorSelection sel( 0, textEnd );
+                BoldL( sel );
+                // System messages need different kind of alignment
+                CParaFormat paraFormat;
+                TParaFormatMask paraFormatMask;
+                paraFormat.iLeftMarginInTwips = 0;
+                paraFormatMask.SetAttrib( EAttLeftMargin );
+                iRichText->ApplyParaFormatL( &paraFormat, paraFormatMask,
+                                             0, textEnd + 1 );
+                }
+            else
+                {
+                // Apply alignment for "normal" messages
+                CParaFormat paraFormat;
+                TParaFormatMask paraFormatMask;
+                paraFormat.iLeftMarginInTwips = 100;
+                paraFormatMask.SetAttrib( EAttLeftMargin );
+                iRichText->ApplyParaFormatL( &paraFormat, paraFormatMask,
+                                             0, textEnd + 1 );
+
+                // Remove bolding from message content
+                TCharFormat charFormat;
+                TCharFormatMask charFormatMask;
+                charFormat.iFontSpec.iFontStyle.SetStrokeWeight( EStrokeWeightNormal );
+                charFormatMask.SetAttrib( EAttFontStrokeWeight );
+                iRichText->ApplyCharFormatL( charFormat, charFormatMask,
+                                             0, textEnd + 1 );
+                }
+
+            // Cleanup
+            if ( numberConv )
+                {
+                CleanupStack::PopAndDestroy( numberConv );
+                }
+            if ( tempMsg )
+                {
+                CleanupStack::PopAndDestroy( tempMsg );
+                }
+
+            return iRichText->DocumentLength() - oldLen;
+            }
+        case TEnumsPC::EContentPicture: // Flowthrough
+        case TEnumsPC::EContentOther:
+            {
+            TInt oldLen = iRichText->DocumentLength();
+            // insert thumbnail (if it's ready)
+            AddThumbL( 0, aMessageWrapper );
+            return iRichText->DocumentLength() - oldLen;
+            }
+        case TEnumsPC::EContentInvalid:
+            {
+            break;
+            }
+        default:
+            {
+            // Unsupported type
+            __CHAT_ASSERT_DEBUG( false );
+            break;
+            }
+        }
+
+    return 0;
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::InsertNickL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TCursorSelection CCARichTextContainer::InsertNickL(
+    CCAMessageWrapper& aMessageWrapper )
+    {
+    // insert nick
+    MCAConversationMessage& message = aMessageWrapper.Message();
+
+    if ( message.FailedMessage() )
+        {
+        return 	TCursorSelection( 0, 0 );
+        }
+
+    TPtrC sender;
+    TPtrC recipient;
+    if ( message.MessageType() == TEnumsPC::EMessageGroup ||
+         message.MessageType() == TEnumsPC::EMessageWhisper )
+        {
+        sender.Set( message.Sender() );
+
+        if ( message.MessagerType() == TEnumsPC::EMessageSent )
+            {
+            recipient.Set( message.Recipient() );
+            }
+        else
+            {
+            CCAAppUi* appUI = static_cast <CCAAppUi*> ( CCoeEnv::Static()->AppUi() );
+            recipient.Set( appUI->GetProcessManager().GetGroupInterface()->ScreenName() );
+            }
+
+        }
+    else
+        {
+        MCAStoredContacts* contacts =
+            CCAStorageManagerFactory::ContactListInterfaceL();
+        if ( message.MessagerType() == TEnumsPC::EMessageSent
+             && message.MessageType() != TEnumsPC::EMessageSystem )
+            {
+            sender.Set( contacts->OwnStatus().Identification() );
+            }
+        else
+            {
+            sender.Set( contacts->Identification( message.Sender() ) );
+            }
+
+        recipient.Set( contacts->Identification( message.Recipient() ) );
+        }
+    TCursorSelection nickSel( 0, 0 );
+
+    if ( message.MessagerType() == TEnumsPC::EMessageSent &&
+         message.MessageType() == TEnumsPC::EMessagePTOP &&
+         iOwnMsgIcon )
+        {
+        // this is sent (or failed) p2p message,
+        // insert "from me" icon and separator
+        // (if icons are in use)
+        //	IM client UI customization, phase 2
+        //  Based on Variation flag, changes Nick format in conversation view
+        //  removes arrow sign and append only a seperator.
+
+        // read variation flag values
+        TInt requireUserIdentity = IMUtils::IntResourceValueL( RSC_CHAT_VARIATION_SHOW_USER_IDENTITY );
+        // and check dynamic features
+        if ( !requireUserIdentity )
+            {
+            CCAPicture* pic = new( ELeave ) CCAPicture( iMap, iFromMe );
+            TPictureHeader header;
+            header.iPicture = TSwizzle<CPicture>( pic );
+            iRichText->CancelInsertCharFormat();    // to prevent ETEXT 31 panic
+            iRichText->InsertL( 0, header ); // takes ownership
+            iRichText->InsertL( 1, KSeparator );
+            nickSel.iAnchorPos = 1;
+            }
+        else
+            {
+            iRichText->InsertL( 0, KSeparator );
+            nickSel.iAnchorPos = 0;
+            }
+        }
+    else
+        {
+        TInt nickStart = 0;
+        TInt nickEnd = nickStart;
+
+        if ( message.MessageType() == TEnumsPC::EMessageWhisper )
+            {
+            // this is send/received whisper message (to us),
+            // insert sender, "to me" icon and separator
+            iRichText->InsertL( nickStart, sender );
+            nickEnd = sender.Length();
+
+            CCAPicture* pic = NULL;
+            if ( message.MessagerType() == TEnumsPC::EMessageSent )
+                {
+                pic = new( ELeave )CCAPicture( iMap,
+                                               iFromMe );
+                }
+            else
+                {
+                pic = new( ELeave )CCAPicture( iMap,
+                                               iToMe );
+                }
+            TPictureHeader header;
+            header.iPicture = TSwizzle<CPicture>( pic );
+            iRichText->CancelInsertCharFormat(); // to prevent ETEXT 31 panic
+            iRichText->InsertL( nickEnd, header ); // takes ownership
+
+            iRichText->InsertL( nickEnd + 1, recipient );
+            nickEnd = nickEnd + 1 + recipient.Length();
+
+            iRichText->InsertL( nickEnd, KSeparator );
+            }
+        else if ( message.MessageType() == TEnumsPC::EMessagePTOP &&
+                  message.MessagerType() == TEnumsPC::EMessageReceived &&
+                  iMsgIcon )
+            {
+            // received p2p message and we want to display icon
+            // insert "to me" icon and separator
+            //	IM client UI customization, phase 2
+            //  Based on Variation flag, changes Nick format in conversation view
+            //  removes arrow sign and append only a seperator.
+
+            // read variation flag values
+            TInt requireUserIdentity = IMUtils::IntResourceValueL( RSC_CHAT_VARIATION_SHOW_USER_IDENTITY );
+            // and check dynamic features
+            if ( !requireUserIdentity )
+                {
+                CCAPicture* pic = new( ELeave ) CCAPicture( iMap,
+                                                            iToMe );
+                TPictureHeader header;
+                header.iPicture = TSwizzle<CPicture>( pic );
+                iRichText->CancelInsertCharFormat(); // to prevent ETEXT 31 panic
+                iRichText->InsertL( nickStart, header ); // takes ownership
+                iRichText->InsertL( nickStart + 1, KSeparator );
+                nickEnd = 1;
+                }
+            else
+                {
+                iRichText->InsertL( nickStart, KSeparator );
+                nickEnd = 0;
+                }
+            }
+        else if ( sender.Length() > 0 )
+            {
+            // this is normal group message (or p2p message if icons are not used),
+            // insert sender and separator
+            iRichText->InsertL( nickStart, sender );
+            nickEnd = nickStart + sender.Length();
+            iRichText->InsertL( nickEnd, KSeparator );
+            }
+
+        // formatting (bold nickname)
+        nickSel.SetSelection( nickStart, nickEnd );
+        if ( nickSel.Length() > 0 )
+            {
+            BoldL( nickSel );
+            }
+        }
+    return nickSel;
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::LayoutChangedL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCARichTextContainer::LayoutChangedL( TInt /*aType*/ )
+    {
+    UpdateSkinnedTextColourL();
+    if ( Highlighted() )
+        {
+        ChangeHighlightColorL();
+        }
+    }
+
+TInt CCARichTextContainer::IntResourceValueL( TInt aResourceId )
+    {
+    // Show user Identity, if variated so
+    TResourceReader reader;
+    TInt value( KErrNone );
+    CCoeEnv::Static()->CreateResourceReaderLC( reader, aResourceId );
+    value = ResourceUtils::ReadTInt32L( reader );
+    CleanupStack::PopAndDestroy(); // reader
+
+    return value;
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::AddMessageL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCARichTextContainer::AddMessageL( MCAConversationMessage& aMessage )
+    {
+    if ( !iShowTimeStamps &&
+         aMessage.SystemMessageType() == TEnumsPC::ESystemMessageDateChange )
+        {
+        // if timestamp setting is OFF we don't show day change items
+        return;
+        }
+
+    TInt oldCount = iMessages.Count();
+
+    // create wrapper
+    CCAMessageWrapper* wrapper = CCAMessageWrapper::NewL( aMessage, *this );
+
+    CleanupStack::PushL( wrapper );
+    iMessages.AppendL( wrapper );   // takes the ownership
+    CleanupStack::Pop( wrapper );
+
+    if ( aMessage.ContentType() == TEnumsPC::EContentPicture )
+        {
+        if ( IMUtils::ContentProtectedL( aMessage.ContentData() ) )
+            {
+            aMessage.SetProcessState( TEnumsPC::EContentNotSupported );
+            }
+        else
+            {
+            // add thumbnail processor for message
+            aMessage.AddContentProcessorL( iThumbSize );
+
+            // If this is recorded chat container (iScrollOver == EFalse)
+            // and added message was first move highlight
+            if ( oldCount == 0 && !iScrollOver )
+                {
+                iMsgAddedToContentProcessor = 1;
+                }
+            }
+        }
+
+    // start new paragraph
+    TInt lineStart = iRichText->DocumentLength();
+    if ( lineStart != 0 )
+        {
+        iRichText->InsertL( lineStart, CEditableText::EParagraphDelimiter );
+        }
+
+    // Set Alignment from local layout
+    iRichText->InsertL( iRichText->DocumentLength(),
+                        AknLayoutUtils::LayoutMirrored() ? KUnicodeRLM : KUnicodeLRM );
+
+    // add message to rich text
+    TInt startPos( iRichText->DocumentLength() );
+
+    //	IM client UI customization, phase 2
+    //  Based on Variation flag, enables User Identity with Time Stamp
+    //  in chat conversation view.
+
+    // read variation flag values
+    TInt requireUserIdentity = IMUtils::IntResourceValueL( RSC_CHAT_VARIATION_SHOW_USER_IDENTITY );
+    // and check dynamic features
+    if ( requireUserIdentity )
+        {
+        TCursorSelection userSel = AddUserIdentityL( *wrapper );
+        }
+
+    TCursorSelection timeSel = AddTimeStampL( *wrapper );
+    TCursorSelection nickSel = AddNickL( *wrapper );
+    AddContentL( startPos, *wrapper );
+    TInt endPos( iRichText->DocumentLength() );
+
+    // set selection for highlight and the whole selection
+    // (so that this can be removed)
+    // append deletioncount to new messages
+    wrapper->Selection().SetSelection(    endPos - 1, startPos );
+    wrapper->WholeSelection().SetSelection( endPos, lineStart );
+    wrapper->MessageSelection().SetSelection( endPos - 1, nickSel.HigherPos() );
+
+    CHAT_DP( D_CHAT_LIT( "owncol: %d msgcol: %d" ), iOwnMsgColorInUse, iMsgColorInUse );
+
+    // append coloring
+    TCursorSelection& sel = iColorWholeMessage ? wrapper->Selection() : nickSel;
+    TInt len( sel.Length() );
+    CHAT_DP( D_CHAT_LIT( "selectiong length %d" ), len );
+
+    // Make sure the background (highlight) is not copied from
+    // previous message.
+    BackColorL( sel, KRgbWhite );
+    TextBackColorL( sel, KRgbWhite );
+
+    if ( len > 0 &&
+         aMessage.MessageType() != TEnumsPC::EMessageSystem )
+        {
+        // custom colors
+        if ( aMessage.MessagerType() == TEnumsPC::EMessageSent )
+            {
+            // own msg
+            if ( iOwnMsgColorInUse )
+                {
+                TextColorL( sel, iOwnMsgColor );
+                }
+            else
+                {
+                //default color
+                TextColorL( sel, iDefaultMsgColor );
+                }
+            }
+        else if ( aMessage.MessagerType() == TEnumsPC::EMessageReceived )
+            {
+            // other msg
+            if ( iMsgColorInUse )
+                {
+                TextColorL( sel, iMsgColor );
+                }
+            else
+                {
+                //default color
+                TextColorL( sel, iDefaultMsgColor );
+                }
+            }
+
+        }
+
+
+    // inform of inserted rich text
+    TCursorSelection curSel( CurrentSelection() );
+    TRAPD( error, iTextView.HandleAdditionL( lineStart == 0, curSel, EFalse ) );
+    if ( error != KErrNone )
+        {
+        CHAT_DP_TXT( "CCARichTextContainer::AddMessageL: Recovering from error" );
+
+        // Remove failed text
+        TCursorSelection del = wrapper->WholeSelection();
+        iRichText->DeleteL( del.LowerPos(), del.Length() );
+
+        if ( error == KErrNoMemory )
+            {
+            // If OOM => stop processing all our pending messages
+            iRecoveringFromOOM = ETrue;
+            TInt count = iMessages.Count();
+            for ( TInt i = count - 1; i >= 0; --i )
+                {
+                TRAP_IGNORE( iMessages[i]->Message().RemoveProcessingL() );
+                }
+            iRecoveringFromOOM = EFalse;
+            }
+        else
+            {
+            TRAP_IGNORE( wrapper->Message().RemoveProcessingL() );
+            }
+
+        // Remove the failed wrapper and leave
+        TInt index = iMessages.Find( wrapper );
+        if ( index != KErrNotFound )
+            {
+            delete wrapper;
+            iMessages.Remove( index );
+            }
+
+        // Try to handle changes once more
+        TRAPD( updateErr, iTextView.HandleGlobalChangeNoRedrawL() );
+        if ( !updateErr )
+            {
+            TCursorSelection curSel( CurrentSelection() );
+            TRAP_IGNORE( iTextView.ScrollVisibleL( curSel, EFalse ) );
+            }
+        User::Leave( error );
+        }
+
+    // and scroll (unless in highlight-mode)
+    if ( iHighlightState == ENoHighlight )
+        {
+        TCursorSelection curSel( CurrentSelection() );
+        iTextView.ScrollVisibleL( curSel, EFalse );
+
+        // If this is recorded chat container (iScrollOver == EFalse)
+        // and added message was first move highlight
+        // so we have focus on the topmost item.
+        if ( oldCount == 0 && !iScrollOver )
+            {
+            if ( !iMsgAddedToContentProcessor )
+                {
+                MoveHighlightL( ENext );
+                }
+            if ( iAddMsgObserver )
+                {
+                iAddMsgObserver->HandleMessageAddedL( iMessages.Count() );
+                }
+            }
+
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::MessageChangedL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCARichTextContainer::MessageChangedL( TInt aIndex )
+    {
+    CHAT_DP_FUNC_ENTER( "CCARichTextContainer::MessageChangedL" );
+    __CHAT_ASSERT_DEBUG( aIndex >= 0 && aIndex < iMessages.Count() );
+
+    if ( iRecoveringFromOOM )
+        {
+        // Don't handle changes if we had OOM situation.
+        return;
+        }
+
+    CCAMessageWrapper* wrapper = iMessages[ aIndex ];
+
+    // we don't know what's changed, so update whole message
+
+    TCursorSelection& thumbPos = wrapper->ThumbPos();
+    if ( thumbPos.iAnchorPos != 0 )
+        {
+        TInt oldLength( thumbPos.Length() );
+
+        // update thumbnail
+        if ( thumbPos.Length() > 0 )
+            {
+            // delete old thumb
+            iRichText->DeleteL( thumbPos.iAnchorPos, oldLength );
+
+            TCursorSelection& sel = wrapper->Selection();
+            TCursorSelection& wholeSel = wrapper->WholeSelection();
+
+            sel.iCursorPos -= thumbPos.Length();
+            wholeSel.iCursorPos -= thumbPos.Length();
+            }
+        AddThumbL( thumbPos.iAnchorPos, *wrapper );
+        TInt newLength = wrapper->ThumbPos().Length();
+
+        // if there are messages after this one,
+        // change the selections of those so that they
+        // are correct after we've added some characters
+        UpdateWrappers( aIndex + 1, newLength - oldLength );
+
+        // inform of deleted and inserted text
+        if ( !wrapper->IsInserted() )
+            {
+            iTextView.HandleInsertDeleteL( wrapper->ThumbPos(), oldLength );
+            }
+        }
+
+    if ( !wrapper->IsInserted() )
+        {
+        iTextView.HandleFormatChangedL( wrapper->Selection(),
+                                        iHighlightState != ENoHighlight );
+        }
+    else
+        {
+        // HandleGlobalChangeNoRedrawL worked before, but not anymore.. dunno why.
+        // We have to use this instead.
+        TCursorSelection sel = CurrentSelection();
+        iTextView.HandleAdditionL( ETrue, sel, EFalse );
+        }
+
+    // Scroll view correctly
+    TCursorSelection sel = CurrentSelection();
+    iTextView.ScrollVisibleL( sel, EFalse );
+
+    //Messages whose content are images
+    //have completed the processing
+    if ( iMsgAddedToContentProcessor )
+        {
+        //decrement the messages which has completed processing
+        iMsgAddedToContentProcessor--;
+
+        if ( !iScrollOver )
+            {
+            //only for recorded chats iScrollOver=EFalse
+            //put the focus on the first item
+            MoveHighlightL( ENext );
+            }
+
+        else
+            {
+            //when user navigate among tab.
+            //for conversations/groupview
+            if ( ( iHighlightState == ENoHighlight ) &&
+                 !iMsgAddedToContentProcessor &&
+                 iAddMsgObserver )
+                {
+                iAddMsgObserver->HandleMessageAddedL( iMessages.Count() );
+                }
+            }
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::RemoveMessage
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCARichTextContainer::RemoveMessage( TInt aIndex )
+    {
+    __CHAT_ASSERT_DEBUG( aIndex >= 0 && aIndex < iMessages.Count() );
+    CCAMessageWrapper* wrapper = iMessages[ aIndex ];
+
+    TCursorSelection& sel = wrapper->WholeSelection();
+    TInt selectionLength( sel.Length() );
+
+    TRAPD( err, iRichText->DeleteL( sel.LowerPos(), selectionLength ) )
+    if ( err != KErrNone )
+        {
+        // nothing else we could do if the rich text deletion,
+        // for some reason, didn't succeed.
+        CActiveScheduler::Current()->Error( err );
+        }
+    else
+        {
+        // inform viewer of deletion
+        TCursorSelection startPos( sel.LowerPos(), sel.LowerPos() );
+        TRAPD( err, iTextView.HandleInsertDeleteL( startPos, selectionLength ) );
+        if ( err != KErrNone )
+            {
+            CActiveScheduler::Current()->Error( err );
+            }
+        iTextView.Redraw();
+
+        // message deleted from rich text, we must update the
+        // positions of all messages after this one
+        UpdateWrappers( aIndex + 1, -selectionLength );
+
+        // delete wrapper
+        delete wrapper;
+        iMessages.Remove( aIndex );
+
+        // check selection
+        TInt count( iMessages.Count() );
+        if ( iSelected >= count )
+            {
+            iSelected = count - 1;
+            if ( iSelected < 0 )
+                {
+                // no messages, nothing to highlight
+                iSelected = 0;
+                TRAPD( err, DisableHighlightL() );
+                if ( err != KErrNone )
+                    {
+                    CActiveScheduler::Current()->Error( err );
+                    }
+                }
+            }
+
+        // check scroll position
+        TCursorSelection scroll( iTextView.ScrollSelection() );
+        TInt docLen( iRichText->DocumentLength() );
+        if ( scroll.HigherPos() >= docLen && docLen ) // no need for scroll with zero doclen
+            {
+            // update if it was wrong
+            scroll.iAnchorPos = docLen - 1;
+            scroll.iCursorPos = docLen - 1;
+            TRAPD( err, iTextView.ScrollVisibleL( scroll, EFalse ) );
+            if ( err != KErrNone )
+                {
+                CActiveScheduler::Current()->Error( err );
+                }
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::IsDeleted
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CCARichTextContainer::IsDeleted() const
+    {
+    return iMessagesDeleted;
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::MarkDeleted
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCARichTextContainer::MarkDeleted()
+    {
+    iMessagesDeleted = ETrue;
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::InsertMessageL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCARichTextContainer::InsertMessageL( MCAConversationMessage& aMessage )
+    {
+    if ( !iShowTimeStamps &&
+         aMessage.SystemMessageType() == TEnumsPC::ESystemMessageDateChange )
+        {
+        // if timestamp setting is OFF we don't show day change items
+        return;
+        }
+    // create wrapper
+    CCAMessageWrapper* wrapper = CCAMessageWrapper::NewL( aMessage, *this );
+
+    CleanupStack::PushL( wrapper );
+    iMessages.InsertL( wrapper, 0 ); // takes the ownership
+    CleanupStack::Pop( wrapper );
+
+    if ( aMessage.ContentType() == TEnumsPC::EContentPicture )
+        {
+        if ( IMUtils::ContentProtectedL( aMessage.ContentData() ) )
+            {
+            aMessage.SetProcessState( TEnumsPC::EContentNotSupported );
+            }
+        else
+            {
+            // add thumbnail processor for message
+            aMessage.AddContentProcessorL( iThumbSize );
+
+            //once any message added to the content processor
+            //increment this iMsgAddedToContentProcessor
+            iMsgAddedToContentProcessor++;
+
+            }
+        }
+
+    TInt oldLen = iRichText->DocumentLength();
+
+    // Insert paragraph break if this is not the last message
+    TInt paraBreak = 0;
+    if ( iMessages.Count() > 1 )
+        {
+        iRichText->InsertL( 0, CEditableText::EParagraphDelimiter );
+        paraBreak = 1;
+        }
+
+    // Insert message to rich text in reverse order compared to adding
+    TInt contentLen = InsertContentL( *wrapper );
+    TCursorSelection nickSel = InsertNickL( *wrapper );
+    TCursorSelection timeSel = InsertTimeStampL( *wrapper );
+    //	IM client UI customization, phase 2
+    //  Based on Variation flag, enables User Identity with Time Stamp
+    //  in chat conversation view.
+
+    // read variation flag values
+    TInt requireUserIdentity = IMUtils::IntResourceValueL( RSC_CHAT_VARIATION_SHOW_USER_IDENTITY );
+    TCursorSelection userSel;
+    if ( requireUserIdentity )
+        {
+        userSel = InsertUserIdentityL( *wrapper );
+        }
+
+    TInt dirChrLen = iRichText->DocumentLength();
+    iRichText->InsertL( 0, AknLayoutUtils::LayoutMirrored() ?
+                        KUnicodeRLM : KUnicodeLRM );
+    dirChrLen = iRichText->DocumentLength() - dirChrLen;
+
+    wrapper->SetInserted( ETrue );
+
+    // read variation flag values
+    //TInt needUserIdentity = IntResourceValueL(RSC_CHAT_VARIATION_SHOW_USER_IDENTITY);
+    TInt needUserIdentity = IMUtils::IntResourceValueL( RSC_CHAT_VARIATION_SHOW_USER_IDENTITY );
+    if ( needUserIdentity )
+        {
+        // Update user selection
+        userSel.iAnchorPos += dirChrLen;
+        userSel.iCursorPos += dirChrLen;
+        // Update timestamp selection
+        timeSel.iAnchorPos += userSel.HigherPos();
+        timeSel.iCursorPos += userSel.HigherPos();
+        // Update nick selection
+        nickSel.iAnchorPos += timeSel.HigherPos();
+        nickSel.iCursorPos += timeSel.HigherPos();
+        }
+    else
+        {
+        // Update timestamp selection
+        timeSel.iAnchorPos += dirChrLen;
+        timeSel.iCursorPos += dirChrLen;
+        // Update nick selection
+        nickSel.iAnchorPos += timeSel.HigherPos();
+        nickSel.iCursorPos += timeSel.HigherPos();
+        }
+    // Update thumb pos
+    TCursorSelection& thumbPos = wrapper->ThumbPos();
+    thumbPos.iAnchorPos += nickSel.HigherPos() + KSeparator().Length();
+    thumbPos.iCursorPos += nickSel.HigherPos() + KSeparator().Length();
+
+    TInt addedLen = iRichText->DocumentLength() - oldLen;
+
+    // parse text for highlights and store positions to messagewrapper
+    HBufC* text = HBufC::NewMaxLC( contentLen );
+    TPtr txt( text->Des() );
+    iRichText->Extract( txt,
+                        nickSel.HigherPos() + KSeparator().Length() + 1, // Don't extract separator and space
+                        contentLen );
+    ParseTextL( txt, nickSel.HigherPos() + KSeparator().Length() + 1,
+                nickSel.HigherPos() + KSeparator().Length() + 1, *wrapper );
+    CleanupStack::PopAndDestroy( text );
+
+    // Set selection for highlight and the whole selection
+    // so that this message can be removed
+    wrapper->Selection().SetSelection( addedLen - 1 - paraBreak, 0 );
+    wrapper->WholeSelection().SetSelection( addedLen - 1, 0 );
+    wrapper->MessageSelection().SetSelection( addedLen - 1,
+                                              nickSel.HigherPos() + 1 );
+
+    if ( iHighlightState != ENoHighlight )
+        {
+        BackColorL( wrapper->WholeSelection(), KRgbWhite );
+        TextBackColorL( wrapper->WholeSelection(), KRgbWhite );
+        }
+
+    // Update wrappers after this if there is any
+    if ( iMessages.Count() > 1 )
+        {
+        UpdateWrappers( 1, addedLen );
+        }
+
+    // Append coloring
+    TCursorSelection& sel = iColorWholeMessage ? wrapper->Selection() : nickSel;
+    TInt len( sel.Length() );
+    CHAT_DP( D_CHAT_LIT( "selectiong length %d" ), len );
+
+    if ( len > 0 &&
+         aMessage.MessageType() != TEnumsPC::EMessageSystem )
+        {
+        // Custom colors
+        if ( aMessage.MessagerType() == TEnumsPC::EMessageSent )
+            {
+            // Own msg
+            if ( iOwnMsgColorInUse )
+                {
+                TextColorL( sel, iOwnMsgColor );
+                }
+            else
+                {
+                //default color
+                TextColorL( sel, iDefaultMsgColor );
+                }
+
+            }
+        else if ( aMessage.MessagerType() == TEnumsPC::EMessageReceived )
+            {
+            // Other msg
+            if ( iMsgColorInUse )
+                {
+                TextColorL( sel, iMsgColor );
+                }
+            else
+                {
+                //default color
+                TextColorL( sel, iDefaultMsgColor );
+                }
+            }
+        }
+
+    if ( len > 0 &&
+         aMessage.MessageType() == TEnumsPC::EMessageSystem )
+        {
+        TextColorL( sel, iDefaultMsgColor );
+        }
+    // Inform of inserted rich text
+    TInt error = KErrNone;
+    if ( oldLen == 0 )
+        {
+        TCursorSelection curSel( CurrentSelection() );
+        // First message inserted, format the whole text
+        TRAP( error, iTextView.HandleAdditionL( ETrue, curSel, EFalse ) );
+        }
+    else
+        {
+        TCursorSelection curSel( CurrentSelection() );
+        // There might be a faster method to handle text addition, but
+        // this works for now.
+        TRAP( error, iTextView.HandleAdditionL( ETrue, curSel, EFalse ) );
+        }
+
+    if ( error != KErrNone )
+        {
+        // Remove the failed wrapper and leave
+        wrapper->Message().RemoveProcessingL();
+        TInt index = iMessages.Find( wrapper );
+        if ( index != KErrNotFound )
+            {
+            delete wrapper;
+            iMessages.Remove( index );
+            }
+        User::Leave( error );
+        }
+
+    // And scroll (unless in highlight-mode)
+    if ( iHighlightState == ENoHighlight )
+        {
+        TCursorSelection curSel( CurrentSelection() );
+        iTextView.ScrollVisibleL( curSel, EFalse );
+
+        //if no messages are being processed for the content
+        //i.e., all messages are text messages
+        if ( !iMsgAddedToContentProcessor && iAddMsgObserver )
+            {
+            iAddMsgObserver->HandleMessageAddedL( iMessages.Count() );
+            }
+        }
+    else
+        {
+        // In highlight mode, message inserted -> increase selected
+        // message index and previous selection indexes
+        iSelected++;
+        iPrevious.iAnchorPos += addedLen;
+        iPrevious.iCursorPos += addedLen;
+
+        TCursorSelection curSel( CurrentSelection() );
+        iTextView.ScrollVisibleL( curSel, EFalse );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::UpdateWrappers
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCARichTextContainer::UpdateWrappers( TInt aFirstIndex, TInt aChange )
+    {
+    TInt count( iMessages.Count() );
+    for ( TInt i( aFirstIndex ); i < count; ++i )
+        {
+        CCAMessageWrapper* wrapper = iMessages[i];
+        TCursorSelection& selection = wrapper->Selection();
+        TCursorSelection& wholeSelection = wrapper->WholeSelection();
+        TCursorSelection& thumbPos = wrapper->ThumbPos();
+        selection.iAnchorPos += aChange;
+        selection.iCursorPos += aChange;
+        wholeSelection.iAnchorPos += aChange;
+        wholeSelection.iCursorPos += aChange;
+        thumbPos.iAnchorPos += aChange;
+        thumbPos.iCursorPos += aChange;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::Union
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TCursorSelection CCARichTextContainer::Union( const TCursorSelection& aSel1,
+                                              const TCursorSelection& aSel2 )
+    {
+    // make union of selections
+    TCursorSelection changed;
+    changed.iAnchorPos = aSel1.LowerPos();
+    changed.iCursorPos = aSel1.HigherPos();
+
+    TInt low(  aSel2.LowerPos() );
+    TInt high( aSel2.HigherPos() );
+    if ( low < changed.iAnchorPos )
+        {
+        changed.iAnchorPos = low;
+        }
+    if ( high > changed.iCursorPos )
+        {
+        changed.iCursorPos = high;
+        }
+
+    return changed;
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::CurrentSelection
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TCursorSelection CCARichTextContainer::CurrentSelection() const
+    {
+    TCursorSelection sel( 0, 0 );
+    if ( iHighlightState == ENoHighlight )
+        {
+        // if nothing highlighted, return last message
+        TInt count( iMessages.Count() );
+        if ( count > 0 )
+            {
+            sel = iMessages[count-1]->Selection();
+            }
+        }
+    else
+        {
+        // something highlighted, start with current message
+        sel = iMessages[iSelected]->Selection();
+
+        // check if the highlighted selection is item inside message
+        if ( iHighlightState == EItemSelected )
+            {
+            // calculate item highlight position
+            TCursorSelection itemSel(
+                iMessages[iSelected]->Highlights()[iSelectedItem] );
+
+            TInt messageStart( sel.LowerPos() );
+            sel.iAnchorPos = itemSel.iAnchorPos + messageStart;
+            sel.iCursorPos = itemSel.iCursorPos + messageStart;
+            }
+        }
+
+    return sel;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::TextBackColorL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCARichTextContainer::TextBackColorL( const TCursorSelection& aSel,
+                                           const TRgb& aColor )
+    {
+#ifdef _DEBUG
+    TInt len( iRichText->DocumentLength() );
+    CHAT_DP( D_CHAT_LIT(
+                 "CCARichTextContainer::TextBackColorL selection: %d,%d, textlen %d" ),
+             aSel.iAnchorPos, aSel.iCursorPos, len );
+#endif //_DEBUG
+
+    TCharFormat charFormat;
+    TCharFormatMask charFormatMask;
+    charFormatMask.SetAttrib( EAttFontHighlightColor );
+    charFormatMask.SetAttrib( EAttFontHighlightStyle );
+
+    charFormat.iFontPresentation.iHighlightColor = aColor;
+    charFormat.iFontPresentation.iHighlightStyle = aColor == KRgbWhite ?
+                                                   TFontPresentation::EFontHighlightNone :
+                                                   TFontPresentation::EFontHighlightNormal;
+
+    iRichText->ApplyCharFormatL( charFormat, charFormatMask,
+                                 aSel.LowerPos(),
+                                 aSel.Length() );
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::TextColorL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCARichTextContainer::TextColorL( const TCursorSelection& aSel,
+                                       const TRgb& aColor )
+    {
+#ifdef _DEBUG
+    TInt len( iRichText->DocumentLength() );
+    CHAT_DP( D_CHAT_LIT(
+                 "CCARichTextContainer::TextColorL selection: %d,%d, textlen %d" ),
+             aSel.iAnchorPos, aSel.iCursorPos, len );
+#endif //_DEBUG
+    TCharFormat charFormat;
+    TCharFormatMask charFormatMask;
+    charFormatMask.SetAttrib( EAttColor );
+    charFormat.iFontPresentation.iTextColor = aColor;
+
+    iRichText->ApplyCharFormatL( charFormat, charFormatMask,
+                                 aSel.LowerPos(),
+                                 aSel.Length() );
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::BackColorL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCARichTextContainer::BackColorL( const TCursorSelection& aSel,
+                                       const TRgb& aColor )
+    {
+#ifdef _DEBUG
+    TInt len( iRichText->DocumentLength() );
+    CHAT_DP( D_CHAT_LIT(
+                 "CCARichTextContainer::BackColorL selection: %d,%d, textlen %d" ),
+             aSel.iAnchorPos, aSel.iCursorPos, len );
+#endif //_DEBUG
+
+    CParaFormat paraFormat;
+    TParaFormatMask paraFormatMask;
+    paraFormatMask.SetAttrib( EAttFillColor );
+
+    paraFormat.iFillColor = aColor;
+    iRichText->ApplyParaFormatL( &paraFormat, paraFormatMask,
+                                 aSel.LowerPos(),
+                                 aSel.Length() );
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::HighLightItemL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCARichTextContainer::HighLightItemL( const TCursorSelection& aSel )
+    {
+#ifdef _DEBUG
+    TInt len( iRichText->DocumentLength() );
+    CHAT_DP( D_CHAT_LIT(
+                 "CCARichTextContainer::HighLightItemL selection: %d,%d, textlen %d" ),
+             aSel.iAnchorPos, aSel.iCursorPos, len );
+#endif //_DEBUG
+
+    TCharFormat charFormat;
+    TCharFormatMask charFormatMask;
+    charFormatMask.SetAttrib( EAttFontUnderline );
+
+    charFormat.iFontPresentation.iUnderline = EUnderlineOn;
+
+    iRichText->ApplyCharFormatL( charFormat, charFormatMask,
+                                 aSel.LowerPos(),
+                                 aSel.Length() );
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::BoldL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCARichTextContainer::BoldL( const TCursorSelection& aSel )
+    {
+#ifdef _DEBUG
+    TInt len( iRichText->DocumentLength() );
+    CHAT_DP( D_CHAT_LIT(
+                 "CCARichTextContainer::BoldL selection: %d,%d, textlen %d" ),
+             aSel.iAnchorPos, aSel.iCursorPos, len );
+#endif //_DEBUG
+
+    TCharFormat charFormat;
+    TCharFormatMask charFormatMask;
+
+    charFormat.iFontSpec.iFontStyle.SetStrokeWeight( EStrokeWeightBold );
+    charFormatMask.SetAttrib( EAttFontStrokeWeight );
+
+    iRichText->ApplyCharFormatL( charFormat, charFormatMask,
+                                 aSel.LowerPos(),
+                                 aSel.Length() );
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::ParseTextL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCARichTextContainer::ParseTextL( const TDesC& aText, TInt aStartPos,
+                                       TInt aRelativePos, CCAMessageWrapper& aMessageWrapper )
+    {
+    CFindItemEngine* findItem = CFindItemEngine::NewL( aText,
+                                                       CFindItemEngine::TFindItemSearchCase(
+                                                           CFindItemEngine::EFindItemSearchPhoneNumberBin |
+                                                           CFindItemEngine::EFindItemSearchMailAddressBin |
+                                                           CFindItemEngine::EFindItemSearchURLBin/* |
+                                CFindItemEngine::EFindItemSearchScheme*/ )
+                                                     );
+
+    CleanupStack::PushL( findItem );
+
+    // reset array
+    RArray<TCursorSelection>& highlights = aMessageWrapper.Highlights();
+    RArray<TInt>& types = aMessageWrapper.HighlightTypes();
+    highlights.Reset();
+    types.Reset();
+
+    // get found items
+    const CArrayFixFlat<CFindItemEngine::SFoundItem>* items =
+        findItem->ItemArray();
+    TInt count( items->Count() );
+
+    for ( TInt i( 0 ); i < count; ++i )
+        {
+        const CFindItemEngine::SFoundItem item = items->At( i );
+
+        // selection in rich text
+        TCursorSelection realSel( aStartPos + item.iStartPos + item.iLength,
+                                  aStartPos + item.iStartPos );
+
+        // relative selection inside one message
+        TCursorSelection relativeSel( aRelativePos + item.iStartPos +
+                                      item.iLength,
+                                      aRelativePos + item.iStartPos );
+
+        highlights.AppendL( relativeSel );
+        types.AppendL( item.iItemType );
+
+        // apply highlight item formatting
+        HighLightItemL( realSel );
+        }
+
+    CleanupStack::PopAndDestroy( findItem );
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::AddNickL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TCursorSelection CCARichTextContainer::AddNickL(
+    CCAMessageWrapper& aMessageWrapper )
+    {
+
+
+    // insert nick
+    MCAConversationMessage& message = aMessageWrapper.Message();
+
+    if ( message.FailedMessage() )
+        {
+        return 	TCursorSelection( 0, 0 );
+        }
+
+    TPtrC sender;
+    TPtrC recipient;
+
+    if ( message.MessageType() == TEnumsPC::EMessageGroup ||
+         message.MessageType() == TEnumsPC::EMessageWhisper )
+        {
+        sender.Set( message.Sender() );
+        recipient.Set( message.Recipient() );
+        }
+    else
+        {
+        MCAStoredContacts* contacts =
+            CCAStorageManagerFactory::ContactListInterfaceL();
+        if ( message.MessagerType() == TEnumsPC::EMessageSent
+             && message.MessageType() != TEnumsPC::EMessageSystem )
+            {
+            sender.Set( contacts->OwnStatus().Identification() );
+            }
+        else
+            {
+            sender.Set( contacts->Identification( message.Sender() ) );
+            }
+
+        recipient.Set( contacts->Identification( message.Recipient() ) );
+        }
+    TCursorSelection nickSel( 0, 0 );
+
+    if ( message.MessagerType() == TEnumsPC::EMessageSent &&
+         message.MessageType() == TEnumsPC::EMessagePTOP &&
+         iOwnMsgIcon )
+        {
+        // this is sent (or failed) p2p message,
+        // insert "from me" icon and separator
+        // (if icons are in use)
+
+        //	IM client UI customization, phase 2
+        //  Based on Variation flag, changes Nick format in conversation view
+        //  removes arrow sign and append only a seperator.
+
+        // read variation flag values
+        TInt requireUserIdentity = IMUtils::IntResourceValueL( RSC_CHAT_VARIATION_SHOW_USER_IDENTITY );
+        // and check dynamic features
+        if ( !requireUserIdentity )
+            {
+            CCAPicture* pic = new( ELeave )CCAPicture( iMap, iFromMe );
+            TPictureHeader header;
+            header.iPicture = TSwizzle<CPicture>( pic );
+            iRichText->CancelInsertCharFormat();    // to prevent ETEXT 31 panic
+            iRichText->InsertL( iRichText->DocumentLength(), header ); // takes ownership
+            }
+        iRichText->InsertL( iRichText->DocumentLength(), KSeparator );
+        }
+    else
+        {
+        TInt nickStart( iRichText->DocumentLength() );
+        TInt nickEnd( nickStart );
+
+        if ( message.MessageType() == TEnumsPC::EMessageWhisper )
+            {
+            // This is received whisper message (to us),
+            // insert sender, "to me" icon and separator
+            iRichText->InsertL( nickStart, sender );
+            nickEnd = iRichText->DocumentLength();
+
+            CCAPicture* pic = NULL;
+            if ( message.MessagerType() == TEnumsPC::EMessageSent )
+                {
+                pic = new( ELeave )CCAPicture( iMap,
+                                               iFromMe );
+                }
+            else
+                {
+                pic = new( ELeave )CCAPicture( iMap,
+                                               iToMe );
+                }
+            TPictureHeader header;
+            header.iPicture = TSwizzle<CPicture>( pic );
+            iRichText->CancelInsertCharFormat(); // to prevent ETEXT 31 panic
+            iRichText->InsertL( nickEnd, header ); // takes ownership
+            iRichText->InsertL( iRichText->DocumentLength(), recipient );
+            nickEnd = iRichText->DocumentLength();
+            iRichText->InsertL( iRichText->DocumentLength(), KSeparator );
+            }
+        else if ( message.MessageType() == TEnumsPC::EMessagePTOP &&
+                  message.MessagerType() == TEnumsPC::EMessageReceived &&
+                  iMsgIcon )
+            {
+            // received p2p message and we want to display icon
+            // insert "to me" icon and separator
+            //	IM client UI customization, phase 2
+            //  Based on Variation flag, changes Nick format in conversation view
+            //  removes arrow sign and append only a seperator.
+
+            // read variation flag values
+            TInt requireUserIdentity = IMUtils::IntResourceValueL( RSC_CHAT_VARIATION_SHOW_USER_IDENTITY );
+            // and check dynamic features
+            if ( !requireUserIdentity )
+                {
+                CCAPicture* pic = new( ELeave )CCAPicture( iMap,
+                                                           iToMe );
+                TPictureHeader header;
+                header.iPicture = TSwizzle<CPicture>( pic );
+                iRichText->CancelInsertCharFormat(); // to prevent ETEXT 31 panic
+                iRichText->InsertL( iRichText->DocumentLength(), header ); // takes ownership
+                }
+            nickEnd = iRichText->DocumentLength();
+            iRichText->InsertL( iRichText->DocumentLength(), KSeparator );
+            }
+        else if ( sender.Length() > 0 )
+            {
+            // this is normal group message (or p2p message if icons are not used),
+            // insert sender and separator
+            iRichText->InsertL( nickStart, sender );
+            nickEnd = iRichText->DocumentLength();
+            iRichText->InsertL( iRichText->DocumentLength(), KSeparator );
+            }
+
+        // formatting (bold nickname)
+        nickSel.SetSelection( nickStart, nickEnd );
+        if ( nickSel.Length() > 0 )
+            {
+            BoldL( nickSel );
+            }
+        }
+    return nickSel;
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::AddTimeStampL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TCursorSelection CCARichTextContainer::AddTimeStampL(
+    CCAMessageWrapper& aMessageWrapper )
+    {
+    TInt start = iRichText->DocumentLength();
+    TCursorSelection timeSel( start, start );
+
+    if ( !iSettings.GetBoolValuePC( TEnumsPC::EShowTimeStamps, NULL ) ||
+         aMessageWrapper.Message().SystemMessageType() ==
+         TEnumsPC::ESystemMessageDateChange )
+        {
+        // 1. Setting for time stamp is OFF
+        // 2. Special case: date change don't have time stamp.
+        return timeSel;
+        }
+
+    // format time
+    HBufC* timeStamp = HBufC::NewLC( KTimeStampMaxLength + KSpace().Length() );
+    TPtr timePtr( timeStamp->Des() );
+
+    HBufC* timeStampFormat = NULL;
+    timeStampFormat = StringLoader::LoadLC( R_QTN_TIME_USUAL_WITH_ZERO );
+
+    TTime time = aMessageWrapper.Message().TimeStamp();
+    TRAPD( err, time.FormatL( timePtr, *timeStampFormat ) );
+    if ( err == KErrOverflow )
+        {
+        // Reserved text space was not enough.
+        // Adjust the KTimeStampMaxLength
+        __CHAT_ASSERT_DEBUG( EFalse );
+
+        // in release builds return without timestamp
+        CleanupStack::PopAndDestroy( 2, timeStamp ); // timeStamp, timeStampFormat
+        return timeSel;
+        }
+
+    // Convert numbers to local language
+    AknTextUtils::LanguageSpecificNumberConversion( timePtr );
+
+    // Set Alignment of Pm/Am from local setting
+    // This keeps the am/pm text close to the time.
+    timePtr.Append( AknLayoutUtils::LayoutMirrored() ?
+                    KUnicodeRLM : KUnicodeLRM );
+
+    //	IM client UI customization, phase 2
+    //  Based on Variation flag, changes Time Stamp format in conversation view.
+    //  where Time Stamp should appear in brackets.
+
+    // read variation flag values
+    TInt requireUserIdentity = IMUtils::IntResourceValueL( RSC_CHAT_VARIATION_SHOW_USER_IDENTITY );
+    // and check dynamic features
+    if ( requireUserIdentity )
+        {
+        // append time to rich text
+        timePtr.Insert( 0, _L( "(" ) );
+        timePtr.Append( _L( ")" ) );
+        timePtr.Append( KSpace );
+        }
+    else
+        {
+        timePtr.Append( KSpace );
+        }
+    iRichText->InsertL( start, timePtr );
+
+    CleanupStack::PopAndDestroy( 2, timeStamp ); // timeStamp, timeStampFormat
+    timeSel.SetSelection( start, iRichText->DocumentLength() - 1 );
+
+    // bold the time
+    if ( timeSel.Length() > 0 )
+        {
+        BoldL( timeSel );
+        }
+
+    return timeSel;
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::AddUserIdentityL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TCursorSelection CCARichTextContainer::AddUserIdentityL(
+    CCAMessageWrapper& aMessageWrapper )
+    {
+    TInt start = iRichText->DocumentLength();
+    TCursorSelection userSel( start, start );
+
+    MCAConversationMessage& message = aMessageWrapper.Message();
+    TPtrC sender;
+    TPtrC recipient;
+    MCAStoredContacts* contacts = CCAStorageManagerFactory::ContactListInterfaceL();
+    if ( message.MessagerType() == TEnumsPC::EMessageSent
+         && message.MessageType() != TEnumsPC::EMessageSystem )
+        {
+        sender.Set( contacts->OwnStatus().Identification() );
+        }
+    else
+        {
+        sender.Set( contacts->Identification( message.Sender() ) );
+        }
+    recipient.Set( contacts->Identification( message.Recipient() ) );
+
+    if ( message.MessagerType() == TEnumsPC::EMessageSent &&
+         message.MessageType() == TEnumsPC::EMessagePTOP &&
+         iOwnMsgIcon )
+        {
+        if ( sender.Length() >= KMaxLength )
+            {
+            TPtrC aTempPtr;
+            aTempPtr.Set( sender.Left( 8 ) );
+            TBuf<10> aTruncateSender( aTempPtr );
+            aTruncateSender.Append( _L( ".." ) );
+            iRichText->InsertL( start, aTruncateSender );
+            }
+        else
+            {
+            iRichText->InsertL( iRichText->DocumentLength(), sender );
+            }
+        }
+    else if ( message.MessageType() == TEnumsPC::EMessagePTOP &&
+              message.MessagerType() == TEnumsPC::EMessageReceived &&
+              iMsgIcon )
+        {
+        if ( recipient.Length() >= KMaxLength )
+            {
+            TPtrC aTempPtr;
+            aTempPtr.Set( recipient.Left( 8 ) );
+            TBuf<10> aTruncateRecipient( aTempPtr );
+            aTruncateRecipient.Append( _L( ".." ) );
+            iRichText->InsertL( iRichText->DocumentLength(), aTruncateRecipient );
+            }
+        else
+            {
+            iRichText->InsertL( iRichText->DocumentLength(), recipient );
+            }
+        }
+    iRichText->InsertL( iRichText->DocumentLength(), KSpace );
+    userSel.SetSelection( start, iRichText->DocumentLength() - 1 );
+
+    // bold the time
+    if ( userSel.Length() > 0 )
+        {
+        BoldL( userSel );
+        }
+
+    return userSel;
+    }
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::AddContentL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCARichTextContainer::AddContentL( TInt aMsgStart,
+                                        CCAMessageWrapper& aMessageWrapper )
+    {
+    MCAConversationMessage& message = aMessageWrapper.Message();
+
+    TEnumsPC::TContentType type( message.ContentType() );
+    switch ( type )
+        {
+        case TEnumsPC::EContentText:
+            {
+            // insert text
+            TPtrC msg( message.Text() );
+
+            HBufC* tempMsg = NULL;
+
+            TInt paraBreak = msg.Locate( CEditableText::EParagraphDelimiter );
+            // Replace all paragraph delimiters with line breaks
+            // to keep alingment consistent
+            if ( paraBreak != KErrNotFound )
+                {
+                tempMsg = msg.AllocLC();
+                TPtr ptr( tempMsg->Des() );
+                ptr.Zero();
+
+                ReplaceParaDelimsWithLineBreaks( msg, ptr );
+                msg.Set( ptr );
+                }
+
+            HBufC* numberConv = NULL;
+
+            // Convert numerals to local language
+            // 1) date item
+            if ( aMessageWrapper.Message().SystemMessageType() ==
+                 TEnumsPC::ESystemMessageDateChange )
+                {
+                // don't touch the original message
+                numberConv = msg.AllocLC();
+                TPtr ptr( numberConv->Des() );
+                AknTextUtils::LanguageSpecificNumberConversion( ptr );
+                msg.Set( ptr );
+                }
+
+            TInt textStart( iRichText->DocumentLength() );
+            iRichText->InsertL( textStart, msg );
+
+            // check for extensions (smileys)
+            TCursorSelection selection( iRichText->DocumentLength(),
+                                        textStart );
+            iExtensionsHandler.ConvertSelectionToExtensionL( *iRichText,
+                                                             selection );
+
+            TInt textEnd( iRichText->DocumentLength() );
+
+            // add nbs to preserve formatting
+            iRichText->InsertL( iRichText->DocumentLength(),
+                                CEditableText::EZeroWidthNoBreakSpace );
+
+            // if this is system message, it should be bold
+            if ( message.MessageType() == TEnumsPC::EMessageSystem )
+                {
+                TCursorSelection sel( textStart, textEnd );
+                BoldL( sel );
+                // System messages need different kind of alignment
+                CParaFormat paraFormat;
+                TParaFormatMask paraFormatMask;
+                paraFormat.iLeftMarginInTwips = 0;
+                paraFormatMask.SetAttrib( EAttLeftMargin );
+                iRichText->ApplyParaFormatL( &paraFormat, paraFormatMask,
+                                             textStart, sel.Length() );
+                }
+            else
+                {
+                // Apply alignment for "normal" messages
+                CParaFormat paraFormat;
+                TParaFormatMask paraFormatMask;
+                paraFormat.iLeftMarginInTwips = 100;
+                paraFormatMask.SetAttrib( EAttLeftMargin );
+                iRichText->ApplyParaFormatL( &paraFormat, paraFormatMask,
+                                             textStart, textEnd - textStart );
+                }
+
+            // parse text for highlights and store positions to messagewrapper
+            HBufC* text = HBufC::NewMaxLC( textEnd - textStart );
+            TPtr txt( text->Des() );
+            iRichText->Extract( txt, textStart, textEnd - textStart );
+            ParseTextL( txt, textStart, textStart - aMsgStart, aMessageWrapper );
+            CleanupStack::PopAndDestroy( text );
+
+            // Cleanup
+            if ( numberConv )
+                {
+                CleanupStack::PopAndDestroy( numberConv );
+                }
+            if ( tempMsg )
+                {
+                CleanupStack::PopAndDestroy( tempMsg );
+                }
+            break;
+            }
+        case TEnumsPC::EContentPicture: // Flowthrough
+        case TEnumsPC::EContentOther:
+            {
+            // insert thumbnail (if it's ready)
+            AddThumbL( iRichText->DocumentLength(), aMessageWrapper );
+            break;
+            }
+        case TEnumsPC::EContentInvalid:
+            {
+            break;
+            }
+        default:
+            {
+            // unsupported type
+            __CHAT_ASSERT_DEBUG( false );
+            break;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::AddThumbL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCARichTextContainer::AddThumbL( TInt aPos,
+                                      CCAMessageWrapper& aMessageWrapper )
+    {
+    TCursorSelection& thumb = aMessageWrapper.ThumbPos();
+    thumb.iAnchorPos = aPos;
+    thumb.iCursorPos = aPos;
+
+    MCAConversationMessage& message = aMessageWrapper.Message();
+    TEnumsPC::TContentType type = message.ContentType();
+    if ( type == TEnumsPC::EContentPicture ||
+         type == TEnumsPC::EContentOther )
+        {
+        // this is a content message
+        CFbsBitmap* bitmap = NULL;
+        CFbsBitmap* mask = NULL;
+        switch ( message.ContentProcessState() )
+            {
+            case TEnumsPC::EThumbnailReady:
+                {
+                // get the thumbnail from message
+                bitmap = message.Thumbnail();
+                break;
+                }
+            case TEnumsPC::EContentNotSupported:
+                {
+                bitmap = iUnsupported->Bitmap();
+                mask = iUnsupported->Mask();
+                break;
+                }
+            case TEnumsPC::EContentCorrupted:
+            case TEnumsPC::EContentNotSupportedDrm:
+                {
+                bitmap = iCorrupted->Bitmap();
+                mask = iCorrupted->Mask();
+                break;
+                }
+            default:
+                {
+                // other types do not have thumbnails.
+                return;
+                }
+            }
+
+        // create gulicon
+        CGulIcon* icon = CGulIcon::NewL( bitmap, mask );
+        //we don`t own the bitmap, just the CGulIcon
+        icon->SetBitmapsOwnedExternally( ETrue );
+        CleanupStack::PushL( icon );
+
+        // insert in to rich text
+        CCAPicture* pic = new( ELeave )CCAPicture( iMap, icon, KErrNotFound, EFalse );
+        CleanupStack::Pop( icon ); //ownership is taken by pic
+
+        TSize thumbnailSize;
+        pic->GetOriginalSizeInTwips( thumbnailSize );
+
+        CleanupStack::PushL( pic );
+        TPictureHeader header;
+        header.iPicture = TSwizzle<CPicture>( pic );
+        iRichText->CancelInsertCharFormat();    // to prevent ETEXT 31 panic
+
+        // new paragraph, image and new paragraph
+        // 1 char for EParagraphDelimiter
+        // 1 char for picture
+        // 1 char for EZeroWidthNoBreakSpace
+        // 1 char for EParagraphDelimiter
+        TInt pos = aPos;
+        iRichText->InsertL( pos++, CEditableText::EParagraphDelimiter );
+        TInt picStart = pos;
+        CleanupStack::Pop( pic );
+        iRichText->InsertL( pos++, header ); // takes ownership
+        iRichText->InsertL( pos++, CEditableText::EZeroWidthNoBreakSpace );
+        TInt picEnd = pos;
+        iRichText->InsertL( pos++, CEditableText::EParagraphDelimiter );
+
+        // store length
+        thumb.iCursorPos = pos;
+
+        // update wrapper
+        TCursorSelection& sel = aMessageWrapper.Selection();
+        TCursorSelection& wholeSel = aMessageWrapper.WholeSelection();
+        sel.iCursorPos += thumb.Length();
+        wholeSel.iCursorPos += thumb.Length();
+
+        // append formatting
+        CParaFormat paraFormat;
+        TParaFormatMask paraFormatMask;
+        paraFormat.iIndentInTwips = 0;
+        paraFormat.iLeftMarginInTwips = 100;
+        paraFormatMask.SetAttrib( EAttIndent );
+        paraFormatMask.SetAttrib( EAttLeftMargin );
+
+        paraFormat.iLineSpacingInTwips = thumbnailSize.iHeight;
+        paraFormatMask.SetAttrib( EAttLineSpacing );
+
+        // apply formatting to picture character only
+        iRichText->ApplyParaFormatL( &paraFormat, paraFormatMask, picStart,
+                                     picEnd - picStart );
+
+        CHAT_DP( D_CHAT_LIT( "*Added thumbnail to %d-%d" ),
+                 thumb.iAnchorPos, thumb.iCursorPos );
+        }
+    }
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::UpdateSkinnedTextColourL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCARichTextContainer::UpdateSkinnedTextColourL()
+    {
+    // Get current text's color
+    TRgb defaultSkinTextColor( KRgbBlack );
+    AknsUtils::GetCachedColor( AknsUtils::SkinInstance(),
+                               defaultSkinTextColor,
+                               KAknsIIDQsnTextColors,
+                               EAknsCIQsnTextColorsCG6 );
+
+    iDefaultMsgColor =  defaultSkinTextColor;
+    TCharFormat charFormat;
+    TCharFormatMask charFormatMask;
+    charFormat.iFontPresentation.iTextColor = defaultSkinTextColor;
+    charFormatMask.SetAttrib( EAttColor );
+
+    // The color settings is read from the resource file only, so IntResourceValueFromRssL is used instead of IntResourceValueL
+    TBool defaultColors = IMUtils::IntResourceValueFromRssL(
+                              RSC_CHAT_DEFAULT_MESSAGE_COLORS );
+
+    // Update text colour in all messages
+    TInt messagecount = iMessages.Count();
+    for ( TInt i = 0; i < messagecount; ++i )
+        {
+        MCAConversationMessage &msg = iMessages[ i ]->Message();
+        TCursorSelection sel( 0, 0 );
+
+        // system message use always default color
+        if ( msg.MessageType() == TEnumsPC::EMessageSystem )
+            {
+            sel = iMessages[ i ]->WholeSelection();
+            }
+        // Sent messages
+        else if ( msg.MessagerType() == TEnumsPC::EMessageSent )
+            {
+            sel = SkinColoredSelection( *iMessages[ i ],
+                                        defaultColors,
+                                        iOwnMsgColorInUse );
+            }
+        // Received messages
+        else if ( msg.MessagerType() == TEnumsPC::EMessageReceived )
+            {
+            sel = SkinColoredSelection( *iMessages[ i ],
+                                        defaultColors,
+                                        iMsgColorInUse );
+            }
+
+        // Only update texts which use default color.
+        if ( sel.Length() > 0 )
+            {
+            iRichText->ApplyCharFormatL( charFormat,
+                                         charFormatMask,
+                                         sel.LowerPos(),
+                                         sel.Length() );
+            }
+        }
+    // also appended messages should have new colour
+    iRichText->SetInsertCharFormatL( charFormat, charFormatMask, iRichText->DocumentLength() );
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::SkinColoredSelection
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TCursorSelection CCARichTextContainer::SkinColoredSelection(
+    CCAMessageWrapper& aMessageWrapper,
+    TBool aUseDefaultColors,
+    TBool aCustomDefinedColor )
+    {
+    // This logic determines which part of the message is colored by the theme
+    if ( !aCustomDefinedColor && aUseDefaultColors )
+        {
+        return aMessageWrapper.WholeSelection();
+        }
+
+    if ( !iColorWholeMessage )
+        {
+        return aMessageWrapper.MessageSelection();
+        }
+
+    return TCursorSelection( 0, 0 );
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::ReplaceParaDelimsWithLineBreaks
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCARichTextContainer::ReplaceParaDelimsWithLineBreaks(
+    const TPtrC& aSource,
+    TPtr& aTarget ) const
+    {
+#ifdef _DEBUG
+    TPtrC target;
+    target.Set( aTarget );
+    CHAT_DP( D_PLAIN_LIT( "CCARichTextContainer::ReplaceParaDelimsWithLineBreaks: target =  %S" ), &target );
+#endif
+
+    TInt paraBreak = aSource.Mid( aTarget.Length() ).Locate(
+                         CEditableText::EParagraphDelimiter );
+
+    if ( paraBreak == KErrNotFound )
+        {
+        // No more paragraph delimiters, append what's left
+        aTarget.Append( aSource.Mid( aTarget.Length() ) );
+        // And break away from recursion
+        return;
+        }
+
+    aTarget.Append( aSource.Mid( aTarget.Length(), paraBreak ) );
+    aTarget.Append( CEditableText::ELineBreak );
+
+#ifdef _DEBUG
+    target.Set( aTarget );
+    CHAT_DP( D_PLAIN_LIT( "CCARichTextContainer::ReplaceParaDelimsWithLineBreaks: target =  %S" ), &target );
+#endif
+
+    ReplaceParaDelimsWithLineBreaks( aSource, aTarget );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::GetMessageCount
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TInt CCARichTextContainer::GetMessageCount()
+    {
+    return iMessages.Count();
+    }
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::GetMessageCount
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCARichTextContainer::ChangeHighlightColorL()
+    {
+    // get the selection
+    TCursorSelection curSel( CurrentSelection() );
+
+    // remove colors from old highlight
+    TInt textLen( iRichText->DocumentLength() );
+    if ( iPrevious.iAnchorPos < textLen &&
+         iPrevious.iCursorPos <= textLen )
+        {
+        BackColorL( iPrevious, KRgbWhite );
+        TextBackColorL( iPrevious, KRgbWhite );
+        }
+
+    // and set new one
+    if ( iHighlightState == EItemSelected )
+        {
+        MAknsSkinInstance* skin = AknsUtils::SkinInstance();
+        TRgb color;
+
+        TInt error = AknsUtils::GetCachedColor( skin,
+                                                color,
+                                                KAknsIIDQsnHighlightColors,
+                                                EAknsCIQsnHighlightColorsCG2 );
+
+        if ( !error )
+            {
+            // No error, use skinned background color
+            TextBackColorL( curSel, color );
+            }
+        else
+            {
+            TextBackColorL( curSel, AKN_LAF_COLOR_STATIC( KChatHighlightColor ) );
+            }
+        }
+    else
+        {
+        MAknsSkinInstance* skin = AknsUtils::SkinInstance();
+        TRgb color;
+
+        TInt error = AknsUtils::GetCachedColor( skin,
+                                                color,
+                                                KAknsIIDQsnHighlightColors,
+                                                EAknsCIQsnHighlightColorsCG2 );
+
+        if ( !error )
+            {
+            // No error, use skinned background color
+            BackColorL( curSel, color );
+            }
+        else
+            {
+            BackColorL( curSel, AKN_LAF_COLOR_STATIC( KChatHighlightColor ) );
+            }
+        }
+
+    // handle changed format
+    TCursorSelection changed( Union( iPrevious, curSel ) );
+
+    iTextView.HandleFormatChangedL( changed );
+
+    iTextView.ScrollVisibleL( curSel, ETrue );
+
+    iPrevious = curSel;
+    }
+
+// -----------------------------------------------------------------------------
+// CCARichTextContainer::UnRegisterRichTxtCtrlObserver
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCARichTextContainer::UnRegisterRichTxtCtrlObserver()
+    {
+    iAddMsgObserver = NULL;
+    }
+
+//  End of File