/* * * * 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 <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); // 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.lSetOwner(this); displayableLF = listLF = LFFactory.getFactory().getListLF(this); } } // ***************************************************** // Public methods // ***************************************************** /** * 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 * */ public void removeCommand(Command cmd) { synchronized (Display.LCDUILock) { int i = super.removeCommandImpl(cmd); if (cmd == selectCommand) { selectCommand = null; } if (i != -1) { listLF.lRemoveCommand(cmd, i); } } // 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 * */ public void setSelectCommand(Command command) { // If we're not an IMPLICIT List, ignore this method // call entirely if (cg.choiceType != 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 */ 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 */ 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 */ 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) */ public Font getFont(int elementNum) { return cg.getFont(elementNum); } // package private members // 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 */ 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(). */ Command selectCommand = SELECT_COMMAND; /** * Look & Feel object associated with this List */ FormLF listLF; }