Source code: javax/microedition/lcdui/ChoiceGroup.java
1 /*
2 * MicroEmulator
3 * Copyright (C) 2001 Bartek Teodorczyk <barteo@it.pl>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * Contributor(s):
20 * Shane Harper
21 */
22
23 package javax.microedition.lcdui;
24
25
26 public class ChoiceGroup extends Item implements Choice
27 {
28
29 ChoiceItem items[] = new ChoiceItem[4];
30 int numOfItems = 0;
31
32 int choiceType;
33
34 int highlightedItemIndex = -1;
35
36 static byte multiOff[] = {
37 -119, 80, 78, 71, 13, 10, 26, 10, 0, 0,
38 0, 13, 73, 72, 68, 82, 0, 0, 0, 10,
39 0, 0, 0, 11, 2, 3, 0, 0, 0, 59,
40 0, -12, -117, 0, 0, 0, 6, 80, 76, 84,
41 69, -1, -1, -1, -69, -69, -69, -57, 75, -33,
42 -8, 0, 0, 0, 30, 73, 68, 65, 84, 120,
43 -38, 99, 96, 96, 96, 96, 12, 101, -8, -51,
44 -32, -64, 32, -64, -60, -64, -64, -128, 11, 51,
45 -122, 50, -4, 6, 0, 63, 116, 3, 1, 53,
46 -108, 39, -26, 0, 0, 0, 0, 73, 69, 78,
47 68, -82, 66, 96, -126 };
48
49 static byte multiOn[] = {
50 -119, 80, 78, 71, 13, 10, 26, 10, 0, 0,
51 0, 13, 73, 72, 68, 82, 0, 0, 0, 10,
52 0, 0, 0, 11, 2, 3, 0, 0, 0, 59,
53 0, -12, -117, 0, 0, 0, 12, 80, 76, 84,
54 69, -1, -1, -1, -69, -69, -69, 106, 106, 106,
55 2, 2, 2, 106, -103, 14, -47, 0, 0, 0,
56 53, 73, 68, 65, 84, 120, -38, 99, 96, 96,
57 124, -64, -16, -1, -77, 3, -45, 65, -111, 15,
58 76, 12, 108, 12, 76, 12, -4, 12, 76, 12,
59 18, 12, 76, -68, 127, 24, -104, 126, 45, 96,
60 96, -7, -11, -109, -127, -23, -65, 3, 3, -29,
61 127, -122, -113, 0, 5, 37, 12, -34, 1, -99,
62 -83, 100, 0, 0, 0, 0, 73, 69, 78, 68,
63 -82, 66, 96, -126 };
64
65 static byte radioOff[] = {
66 -119, 80, 78, 71, 13, 10, 26, 10, 0, 0,
67 0, 13, 73, 72, 68, 82, 0, 0, 0, 11,
68 0, 0, 0, 11, 2, 3, 0, 0, 0, -44,
69 -62, -97, -75, 0, 0, 0, 9, 80, 76, 84,
70 69, -1, -1, -1, -69, -69, -69, 106, 106, 106,
71 -44, 13, -1, -24, 0, 0, 0, 42, 73, 68,
72 65, 84, 120, -38, 99, 96, 90, -59, -64, 32,
73 -63, 48, -127, 65, -127, 65, -127, 41, -127, -31,
74 5, 19, 3, 3, 3, 50, 102, 80, 96, 80,
75 96, -6, -63, 80, -64, -64, -76, -118, 1, 0,
76 113, 24, 5, 61, 73, -68, -100, 98, 0, 0,
77 0, 0, 73, 69, 78, 68, -82, 66, 96, -126 };
78
79 static byte radioOn[] = {
80 -119, 80, 78, 71, 13, 10, 26, 10, 0, 0,
81 0, 13, 73, 72, 68, 82, 0, 0, 0, 11,
82 0, 0, 0, 11, 2, 3, 0, 0, 0, -44,
83 -62, -97, -75, 0, 0, 0, 12, 80, 76, 84,
84 69, -1, -1, -1, -69, -69, -69, 106, 106, 106,
85 2, 2, 2, 106, -103, 14, -47, 0, 0, 0,
86 50, 73, 68, 65, 84, 120, -38, 5, -63, 65,
87 13, 0, 32, 12, 4, -63, -19, -11, -117, 1,
88 18, 68, -100, 10, 52, 19, 94, 72, 64, 17,
89 101, -122, 44, -44, -29, 98, -52, 89, 77, -102,
90 40, 2, 85, -95, -73, -63, -104, -63, 37, -117,
91 15, -40, 119, 10, 41, 78, 26, -79, 59, 0,
92 0, 0, 0, 73, 69, 78, 68, -82, 66, 96,
93 -126 };
94
95 private static final Image imgMultiOff = Image.createImage(multiOff, 0, multiOff.length);
96 private static final Image imgMultiOn = Image.createImage(multiOn, 0, multiOn.length);
97 private static final Image imgRadioOff = Image.createImage(radioOff, 0, radioOff.length);
98 private static final Image imgRadioOn = Image.createImage(radioOn, 0, radioOn.length);
99
100
101 public ChoiceGroup(String label, int choiceType)
102 {
103 super(label);
104 this.choiceType = choiceType;
105 }
106
107
108 // XXX imageElements is ignored.
109 public ChoiceGroup(String label, int choiceType, String[] stringElements, Image[] imageElements)
110 {
111 this(label, choiceType);
112
113 for (int i = 0; i < stringElements.length; i++) {
114 if (imageElements == null) {
115 append(stringElements[i], null);
116 } else {
117 append(stringElements[i], imageElements[i]);
118 }
119 }
120 }
121
122
123 public int append(String stringPart, Image imagePart)
124 {
125 insert(numOfItems, stringPart, imagePart);
126
127 return (numOfItems - 1);
128 }
129
130
131 public void delete(int itemNum)
132 {
133 if (itemNum < 0 || itemNum >= numOfItems) {
134 throw new IndexOutOfBoundsException();
135 }
136
137 // Ensure that an item of an EXCLUSIVE list remains selected.
138 if (Choice.EXCLUSIVE == choiceType && items[itemNum].isSelected()) {
139 if (numOfItems > 1) {
140 items[itemNum!=0 ? 0 : 1].setSelectedState(true);
141 }
142 }
143
144 // Delete item.
145 if (itemNum != numOfItems - 1) {
146 System.arraycopy(items, itemNum+1, items, itemNum, numOfItems-itemNum-1);
147 }
148 numOfItems--;
149
150 // Ensure highlighted item remains highlighted (if it wasn't just deleted).
151 if (highlightedItemIndex > itemNum) {
152 --highlightedItemIndex;
153 }
154
155 // Ensure that an item remains highlighted.
156 if (highlightedItemIndex >= numOfItems) {
157 highlightedItemIndex = numOfItems-1;
158 }
159
160 repaint();
161 }
162
163
164 public Image getImage(int elementNum)
165 {
166 if (elementNum < 0 || elementNum >= numOfItems) {
167 throw new IndexOutOfBoundsException();
168 }
169
170 return null;
171 }
172
173
174 /**
175 * Queries the state of a ChoiceGroup and returns the state of all elements in
176 * the boolean array selectedArray_return. NOTE: this is a result parameter.
177 * It must be at least as long as the size of the ChoiceGroup as returned by
178 * size(). If the array is longer, the extra elements are set to false.
179 *
180 * For ChoiceGroup objects of type MULTIPLE, any number of elements may be
181 * selected and set to true in the result array. For ChoiceGroup objects of
182 * type EXCLUSIVE, exactly one element will be selected, unless there are zero
183 * elements in the ChoiceGroup.
184 */
185 public int getSelectedFlags(boolean[] selectedArray_return)
186 {
187 if (selectedArray_return == null) {
188 throw new NullPointerException();
189 }
190 if (selectedArray_return.length < numOfItems) {
191 throw new IllegalArgumentException();
192 }
193
194 // set selectedArray_return elements and count number of selected items
195 int selectedItemsCount = 0;
196 for (int i = 0; i < selectedArray_return.length; ++i) {
197 selectedArray_return[i] = (i<numOfItems) ? items[i].isSelected() : false;
198 if (selectedArray_return[i]) {
199 ++selectedItemsCount;
200 }
201 }
202
203 return selectedItemsCount;
204 }
205
206 /**
207 * Returns the index number of an element in the ChoiceGroup that is
208 * selected. For ChoiceGroup objects of type EXCLUSIVE there is at most one
209 * element selected, so this method is useful for determining the user's
210 * choice. Returns -1 if there are no elements in the ChoiceGroup.
211 *
212 * For ChoiceGroup objects of type MULTIPLE, this always returns -1 because
213 * no single value can in general represent the state of such a ChoiceGroup.
214 * To get the complete state of a MULTIPLE Choice, see getSelectedFlags.
215 */
216 public int getSelectedIndex()
217 {
218 switch (choiceType) {
219 case Choice.EXCLUSIVE:
220 // XXX It'd be nice if the selected item index was stored, so it isn't
221 // necessary to search for it.
222 for (int i = 0; i < numOfItems; ++i) {
223 if (items[i].isSelected()) return i;
224 }
225 break;
226 case Choice.IMPLICIT:
227 return highlightedItemIndex;
228 }
229 return -1;
230 }
231
232
233 public String getString(int elementNum)
234 {
235 if (elementNum < 0 || elementNum >= numOfItems) {
236 throw new IndexOutOfBoundsException();
237 }
238
239 return items[elementNum].getText();
240 }
241
242
243 public void insert(int elementNum, String stringPart, Image imagePart)
244 {
245 if (elementNum < 0 || elementNum > numOfItems) {
246 throw new IndexOutOfBoundsException();
247 }
248 if (imagePart != null && imagePart.isMutable()) {
249 throw new IllegalArgumentException();
250 }
251 if (stringPart == null) {
252 throw new NullPointerException();
253 }
254
255 if (numOfItems == items.length /*no space left in item array*/) {
256 ChoiceItem newItems[] = new ChoiceItem[numOfItems + 4];
257 System.arraycopy(items, 0, newItems, 0, numOfItems);
258 items = newItems;
259 }
260
261 System.arraycopy(items, elementNum, items, elementNum + 1,
262 numOfItems - elementNum);
263
264 items[elementNum] = new ChoiceItem(null, imagePart, stringPart);
265
266 ++numOfItems;
267
268 if (numOfItems == 1) {
269 highlightedItemIndex = 0;
270 if (Choice.EXCLUSIVE == choiceType) {
271 setSelectedIndex(0, true);
272 }
273 }
274
275 repaint();
276 }
277
278
279 public boolean isSelected(int elementNum)
280 {
281 if (elementNum < 0 || elementNum >= numOfItems) {
282 throw new IndexOutOfBoundsException();
283 }
284
285 return items[elementNum].isSelected();
286 }
287
288
289 public void set(int elementNum, String stringPart, Image imagePart)
290 {
291 if (elementNum < 0 || elementNum >= numOfItems) {
292 throw new IndexOutOfBoundsException();
293 }
294 if (imagePart != null && imagePart.isMutable()) {
295 throw new IllegalArgumentException();
296 }
297 if (stringPart == null) {
298 throw new NullPointerException();
299 }
300
301 items[elementNum].setText(stringPart);
302 items[elementNum].setImage(imagePart);
303
304 repaint();
305 }
306
307
308 public void setLabel(String label)
309 {
310 super.setLabel(label);
311 }
312
313
314 public void setSelectedFlags(boolean[] selectedArray)
315 {
316 if (selectedArray == null) {
317 throw new NullPointerException();
318 }
319 if (selectedArray.length < numOfItems) {
320 throw new NullPointerException();
321 }
322
323 if (choiceType == Choice.EXCLUSIVE) {
324 boolean performed = false;
325 for (int i = 0; i < numOfItems; i++) {
326 if (selectedArray[i]) {
327 setSelectedIndex(i, true);
328 performed = true;
329 break;
330 }
331 }
332 if (!performed) {
333 setSelectedIndex(0, true);
334 }
335 } else if (choiceType == Choice.MULTIPLE) {
336 for (int i = 0; i < numOfItems; i++) {
337 setSelectedIndex(i, selectedArray[i]);
338 }
339 }
340 }
341
342
343 public void setSelectedIndex(int elementNum, boolean selected)
344 {
345 if (elementNum < 0 || elementNum >= numOfItems) {
346 throw new IndexOutOfBoundsException();
347 }
348
349 if (choiceType == Choice.EXCLUSIVE && selected) {
350 for (int i = 0; i < numOfItems; i++) {
351 items[i].setSelectedState(elementNum == i);
352 }
353 repaint();
354 } else if (choiceType == Choice.MULTIPLE) {
355 items[elementNum].setSelectedState(selected);
356 repaint();
357 }
358 }
359
360
361 public int size()
362 {
363 return numOfItems;
364 }
365
366
367 boolean isFocusable()
368 {
369 return true;
370 }
371
372
373 int getHeight()
374 {
375 int height = 0;
376 for (int i = 0; i < numOfItems; i++) {
377 height += items[i].getHeight();
378 }
379
380 return super.getHeight() + height;
381 }
382
383
384 int paint(Graphics g)
385 {
386 super.paintContent(g);
387
388 g.translate(0, super.getHeight());
389 int translatedY = 0;
390 for (int i = 0; i < numOfItems; i++) {
391 items[i].invertPaint(i == highlightedItemIndex && hasFocus());
392 items[i].paint(g);
393 g.translate(0, items[i].getHeight());
394 translatedY += items[i].getHeight();
395 }
396 g.translate(0, -translatedY);
397 g.translate(0, -super.getHeight());
398
399 return getHeight();
400 }
401
402
403 boolean select()
404 {
405 if (numOfItems == 0) {
406 return false;
407 }
408
409 // XXX What does the following statement do?
410 setSelectedIndex(highlightedItemIndex, !items[highlightedItemIndex].isSelected());
411
412 return true;
413 }
414
415
416 int traverse(int gameKeyCode, int top, int bottom, boolean action)
417 {
418 if (gameKeyCode == Canvas.UP) {
419 if (highlightedItemIndex > 0) {
420 if (action) {
421 highlightedItemIndex--;
422 }
423 int height = super.getHeight();
424 for (int i = 0; i < highlightedItemIndex; i++) {
425 height += items[i].getHeight();
426 }
427 if (height < top) {
428 return height - top;
429 } else {
430 repaint();
431 }
432 } else {
433 if (top > 0) {
434 return -top;
435 } else {
436 return Item.OUTOFITEM;
437 }
438 }
439 }
440 if (gameKeyCode == Canvas.DOWN) {
441 if ((!action && highlightedItemIndex < numOfItems)
442 || (action && highlightedItemIndex < (numOfItems - 1))) {
443 if (action) {
444 highlightedItemIndex++;
445 }
446 int height = super.getHeight();
447 for (int i = 0; i <= highlightedItemIndex; i++) {
448 height += items[i].getHeight();
449 }
450 if (height > bottom) {
451 return height - bottom;
452 } else {
453 repaint();
454 }
455 } else {
456 return Item.OUTOFITEM;
457 }
458 }
459
460 return 0;
461 }
462
463
464 class ChoiceItem extends ImageStringItem
465 {
466 private boolean selected;
467
468 ChoiceItem(String label, Image image, String text)
469 {
470 super(label, image, text);
471 setSelectedState(false);
472 }
473
474 boolean isSelected()
475 {
476 return selected;
477 }
478
479 void setSelectedState(boolean state)
480 {
481 selected = state;
482
483 if (choiceType != Choice.IMPLICIT) {
484 setImage(Choice.EXCLUSIVE == choiceType ?
485 (state? imgRadioOn:imgRadioOff) : (state? imgMultiOn:imgMultiOff));
486 }
487 }
488 }
489
490 }