/* * * * Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. */ package javax.microedition.lcdui; /** * 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> * */ 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> */ 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> */ 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> */ 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> */ 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> */ 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> */ 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> */ 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> */ 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> */ 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> */ 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> */ 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> */ public final static int LAYOUT_VEXPAND = 0x2000; /** * A layout directive indicating that new MIDP 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> * */ 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> */ 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> */ 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> */ public final static int BUTTON = 2; // ************************************************************ // Static initializer, constructor // ************************************************************ /** * 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) { if (label != this.label && (label == null || !label.equals(this.label))) { this.label = label; itemLF.lSetLabel(label); } } } /** * 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 * @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> * @see #getLayout */ public void setLayout(int layout) { synchronized (Display.LCDUILock) { int oldLayout = this.layout; setLayoutImpl(layout); if (oldLayout != this.layout) { itemLF.lSetLayout(layout); } } } /** * 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> */ 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 */ 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> */ 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 */ public int getPreferredWidth() { synchronized (Display.LCDUILock) { if (lockedWidth != -1) { return lockedWidth; } else { return itemLF.lGetPreferredWidth(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 */ public int getPreferredHeight() { synchronized (Display.LCDUILock) { if (lockedHeight != -1) { return lockedHeight; } else { return itemLF.lGetPreferredHeight(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 */ 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(); } userPreferredWidth = width; userPreferredHeight = height; lUpdateLockedSize(); } // synchronized } /** * Re-calculate the locked width and height using the current values * of preferred and minimum width and height. */ void lUpdateLockedSize() { // Collect minimum size information int minWidth = itemLF.lGetMinimumWidth(); int minHeight = itemLF.lGetMinimumHeight(); int newLockedWidth = (userPreferredWidth != -1 && userPreferredWidth < minWidth) ? minWidth : userPreferredWidth; int newLockedHeight = (userPreferredHeight != -1 && userPreferredHeight < minHeight) ? minHeight : userPreferredHeight; if (newLockedWidth != lockedWidth || newLockedHeight != lockedHeight) { lockedWidth = newLockedWidth; lockedHeight = newLockedHeight; itemLF.lSetPreferredSize(lockedWidth, lockedHeight); } } /** * 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 */ public int getMinimumWidth() { synchronized (Display.LCDUILock) { return itemLF.lGetMinimumWidth(); } } /** * 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 */ public int getMinimumHeight() { synchronized (Display.LCDUILock) { return itemLF.lGetMinimumHeight(); } } /** * 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> */ public void setDefaultCommand(Command cmd) { synchronized (Display.LCDUILock) { if (defaultCommand != cmd) { // Make sure the command present on the Item if (cmd != null) { addCommandImpl(cmd); } // Set it as new default command defaultCommand = cmd; itemLF.lSetDefaultCommand(defaultCommand, numCommands); } } } /** * 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> */ public void notifyStateChanged() { synchronized (Display.LCDUILock) { // Among the public Displayables, // List, TextBox and Form are legal to own Items. // Canvas does not accept Item. // Alert is the only one that we need to prevent. if (owner == null || owner instanceof Alert) { throw new IllegalStateException(); } // SYNC NOTE: Displayable.itemStateChanged() will // simply schedule a state change event. So it's // OK to call it while holding LCDUILock. owner.itemStateChanged(this); } } // ************************************************************ // protected methods // ************************************************************ // ************************************************************ // package private methods // ************************************************************ /** * Set the Screen owner of this Item * SYNC NOTE: Caller must hold LCDUILock around this call. * * @param owner The Screen containing this Item */ void lSetOwner(Screen owner) { if (this.owner != null && owner != null) { throw new IllegalStateException(); } Screen oldOwner = this.owner; this.owner = owner; itemLF.lSetOwner(oldOwner); } /** * Gets look & feel object associated with this * Item. * @return - ItemLF associated with this Item. */ ItemLF getLF() { return itemLF; } /** * Return whether the Item takes user input focus. * * @return return <code>true</code> if abstract commands are present */ boolean acceptFocus() { // user needs to access abstract commands return (numCommands > 0); } /** * Adds a context sensitive Command to the item. * LCDUI Lock must be acquired prior to calling this method. * * @param cmd the command to be added * @exception NullPointerException if cmd is null */ private void addCommandImpl(Command cmd) { 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; itemLF.lAddCommand(cmd, numCommands); } /** * 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; itemLF.lSetDefaultCommand(null, i); } itemLF.lRemoveCommand(cmd, i); return; } } } /** * Set the layout type of this Item * * @param layout The layout type. */ void setLayoutImpl(int layout) { // LCDUI Lock must be acquired // prior to calling this method. if ((layout & ~VALID_LAYOUT) != 0) { throw new IllegalArgumentException(); } this.layout = layout; } /** * Notify the item to the effect that it has been recently deleted */ void itemDeleted() { synchronized (Display.LCDUILock) { lSetOwner(null); } } // ************************************************************ // protected member variables // ************************************************************ // ************************************************************ // package private member variables // ************************************************************ /** internal bitmask representing a valid layout mask */ final static int VALID_LAYOUT; 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; } /** * Item' Look&Feel object associated with this item * It is set in the subclasses constructors */ ItemLF itemLF; /** * commandListener that has to be notified of when ITEM command is * activated */ ItemCommandListener commandListener; // = null; /** The label of this Item */ String label; // = null /** * The owner Screen for this Item */ Screen owner; // = null /** * The layout type of this Item */ int layout; // = 0 ; LAYOUT_DEFAULT = 0 /** An array of Commands added to this Item */ Command commands[]; /** The number of Commands added to this Item */ int numCommands; // = 0 /** * This is a default Command which represents the callback * to a selection event. */ Command defaultCommand; // = null /** The locked width of this Item, -1 by default. * If non-default, locked width is the maximum of minimal * width and the preferred width. */ int lockedWidth = -1; /** The preferred width of this Item, specified in the last call * of setPreferredSize(int width, int height), -1 by default. */ int userPreferredWidth = -1; /** The locked height of this Item, -1 by default. * If non-default, locked height is the maximum of minimal * height and the preferred height. */ int lockedHeight = -1; /** The preferred height of this Item, specified in the last call * of setPreferredSize(int width, int height), -1 by default. */ int userPreferredHeight = -1; }