001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package javax.microedition.lcdui;
028:
029: import com.sun.midp.configurator.Constants;
030: import javax.microedition.lcdui.ChoiceGroup.CGElement;
031:
032: /**
033: * This is the look and feel implementation for ChoiceGroup.
034: */
035: class ChoiceGroupLFImpl extends ItemLFImpl implements ChoiceGroupLF {
036:
037: /**
038: * Creates ChoiceLF for the passed in ChoiceGroup.
039: * @param choiceGroup - the ChoiceGroup object associated with this view
040: */
041: ChoiceGroupLFImpl(ChoiceGroup choiceGroup) {
042: super (choiceGroup);
043:
044: cg = choiceGroup;
045:
046: if (cg.numOfEls > 0 && cg.choiceType != Choice.MULTIPLE) {
047: selectedIndex = 0;
048: cg.cgElements[selectedIndex].setSelected(true);
049: }
050: }
051:
052: // *******************************************************
053: // ChoiceGroupLF implementation
054: // ********************************************************
055:
056: /**
057: * Notifies Look &s; Feel that an element was inserted into the
058: * <code>ChoiceGroup</code> at the the elementNum specified.
059: *
060: * @param elementNum the index of the element where insertion occurred
061: * @param stringPart the string part of the element to be inserted
062: * @param imagePart the image part of the element to be inserted,
063: * or <code>null</code> if there is no image part
064: */
065: public void lInsert(int elementNum, String stringPart,
066: Image imagePart) {
067: // make sure that there is a default selection
068: if (cg.choiceType != Choice.MULTIPLE) {
069: if (selectedIndex == -1) {
070: selectedIndex = 0;
071: cg.cgElements[selectedIndex].setSelected(true);
072: } else if (elementNum < selectedIndex
073: && nativeId == DisplayableLFImpl.INVALID_NATIVE_ID) {
074: // an element was inserted before selectedIndex and
075: // selectedIndex has to be updated
076: selectedIndex++;
077: }
078: }
079:
080: // Only update native resource if it exists.
081: if (nativeId != DisplayableLFImpl.INVALID_NATIVE_ID) {
082: ImageData imagePartData = null;
083:
084: if (imagePart != null) {
085: imagePartData = imagePart.getImageData();
086: }
087:
088: insert0(nativeId, elementNum, stringPart, imagePartData,
089: cg.cgElements[elementNum].selected);
090: }
091:
092: lRequestInvalidate(true, true);
093: }
094:
095: /**
096: * Notifies Look &s; Feel that an element referenced by
097: * <code>elementNum</code> was deleted in the corresponding
098: * ChoiceGroup.
099: *
100: * @param elementNum the index of the deleted element
101: */
102: public void lDelete(int elementNum) {
103:
104: // adjust selected index
105: if (cg.numOfEls == 0) {
106: selectedIndex = -1;
107: } else if (cg.choiceType != ChoiceGroup.MULTIPLE) {
108: if (nativeId != DisplayableLFImpl.INVALID_NATIVE_ID) {
109: if (selectedIndex != -1 && selectedIndex < cg.numOfEls) {
110: cg.cgElements[selectedIndex].setSelected(false);
111: }
112: selectedIndex = getSelectedIndex0(nativeId);
113: }
114:
115: if (elementNum < selectedIndex) {
116: selectedIndex--;
117: } else if (elementNum == selectedIndex
118: && selectedIndex == cg.numOfEls) {
119: // last element is selected and deleted -
120: // new last should be selected
121: selectedIndex = cg.numOfEls - 1;
122: }
123: cg.cgElements[selectedIndex].setSelected(true);
124: }
125:
126: if (nativeId != DisplayableLFImpl.INVALID_NATIVE_ID) {
127: delete0(nativeId, elementNum, selectedIndex);
128: }
129:
130: lRequestInvalidate(true, true);
131: }
132:
133: /**
134: * Notifies Look &s; Feel that all elements
135: * were deleted in the corresponding ChoiceGroup.
136: */
137: public void lDeleteAll() {
138: // Only update native resource if it exists.
139: if (nativeId != DisplayableLFImpl.INVALID_NATIVE_ID) {
140: deleteAll0(nativeId);
141: }
142: selectedIndex = -1;
143: lRequestInvalidate(true, true);
144: }
145:
146: /**
147: * Notifies Look &s; Fell that the <code>String</code> and
148: * <code>Image</code> parts of the
149: * element referenced by <code>elementNum</code> were set in
150: * the corresponding ChoiceGroup,
151: * replacing the previous contents of the element.
152: *
153: * @param elementNum the index of the element set
154: * @param stringPart the string part of the new element
155: * @param imagePart the image part of the element, or <code>null</code>
156: * if there is no image part
157: */
158: public void lSet(int elementNum, String stringPart, Image imagePart) {
159: // Only update native resource if it exists.
160: if (nativeId != DisplayableLFImpl.INVALID_NATIVE_ID) {
161: ImageData imagePartData = null;
162: if (imagePart != null) {
163: imagePartData = imagePart.getImageData();
164: }
165:
166: // for selected value to be passed correctly to the
167: // newly created element we have to do the sync first
168: // (alternatively we could rely on native to maintain
169: // the selected state correctly)
170: syncSelectedIndex();
171: syncSelectedFlags();
172: set0(nativeId, elementNum, stringPart, imagePartData,
173: cg.cgElements[elementNum].selected);
174: }
175: lRequestInvalidate(true, true);
176: }
177:
178: /**
179: * Notifies Look &s; Feel that an element was selected (or
180: * deselected) in the corresponding ChoiceGroup.
181: *
182: * @param elementNum the number of the element. Indexing of the
183: * elements is zero-based
184: * @param selected the new state of the element <code>true=selected</code>,
185: * <code>false=not</code> selected
186: */
187: public void lSetSelectedIndex(int elementNum, boolean selected) {
188: // Only update native resource if it exists.
189: if (nativeId != DisplayableLFImpl.INVALID_NATIVE_ID) {
190: setSelectedIndex0(nativeId, elementNum, selected);
191: } else {
192: if (cg.choiceType == Choice.MULTIPLE) {
193: cg.cgElements[elementNum].setSelected(selected);
194: } else {
195: // selected item cannot be deselected in
196: // EXCLUSIVE, IMPLICIT, POPUP ChoiceGroup
197: if (!selected || (/* choiceType != Choice.IMPLICIT && */
198: selectedIndex == elementNum)) {
199: return;
200: }
201:
202: cg.cgElements[selectedIndex].setSelected(false);
203: selectedIndex = elementNum;
204: cg.cgElements[selectedIndex].setSelected(true);
205: }
206: }
207: }
208:
209: /**
210: * Notifies Look &s; Feel that selected state was changed on
211: * several elements in the corresponding MULTIPLE ChoiceGroup
212: * (cannot be null).
213: * @param selectedArray an array in which the method collect the
214: * selection status
215: */
216: public void lSetSelectedFlags(boolean[] selectedArray) {
217: // Only update native resource if it exists.
218: if (nativeId != DisplayableLFImpl.INVALID_NATIVE_ID) {
219: setSelectedFlags0(nativeId, selectedArray,
220: selectedArray.length);
221: }
222: }
223:
224: /**
225: * Notifies Look &s; Feel that a new text fit policy was set
226: * in the corresponding ChoiceGroup.
227: * @param fitPolicy preferred content fit policy for choice elements
228: */
229: public void lSetFitPolicy(int fitPolicy) {
230: // Only update native resource if it exists.
231: if (nativeId != DisplayableLFImpl.INVALID_NATIVE_ID) {
232: setFitPolicy0(nativeId, fitPolicy);
233: lRequestInvalidate(true, true);
234: }
235: }
236:
237: /**
238: * Notifies Look &s; Feel that a new font was set for an
239: * element with the specified elementNum in the
240: * corresponding ChoiceGroup.
241: * @param elementNum the index of the element, starting from zero
242: * @param font the preferred font to use to render the element
243: */
244: public void lSetFont(int elementNum, Font font) {
245: // Only update native resource if it exists.
246: if (nativeId != DisplayableLFImpl.INVALID_NATIVE_ID) {
247: setFont0(nativeId, elementNum, font.getFace(), font
248: .getStyle(), font.getSize());
249: lRequestInvalidate(true, true);
250: }
251: }
252:
253: /**
254: * Gets default font to render ChoiceGroup element if it was not
255: * set by the application
256: * @return - the font to render ChoiceGroup element if it was not
257: * set by the app
258: */
259: public Font getDefaultFont() {
260: return Theme.curContentFont;
261: }
262:
263: /**
264: * Gets currently selected index
265: * @return currently selected index
266: */
267: public int lGetSelectedIndex() {
268: if (nativeId == DisplayableLFImpl.INVALID_NATIVE_ID) {
269: return selectedIndex;
270: } else {
271: // sync with native
272: syncSelectedIndex();
273: return selectedIndex;
274: }
275: }
276:
277: /**
278: * Gets selected flags.(only elements corresponding to the
279: * elements are expected to be filled). ChoiceGroup sets the rest to
280: * false
281: * @param selectedArray_return to contain the results
282: * @return the number of selected elements
283: */
284: public int lGetSelectedFlags(boolean[] selectedArray_return) {
285: int countSelected = 0;
286: if (nativeId == DisplayableLFImpl.INVALID_NATIVE_ID) {
287: for (int i = 0; i < cg.numOfEls; i++) {
288: selectedArray_return[i] = cg.cgElements[i].selected;
289: if (selectedArray_return[i]) {
290: countSelected++;
291: }
292: }
293:
294: } else {
295: countSelected = getSelectedFlags0(nativeId,
296: selectedArray_return, cg.numOfEls);
297:
298: // sync with native
299: for (int i = 0; i < cg.numOfEls; i++) {
300: cg.cgElements[i].setSelected(selectedArray_return[i]);
301: }
302: }
303: return countSelected;
304: }
305:
306: /**
307: * Determines if an element with a passed in index
308: * is selected or not.
309: * @param elementNum the index of an element in question
310: * @return true if the element is selected, false - otherwise
311: */
312: public boolean lIsSelected(int elementNum) {
313: if (nativeId == DisplayableLFImpl.INVALID_NATIVE_ID) {
314: return cg.cgElements[elementNum].selected;
315: }
316:
317: return isSelected0(nativeId, elementNum);
318: }
319:
320: // *****************************************************
321: // Package private methods
322: // *****************************************************
323:
324: /**
325: * Called by event delivery to notify an ItemLF in current FormLF
326: * of a change in its peer state.
327: *
328: * @param hint index of the element whose selection status has changed
329: * @return always true so ItemStateListener should be notified
330: */
331: boolean uCallPeerStateChanged(int hint) {
332: // Any hint means selection has change
333: // For types other than IMPLICIT List, notify itemStateListener.
334: if (cg.choiceType != Choice.IMPLICIT) {
335: return true; // notify itemStateListener
336: }
337:
338: // For IMPLICIT List, notify commandListener
339: List list;
340: CommandListener cl;
341: Command cmd;
342:
343: synchronized (Display.LCDUILock) {
344: list = (List) cg.owner;
345:
346: if (list.listener == null || list.selectCommand == null
347: || cg.numOfEls == 0) {
348: return false; // No itemStateListener to notify
349: }
350:
351: cl = list.listener;
352: cmd = list.selectCommand;
353: }
354:
355: try {
356: synchronized (Display.calloutLock) {
357: cl.commandAction(cmd, list);
358: }
359: } catch (Throwable thr) {
360: Display.handleThrowable(thr);
361: }
362:
363: return false; // No itemStateListener to notify
364: }
365:
366: /**
367: * Determine if this Item should have a newline after it
368: *
369: * @return true if it should have a newline after
370: */
371: boolean equateNLA() {
372: if (super .equateNLA()) {
373: return true;
374: }
375: return ((cg.layout & Item.LAYOUT_2) != Item.LAYOUT_2);
376: }
377:
378: /**
379: * Determine if this Item should have a newline before it
380: *
381: * @return true if it should have a newline before
382: */
383: boolean equateNLB() {
384: if (super .equateNLB()) {
385: return true;
386: }
387:
388: return ((cg.layout & Item.LAYOUT_2) != Item.LAYOUT_2);
389: }
390:
391: /**
392: /**
393: * Override <code>ItemLFImpl</code> method to sync with native resource
394: * before hiding the native resource. Selection of native resource will
395: * be preserved before the resource is hidden.
396: */
397: void lHideNativeResource() {
398: // sync selected flags and selectedIndex
399: // before any visible native resource is deleted.
400: if (nativeId != DisplayableLFImpl.INVALID_NATIVE_ID) {
401: syncSelectedIndex();
402: syncSelectedFlags();
403: }
404:
405: // Hide native resource
406: super .lHideNativeResource();
407: }
408:
409: /**
410: * Creates and sets native resource for current ChoiceGroup.
411: * Override function in ItemLFImpl.
412: * @param ownerId Owner screen's native resource id
413: */
414: void createNativeResource(int ownerId) {
415: nativeId = createNativeResource0(ownerId, cg.label,
416: (cg.owner instanceof List ? -1 : cg.layout),
417: cg.choiceType, cg.fitPolicy, cg.cgElements,
418: cg.numOfEls, selectedIndex);
419: }
420:
421: // *****************************************************
422: // Private methods
423: // *****************************************************
424:
425: /**
426: * Read and save user selection from native resource.
427: */
428: private void syncSelectedIndex() {
429: if (cg.choiceType != Choice.MULTIPLE) {
430: int newSelectedIndex = getSelectedIndex0(nativeId);
431: if (selectedIndex != newSelectedIndex) {
432: if (selectedIndex != -1) {
433: cg.cgElements[selectedIndex].setSelected(false);
434: }
435: selectedIndex = newSelectedIndex;
436: if (selectedIndex != -1) {
437: cg.cgElements[selectedIndex].setSelected(true);
438: }
439: }
440: }
441: }
442:
443: /**
444: * Read and save user selection from native resource.
445: */
446: private void syncSelectedFlags() {
447: if (cg.numOfEls > 0 && cg.choiceType == Choice.MULTIPLE) {
448: boolean[] selectedArray_return = new boolean[cg.numOfEls];
449:
450: getSelectedFlags0(nativeId, selectedArray_return,
451: cg.numOfEls);
452:
453: for (int i = 0; i < cg.numOfEls; i++) {
454: cg.cgElements[i].setSelected(selectedArray_return[i]);
455: }
456: }
457: }
458:
459: /**
460: * KNI function that creates native resource for current ChoiceGroup.
461: * @param ownerId Owner screen's native resource id (MidpDisplayable *)
462: * @param label string to be used as label for this ChoiceGroup
463: * @param layout layout directive associated with this <code>Item</code>
464: * @param choiceType should be EXCLUSIVE, MULTIPLE, IMPLICIT, POPUP
465: * @param fitPolicy should be TEXT_WRAP_DEFAULT, TEXT_WRAP_ON, or
466: * TEXT_WRAP_OFF
467: * @param cgElements array of CGElement that stores such data as
468: * image, text, font, selection state per element
469: * @param numChoices number of valid elements in cgElements array
470: * @param selectedIndex index of a currently selected element
471: * (has no meaning for MULTIPLE ChoiceGroup)
472: * @return native resource id (MidpItem *) of this ChoiceGroup
473: */
474: private native int createNativeResource0(int ownerId, String label,
475: int layout, int choiceType, int fitPolicy,
476: CGElement[] cgElements, int numChoices, int selectedIndex);
477:
478: /**
479: * KNI function that notifies native resource of a new element
480: * inserted prior to the element specified
481: *
482: * @param nativeId native resource id (MidpItem *) of this ChoiceGroup
483: * @param elementNum the index of an element where insertion is to occur
484: * @param stringPart the string part of the element to be inserted
485: * @param imagePart the image part of the element to be inserted
486: * @param selected the selected state of the element to be inserted
487: */
488: private native void insert0(int nativeId, int elementNum,
489: String stringPart, ImageData imagePart, boolean selected);
490:
491: /**
492: * KNI function that notifies native resource of a specified element
493: * being deleted in the corresponding ChoiceGroup.
494: *
495: * @param nativeId native resource id (MidpItem *) of this ChoiceGroup
496: * @param elementNum the index of an element to be deleted
497: * @param selectedIndex the index of an element to be selected after the
498: * deletion is done (has no meaning for MULTIPLE ChoiceGroup)
499: */
500: private native void delete0(int nativeId, int elementNum,
501: int selectedIndex);
502:
503: /**
504: * KNI function that notifies native resource that all elements were
505: * deleted in the corresponding ChoiceGroup.
506: *
507: * @param nativeId native resource id (MidpItem *) of this ChoiceGroup
508: */
509: private native void deleteAll0(int nativeId);
510:
511: /**
512: * KNI function that notifies native resource of a specified element
513: * being set in the corresponding ChoiceGroup.
514: *
515: * @param nativeId native resource id (MidpItem *) of this ChoiceGroup
516: * @param elementNum the index of an element to be set
517: * @param stringPart the string part of the element to be set
518: * @param imagePart the image part of the element to be set
519: * @param selected the selected state of the element to be set
520: */
521: private native void set0(int nativeId, int elementNum,
522: String stringPart, ImageData imagePart, boolean selected);
523:
524: /**
525: * KNI function that notifies native resource of an element's new selected
526: * state in the corresponding ChoiceGroup.
527: *
528: * @param nativeId native resource id (MidpItem *) of this ChoiceGroup
529: * @param elementNum the index of an element which selected state changed
530: * @param selected the new selected state
531: */
532: private native void setSelectedIndex0(int nativeId, int elementNum,
533: boolean selected);
534:
535: /**
536: * KNI function that notifies native resource of new selected
537: * states in the corresponding ChoiceGroup.
538: *
539: * @param nativeId native resource id (MidpItem *) of this ChoiceGroup
540: * @param selectedArray array with new selected states
541: * @param numSelectedArray number of elements in selectedArray to be used
542: */
543: private native void setSelectedFlags0(int nativeId,
544: boolean[] selectedArray, int numSelectedArray);
545:
546: /**
547: * KNI function that notifies native resource of fit policy change
548: * in the corresponding ChoiceGroup.
549: *
550: * @param nativeId native resource id (MidpItem *) of this ChoiceGroup
551: * @param fitPolicy new fit policy (can be TEXT_WRAP_OFF, TEXT_WRAP_ON,
552: * or TEXT_WRAP_DEFAULT)
553: */
554: private native void setFitPolicy0(int nativeId, int fitPolicy);
555:
556: /**
557: * KNI function that notifies native resource of an element's new font
558: * setting in the corresponding ChoiceGroup.
559: *
560: * @param nativeId native resource id (MidpItem *) of this ChoiceGroup
561: * @param elementNum the index of an element which font has changed
562: * @param face of the newly set font
563: * @param style of the newly set font
564: * @param size of newly set font
565: */
566: private native void setFont0(int nativeId, int elementNum,
567: int face, int style, int size);
568:
569: /**
570: * KNI function that gets index of a currently selected index from
571: * the ChoiceGroup's native resource.
572: *
573: * @param nativeId native resource id (MidpItem *) of this ChoiceGroup
574: * @return index of the currently selected element
575: */
576: private native int getSelectedIndex0(int nativeId);
577:
578: /**
579: * KNI function that queries the state of all elements in the native
580: * resource and returns it in the passed in selectedArray array.
581: *
582: * @param nativeId native resource id (MidpItem *) of this ChoiceGroup
583: * @param selectedArray to contain the results
584: * @param numOfEls number of elements in selectedArray
585: * @return the number of elements selected in the native resource
586: */
587: private native int getSelectedFlags0(int nativeId,
588: boolean[] selectedArray, int numOfEls);
589:
590: /**
591: * KNI function that queries the state of an element in the native
592: * resource
593: *
594: * @param nativeId native resource id (MidpItem *) of this ChoiceGroup
595: * @param elementNum the index of an element which state is queried
596: * @return the current state of an element in the nativer resource
597: */
598: private native boolean isSelected0(int nativeId, int elementNum);
599:
600: /** ChoiceGroup associated with this ChoiceGroupLF. */
601: ChoiceGroup cg;
602:
603: /**
604: * The currently selected index of this ChoiceGroup (-1 by default).
605: */
606: int selectedIndex = -1;
607: }
|