javauis/lcdui_qt/src/javax/microedition/lcdui/FormLayouter.java
changeset 61 bf7ee68962da
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javauis/lcdui_qt/src/javax/microedition/lcdui/FormLayouter.java	Wed Aug 18 09:43:15 2010 +0300
@@ -0,0 +1,2060 @@
+/*
+* 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:
+*
+*/
+package javax.microedition.lcdui;
+
+import java.util.NoSuchElementException;
+import java.util.Vector;
+import java.util.Enumeration;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/**
+ * FormLayouter implements form layout algorithm.
+ */
+class FormLayouter
+{
+
+    /**
+     * Form instance (not owned).
+     */
+    private Form form;
+
+    /**
+     * Form's scrolled composite (not owned).
+     */
+    protected ScrolledComposite formComposite;
+
+    /**
+     * Controls vector.
+     */
+    private Vector layoutObjects = new Vector();
+
+    /**
+     * Rows vector.
+     */
+    private Vector rows = new Vector();
+
+    /**
+     * Form's current horizontal alignment
+     */
+    private int currentHLayoutDirective;
+
+    private ImageItemLayouter imIL;
+
+    private StringItemLayouter sIL;
+
+    private GaugeLayouter gL;
+
+    private TextFieldLayouter tfL;
+
+    private DateFieldLayouter dfL;
+
+    private ChoiceGroupLayouter cgL;
+
+    private CustomItemLayouter ciL;
+
+    private SpacerLayouter sL;
+
+    private int vPosition;
+
+    private Item deferredScrollToItem;
+
+    private boolean isCurrent;
+
+    private Control itemMainControl;
+
+    private static final int NO_DIRECTION = -1;
+
+    private Item currentSelectedItem;
+
+    private int direction = NO_DIRECTION;
+
+    private boolean mousePressed;
+
+    private LayoutObject currentlyUnderMouse;
+
+
+    /**
+     * Constructor.
+     *
+     * @param form Form to perform layout on.
+     */
+    FormLayouter(Form form)
+    {
+        this.form = form;
+        formComposite = form.getFormComposite();
+        imIL = new ImageItemLayouter(this);
+        sIL = new StringItemLayouter(this);
+        gL = new GaugeLayouter(this);
+        dfL = new DateFieldLayouter(this);
+        tfL = new TextFieldLayouter(this);
+        cgL = new ChoiceGroupLayouter(this);
+        ciL = new CustomItemLayouter(this);
+        sL = new SpacerLayouter(this);
+    }
+
+    /**
+     * Dispose and cleanup layouted items.
+     */
+    void dispose()
+    {
+        ESWTUIThreadRunner.syncExec(new Runnable()
+        {
+            public void run()
+            {
+                eswtClearRows(0, null);
+    			removeAllLayoutObjects();
+				rows = null;
+				layoutObjects = null;
+            }
+        });
+    }
+
+    /**
+     * Log out a control with all its children at the given indentation level.
+     */
+    void logControl(int level, Control control)
+    {
+        if(control != null)
+        {
+            String s2 = control.toString();
+            s2 = s2.substring(0, s2.indexOf('}') - 1);
+            String s3 = control.getBounds().toString();
+            s3 = s3.substring(s3.indexOf('{'));
+            Logger.verbose(Logger.indent(s2 + s3, level * 2));
+            if(control instanceof Composite)
+            {
+                Control[] arr = ((Composite) control).getChildren();
+                for(int i = 0; i < arr.length; i++)
+                {
+                    logControl(level + 1, arr[i]);
+                }
+            }
+        }
+    }
+
+    /**
+     * Log out all layoutobjects for each item.
+     */
+    void logFormLayout()
+    {
+        Logger.verbose(form + " ---------------------------------------------");
+        LayoutObject lo = null;
+        Item item = null;
+        int line = -1;
+        while((lo = getNextLayoutObjectOfItem(lo, null)) != null)
+        {
+            if(lo.getOwningItem() != item)
+            {
+                item = lo.getOwningItem();
+                Logger.verbose(item.toString());
+            }
+            if(lo.getRowIdx() != line)
+            {
+                line = lo.getRowIdx();
+            }
+            Logger.verbose(Logger.indent("Row:" + lo.getRowIdx(), 2));
+            logControl(2, lo.getControl());
+        }
+        Logger.verbose(form + " ---------------------------------------------");
+    }
+
+    /**
+     * Called when Form is about to be shown.<br>
+     * NOTE: this is called from eSWT UI-thread
+     */
+    void handleShowCurrentEvent()
+    {
+        Logger.method(this, "handleShowCurrentEvent");
+        isCurrent = true;
+
+        // restore our scrolling position (eSWT resets it to 0 by default)
+        eswtSetScrollingPosition(vPosition, true);
+
+        Item item = null;
+        LayoutObject lo = null;
+        while((lo = getNextLayoutObjectOfItem(lo, null)) != null)
+        {
+            if(lo.getOwningItem() != item)
+            {
+                // item border
+                item = lo.getOwningItem();
+                getItemLayouter(item).eswtAddListeners(item, lo);
+            }
+        }
+
+		eswtApplyCurrentFocus();	
+    }
+
+    /**
+     * Called when Form is about to be hidden.<br>
+     * NOTE: this is called from eSWT UI-thread
+     */
+    void handleHideCurrentEvent()
+    {
+        Logger.method(this, "handleHideCurrentEvent");
+        isCurrent = false;
+
+        Item item = null;
+        LayoutObject lo = null;
+        while((lo = getNextLayoutObjectOfItem(lo, null)) != null)
+        {
+            if(lo.getOwningItem() != item)
+            {
+                // item border
+                item = lo.getOwningItem();
+                getItemLayouter(item).eswtRemoveListeners(item, lo);
+                getItemLayouter(item).eswtHandleVisibilityChange(item, false);
+            }
+        }
+
+		direction = NO_DIRECTION;
+    }
+
+    /**
+     * Called when Form is beeing resized.<br>
+     * NOTE: this is called from eSWT UI-thread
+     */
+    void handleResizeEvent(int width, int height)
+    {
+        // Logger.method(this, "handleResizeEvent");
+        int numitems = getItemCount();
+        for(int i = 0; i < numitems; i++)
+        {
+            getItem(i).invalidateCachedSizes();
+        }
+        ItemLayouter.eswtUpdateStaticShellSize(width, height);
+    }
+
+    /**
+     * Do form layout according to startIndex.
+     *
+     * @param startItem - index of item which need to be layouted.
+     */
+    void layoutForm(final int startIndex)
+    {
+        ESWTUIThreadRunner.syncExec(new Runnable()
+        {
+            public void run()
+            {
+                eswtLayoutForm(startIndex);
+            }
+        });
+    }
+
+    /**
+     * eSWT callback for doLayout().
+     */
+    void eswtLayoutForm(int startIndex)
+    {
+        int numItems = getItemCount();
+        Logger.method(this, "eswtLayoutForm", startIndex + " / " + numItems);
+
+        eswtUpdateFormComposite(false);
+        if(numItems > 0)
+        {
+            Item previousItem = null;
+            int startRowIndex = 0;
+
+            if(startIndex > 0)
+            {
+                // Find row with previous item.
+                previousItem = getItem(startIndex - 1);
+                Row prevItemRow = getLastRowOfItem(previousItem);
+                if(prevItemRow != null)
+                {
+                    startRowIndex = rows.indexOf(prevItemRow);
+                }
+            }
+
+            // Clear rows starting from item - partial re-layouting
+            eswtClearRows(startRowIndex, previousItem);
+            // Layout items
+            for(int i = startIndex; i < numItems; i++)
+            {
+                eswtLayoutItem(getItem(i));
+            }
+            // Update last row
+            eswtUpdateRow(getLastRow());
+        }
+        else
+        {
+            eswtClearRows(0, null);
+        }
+        // check if we need to scroll to a particular item
+        if(deferredScrollToItem != null)
+        {
+            eswtSetCurrentItem(deferredScrollToItem);
+            deferredScrollToItem = null;
+        }
+        eswtUpdateFormComposite(true);
+        eswtHandleVisibilityChanges();
+
+        if(Logger.isLogVerbose())
+        {
+            logFormLayout();
+        }
+
+		// clear invalid selected item
+		eswtCheckCurrentSelectedItem();
+		
+		if(currentSelectedItem != null
+				&& (currentSelectedItem.isFocusable()))
+		{
+			eswtApplyCurrentFocus();
+		}
+		else
+		{
+			// If there's no item currently selected try to find first
+			// focusable item and set it current (if found):
+			Item found = eswtGetNextFocusableItem(
+							 getItem(startIndex - 1), SWT.ARROW_RIGHT);
+			if(found != null)
+			{
+				eswtSetCurrentSelectedItem(found, NO_DIRECTION);
+			}
+			else
+			{
+				eswtApplyCurrentFocus();
+			}
+		}		
+    }
+
+    /**
+     * Returns if the parameter is a eSWT directional key code.
+     *
+     * @param keyCode key code
+     */
+    private boolean isDirectionKey(int keyCode)
+    {
+        return (keyCode == SWT.ARROW_DOWN || keyCode == SWT.ARROW_UP
+                || keyCode == SWT.ARROW_LEFT || keyCode == SWT.ARROW_RIGHT);
+    }
+
+    /**
+     * Handler for key events.<br>
+     * The implementation moves focus and/or scrolls the form when
+     * needed. The method is called by the Form.
+     *
+     * @param keyCode eSWT key code.
+     * @param keyType eSWT key type.
+     */
+    final void handleKeyEvent(int keyCode, int keyType)
+    {
+        Logger.method(this, "handleKeyEvent", currentSelectedItem,
+                      String.valueOf(keyCode), String.valueOf(keyType));
+
+        boolean isDirectionalKey = isDirectionKey(keyCode);
+        if(keyType == SWT.KeyDown && isDirectionalKey)
+        {
+            eswtCheckCurrentSelectedItem();
+        }
+
+        if(currentSelectedItem != null)
+        {
+            if(getItemLayouter(currentSelectedItem).eswtOfferKeyEvent(
+                        currentSelectedItem, keyCode, keyType))
+            {
+                // if the key has been consumed
+                return;
+            }
+        }
+
+        // scrolling/focus traverse only happens on directional key's down event
+        if(keyType == SWT.KeyDown && isDirectionalKey)
+        {
+            // try to find next focusable item
+            Item next = eswtGetNextFocusableItem(currentSelectedItem, keyCode);
+
+            // if no visible & focusable item was found to transfer focus
+            if(next == currentSelectedItem)
+            {
+                // try to scroll a bit
+                eswtSetScrollingPosition(getNextScrollingPosition(keyCode),
+                                         true);
+                // find next focusable after scrolling
+                next = eswtGetNextFocusableItem(currentSelectedItem, keyCode);
+            }
+
+            if(next != currentSelectedItem)
+            {
+                //textfield always have to be fully visible when focused.
+                if(next instanceof TextField)
+                {
+                    eswtScrollToItem(next);
+                }
+                eswtSetCurrentSelectedItem(next, keyCode);
+            }
+        }
+    }
+
+    /**
+     * Handler for pointer events.<br>
+     * The method is called by the Form.
+     *
+     * @param x coordinate relative to scrolledComposite
+     * @param y coordinate relative to scrolledComposite
+     * @param type event type: SWT.MouseDown, SWT.MouseMove, SWT.MouseUp
+     */
+    final void handlePointerEvent(int x, int y, int type)
+    {
+        Logger.method(this, "handlePointerEvent", String.valueOf(x),
+                      String.valueOf(y), String.valueOf(type));
+
+        // TODO: change when DirectUI style arrives.
+        /*
+        Item item;
+        if (type == SWT.MouseMove) {
+            if (currentlyUnderMouse == null
+                    || !currentlyUnderMouse.contains(x, y)) {
+                if (currentlyUnderMouse != null) {
+                    //currentlyUnderMouse.getControl().setCapture(false);
+                }
+                item = eswtFindItemUnderMouse(x, y);
+                if (item != null && item != currentSelectedItem
+                        && item.isFocusable()) {
+                    setCurrentItem(item);
+                    item.internalSetFocused(true);
+                    eswtSetCurrentSelectedItem(item);
+                    //following method causes all mouse events delivered to it
+
+                    currentlyUnderMouse.getControl().setCapture(true);
+                    Logger.warning("seting capture to:" + item);
+                }
+            }
+            int currentVPosition = getVPosition();
+            boolean isMouseDirectionUp = false;
+            boolean doScrolling = false;
+            int localY = y;
+
+            if (y <= currentVPosition) {
+                localY = Math.max(0, y);
+                eswtSetScrollingPosition(localY, true);
+                isMouseDirectionUp = true;
+                doScrolling = true;
+            }
+            else if (y > (currentVPosition + getFormHeight())) {
+                //check for maxVPosition
+                if (y > (eswtGetMaxVPosition() + getFormHeight())) {
+                    localY = eswtGetMaxVPosition() + getFormHeight();
+                }
+                else {
+                    localY = y;
+                }
+                currentVPosition = localY - getFormHeight();
+                eswtSetScrollingPosition(currentVPosition, true);
+
+                isMouseDirectionUp = false;
+                doScrolling = true;
+            }
+            if (mousePressed && doScrolling) {
+                resetEventTimer(isMouseDirectionUp, localY);
+            }
+        }
+        else
+        if (type == SWT.MouseDown) {
+            mousePressed = true;
+            item = eswtFindItemUnderMouse(x, y);
+            if (item != null && item != currentSelectedItem
+                    && item.isFocusable() && getForm().getShell() ==
+                        getForm().getShell().getDisplay().getActiveShell()) {
+                //eswtScrollToItem(item);
+                //following method causes all mouse events delivered to it
+
+                //currentlyUnderMouse.getControl().setCapture(true);
+            }
+        }
+        else if (type == SWT.MouseUp) {
+            mousePressed = false;
+            if (currentlyUnderMouse != null) {
+                //currentlyUnderMouse.getControl().setCapture(false);
+            }
+        }*/
+    }
+
+    /**
+     * Find item at the specified point.
+     *
+     * @param x coordinate.
+     * @param y coordinate.
+     * @return Item.
+     */
+    Item eswtFindItemUnderMouse(int x, int y)
+    {
+        Row itemRow;
+        for(int i = 0; i < getRowCount(); i++)
+        {
+            itemRow = getRow(i);
+            if(itemRow.getYShift() <= y && y <= itemRow.getBottomPosition())
+            {
+                LayoutObject lo;
+                for(int j = 0; j < itemRow.size(); j++)
+                {
+                    lo = itemRow.getLayoutObject(j);
+                    if(lo.contains(x, y))
+                    {
+                        Logger.info("Item under mouse: "
+                                    + lo.getOwningItem());
+                        currentlyUnderMouse = lo;
+                        return lo.getOwningItem();
+                    }
+                }
+                break;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Gets next (or nearest) focusable item.
+     *
+     * @param fromItem Item where to start to search the next focusable item.
+     * @param dir Search direction, one of the arrow key constants defined
+     *      in class SWT.
+     *
+     * @return Nearest focusable item or null if no item found.
+     */
+    final Item eswtGetNextFocusableItem(Item fromItem, int dir)
+    {
+        Item nextItem = fromItem;
+
+        switch(dir)
+        {
+        case SWT.ARROW_RIGHT:
+        {
+            LayoutObject obj = getLastLayoutObjectOfItem(fromItem);
+            while((obj = getNextLayoutObjectOfItem(obj, null)) != null)
+            {
+                Item owner = obj.getOwningItem();
+                if(owner != null && owner != fromItem
+                        && owner.isFocusable()
+                        && isPartiallyVisible(obj, Config.DFI_VISIBILITY_PERCENT))
+                {
+                    nextItem = owner;
+                    break;
+                }
+            }
+            break;
+        }
+
+        case SWT.ARROW_LEFT:
+        {
+            LayoutObject obj = getFirstLayoutObjectOfItem(fromItem);
+            while((obj = getPrevLayoutObjectOfItem(obj, null)) != null)
+            {
+                Item owner = obj.getOwningItem();
+                if(owner != null && owner != fromItem
+                        && owner.isFocusable()
+                        && isPartiallyVisible(obj, Config.DFI_VISIBILITY_PERCENT))
+                {
+                    nextItem = owner;
+                    break;
+                }
+            }
+            break;
+        }
+
+        case SWT.ARROW_DOWN:
+        {
+            int minDist = Integer.MAX_VALUE;
+            LayoutObject start = getLastLayoutObjectOfItem(fromItem);
+            LayoutObject obj = start;
+            while((obj = getNextLayoutObjectOfItem(obj, null)) != null)
+            {
+                Item owner = obj.getOwningItem();
+                if(owner != null && owner != fromItem
+                        && owner.isFocusable() && obj.isBelow(start)
+                        && isPartiallyVisible(obj, Config.DFI_VISIBILITY_PERCENT))
+                {
+                    int dist = obj.distanceTo(start);
+                    if(dist < minDist)
+                    {
+                        minDist = dist;
+                        nextItem = owner;
+                    }
+                }
+            }
+            break;
+        }
+
+        case SWT.ARROW_UP:
+        {
+            int minDist = Integer.MAX_VALUE;
+            LayoutObject start = getFirstLayoutObjectOfItem(fromItem);
+            LayoutObject obj = start;
+            while((obj = getPrevLayoutObjectOfItem(obj, null)) != null)
+            {
+                Item owner = obj.getOwningItem();
+                if(owner != null && owner != fromItem
+                        && owner.isFocusable() && obj.isAbove(start)
+                        && isPartiallyVisible(obj, Config.DFI_VISIBILITY_PERCENT))
+                {
+                    int dist = obj.distanceTo(start);
+                    if(dist < minDist)
+                    {
+                        minDist = dist;
+                        nextItem = owner;
+                    }
+                }
+            }
+            break;
+        }
+
+        default:
+        }
+
+        return nextItem;
+    }
+
+    /**
+     * Check if the currentSelectedItem is valid and visible. If not then it
+     * sets it to null.
+     */
+    final void eswtCheckCurrentSelectedItem()
+    {
+        if(currentSelectedItem != null)
+        {
+            if(currentSelectedItem.getParent() != getForm()
+                    || !currentSelectedItem.isVisible())
+            {
+                // we need to find another
+                Logger.method(this, "eswtCheckCurrentSelectedItem");
+                eswtSetCurrentSelectedItem(null, NO_DIRECTION);
+            }
+        }
+    }
+
+    /**
+     * Sets currentSelectedItem and sets focus to it.<br>
+     * If one of form's items is already selected when this method is called,
+     * removes focus from old item and then moves focus to new one.
+     *
+     * @param item Item to set as current selected. If null, nothing happens.
+     * @param dir Direction which is delivered to layouter.
+     */
+    void eswtSetCurrentSelectedItem(Item item, int dir)
+    {
+        if(currentSelectedItem != item)
+        {
+            Logger.info(this + "::SelectedItem: "
+                        + currentSelectedItem + " --(" + dir + ")--> " + item);
+
+            // Save direction
+            direction = dir;
+            // Remove focus from currentSelectedItem and notify its Layouter.
+            if(currentSelectedItem != null)
+            {
+                getItemLayouter(currentSelectedItem).eswtFocusLost(
+                    currentSelectedItem);
+            }
+
+            // Set new currentSelectedItem, must be focusable or null
+            currentSelectedItem = item;
+
+            // Set focus to currentSelectedItem and notify its Layouter.
+            if(currentSelectedItem != null)
+            {
+                getItemLayouter(currentSelectedItem).eswtFocusGained(
+                    currentSelectedItem, dir);
+            }
+
+            // Apply eSWT focus to currentSelectedItem's control
+            eswtApplyCurrentFocus();
+        }
+    }
+
+    /**
+     * Sets currentSelectedItem and sets focus to it.<br>
+     * If one of form's items is already selected when this method is called,
+     * removes focus from old item and then moves focus to new one.
+     *
+     * @param item Item to set as current selected. If null, nothing happens.
+     * @param dir Direction which is delivered to layouter.
+     */
+    void eswtSetCurrentSelectedItem(Item item)
+    {
+        if(currentSelectedItem != item)
+        {
+            Logger.info(this + "::SelectedItem: "
+                        + currentSelectedItem + " ---> " + item);
+
+            // Remove focus from currentSelectedItem and notify its Layouter.
+            if(currentSelectedItem != null)
+            {
+                getItemLayouter(currentSelectedItem).eswtFocusLost(
+                    currentSelectedItem);
+            }
+
+            // Set new currentSelectedItem, must be focusable or null
+            currentSelectedItem = item;
+
+            // Set focus to currentSelectedItem and notify its Layouter.
+            if(currentSelectedItem != null)
+            {
+                getItemLayouter(currentSelectedItem).eswtFocusGained(
+                    currentSelectedItem, NO_DIRECTION);
+            }
+
+            // Apply eSWT focus to currentSelectedItem's control
+            //eswtApplyCurrentFocus();
+        }
+    }
+
+    /**
+     * Sets focus to currentSelectedItem's control if its partially visible.
+     * Otherwise it sets dummy focus to form's composite.<br>
+     * <br>
+     * Note that this method applies focus only to eSWT control. Item focus
+     * update and layouter notifications are handled in method
+     * <code>eswtSetCurrentSelectedItem()</code>.<br>
+     * If currentSelectedItem is null or form is not shown, this method has no
+     * effect.
+     */
+    void eswtApplyCurrentFocus()
+    {
+        if(isFormCurrent())
+        {
+            // if any of the Item's LayoutObjects is visible
+            if(isItemPartiallyVisible(currentSelectedItem))
+            {
+                Logger.method(this, "ApplyFocus", currentSelectedItem);
+                eswtSetFocusToFirstControl(currentSelectedItem);
+            }
+            else
+            {
+                Logger.method(this, "ApplyFocus", "dummy");
+                formComposite.forceFocus();
+            }
+        }
+    }
+
+    /**
+     * If the Item is valid and it is layouted, then sets the Item's first
+     * LayoutObject focused.
+     *
+     * @param item an item which first LayoutObject is set focused.
+     */
+    void eswtSetFocusToFirstControl(Item item)
+    {
+        if(item != null && item.isFocusable())
+        {
+            LayoutObject lo = getFirstLayoutObjectOfItem(item);
+            if(lo != null)
+            {
+                lo.getControl().forceFocus();
+            }
+        }
+    }
+
+    /**
+     * Gets Current selected item.
+     *
+     * @return Current selected item. May also return null.
+     */
+    Item getCurrentSelectedItem()
+    {
+        return currentSelectedItem;
+    }
+
+    /**
+     * Get the direction of scrolling.
+     *
+     * @return direction of scrolling.
+     */
+    int getDirection()
+    {
+        return direction;
+    }
+
+    /**
+     * Set focus to an item if it is focusable and scroll form to make it
+     * visible if it is not.
+     *
+     * @param item Item to set as current item.
+     */
+    void setCurrentItem(final Item item)
+    {
+        Logger.method(this, "setCurrentItem", item);
+        ESWTUIThreadRunner.syncExec(new Runnable()
+        {
+            public void run()
+            {
+                eswtSetCurrentItem(item);
+            }
+        });
+    }
+
+    /**
+     * eSWT callback for setCurrentItem.
+     */
+    boolean eswtSetCurrentItem(Item item)
+    {
+        if(item != null)
+        {
+            if(isItemLayouted(item))
+            {
+                eswtScrollToItem(item);
+                deferredScrollToItem = null;
+
+				if(item.isFocusable())
+				{
+					eswtSetCurrentSelectedItem(item, NO_DIRECTION);
+					Logger.info("eswtSetCurrentItem" + item);
+				}
+                return true;
+            }
+            else
+            {
+                deferredScrollToItem = item;
+            }
+        }
+        return false;
+    }
+
+    void eswtScrollToItem(Item item)
+    {
+        if(item != null)
+        {
+            int pos = getItemBottomPosition(item) - getFormHeight();
+            if(!isItemPartiallyVisible(item))
+            {
+                eswtSetScrollingPosition(pos, true);
+            }
+            else if(item instanceof TextField && !isItemFullyVisible(item))
+            {
+                eswtSetScrollingPosition(pos, true);
+            }
+        }
+    }
+
+    void eswtScrolltoRegion(int yTop, int yBottom, int swtDir)
+    {
+        if(yTop < vPosition || yBottom > vPosition + getFormHeight())
+        {
+            // if the region is somewhat outside the screen
+            if(swtDir == SWT.ARROW_DOWN || swtDir == SWT.ARROW_RIGHT)
+            {
+                // align to top
+                eswtSetScrollingPosition(yTop, true);
+            }
+            else
+            {
+                // align to bottom
+                eswtSetScrollingPosition(yBottom - getFormHeight(), true);
+            }
+        }
+    }
+
+    void eswtScrollIfNeeded(final int top, final int bottom)
+    {
+        if(bottom > vPosition + getFormHeight())
+        {
+            eswtSetScrollingPosition(bottom - (getFormHeight() / 2), true);
+        }
+        else if(top < vPosition)
+        {
+            eswtSetScrollingPosition(bottom - (getFormHeight() / 2), true);
+        }
+    }
+
+    /**
+     * Get control's position relative to composite.
+     */
+    void getControlPositionOnComposite(Control control, Point location)
+    {
+        if(control != formComposite)
+        {
+            Point rel = control.getLocation();
+            location.x += rel.x;
+            location.y += rel.y;
+            getControlPositionOnComposite(control.getParent(), location);
+        }
+    }
+
+    /**
+     * eSWT specific calls to do update ScrolledComposite.
+     */
+    private void eswtUpdateFormComposite(boolean show)
+    {
+        if(getRowCount() > 0)
+        {
+            if(show)
+            {
+                formComposite.updateScrollbar(getLastRow().getBottomPosition());
+                formComposite.pack();
+            }
+        }
+        // Could happen if changing item from very tall to very short.
+        // so we have to update VPosition
+        if(getVPosition() > eswtGetMaxVPosition())
+        {
+            eswtSetScrollingPosition(eswtGetMaxVPosition(), false);
+        }
+
+        formComposite.setRedraw(show);
+        formComposite.setVisible(show);
+    }
+
+    /**
+     * Clean all form rows starting from startIndex.
+     *
+     * @param startIndex Start row from which to clean.
+     * @param keepItem - item in a startRow which shouldn't be recreated.
+     */
+    private void eswtClearRows(int startIndex, Item keepItem)
+    {
+        Logger.method(this, "clearRows", String.valueOf(startIndex), keepItem);
+        Row row = null;
+        for(int i = (getRowCount() - 1); i >= startIndex; i--)
+        {
+            row = getRow(i);
+            if(row.cleanRow(keepItem))
+            {
+                break;
+            }
+            else
+            {
+                rows.removeElement(row);
+            }
+        }
+
+        // one row always should be available.
+        if((getRowCount() == 0))
+        {
+            // rows.addElement(tempRow);
+            currentHLayoutDirective = Item.LAYOUT_DEFAULT;
+            Row newRow = new Row(ItemLayouter.getMaximumItemWidth(null),
+                                 getCurrentHLayoutDirective());
+            rows.addElement(newRow);
+        }
+    }
+
+    /**
+     * Update Row's internal layout. Handles LAYOUT_2 related post-processing.
+     *
+     * @param row Row
+     */
+    private void eswtUpdateRow(Row row)
+    {
+        if(row != null)
+        {
+            //Logger.verbose("updateRow start: " + row);
+            int numShrink = row.getNumLayoutObjects(Item.LAYOUT_SHRINK);
+            int numExpand = row.getNumLayoutObjects(Item.LAYOUT_EXPAND);
+            //Logger.verbose("shrink: " + numShrink + " expand: " + numExpand);
+
+            int vMask = Item.LAYOUT_VSHRINK | Item.LAYOUT_VEXPAND;
+            // Expand items vertically with VSHRINK or VEXPAND layout directive
+            LayoutObject lo = null;
+            int maxHeight = row.getRowHeight(vMask);
+            while((lo = row.getNextLayoutObject(lo, vMask)) != null)
+            {
+                if(lo.getOwningItem().hasLayout(Item.LAYOUT_VSHRINK))
+                {
+                    int pref = lo.getOwningItem().getPreferredHeight();
+                    getItemLayouter(lo.getOwningItem()).eswtResizeObject(lo,
+                            lo.getWidth(), Math.min(pref, maxHeight));
+                }
+                else if(lo.getOwningItem().hasLayout(Item.LAYOUT_VEXPAND))
+                {
+                    getItemLayouter(lo.getOwningItem()).eswtResizeObject(lo,
+                            lo.getWidth(), maxHeight);
+                }
+            }
+
+            // Expand items with SHRINK layout directive
+            if(numShrink > 0)
+            {
+                // Get extra space before shrink and expand
+                int offset = row.getFreeSpace() / numShrink;
+                // Logger.verbose("shrinkOffset: " + offset);
+                if(offset >= 0)
+                {
+                    while((lo = row.getNextLayoutObject(lo, Item.LAYOUT_SHRINK)) != null)
+                    {
+                        int pref = lo.getOwningItem().getPreferredWidth();
+                        int min = lo.getOwningItem().getMinimumWidth();
+                        int itemWidth = Math.min(pref, min + offset);
+                        getItemLayouter(lo.getOwningItem()).eswtResizeObject(lo,
+                                itemWidth, lo.getHeight());
+                    }
+                }
+            }
+
+            // Expand items with EXPAND layout directive
+            if(numExpand > 0)
+            {
+                // Get extra space after shrink but before expand
+                int offset = row.getFreeSpace(Item.LAYOUT_EXPAND) / numExpand;
+                if(offset >= 0)
+                {
+                    // Logger.verbose("expandOffset: " + offset);
+                    while((lo = row.getNextLayoutObject(lo, Item.LAYOUT_EXPAND)) != null)
+                    {
+                        int pref = lo.getOwningItem().getPreferredWidth();
+                        getItemLayouter(lo.getOwningItem()).eswtResizeObject(lo,
+                                pref + offset, lo.getHeight());
+                    }
+                }
+            }
+
+            //if (numShrink > 0 || numExpand > 0) {
+            row.updateRowInternals();
+            //}
+
+            row.updateRowLayout(form.getLeftRightLanguage());
+            // Logger.verbose("updateRow: " + row);
+        }
+    }
+
+    /**
+     * Add a new Row.
+     */
+    private Row eswtAddNewRow()
+    {
+        Row lastRow = getLastRow();
+        eswtUpdateRow(lastRow);
+        int yShift = (lastRow == null ? 0 : lastRow.getBottomPosition());
+        // create new Row
+        Row newRow = new Row(ItemLayouter.getMaximumItemWidth(null),
+                             getCurrentHLayoutDirective());
+        newRow.setYShift(yShift);
+        rows.addElement(newRow);
+        return newRow;
+    }
+
+    /**
+     * Add a LayoutObject to the last Row.
+     *
+     * @param layoutObject the layout object
+     */
+    void eswtAddNewLayoutObject(LayoutObject layoutObject)
+    {
+    	if(!layoutObjects.contains(layoutObject))
+    	{
+    		layoutObjects.addElement(layoutObject);
+    	}
+        Row lastRow = getLastRow();
+        // check if the current Row is full
+        if(!lastRow.isEmpty()
+                && lastRow.getFreeSpace() < layoutObject.getWidth())
+        {
+            lastRow = eswtAddNewRow();
+        }
+        lastRow.eswtAddLayoutObject(layoutObject);
+        layoutObject.setRowIdx(getRowCount() - 1);
+    }
+
+    /**
+     * Optionally add a new Row and adds a LayoutObject.
+     *
+     * @param layoutObject the layout object
+     * @param newRow adds a new row if true. If false, adds new row only if
+     *            there's no space for layoutObject in current row.
+     */
+    void eswtAddNewLayoutObject(LayoutObject layoutObject, boolean newRow)
+    {
+        if(newRow)
+        {
+            eswtAddNewRow();
+        }
+        eswtAddNewLayoutObject(layoutObject);
+    }
+
+    /**
+     * Layout item in a row, if needed new row is added.
+     *
+     * @param row - where to startLayout.
+     * @param item - Item to Layout
+     */
+    private void eswtLayoutItem(Item item)
+    {
+        Row lastRow = getLastRow();
+        boolean hlChange = setCurrentHLayoutDirective(item.internalGetLayout());
+        if(hlChange || getItemNewLineBefore(item))
+        {
+            // newline directive or horizontal layout changed
+            if(lastRow.isEmpty())
+            {
+                // if the current/last row is empty - use that
+                lastRow.setRowHLayout(getCurrentHLayoutDirective());
+            }
+            else
+            {
+                eswtAddNewRow();
+            }
+        }
+
+        // Use the specific layouter to layout item in the last row
+        getItemLayouter(item).eswtLayoutItem(getLastRow(), item);
+
+        if(form.eswtIsShown())
+        {
+            LayoutObject lo = getFirstLayoutObjectOfItem(item);
+            if(lo != null)
+            {
+                getItemLayouter(item).eswtAddListeners(item, lo);
+            }
+        }
+
+        if(getItemNewLineAfter(item))
+        {
+            eswtAddNewRow();
+        }
+    }
+
+    /**
+     * Set Form's Layout directive. if it differ from current set flag
+     * startFromNewLine = true;
+     *
+     * @param newLayoutDirective
+     * @return true if a layout change has occured
+     */
+    private boolean setCurrentHLayoutDirective(int newLayoutDirective)
+    {
+        int newHLayoutDirective = Item.getHorizontalLayout(newLayoutDirective);
+        if((newHLayoutDirective != currentHLayoutDirective)
+                && (newHLayoutDirective != Item.LAYOUT_DEFAULT))
+        {
+            currentHLayoutDirective = newHLayoutDirective;
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Get Form current Layout directive.
+     *
+     * @return current Layout directive for Form.
+     */
+    private int getCurrentHLayoutDirective()
+    {
+        if(currentHLayoutDirective == Item.LAYOUT_DEFAULT)
+        {
+            return getLanguageSpecificLayoutDirective();
+        }
+        return currentHLayoutDirective;
+    }
+
+    /**
+     * Returns language specific layout directive.
+     *
+     * @return LAYOUT_LEFT or LAYOUT_RIGHT.
+     */
+    int getLanguageSpecificLayoutDirective()
+    {
+        if(form.getLeftRightLanguage())
+        {
+            return Item.LAYOUT_LEFT;
+        }
+        else
+        {
+            return Item.LAYOUT_RIGHT;
+        }
+    }
+
+    private boolean getItemNewLineBefore(Item item)
+    {
+        return ((item.internalGetLayout() & Item.LAYOUT_NEWLINE_BEFORE) != 0);
+    }
+
+    private boolean getItemNewLineAfter(Item item)
+    {
+        return ((item.internalGetLayout() & Item.LAYOUT_NEWLINE_AFTER) != 0);
+    }
+
+    boolean isItemLayouted(Item item)
+    {
+        return (getFirstLayoutObjectOfItem(item) != null);
+    }
+
+    /**
+     * Returns if the form is shown.
+     */
+    boolean isFormCurrent()
+    {
+        return isCurrent;
+    }
+
+    /**
+     * Returns if the region is partially visible.
+     *
+     * @param viewTop viewPort's top position
+     * @param viewBottom viewPort's bottom position
+     * @return true if visible
+     */
+    boolean isPartiallyVisible(int yTop, int yBottom)
+    {
+        int vBottomPosition = vPosition + getFormHeight();
+        if((vPosition <= yTop && vBottomPosition <= yTop)
+                || (vPosition >= yBottom && vBottomPosition >= yBottom))
+        {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Returns if at least the region's given percentage is visible.
+     */
+    boolean isPartiallyVisible(int yTop, int yBottom, int minPercent)
+    {
+        int visPercent = getVisibilityPercent(yTop, yBottom);
+        if(visPercent > minPercent)
+        {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Returns the region's visibility percentage.
+     */
+    int getVisibilityPercent(int yTop, int yBottom)
+    {
+        if(yTop >= yBottom)
+        {
+            return 0;
+        }
+        int vBottomPosition = vPosition + getFormHeight();
+        int r1 = Math.max(vPosition, Math.min(yTop, vBottomPosition));
+        int r2 = Math.min(vBottomPosition, Math.max(yBottom, vPosition));
+        return ((r2 - r1) * 100) / (yBottom - yTop);
+    }
+
+    /**
+     * Returns if the LayoutObject is partially visible.
+     */
+    boolean isPartiallyVisible(LayoutObject lo)
+    {
+        if(lo != null)
+        {
+            return isPartiallyVisible(lo.getY(), lo.getY() + lo.getHeight());
+        }
+        return false;
+    }
+
+    /**
+     * Returns if at least the LayoutObject's given percentage is visible.
+     */
+    boolean isPartiallyVisible(LayoutObject lo, int minPercent)
+    {
+        if(lo != null)
+        {
+            return isPartiallyVisible(lo.getY(), lo.getY() + lo.getHeight(),
+                                      minPercent);
+        }
+        return false;
+    }
+
+    /**
+     * Returns if the Item is partially visible (if one of its LayoutObjects is
+     * partially visible).
+     *
+     * @param item the Item
+     * @return true if partially visible
+     */
+    boolean isItemPartiallyVisible(Item item)
+    {
+        if(item != null)
+        {
+            LayoutObject lo = null;
+            while((lo = getNextLayoutObjectOfItem(lo, item)) != null)
+            {
+                if(isPartiallyVisible(lo))
+                {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+
+
+    /**
+     * Returns true if item is fully visible.
+     *
+     * @param item the Item.
+     * @return true if fully visible.
+     */
+    boolean isItemFullyVisible(Item item)
+    {
+        if(item != null)
+        {
+            LayoutObject lo = null;
+            while((lo = getNextLayoutObjectOfItem(lo, item)) != null)
+            {
+                if(!isLOFullyVisible(lo))
+                {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Returns if the LayoutObject is fully visible.
+     */
+    boolean isLOFullyVisible(LayoutObject lo)
+    {
+        if(lo != null)
+        {
+            return isFullyVisible(lo.getY(), lo.getY() + lo.getHeight());
+        }
+        return false;
+    }
+
+    /**
+     * Returns if the region is fully visible.
+     *
+     * @param viewTop viewPort's top position
+     * @param viewBottom viewPort's bottom position
+     * @return true if visible
+     */
+    boolean isFullyVisible(int yTop, int yBottom)
+    {
+        int vBottomPosition = vPosition + getFormHeight();
+        if((vPosition <= yTop && vBottomPosition >= yBottom))
+        {
+            return true;
+        }
+        return false;
+    }
+
+    int getItemTopPosition(Item item)
+    {
+        LayoutObject lo = getFirstLayoutObjectOfItem(item);
+        if(lo != null)
+        {
+            return lo.getY();
+        }
+        return 0;
+    }
+
+    int getItemBottomPosition(Item item)
+    {
+        LayoutObject lo = getLastLayoutObjectOfItem(item);
+        if(lo != null)
+        {
+            return lo.getY() + lo.getHeight();
+        }
+        return 0;
+    }
+
+    int getItemCount()
+    {
+        return form.size();
+    }
+
+    Item getItem(int index)
+    {
+        try
+        {
+            return (Item) form.getItems().elementAt(index);
+        }
+        catch(ArrayIndexOutOfBoundsException e)
+        {
+            // Logger.exception(e);
+            return null;
+        }
+    }
+
+    int getItemIndex(Item item)
+    {
+        return form.getItems().indexOf(item);
+    }
+
+    int getRowCount()
+    {
+        return rows.size();
+    }
+
+    /**
+     * Return the Row with the given index.
+     *
+     * @param index Row's index
+     * @return a Row
+     */
+    Row getRow(int index)
+    {
+        try
+        {
+            return (Row) rows.elementAt(index);
+        }
+        catch(ArrayIndexOutOfBoundsException e)
+        {
+            Logger.exception("getRow", e);
+            return null;
+        }
+    }
+
+    /**
+     * Return the Row to which the given LayoutObject belongs.
+     *
+     * @param lo LayoutObject
+     * @return the owning Row
+     */
+    Row getRow(LayoutObject lo)
+    {
+        try
+        {
+            return getRow(lo.getRowIdx());
+        }
+        catch(NullPointerException e)
+        {
+            // Logger.exception("getRow", e);
+            return null;
+        }
+    }
+
+    /**
+     * Returns the last row of the form.
+     */
+    Row getLastRow()
+    {
+        try
+        {
+            return (Row) rows.lastElement();
+        }
+        catch(NoSuchElementException nse)
+        {
+            // Logger.exception("getLastRow", nse);
+            return null;
+        }
+    }
+
+    /**
+     * Find last row which contains corresponding Item.
+     *
+     * @param item Item in a Row.
+     * @return Last Row with that item.
+     */
+    Row getLastRowOfItem(Item item)
+    {
+        return getRow(getLastLayoutObjectOfItem(item));
+    }
+
+    /**
+     * Get Form which requires layout.
+     *
+     * @return form.
+     */
+    Form getForm()
+    {
+        return form;
+    }
+
+    /**
+     * Form's content height.
+     */
+    int getFormHeight()
+    {
+        return form.getHeight();
+    }
+
+    /**
+     * Form's content width.
+     */
+    int getFormWidth()
+    {
+        return form.getWidth();
+    }
+
+    /**
+     * Returns LayoutObject for the given Item.
+     *
+     * @param item Item to layout
+     * @return LayoutObject
+     */
+    LayoutObject getLayoutObject(Item item)
+	{
+		int num = layoutObjects.size();
+
+		for(int i = 0; i < num; i++)
+		{
+			if(((LayoutObject)layoutObjects.elementAt(i)).getOwningItem() == item)
+			{
+				LayoutObject lo = (LayoutObject)(layoutObjects.elementAt(i));
+				lo.setRowIdx(-1);
+				return lo;
+			}
+		}
+
+		return null;
+	}
+
+    /**
+     * Removes Layout Object for the given Item.
+     *
+     * @param item Item to remove LayoutObject
+     */
+    void removeLayoutObject(Item item)
+	{
+
+		int num = layoutObjects.size();
+
+		for(int i = 0; i < num; i++)
+		{
+			if(((LayoutObject)layoutObjects.elementAt(i)).getOwningItem() == item)
+			{
+				LayoutObject lo = (LayoutObject)(layoutObjects.elementAt(i));
+				layoutObjects.removeElement(lo);
+				lo.dispose();
+				break;
+			}
+		}
+	}
+
+    /**
+     * Removes all Layout Objects from the FormLayouter.
+     */
+    void removeAllLayoutObjects()
+	{
+		Enumeration e = layoutObjects.elements();
+
+		while(e.hasMoreElements())
+		{
+			LayoutObject lo = (LayoutObject)e.nextElement();
+			layoutObjects.removeElement(lo);
+			lo.dispose();
+		}
+	}
+
+    /**
+     * Returns the next LayoutObject belonging to this Item.<br>
+     *
+     * @param lo starting LayoutObject; if null then it start from first.
+     * @param item specifies the parent Item; null means any Item
+     * @return the next LayoutObject in the layout.
+     */
+    LayoutObject getNextLayoutObjectOfItem(LayoutObject lo, Item item)
+    {
+        int startRow = (lo == null ? 0 : lo.getRowIdx());
+        LayoutObject temp = null;
+        for(int i = startRow; i < getRowCount(); i++)
+        {
+            temp = getRow(i).getNextLayoutObject(lo, item);
+            if(temp != null && temp != lo)
+            {
+                return temp;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns the previous LayoutObject belonging to this Item.<br>
+     *
+     * @param lo starting LayoutObject; if null then it start from last.
+     * @param item specifies the parent Item; null means any Item
+     * @return the previous LayoutObject in the layout.
+     */
+    LayoutObject getPrevLayoutObjectOfItem(LayoutObject lo, Item item)
+    {
+        int startRow = (lo == null ? rows.size() - 1 : lo.getRowIdx());
+        LayoutObject temp = null;
+        for(int i = startRow; i >= 0; i--)
+        {
+            temp = getRow(i).getPrevLayoutObject(lo, item);
+            if(temp != null && temp != lo)
+            {
+                return temp;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns the first LayoutObject of a layouted item.
+     *
+     * @param item
+     * @return the LO, or NULL if the item is not layouted
+     */
+    LayoutObject getFirstLayoutObjectOfItem(Item item)
+    {
+        if(item != null)
+        {
+            return getNextLayoutObjectOfItem(null, item);
+        }
+        return null;
+    }
+
+    /**
+     * Returns the last LayoutObject of a layouted item.
+     *
+     * @param item
+     * @return the LO, or NULL if the item is not layouted
+     */
+    LayoutObject getLastLayoutObjectOfItem(Item item)
+    {
+        if(item != null)
+        {
+            return getPrevLayoutObjectOfItem(null, item);
+        }
+        return null;
+    }
+
+    /**
+     * Update item state in form.
+     *
+     * @param item
+     * @param updateReason
+     * @param param additional parameter
+     */
+    void updateItemState(Item item, int updateReason, Object param)
+    {
+        Logger.method(this, "updateItemState", item,
+                      String.valueOf(updateReason), param);
+
+		LayoutObject lo = getFirstLayoutObjectOfItem(item);
+
+		if(lo != null)
+		{
+			getItemLayouter(item).updateItem(item, lo.getControl(), updateReason,
+										 param);
+		}
+
+        // Clean reason - without resizing flags
+        int reason = updateReason & Item.UPDATE_SIZE_MASK;
+        switch(reason)
+        {
+        case Item.UPDATE_ADDCOMMAND:
+        {
+            if(isFormCurrent() && param != null)
+            {
+                if(lo != null && param instanceof Command)
+                {
+                    lo.addCommand((Command) param);
+                }
+            }
+            break;
+        }
+        case Item.UPDATE_REMOVECOMMAND:
+        {
+            if(isFormCurrent() && param != null)
+            {
+                if(lo != null && param instanceof Command)
+                {
+                    lo.removeCommand((Command) param);
+                }
+            }
+            break;
+        }
+        }
+
+        // Check this always - because this is a flag
+        if((updateReason & Item.UPDATE_HEIGHT_CHANGED)
+                == Item.UPDATE_HEIGHT_CHANGED)
+        {
+            resizeItemAndShift(item);
+        }
+    }
+
+    int eswtGetMaxVPosition()
+    {
+        return formComposite.getSize().y - getFormHeight();
+    }
+
+    /**
+     * Called by key Form to compute new vertical coordinate to position form's
+     * content.
+     *
+     * @param swtDir scrolling direction.
+     * @return New vertical position of Form's content.
+     */
+    protected int getNextScrollingPosition(int swtDir)
+    {
+        boolean scrollDown = (swtDir == SWT.ARROW_DOWN
+                              || swtDir == SWT.ARROW_RIGHT);
+        int formHeight = getFormHeight();
+        int refPoint;
+        int ret = vPosition;
+        if(scrollDown)
+        {
+            ret += formHeight / 5;
+            refPoint = (vPosition + 1) + formHeight;
+        }
+        else
+        {
+            ret -= formHeight / 5;
+            refPoint = (vPosition - 1);
+        }
+
+        Row row = null;
+        for(int i = 0; i < getRowCount(); i++)
+        {
+            row = getRow(i);
+            if(row.isInsideRow(refPoint)
+                    && (row.getRowHeight() < formHeight))
+            {
+                if(scrollDown)
+                {
+                    ret = row.getBottomPosition() - formHeight;
+                }
+                else
+                {
+                    ret = row.getYShift();
+                }
+                break;
+            }
+        }
+
+        return ret;
+    }
+
+    /**
+     * Set the scrolling to the specified position.<br>
+     * This method also updates the Form's scrollbars.
+     *
+     * @param position new position
+     */
+    void eswtSetScrollingPosition(int position, boolean keyNav)
+    {
+        // check constraints
+        int newVPosition = position;
+        int maxVPos = eswtGetMaxVPosition();
+        newVPosition = Math.min(newVPosition, maxVPos);
+        newVPosition = Math.max(newVPosition, 0);
+
+        vPosition = newVPosition;
+        formComposite.setRedraw(false);
+        formComposite.setOrigin(0, vPosition, keyNav);
+        formComposite.pack();
+        formComposite.setRedraw(true);
+
+        eswtHandleVisibilityChanges();
+    }
+
+    /**
+     * Returns the scrolling position.
+     */
+    protected int getScrollingPosition()
+    {
+        return vPosition;
+    }
+
+    /**
+     * Updates visibility status of all items.
+     */
+    protected void eswtHandleVisibilityChanges()
+    {
+        // Logger.method(this, "eswtHandleVisibilityChanges");
+        boolean shown = false;
+        Item item = null;
+        LayoutObject lo = null;
+        // Go through all LayoutObjects and check/update visibilities
+        while((lo = getNextLayoutObjectOfItem(lo, null)) != null)
+        {
+            // check if owning item is changing
+            if(lo.getOwningItem() != item)
+            {
+                if(item != null)
+                {
+                    // set current item's visibility
+                    getItemLayouter(item).eswtHandleVisibilityChange(item, shown);
+                }
+                // new item
+                item = lo.getOwningItem();
+                shown = false;
+            }
+
+            // track current item's visibility
+            if(!shown && isFormCurrent() && isPartiallyVisible(lo))
+            {
+                shown = true;
+            }
+        }
+
+        // call it for last item
+        if(item != null)
+        {
+            getItemLayouter(item).eswtHandleVisibilityChange(item, shown);
+        }
+
+		eswtCheckCurrentSelectedItem();
+    }
+
+    /**
+     * Changes item size and does shift of all Rows.
+     *
+     * @param item - item to changeSize.
+     */
+    void resizeItemAndShift(final Item item)
+    {
+        ESWTUIThreadRunner.syncExec(new Runnable()
+        {
+            public void run()
+            {
+                int newVPosition = eswtResizeItemAndShift(item);
+                if(newVPosition != vPosition)
+                {
+                    eswtSetScrollingPosition(newVPosition, true);
+                }
+                else
+                {
+                    eswtHandleVisibilityChanges();
+                }
+            }
+        });
+    }
+
+    /**
+     * eSWT callback for resizeItemAndShift.
+     *
+     * @param item Item to be resized.
+     * @return new scrolling vPosition
+     */
+    int eswtResizeItemAndShift(Item item)
+    {
+		// save the state of the last row before resizing and Shifting.
+		boolean itemWasVisible = isItemPartiallyVisible(item);
+        Row row = getLastRowOfItem(item);
+        int deltaYShift = row.getRowHeight();
+        // if we un-comment this then when we set true,
+        // focus will jump to first item.
+        // eswtUpdateFormComposite(false);
+        LayoutObject lo = getFirstLayoutObjectOfItem(item);
+        if(lo != null)
+        {
+            getItemLayouter(item).eswtResizeObject(lo);
+        }
+
+        eswtUpdateRow(row);
+
+        /*
+        // to avoid double call of updateRowInternals
+        if (row.getNumLayoutObjects(Item.LAYOUT_SHRINK) > 0
+                || row.getNumLayoutObjects(Item.LAYOUT_EXPAND) > 0) {
+            eswtUpdateRow(row);
+        }
+        else {
+            row.updateRowInternals();
+        }
+        */
+        deltaYShift = row.getRowHeight() - deltaYShift;
+        // row's height change - all remaining rows are shifted with this.
+
+        Row lastRow = getLastRow();
+        if(row != lastRow)
+        {
+            for(int i = rows.indexOf(row) + 1; i < getRowCount(); i++)
+            {
+                row = getRow(i);
+                row.setYShift(row.getYShift() + deltaYShift);
+                eswtUpdateRow(row);
+            }
+        }
+
+        // following code updates scrolling if needed.
+        // need to check where in the form resize happeneed.
+
+        int itemRowYShift = getLastRowOfItem(item).getYShift();
+        // vPosition should be changed in syncexec
+        int newVPosition = vPosition;
+
+        // we need to scroll only if changes happened above the screen.
+        if(newVPosition >= itemRowYShift)
+        {
+            newVPosition = Math.max(0, newVPosition + deltaYShift);
+        }
+        // check to avoid gap in the bottom of the form
+        if(newVPosition + getFormHeight() > lastRow.getBottomPosition())
+        {
+            newVPosition = Math.max(0,
+                                    lastRow.getBottomPosition() - getFormHeight());
+        }
+
+        eswtUpdateFormComposite(true);
+
+        // formComposite.pack();
+        // formComposite.updateScrollbarSize(lastRow.getBottomPosition());
+
+		if(item == currentSelectedItem)
+		{
+			if(itemWasVisible)
+			{
+				int itemTop = getItemTopPosition(item);
+				int itemBottom = getItemBottomPosition(item);
+				// currentSelectedItem has to be focused if it was focused
+				// before resizing e.g TextField when it is resized by adding a
+				// new row and it was in the bottom of the Screen.
+				if(newVPosition <= itemTop
+						&& (newVPosition + getFormHeight()) >= itemBottom)
+				{
+					// do not change vPosition;
+				}
+				else if(newVPosition > itemTop)
+				{
+					newVPosition = itemTop;
+				}
+				else if((newVPosition + getFormHeight()) < itemBottom)
+				{
+					newVPosition = itemBottom - getFormHeight();
+				}
+			}
+		}
+		return newVPosition;
+    }
+
+    /**
+     * Gets layouter that can layout the specified item.
+     *
+     * @param item Item to be layouted.
+     * @return ItemLayouter or null if no Layouter found.
+     */
+    protected final ItemLayouter getItemLayouter(Item item)
+    {
+        if(item instanceof StringItem)
+        {
+            return sIL;
+        }
+        else if(item instanceof ImageItem)
+        {
+            return imIL;
+        }
+        else if(item instanceof Gauge)
+        {
+            return gL;
+        }
+        else if(item instanceof TextField)
+        {
+            return tfL;
+        }
+        else if(item instanceof DateField)
+        {
+            return dfL;
+        }
+        else if(item instanceof ChoiceGroup)
+        {
+            return cgL;
+        }
+        else if(item instanceof CustomItem)
+        {
+            return ciL;
+        }
+        else if(item instanceof Spacer)
+        {
+            return sL;
+        }
+        return null;
+    }
+
+    /**
+     * Returns eSWT Control that represents the item specified.
+     */
+    Control getItemControl(final Item item)
+    {
+        final LayoutObject lo = getFirstLayoutObjectOfItem(item);
+        if(lo != null)
+        {
+            ESWTUIThreadRunner.syncExec(new Runnable()
+            {
+                public void run()
+                {
+                    itemMainControl = getItemLayouter(item)
+                                      .eswtFindSpecificControl(item, lo.getControl());
+                }
+            });
+            return itemMainControl;
+        }
+        return null;
+    }
+
+    void updateScrolling(final int value, final boolean keyNav)
+    {
+        Logger.method("updateScrolling", String.valueOf(value));
+        ESWTUIThreadRunner.syncExec(new Runnable()
+        {
+            public void run()
+            {
+
+                eswtSetScrollingPosition(value, keyNav);
+
+            }
+        });
+    }
+
+    /**
+     * Get current scrolling value.
+     *
+     * @return vPosition.
+     */
+    int getVPosition()
+    {
+        return vPosition;
+    }
+
+
+	private Timer eventTimer = new Timer();
+	private EventGeneratorTask eventTask;
+
+	/**
+	 * Reset timer for do layout with a given start index.
+	 */
+	private void resetEventTimer(boolean directionUp, int y)
+	{
+		if(eventTimer != null)
+		{
+			if(eventTask != null)
+			{
+				eventTask.cancel();
+				eventTask = null;
+			}
+			// schedule new timer
+			eventTask = new EventGeneratorTask(directionUp, y);
+			eventTimer.schedule(eventTask, Config.DFI_EVENT_TIMER_DELAY);
+		}
+	}
+
+	/**
+	 * Form Timer task. Triggers the formComposite to Layout.
+	 */
+	class EventGeneratorTask extends TimerTask
+	{
+
+		private boolean isUpDirection;
+		private int localY;
+
+		public EventGeneratorTask(boolean direction, int y)
+		{
+			isUpDirection = direction;
+			localY = y;
+			Logger.info("y is " + localY);
+		}
+
+		public void run()
+		{
+			if(isUpDirection)
+			{
+				localY -= Config.DFI_EVENT_MOVE_DELTA;
+			}
+			else
+			{
+				localY += Config.DFI_EVENT_MOVE_DELTA;
+			}
+			handlePointerEvent(0, localY, SWT.MouseMove);
+		}
+	}
+
+}