/*
*
*
* Copyright 1990-2007 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;
}
|