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

ChoiceGroup

public class ChoiceGroup extends Item implements Choice
A ChoiceGroup 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.

Note: most of the essential methods have been specified in the {@link Choice Choice} interface.

since
MIDP 1.0

Fields Summary
boolean
isList
If a List is using this ChoiceGroup, it will set isList to true
private int
choiceType
The type of this ChoiceGroup
private int
fitPolicy
The string fit policy for this ChoiceGroup '0' by default, which is Choice.TEXT_WRAP_DEFAULT
private int
numOfEls
The number of elements in this ChoiceGroup
private int
selectedIndex
The currently selected index of this ChoiceGroup (-1 by default)
private int
hilightedIndex
The currently highlighted index of this ChoiceGroup (-1 by default)
private boolean[]
selEls
The array of selected elements of this ChoiceGroup (in the case of a multi-select type)
private String[]
stringEls
The array containing the String parts of each element
private Image[]
imageEls
The array containing the Image parts of each element (null unless there are Image parts)
private Image[]
mutableImageEls
The array containing mutable Image parts of each element (null unless there are mutable Image parts)
private Font[]
fontEls
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.
private int[]
elHeights
The array containing the individual heights of each element, based on the preferred layout width
private int
cachedWidth
The cachedWidth is the width used to calculate the height of each element. If a different width is passed into paint(), we need to recalculate the heights of the elements.
private static final int
DEFAULT_WIDTH
By default, a ChoiceGroup is 80 pixels wide
private boolean
popUpOpen
The state of the popup ChoiceGroup (false by default)
private boolean
traversedIn
A flag indicating if traversal has occurred into this CG on a prior callTraverse. Its reset to false again in callTraverseOut().
private DisplayManager
displayManager
The DisplayManager object handling the display events. Used to suspend/resume display updates when an open popup choice group is on screen.
private int
maxPopupWidth
Max width of requested popup menu
private static final int
PU_WIN_HEIGHT
The default height for the popup window for a popup choice, 130 pixels by default
private static final Image
CKBX_OFF_IMG
Image to represent an unselected checkbox
private static final Image
CKBX_ON_IMG
Image to represent a selected checkbox
private static final int
CKBX_WIDTH
Width of a checkbox image (both selected and unselected)
private static final int
CKBX_HEIGHT
Height of a checkbox image (both selected and unselected)
private static final Image
RD_OFF_IMG
Image to represent an unselected radio button
private static final Image
RD_ON_IMG
Image to represent a selected radio button
private static final int
RD_WIDTH
Width of a radio button image (both selected and unselected)
private static final int
RD_HEIGHT
Height of a radio button image (both selected and unselected)
private static final Image
POPUP_ARROW_IMG
Image to represent a popup arrow
private static final int
POPUP_AR_WIDTH
Width of the popup arrow image
private static final int
POPUP_AR_HEIGHT
Height of popup arrow image
static final int
PREFERRED_IMG_W
The preferred image width for an image as part of an element of a choice (12 pixels).
static final int
PREFERRED_IMG_H
The preferred image height for an image as part of an element of a choice (12 pixels).
Constructors Summary
public ChoiceGroup(String label, int choiceType)
Creates a new, empty ChoiceGroup, specifying its title and its type. The type must be one of EXCLUSIVE, MULTIPLE, or POPUP. The IMPLICIT choice type is not allowed within a ChoiceGroup.

param
label the item's label (see {@link Item Item})
param
choiceType EXCLUSIVE, MULTIPLE, or POPUP
throws
IllegalArgumentException if choiceType is not one of EXCLUSIVE, MULTIPLE, or POPUP
see
Choice#EXCLUSIVE
see
Choice#MULTIPLE
see
Choice#IMPLICIT
see
Choice#POPUP


                                                                            
         
        this(label, choiceType, new String[] {}, null);
    
public ChoiceGroup(String label, int choiceType, String[] stringElements, Image[] imageElements)
Creates a new ChoiceGroup, specifying its title, the type of the ChoiceGroup, and an array of Strings and Images to be used as its initial contents.

The type must be one of EXCLUSIVE, MULTIPLE, or POPUP. The IMPLICIT type is not allowed for ChoiceGroup.

The stringElements array must be non-null and every array element must also be non-null. The length of the stringElements array determines the number of elements in the ChoiceGroup. The imageElements array may be null to indicate that the ChoiceGroup elements have no images. If the imageElements array is non-null, it must be the same length as the stringElements array. Individual elements of the imageElements array may be null in order to indicate the absence of an image for the corresponding ChoiceGroup element. Non-null elements of the imageElements array may refer to mutable or immutable images.

param
label the item's label (see {@link Item Item})
param
choiceType EXCLUSIVE, MULTIPLE, or POPUP
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
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 not one of EXCLUSIVE, MULTIPLE, or POPUP
see
Choice#EXCLUSIVE
see
Choice#MULTIPLE
see
Choice#IMPLICIT
see
Choice#POPUP


        this(label, choiceType, stringElements, imageElements, false);
    
ChoiceGroup(String label, int choiceType, String[] stringElements, Image[] imageElements, boolean implicitAllowed)
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


        super(label);
        
        if (displayManager == null) {
            displayManager = DisplayManagerFactory.getDisplayManager();
        }

        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;

            switch (choiceType) {
                case Choice.MULTIPLE:
                    selEls = new boolean[numOfEls];
                    for (int i = 0; i < numOfEls; i++) {
                        selEls[i] = false;
                    }
                    break;
                case Choice.POPUP:
                case Choice.IMPLICIT:
                case Choice.EXCLUSIVE:
                    if (numOfEls > 0) {
                        selectedIndex = 0;
                    }
                    break;
            }

            stringEls = new String[numOfEls];
            System.arraycopy(stringElements, 0, stringEls, 0, numOfEls);

            if (imageElements != null) {
                imageEls        = new Image[numOfEls];
                mutableImageEls = new Image[numOfEls];

                // Need to check each and every Image to see if it's mutable
                for (int i = 0; i < numOfEls; i++) {
                    if (imageElements[i] != null &&
                        imageElements[i].isMutable()) {
                        // Save original, mutable Image
                        mutableImageEls[i] = imageElements[i];
                        // Create a snapshot for display
                        imageEls[i] = Image.createImage(imageElements[i]);
                    } else {
                        // Save the immutable image for display
                        imageEls[i] = imageElements[i];
                    }
                }
            }
            hilightedIndex = 0;
        } // synchronized
    
Methods Summary
public intappend(java.lang.String stringPart, Image imagePart)
Appends an element to the ChoiceGroup.

param
stringPart the string part of the element to be added
param
imagePart the image part of the element to be added, or null if there is no image part
return
the assigned index of the element
throws
NullPointerException if stringPart is null

        int returnVal = -1;

        synchronized (Display.LCDUILock) {
            checkNull(stringPart, imagePart);
            returnVal = insertImpl(numOfEls, stringPart, imagePart);
        }
        return returnVal;
    
private intcalculateElementHeight(int width)
Get the total element height of this CGroup

param
width the desired width for this CG
return
the total element height


        // we cache the width we calculated the heights for
        cachedWidth = width;

        int eHeight = 0;
        if (elHeights == null || elHeights.length < numOfEls) {
            elHeights = new int[numOfEls];
        }
        int textOffset = 0;

        Font fnt;

        for (int x = 0; x < numOfEls; x++) {
            if (imageEls == null || imageEls[x] == null) {
                textOffset = 0;
            } else {
                textOffset = PREFERRED_IMG_W + LABEL_PAD;
            }

            if (fontEls == null || fontEls[x] == null) {
                fnt = Screen.CONTENT_FONT;
            } else {
                fnt = fontEls[x];
            }

            if (fitPolicy == TEXT_WRAP_OFF || choiceType == Choice.POPUP) {
                elHeights[x] = fnt.getHeight();
            } else {
                elHeights[x] = Text.getHeightForWidth(stringEls[x], fnt,
                                                      width, textOffset);
            }
            eHeight += elHeights[x];
        }
        return eHeight;
    
voidcallKeyPressed(int keyCode)
Handle a key press event

param
keyCode the key which was pressed

        if (keyCode != Display.KEYCODE_SELECT
            || numOfEls == 0) {
            return;
        }
        switch (choiceType) {
        case Choice.POPUP:
            if (!popUpOpen) {
                displayManager.suspendPainting();
                int lW = getLabelWidth();
                boolean tickerflag = false;
                boolean titleflag = false;
                if (owner.getTicker() != null) {
                    tickerflag = true;
                }
                if (owner.getTitle() != null) {
                    titleflag = true;
                }
                updatePopupElements(stringEls, imageEls, numOfEls,
                                    selectedIndex,
                                    bounds[X] + owner.viewport[X] - 
                                    owner.view[X] + lW,
                                    bounds[Y] + owner.viewport[Y] -
                                    owner.view[Y], 
                                    owner.viewport[WIDTH],
                                    owner.viewport[HEIGHT], 
				    maxPopupWidth,
                                    tickerflag, titleflag);
                popUpOpen = !popUpOpen;
            } else {
                displayManager.resumePainting();
                popUpOpen = !popUpOpen;
                int selected = getPopupSelection();
                if (selected >= 0) {
                    hilightedIndex = selected;
                    setSelectedIndexImpl(hilightedIndex, true);
                    owner.itemStateChanged(this);
                }
                invalidate();
            }
            break;
        case Choice.EXCLUSIVE:
            if (hilightedIndex == selectedIndex) {
                return;
            }
            setSelectedIndexImpl(hilightedIndex, true);
            owner.itemStateChanged(this);
            break;
        case Choice.MULTIPLE:
            setSelectedIndexImpl(hilightedIndex, !selEls[hilightedIndex]);
            owner.itemStateChanged(this);
            break;
        default:
            break;
        }
    
intcallMinimumHeight()
Get the minimum height of this Item

return
the minimum height

        return callPreferredHeight(callMinimumWidth());
    
intcallMinimumWidth()
Get the minimum width of this Item

return
the minimum width


        int lW = getLabelWidth();
	
        if (lW == 0 && numOfEls == 0) {
            return 0;
        }
	
        if ((layout == Item.LAYOUT_DEFAULT) || (equateNLB() && equateNLA())) {
            if (owner != null) {
                return ((Form)owner).getWidth();
            }
            return Item.DEFAULT_WIDTH;
        }
	
        // Find the widest element and then base our width on that
        int textOffset = 0;
        int w = 0;
        int maxElWidth = 0;
        Font fnt;
	
        int grWidth = 0;
        if (choiceType == Choice.EXCLUSIVE) {
            grWidth = RD_WIDTH + LABEL_PAD;
        } else if (choiceType == Choice.MULTIPLE) {
            grWidth = CKBX_WIDTH + LABEL_PAD;
        }
       
        for (int i = 0; i < numOfEls; i++) {
            w = (imageEls == null || imageEls[i] == null) ? 
                 0 : PREFERRED_IMG_W + LABEL_PAD;

            if (stringEls[i] != null && stringEls[i].length() > 0) {

                textOffset = w;

                if (fontEls != null && fontEls[i] != null) {
                    fnt = fontEls[i];
                } else {
                    fnt = Screen.CONTENT_FONT;
                }

		if (choiceType != Choice.POPUP) {
		    w = Text.getWidestLineWidth(stringEls[i].toCharArray(), 
						textOffset, 
						DEFAULT_WIDTH - grWidth, 
						fnt);
		} else {
		    w = Text.getWidestLineWidth(stringEls[i].toCharArray(),
						textOffset, 
						DEFAULT_WIDTH * 2, fnt);
		}			

                if (w > maxElWidth) {
                    maxElWidth = w;
                }
            }
        }
        
        w = lW;

        if (choiceType == Choice.POPUP) {

            if (w > 0) {
                w += LABEL_PAD;
            }

            w += POPUP_AR_WIDTH + LABEL_PAD + maxElWidth;

	    maxPopupWidth = maxElWidth; 
            return (w > Item.DEFAULT_WIDTH ? Item.DEFAULT_WIDTH : w);
        } 

        if (w  < grWidth + maxElWidth) {
            // minimum required width is the maximum of the label width and
            // of the widest element width
            w = grWidth + maxElWidth;
        }
        return (w < DEFAULT_WIDTH ? w : DEFAULT_WIDTH);
    
voidcallPaint(Graphics g, int w, int h)
Paint this ChoiceGroup

param
g the Graphics to paint to
param
w the width to paint
param
h the height to paint

        int labelHeight = super.paintLabel(g, w);

        // If its an empty ChoiceGroup, just return
        if (numOfEls == 0 && choiceType != Choice.POPUP) {
            return;
        }
        int translatedX = 0;
        int translatedY = 0;

        if (choiceType == Choice.POPUP) {
            // paint closed state of the popup
            
            if (labelHeight > LABEL_HEIGHT) {
                // translatedX = 0;
                translatedY = labelHeight;
            } else {
                translatedX = getLabelWidth();
                translatedX = (translatedX > 0) ? translatedX + LABEL_PAD : 0;
                // translatedY = 0;
            }

            g.drawImage(POPUP_ARROW_IMG, translatedX, translatedY,
                        Graphics.LEFT | Graphics.TOP);

            if (numOfEls == 0) {
                return;
            }

            translatedX += (POPUP_AR_WIDTH + LABEL_PAD);

            if (imageEls != null && imageEls[selectedIndex] != null) {
                int iX = g.getClipX();
                int iY = g.getClipY();
                int iW = g.getClipWidth();
                int iH = g.getClipHeight();

                g.clipRect(translatedX, translatedY, 
                             PREFERRED_IMG_W, PREFERRED_IMG_H);
                g.drawImage(imageEls[selectedIndex], translatedX, translatedY,
                            Graphics.LEFT | Graphics.TOP);
                g.setClip(iX, iY, iW, iH);
            }

            int elWidth = w;
            if (elWidth != cachedWidth) {
                calculateElementHeight(elWidth);
            }
            elWidth -= POPUP_AR_WIDTH + LABEL_PAD;

            Font fnt;
            if (fontEls != null && fontEls[selectedIndex] != null) {
                fnt = fontEls[selectedIndex];
            } else {
                fnt = Screen.CONTENT_FONT;
            }

            g.translate(translatedX, translatedY);

            int textOffset = 0;
            if (imageEls != null && imageEls[selectedIndex] != null) {
                textOffset = PREFERRED_IMG_W + LABEL_PAD;              
            }

            if (hasFocus) {
                // draw the hilight after drawing the label
                g.fillRect(textOffset, 0,
                           g.getClipWidth() - textOffset,
                           elHeights[selectedIndex]);
                // If there was an offset, we need to fill in the 
                // hilight box under the element's image 

                if (textOffset != 0 && elHeights[selectedIndex] > textOffset) {
                    g.fillRect(0, textOffset, textOffset, 
                               elHeights[selectedIndex] - textOffset); 
                } 
                Text.paint(stringEls[selectedIndex],
                           fnt, g, elWidth,
                           elHeights[selectedIndex], textOffset,
                           (Text.INVERT | Text.TRUNCATE), null);
            } else {
                Text.paint(stringEls[selectedIndex],
                           fnt, g, elWidth,
                           elHeights[selectedIndex], textOffset, 
                           (Text.NORMAL | Text.TRUNCATE), null);
            }
            g.translate(-translatedX, -translatedY);
        } else {
            translatedY = labelHeight;
            if (labelHeight > 0) {
                translatedY += LABEL_PAD;
            }
            g.translate(0, translatedY);
            paintElements(g, w);
            g.translate(0, -translatedY);
        }
    
intcallPreferredHeight(int width)
Get the preferred height of this Item

param
width the desired width for this CG
return
the preferred height

        if (width == -1) {
            width = callPreferredWidth(-1);
        }

        // empty ChoiceGroup is not shown
        if (width == 0) {
            return 0;
        }

        int lH = getLabelHeight(width);

        if (choiceType == Choice.EXCLUSIVE) {
            width -= (RD_WIDTH + LABEL_PAD);
        } else if (choiceType == Choice.MULTIPLE) {
            width -= (CKBX_WIDTH + LABEL_PAD);
        }

        int eHeight = calculateElementHeight(width);

        if (lH == 0) {
            // empty ChoiceGroup is not shown
            if (eHeight == 0) {
                return 0;
            }
        } else {
            lH += LABEL_PAD;
        }

        if (choiceType == Choice.POPUP) {
            if (eHeight > 0) {
                eHeight = elHeights[selectedIndex == -1 ? 0 : selectedIndex];
            }
             
            if (lH <= LABEL_HEIGHT) {
                // single line label
                return (eHeight > LABEL_HEIGHT - LABEL_PAD ? 
                        eHeight : LABEL_HEIGHT);
            }
        }
        return lH + eHeight;
    
intcallPreferredWidth(int h)
Get the preferred width of this Item

param
h the desired height for this CG
return
the preferred width

        // If we're a List, we want to be as wide as possible
        if (isList) {
            return 500;
        }

        return callMinimumWidth();
    
booleancallTraverse(int dir, int viewportWidth, int viewportHeight, int[] visRect)
Handle traversal within this ChoiceGroup

param
dir the direction of traversal
param
viewportWidth the width of the viewport
param
viewportHeight the height of the viewport
param
visRect the in/out rectangle for the internal traversal location
return
True if traversal occurred within this ChoiceGroup


        super.callTraverse(dir, viewportWidth, viewportHeight, visRect);

        // If we have no elements, or if the user pressed left/right,
        // don't bother with the visRect and just return false
        if (numOfEls == 0) {
            return false;
        }

        // If we are a closed popup, don't bother with the visRect
        // and return true on the initial traverse, false on subsequent
        // traverses
        if ((choiceType == Choice.POPUP) && !popUpOpen) {
            if (!traversedIn) {
                traversedIn = true;
                return true;
            } else {
                return false;
            }
        }

        int lh = getLabelHeight(visRect[WIDTH]);
        visRect[Y] = (lh > 0) ? lh + LABEL_PAD : 0;
        for (int i = 0; i < hilightedIndex; i++) {
            visRect[Y] += elHeights[i];
        }
        visRect[HEIGHT] = elHeights[hilightedIndex];

        if (!traversedIn) {
            traversedIn = true;
        } else {
            if (dir == Canvas.UP) {
                if (hilightedIndex > 0) {
                    hilightedIndex--;
                    visRect[Y] -= elHeights[hilightedIndex];
                } else {
                    return popUpOpen;
                }
            } else if (dir == Canvas.DOWN) {
                if (hilightedIndex < (numOfEls - 1)) {
                    visRect[Y] += elHeights[hilightedIndex];
                    hilightedIndex++;
                } else {
                    return popUpOpen;
                }
            } else {
                return popUpOpen;
            }
        }
        visRect[HEIGHT] = elHeights[hilightedIndex];
        if (choiceType == Choice.IMPLICIT) {
            selectedIndex = hilightedIndex;
            // FIX ME: notify listener
        }
        repaint();
        return true;
    
voidcallTraverseOut()
Traverse out of this ChoiceGroup

        super.callTraverseOut();
        traversedIn = false;
    
private voidcheckFlag(boolean[] flag)
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

        if (flag == null) {
            throw new NullPointerException();
        }

        if (flag.length < numOfEls) {
            throw new IllegalArgumentException();
        }
    
private voidcheckIndex(int 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

        if (elementNum < 0 || elementNum >= numOfEls) {
            throw new IndexOutOfBoundsException();
        }
    
private voidcheckNull(java.lang.String stringPart, Image imagePart)
Check the given values for null

param
stringPart The string part of the element
param
imagePart The image part of the element
throws
NullPointerException If the string part is null

        if (stringPart == null) {
            throw new NullPointerException();
        }
    
public voiddelete(int elementNum)
Deletes the element referenced by elementNum.

param
elementNum the index of the element to be deleted
throws
IndexOutOfBoundsException if elementNum is invalid

        synchronized (Display.LCDUILock) {
            checkIndex(elementNum);

            if (elementNum != numOfEls - 1) {

                System.arraycopy(stringEls, elementNum + 1, stringEls,
                                 elementNum, numOfEls - elementNum - 1);

                if (imageEls != null) {
                    // Delete Image snapshot
                    System.arraycopy(imageEls, elementNum + 1, imageEls,
                                     elementNum, numOfEls - elementNum - 1);
                    // Delete mutable Image
                    System.arraycopy(mutableImageEls, elementNum + 1,
                                     mutableImageEls, elementNum,
                                     numOfEls - elementNum - 1);
                }

                if (fontEls != null) {
                    System.arraycopy(fontEls, elementNum + 1, fontEls,
                                     elementNum, numOfEls - elementNum - 1);
                }

                if (choiceType == ChoiceGroup.MULTIPLE) {
                    System.arraycopy(selEls, elementNum + 1, selEls,
                                     elementNum, numOfEls - elementNum - 1);
                }
            }

            if (choiceType == ChoiceGroup.MULTIPLE) {
                selEls[numOfEls - 1] = false;
            }

            --numOfEls;

            stringEls[numOfEls] = null;
            if (imageEls != null) {
                imageEls[numOfEls] = null;
                mutableImageEls[numOfEls] = null;
            }

            if (fontEls != null) {
                fontEls[numOfEls] = null;
            }

            // layouts[--numOfEls] = null;

            if (numOfEls == 0) {
                hilightedIndex = selectedIndex = -1;
            } else {
                // adjust hilighted index
                if (elementNum < hilightedIndex) {
                    hilightedIndex--;
                } else if (elementNum == hilightedIndex &&
                        hilightedIndex == numOfEls) {
                    hilightedIndex = numOfEls - 1;
                }

                // adjust selected index if choiceGroup is not MULTIPLE
                if (choiceType != ChoiceGroup.MULTIPLE) {
                    if (elementNum < selectedIndex) {
                        selectedIndex--;
                    } else if (elementNum == selectedIndex &&
                            selectedIndex == numOfEls) {
                        selectedIndex = numOfEls - 1;
                    }
                }
            }
            invalidate();
        } // synchronized
    
public voiddeleteAll()
Deletes all elements from this ChoiceGroup.

        synchronized (Display.LCDUILock) {
            for (int x = 0; x < numOfEls; x++) {
                stringEls[x] = null;
                if (imageEls != null) {
                    imageEls[x] = null;
                    mutableImageEls[x] = null;
                }
                if (fontEls != null) {
                    fontEls[x] = null;
                }
            }

            numOfEls = 0;
            hilightedIndex = selectedIndex = -1;
            invalidate();
        }
    
booleanequateNLA()
Determine if this Item should have a newline after it

return
true if it should have a newline after

        if (super.equateNLA()) {
            return true;
        }
        return ((layout & Item.LAYOUT_2) != Item.LAYOUT_2);
    
booleanequateNLB()
Determine if this Item should have a newline before it

return
true if it should have a newline before

        if (super.equateNLB()) {
            return true;
        }

        return ((layout & Item.LAYOUT_2) != Item.LAYOUT_2);
    
public intgetFitPolicy()
Gets the application's preferred policy for fitting Choice 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

        // SYNC NOTE: return of atomic value, no locking necessary
        return fitPolicy;
    
public FontgetFont(int elementNum)
Gets the application's preferred font for rendering the specified element of this Choice. 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 null, the value is the default font chosen by the implementation.

The elementNum parameter must be within the range [0..size()-1], inclusive.

param
elementNum the index of the element, starting from zero
return
the preferred font to use to render the element
throws
IndexOutOfBoundsException if elementNum is invalid
see
#setFont(int elementNum, Font font)
since
MIDP 2.0

        synchronized (Display.LCDUILock) {
            checkIndex(elementNum);
            if (fontEls != null && fontEls[elementNum] != null) {
                return fontEls[elementNum];
            } else {
                return Screen.CONTENT_FONT;
            }
        }
    
public ImagegetImage(int elementNum)
Gets the Image part of the element referenced by elementNum.

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)

        synchronized (Display.LCDUILock) {
            checkIndex(elementNum);
            if (imageEls != null) {
                if (mutableImageEls[elementNum] != null) {
                    // This element has a mutable Image
                    return mutableImageEls[elementNum];
                }
                // This element does not have a mutable Image
                return imageEls[elementNum];
            }
            // This element does not have any Image
            return null;
        }
    
private native intgetPopupSelection()
When an open popup choice group closes, this method asks the native data structure for the newly selected choice element.

return
index of selected choice element, or -1 in if the popup choice menu was canceled out of

public intgetSelectedFlags(boolean[] selectedArray_return)
Queries the state of a ChoiceGroup and returns the state of all elements in the boolean array selectedArray_return. Note: this is a result parameter. It must be at least as long as the size of the ChoiceGroup as returned by size(). If the array is longer, the extra elements are set to false.

For ChoiceGroup objects of type MULTIPLE, any number of elements may be selected and set to true in the result array. For ChoiceGroup objects of type EXCLUSIVE and POPUP exactly one element will be selected, unless there are zero elements in the ChoiceGroup.

return
the number of selected elements in the ChoiceGroup
param
selectedArray_return array to contain the results
throws
IllegalArgumentException if selectedArray_return is shorter than the size of the ChoiceGroup
throws
NullPointerException if selectedArray_return is null
see
#setSelectedFlags

        synchronized (Display.LCDUILock) {
            checkFlag(selectedArray_return);
            int selectedNum = 0;
            if (choiceType == Choice.MULTIPLE) {
                System.arraycopy(selEls, 0, selectedArray_return, 0, numOfEls);
                for (int i = 0; i < numOfEls; i++) {
                    if (selEls[i]) selectedNum++;
                }
                for (int i = numOfEls; i < selectedArray_return.length; i++) {
                    selectedArray_return[i] = false;
                }
            } else {
                for (int i = 0; i < selectedArray_return.length; i++) {
                    selectedArray_return[i] = false;
                }
                if (selectedIndex != -1) {
                    selectedArray_return[selectedIndex] = true;
                    selectedNum = 1;
                }
            }
            return selectedNum;
        }
    
public intgetSelectedIndex()
Returns the index number of an element in the ChoiceGroup that is selected. For ChoiceGroup objects of type EXCLUSIVE and POPUP there is at most one element selected, so this method is useful for determining the user's choice. Returns -1 if there are no elements in the ChoiceGroup.

For ChoiceGroup objects of type MULTIPLE, this always returns -1 because no single value can in general represent the state of such a ChoiceGroup. To get the complete state of a MULTIPLE Choice, see {@link #getSelectedFlags getSelectedFlags}.

return
index of selected element, or -1 if none
see
#setSelectedIndex

 
        // SYNC NOTE: return of atomic value, no locking necessary
        return selectedIndex;
    
public java.lang.StringgetString(int elementNum)
Gets the String part of the element referenced by elementNum.

param
elementNum the index of the element to be queried
return
the string part of the element
throws
IndexOutOfBoundsException if elementNum is invalid
see
#getImage(int)

        synchronized (Display.LCDUILock) {
            checkIndex(elementNum);
            return stringEls[elementNum];
        }
    
intgetType()
Get the type of this ChoiceGroup

return
The type of this ChoiceGroup, ie IMPLICIT, EXPLICIT, etc.

        return choiceType;
    
public voidinsert(int elementNum, java.lang.String stringPart, Image imagePart)
Inserts an element into the ChoiceGroup 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 null if there is no image part
throws
IndexOutOfBoundsException if elementNum is invalid
throws
NullPointerException if stringPart is null

        
        synchronized (Display.LCDUILock) {
            if (elementNum < 0 || elementNum > numOfEls) {
                throw new IndexOutOfBoundsException();
            }
            checkNull(stringPart, imagePart);
            insertImpl(elementNum, stringPart, imagePart);
        }
    
private intinsertImpl(int elementNum, java.lang.String stringPart, Image imagePart)
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


        if (numOfEls == stringEls.length) {

            String[] newStrings = new String[stringEls.length + 4];
            System.arraycopy(stringEls, 0, newStrings, 0, elementNum);
            System.arraycopy(stringEls, elementNum, newStrings,
                             elementNum + 1, numOfEls - elementNum);
            stringEls = newStrings;

            if (imageEls != null) {
                Image[] newImages = new Image[imageEls.length + 4];
                Image[] newMutableImages = new Image[imageEls.length + 4];
                System.arraycopy(imageEls, 0, newImages, 0, elementNum);
                System.arraycopy(imageEls, elementNum, newImages,
                                 elementNum + 1, numOfEls - elementNum);
                System.arraycopy(mutableImageEls, 0, newMutableImages, 
                                 0, elementNum);
                System.arraycopy(mutableImageEls, elementNum, newMutableImages,
                                 elementNum + 1, numOfEls - elementNum);
                imageEls = newImages;
                mutableImageEls = newMutableImages;
            }

            if (fontEls != null) {
                Font[] newFonts = new Font[fontEls.length + 4];
                System.arraycopy(fontEls, 0, newFonts, 0, elementNum);
                System.arraycopy(fontEls, elementNum, newFonts,
                                 elementNum + 1, numOfEls - elementNum);
            }

        } else {

            System.arraycopy(stringEls, elementNum, stringEls, elementNum + 1,
                             numOfEls - elementNum);

            if (imageEls != null) {
                System.arraycopy(imageEls, elementNum, imageEls,
                                 elementNum + 1, numOfEls - elementNum);
                System.arraycopy(mutableImageEls, elementNum, mutableImageEls,
                                 elementNum + 1, numOfEls - elementNum);
            }

            if (fontEls != null) {
                System.arraycopy(fontEls, elementNum, fontEls,
                                 elementNum + 1, numOfEls - elementNum);
            }
        }

        if (choiceType == Choice.MULTIPLE) {
            if (selEls.length == numOfEls) {
                boolean newSelEls[] = new boolean[numOfEls + 4];
                System.arraycopy(selEls, 0, newSelEls, 0, elementNum);
                System.arraycopy(selEls, elementNum, newSelEls, elementNum + 1,
                                 numOfEls - elementNum);
                selEls = newSelEls;
            } else {
                System.arraycopy(selEls, elementNum, selEls, elementNum + 1,
                                 numOfEls - elementNum);
            }
            selEls[elementNum] = false;
        }

        stringEls[elementNum] = null;
        if (imageEls != null) {
            imageEls[elementNum] = null;
            mutableImageEls[elementNum] = null;
        }
        if (fontEls != null) {
            fontEls[elementNum] = null;
        }

        numOfEls++;

        if (choiceType != Choice.MULTIPLE &&
                (elementNum < selectedIndex || selectedIndex == -1)) {
            selectedIndex++;
            hilightedIndex = selectedIndex;
        } else if (elementNum < hilightedIndex || hilightedIndex == -1) {
            hilightedIndex++;
        }

        setImpl(elementNum, stringPart, imagePart);

        return elementNum;
    
public booleanisSelected(int elementNum)
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 elementNum is invalid

        synchronized (Display.LCDUILock) {
            checkIndex(elementNum);
            return (choiceType == Choice.MULTIPLE ? selEls[elementNum] :
                                            (selectedIndex == elementNum));
        }
    
private voidpaintElements(Graphics g, int w)
Paint this ChoiceGroup

param
g the Graphics to paint to
param
w the width to paint

        int elWidth = w;
        int textOffset;
        Image img;
        Font fnt;
        int translatedX = 0;
        int translatedY = 0;

        if (choiceType == Choice.EXCLUSIVE) {
            translatedX = RD_WIDTH + LABEL_PAD;
            elWidth -= translatedX;
        } else if (choiceType == Choice.MULTIPLE) {
            translatedX = CKBX_WIDTH + LABEL_PAD;
            elWidth -= translatedX;
        }

        if ((elWidth != cachedWidth) || (elHeights.length != numOfEls)) {
            calculateElementHeight(elWidth);
        }

        // start for
        for (int i = 0; i < numOfEls; i++) {

            if (choiceType == Choice.EXCLUSIVE) {
                img = (i == selectedIndex) ? RD_ON_IMG : RD_OFF_IMG;
            } else if (choiceType == Choice.MULTIPLE) {
                img = (selEls[i]) ? CKBX_ON_IMG : CKBX_OFF_IMG;
            } else {
                img = null;
            }

            if (img != null) {
                g.drawImage(img, 0, 0,
                            Graphics.LEFT | Graphics.TOP);
                // elWidth = w - translatedX;
                g.translate(translatedX, 0);
            }

            textOffset = 0;

            if (imageEls != null && imageEls[i] != null) {
                int iX = g.getClipX();
                int iY = g.getClipY();
                int iW = g.getClipWidth();
                int iH = g.getClipHeight();

                g.clipRect(0, 0, PREFERRED_IMG_W, PREFERRED_IMG_H);
                g.drawImage(imageEls[i], 0, 0,
                            Graphics.LEFT | Graphics.TOP);
                g.setClip(iX, iY, iW, iH);
                textOffset = PREFERRED_IMG_W + LABEL_PAD;
            }

            if (fontEls != null && fontEls[i] != null) {
                fnt = fontEls[i];
            } else {
                fnt = Screen.CONTENT_FONT;
            }

            if (i == hilightedIndex && hasFocus) {
                g.fillRect(textOffset, 0,
                           g.getClipWidth() - translatedX - textOffset,
                           elHeights[i]);
                // If there was an offset, we need to fill in the 
                // hilight box under the element's image 
                if (textOffset != 0 && elHeights[i] > textOffset) { 
                    g.fillRect(0, textOffset, textOffset, 
                               elHeights[i] - textOffset); 
                } 

                Text.paint(stringEls[i], fnt, g, elWidth,
                     elHeights[i], textOffset,
                     ((fitPolicy == Choice.TEXT_WRAP_OFF)
                     ? (Text.INVERT | Text.TRUNCATE) : Text.INVERT), null);
            } else {
                Text.paint(stringEls[i], fnt, g, elWidth,
                     elHeights[i], textOffset,
                     ((fitPolicy == Choice.TEXT_WRAP_OFF)
                     ? (Text.NORMAL | Text.TRUNCATE) : Text.NORMAL), null);
            }

            if (img != null) {
                g.translate(-translatedX, 0);
            }

            g.translate(0, elHeights[i]);
            translatedY += elHeights[i];

        } // end for

        g.translate(0, -translatedY);
    
public voidset(int elementNum, java.lang.String stringPart, Image imagePart)
Sets the String and Image parts of the element referenced by elementNum, 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 null if there is no image part
throws
IndexOutOfBoundsException if elementNum is invalid
throws
NullPointerException if stringPart is null

        synchronized (Display.LCDUILock) {
            checkIndex(elementNum);
            checkNull(stringPart, imagePart);
            setImpl(elementNum, stringPart, imagePart);
        }
    
public voidsetFitPolicy(int fitPolicy)
Sets the application's preferred policy for fitting Choice element contents to the available screen space. The set policy applies for all elements of the Choice 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 fitPolicy is invalid
see
#getFitPolicy
since
MIDP 2.0

        if (fitPolicy < TEXT_WRAP_DEFAULT || fitPolicy > TEXT_WRAP_OFF) {
            throw new IllegalArgumentException();
        }
        synchronized (Display.LCDUILock) {
            if (this.fitPolicy != fitPolicy) {
                this.fitPolicy = fitPolicy;
                invalidate();
            }
        }
    
public voidsetFont(int elementNum, Font font)
Sets the application's preferred font for rendering the specified element of this Choice. An element's font is a hint, and the implementation may disregard the application's preferred font.

The elementNum parameter must be within the range [0..size()-1], inclusive.

The font parameter must be a valid Font object or null. If the font parameter is null, the implementation must use its default font to render the element.

param
elementNum the index of the element, starting from zero
param
font the preferred font to use to render the element
throws
IndexOutOfBoundsException if elementNum is invalid
see
#getFont
since
MIDP 2.0

        synchronized (Display.LCDUILock) {
            checkIndex(elementNum);
            if (fontEls == null) {
                fontEls = new Font[numOfEls];
            }
            fontEls[elementNum] = font;
        }
    
private voidsetImpl(int elementNum, java.lang.String stringPart, Image imagePart)
Set a particular element of this ChoiceGroup

param
elementNum The index of the element to establish
param
stringPart The string part of the element to establish
param
imagePart The image part of the element to establish


        stringEls[elementNum] = stringPart;

        // Create Image storage, if needed
        if ((imagePart != null) && (imageEls == null)) {
            imageEls        = new Image[stringEls.length];
            mutableImageEls = new Image[stringEls.length];
        }

        if (imageEls != null) {
            if ((imagePart != null) && imagePart.isMutable()) {
                // Adding a mutable Image; save it and create a
                // snapshot for display purposes
                mutableImageEls[elementNum] = imagePart;
                imageEls[elementNum] = Image.createImage(imagePart);
            } else {
                // We get here if imagePart is 'null' or if imagePart
                // is not mutable. In either case, the result is the
                // same; set the displayable image to imagePart
                // (whether an Image or 'null', it is the same) and
                // set the mutableImage to 'null'
                mutableImageEls[elementNum] = null;
                imageEls[elementNum] = imagePart;
            }
        }
        invalidate();
    
public voidsetSelectedFlags(boolean[] selectedArray)
Attempts to set the selected state of every element in the ChoiceGroup. The array must be at least as long as the size of the ChoiceGroup. If the array is longer, the additional values are ignored.

For ChoiceGroup objects of type MULTIPLE, this sets the selected state of every element in the Choice. An arbitrary number of elements may be selected.

For ChoiceGroup objects of type EXCLUSIVE and POPUP, exactly one array element must have the value true. If no element is true, the first element in the Choice will be selected. If two or more elements are true, the implementation will choose the first true element and select it.

param
selectedArray an array in which the method collect the selection status
throws
IllegalArgumentException if selectedArray is shorter than the size of the ChoiceGroup
throws
NullPointerException if the selectedArray is null
see
#getSelectedFlags

        synchronized (Display.LCDUILock) {
            checkFlag(selectedArray);
            if (numOfEls == 0) {
                return;
            }
            if (choiceType == Choice.MULTIPLE) {
                System.arraycopy(selectedArray, 0, selEls, 0, numOfEls);
            } else {
                int i = 0;
                for (; i < numOfEls; i++) {
                    if (selectedArray[i]) {
                        break;
                    }
                }
                if (i == numOfEls) {
                    i = 0;
                }
                setSelectedIndexImpl(i, true);
            }
            repaint();
        } // synchronized
    
public voidsetSelectedIndex(int elementNum, boolean selected)
For ChoiceGroup objects of type MULTIPLE, this simply sets an individual element's selected state.

For ChoiceGroup objects of type EXCLUSIVE and POPUP, this can be used only to select an element. That is, the selected parameter must be true . When an element is selected, the previously selected element is deselected. If selected is false , this call is ignored.

For both list types, the elementNum parameter must be within the range [0..size()-1], inclusive.

param
elementNum the number of the element. Indexing of the elements is zero-based
param
selected the new state of the element true=selected, false=not selected
throws
IndexOutOfBoundsException if elementNum is invalid
see
#getSelectedIndex

        synchronized (Display.LCDUILock) {
            setSelectedIndexImpl(elementNum, selected);
        } // synchronized
    
voidsetSelectedIndexImpl(int elementNum, boolean selected)
Set the selected state of the given element index

param
elementNum the index of the element to select
param
selected true if the element should be selected

        checkIndex(elementNum);

        switch (choiceType) {
            case Choice.IMPLICIT:
                // hilight changes as a result of selection only
                // if it is an implicit choice
                if (!selected) {
                    return;
                }
                selectedIndex = elementNum;
                hilightedIndex = elementNum;
                break;
            case Choice.POPUP:
                /* fall through */
            case Choice.EXCLUSIVE:
                // selected item cannot be deselected
                if (selectedIndex == elementNum || !selected) {
                    return;
                }
                selectedIndex = elementNum;
                break;
            case Choice.MULTIPLE:
                selEls[elementNum] = selected;
                break;
        }
        repaint();
    
booleanshouldSkipTraverse()
Determine if Form should not traverse to this ChoiceGroup

return
true if Form should not traverse to this ChoiceGroup

        if ((label == null || label.equals("")) && (numOfEls == 0)) {
            return true;
        }
        return false;
    
public intsize()
Returns the number of elements in the ChoiceGroup.

return
the number of elements in the ChoiceGroup

        // SYNC NOTE: return of atomic value, no locking necessary
        return numOfEls;
    
private native voidupdatePopupElements(java.lang.String[] strings, Image[] images, int numElements, int selectedElem, int xPos, int yPos, int vWidth, int vHeight, int maxWidth, boolean tickerFlag, boolean titleFlag)
Updates the native data structures used to draw a Choice.POPUP type choice group menu.

param
strings array of string elements for the choice group
param
images array of image elements for the choice group (may be null if no choice elements contain images)
param
numElements number of elements in the choice group
param
selectedElem initial element to draw in selected (hilighted)state
param
xPos x coordinate of where the open choice group should attempt to position itself. (the upper right corner of the closed choice group arrow)
param
yPos y coordinate of where the open choice group should attempt to position itself.
param
vWidth width of the viewport
param
vHeight height of the viewport
param
maxWidth width of widest choice group element
param
tickerFlag true if owner has a ticker showing
param
titleFlag true if owner has a title showing