meetingrequest/mrgui/src/cmrfieldcontainer.cpp
branchRCL_3
changeset 64 3533d4323edc
child 80 726fba06891a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/meetingrequest/mrgui/src/cmrfieldcontainer.cpp	Wed Sep 01 12:28:57 2010 +0100
@@ -0,0 +1,1155 @@
+/*
+* 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