/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  ESMR editor impl.
*
*/

#include "cesmreditor.h"
#include "nmrcolormanager.h"
#include "esmrfieldbuilderdef.h"
#include "esmrdef.h"
#include "mesmrlistobserver.h"

#include <txtfrmat.h>
#include <txtglobl.h>
#include <txtrich.h>
#include <gulfont.h>
#include <eikenv.h>
#include <avkon.hrh>
#include <AknUtils.h>


#include "emailtrace.h"

// ======== MEMBER FUNCTIONS ========

// ---------------------------------------------------------------------------
// CESMREditor::NewL
// ---------------------------------------------------------------------------
//
EXPORT_C CESMREditor* CESMREditor::NewL( )
    {
    FUNC_LOG;
    /*
     Default parameters for edwin. Note that as the parent
     is NULL, the edwin MUST be EOwnsWindow-type edwin.
     */
    return CESMREditor::NewL (
		NULL, // parent
		1, // number of lines
		KTextLimit, // text limit
		CEikEdwin::EResizable | CEikEdwin::EOwnsWindow );
    }

// ---------------------------------------------------------------------------
// CESMREditor::NewL
// ---------------------------------------------------------------------------
//
EXPORT_C CESMREditor* CESMREditor::NewL(
		const CCoeControl* aParent, TInt aNumberOfLines,
        TInt aTextLimit, TInt aEdwinFlags )
    {
    FUNC_LOG;
    CESMREditor* self = new (ELeave) CESMREditor();
    CleanupStack::PushL ( self );
    self->ConstructL ( aParent, aNumberOfLines, aTextLimit, aEdwinFlags );
    CleanupStack::Pop ( self );
    return self;
    }

// ---------------------------------------------------------------------------
// CESMREditor::~CESMREditor
// ---------------------------------------------------------------------------
//
EXPORT_C CESMREditor::~CESMREditor( )
    {
    FUNC_LOG;
    delete iDefaultText;
    }

// ---------------------------------------------------------------------------
// CESMREditor::PositionChanged
// ---------------------------------------------------------------------------
//
EXPORT_C void CESMREditor::PositionChanged( )
    {
    FUNC_LOG;
    CTextView* view = TextView();
    if ( view )
        {
        view->SetViewRect ( Rect() );
        }
    }

// ---------------------------------------------------------------------------
// CESMREditor::OfferKeyEventL
// ---------------------------------------------------------------------------
//
EXPORT_C TKeyResponse CESMREditor::OfferKeyEventL(
		const TKeyEvent& aKeyEvent,TEventCode aType )
    {
    FUNC_LOG;

    TKeyResponse ret = CEikRichTextEditor::OfferKeyEventL(aKeyEvent, aType);

    if ( aType == EEventKey )
        {
        TPoint firstRowExtra(0,RowHeight());
        TextLayout()->DocPosToXyPosL( 0, firstRowExtra);
        //firstRowExtra.iY
        TPoint rel(PositionRelativeToScreen());
        TPoint point(0,0);
        TextLayout()->DocPosToXyPosL( CursorPos(), point);

        // +1 because first line is zero
        TInt currentLineNumber = TextLayout()->GetLineNumber( CursorPos() ) + 1;
        TInt cursorLowerPosition = currentLineNumber * RowHeight();
        TInt cursorUpperPosition = ( currentLineNumber -1 )* RowHeight();

        if ( aKeyEvent.iCode == EKeyDownArrow && iObserver)
            {
            TPoint firstRowExtra(0,RowHeight());
            TextLayout()->DocPosToXyPosL( 0, firstRowExtra);
            TPoint cursorPos(0,0);
            TextLayout()->DocPosToXyPosL( CursorPos(), cursorPos);
            TInt edwinTlY = Position().iY;
            TInt listHeight = iObserver->ListHeight();

            // edwinTlY negative
            if ( cursorLowerPosition > ( listHeight - edwinTlY ))
                {
                iObserver->RePositionFields( -RowHeight() );
                }
            }
        else if ( aKeyEvent.iCode == EKeyUpArrow && iObserver)
            {
            TPoint firstRowExtra(0,RowHeight());
            TextLayout()->DocPosToXyPosL( 0, firstRowExtra);
            TPoint cursorPos(0,0);
            TextLayout()->DocPosToXyPosL( CursorPos(), cursorPos);
            TInt hiddenHeight = Position().iY;
            // upper corner of field not visible
            if ( hiddenHeight < 0 )
                {
                if ( (cursorPos.iY - firstRowExtra.iY * 2) < (-hiddenHeight))
                    {
                    iObserver->RePositionFields( RowHeight() );
                    }
                }
            }
        }


    return ret;
    }

// ---------------------------------------------------------------------------
// CESMREditor::FocusChanged
// ---------------------------------------------------------------------------
//
EXPORT_C void CESMREditor::FocusChanged(TDrawNow aDrawNow)
    {
    FUNC_LOG;

    CEikRichTextEditor::FocusChanged( aDrawNow );

    TRAPD( error, TryToSetSelectionL() );
    if ( error != KErrNone )
        {
        iCoeEnv->HandleError( error );// codescanner::eikonenvstatic
        }
    }

// ---------------------------------------------------------------------------
// CESMREditor::HandlePointerEventL
// ---------------------------------------------------------------------------
//

void CESMREditor::HandlePointerEventL( const TPointerEvent& aPointerEvent )
    {
    if ( Rect().Contains( aPointerEvent.iPosition ) )
        {
        switch ( aPointerEvent.iType )
            {
            case TPointerEvent::EButton1Down:
            case TPointerEvent::EButton1Up:
            	{
            	CEikRichTextEditor::HandlePointerEventL( aPointerEvent );
                break;
                }
            default:
            	break;
            }
        }
    }

// ---------------------------------------------------------------------------
// CESMREditor::TryToSetSelectionL
// ---------------------------------------------------------------------------
//
void CESMREditor::TryToSetSelectionL()
    {
    FUNC_LOG;
    if ( IsFocused() )
        {
        // set selection to text if it is the default text
        HBufC* text = GetTextInHBufL();
        if ( text )
            {
            CleanupStack::PushL( text );
            if ( iDefaultText->Compare( *text ) == KErrNone )
                {
                SetSelectionL(0, text->Length() );
                }
            CleanupStack::PopAndDestroy( text );
            }
        }
    }

// ---------------------------------------------------------------------------
// CESMREditor::HandleEdwinEventL
// ---------------------------------------------------------------------------
//
EXPORT_C void CESMREditor::HandleEdwinEventL(
		CEikEdwin* aEdwin,TEdwinEvent aEventType )
    {
    FUNC_LOG;
    if ( aEdwin == this )
        {
        switch( aEventType )
        	{
        	case EEventNavigation:
        		{
        		if ( iObserver )
        			{
        	        TInt curPos = CursorPos ();
        	        TInt textLength = TextLength();
        	        // Update viewarea scrolling in cases where the cursor location
        	        // is changed directly from bottom to upmost position or vise versa.
        	        if ( CursorPos () == TextLength() || CursorPos () == 0 )
        	            {
        	            // KErrNotFound as field id is interpret as focused field:
        	            iObserver->ScrollControlVisible( KErrNotFound );
        	            }
        			}
        		break;
        		}

        	case EEventTextUpdate:
        		{
        		if ( IsVisible() )
        			{
        			DrawDeferred();
        			}
        		break;
        		}

        	default:
        		{
        		break;
        		}
        	}
        }
    }

// ---------------------------------------------------------------------------
// CESMREditor::ClearSelectionAndSetTextL
// ---------------------------------------------------------------------------
//
EXPORT_C void CESMREditor::ClearSelectionAndSetTextL( const TDesC& aText )
    {
    FUNC_LOG;
    ClearSelectionL();
    SetCursorPosL(0, EFalse );
    SetTextL( &aText );
    SetCursorPosL(0, EFalse );
    HandleTextChangedL();
    }

// ---------------------------------------------------------------------------
// CESMREditor::SetFontL
// ---------------------------------------------------------------------------
//
EXPORT_C void CESMREditor::SetFontL( const CFont* aFont )
    {
    FUNC_LOG;
    const CFont* font = aFont;
    TFontSpec fontSpec = font->FontSpecInTwips();

    CParaFormat* paraFormat = CParaFormat::NewLC();
    TParaFormatMask paraFormatMask;
    paraFormat->iLineSpacingControl = CParaFormat::ELineSpacingExactlyInPixels;

    paraFormatMask.SetAttrib( EAttLineSpacing );
    paraFormat->iHorizontalAlignment = CParaFormat::ELeftAlign;
    if ( AknLayoutUtils::LayoutMirrored() )
        {
        paraFormat->iHorizontalAlignment = CParaFormat::ERightAlign;
        }
    paraFormatMask.SetAttrib( EAttAlignment );

    TCharFormat charFormat;
    TCharFormatMask formatMask;
    charFormat.iFontSpec = fontSpec;

    formatMask.SetAttrib( EAttFontTypeface );
    formatMask.SetAttrib( EAttFontHeight );
    formatMask.SetAttrib( EAttFontPosture );
    formatMask.SetAttrib( EAttFontStrokeWeight );
    formatMask.SetAttrib(EAttFontHighlightColor);
    formatMask.SetAttrib( EAttColor );

    charFormat.iFontPresentation.iTextColor =
        NMRColorManager::Color( NMRColorManager::EMRMainAreaTextColor );

    charFormat.iFontPresentation.iHighlightColor =
        NMRColorManager::Color( NMRColorManager::EMRCutCopyPasteHighlightColor );

    CParaFormatLayer* paraFormatLayer =
        CParaFormatLayer::NewL( paraFormat, paraFormatMask );
    CleanupStack::PushL( paraFormatLayer );
    CCharFormatLayer* charFormatLayer =
        CCharFormatLayer::NewL( charFormat, formatMask );

    SetParaFormatLayer( paraFormatLayer );
    CleanupStack::Pop( paraFormatLayer );
    CleanupStack::PopAndDestroy( paraFormat );
    SetCharFormatLayer( charFormatLayer );

    // This forces CEikEdwin::OnReformatL to notify observer
    // through HandleEdwinSizeEventL about changed size.
    // It is notified only if linecount changes.
    CEikEdwin::iNumberOfLines = 0;
    CEikEdwin::FormatTextL();
    }

// ---------------------------------------------------------------------------
// CESMREditor::CursorLinePos
// ---------------------------------------------------------------------------
//
EXPORT_C TInt CESMREditor::CursorLinePos( ) const
    {
    FUNC_LOG;
    return TextLayout()->GetLineNumber ( CursorPos ( ) );
    }

// ---------------------------------------------------------------------------
// CESMREditor::LineCount
// ---------------------------------------------------------------------------
//
EXPORT_C TInt CESMREditor::LineCount( ) const
    {
    FUNC_LOG;
    // first line is zero, that's why + 1 is added
    TInt lineCount( TextLayout()->GetLineNumber ( TextLength ( ) ) + 1 );
    return lineCount;
    }

// ---------------------------------------------------------------------------
// CESMREditor::RowHeight
// ---------------------------------------------------------------------------
//
EXPORT_C TInt CESMREditor::RowHeight()
    {
    FUNC_LOG;
    TInt bandHeight = TextLayout()->BandHeight();
    // Starts from zero, so let's increase the count by one.
    TInt lineNumberCount = TextLayout()->GetLineNumber(TextLength()) + 1;

    return ( bandHeight / lineNumberCount );
    }

// ---------------------------------------------------------------------------
// CESMREditor::CurrentLineNumber
// ---------------------------------------------------------------------------
//
EXPORT_C TInt CESMREditor::CurrentLineNumber()
    {
    FUNC_LOG;
    // first line is zero, let's increase it by one
    return TextLayout()->GetLineNumber( CursorPos() ) + 1;
    }

// ---------------------------------------------------------------------------
// CESMREditor::LineCount
// ---------------------------------------------------------------------------
//
EXPORT_C  void CESMREditor::SetDefaultTextL(
        HBufC* aDefaultText ) // codescanner::nonconsthbufc
    {
    FUNC_LOG;
    SetTextL( aDefaultText );

    if ( iDefaultText )
        {
        delete iDefaultText;
        iDefaultText = NULL;
        }
    iDefaultText = aDefaultText;
    }

// ---------------------------------------------------------------------------
// CESMREditor::LineCount
// ---------------------------------------------------------------------------
//
EXPORT_C const TDesC& CESMREditor::DefaultText()
    {
    FUNC_LOG;
    return *iDefaultText;
    }

// ---------------------------------------------------------------------------
// CESMREditor::SetListObserver
// ---------------------------------------------------------------------------
//
EXPORT_C void CESMREditor::SetListObserver( MESMRListObserver* aObserver )
    {
    FUNC_LOG;
    iObserver = aObserver;
    }

// ---------------------------------------------------------------------------
// CESMREditor::CESMREditor
// ---------------------------------------------------------------------------
//
CESMREditor::CESMREditor( )
    {
    FUNC_LOG;
    // Do nothing
    }

// ---------------------------------------------------------------------------
// CESMREditor::ConstructL
// ---------------------------------------------------------------------------
//
void CESMREditor::ConstructL(const CCoeControl* aParent, TInt aNumberOfLines,
        TInt aTextLimit, TInt aEdwinFlags )
    {
    FUNC_LOG;
    CEikRichTextEditor::ConstructL ( aParent, aNumberOfLines, aTextLimit,
            aEdwinFlags );

    AddEdwinObserverL(this);

    SetUpperFullFormattingLength( aTextLimit );

    iLimitLength = aTextLimit;
    }

// ---------------------------------------------------------------------------
// CESMREditor::GetLimitLength
// ---------------------------------------------------------------------------
//
EXPORT_C TInt CESMREditor::GetLimitLength() const
	{
    FUNC_LOG;
	return iLimitLength;
	}

//EOF
