/*
* Copyright (c) 2002-2010 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: 
*             Declares container control for application.
*
*/


// INCLUDE FILES

#include    <ussd.rsg>
#include    <aknkeys.h>
#include    <eikedwin.h>
#include    <bldvariant.hrh>
#include    <featmgr.h>
#include    <centralrepository.h>
#include    <telinternalcrkeys.h>
#include <csxhelp/ussd.hlp.hrh>  // for help context

// For skinning.
#include    <AknsBasicBackgroundControlContext.h>
#include    <AknsDrawUtils.h>
#include    <AknsUtils.h>
#include    <txtglobl.h>

#include    "telephonyvariant.hrh"
#include    "UssdComms.h"
#include    "UssdNaviPane.h"
#include    "UssdAppUi.h"
#include    "UssdContainer.h"
#include    "UssdEditorLines.h"
#include    "UssdLayout.h"
#include    "ussd.hrh"
#include    "UssdApp.h" // for applicationUID
#include    "UssdLogger.h"

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

// -----------------------------------------------------------------------------
// CUssdContainer::CUssdContainer
// C++ constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CUssdContainer::CUssdContainer( CUssdAppUi& aAppUi ): iAppUi( aAppUi )
    {
    }


// -----------------------------------------------------------------------------
// CUssdContainer::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CUssdContainer::ConstructL( const TRect& aRect )
    {
    _LOGSTRING( "CUssdContainer::ConstructL =>" )
    CreateWindowL();

    // Create background control context for skins.
    iBgContext = CAknsBasicBackgroundControlContext::NewL(
        KAknsIIDQsnBgAreaMainMessage, aRect, ETrue /*Parent absolute*/ );

    // Create editor
    iEditor = CreateEdwinL();

    // Lines
    iLines = new ( ELeave ) CUssdEditorLines;
    iLines->ConstructL( this );

    TInt featureBitmask( 0 );

    // Connecting and initialization KCRUidTelVariation
    CRepository* repository = CRepository::NewL( KCRUidTelVariation );
    CleanupStack::PushL( repository );

    // Get the value from Central Repository
    repository->Get( KTelVariationFlags, featureBitmask );
    if ( featureBitmask & KTelephonyLVFlagUssdUIRemainingChars )
        {
        iNaviPaneHandler = CUssdNaviPane::NewL( iAppUi );
        }

    CleanupStack::PopAndDestroy( repository );

    // Finish the job
    SetRect( aRect );
    ActivateL();

    iEditor->SetFocus( ETrue );
    _LOGSTRING( "CUssdContainer::ConstructL <=" )
    }


// Destructor
CUssdContainer::~CUssdContainer()
    {
    _LOGSTRING( "CUssdContainer::~CUssdContainer =>" ) 
    delete iLines;

    AknsUtils::DeregisterControlPosition( iEditor );
    delete iEditor;
    delete iNaviPaneHandler;

    delete iBgContext; // For skinning, can be deleted, NULL if not exist.
    _LOGSTRING( "CUssdContainer::~CUssdContainer <=" )
    }

// -----------------------------------------------------------------------------
// CUssdContainer::HandleEdwinEventL
// Called by framework when the Editor is changed
//
// -----------------------------------------------------------------------------
//
void CUssdContainer::HandleEdwinEventL( CEikEdwin* /*aEdwin*/,
        TEdwinEvent aEventType )
    {
     switch( aEventType )
         {
         case EEventTextUpdate:
             {
             UpdateNavipaneMsgLengthL();
             break;
             }
         default:
             break;
         }
    }
    
// -----------------------------------------------------------------------------
// CUssdContainer::SizeChanged
// Called by framework when the view size is changed
//
// -----------------------------------------------------------------------------
//
void CUssdContainer::SizeChanged()
    {
    // Backgroud context
    iBgContext->SetParentPos( PositionRelativeToScreen() );
    iBgContext->SetRect( Rect() ) ;
    // Edwin
    AknLayoutUtils::LayoutEdwin(
        iEditor,
        Rect(),
        UssdLayout::MessageWritingTexts3() );

    // We need to make some room for scrollbar to fit
    // so the editor must be narrowed down a bit.

    TAknLayoutId layout = UssdLayout::CurrentLayout();
    TRect sbr = iEditor->ScrollBarFrame()->VerticalScrollBar()->Rect();

    if( layout != EAknLayoutIdABRW )
        {
        TPoint editorTLPoint(Rect().iTl.iX, iEditor->Rect().iTl.iY);

        iEditor->SetExtent( editorTLPoint ,
                    TSize( Rect().Width() - sbr.Width(), sbr.Height() ) );
        }
    else // right to left layout
        {
        TPoint editorTLPoint( ( Rect().iTl.iX + sbr.Width() ),
                                iEditor->Rect().iTl.iY);

        iEditor->SetExtent( editorTLPoint ,
                            TSize( Rect().Width() - sbr.Width(),
                            sbr.Height() ) );
        }

    TRAP_IGNORE( UpdateNavipaneMsgLengthL() );

    // overwite inputmode in portraitmode
    if ( Rect().Height() > Rect().Width() )
        {
        iEditor->SetAknEditorCurrentInputMode( EAknEditorNumericInputMode );
        }

    // Change the colour of the edwin if needed
    MAknsSkinInstance* skin = AknsUtils::SkinInstance();
    if ( skin )
        {
        TRgb color;
        TInt error = AknsUtils::GetCachedColor(
            skin,
            color,
            KAknsIIDQsnTextColors,
            EAknsCIQsnTextColorsCG6 );

        if ( error == KErrNone )
            {
            TCharFormat charFormat;
            TCharFormatMask charFormatMask;
            ( reinterpret_cast< CGlobalText* >( iEditor->Text() ) )
                ->GetCharFormat( charFormat, charFormatMask, 0, 0 );

            charFormat.iFontPresentation.iTextColor = color;
            charFormatMask.SetAll();

            CCharFormatLayer* charFormatLayer = NULL;

            TRAP( error, charFormatLayer =
                CCharFormatLayer::NewL( charFormat,charFormatMask ) );

            if ( !error )
                {
                iEditor->SetCharFormatLayer( charFormatLayer );
                }
            }
        }

    // Set editor lines
    iLines->SetRect( Rect() );

    AknsUtils::RegisterControlPosition( iEditor );
    }


// -----------------------------------------------------------------------------
// CUssdContainer::CountComponentControls
//
//
// -----------------------------------------------------------------------------
//
TInt CUssdContainer::CountComponentControls() const
    {
    return 2; // editor and lines
    }


// -----------------------------------------------------------------------------
// CUssdContainer::ComponentControl
//
// -----------------------------------------------------------------------------
//
CCoeControl* CUssdContainer::ComponentControl( TInt aIndex ) const
    {
    switch ( aIndex )
        {
        case 0:
            return iEditor;
        case 1:
            return iLines;
        default:
            return NULL;
        }

    }


// -----------------------------------------------------------------------------
// CUssdContainer::Draw
//
// -----------------------------------------------------------------------------
//
void CUssdContainer::Draw( const TRect& aRect ) const
    {
    CWindowGc& gc = SystemGc();

    MAknsSkinInstance* skin = AknsUtils::SkinInstance();

    if ( iBgContext )
        {
        AknsDrawUtils::Background(
            skin, iBgContext, this, gc, aRect);
        }
    else
        {
        // Otherwise clear the area
        gc.SetBrushColor( AKN_LAF_COLOR( UssdLayout::LayoutColourWhite() ) );
        DrawUtils::ClearBetweenRects( gc, aRect, iEditor->Rect() );
        }
    }


// -----------------------------------------------------------------------------
// CUssdContainer::OfferKeyEventL
// -----------------------------------------------------------------------------
//
TKeyResponse CUssdContainer::OfferKeyEventL(
    const TKeyEvent& aKeyEvent, TEventCode aType )
    {
    _LOGSTRING3(
    "CUssdContainer::OfferKeyEventL =>,TKeyEvent::iCode=%d,TEventCode=%d",
    aKeyEvent.iCode, aType )
    TKeyResponse response = EKeyWasNotConsumed;

    // Special key handling comes first.
    if ( aKeyEvent.iScanCode == EStdKeyYes ) // Send key.
        {
        // The reason that the send key is handled via TStdScanCode rather than TKeyCode is that
        // we also have to be able to catch EEventKeyUp and EEventKeyDown key events in addition
        // to EEventKey. This is because TKeyEvent::iCode is always 0 when TEventCode is EEventKey.
        if ( iEditor->TextLength() )
            {
            if ( aType == EEventKey )
                {
                if ( FeatureManager::FeatureSupported( KFeatureIdHelp ) )
                    {
                    iAppUi.HandleCommandL( EUssdMenuItemSend );
                    }
                else
                    {
                    iAppUi.HandleCommandL( EUssdSoftkeySend );
                    }
                }
            response = EKeyWasConsumed; // Dialer should not be launched when the USSD string exists and send key is used.
            }
        }
    else if ( aKeyEvent.iCode == EKeyEscape )
        {
        iAppUi.HandleCommandL( EAknSoftkeyExit );
        response = EKeyWasConsumed;
        }
    else // Default keys are handled here.
        {
        response = iEditor->OfferKeyEventL( aKeyEvent, aType );

        if ( aType == EEventKey || aType == EEventKeyUp )
            {
            UpdateNavipaneMsgLengthL();
            }

        if ( !FeatureManager::FeatureSupported( KFeatureIdHelp ) )
            {
            // Change softkeys if needed.
            iAppUi.SetSoftkeySendVisibleL( iEditor->TextLength() != 0 );
            }

            iAppUi.Cba()->SetCommandSetL( R_USSD_SOFTKEYS_OPTIONS_EXIT_OPTIONS );
            iAppUi.Cba()->DrawNow();
        }
    _LOGSTRING2(
    "CUssdContainer::OfferKeyEventL <=, response=%d", response )
    return response;
    }


// -----------------------------------------------------------------------------
// CUssdContainer::Editor
// Give editor
// -----------------------------------------------------------------------------
//
CEikEdwin& CUssdContainer::Editor()
    {
    return *iEditor;
    }


// -----------------------------------------------------------------------------
// CUssdContainer::FocusChanged
//
// -----------------------------------------------------------------------------
//
void CUssdContainer::FocusChanged( TDrawNow aDrawNow )
    {
    iEditor->SetFocus( IsFocused(), aDrawNow );
    }



// -----------------------------------------------------------------------------
// CUssdContainer::GetHelpContext
// This function is called when Help application is launched.
//
// -----------------------------------------------------------------------------
//
void CUssdContainer::GetHelpContext(
    TCoeHelpContext& aContext ) const
    {
    // If help defined.
    if ( FeatureManager::FeatureSupported( KFeatureIdHelp ) )
        {
        aContext.iMajor = KUidussd;
        aContext.iContext = KUSSD_HLP_EDITOR;
        }

    // If help not defined, do nothing
    }



// -----------------------------------------------------------------------------
// CUssdContainer::HandleResourceChange
// This function is called when Help application is launched.
//
// -----------------------------------------------------------------------------
//
void CUssdContainer::HandleResourceChange( TInt aType )
    {
    switch ( aType )
        {
        case KEikColorResourceChange:
        case KAknsMessageSkinChange:
            {
            SizeChanged();
            DrawDeferred();
            break;
            }

        default:
            {
            CCoeControl::HandleResourceChange( aType );
            }
        }
    }


// -----------------------------------------------------------------------------
// CUssdContainer::MopSupplyObject
//
// -----------------------------------------------------------------------------
//
TTypeUid::Ptr CUssdContainer::MopSupplyObject( TTypeUid aId )
    {
    if ( aId.iUid == MAknsControlContext::ETypeId )
        {
        return MAknsControlContext::SupplyMopObject( aId, iBgContext );
        }
    return CCoeControl::MopSupplyObject( aId );
    }


// -----------------------------------------------------------------------------
// CUssdContainer::CreateEdwinL
// Creates new edwin
//
// -----------------------------------------------------------------------------
//
CEikEdwin* CUssdContainer::CreateEdwinL()
    {
    CEikEdwin* newEditor = new ( ELeave ) CEikEdwin;
    CleanupStack::PushL( newEditor );
    newEditor->SetContainerWindowL( *this );
    //Set the editor observer
    newEditor->SetEdwinObserver( this );
    
    newEditor->SetAknEditorAllowedInputModes(
        EAknEditorNumericInputMode | EAknEditorTextInputMode );
    newEditor->SetAknEditorInputMode( EAknEditorNumericInputMode );
    newEditor->SetAknEditorNumericKeymap( EAknEditorStandardNumberModeKeymap );

    TInt editorFlags = EAknEditorFlagNoT9 | EAknEditorFlagEnableScrollBars | 
        EAknEditorFlagLatinInputModesOnly;

     if( FeatureManager::FeatureSupported( KFeatureIdPenSupport ) )
        {
        editorFlags |= EAknEditorFlagDeliverVirtualKeyEventsToApplication;
        }

    newEditor->SetAknEditorFlags( editorFlags );

    // Get the layout, i.e. variant.
    EVariantFlag variant = AknLayoutUtils::Variant();

    // According to layout, construct the editor.
    if ( variant == EApacVariant )
        {
        // APAC variant
        AknEditUtils::ConstructEditingL( newEditor , R_USSD_EDWIN_EDITOR_APAC );
        }
    else
        {
        // EEuropeanVariant (includes ABRW)
        AknEditUtils::ConstructEditingL( newEditor , R_USSD_EDWIN_EDITOR_ELAF );
        }

    CleanupStack::Pop( newEditor );
    return newEditor;
    }

// ---------------------------------------------------------
// CUssdContainer::UpdateNavipaneMsgLengthL
// ---------------------------------------------------------
void CUssdContainer::UpdateNavipaneMsgLengthL()
    {
    _LOGSTRING( "CUssdContainer::UpdateNavipaneMsgLengthL =>" )

    if ( iNaviPaneHandler )
        {

        TInt maxLen=0;
        TBuf<KUssdEditorMaxLenght> inputTexts;

        iEditor->GetText( inputTexts );

        maxLen = iNaviPaneHandler->UpdateMsgLengthL( inputTexts, this );

        // if pasted more than 91 chinese characters then it must be
        // cutted and set correct message length in navi pane
        if ( inputTexts.Length() > maxLen )
            {
            inputTexts.Copy( inputTexts.Left( maxLen ) );
            iEditor->SetTextL( &inputTexts );
            iNaviPaneHandler->UpdateMsgLengthL( inputTexts, this );
            iEditor->DrawNow();
            iEditor->SetCursorPosL( maxLen, EFalse );
            }

        iEditor->SetMaxLength( maxLen );

        }
    _LOGSTRING( "CUssdContainer::UpdateNavipaneMsgLengthL <=" )
    }

// End of File
