FileDocCategorySizeDatePackage
Item.javaAPI DocJ2ME MIDP 2.055695Thu Nov 07 12:02:28 GMT 2002javax.microedition.lcdui

Item.java

/*
 * @(#)Item.java	1.148 02/10/14 @(#)
 *
 * Copyright (c) 1999-2002 Sun Microsystems, Inc.  All rights reserved.
 * PROPRIETARY/CONFIDENTIAL
 * Use is subject to license terms.
 */

package javax.microedition.lcdui;

import com.sun.midp.lcdui.Text;

/**
 * A superclass for components that can be added to a {@link Form
 * Form}. All <code>Item</code> objects have a label field,
 * which is a string that is
 * attached to the item. The label is typically displayed near the component
 * when it is displayed within a screen.  The label should be positioned on
 * the same horizontal row as the item or
 * directly above the item.  The implementation should attempt to distinguish
 * label strings from other textual content, possibly by displaying the label
 * in a different font, aligning it to a different margin, or appending a
 * colon to it if it is placed on the same line as other string content.
 * If the screen is scrolling, the implementation should try
 * to keep the label visible at the same time as the <code>Item</code>.
 *
 * <p>In some cases,
 * when the user attempts to interact with an <code>Item</code>,
 * the system will switch to
 * a system-generated screen where the actual interaction takes place. If
 * this occurs, the label will generally be carried along and displayed within
 * this new screen in order to provide the user with some context for the
 * operation. For this reason it is recommended that applications supply a
 * label to all interactive Item objects. However, this is not required, and
 * a <code>null</code> value for a label is legal and specifies
 * the absence of a label.
 * </p>
 *
 * <h3>Item Layout</h3>
 *
 * <p>An <code>Item's</code> layout within its container is
 * influenced through layout directives:</p>
 *
 * <ul>
 * <li> <code>LAYOUT_DEFAULT</code> </li>
 * <li> <code>LAYOUT_LEFT</code> </li>
 * <li> <code>LAYOUT_RIGHT</code> </li>
 * <li> <code>LAYOUT_CENTER</code> </li>
 * <li> <code>LAYOUT_TOP</code> </li>
 * <li> <code>LAYOUT_BOTTOM</code> </li>
 * <li> <code>LAYOUT_VCENTER</code> </li>
 * <li> <code>LAYOUT_NEWLINE_BEFORE</code> </li>
 * <li> <code>LAYOUT_NEWLINE_AFTER</code> </li>
 * <li> <code>LAYOUT_SHRINK</code> </li>
 * <li> <code>LAYOUT_VSHRINK</code> </li>
 * <li> <code>LAYOUT_EXPAND</code> </li>
 * <li> <code>LAYOUT_VEXPAND</code> </li>
 * <li> <code>LAYOUT_2</code> </li>
 * </ul>
 *
 * <p>The <code>LAYOUT_DEFAULT</code> directive indicates
 * that the container's default
 * layout policy is to be used for this item.
 * <code>LAYOUT_DEFAULT</code> has the value
 * zero and has no effect when combined with other layout directives.  It is
 * useful within programs in order to document the programmer's intent.</p>
 *
 * <p>The <code>LAYOUT_LEFT</code>, <code>LAYOUT_RIGHT</code>, and
 * <code>LAYOUT_CENTER</code> directives indicate
 * horizontal alignment and are mutually exclusive.  Similarly, the
 * <code>LAYOUT_TOP</code>, <code>LAYOUT_BOTTOM</code>, and
 * <code>LAYOUT_VCENTER</code> directives indicate vertical
 * alignment and are mutually exclusive.</p>
 *
 * <p>A horizontal alignment directive, a vertical alignment directive, and
 * any combination of other layout directives may be combined using the
 * bit-wise <code>OR</code> operator (<code>|</code>) to compose a
 * layout directive value.  Such a value
 * is used as the parameter to the {@link #setLayout} method and is the return
 * value from the {@link #getLayout} method.</p>
 *
 * <p>Some directives have no defined behavior in some contexts.  A layout
 * directive is ignored if its behavior is not defined for the particular
 * context within which the <code>Item</code> resides.</p>
 *
 * <p>A complete specification of the layout of <code>Items</code>
 * within a <code>Form</code> is given
 * <a href="Form.html#layout">here</a>.</p>
 *
 * <a name="sizes"></a>
 * <h3>Item Sizes</h3>
 *
 * <p><code>Items</code> have two explicit size concepts: the <em>minimum</em>
 * size and the
 * <em>preferred</em> size.  Both the minimum and the preferred sizes refer to
 * the total area of the <code>Item</code>, which includes space for the
 * <code>Item's</code> contents,
 * the <code>Item's</code> label, as well as other space that is
 * significant to the layout
 * policy.  These sizes do not include space that is not significant for
 * layout purposes.  For example, if the addition of a label to an
 * <code>Item</code> would
 * cause other <code>Items</code> to move in order to make room,
 * then the space occupied by
 * this label is significant to layout and is counted as part of
 * the <code>Item's</code>
 * minimum and preferred sizes.  However, if an implementation were to place
 * the label in a margin area reserved exclusively for labels, this would not
 * affect the layout of neighboring <code>Items</code>.
 * In this case, the space occupied
 * by the label would not be considered part of the minimum and preferred
 * sizes.</p>
 *
 * <p>The minimum size is the smallest size at which the
 * <code>Item</code> can function and
 * display its contents, though perhaps not optimally.  The minimum size
 * may be recomputed whenever the <code>Item's</code> contents changes.</p>
 *
 * <p>The preferred size is generally a size based on the
 * <code>Item's</code> contents and
 * is the smallest size at which no information is clipped and text wrapping
 * (if any) is kept to a tolerable minimum.  The preferred size may be
 * recomputed whenever the <code>Item's</code> contents changes.
 * The application can
 * <em>lock</em> the preferred width or preferred height (or both) by
 * supplying specific values for parameters to the {@link #setPreferredSize
 * setPreferredSize} method.  The manner in which an
 * <code>Item</code> fits its contents
 * within an application-specified preferred size is implementation-specific.
 * However, it is recommended that textual content be word-wrapped to fit the
 * preferred size set by the application.  The application can <em>unlock</em>
 * either or both dimensions by supplying the value <code>-1</code>
 * for parameters to the <code>setPreferredSize</code> method.</p>
 *
 * <p>When an <code>Item</code> is created, both the preferred width
 * and height are
 * unlocked.  In this state, the implementation computes the preferred width
 * and height based on the <code>Item's</code> contents, possibly
 * including other relevant
 * factors such as the <code>Item's</code> graphic design and the
 * screen dimensions.
 * After having locked either the preferred width or height, the application
 * can restore the initial, unlocked state by calling
 * <code>setPreferredSize(-1, -1)</code>.</p>
 *
 * <p>The application can lock one dimension of the preferred size and leave
 * the other unlocked.  This causes the system to compute an appropriate value
 * for the unlocked dimension based on arranging the contents to fit the
 * locked dimension.  If the contents changes, the size on the unlocked
 * dimension is recomputed to reflect the new contents, but the size on the
 * locked dimension remains unchanged.  For example, if the application called
 * <code>setPreferredSize(50, -1)</code>, the preferred width would be
 * locked at <code>50</code> pixels and the preferred height would
 * be computed based on the
 * <code>Item's</code> contents.  Similarly, if the application called
 * <code>setPreferredSize(-1, 60)</code>, the preferred height would be
 * locked at <code>60</code> pixels and the preferred width would be
 * computed based on the
 * <code>Item's</code> contents.  This feature is particularly useful
 * for <code>Items</code> with
 * textual content that can be line wrapped.</p>
 *
 * <p>The application can also lock both the preferred width and height to
 * specific values.  The <code>Item's</code> contents are truncated or padded
 * as necessary to honor this request.  For <code>Items</code> containing
 * text, the text should be wrapped to the specified width, and any truncation
 * should occur at the end of the text.</p>
 *
 * <p><code>Items</code> also have an implicit maximum size provided by the
 * implementation.  The maximum width is typically based on the width of the
 * screen space available to a <code>Form</code>.  Since <code>Forms</code>
 * can scroll vertically, the maximum height should typically not be based on
 * the height of the available screen space.</p>
 *
 * <p>If the application attempts to lock a preferred size dimension to a
 * value smaller than the minimum or larger than the maximum, the
 * implementation may disregard the requested value and instead use either the
 * minimum or maximum as appropriate.  If this occurs, the actual values used
 * must be visible to the application via the values returned from the
 * {@link #getPreferredWidth getPreferredWidth} and
 * {@link #getPreferredHeight getPreferredHeight} methods.
 * </p>
 *
 * <h3>Commands</h3>
 *
 * <p>A <code>Command</code> is said to be present on an <code>Item</code>
 * if the <code>Command</code> has been
 * added to this <code>Item</code> with a prior call to {@link #addCommand}
 * or {@link #setDefaultCommand} and if
 * the <code>Command</code> has not been removed with a subsequent call to
 * {@link #removeCommand}.  <code>Commands</code> present on an
 * item should have a command
 * type of <code>ITEM</code>.  However, it is not an error for a
 * command whose type is
 * other than <code>ITEM</code> to be added to an item.
 * For purposes of presentation and
 * placement within its user interface, the implementation is allowed to
 * treat a command's items as if they were of type <code>ITEM</code>. </p>
 *
 * <p><code>Items</code> may have a <em>default</em> <code>Command</code>.
 * This state is
 * controlled by the {@link #setDefaultCommand} method.  The default
 * <code>Command</code> is eligible to be bound to a special
 * platform-dependent user
 * gesture.  The implementation chooses which gesture is the most
 * appropriate to initiate the default command on that particular
 * <code>Item</code>.
 * For example, on a device that has a dedicated selection key, pressing
 * this key might invoke the item's default command.  Or, on a
 * stylus-based device, tapping on the <code>Item</code> might
 * invoke its default
 * command.  Even if it can be invoked through a special gesture, the
 * default command should also be invokable in the same fashion as
 * other item commands.</p>
 *
 * <p>It is possible that on some devices there is no special gesture
 * suitable for invoking the default command on an item.  In this case
 * the default command must be accessible to the user in the same
 * fashion as other item commands.  The implementation may use the state
 * of a command being the default in deciding where to place the command
 * in its user interface.</p>
 *
 * <p>It is possible for an <code>Item</code> not to have a default command.
 * In this
 * case, the implementation may bind its special user gesture (if any)
 * for another purpose, such as for displaying a menu of commands.  The
 * default state of an <code>Item</code> is not to have a default command.
 * An <code>Item</code>
 * may be set to have no default <code>Command</code> by removing it from
 * the <code>Item</code> or
 * by passing <code>null</code> to the <code>setDefaultCommand()</code>
 * method.</p>
 *
 * <p>The same command may occur on more than one
 * <code>Item</code> and also on more than
 * one <code>Displayable</code>.  If this situation occurs, the user
 * must be provided with
 * distinct gestures to invoke that command on each <code>Item</code> or
 * <code>Displayable</code> on
 * which it occurs, while those <code>Items</code> or <code>Displayables</code>
 * are visible on the
 * display.  When the user invokes the command, the listener
 * (<code>CommandListener</code>
 * or <code>ItemCommandListener</code> as appropriate) of just the
 * object on which the
 * command was invoked will be called.</p>
 *
 * <p>Adding commands to an <code>Item</code> may affect its appearance, the
 * way it is laid out, and the traversal behavior.  For example, the presence
 * of commands on an <code>Item</code> may cause row breaks to occur, or it
 * may cause additional graphical elements (such as a menu icon) to appear.
 * In particular, if a <code>StringItem</code> whose appearance mode is
 * <code>PLAIN</code> (see below) is given one or more <code>Commands</code>,
 * the implementation is allowed to treat it as if it had a different
 * appearance mode.</p>
 *
 * <a name="appearance"></a>
 * <h3>Appearance Modes</h3>
 *
 * <p>The <code>StringItem</code> and <code>ImageItem</code> classes have an
 * <em>appearance mode</em> attribute that can be set in their constructors.
 * This attribute can have one of the values {@link #PLAIN PLAIN},
 * {@link #HYPERLINK HYPERLINK}, or {@link #BUTTON BUTTON}.
 * An appearance mode of <code>PLAIN</code> is typically used
 * for non-interactive
 * display of textual or graphical material.  The appearance
 * mode values do not have any side effects on the interactivity of the item.
 * In order to be interactive, the item must have one or more
 * <code>Commands</code>
 * (preferably with a default command assigned), and it must have a
 * <code>CommandListener</code> that receives notification of
 * <code>Command</code> invocations.  The
 * appearance mode values also do not have any effect on the semantics of
 * <code>Command</code> invocation on the item.  For example,
 * setting the appearance mode
 * of a <code>StringItem</code> to be <code>HYPERLINK</code>
 * requests that the implementation display
 * the string contents as if they were a hyperlink in a browser.  It is the
 * application's responsibility to attach a <code>Command</code>
 * and a listener to the
 * <code>StringItem</code> that provide behaviors that the user
 * would expect from invoking
 * an operation on a hyperlink, such as loading the referent of the link or
 * adding the link to the user's set of bookmarks.</p>
 *
 * <p>Setting the appearance mode of an <code>Item</code> to be other than
 * <code>PLAIN</code> may affect its minimum, preferred, and maximum sizes, as
 * well as the way it is laid out.  For example, a <code>StringItem</code>
 * with an appearance mode of <code>BUTTON</code> should not be wrapped across
 * rows.  (However, a <code>StringItem</code> with an appearance mode of
 * <code>HYPERLINK</code> should be wrapped the same way as if its appearance
 * mode is <code>PLAIN</code>.)</p>
 *
 * <p>A <code>StringItem</code> or <code>ImageItem</code>
 * in <code>BUTTON</code> mode can be used to create a
 * button-based user interface.  This can easily lead to applications that are
 * inconvenient to use.  For example, in a traversal-based system, users must
 * navigate to a button before they can invoke any commands on it.  If buttons
 * are spread across a long <code>Form</code>, users may be required
 * to perform a
 * considerable amount of navigation in order to discover all the available
 * commands.  Furthermore, invoking a command from a button at the
 * other end of the <code>Form</code> can be quite cumbersome.
 * Traversal-based systems
 * often provide a means of invoking commands from anywhere (such as from a
 * menu), without the need to traverse to a particular item.  Instead of
 * adding a command to a button and placing that button into a
 * <code>Form</code>, it would
 * often be more appropriate and convenient for users if that command were
 * added directly to the <code>Form</code>.  Buttons should be used
 * only in cases where
 * direct user interaction with the item's string or image contents is
 * essential to the user's understanding of the commands that can be invoked
 * from that item.</p>
 *
 * <h3>Default State</h3>
 *
 * <p>Unless otherwise specified by a subclass, the default state of newly
 * created <code>Items</code> is as follows:</p>
 *
 * <ul>
 * <li>the <code>Item</code> is not contained within
 * ("owned by") any container;</li>
 * <li>there are no <code>Commands</code> present;</li>
 * <li>the default <code>Command</code> is <code>null</code>;</li>
 * <li>the <code>ItemCommandListener</code> is <code>null</code>;</li>
 * <li>the layout directive value is <code>LAYOUT_DEFAULT</code>; and</li>
 * <li>both the preferred width and preferred height are unlocked.</li>
 * </ul>
 *
 * @since MIDP 1.0
 */

abstract public class Item {

// ************************************************************
//  public member variables
// ************************************************************

    /**
     * A layout directive indicating that this <code>Item</code> 
     * should follow the default layout policy of its container.
     *
     * <P>Value <code>0</code> is assigned to <code>LAYOUT_DEFAULT</code>.</P>
     *
     * @since MIDP 2.0
     */
    public final static int LAYOUT_DEFAULT = 0;

    /**
     * A layout directive indicating that this <code>Item</code> should have a
     * left-aligned layout.
     *
     * <P>Value <code>1</code> is assigned to <code>LAYOUT_LEFT</code>.</P>
     * @since MIDP 2.0
     */
    public final static int LAYOUT_LEFT = 1;

    /**
     * A layout directive indicating that this <code>Item</code> should have a
     * right-aligned layout.
     *
     * <P>Value <code>2</code> is assigned to <code>LAYOUT_RIGHT</code>.</P>
     * @since MIDP 2.0
     */
    public final static int LAYOUT_RIGHT = 2;

    /**
     * A layout directive indicating that this <code>Item</code> should have a
     * horizontally centered layout.
     *
     * <P>Value <code>3</code> is assigned to <code>LAYOUT_CENTER</code>.</P>
     * @since MIDP 2.0
     */
    public final static int LAYOUT_CENTER = 3;

    /**
     * A layout directive indicating that this <code>Item</code> should have a
     * top-aligned layout.
     *
     * <P>Value <code>0x10</code> is assigned to <code>LAYOUT_TOP</code>.</P>
     * @since MIDP 2.0
     */
    public final static int LAYOUT_TOP = 0x10;

    /**
     * A layout directive indicating that this <code>Item</code> should have a
     * bottom-aligned layout.
     *
     * <P>Value <code>0x20</code> is assigned to <code>LAYOUT_BOTTOM</code>.</P>
     * @since MIDP 2.0
     */
    public final static int LAYOUT_BOTTOM = 0x20;

    /**
     * A layout directive indicating that this <code>Item</code> should have a
     * vertically centered layout.
     *
     * <P>Value <code>0x30</code> is assigned to 
     * <code>LAYOUT_VCENTER</code>.</P>
     * @since MIDP 2.0
     */
    public final static int LAYOUT_VCENTER = 0x30;

    /**
     * A layout directive indicating that this <code>Item</code> 
     * should be placed at the beginning of a new line or row.
     *
     * <P>Value <code>0x100</code> is assigned to 
     * <code>LAYOUT_NEWLINE_BEFORE</code>.</P>
     * @since MIDP 2.0
     */
    public final static int LAYOUT_NEWLINE_BEFORE = 0x100;

    /**
     * A layout directive indicating that this <code>Item</code>
     * should the last on its line or row, and that the next
     * <code>Item</code> (if any) in the container
     * should be placed on a new line or row.
     *
     * <P>Value <code>0x200</code> is assigned to 
     * <code>LAYOUT_NEWLINE_AFTER</code>.</P>
     * @since MIDP 2.0
     */
    public final static int LAYOUT_NEWLINE_AFTER = 0x200;

    /**
     * A layout directive indicating that this <code>Item's</code>
     * width may be reduced to its minimum width.
     *
     *<P>Value <code>0x400</code> is assigned to <code>LAYOUT_SHRINK</code></P>
     * @since MIDP 2.0
     */
    public final static int LAYOUT_SHRINK = 0x400;

    /**
     * A layout directive indicating that this <code>Item's</code> 
     * width may be increased to fill available space.
     *
     *<P>Value <code>0x800</code> is assigned to <code>LAYOUT_EXPAND</code>.</P>
     * @since MIDP 2.0
     */
    public final static int LAYOUT_EXPAND = 0x800;

    /**
     * A layout directive indicating that this <code>Item's</code>
     * height may be reduced to its minimum height.
     *
     * <P>Value <code>0x1000</code> is assigned to
     * <code>LAYOUT_VSHRINK</code>.</P>
     * @since MIDP 2.0
     */
    public final static int LAYOUT_VSHRINK = 0x1000;

    /**
     * A layout directive indicating that this <code>Item's</code> 
     * height may be increased to fill available space.
     *
     * <P>Value <code>0x2000</code> is assigned to 
     * <code>LAYOUT_VEXPAND</code>.</P>
     * @since MIDP 2.0
     */
    public final static int LAYOUT_VEXPAND = 0x2000;

    /**
     * A layout directive indicating that new MIDP 2.0 layout
     * rules are in effect for this <code>Item</code>.  If this
     * bit is clear, indicates that MIDP 1.0 layout behavior
     * applies to this <code>Item</code>.
     *
     * <P>Value <code>0x4000</code> is assigned to
     * <code>LAYOUT_2</code>.</P>
     * 
     * @since MIDP 2.0
     */
    public static final int LAYOUT_2 = 0x4000;

    /**
     * An appearance mode value indicating that the <code>Item</code> is to have
     * a normal appearance.
     *
     * <P>Value <code>0</code> is assigned to <code>PLAIN</code>.</P>
     * @since MIDP 2.0
     */
    public final static int PLAIN = 0;

    /**
     * An appearance mode value indicating that the <code>Item</code>
     * is to appear as a hyperlink.
     * <P>Value <code>1</code> is assigned to <code>HYPERLINK</code>.</P>
     * @since MIDP 2.0
     */
    public final static int HYPERLINK = 1;

    /**
     * An appearance mode value indicating that the <code>Item</code>
     * is to appear as a button.
     * <P>Value <code>2</code> is assigned to <code>BUTTON</code>.</P>
     * @since MIDP 2.0
     */
    public final static int BUTTON = 2;

// ************************************************************
//  protected member variables
// ************************************************************

// ************************************************************
//  package private member variables
// ************************************************************

    /** bounds[] array index to x coordinate */
    final static int X      = Displayable.X;

    /** bounds[] array index to y coordinate */
    final static int Y      = Displayable.Y;

    /** bounds[] array index to width */
    final static int WIDTH  = Displayable.WIDTH;

    /** bounds[] array index to height */
    final static int HEIGHT = Displayable.HEIGHT;

    /** internal bitmask representing a valid layout mask */
    final static int VALID_LAYOUT;

    /**
     * An array of 4 elements, describing the x, y, width, height
     * of this Item's bounds in the viewport coordinate space. If
     * its null, it means the Item is currently not in the viewport
     */
    int[] bounds;

    /**
     * A flag indicating this Item has the input focus. This is
     * maintained by the Item superclass for easy use by subclass
     * code.
     */
    boolean hasFocus;

    /**
     * A flag indicating this Item is currently (at least partially)
     * visible on the Form it is on. This is maintained by the Item
     * superclass for easy use by subclass code.
     */
    boolean visible;

    /**
     * A flag indicating the size of this Item has changed in a
     * subsequent layout operation
     */
    boolean sizeChanged;

    /**
     * commandListener that has to be notified of when ITEM command is
     * activated
     */
    ItemCommandListener commandListener; // = null;

    /** The label of this Item */
    String label;

    /**
     * The owner Screen for this Item
     */
    Screen owner;     // = null

    /**
     * The layout type of this Item
     */
    int layout;       // = 0 ; LAYOUT_DEFAULT = 0

    /**
     * This is a default Command which represents the callback
     * to a selection event.
     */
    Command defaultCommand;

    /** The number of Commands added to this Item */
    int numCommands;

    /** The locked width of this Item, -1 by default */
    int lockedWidth = -1;

    /** The locked height of this Item, -1 by default */
    int lockedHeight = -1;

    /**
     * A flag signaling how labels are painted. If true,
     * labels are only painted bold on traverse, else they
     * are always painted bold
     */
    final static boolean LABEL_BOLD_ON_TRAVERSE = false;

    /**
     * Padding used between Button Border and ImageItem
     */
    final static int BUTTON_PAD = 2;

    /**
     * Button Border is 3 pixel wide and 3 pixel high
     */
    final static int BUTTON_BORDER = 3;

    /** Button border color for light gray border */
    static final int LIGHT_GRAY_COLOR = 0x00AFAFAF; // light gray

    /** Button border color for dark gray border */
    static final int DARK_GRAY_COLOR = 0x00606060; // dark gray

    /** The font to render item labels with focus */
    final static Font LABEL_FONT = Font.getFont(
        Screen.CONTENT_FONT.getFace(),
        Font.STYLE_BOLD,
        Screen.CONTENT_FONT.getSize());

    /** 2 pixel padding between the label and the item's contents */
    final static int LABEL_PAD = 2;

    /** The height of the label (maximum of 1 line */
    final static int LABEL_HEIGHT = LABEL_FONT.getHeight() + LABEL_PAD;

    /** Maximum width available to any Item */
    final static int DEFAULT_WIDTH = 
        Display.WIDTH - Form.CELL_SPACING - Form.CELL_SPACING;

// ************************************************************
//  private member variables
// ************************************************************

    /** An array of Commands added to this Item */
    private Command commands[];

// ************************************************************
//  Static initializer, constructor
// ************************************************************

    static {
        VALID_LAYOUT =
            Item.LAYOUT_DEFAULT |
            Item.LAYOUT_LEFT |
            Item.LAYOUT_RIGHT |
            Item.LAYOUT_CENTER |
            Item.LAYOUT_TOP |
            Item.LAYOUT_BOTTOM |
            Item.LAYOUT_VCENTER |
            Item.LAYOUT_SHRINK |
            Item.LAYOUT_EXPAND |
            Item.LAYOUT_VSHRINK |
            Item.LAYOUT_VEXPAND |
            Item.LAYOUT_NEWLINE_BEFORE |
            Item.LAYOUT_NEWLINE_AFTER |
            Item.LAYOUT_2;
    }

    /**
     * Creates a new item with a given label.
     *
     * @param label the label string; null is allowed
     */
    Item(String label) {
        // SYNC NOTE: probably safe, but since subclasses can't lock
        // around their call to super(), we'll lock it here
        synchronized (Display.LCDUILock) {
            this.label = label;
        }
    }

// ************************************************************
//  public methods
// ************************************************************

    /**
     * Sets the label of the <code>Item</code>. If <code>label</code>
     * is <code>null</code>, specifies that this item has no label.
     * 
     * <p>It is illegal to call this method if this <code>Item</code>
     * is contained within  an <code>Alert</code>.</p>
     * 
     * @param label the label string
     * @throws IllegalStateException if this <code>Item</code> is contained 
     * within an <code>Alert</code>
     * @see #getLabel
     */
    public void setLabel(String label) {
        synchronized (Display.LCDUILock) {
            this.label = label;
            invalidate();
        }
    }
    
    /**
     * Gets the label of this <code>Item</code> object.
     * @return the label string
     * @see #setLabel
     */
    public String getLabel() {
        // SYNC NOTE: return of atomic value, no locking necessary
        return label;
    }

    /**
     * Gets the layout directives used for placing the item.
     * @return a combination of layout directive values
     * @since MIDP 2.0
     * @see #setLayout
     */
    public int getLayout() {
        // SYNC NOTE: return of atomic value, no locking necessary
        return layout;
    }

    /**
     * Sets the layout directives for this item.
     *
     * <p>It is illegal to call this method if this <code>Item</code> 
     * is contained within an <code>Alert</code>.</p>
     * 
     * @param layout a combination of layout directive values for this item
     * @throws IllegalArgumentException if the value of layout is not a
     * bit-wise OR combination of layout directives
     * @throws IllegalStateException if this <code>Item</code> is
     * contained within an <code>Alert</code>
     * @since MIDP 2.0
     * @see #getLayout
     */
    public void setLayout(int layout) {
        synchronized (Display.LCDUILock) {
            setLayoutImpl(layout);
            invalidate();
        }
    }

    /**
     * Adds a context sensitive <code>Command</code> to the item.
     * The semantic type of
     * <code>Command</code> should be <code>ITEM</code>. The implementation
     * will present the command
     * only when the item is active, for example, highlighted.
     * <p>
     * If the added command is already in the item (tested by comparing the
     * object references), the method has no effect. If the item is
     * actually visible on the display, and this call affects the set of
     * visible commands, the implementation should update the display as soon
     * as it is feasible to do so.
     *
     * <p>It is illegal to call this method if this <code>Item</code>
     * is contained within an <code>Alert</code>.</p>
     *
     * @param cmd the command to be added
     * @throws IllegalStateException if this <code>Item</code> is contained
     * within an <code>Alert</code>
     * @throws NullPointerException if cmd is <code>null</code>
     * @since MIDP 2.0
     */
    public void addCommand(Command cmd) {
        synchronized (Display.LCDUILock) {
            addCommandImpl(cmd);
        }
        }

    /**
     * Removes the context sensitive command from item. If the command is not
     * in the <code>Item</code> (tested by comparing the object references),
     * the method has
     * no effect. If the <code>Item</code> is actually visible on the display, 
     * and this  call
     * affects the set of visible commands, the implementation should update
     * the display as soon as it is feasible to do so.
     *
     *
     * If the command to be removed happens to be the default command,
     * the command is removed and the default command on this Item is
     * set to <code>null</code>.
     *
     * The following code:
     * <CODE> <pre>
     *     // Command c is the default command on Item item
     *     item.removeCommand(c);
     * </pre> </CODE>
     * is equivalent to the following code:
     * <CODE> <pre>
     *     // Command c is the default command on Item item
     *     item.setDefaultCommand(null);
     *     item.removeCommand(c);
     * </pre> </CODE>
     *
     *
     * @param cmd the command to be removed
     * @since MIDP 2.0
     */
    public void removeCommand(Command cmd) {
        synchronized (Display.LCDUILock) {
            removeCommandImpl(cmd);
        }
    }

    /**
     * Sets a listener for <code>Commands</code> to this <code>Item</code>,
     * replacing any previous
     * <code>ItemCommandListener</code>. A <code>null</code> reference
     * is allowed and has the effect of
     * removing any existing listener.
     *
     * <p>It is illegal to call this method if this <code>Item</code>
     * is contained within an <code>Alert</code>.</p>
     *
     * @param l the new listener, or <code>null</code>.
     * @throws IllegalStateException if this <code>Item</code> is contained
     * within an <code>Alert</code>
     * @since MIDP 2.0
     */
    public void setItemCommandListener(ItemCommandListener l) {
        synchronized (Display.LCDUILock) {
            commandListener = l;
        }
    }

    /**
     * Gets the preferred width of this <code>Item</code>.  
     * If the application has locked
     * the width to a specific value, this method returns that value.
     * Otherwise, the return value is computed based on the 
     * <code>Item's</code> contents,
     * possibly with respect to the <code>Item's</code> preferred height 
     * if it is locked.
     * See <a href="#sizes">Item Sizes</a> for a complete discussion.
     *
     * @return the preferred width of the Item
     * @see #getPreferredHeight
     * @see #setPreferredSize
     * @since MIDP 2.0
     */
    public int getPreferredWidth() {
        synchronized (Display.LCDUILock) {
            return (lockedWidth != -1) ? lockedWidth :
                        callPreferredWidth(lockedHeight);
        }
    }

    /**
     * Gets the preferred height of this <code>Item</code>.  
     * If the application has locked
     * the height to a specific value, this method returns that value.
     * Otherwise, the return value is computed based on the 
     * <code>Item's</code> contents,
     * possibly with respect to the <code>Item's</code> preferred 
     * width if it is locked.
     * See <a href="#sizes">Item Sizes</a> for a complete discussion.
     *
     * @return the preferred height of the <code>Item</code>
     * @see #getPreferredWidth
     * @see #setPreferredSize
     * @since MIDP 2.0
     */
    public int getPreferredHeight() {
        synchronized (Display.LCDUILock) {
            return (lockedHeight != -1) ? lockedHeight :
                        callPreferredHeight(lockedWidth);
        }
    }

    /**
     * Sets the preferred width and height for this <code>Item</code>.
     * Values for width and height less than <code>-1</code> are illegal.
     * If the width is between zero and the minimum width, inclusive,
     * the minimum width is used instead.
     * If the height is between zero and the minimum height, inclusive,
     * the minimum height is used instead.
     *
     * <p>Supplying a width or height value greater than the minimum width or 
     * height <em>locks</em> that dimension to the supplied
     * value.  The implementation may silently enforce a maximum dimension for 
     * an <code>Item</code> based on factors such as the screen size. 
     * Supplying a value of
     * <code>-1</code> for the width or height unlocks that dimension.
     * See <a href="#sizes">Item Sizes</a> for a complete discussion.</p>
     * 
     * <p>It is illegal to call this method if this <code>Item</code> 
     * is contained within  an <code>Alert</code>.</p>
     * 
     * @param width the value to which the width should be locked, or
     * <code>-1</code> to unlock
     * @param height the value to which the height should be locked, or 
     * <code>-1</code> to unlock
     * @throws IllegalArgumentException if width or height is less than 
     * <code>-1</code>
     * @throws IllegalStateException if this <code>Item</code> is contained
     * within an <code>Alert</code>
     * @see #getPreferredHeight
     * @see #getPreferredWidth
     * @since MIDP 2.0
     */
    public void setPreferredSize(int width, int height) {
        if (width < -1 || height < -1) {
            throw new IllegalArgumentException();
        }

        synchronized (Display.LCDUILock) {
            if (owner != null && owner instanceof Alert) {
                throw new IllegalStateException();
            }

            int minWidth  = getMinimumWidth();
            int minHeight = getMinimumHeight();

            this.lockedWidth  = (width != -1 && width < minWidth) 
                              ? minWidth 
                              : width;

            this.lockedHeight = (height != -1 && height < minHeight) 
                              ? minHeight 
                              : height;

            if (visible) {
                if (lockedWidth != bounds[WIDTH] ||
                        lockedHeight != bounds[HEIGHT]) {
                    invalidate();
                }
            }
        } // synchronized
    }

    /**
     * Gets the minimum width for this <code>Item</code>.  This is a width
     * at which the item can function and display its contents,
     * though perhaps not optimally.
     * See <a href="#sizes">Item Sizes</a> for a complete discussion.
     * 
     * @return the minimum width of the item
     * @since MIDP 2.0
     */
    public int getMinimumWidth() {
        synchronized (Display.LCDUILock) {
            return callMinimumWidth();
        }
    }

    /**
     * Gets the minimum height for this <code>Item</code>.  This is a height
     * at which the item can function and display its contents,
     * though perhaps not optimally.
     * See <a href="#sizes">Item Sizes</a> for a complete discussion.
     *
     * @return the minimum height of the item
     * @since MIDP 2.0
     */
    public int getMinimumHeight() {
        synchronized (Display.LCDUILock) {
            return callMinimumHeight();
        }
    }

    /**
     * Sets default <code>Command</code> for this <code>Item</code>.  
     * If the <code>Item</code> previously had a
     * default <code>Command</code>, that <code>Command</code> 
     * is no longer the default, but it
     * remains present on the <code>Item</code>.
     *
     * <p>If not <code>null</code>, the <code>Command</code> object
     * passed becomes the default <code>Command</code>
     * for this <code>Item</code>.  If the <code>Command</code> object
     * passed is not currently present
     * on this <code>Item</code>, it is added as if {@link #addCommand}
     * had been called
     * before it is made the default <code>Command</code>.</p>
     *
     * <p>If <code>null</code> is passed, the <code>Item</code> is set to
     * have no default <code>Command</code>.
     * The previous default <code>Command</code>, if any, remains present
     * on the <code>Item</code>.
     * </p>
     *
     * <p>It is illegal to call this method if this <code>Item</code>
     * is contained within  an <code>Alert</code>.</p>
     * 
     * @param cmd the command to be used as this <code>Item's</code> default
     * <code>Command</code>, or <code>null</code> if there is to 
     * be no default command
     *
     * @throws IllegalStateException if this <code>Item</code> is contained
     * within an <code>Alert</code>
     * @since MIDP 2.0
     */
    public void setDefaultCommand(Command cmd) {
        if (cmd != null) {
            addCommand(cmd);
        }
        defaultCommand = cmd;
    }

    /**
     * Causes this <code>Item's</code> containing <code>Form</code> to notify
     * the <code>Item's</code> {@link ItemStateListener}.
     * The application calls this method to inform the
     * listener on the <code>Item</code> that the <code>Item's</code>
     * state has been changed in
     * response to an action.  Even though this method simply causes a call
     * to another part of the application, this mechanism is useful for
     * decoupling the implementation of an <code>Item</code> (in particular, the
     * implementation of a <code>CustomItem</code>, though this also applies to
     * subclasses of other items) from the consumer of the item.
     *
     * <p>If an edit was performed by invoking a separate screen, and the
     * editor now wishes to "return" to the form which contained the
     * selected <code>Item</code>, the preferred method is
     * <code>Display.setCurrent(Item)</code>
     * instead of <code>Display.setCurrent(Displayable)</code>,
     * because it allows the
     * <code>Form</code> to restore focus to the <code>Item</code>
     * that initially invoked the editor.</p>
     *
     * <p>In order to make sure that the documented behavior of
     * <code>ItemStateListener</code> is maintained, it is up to the caller
     * (application) to guarantee that this function is
     * not called unless:</p>
     *
     * <ul>
     * <li>the <code>Item's</code> value has actually been changed, and</li>
     * <li>the change was the result of a user action (an "edit")
     * and NOT as a result of state change via calls to
     * <code>Item's</code> APIs </li>
     * </ul>
     *
     * <p>The call to <code>ItemStateListener.itemStateChanged</code>
     * may be delayed in order to be serialized with the event stream.
     * The <code>notifyStateChanged</code> method does not block awaiting
     * the completion of the <code>itemStateChanged</code> method.</p>
     *
     * @throws IllegalStateException if the <code>Item</code> is not owned
     * by a <code>Form</code>
     * @since MIDP 2.0
     */
    public void notifyStateChanged() { 
        // get a copy of the object reference to item's owning form
        Screen owner = this.owner;

        if (owner == null || !(owner instanceof Form)) {
            throw new IllegalStateException();
        }

        owner.itemStateChanged(this);
    }

// ************************************************************
//  protected methods
// ************************************************************

// ************************************************************
//  package private methods
// ************************************************************

    /**
     * Called to commit any pending user interaction for the item
     */
    void commitPendingInteraction() { }
        
    /**
     * Return the height of the label for this Item. If null,
     * returns 0, otherwise, returns LABEL_HEIGHT - which is
     * one line height, multi-line labels are currently disabled
     * by this method
     *
     * @param w the width available for the label (-1 means as wide
     *          as possible)
     * @return the height for the label
     */
    int getLabelHeight(int w) {
        if (label == null || label.length() == 0) {
            return 0;
        } 

        if (w == -1) {
            w = DEFAULT_WIDTH;
        }
        return Text.getHeightForWidth(label, LABEL_FONT, w, 0);
    }

    /**
     * Return the width of the label for this Item. If null,
     * returns 0, otherwise, returns the width in pixels of the
     * current label using LABEL_FONT.
     *
     * @return the width for the label
     */
    int getLabelWidth() {
        if (label == null || label.length() == 0) {
            return 0;
        }
        
        return Text.getWidestLineWidth(label.toCharArray(), 0, DEFAULT_WIDTH,
                                       LABEL_FONT);
    }

    /**
     * Get the preferred width of this Item
     *
     * @param height the tentative content height in pixels, or -1 if a
     * tentative height has not been computed
     * @return the preferred width
     */
    abstract int callPreferredWidth(int height);

    /**
     * Get the preferred height of this Item
     *
     * @param width the tentative content width in pixels, or -1 if a
     * tentative width has not been computed
     * @return the preferred height
     */
    abstract int callPreferredHeight(int width);

    /**
     * Get the minimum width of this Item
     *
     * @return the minimum width
     */
    abstract int callMinimumWidth();

    /**
     * Get the minimum height of this Item
     *
     * @return the minimum height
     */
    abstract int callMinimumHeight();

    /**
     * Determine if this Item should horizontally shrink
     *
     * @return true if it should horizontally shrink
     */
    boolean shouldHShrink() {
        return ((layout & LAYOUT_SHRINK) == LAYOUT_SHRINK);
    }

    /**
     * Determine if this Item should horizontally expand
     *
     * @return true if it should horizontally expand
     */
    boolean shouldHExpand() {
        return ((layout & LAYOUT_EXPAND) == LAYOUT_EXPAND);
    }

    /**
     * Determine if this Item should vertically shrink
     *
     * @return true if it should vertically shrink
     */
    boolean shouldVShrink() {
        return ((layout & LAYOUT_VSHRINK) == LAYOUT_VSHRINK);
    }

    /**
     * Determine if this Item should vertically expand
     *
     * @return true if it should vertically expand
     */
    boolean shouldVExpand() {
        return ((layout & LAYOUT_VEXPAND) == LAYOUT_VEXPAND);
    }

    /**
     * Determine if this Item should have a newline after it
     *
     * @return true if it should have a newline after
     */
    boolean equateNLA() {
        return ((layout & LAYOUT_NEWLINE_AFTER) == LAYOUT_NEWLINE_AFTER);
    }

    /**
     * Determine if this Item should have a newline before it
     *
     * @return true if it should have a newline before
     */
    boolean equateNLB() {
        return ((layout & LAYOUT_NEWLINE_BEFORE) == LAYOUT_NEWLINE_BEFORE);
    }

    /**
     * Determine if this Item should not be traversed to
     *
     * @return true if this Item should not be traversed to
     */
    boolean shouldSkipTraverse() {
        return false;
    }

    /**
     * Paint the content of this Item
     *
     * @param g the Graphics object to be used for rendering the item
     * @param w current width of the item in pixels
     * @param h current height of the item in pixels
     */
    abstract void callPaint(Graphics g, int w, int h);

    /**
     * Called by subclasses to repaint this entire Item's bounds
     */
    void repaint() {
        if (bounds != null) {
            repaint(0, 0, bounds[WIDTH], bounds[HEIGHT]);
        }
    }

    /**
     * Called by subclasses to repaint a portion of this Item's bounds
     *
     * @param x the x coordinate of the origin of the dirty region
     * @param y the y coordinate of the origin of the dirty region
     * @param w the width of the dirty region
     * @param h the height of the dirty region
     */
    void repaint(int x, int y, int w, int h) {

        if (owner != null) {

            if (x < 0) {
                x = 0;
            } else if (x > bounds[WIDTH]) {
                return;
            }

            if (y < 0) {
                y = 0;
            } else if (y > bounds[HEIGHT]) {
                return;
            }

            if (w < 0) {
                w = 0;
            } else if (w > bounds[WIDTH]) {
                w = bounds[WIDTH];
            }

            if (h < 0) {
                h = 0;
            } else if (h > bounds[HEIGHT]) {
                h = bounds[HEIGHT];
            }
            owner.repaintItem(this, x, y, w, h);
        }
    }

    /**
     * Called by subclasses to paint this Item's label
     *
     * @param g the graphics to draw to
     * @param width the allowable width for the label
     * @return the vertical offset of the label, if it was painted, 0
     *         if it was not
     */
    int paintLabel(Graphics g, int width) {
        int labelHeight = getLabelHeight(width);
        if (LABEL_BOLD_ON_TRAVERSE) {
            Text.paint(label, hasFocus ? LABEL_FONT: Screen.CONTENT_FONT,
                    g, width, labelHeight, 0, Text.NORMAL, null);
        } else {
            Text.paint(label, LABEL_FONT,
                    g, width, labelHeight, 0, Text.NORMAL, null);
        }
        return labelHeight;
    }

    /**
     * Called by the system to indicate the size available to this Item
     * has changed
     *
     * @param w the new width of the item's content area
     * @param h the new height of the item's content area
     */
    void callSizeChanged(int w, int h) { }

    /**
     * Called by subclass code to indicate to the system that it has
     * either modified its size requirements or performed an internal
     * traversal
     */
    void invalidate() {
        synchronized (Display.LCDUILock) {
            if (owner != null) {
                owner.invalidate(this);
            }
        }
    }

    /**
     * Called by the system
     *
     * <p>The default implementation of the traverse() method always returns
     * false.</p>
     *
     * @param dir the direction of traversal
     * @param viewportWidth the width of the container's viewport
     * @param viewportHeight the height of the container's viewport
     * @param visRect_inout passes the visible rectangle into the method, and
     * returns the updated traversal rectangle from the method
     * @return true if internal traversal had occurred, false if traversal
     * should proceed out
     *
     * @see #getInteractionModes
     * @see #traverseOut
     * @see #TRAVERSE_HORIZONTAL
     * @see #TRAVERSE_VERTICAL
     */
    boolean callTraverse(int dir, int viewportWidth, int viewportHeight,
                         int[] visRect_inout) {

        hasFocus = true;
        return false;
    }

    /**
     * Called by the system to indicate traversal has left this Item
     *
     * @see #getInteractionModes
     * @see #traverse
     * @see #TRAVERSE_HORIZONTAL
     * @see #TRAVERSE_VERTICAL
     */
    void callTraverseOut() {
        hasFocus = false;
    }

    /**
     * Called by the system to signal a key press
     *
     * @param keyCode the key code of the key that has been pressed
     * @see #getInteractionModes
     */
    void callKeyPressed(int keyCode) { }

    /**
     * Called by the system to signal a key typed
     *
     * @param c The character entered from the QWERTY keyboard
     */
    void callKeyTyped(char c) { }

    /**
     * Called by the system to signal a key release
     *
     * @param keyCode the key code of the key that has been released
     * @see #getInteractionModes
     */
    void callKeyReleased(int keyCode) { }

    /**
     * Called by the system to signal a key repeat
     *
     * @param keyCode the key code of the key that has been repeated
     * @see #getInteractionModes
     */
    void callKeyRepeated(int keyCode) { }

    /**
     * Called by the system to signal a pointer press
     *
     * @param x the x coordinate of the pointer down
     * @param y the y coordinate of the pointer down
     *
     * @see #getInteractionModes
     */
    void callPointerPressed(int x, int y) { }

    /**
     * Called by the system to signal a pointer release
     *
     * @param x the x coordinate of the pointer up
     * @param y the x coordinate of the pointer up
     *
     * @see #getInteractionModes
     */
    void callPointerReleased(int x, int y) {}

    /**
     * Called by the system to signal a pointer drag
     *
     * @param x the x coordinate of the pointer drag
     * @param y the x coordinate of the pointer drag
     *
     * @see #getInteractionModes
     */
    void callPointerDragged(int x, int y) { }

    /**
     * Called by the system to notify this Item it is being shown
     *
     * <p>The default implementation of this method updates
     * the 'visible' state
     */
    void callShowNotify() {
        this.visible = true;
    }

    /**
     * Called by the system to notify this Item it is being hidden
     *
     * <p>The default implementation of this method updates
     * the 'visible' state
     */
    void callHideNotify() {
        this.visible = false;
    }

    /**
     * Draw a Button Border around this Item when in Button Mode
     *
     * @param g The Graphics context to paint to
     * @param x  x co-ordinate of the Button Border
     * @param y  y co-ordinate of the Button Border
     * @param w  width of the Button Border
     * @param h height of the Button Border
     * @param hasFocus A flag indicating this Item has focus or not
     */
    void drawButtonBorder(Graphics g, int x, int y, int w, int h,
                          boolean hasFocus) {
        g.setColor(hasFocus ? DARK_GRAY_COLOR : LIGHT_GRAY_COLOR);
        g.fillRect(x, y, w, BUTTON_BORDER);
        g.fillRect(x, y, BUTTON_BORDER, h);

        g.setColor(hasFocus ? LIGHT_GRAY_COLOR : DARK_GRAY_COLOR);

        g.fillTriangle(x, y + h,
            x + BUTTON_BORDER,
            y + h - BUTTON_BORDER,
            x + BUTTON_BORDER,
            y + h);

        g.fillRect(x + BUTTON_BORDER,
            y + h - BUTTON_BORDER,
            w - BUTTON_BORDER,
            BUTTON_BORDER);

        g.fillTriangle(x + w, y,
            x + w - BUTTON_BORDER,
            y + BUTTON_BORDER,
            x + w,
            y + BUTTON_BORDER);

        g.fillRect(x + w - BUTTON_BORDER,
            y + BUTTON_BORDER,
            BUTTON_BORDER, h - BUTTON_BORDER);

        g.setColor(Display.FG_COLOR);
    }

    /**
     *  Adds a context sensitive Command to the item.
     * @param cmd the command to be removed
     */
    void addCommandImpl(Command cmd) {
        // LCDUI Lock must be acquired
        // prior to calling this method.
        if (cmd == null) {
            throw new NullPointerException();
        }

        for (int i = 0; i < numCommands; ++i) {
            if (commands[i] == cmd) {
                return;
            }
        }

        if ((commands == null) || (numCommands == commands.length)) {
            Command[] newCommands = new Command[numCommands + 4];
            if (commands != null) {
                System.arraycopy(commands, 0, newCommands, 0,
                                 numCommands);
            }
            commands = newCommands;
        }

        commands[numCommands] = cmd;
        ++numCommands;

        if (owner != null) {
            owner.updateCommandSet();
        }
    }

    /**
     * Removes the context sensitive command from item.
     * @param cmd the command to be removed
     */
    void removeCommandImpl(Command cmd) {
        // LCDUI Lock must be acquired
        // prior to calling this method.
        for (int i = 0; i < numCommands; ++i) {
            if (commands[i] == cmd) {
                commands[i] = commands[--numCommands];
                commands[numCommands] = null;

                if (cmd == defaultCommand) {
                    defaultCommand = null;
                }

                if (owner != null) {
                    owner.updateCommandSet();
                }

                break;
            }
        }
    }

    /**
     * Gets the set of Commands that have been added to this Item
     *
     * @return Command[] The array of Commands added to this Item
     */
    Command[] getCommands() {
        return commands;
    }

    /**
     * Gets the number of commands that have been added to this Item
     *
     * @return int The number of commands that have been added to this
     *             Item
     */
    int getCommandCount() {
        return numCommands;
    }

    /**
     * Gets ItemCommandListener for this Item
     * @return ItemCommandListener The ItemCommandListener for this Item
     */ 
    ItemCommandListener getItemCommandListener() {
        return commandListener;
    }

    /**
     * Get the owner of this Item
     *
     * @return Screen The owner of this Item
     */
    final Screen getOwner() {
        return owner;
    }

    /**
     * Set the Screen owner of this Item
     *
     * @param owner The Screen containing this Item
     */
    void setOwner(Screen owner) {
        synchronized (Display.LCDUILock) {
            if (this.owner != null && owner != null) {
                throw new IllegalStateException();
            }
            this.owner = owner;
        }
    }

    /**
     * Set the layout type of this Item
     *
     * @param layout The layout type.
     */
    void setLayoutImpl(int layout) {

        if ((layout & ~VALID_LAYOUT) != 0) {
            throw new IllegalArgumentException();
        }

        this.layout = layout;
    }

    /**
     * Get the effective layout type of this Item
     *
     * @return layout The translated layout type.
     */
    int callGetLayout() {
        int l = this.layout;
        if (l == LAYOUT_DEFAULT) {
            return LAYOUT_TOP | LAYOUT_LEFT;
        } else {
            return l;
        }
    }
}