/*
* 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:  Field container for UI fields
*
*/
#include "cmrfieldcontainer.h"
#include "mesmrfieldstorage.h"
#include "mmrfieldcontainerobserver.h"
#include "cesmrfield.h"

//DEBUG
#include "emailtrace.h"

namespace { // codescanner::namespace

// Off screen field x coordinate
const TInt KOffScreenPositionX =  1000;

/**
 * Vertical scroll margin
 */
const TInt KVerticalScrollMargin = 3;


// ----------------
// IndexByFieldId
// ----------------
//
TInt IndexByFieldId( const MESMRFieldStorage& aFactory,
                     TESMREntryFieldId aFieldId )
    {
    TInt index( KErrNotFound );
    TInt count( aFactory.Count() );

    for ( TInt i = 0; i < count; ++i )
        {
        if ( aFactory.Field( i )->FieldId() == aFieldId )
            {
            index = i;
            break;
            }
        }

    return index;
    }
}

//----- MEMBER FUNCTIONS ----

// ---------------------------------------------------------------------------
// CMRFieldContainer::CMRFieldContainer
// ---------------------------------------------------------------------------
//
CMRFieldContainer::CMRFieldContainer( MESMRFieldStorage& aFactory )
    : iFactory( aFactory )
    {
    FUNC_LOG;
    }

// ---------------------------------------------------------------------------
// CMRFieldContainer::~CMRFieldContainer
// ---------------------------------------------------------------------------
//
CMRFieldContainer::~CMRFieldContainer()
    {
    FUNC_LOG;
    // No implementation
    }

// ---------------------------------------------------------------------------
// CMRFieldContainer::NewL
// ---------------------------------------------------------------------------
//
CMRFieldContainer* CMRFieldContainer::NewL(
        MESMRFieldStorage& aFactory,
        const CCoeControl& aParent )
    {
    FUNC_LOG;
    CMRFieldContainer* self = new( ELeave )CMRFieldContainer( aFactory );
    CleanupStack::PushL( self );
    self->ConstructL( aParent );
    CleanupStack::Pop( self );
    return self;
    }

// ---------------------------------------------------------------------------
// CMRFieldContainer::ConstructL
// ---------------------------------------------------------------------------
//
void CMRFieldContainer::ConstructL( const CCoeControl& aParent )
    {
    FUNC_LOG;
    CCoeControl::SetComponentsToInheritVisibility( ETrue );
    SetContainerWindowL( aParent );

    TBool focusSet( EFalse );
    const TInt count( iFactory.Count() );
    for ( TInt i = 0; i < count; i++ )
        {
        iFactory.Field(i)->SetContainerWindowL( *this );
        }

    for ( TInt i = 0; i < count; i++ )
        {
        CESMRField* field = iFactory.Field( i );

        // Initialize field
        field->InitializeL();

        if ( !focusSet
             && field->IsVisible()
             && !field->IsNonFocusing())
            {
            field->SetOutlineFocusL( ETrue );
            focusSet = ETrue;
            iFocusedFieldIndex = i;
            }
        }

    for ( TInt i = 0; i < count; i++ )
        {
        CESMRField* field = iFactory.Field( i );

        field->SetListObserver( this );
        }
    }

// ---------------------------------------------------------------------------
// CMRFieldContainer::FocusedItem
// ---------------------------------------------------------------------------
//
CESMRField* CMRFieldContainer::FocusedField() const
    {
    FUNC_LOG;
    /*
     * Returns currently focused field
     */
    CESMRField* field = NULL;
    if ( iFactory.Count() > 0 )
        {
        field = iFactory.Field( iFocusedFieldIndex );
        }
    return field;
    }


// ---------------------------------------------------------------------------
// CMRFieldContainer::MoveFocusUpL
// ---------------------------------------------------------------------------
//
TKeyResponse CMRFieldContainer::MoveFocusUpL( TBool aHiddenFocus )
    {
    FUNC_LOG;
    /*
     * Moves focus up after key event. If aHiddenFocus, moves focus
     * to the first visible field in the bottom of the viewable area.
     */

    if( aHiddenFocus )
        {
        return MoveFocusVisibleL();
        }
    else
        {
        TInt ind( iFocusedFieldIndex );

        // search next visible focus item
        while ( ind > 0 )
            {
            CESMRField* field = iFactory.Field( --ind );

            if ( !field->IsNonFocusing() )
                {
                field = iFactory.Field( ind );

                CESMRField* focusedField = iFactory.Field( iFocusedFieldIndex );
                if ( field->IsVisible() )
                    {
                    TBool canLoseFocus(
                            focusedField->OkToLoseFocusL( field->FieldId() ) );

                    if ( canLoseFocus )
                        {
                        field->SetPreItemIndex( iFocusedFieldIndex );
                        iFocusedFieldIndex = ind;
                        field->SetCurrentItemIndex( iFocusedFieldIndex );

                        // Remove focus from previous position
                        focusedField->SetOutlineFocusL( EFalse );
                        focusedField->SetFocus( EFalse );
                        focusedField->MoveToScreen( EFalse );

                        // Set focus to new position
                        field->SetOutlineFocusL( ETrue );
                        field->SetFocus( ETrue );
                        field->MoveToScreen( ETrue );

                        // Scrollbar and physics update is done here
                        ScrollControlVisible( iFocusedFieldIndex );

                        DrawDeferred();
                        }

                    return EKeyWasConsumed;
                    }
                }
            }
        return EKeyWasNotConsumed;
        }
    }

// ---------------------------------------------------------------------------
// CMRFieldContainer::MoveFocusDownL
// ---------------------------------------------------------------------------
//
TKeyResponse CMRFieldContainer::MoveFocusDownL( TBool aHiddenFocus )
    {
    FUNC_LOG;
    /*
     * Moves focus down after key event. If aHiddenFocus, moves focus
     * to the first visible field in the top of the viewable area.
     */

    if( aHiddenFocus )
        {
        return MoveFocusVisibleL();
        }
    else
        {
        TInt ind( iFocusedFieldIndex );

        // start searching next possible focus item
        TInt maxItemIndex = iFactory.Count() - 1;

        while ( ind < maxItemIndex )
            {
            // only visible and focusable items can be focused
            CESMRField* field = iFactory.Field( ++ind );

            if ( field->IsVisible() && !field->IsNonFocusing() )
                {
                CESMRField* focusedField = iFactory.Field( iFocusedFieldIndex );

                TBool canLoseFocus(
                        focusedField->OkToLoseFocusL( field->FieldId() ) );

                // check it its ok for the old focus item to lose focus
                if ( canLoseFocus )
                    {
                    field->SetPreItemIndex( iFocusedFieldIndex );
                    iFocusedFieldIndex = ind;
                    field->SetCurrentItemIndex( iFocusedFieldIndex );

                    // Remove focus from previous position
                    focusedField->SetOutlineFocusL( EFalse );
                    focusedField->SetFocus( EFalse );
                    focusedField->MoveToScreen( EFalse );

                    // Set focus to new position
                    field->SetOutlineFocusL( ETrue );
                    field->SetFocus( ETrue );
                    field->MoveToScreen( ETrue );

                    // Scrollbar and physics update is done here
                    ScrollControlVisible( iFocusedFieldIndex );

                    DrawDeferred();
                    }

                return EKeyWasConsumed;
                }
            }
        return EKeyWasNotConsumed;
        }
    }

// ---------------------------------------------------------------------------
// CMRFieldContainer::MoveFocusVisibleL
// ---------------------------------------------------------------------------
//
TKeyResponse CMRFieldContainer::MoveFocusVisibleL()
    {
    FUNC_LOG;
    /*
     * Move focus to first completely visible field in the view,
     * if focus was in a field that was not visible in the view.
     * Use case: After pointer scroll focus is hidden. User presses
     * arrow keys -> Focus appears to the first visible field on the upper
     * or bottom part of the viewable area.
     */

    TKeyResponse response( EKeyWasNotConsumed );

    CESMRField* focusedField = FocusedField();
    CESMRField* visibleField = NULL;
    TRect view( Parent()->Rect() );

    // Focus is above the visible view area
    if ( focusedField->Rect().iBr.iY <= view.iTl.iY )
        {
        // Move focus to next visible field
        TInt lastIndex = iFactory.Count() - 1;
        TInt ind( iFocusedFieldIndex );
        while ( ind < lastIndex && !visibleField )
            {
            visibleField = iFactory.Field( ++ind );
            TRect fieldRect = visibleField->Rect();
            if ( visibleField->IsVisible()
                 && !visibleField->IsNonFocusing()
                 && fieldRect.iTl.iY >= view.iTl.iY )
                {
                // Update previous and current field indexes
                visibleField->SetPreItemIndex( iFocusedFieldIndex );
                iFocusedFieldIndex = ind;
                visibleField->SetCurrentItemIndex( iFocusedFieldIndex );
                }
            else
                {
                visibleField = NULL;
                }
            }
        }
    // Focus is below the visible view area
    else
        {
        // Move focus to previous visible field
        TInt ind( iFocusedFieldIndex );
        while ( ind > 0 && !visibleField )
            {
            visibleField = iFactory.Field( --ind );
            TRect fieldRect = visibleField->Rect();
            if ( visibleField->IsVisible()
                 && !visibleField->IsNonFocusing()
                 && fieldRect.iBr.iY <= view.iBr.iY )
                {
                // Update previous and current field indexes
                visibleField->SetPreItemIndex( iFocusedFieldIndex );
                iFocusedFieldIndex = ind;
                visibleField->SetCurrentItemIndex( iFocusedFieldIndex );
                }
            else
                {
                visibleField = NULL;
                }
            }
        }

    if ( visibleField )
        {
        // Remove existing focus
        focusedField->SetOutlineFocusL( EFalse );
        focusedField->SetFocus( EFalse );

        // Set focus to new field
        visibleField->SetOutlineFocusL( ETrue );
        visibleField->SetFocus( ETrue );

        response = EKeyWasConsumed;

        DrawDeferred();
        }

    return response;
    }

// ---------------------------------------------------------------------------
// CMRFieldContainer::SetFieldContainerObserver
// ---------------------------------------------------------------------------
//
void CMRFieldContainer::SetFieldContainerObserver(
        MMRFieldContainerObserver* aObserver )
    {
    FUNC_LOG;
    iObserver = aObserver;
    }

// ---------------------------------------------------------------------------
// CMRFieldContainer::CountComponentControls
// ---------------------------------------------------------------------------
//
TInt CMRFieldContainer::CountComponentControls() const
    {
    FUNC_LOG;

    // If field container is scrolling, container will draw also children
    TInt count( 0 );

    if ( !iScrolling )
        {
        count = iFactory.Count();
        }

    return count;
    }

// ---------------------------------------------------------------------------
// CMRFieldContainer::ComponentControl
// ---------------------------------------------------------------------------
//
CCoeControl* CMRFieldContainer::ComponentControl( TInt aIndex ) const
    {
    FUNC_LOG;
    return iFactory.Field( aIndex );
    }

// ---------------------------------------------------------------------------
// CMRFieldContainer::MinimumSize
// ---------------------------------------------------------------------------
//
TSize CMRFieldContainer::MinimumSize()
    {
    FUNC_LOG;
    /*
     * Returns the minimum size required by the field container
     */

    TSize containerSize;

    // Calculate height as the sum of the heights of the visible fields
    const TInt count( iFactory.Count() );

    for ( TInt i(0); i < count; ++i )
        {
        CESMRField* field = iFactory.Field( i );
        if ( field->IsVisible() )
            {
            TRect rect( field->Rect() );
            containerSize.iHeight += rect.Height();
            }
        }

    containerSize.iWidth = Parent()->Rect().Width();

    return containerSize;
    }

// ---------------------------------------------------------------------------
// CMRFieldContainer::SizeChanged
// ---------------------------------------------------------------------------
//
void CMRFieldContainer::SizeChanged()
    {
    FUNC_LOG;

    // For example when orientation changes, we might need to scroll
    // the currently focused control visible again. This handles also
    // scrollbar and physics updates.
    ScrollControlVisible( KErrNotFound );

    TPoint tl( Position() );

    const TInt count( iFactory.Count() );

    // Loop all the visible fields and set size and position in the list
    for ( TInt i = 0; i < count; i++ )
        {
        CESMRField* field = iFactory.Field( i );

        if ( field->IsVisible() )
            {
            TPoint pos( tl );

            // If field is not focused, layout it outside screen
            if ( i != iFocusedFieldIndex )
                {
                pos.iX = KOffScreenPositionX;
                }

            LayoutField( *field, pos );

            TInt height = field->Size().iHeight;
            tl.iY += height;
            }
        }
    }


// ---------------------------------------------------------------------------
// CMRFieldContainer::HandlePointerEventL
// ---------------------------------------------------------------------------
//
void CMRFieldContainer::HandlePointerEventL( const TPointerEvent &aPointerEvent )
    {
    FUNC_LOG;

    // Find out to which field this pointer event is intended to
    TInt fieldCount( iFactory.Count() );

    for( TInt i = 0; i < fieldCount; ++i )
        {
        CCoeControl* field = iFactory.Field( i );
        if( field->Rect().Contains( aPointerEvent.iPosition ) &&
                field->IsVisible() )
            {
            field->HandlePointerEventL( aPointerEvent );
            }
        }
    }

// ---------------------------------------------------------------------------
// CMRFieldContainer::ControlSizeChanged
// ---------------------------------------------------------------------------
//
void CMRFieldContainer::ControlSizeChanged( CESMRField* aField )
    {
    FUNC_LOG;
    /*
     * Called whenever a fields size has changed. Requires always
     * relayouting.
     */

    if ( !aField )
        {
        SizeChanged();
        }
    else
        {
        // Relayout field if size has changed
        TSize old( aField->Size() );
        TSize size( aField->MinimumSize() );
        if( size != old )
            {
            aField->SetSize( size );

            TPoint tl( aField->Position() );
            TInt index = IndexByFieldId( iFactory, aField->FieldId() );

            // Move fields below this particular field
            tl.iY += size.iHeight;
            MoveFields( index + 1, tl );

            // Fields have been re-layouted / moved. This requires resetting
            // the size of this field container.
            SetSizeWithoutNotification( MinimumSize() );

            // Update also scrollbar and physics
            iObserver->UpdateScrollBarAndPhysics();

            if( index <= iFocusedFieldIndex )
                {
                // Scroll this field completely visible, if required.
                // This updates also scrollbar and physics if scrolling
                // is done.
                ScrollControlVisible( iFocusedFieldIndex );
                }

            DrawDeferred();
            }
        }
    }

// ---------------------------------------------------------------------------
// CMRFieldContainer::ShowControl
// ---------------------------------------------------------------------------
//
void CMRFieldContainer::ShowControl( TESMREntryFieldId aFieldId )
    {
    FUNC_LOG;
    /*
     * Inserts field visible and layouts it.
     */

    CESMRField* field = iFactory.FieldById( aFieldId );

    if ( field && !field->IsVisible() )
        {
        // Make field visible
        field->MakeVisible( ETrue );
        TInt index = IndexByFieldId( iFactory, aFieldId );

        TPoint tl( Rect().iTl );
        TInt prevIndex = index - 1;

        // Get previous visible field position
        // Index 0 must be included in attendee field case,
        // to avoid field collision. But in response field,
        // causes misplacing of area.
        if ( ( prevIndex >= 0 ) && ( aFieldId != EESMRFieldResponseArea ) )
            {
            CESMRField* previous = NULL;
            do
                {
                previous = iFactory.Field( prevIndex-- );
                }
            while ( prevIndex >= 0 && !previous->IsVisible() );

            tl.iY = previous->Rect().iBr.iY;
            }

        // Layout field
        LayoutField( *field, tl);
        // Move field off screen if it is not focused
        field->MoveToScreen( index == iFocusedFieldIndex );

        // Move following fields
        tl.iY += field->Size().iHeight;
        MoveFields( ++index, tl );

        // Set fieldcontainer size again, because
        // the amount of fields has changed.
        SetSizeWithoutNotification( MinimumSize() );

        // Scrollbar and physics require updating.
        iObserver->UpdateScrollBarAndPhysics();
        }

    DrawDeferred();
    }

// ---------------------------------------------------------------------------
// CMRFieldContainer::HideControl()
// ---------------------------------------------------------------------------
//
void CMRFieldContainer::HideControl( TESMREntryFieldId aFieldId )
    {
    FUNC_LOG;
    /*
     * Sets field non-visible and moves other fields accordingly.
     * Does not delete the field.
     */
    CESMRField* field = iFactory.FieldById( aFieldId );

    if ( field && field->IsVisible() )
        {
        field->MakeVisible( EFalse );
        TInt index = IndexByFieldId( iFactory, aFieldId );
        TBool focused = ( index == iFocusedFieldIndex )? ETrue : EFalse;

        TPoint pos( field->Position() );
        MoveFields( index, pos );

        // Set fieldcontainer size again, because
        // the amount of fields has changed.
        SetSizeWithoutNotification( MinimumSize() );

        // Scrollbar and physics require updating.
        iObserver->UpdateScrollBarAndPhysics();

        if ( focused && !field->IsNonFocusing() )
            {
            // Set focus to next field, or if removed field was the last
            // field, then move focus to last visible field
            TInt lastVisibleFieldIndex( LastVisibleField( aFieldId ) );

            // If field was the last one...
            if( lastVisibleFieldIndex == index )
                {
                // ... Set focus to last visible field.
                TRAP_IGNORE( DoSetFocusL( lastVisibleFieldIndex ) )
                }
            else
                {
                // Othwerwise set focus to next field
                TRAP_IGNORE( DoSetFocusL( index + 1 ) )
                }
            }
        }
    DrawDeferred();
    }

// ---------------------------------------------------------------------------
// CMRFieldContainer::IsControlVisible
// ---------------------------------------------------------------------------
//
TBool CMRFieldContainer::IsControlVisible( TESMREntryFieldId aField )
    {
    FUNC_LOG;
    /*
     * Returns ETrue/EFalse if the field with given field id is
     * visible or not.
     */

    TBool ret( EFalse );

    CESMRField* field = iFactory.FieldById( aField );
    if ( field && field->IsVisible() )
        {
        ret = ETrue;
        }

    return ret;
    }

// ---------------------------------------------------------------------------
// CMRFieldContainer::SetControlFocused
// ---------------------------------------------------------------------------
//
void CMRFieldContainer::SetControlFocusedL( TESMREntryFieldId aField )
    {
    FUNC_LOG;
    /*
     * Set the field with given field id focused.
     */

    // This handles scrollbar and physics updates also.
    DoSetFocusL( IndexByFieldId( iFactory, aField ) );
    }

// ---------------------------------------------------------------------------
// CMRFieldContainer::ListHeight
// ---------------------------------------------------------------------------
//
TInt CMRFieldContainer::ListHeight()
    {
    FUNC_LOG;
    /*
     * Returns the height of all fields, in other words the height
     * of the field container.
     */
    return MinimumSize().iHeight;
    }

// ---------------------------------------------------------------------------
// CMRFieldContainer::IsFocusedControlsBottomVisible
// ---------------------------------------------------------------------------
//
TBool CMRFieldContainer::IsFocusedControlsBottomVisible()
    {
    FUNC_LOG;
    /*
     * Checks if focused field is completely visible in the viewable area.
     */

    // Fetch the position information about currently focused field:
    CESMRField* field = iFactory.Field( iFocusedFieldIndex );
    TBool ret( EFalse );
    if ( field->Rect().iBr.iY <= Parent()->Rect().iBr.iY )
       {
       ret = ETrue;
       }

    return ret;
    }


// ---------------------------------------------------------------------------
// CMRFieldContainer::ScrollControlVisible
// ---------------------------------------------------------------------------
//
void CMRFieldContainer::ScrollControlVisible( TInt aInd )
    {
    FUNC_LOG;
    /*
     * Scrolls the field with the given index visible
     */

    CESMRField* field = NULL;
    if ( aInd == KErrNotFound )
        {
        field = FocusedField();
        }
    else
        {
        field = iFactory.Field( aInd );
        }

    ASSERT( field );

    TRect fieldRect( field->Position(), field->Size() );
    TRect parentRect( Parent()->Rect() );

    /*
     * Case 1: Field's height is less than the viewable area height,
     * let's scroll the whole field visible.
     */
    if( fieldRect.Height() < parentRect.Height() )
        {
        // Scrolling down, let's move fields up
        if( fieldRect.iBr.iY > parentRect.iBr.iY )
            {
            iObserver->ScrollFieldsUp(
                    fieldRect.iBr.iY - parentRect.iBr.iY );
            }
        // scrolling up, let's move field down
        if( fieldRect.iTl.iY < parentRect.iTl.iY )
            {
            iObserver->ScrollFieldsDown(
                    parentRect.iTl.iY - fieldRect.iTl.iY );
            }
        }

    /*
     * Case 2: Field's height is more than the viewable area's height.
     */
    else
        {
        // Field is in view mode
        if( field->FieldMode() == EESMRFieldModeView )
            {
            // Focus to this field is coming from above
            if( field->PreItemIndex() < field->CurrentItemIndex() )
                {
                // Let's scroll the top of the field to the
                // top of the viewable area
                iObserver->ScrollFieldsUp(
                                   fieldRect.iTl.iY - parentRect.iTl.iY );

                }
            // Focus to this field is coming from below
            if( field->PreItemIndex() > field->CurrentItemIndex() )
                {
                // Let's scroll the bottom of the field to the
                // bottom of the viewable area
                iObserver->ScrollFieldsDown(
                                   parentRect.iBr.iY - fieldRect.iBr.iY );
                }
            }

        // Field is in edit mode
        if( field->FieldMode() == EESMRFieldModeEdit )
            {
            TInt viewBottom( parentRect.iBr.iY );

            TInt fieldUpper( 0 );
            TInt fieldLower( 0 );
            field->GetCursorLineVerticalPos( fieldUpper, fieldLower );

            TInt focusFieldVisibleUp( fieldRect.iTl.iY + fieldUpper );
            TInt focusFieldVisibleBottom( fieldRect.iTl.iY + fieldLower );

            // desired position below view rect:
            TInt viewHeight( parentRect.Height() );
            if ( focusFieldVisibleBottom > viewBottom )
                {
                // move field focus line bottom to view bottom
                TInt px = focusFieldVisibleBottom - viewHeight;


                // if focus on last field: add margin height to
                // scroll amount.
                if ( iFocusedFieldIndex == iFactory.Count()-1 )
                    {
                    px += KVerticalScrollMargin;
                    }

                // Scrollbar and physics update is done here
                iObserver->ScrollFieldsUp( px );
                }
            else
                {
                // If field top is invisible, move downwards to make top visible.
                TInt viewTop( parentRect.iTl.iY );

                // recalculate field rect
                focusFieldVisibleUp = fieldRect.iTl.iY + fieldUpper;
                focusFieldVisibleBottom = fieldRect.iTl.iY + fieldLower;

                if ( focusFieldVisibleUp < viewTop )
                    {
                    TInt px( viewTop - focusFieldVisibleUp );

                    // Scrollbar and physics update is done here
                    iObserver->ScrollFieldsDown( px );
                    }
                }
            }
        }
    }

// ---------------------------------------------------------------------------
// CMRFieldContainer::RePositionFields
// ---------------------------------------------------------------------------
//
void CMRFieldContainer::RePositionFields( TInt aAmount )
    {
    FUNC_LOG;

    // Movement downwards
    if( aAmount >= 0 )
        {
        // Also scrollbar and physics update is done here
        iObserver->ScrollFieldsDown( aAmount );
        }
    // Movement upwards
    else
        {
        // Also scrollbar and physics update is done here
        iObserver->ScrollFieldsUp( -aAmount );
        }
    }

// ---------------------------------------------------------------------------
// CMRFieldContainer::ViewableAreaRect
// ---------------------------------------------------------------------------
//
TRect CMRFieldContainer::ViewableAreaRect()
    {
    FUNC_LOG;
    return Parent()->Rect();
    }

// ---------------------------------------------------------------------------
// CMRFieldContainer::MoveFields
// ---------------------------------------------------------------------------
//
void CMRFieldContainer::MoveFields( TInt aIndex, TPoint& aTl )
    {
    FUNC_LOG;
    /*
     * Moves fields from the given index towards the last item.
     * This function does not update scrollbar or physics.
     */

    const TInt count( iFactory.Count() );

    for ( TInt i = aIndex; i < count; ++i )
        {
        CESMRField* field = iFactory.Field( i );

        if ( field->IsVisible() )
            {
            field->SetPosition( aTl );

            aTl.iY += field->Size().iHeight;
            }
        }
    }

// ---------------------------------------------------------------------------
// CMRFieldContainer::LayoutField
// ---------------------------------------------------------------------------
//
void CMRFieldContainer::LayoutField( CESMRField& aField, const TPoint& aTl )
    {
    FUNC_LOG;
    /*
     * Layouts given field according to the size required by the field and
     * given TPoint. This function does not update scrollbar or physics.
     */

    TSize size( aField.MinimumSize() );
    aField.SetExtent( aTl, size );
    }

// ---------------------------------------------------------------------------
// CMRFieldContainer::IsLastVisibleField
// ---------------------------------------------------------------------------
//
TInt CMRFieldContainer::LastVisibleField(
        TESMREntryFieldId aFieldId )
    {
    /*
     * Helper function to find out the last visible field in the list.
     */

    TInt lastVisibleFieldIndex( 0 );
    TInt count( iFactory.Count() );

    // Go through fields from last field towards the first field
    for( TInt i( 1 ); i > count; ++i )
        {
        // Once last visible field is found...
        if( iFactory.Field( count - i )->IsVisible() )
            {
            // ... Compare it to the given field index ...
            if( iFactory.Field( count - i )->FieldId() == aFieldId )
                {
                // ... And if match is found, given fieldId is the
                // the last visible field.
                lastVisibleFieldIndex =
                    IndexByFieldId( iFactory, aFieldId );
                }
            else
                {
                // Otherwise return the found last visible field.
                lastVisibleFieldIndex =
                    IndexByFieldId( iFactory,
                                    iFactory.Field( count - i )->FieldId() );
                }
            break;
            }
        }

    return lastVisibleFieldIndex;
    }

// ---------------------------------------------------------------------------
// CMRFieldContainer::DoSetFocusL
// ---------------------------------------------------------------------------
//
void CMRFieldContainer::DoSetFocusL( TInt aNewFocusIndex )
    {
    FUNC_LOG;
    /*
     * Sets the focus according to the given index.
     */

    TInt count( iFactory.Count() );
    aNewFocusIndex = Max( 0, Min( aNewFocusIndex, count - 1 ) );

    if ( aNewFocusIndex != iFocusedFieldIndex )
        {
        // Get current focused field
        CESMRField* old = iFactory.Field( iFocusedFieldIndex );

        // Get next focused field
        CESMRField* field = iFactory.Field( aNewFocusIndex );

        // Do sanity checks
        while ( aNewFocusIndex < count && !field->IsVisible() )
            {
            field = iFactory.Field( aNewFocusIndex++ );
            }

        if ( !field->IsVisible() )
            {
            aNewFocusIndex = iFocusedFieldIndex - 1;
            while ( aNewFocusIndex > 0 && !field->IsVisible() )
                {
                field = iFactory.Field( aNewFocusIndex-- );
                }
            }

        ASSERT( field->IsVisible() );

        // Update current and previous item indexes
        field->SetPreItemIndex( iFocusedFieldIndex );
        iFocusedFieldIndex = aNewFocusIndex;
        field->SetCurrentItemIndex( iFocusedFieldIndex );

        // Remove focus from old
        old->SetOutlineFocusL( EFalse );
        old->SetFocus( EFalse );
        old->MoveToScreen( EFalse );

        // update focus index to new index
        field->SetOutlineFocusL( ETrue );
        field->SetFocus( ETrue );
        field->MoveToScreen( ETrue );

        // This handles also scrollbar and physics updating,
        // if view scrolling is done.
        ScrollControlVisible( iFocusedFieldIndex );

        DrawDeferred();
        }
    }


// ---------------------------------------------------------------------------
// CMRFieldContainer::SetScrolling
// ---------------------------------------------------------------------------
//
void CMRFieldContainer::SetScrolling( TBool aScrolling )
    {
    FUNC_LOG;

    iScrolling = aScrolling;

    // Move focused field away from screen if container is scrolling.
    // Otherwise move it to screen.
    CESMRField* field = iFactory.Field( iFocusedFieldIndex );
    field->MoveToScreen( !iScrolling );
    }


// ---------------------------------------------------------------------------
// CMRFieldContainer::Draw
// ---------------------------------------------------------------------------
//
void CMRFieldContainer::Draw( const TRect& aRect ) const
    {
    FUNC_LOG;

    // Get visible screen area from parent (list pane)
    TRect parent( Parent()->Rect() );

    // Current container position used to calculate actual field positions
    TPoint tl( iPosition );

    // Field index to skip
    TInt fieldToSkip = KErrNotFound;

    if ( !iScrolling )
        {
        // Container is not scrolling. Don't draw focused field from buffer
        fieldToSkip = iFocusedFieldIndex;
        }

    // Draw all visible fields which are not on screen
    TInt count( iFactory.Count() );

    for ( TInt i = 0; i < count; ++i )
        {
        CESMRField* field = iFactory.Field( i );
        if ( field->IsVisible() )
            {
            // Calculate actual field rect on screen
            TRect screenRect( tl, field->Size() );

            // Draw field if it intersects with screen visible area
            if ( i != fieldToSkip
                 && screenRect.Intersects( parent ) )
                {
                field->Draw( screenRect );
                }
            // Move next field top left corner
            tl.iY += screenRect.Height();
            }
        }
    }

// ---------------------------------------------------------------------------
// CMRFieldContainer::ScrollContainer
// ---------------------------------------------------------------------------
//
void CMRFieldContainer::ScrollContainer( const TPoint& aTl )
    {
    FUNC_LOG;

    // Set scrolling flag and move focused field off screen
    SetScrolling( ETrue );
    // Update control position,
    // but dont propagate the change to component controls
    iPosition = aTl;
    }

// ---------------------------------------------------------------------------
// CMRFieldContainer::Synchronize
// ---------------------------------------------------------------------------
//
void CMRFieldContainer::Synchronize()
    {
    FUNC_LOG;

    // Set actual control positions (y-coordinate) to visible fields
    TPoint tl( iPosition );

    TInt count( iFactory.Count() );

    for ( TInt i = 0; i < count; ++i )
        {
        CESMRField* field = iFactory.Field( i );
        if ( field->IsVisible() )
            {
            TPoint pos( field->Position().iX, tl.iY );
            tl.iY += field->Size().iHeight;
            field->SetPosition( pos );
            }
        }
    SetScrolling( EFalse );
    }

// End of file
