javauis/lcdui_qt/src/javax/microedition/lcdui/LayoutObject.java
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Mon, 03 May 2010 12:27:20 +0300
changeset 21 2a9601315dfc
child 23 98ccebc37403
permissions -rw-r--r--
Revision: v2.1.22 Kit: 201018

/*
* 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.Enumeration;

import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.*;

/**
 * Structure which represents Control stored in Form Row.
 */
final class LayoutObject {

    /**
     * Control which is represented by this LayoutObject.
     */
    private Control control;

    /**
     * If control is Composite (for example if Item has label), then
     * commandControl will contain composite's child that will receive events.
     * Otherwise commandControl will be same as control.
     */
    private Control commandControl;
    private Item owningItem;
    private boolean commandsActivated;

    private int x;
    private int y;
    private int width;
    private int height;

    private EswtItemCommandListener eswtItemCommandListener =
        new EswtItemCommandListener();

    // index of the row current LayoutObject belongs to
    private int layoutRowIdx;

    /**
     * Constructor.
     *
     * @param owningItem - Item which this LayoutObject corresponds to
     * @param control - Control for that LayoutObject
     */
    LayoutObject(Item owningItem, Control control) {
        this.owningItem = owningItem;
        setControl(control);
    }

    /**
     * Set the Control for that LayoutObject.
     *
     * @param newControl Control to set
     */
    private void setControl(final Control newControl) {
        ESWTUIThreadRunner.syncExec(new Runnable() {
            public void run() {
                control = newControl;
                eswtUpdateSize();
                Control temp = eswtGetCommandControl(control);
                commandControl = (temp != null ? temp : control);

                Enumeration e = owningItem.getCommands().elements();
                Command cmd = null;
                while (e.hasMoreElements()) {
                    cmd = (Command) e.nextElement();
                    eswtAddCommand(cmd);
                }
            }
        });
    }

    /**
     * Gets Control which should be used with commands.<br>
     * This might be LayoutObject's control or one of its children in case of
     * Button. Button should be handled separately here because of MSK.
     *
     * @param ctrl Control of this LayoutObject.
     * @return Control.
     */
    Control eswtGetCommandControl(Control ctrl) {
        Control ret = null;
        if (ctrl != null) {
            if (ctrl instanceof Button) {
                ret = ctrl;
            }
            else if (ctrl instanceof Composite) {
                Control[] children = ((Composite) ctrl).getChildren();
                for (int i = 0; i < children.length; i++) {
                    Control result = eswtGetCommandControl(children[i]);
                    if (result != null) {
                        ret = result;
                        break;
                    }
                }
            }
        }
        return ret;
    }

    /**
     * Dispose LayoutObject.
     */
    void dispose() {
        ESWTUIThreadRunner.syncExec(new Runnable() {
            public void run() {
                control.dispose();
                control = null;
                commandControl = null;
            }
        });
    }

    /**
     * Returns the Item's vertical layout.
     */
    int getVerticalLayout() {
        return Item.getVerticalLayout(owningItem.getLayout());
    }

    /**
     * Get Control of the layoutObject.
     *
     * @return control
     */
    Control getControl() {
        return control;
    }

    /**
     * Get Item to which the LayoutObjecy belongs.
     *
     * @return owning Item
     */
    Item getOwningItem() {
        return owningItem;
    }

    /**
     * Set location of the LayoutObject and the control.
     *
     * @param xCoord x coordinate
     * @param yCoord y coordinate
     */
    void eswtSetLocation(int xCoord, int yCoord) {
        x = xCoord;
        y = yCoord;
        control.setLocation(xCoord, yCoord);
    }

    /**
     * Update LayoutObject width and height.
     */
    void eswtUpdateSize() {
        Rectangle bounds = control.getBounds();
        width = bounds.width;
        height = bounds.height;
    }

    /**
     * Get x Coordinate of LayoutObject,
     *
     * @return xCoordinate of LayoutObject.
     */
    int getX() {
        return x;
    }

    /**
     * Get y Coordinate of LayoutObject,
     *
     * @return yCoordinate of LayoutObject.
     */
    int getY() {
        return y;
    }

    /**
     * Get width of LayoutObject.
     *
     * @return width of a control
     */
    int getWidth() {
        return width;
    }

    /**
     * Get width of LayoutObject.
     *
     * @return width of a control
     */
    int getHeight() {
        return height;
    }

    /**
     * Sets the row index of the Row where this LayoutObject is placed.
     *
     * @param row Row index.
     */
    void setRowIdx(int row) {
        layoutRowIdx = row;
    }

    /**
     * Returns row index where this LayoutObject is placed.
     *
     * @return Index of the row.
     */
    int getRowIdx() {
        return layoutRowIdx;
    }

    boolean contains(int xCoord, int yCoord) {
        return (y <= yCoord && yCoord <= y + height
                && x <= xCoord && xCoord <= x + width);
    }

    /**
     * Returns if this LayoutObject is below the other.
     */
    boolean isBelow(LayoutObject other) {
        if (other != null) {
            return (this.getRowIdx() > other.getRowIdx());
        }
        return true;
    }

    /**
     * Returns if this LayoutObject is above the other.
     */
    boolean isAbove(LayoutObject other) {
        if (other != null) {
            return (this.getRowIdx() < other.getRowIdx());
        }
        return true;
    }

    /**
     * Returns the horizontal middle of the LayoutObject.
     *
     * @return x horizontal coordinate of the middle of LayoutObject.
     */
    private int getXMiddle() {
        return (x + width / 2);
    }

    /**
     * Returns the vertical middle of the LayoutObject.
     *
     * @return y vertical coordinate of the middle of LayoutObject.
     */
    private int getYMiddle() {
        return (y + height / 2);
    }

    /**
     * Returns the horizontal distance between the middle of the LayoutObjects.
     * The method is used to find next focusable item.
     *
     * @param other another LayoutObject
     * @return positive distance between the middles
     */
    int distanceTo(LayoutObject other) {
        if (other != null) {
            int xd = Math.abs(getXMiddle() - other.getXMiddle());
            int yd = Math.abs(getYMiddle() - other.getYMiddle());
            return (int) Math.sqrt(xd * xd + yd * yd);
        }
        else {
            return Integer.MAX_VALUE - 1;
        }
    }

    /**
     * Activates commands associated with owning item.
     */
    void eswtAddSelectionListenerForCommands() {
        // Logger.method(this, "eswtAddSelectionListenerForCommands");
        commandsActivated = true;

        // Add new control to commands in owning item:
        Enumeration e = owningItem.getCommands().elements();
        Command cmd = null;
        while (e.hasMoreElements()) {
            cmd = (Command) e.nextElement();
            cmd.eswtAddCommandSelectionListener(commandControl,
                    eswtItemCommandListener);
        }
        // Add SelectionListener to Button control.
        // Listener is activated when command mapped to MSK is clicked.
        if (commandControl instanceof Button && !commandControl.isDisposed()) {
            ((Button) commandControl)
                    .addSelectionListener(eswtItemCommandListener);
        }
    }

    /**
     * DeActivates commands associated with owning item.
     */
    void eswtRemoveSelectionListenerForCommands() {
        // Logger.method(this, "eswtRemoveSelectionListenerForCommands");
        commandsActivated = false;

        // Add new control to commands in owning item:
        Enumeration e = owningItem.getCommands().elements();
        Command cmd = null;
        while (e.hasMoreElements()) {
            cmd = (Command) e.nextElement();
            cmd.eswtRemoveCommandSelectionListener(commandControl,
                    eswtItemCommandListener);
        }
        // Remove SelectionListener from Button control.
        // Listener is activated when command mapped to MSK is clicked.
        if (commandControl instanceof Button && !commandControl.isDisposed()) {
            ((Button) commandControl)
                    .removeSelectionListener(eswtItemCommandListener);
        }
    }

    /**
     * Adds command to the owning item.
     *
     * @param command The command to be added.
     */
    void addCommand(final Command command) {
        ESWTUIThreadRunner.syncExec(new Runnable() {
            public void run() {
                eswtAddCommand(command);
            }
        });
    }

    /**
     * eSWT callback to add a Command.
     */
    void eswtAddCommand(Command command) {
        //Logger.method(this, "eswtAddCommand", command);
        if (command != null && commandControl != null) {
            command.eswtAddESWTCommand(commandControl,
                    (command == owningItem.getDefaultCommand()));
            if (commandsActivated) {
                command.eswtAddCommandSelectionListener(commandControl,
                        eswtItemCommandListener);
            }
        }
    }

    /**
     * Removes command from the owning item.
     *
     * @param command The command to be removed.
     */
    void removeCommand(final Command command) {
        ESWTUIThreadRunner.syncExec(new Runnable() {
            public void run() {
                eswtRemoveCommand(command);
            }
        });
    }

    /**
     * eSWT callback to remove a Command.
     */
    private void eswtRemoveCommand(Command command) {
        //Logger.method(this, "eswtRemoveCommand", command);
        if (command != null && commandControl != null) {
            if (commandsActivated) {
                command.eswtRemoveCommandSelectionListener(commandControl,
                        eswtItemCommandListener);
            }
            command.eswtRemoveESWTCommand(commandControl);
        }
    }

    /**
     * Inner class which receives SelectionEvents from eSWT and convert and
     * forwards those events to LCDUI Item's ItemCommandListener.
     */
    class EswtItemCommandListener implements SelectionListener {

        public void widgetDefaultSelected(SelectionEvent e) {
        }

        /**
         * Executed by eSWT when event occurs. This method will then call
         * Item's ItemCommandListener if event source matches with the
         * Commands added to the Item.
         */
        public void widgetSelected(SelectionEvent event) {
            // Go through all Commands added to owning item:
            Enumeration e = owningItem.getCommands().elements();
            Command cmd = null;
            while (e.hasMoreElements()) {
                cmd = (Command) e.nextElement();
                // get eSWT Command of this Control from Command and compare
                // it to the widget which launched the event:
                if (cmd.getESWTCommand(commandControl) == event.widget) {
                    owningItem.callCommandAction(cmd);
                    break;
                }

                // Handle MSK:
                Command mskCmd = owningItem.getMSKCommand();
                if (mskCmd != null && cmd == mskCmd) {
                    if (commandControl == event.widget) {
                        owningItem.callCommandAction(cmd);
                        break;
                    }
                }
            }
        }
    }

    public String toString() {
        return owningItem + " [line:" + layoutRowIdx + "]";
    }

}