/* * * * 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>ChoiceGroup</code> is a group of selectable elements intended to be * placed within a * {@link Form}. The group may be created with a mode that requires a * single choice to be made or that allows multiple choices. The * implementation is responsible for providing the graphical representation of * these modes and must provide visually different graphics for different * modes. For example, it might use "radio buttons" for the * single choice * mode and "check boxes" for the multiple choice mode. * * <p> <strong>Note:</strong> most of the essential methods have been * specified in the {@link Choice Choice} interface.</p> * @since MIDP 1.0 */ public class ChoiceGroup extends Item implements Choice { /** * Creates a new, empty <code>ChoiceGroup</code>, specifying its * title and its type. * The type must be one of <code>EXCLUSIVE</code>, * <code>MULTIPLE</code>, or <code>POPUP</code>. The * <code>IMPLICIT</code> * choice type is not allowed within a <code>ChoiceGroup</code>. * * @param label the item's label (see {@link Item Item}) * @param choiceType <code>EXCLUSIVE</code>, <code>MULTIPLE</code>, * or <code>POPUP</code> * @throws IllegalArgumentException if <code>choiceType</code> * is not one of * <code>EXCLUSIVE</code>, <code>MULTIPLE</code>, or <code>POPUP</code> * @see Choice#EXCLUSIVE * @see Choice#MULTIPLE * @see Choice#IMPLICIT * @see Choice#POPUP */ public ChoiceGroup(String label, int choiceType) { this(label, choiceType, new String[] {}, null); } /** * Creates a new <code>ChoiceGroup</code>, specifying its title, * the type of the * <code>ChoiceGroup</code>, and an array of <code>Strings</code> * and <code>Images</code> to be used as its * initial contents. * * <p>The type must be one of <code>EXCLUSIVE</code>, * <code>MULTIPLE</code>, or <code>POPUP</code>. The * <code>IMPLICIT</code> * type is not allowed for <code>ChoiceGroup</code>.</p> * * <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>ChoiceGroup</code>. The * <code>imageElements</code> array * may be <code>null</code> to indicate that the * <code>ChoiceGroup</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>ChoiceGroup</code> element. Non-null elements * of the * <code>imageElements</code> array may refer to mutable or * immutable images.</p> * * @param label the item's label (see {@link Item Item}) * @param choiceType <code>EXCLUSIVE</code>, <code>MULTIPLE</code>, * or <code>POPUP</code> * @param stringElements set of strings specifying the string parts of the * <code>ChoiceGroup</code> elements * @param imageElements set of images specifying the image parts of * the <code>ChoiceGroup</code> elements * * @throws NullPointerException if <code>stringElements</code> * is <code>null</code> * @throws NullPointerException if the <code>stringElements</code> * array contains * any <code>null</code> 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>choiceType</code> * is not one of * <code>EXCLUSIVE</code>, <code>MULTIPLE</code>, or <code>POPUP</code> * * @see Choice#EXCLUSIVE * @see Choice#MULTIPLE * @see Choice#IMPLICIT * @see Choice#POPUP */ public ChoiceGroup(String label, int choiceType, String[] stringElements, Image[] imageElements) { this(label, choiceType, stringElements, imageElements, false); } /** * Special constructor used by List * * @param label the item's label (see {@link Item Item}) * @param choiceType EXCLUSIVE or MULTIPLE * @param stringElements set of strings specifying the string parts of the * ChoiceGroup elements * @param imageElements set of images specifying the image parts of * the ChoiceGroup elements * @param implicitAllowed Flag to allow implicit selection * * @throws NullPointerException if stringElements is null * @throws NullPointerException if the stringElements array contains * any null elements * @throws IllegalArgumentException if the imageElements array is non-null * and has a different length from the stringElements array * @throws IllegalArgumentException if choiceType is neither * EXCLUSIVE nor MULTIPLE * @throws IllegalArgumentException if any image in the imageElements * array is mutable * * @see Choice#EXCLUSIVE * @see Choice#MULTIPLE * @see Choice#IMPLICIT */ ChoiceGroup(String label, int choiceType, String[] stringElements, Image[] imageElements, boolean implicitAllowed) { super(label); if (!((choiceType == Choice.MULTIPLE) || (choiceType == Choice.EXCLUSIVE) || ((choiceType == Choice.IMPLICIT) && implicitAllowed) || (choiceType == Choice.POPUP))) { throw new IllegalArgumentException(); } // If stringElements is null NullPointerException will be thrown // as expected for (int x = 0; x < stringElements.length; x++) { if (stringElements[x] == null) { throw new NullPointerException(); } } if (imageElements != null) { if (stringElements.length != imageElements.length) { throw new IllegalArgumentException(); } } synchronized (Display.LCDUILock) { this.choiceType = choiceType; numOfEls = stringElements.length; cgElements = new CGElement[numOfEls + GROW_FACTOR]; if (imageElements != null) { for (int i = 0; i < numOfEls; i++) { cgElements[i] = new CGElement(stringElements[i], imageElements[i]); } } else { for (int i = 0; i < numOfEls; i++) { cgElements[i] = new CGElement(stringElements[i], null /* image */); } } itemLF = choiceGroupLF = LFFactory.getFactory().getChoiceGroupLF(this); // initialize fonts to default one in all elements; // this has to be done after ChoiceGroupLF is created for (int i = 0; i < numOfEls; i++) { cgElements[i].setFont(null); } } // synchronized } /** * Returns the number of elements in the <code>ChoiceGroup</code>. * @return the number of elements in the <code>ChoiceGroup</code> */ public int size() { // SYNC NOTE: return of atomic value, no locking necessary return numOfEls; } /** * 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) { synchronized (Display.LCDUILock) { checkIndex(elementNum); // return stringEls[elementNum]; return cgElements[elementNum].stringEl; } } /** * 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 null if there is no image * @throws IndexOutOfBoundsException if elementNum is invalid * @see #getString(int) */ public Image getImage(int elementNum) { synchronized (Display.LCDUILock) { checkIndex(elementNum); // return as mutable, if possible return (cgElements[elementNum].mutableImageEl == null ? cgElements[elementNum].imageEl : cgElements[elementNum].mutableImageEl); } } /** * Appends an element to the <code>ChoiceGroup</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) { int elementNum = -1; synchronized (Display.LCDUILock) { checkNull(stringPart); if ((elementNum = insertImpl(numOfEls, stringPart, imagePart)) >= 0) { choiceGroupLF.lInsert(elementNum, stringPart, imagePart); } } return elementNum; } /** * Inserts an element into the <code>ChoiceGroup</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) { synchronized (Display.LCDUILock) { if (elementNum < 0 || elementNum > numOfEls) { throw new IndexOutOfBoundsException(); } checkNull(stringPart); if (insertImpl(elementNum, stringPart, imagePart) >= 0) { choiceGroupLF.lInsert(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) { synchronized (Display.LCDUILock) { checkIndex(elementNum); --numOfEls; // setup new elements array if (elementNum != numOfEls) { System.arraycopy(cgElements, elementNum + 1, cgElements, elementNum, numOfEls - elementNum); } // free some memory... (efficient for very large arrays) if (cgElements.length > (GROW_FACTOR * 10) && cgElements.length / numOfEls >= 2) { CGElement[] newArray = new CGElement[numOfEls + GROW_FACTOR]; System.arraycopy(cgElements, 0, newArray, 0, numOfEls); cgElements = newArray; newArray = null; } cgElements[numOfEls] = null; // notify l&f choiceGroupLF.lDelete(elementNum); } // synchronized } /** * Deletes all elements from this <code>ChoiceGroup</code>. */ public void deleteAll() { synchronized (Display.LCDUILock) { cgElements = new CGElement[GROW_FACTOR]; // initial size numOfEls = 0; choiceGroupLF.lDeleteAll(); } } /** * 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) { synchronized (Display.LCDUILock) { checkIndex(elementNum); checkNull(stringPart); cgElements[elementNum].set(stringPart, imagePart); choiceGroupLF.lSet(elementNum, stringPart, imagePart); } } /** * Gets a boolean value indicating whether this element is selected. * * @param elementNum the index of the element to be queried * * @return selection state of the element * * @throws IndexOutOfBoundsException if <code>elementNum</code> is invalid */ public boolean isSelected(int elementNum) { synchronized (Display.LCDUILock) { checkIndex(elementNum); return choiceGroupLF.lIsSelected(elementNum); } } /** * Returns the index number of an element in the * <code>ChoiceGroup</code> that is * selected. For <code>ChoiceGroup</code> objects of type * <code>EXCLUSIVE</code> and <code>POPUP</code> * there is at most one element selected, so * this method is useful for determining the user's choice. * Returns <code>-1</code> if * there are no elements in the <code>ChoiceGroup</code>. * * <p>For <code>ChoiceGroup</code> objects of type * <code>MULTIPLE</code>, this always * returns <code>-1</code> because no * single value can in general represent the state of such a * <code>ChoiceGroup</code>. * To get the complete state of a <code>MULTIPLE</code> * <code>Choice</code>, see {@link * #getSelectedFlags getSelectedFlags}.</p> * * @return index of selected element, or <code>-1</code> if none * @see #setSelectedIndex */ public int getSelectedIndex() { synchronized (Display.LCDUILock) { return choiceGroupLF.lGetSelectedIndex(); } } /** * Queries the state of a <code>ChoiceGroup</code> and returns the state of * all elements in the * boolean array * <code>selectedArray_return</code>. <strong>Note:</strong> this * is a result parameter. * It must be at least as long as the size * of the <code>ChoiceGroup</code> as returned by <code>size()</code>. * If the array is longer, the extra * elements are set to <code>false</code>. * * <p>For <code>ChoiceGroup</code> objects of type * <code>MULTIPLE</code>, any * number of elements may be selected and set to true in the result * array. For <code>ChoiceGroup</code> objects of type * <code>EXCLUSIVE</code> and <code>POPUP</code> * exactly one element will be selected, unless there are * zero elements in the <code>ChoiceGroup</code>. </p> * * @return the number of selected elements in the <code>ChoiceGroup</code> * * @param selectedArray_return array to contain the results * @throws IllegalArgumentException if <code>selectedArray_return</code> * is shorter than the size of the <code>ChoiceGroup</code> * @throws NullPointerException if <code>selectedArray_return</code> * is null * @see #setSelectedFlags */ public int getSelectedFlags(boolean[] selectedArray_return) { checkFlag(selectedArray_return); synchronized (Display.LCDUILock) { int numSelected = 0; if (numOfEls > 0) { numSelected = choiceGroupLF.lGetSelectedFlags(selectedArray_return); } for (int i = numOfEls; i < selectedArray_return.length; i++) { selectedArray_return[i] = false; } return numSelected; } } /** * For <code>ChoiceGroup</code> objects of type * <code>MULTIPLE</code>, this simply sets an * individual element's selected state. * * <P>For <code>ChoiceGroup</code> objects of type * <code>EXCLUSIVE</code> and <code>POPUP</code>, this can be used only to * select an element. That is, the <code> selected </code> parameter must * be <code> true </code>. When an element is selected, the previously * selected element is deselected. If <code> selected </code> is <code> * false </code>, this call is ignored.</P> * * <p>For both list types, the <code>elementNum</code> parameter * must be within * the range * <code>[0..size()-1]</code>, inclusive. </p> * * @param elementNum the number of the element. Indexing of the * elements is zero-based * @param selected the new state of the element <code>true=selected</code>, * <code>false=not</code> selected * @throws IndexOutOfBoundsException if <code>elementNum</code> is invalid * @see #getSelectedIndex */ public void setSelectedIndex(int elementNum, boolean selected) { checkIndex(elementNum); synchronized (Display.LCDUILock) { choiceGroupLF.lSetSelectedIndex(elementNum, selected); } // synchronized } /** * Attempts to set the selected state of every element in the * <code>ChoiceGroup</code>. The array * must be at least as long as the size of the * <code>ChoiceGroup</code>. If the array is * longer, the additional values are ignored. <p> * * For <code>ChoiceGroup</code> objects of type * <code>MULTIPLE</code>, this sets the selected * state of every * element in the <code>Choice</code>. An arbitrary number of * elements may be selected. * <p> * * For <code>ChoiceGroup</code> objects of type * <code>EXCLUSIVE</code> and <code>POPUP</code>, exactly one array * element must have the value <code>true</code>. If no element is * <code>true</code>, * the first element * in the <code>Choice</code> will be selected. If two or more * elements are <code>true</code>, the * implementation will choose the first <code>true</code> element * and select it. <p> * * @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>ChoiceGroup</code> * @throws NullPointerException if the <code>selectedArray</code> * is <code>null</code> * @see #getSelectedFlags */ public void setSelectedFlags(boolean[] selectedArray) { synchronized (Display.LCDUILock) { checkFlag(selectedArray); if (numOfEls == 0) { return; } if (choiceType == Choice.MULTIPLE) { for (int i = 0; i < numOfEls; i++) { cgElements[i].setSelected(selectedArray[i]); } choiceGroupLF.lSetSelectedFlags(selectedArray); } else { for (int i = 0; i < numOfEls; i++) { if (selectedArray[i]) { choiceGroupLF.lSetSelectedIndex(i, true); return; } } choiceGroupLF.lSetSelectedIndex(0, true); } } // synchronized } /** * 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) { if (fitPolicy < TEXT_WRAP_DEFAULT || fitPolicy > TEXT_WRAP_OFF) { throw new IllegalArgumentException(); } synchronized (Display.LCDUILock) { if (this.fitPolicy != fitPolicy) { this.fitPolicy = fitPolicy; choiceGroupLF.lSetFitPolicy(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() { // SYNC NOTE: return of atomic value, no locking necessary return fitPolicy; } /** * 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) { synchronized (Display.LCDUILock) { checkIndex(elementNum); cgElements[elementNum].setFont(font); choiceGroupLF.lSetFont(elementNum, cgElements[elementNum].getFont()); } } /** * 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) { synchronized (Display.LCDUILock) { checkIndex(elementNum); return cgElements[elementNum].getFont(); } } // *********************************************************** // package private // *********************************************************** /** * Return whether the Item takes user input focus. * * @return return <code>true</code> if contents is not null or have * abstract commands. */ boolean acceptFocus() { return super.acceptFocus() || numOfEls > 0; } // *********************************************************** // private // *********************************************************** /** * Insert a particular element of this ChoiceGroup * * @param elementNum The index to insert the element * @param stringPart The string part of the element to insert * @param imagePart The image part of the element to insert * @return int The index of the newly inserted element */ private int insertImpl(int elementNum, String stringPart, Image imagePart) { // cgElements is created in the constructor and cannot be null // full capacity reached if (numOfEls == cgElements.length) { CGElement[] newCGEls = new CGElement[numOfEls + GROW_FACTOR]; System.arraycopy(cgElements, 0, newCGEls, 0, elementNum); System.arraycopy(cgElements, elementNum, newCGEls, elementNum + 1, numOfEls - elementNum); cgElements = newCGEls; // swap them } else if (elementNum != numOfEls) { // if we're not appending System.arraycopy(cgElements, elementNum, cgElements, elementNum + 1, numOfEls - elementNum); } numOfEls++; cgElements[elementNum] = new CGElement(stringPart, imagePart); return elementNum; } /** * Check the validity of a given element index * * @param elementNum The index to check * @throws IndexOutOfBoundsException If no element exists at the * that index */ private void checkIndex(int elementNum) { if (elementNum < 0 || elementNum >= numOfEls) { throw new IndexOutOfBoundsException(); } } /** * Check the given values for null. * * @param stringPart The string part of the element * @throws NullPointerException If the string part is null */ private void checkNull(String stringPart) { if (stringPart == null) { throw new NullPointerException(); } } /** * Check the validity of the selection array * * @param flag The array of boolean flags representing the * selected state of the elements * @throws NullPointerException If the flag array is null * @throws IllegalArgumentException If the flag array is not * the same size as the element array */ private void checkFlag(boolean[] flag) { if (flag == null) { throw new NullPointerException(); } if (flag.length < numOfEls) { throw new IllegalArgumentException(); } } /** * The look&feel associated with this ChoiceGroup. * Set in the constructor. */ ChoiceGroupLF choiceGroupLF; // = null /** * The type of this ChoiceGroup */ int choiceType; /** * The string fit policy for this ChoiceGroup * '0' by default, which is Choice.TEXT_WRAP_DEFAULT */ int fitPolicy; /* * NOTE: If this is a POPUP choice group, regardless of * the set fit policy the system will behave as though * fitPolicy == Choice.TEXT_WRAP_OFF. Popup choice elements * will never wrap, and may be truncated. */ /** * The number of elements in this ChoiceGroup */ int numOfEls; /** * The array containing the Font of each element (null if no setFont() * method was ever called). If fontEls is non-null, only the elements * which were set by setFont() are non-null. */ // see class on the bottom of this file CGElement[] cgElements; /** * Optimization for CGElement array size management. * Notice that cgElements.length is not equal to numOfEls. * Use numOfEls only when accessing the array. */ static final int GROW_FACTOR = 4; /** * Helper method, used solely by the native method * call: updatePopupElements() * @return an array of string elements */ String[] getStringElements() { String[] ret = new String[numOfEls]; for (int i = 0; i < numOfEls; i++) { ret[i] = cgElements[i].stringEl; } return ret; } /** * Helper method, used solely by the native method * call: updatePopupElements() * @return an array of image elements */ Image[] getImageElements() { Image[] ret = new Image[numOfEls]; for (int i = 0; i < numOfEls; i++) { ret[i] = cgElements[i].imageEl; } return ret; } /** * Class that groups information about a single ChoiceGroup element * (such as its string, image, font). It also contains current state * information like selection. */ class CGElement { /** * Creates CGElement * @param str - the string to be used for this ChoiceGroup element * @param img - the image to be used for this ChoiceGroup element */ CGElement(String str, Image img) { set(str, img); // If CGElement is created from ChoiceGroup constructor // choiceGroupLF is not yet created there if (choiceGroupLF != null) { fontEl = choiceGroupLF.getDefaultFont(); } } /** * Sets the string and image. * @param str - the string to be used for this ChoiceGroup element * @param img - the image to be used for this ChoiceGroup element */ void set(String str, Image img) { stringEl = str; if (img != null && img.isMutable()) { // Save original, mutable Image mutableImageEl = img; // Create a snapshot for display imageEl = Image.createImage(img); } else { // Save the immutable image for display imageEl = img; mutableImageEl = null; } if (imageEl != null) { imageDataEl = imageEl.getImageData(); } } /** * Set the selection. * @param sel the selection */ void setSelected(boolean sel) { selected = sel; } /** * Returns the font that was set by the application. * If it was set to null or was unset, null will be returned. * @return the font */ Font getFont() { return fontEl; } /** * Sets the font. * @param f - the font to set. */ void setFont(Font f) { if (f == null) { f = choiceGroupLF.getDefaultFont(); } fontEl = f; } /** * Needed for CGElementLFImpl * @return boolean indicating whether text wrap is on or off */ boolean isWrap() { return (fitPolicy == TEXT_WRAP_OFF); } /** String portion of this ChoiceGroup element */ String stringEl; // = null; /** Image portion of this ChoiceGroup element (non-mutable) */ Image imageEl; // = null; /** Image portion of this ChoiceGroup element (if mutable) */ Image mutableImageEl; // = null; /** ImageData portion of this ChoiceGroup element (non-mutable) */ private ImageData imageDataEl; // = null; /** Selected state of this ChoiceGroup element */ boolean selected; // = false; /** * Font to be used for rendering this ChoiceGroup element. * It should be null if setFont() was * not called for this element. */ private Font fontEl; // = null; } }