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

List.java

/*
 * @(#)List.java	1.93 02/09/12 @(#)
 *
 * Copyright (c) 1999-2002 Sun Microsystems, Inc.  All rights reserved.
 * PROPRIETARY/CONFIDENTIAL
 * Use is subject to license terms.
 */

package javax.microedition.lcdui;

/**
 * A <code>Screen</code> containing list of choices. Most of its
 * behavior is common with
 * class {@link ChoiceGroup ChoiceGroup}, and their common API. The
 * different <code>List</code> types in particular, are defined in
 * interface {@link Choice
 * Choice}.  When a <code>List</code> is present on the display, the
 * user can interact with
 * it by selecting elements and possibly by traversing and scrolling among
 * them.  Traversing and scrolling operations do not cause application-visible
 * events. The system notifies the application only when a {@link Command
 * Command} is invoked by notifying its {@link CommandListener}.  The
 * <code>List</code>
 * class also supports a select command that may be invoked specially
 * depending upon the capabilities of the device.
 *
 * <p>The notion of a <em>select</em> operation on a <code>List</code>
 * element is central
 * to the user's interaction with the <code>List</code>.  On devices
 * that have a dedicated
 * hardware "select" or "go" key, the select
 * operation is implemented with
 * that key.  Devices that do not have a dedicated key must provide another
 * means to do the select operation, for example, using a soft key.  The
 * behavior of the select operation within the different types of lists is
 * described in the following sections.</p>
 *
 * <p><code>List</code> objects may be created with <code>Choice</code> types of
 * {@link Choice#EXCLUSIVE}, {@link Choice#MULTIPLE}, and
 * {@link Choice#IMPLICIT}.  The <code>Choice</code> type {@link Choice#POPUP}
 * is not allowed on <code>List</code> objects.</p>
 *
 * <h3>Selection in <code>EXCLUSIVE</code> and <code>MULTIPLE</code> Lists</h3>
 *
 * <p>The select operation is not associated with a
 * <code>Command</code> object, so the
 * application has no means of setting a label for it or being notified when
 * the operation is performed.  In <code>Lists</code> of type
 * <code>EXCLUSIVE</code>, the select
 * operation selects the target element and deselects the previously selected
 * element.  In <code>Lists</code> of type <code>MULTIPLE</code>, the
 * select operation toggles the
 * selected state of the target element, leaving the selected state of other
 * elements unchanged.  Devices that implement the select operation using a
 * soft key will need to provide a label for it.  The label should be something
 * similar to "Select" for <code>Lists</code> of type
 * <code>EXCLUSIVE</code>, and it should be something
 * similar to "Mark" or "Unmark" for
 * <code>Lists</code> of type <code>MULTIPLE</code>.</p>
 *
 * <h3>Selection in <code>IMPLICIT</code> Lists</h3>
 *
 * <p>The select operation is associated with a <code>Command</code>
 * object referred to as
 * the <em>select command</em>.  When the user performs the select operation,
 * the system will invoke the select command by notifying the
 * <code>List's</code> {@link
 * CommandListener CommandListener}.  The default select command is the
 * system-provided command <code>SELECT_COMMAND</code>.  The select
 * command may be modified
 * by the application through use of the {@link #setSelectCommand(Command
 * command) setSelectCommand} method.  Devices that implement the select
 * operation using a soft key will use the label from the select command.  If
 * the select command is <code>SELECT_COMMAND</code>, the device may
 * choose to provide its
 * own label instead of using the label attribute of
 * <code>SELECT_COMMAND</code>.
 * Applications should generally provide their own select command to replace
 * <code>SELECT_COMMAND</code>.  This allows applications to provide a
 * meaningful label,
 * instead of relying on the one provided by the system for
 * <code>SELECT_COMMAND</code>.
 * The implementation must <em>not</em> invoke the select command if there are
 * no elements in the <code>List</code>, because if the
 * <code>List</code> is empty the selection does
 * not exist.  In this case the implementation should remove or disable the
 * select command if it would appear explicitly on a soft button or in a menu.
 * Other commands can be invoked normally when the <code>List</code>
 * is empty.</p>
 *
 * <h3>Use of <code>IMPLICIT</code> Lists</h3>
 *
 * <p> <code>IMPLICIT</code> <code>Lists</code> can be used to
 * construct menus by providing operations
 * as <code>List</code> elements.  The application provides a
 * <code>Command</code> that is used to
 * select a <code>List</code> element and then defines this
 * <code>Command</code> to be used as the
 * select command.  The application must also register a
 * <code>CommandListener</code> that
 * is called when the user selects or activates the <code>Command</code>:</p>
 *
 * <TABLE BORDER="2">
 * <TR>
 * <TD ROWSPAN="1" COLSPAN="1">
 *    <pre><code>
 *     String[] elements = { ... }; //Menu items as List elements
 *     List menuList = new List("Menu", List.IMPLICIT, elements, null);
 *     Command selectCommand = new Command("Open", Command.ITEM, 1);
 *     menuList.setSelectCommand(selectCommand);
 *     menuList.setCommandListener(...);     </code></pre>
 * </TD>
 * </TR>
 * </TABLE>
 *
 * <p>The listener can query the <code>List</code> to determine which
 * element is selected
 * and then perform the corresponding action.  Note that setting a command as
 * the select command adds it to the <code>List</code> as a side effect.</p>
 *
 * <p> The select command should be considered as a <em>default operation</em>
 * that takes place when a select key is pressed.  For example, a
 * <code>List</code>
 * displaying email headers might have three operations: read, reply, and
 * delete. Read is considered to be the default operation.  </p>
 *
 * <TABLE BORDER="2">
 * <TR>
 * <TD ROWSPAN="1" COLSPAN="1">
 *    <pre><code>
 *     List list = new List("Email", List.IMPLICIT, headers);
 *     readCommand = new Command("Read", Command.ITEM, 1);
 *     replyCommand = new Command("Reply", Command.ITEM, 2);
 *     deleteCommand = new Command("Delete", Command.ITEM, 3);
 *     list.setSelectCommand(readCommand);
 *     list.addCommand(replyCommand);
 *     list.addCommand(deleteCommand);
 *     list.setCommandListener(...);     </code></pre>
 * </TD>
 * </TR>
 * </TABLE>
 * <p>On a device with a dedicated select key, pressing this key will invoke
 * <code>readCommand</code>.  On a device without a select key, the user is
 * still able to invoke the read command, since it is also provided as an
 * ordinary <code>Command</code>.</p>
 *
 * <p> It should be noted that this kind of default operation must be used
 * carefully, and the usability of the resulting user interface must always
 * kept in mind. The default operation should always be the most intuitive
 * operation on a particular List.  </p>
 *
 * @since MIDP 1.0
 */

public class List extends Screen implements Choice {

    /**
     * The default select command for <code>IMPLICIT</code> <code>Lists</code>.
     * Applications using an <code>IMPLICIT</code> <code>List</code>
     * should set their own select command
     * using 
     * {@link #setSelectCommand(Command command) setSelectCommand}.
     * 
     * <p>
     * The field values of <code>SELECT_COMMAND</code> are:<br>
     * - <code>label = ""</code> (an empty string)<br>
     * - <code>type = SCREEN</code><br>
     * - <code>priority = 0</code><br>
     * </p>
     * <p>(It would be more appropriate if the type were
     * <code>ITEM</code>, but the type of
     * <code>SCREEN</code> is retained for historical purposes.)</p>
     * <p>
     * The application should not use these values for recognizing
     * the <code>SELECT_COMMAND</code>. Instead, object identities of
     * the <code>Command</code> and
     * <code>Displayable</code> (<code>List</code>) should be used.
     * </p>
     * 
     * <p><code>SELECT_COMMAND</code> is treated as an ordinary
     * <code>Command</code> if it is used with other <code>Displayable</code>
     * types.</p>
     */
    public final static Command SELECT_COMMAND =
        new Command("", Command.SCREEN, 0);

    // private members //

    /**
     * An internal Form to render this List (basically, a List is
     * just a Form with a choiceGroup in it
     */
    private Form form;

    // SYNC NOTE: The List constructor establishes 'cg' as non-null
    // and which remains constant for the lifetime of this object.
    // All public api calls are delegated to the 'cg' object and
    // therefore no synchronization is necessary.
    /**
     * An internal choicegroup to handle the selections
     */
    private ChoiceGroup cg;

    /**
     * This is an internal Command which represents the callback
     * to a selection event of an IMPLICIT list. By default, this
     * command is the predefined List.SELECT_COMMAND. This can be
     * overridden however using the setSelectCommand().
     */
    private Command selectCommand = SELECT_COMMAND;

    // constructors //

    /**
     * Creates a new, empty <code>List</code>, specifying its title
     * and the type of the
     * list. 
     * @param title the screen's title (see {@link Displayable Displayable})
     * @param listType one of <code>IMPLICIT</code>, <code>EXCLUSIVE</code>,
     * or <code>MULTIPLE</code>
     * @throws IllegalArgumentException if <code>listType</code> is not
     * one of
     * <code>IMPLICIT</code>,
     * <code>EXCLUSIVE</code>, or <code>MULTIPLE</code>
     * @see Choice
     */
    public List(String title, int listType) {
        this(title, listType, new String[] {}, new Image[] {});
    }

    /**
     * Creates a new <code>List</code>, specifying its title, the type
     * of the <code>List</code>, and
     * an array of <code>Strings</code> and <code>Images</code> to be
     * used as its initial contents.
     *
     * <p>The <code>stringElements</code> array must be non-null and
     * every array element
     * must also be non-null.  The length of the
     * <code>stringElements</code> array
     * determines the number of elements in the <code>List</code>.
     * The <code>imageElements</code> array
     * may be <code>null</code> to indicate that the <code>List</code>
     * elements have no images.  If the
     * <code>imageElements</code> array is non-null, it must be the
     * same length as the
     * <code>stringElements</code> array.  Individual elements of the
     * <code>imageElements</code> array
     * may be <code>null</code> in order to indicate the absence of an
     * image for the
     * corresponding <code>List</code> element. Non-null elements of the
     * <code>imageElements</code> array may refer to mutable or
     * immutable images.</p>
     *
     * @param title the screen's title (see {@link Displayable Displayable})
     * @param listType one of <code>IMPLICIT</code>, <code>EXCLUSIVE</code>,
     * or <code>MULTIPLE</code>
     * @param stringElements set of strings specifying the string parts of the
     * <code>List</code> elements
     * @param imageElements set of images specifying the image parts of
     * the <code>List</code> elements
     *
     * @throws NullPointerException if <code>stringElements</code> is
     * <code>null</code>
     * @throws NullPointerException if the <code>stringElements</code>
     * array contains any null elements
     * @throws IllegalArgumentException if the <code>imageElements</code>
     * array is non-null
     * and has a different length from the <code>stringElements</code> array
     * @throws IllegalArgumentException if <code>listType</code> is not one 
     * of <code>IMPLICIT</code>,
     * <code>EXCLUSIVE</code>, or <code>MULTIPLE</code>
     *
     * @see Choice#EXCLUSIVE
     * @see Choice#MULTIPLE
     * @see Choice#IMPLICIT
     */
    public List(String title, int listType, String[] stringElements,
		Image[] imageElements) {

        super(title);

        if (!(listType == IMPLICIT   ||
              listType == EXCLUSIVE  ||
              listType == MULTIPLE)) {
            throw new IllegalArgumentException();
        }

        synchronized (Display.LCDUILock) {

            cg = new ChoiceGroup(null, listType,
                                 stringElements, imageElements, true);
            cg.isList = true;

            form = new Form(title);
            form.paintDelegate = this;
            form.append(cg);
        }
    }

    // public methods //

    /**
     * Sets a ticker for use with this <code>Displayable</code>,
     * replacing any
     * previous ticker.
     * If <code>null</code>, removes the ticker object
     * from this <code>Displayable</code>. The same ticker may be shared by
     * several <code>Displayable</code>
     * objects within an application. This is done by calling
     * <code>setTicker()</code>
     * with the same <code>Ticker</code> object on several
     * different <code>Displayable</code> objects.
     * If the <code>Displayable</code> is actually visible on the display,
     * the implementation should update
     * the display as soon as it is feasible to do so.
     *
     * <p>The existence of a ticker may affect the size
     * of the area available for <code>Displayable's</code> contents.
     * If the application adds, removes, or sets the ticker text at runtime,
     * this can dynamically change the size of the content area.
     * This is most important to be aware of when using the
     * <code>Canvas</code> class.
     *
     * @param ticker the ticker object used on this screen
     * @since MIDP 2.0
     * @see #getTicker
     */
    public void setTicker(Ticker ticker) {
        super.setTicker(ticker);

        // We override this method from Displayable to set the ticker
        // on our internal Form which is doing all our rendering

        form.setTicker(ticker);
    }

    /**
     * Sets the title of the <code>Displayable</code>. If
     * <code>null</code> is given,
     * removes the title.
     *
     * <P>If the <code>Displayable</code> is actually visible on
     * the display,
     * the implementation should update
     * the display as soon as it is feasible to do so.</P>
     *
     * <P>The existence of a title  may affect the size
     * of the area available for <code>Displayable</code> content.
     * If the application adds, removes, or sets the title text at runtime,
     * this can dynamically change the size of the content area.
     * This is most important to be aware of when using the
     * <code>Canvas</code> class.</p>
     *
     * @param s the new title, or <code>null</code> for no title
     * @since MIDP 2.0
     * @see #getTitle
     */
    public void setTitle(String s) {
        super.setTitle(s);

        // We override this method from Displayable to set the title
        // on our internal Form which is doing all our rendering

        form.setTitle(s);
    }

    /**
     * Gets the number of elements in the <code>List</code>.
     * @return the number of elements in the <code>List</code>
     */
    public int size() {
        return cg.size();
    }

    /**
     * Gets the <code>String</code> part of the element referenced by
     * <code>elementNum</code>.
     * 
     * @param elementNum the index of the element to be queried
     * @return the string part of the element
     * @throws IndexOutOfBoundsException if <code>elementNum</code> is invalid
     * @see #getImage(int)
     */
    public String getString(int elementNum) {
        return cg.getString(elementNum);
    }

    /**
     * Gets the <code>Image</code> part of the element referenced by
     * <code>elementNum</code>.
     *
     * @param elementNum the number of the element to be queried
     * @return the image part of the element, or <code>null</code>
     * if there is no image
     * @throws IndexOutOfBoundsException if <code>elementNum</code> is invalid
     * @see #getString(int)
     */
    public Image getImage(int elementNum) {
        return cg.getImage(elementNum);
    }

    /**
     * Appends an element to the <code>List</code>.
     * 
     * @param stringPart the string part of the element to be added
     * @param imagePart the image part of the element to be added, or
     * <code>null</code> if there is no image part
     * @return the assigned index of the element
     * @throws NullPointerException if <code>stringPart</code> is
     * <code>null</code>
     */
    public int append(String stringPart, Image imagePart) {
        return cg.append(stringPart, imagePart);
    }

    /**
     * Inserts an element into the <code>List</code> just prior to
     * the element specified.
     * 
     * @param elementNum the index of the element where insertion is to occur
     * @param stringPart the string part of the element to be inserted
     * @param imagePart the image part of the element to be inserted,
     * or <code>null</code> if there is no image part
     * @throws IndexOutOfBoundsException if <code>elementNum</code> is invalid
     * @throws NullPointerException if <code>stringPart</code> is
     * <code>null</code>
     */
    public void insert(int elementNum,
                       String stringPart, Image imagePart) {
        cg.insert(elementNum, stringPart, imagePart);
    }

    /**
     * Deletes the element referenced by <code>elementNum</code>.
     * 
     * @param elementNum the index of the element to be deleted
     * @throws IndexOutOfBoundsException if <code>elementNum</code> is invalid
     */
    public void delete(int elementNum) {
        cg.delete(elementNum);
    }

    /**
     * Deletes all elements from this List.
     */
    public void deleteAll() {
        cg.deleteAll();
    }

    /**
     * Sets the <code>String</code> and <code>Image</code> parts of the
     * element referenced by <code>elementNum</code>,
     * replacing the previous contents of the element.
     * 
     * @param elementNum the index of the element to be set
     * @param stringPart the string part of the new element
     * @param imagePart the image part of the element, or <code>null</code>
     * if there is no image part
     *
     * @throws IndexOutOfBoundsException if <code>elementNum</code> is invalid
     * @throws NullPointerException if <code>stringPart</code> is
     * <code>null</code>
     */
    public void set(int elementNum, String stringPart, Image imagePart) {
        cg.set(elementNum, stringPart, imagePart);
    }

    /**
     * Gets a boolean value indicating whether this element is selected.
     * 
     * @param elementNum index to element to be queried
     *
     * @return selection state of the element
     *
     * @throws IndexOutOfBoundsException if <code>elementNum</code> is invalid
     */
    public boolean isSelected(int elementNum) {
        return cg.isSelected(elementNum);
    }

    /**
     * Returns the index number of an element in the <code>List</code>
     * that is selected.
     * 
     * @return index of selected element, or <code>-1</code> if none
     * @see #setSelectedIndex
     */
    public int getSelectedIndex() {
        return cg.getSelectedIndex();
    }

    /**
     * Queries the state of a <code>List</code> and returns the
     * state of all elements
     * in the
     * boolean array
     * <code>selectedArray_return</code>.
     * 
     * @param selectedArray_return array to contain the results
     *
     * @return the number of selected elements in the <code>Choice</code>
     *
     * @throws IllegalArgumentException if <code>selectedArray_return</code>
     * is shorter than the size of the List
     * @throws NullPointerException if <code>selectedArray_return</code> 
     * is <code>null</code>
     * @see #setSelectedFlags
     */
    public int getSelectedFlags(boolean[] selectedArray_return) {
        return cg.getSelectedFlags(selectedArray_return);
    }

    /**
     * Sets the selected state of an element.
     * 
     * @param elementNum the index of the element, starting from zero
     * @param selected the state of the element, where <code>true</code> means
     * selected and <code>false</code> means not selected
     * @throws IndexOutOfBoundsException if <code>elementNum</code> is invalid
     * @see #getSelectedIndex
     */
    public void setSelectedIndex(int elementNum, boolean selected) {
        cg.setSelectedIndex(elementNum, selected);
    }

    /**
     * Sets the selected state of all elements of the <code>List</code>.
     * 
     * @param selectedArray an array in which the method collect
     * the selection status
     * @throws IllegalArgumentException if <code>selectedArray</code> is
     * shorter than the size of the <code>List</code>
     * @throws NullPointerException if <code>selectedArray</code> is
     * <code>null</code>
     * @see #getSelectedFlags
     */
    public void setSelectedFlags(boolean[] selectedArray) {
        cg.setSelectedFlags(selectedArray);
    }

    /**
     * The same as {@link Displayable#removeCommand Displayable.removeCommand} 
     * but with the following additional semantics.
     * 
     * <p>If the command to be removed happens to be the select command, the
     * <code>List</code> is set to have no select command, and the command is
     * removed from the <code>List</code>.</p>
     *
     * <p>The following code: </P>
     * <TABLE BORDER="2">
     * <TR>
     * <TD ROWSPAN="1" COLSPAN="1">
     *    <pre><code>
     *     // Command c is the select command on List list    
     *     list.removeCommand(c);     </code></pre>
     * </TD>
     * </TR>
     * </TABLE>
     * <P>
     * is equivalent to the following code: </P>
     * <TABLE BORDER="2">
     * <TR>
     * <TD ROWSPAN="1" COLSPAN="1">
     *    <pre><code>
     *     // Command c is the select command on List list    
     *     list.setSelectCommand(null);    
     *     list.removeCommand(c);     </code></pre>
     * </TD>
     * </TR>
     * </TABLE>
     * @param cmd the command to be removed
     *
     * @since MIDP 2.0
     */
    public void removeCommand(Command cmd) {
        synchronized (Display.LCDUILock) {
            super.removeCommandImpl(cmd);
            if (cmd == selectCommand) {
                selectCommand = null;
            }
        } // synchronized
    }

    /**
     * Sets the <code>Command</code> to be used for an
     * <code>IMPLICIT</code> <code>List</code> selection
     * action.
     * By default, an implicit selection of a List will result in the
     * predefined <code>List.SELECT_COMMAND</code> being used. This
     * behavior may be
     * overridden by calling the <code>List.setSelectCommand()</code>
     * method with an
     * appropriate parameter value.  If a <code>null</code> reference
     * is passed, this
     * indicates that no "select" action is appropriate for
     * the contents
     * of this <code>List</code>.
     *
     * <p> If a reference to a command object is passed, and
     * it is not the special command <code>List.SELECT_COMMAND</code>, and
     * it is not currently present on this <code>List</code> object,
     * the command object is added to this <code>List</code> as if
     * <code>addCommand(command)</code> had been called
     * prior to the command being made the select command.  This
     * indicates that this command
     * is to be invoked when the user performs the "select"
     * on an element of
     * this <code>List</code>. </p>
     *
     * <p> The select command should have a command type of
     * <code>ITEM</code> to indicate
     * that it operates on the currently selected object.  It is not an error
     * if the command is of some other type.
     * (<code>List.SELECT_COMMAND</code> has a type
     * of <code>SCREEN</code> for historical purposes.)  For purposes
     * of presentation and
     * placement within its user interface, the implementation is allowed to
     * treat the select command as if it were of type <code>ITEM</code>. </p>
     *
     * <p> If the select command is later removed from the <code>List</code>
     * with <code>removeCommand()</code>, the <code>List</code> is set to have
     * no select command as if <code>List.setSelectCommand(null)</code> had
     * been called.</p>
     *
     * <p> The default behavior can be reestablished explicitly by calling
     * <code>setSelectCommand()</code> with an argument of
     * <code>List.SELECT_COMMAND</code>.</p>
     *
     * <p> This method has no effect if the type of the
     * <code>List</code> is not <code>IMPLICIT</code>. </p>
     *
     * @param command the command to be used for an <code>IMPLICIT</code> list
     * selection action, or <code>null</code> if there is none
     *
     * @since MIDP 2.0
     */
    public void setSelectCommand(Command command) {
        // If we're not an IMPLICIT List, ignore this method
        // call entirely
        if (cg.getType() != Choice.IMPLICIT) {
            return;
        }

        // Here we're just resetting the default behavior
        // of this implicit List
        if (command == List.SELECT_COMMAND) {
            selectCommand = command;
            return;
        }

        // Here we're deciding there is no appropriate default
        // command for a selection
        if (command == null) {
            selectCommand = null;
            return;
        }

        // SYNC NOTE: We grab the lock here because we need to determine
        // if the command is in the Displayables command set AND we need
        // to protect ourselves from the Command being removed from the
        // set just after we've done the check. #See how we override the
        // removeCommand() method in this class
        synchronized (Display.LCDUILock) {
            // We ensure that the provided Command has been added
            // to this List.
	    addCommandImpl(command);

            selectCommand = command;
        }

    }

    /**
     * Sets the application's preferred policy for fitting
     * <code>Choice</code> element
     * contents to the available screen space. The set policy applies for all
     * elements of the <code>Choice</code> object.  Valid values are
     * {@link #TEXT_WRAP_DEFAULT}, {@link #TEXT_WRAP_ON},
     * and {@link #TEXT_WRAP_OFF}. Fit policy is a hint, and the
     * implementation may disregard the application's preferred policy.
     *
     * @param fitPolicy preferred content fit policy for choice elements
     * @throws IllegalArgumentException if <code>fitPolicy</code> is invalid
     * @see #getFitPolicy
     * @since MIDP 2.0
     */
    public void setFitPolicy(int fitPolicy) {
        cg.setFitPolicy(fitPolicy);
    }

    /**
     * Gets the application's preferred policy for fitting
     * <code>Choice</code> element
     * contents to the available screen space.  The value returned is the 
     * policy that had been set by the application, even if that value had 
     * been disregarded by the implementation.
     *
     * @return one of {@link #TEXT_WRAP_DEFAULT}, {@link #TEXT_WRAP_ON}, or
     * {@link #TEXT_WRAP_OFF}
     * @see #setFitPolicy
     * @since MIDP 2.0
     */
    public int getFitPolicy() {
        return cg.getFitPolicy();
    }

    /**
     * Sets the application's preferred font for
     * rendering the specified element of this <code>Choice</code>.
     * An element's font is a hint, and the implementation may disregard
     * the application's preferred font.
     *
     * <p> The <code>elementNum</code> parameter must be within the range
     * <code>[0..size()-1]</code>, inclusive.</p>
     *
     * <p> The <code>font</code> parameter must be a valid <code>Font</code>
     * object or <code>null</code>. If the <code>font</code> parameter is
     * <code>null</code>, the implementation must use its default font
     * to render the element.</p>
     *
     * @param elementNum the index of the element, starting from zero
     * @param font the preferred font to use to render the element
     * @throws IndexOutOfBoundsException if <code>elementNum</code> is invalid
     * @see #getFont
     * @since MIDP 2.0
     */
    public void setFont(int elementNum, Font font) {
	    cg.setFont(elementNum, font);
    }

    /**
     * Gets the application's preferred font for
     * rendering the specified element of this <code>Choice</code>. The
     * value returned is the font that had been set by the application,
     * even if that value had been disregarded by the implementation.
     * If no font had been set by the application, or if the application
     * explicitly set the font to <code>null</code>, the value is the default
     * font chosen by the implementation.
     *
     * <p> The <code>elementNum</code> parameter must be within the range
     * <code>[0..size()-1]</code>, inclusive.</p>
     *
     * @param elementNum the index of the element, starting from zero
     * @return the preferred font to use to render the element
     * @throws IndexOutOfBoundsException if <code>elementNum</code> is invalid
     * @see #setFont(int elementNum, Font font)
     * @since MIDP 2.0
     */
    public Font getFont(int elementNum) {
        return cg.getFont(elementNum);
    }

    // package private methods //

    /**
     * Notify this Displayable it is being shown on the given Display
     *
     * @param d the Display showing this Displayable
     */
    void callShowNotify(Display d) {
        super.callShowNotify(d);
        form.callShowNotify(d);
    }

    /**
     * Notify this Displayable it is being hidden on the given Display
     *
     * @param d the Display hiding this Displayable
     */
    void callHideNotify(Display d) {
        super.callHideNotify(d);
        form.callHideNotify(d);
    }

    /**
     * Handle a key pressed event
     *
     * @param keyCode The key that was pressed
     */
    void callKeyPressed(int keyCode) {

        form.callKeyPressed(keyCode);

        if (keyCode == Display.KEYCODE_SELECT) {

	    // don't invoke the select command if there are
	    // no elements in the List
	    if (cg.size() == 0) {
		return;
	    }

            CommandListener cl = null;
            synchronized (Display.LCDUILock) {
                cl = listener;
            }

            if (cl != null) {
                try {
                    // SYNC NOTE: We lock on calloutLock around any calls
                    // into application code
                    synchronized (Display.calloutLock) {
                        cl.commandAction(selectCommand, this);
                    }
                } catch (Throwable thr) {
                    Display.handleThrowable(thr);
                }
            }
        }
    }

    /**
     * Display calls this method on it's current Displayable.
     * SYNC NOTE: The caller of this method handles synchronization.
     *
     * @param g the graphics context to paint into.
     * @param target the target Object of this repaint
     */
    void callPaint(Graphics g, Object target) {
        form.callPaint(g, target);
    }

    /**
     * Called by the event thread to invalidate the contents
     * of this List
     *
     * @param src the Item which may have caused the invalidation
     */
    void callInvalidate(Item src) {
        form.callInvalidate(src);
    }

    /**
     * Called by the event thread to notify an ItemStateChangeListener
     * that an item has changed
     *
     * @param src the Item which has changed
     */
    void callItemStateChanged(Item src) {
        form.callItemStateChanged(src);
    }
}