001: /*
002: #IFNDEF ALT_LICENSE
003: ThinWire(R) RIA Ajax Framework
004: Copyright (C) 2003-2007 Custom Credit Systems
005:
006: This library is free software; you can redistribute it and/or modify it under
007: the terms of the GNU Lesser General Public License as published by the Free
008: Software Foundation; either version 2.1 of the License, or (at your option) any
009: later version.
010:
011: This library is distributed in the hope that it will be useful, but WITHOUT ANY
012: WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
013: PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
014:
015: You should have received a copy of the GNU Lesser General Public License along
016: with this library; if not, write to the Free Software Foundation, Inc., 59
017: Temple Place, Suite 330, Boston, MA 02111-1307 USA
018:
019: Users who would rather have a commercial license, warranty or support should
020: contact the following company who invented, built and supports the technology:
021:
022: Custom Credit Systems, Richardson, TX 75081, USA.
023: email: info@thinwire.com ph: +1 (888) 644-6405
024: http://www.thinwire.com
025: #ENDIF
026: [ v1.2_RC2 ]
027: */
028: package thinwire.ui;
029:
030: import java.util.AbstractList;
031: import java.util.ArrayList;
032: import java.util.List;
033:
034: import thinwire.ui.event.ActionEvent;
035: import thinwire.ui.event.ActionListener;
036: import thinwire.ui.event.PropertyChangeListener;
037:
038: /**
039: * A RadioButton is a screen element that usually appears in groups. Radio buttons can be either checked or cleared, but only one
040: * radio button per group may be checked.
041: * <p>
042: * <b>Example:</b> <br>
043: * <img src="doc-files/RadioButton-1.png"> <br>
044: *
045: * <pre>
046: * final RadioButton rb1 = new RadioButton("Yes");
047: * rb1.setBounds(20, 20, 70, 30);
048: * final RadioButton rb2 = new RadioButton("No");
049: * rb2.setBounds(100, 20, 70, 30);
050: *
051: * RadioButton.Group rbg = new RadioButton.Group();
052: * rbg.add(rb1);
053: * rbg.add(rb2);
054: * rbg.addPropertyChangeListener(RadioButton.PROPERTY_CHECKED, new PropertyChangeListener() {
055: * public void propertyChange(PropertyChangeEvent pce) {
056: * RadioButton rb = (RadioButton) pce.getSource();
057: *
058: * if (rb == rb1) {
059: * rb.setText(rb.isChecked() ? "[YES]" : "Yes");
060: * } else {
061: * rb.setText(rb.isChecked() ? "[NO]" : "No");
062: * }
063: * }
064: * });
065: *
066: * Frame f = Application.current().getFrame();
067: * f.getChildren().add(rb1);
068: * f.getChildren().add(rb2);
069: * </pre>
070: *
071: * </p>
072: * <p>
073: * <b>Keyboard Navigation:</b><br>
074: * <table border="1">
075: * <tr>
076: * <td>KEY</td>
077: * <td>RESPONSE</td>
078: * <td>NOTE</td>
079: * </tr>
080: * <tr>
081: * <td>Space</td>
082: * <td>Fires PropertyChangeEvent( propertyName = RadioButton.PROPERTY_CHECKED )</td>
083: * <td>Only if the component has focus.</td>
084: * </tr>
085: * </table>
086: * </p>
087: * @author Joshua J. Gertzen
088: */
089: public class RadioButton extends AbstractTextComponent implements
090: CheckedComponent {
091: public static class Group extends AbstractList<RadioButton> {
092: private RadioButton checked;
093: private List<RadioButton> l = new ArrayList<RadioButton>(3);
094:
095: public void add(int index, RadioButton o) {
096: RadioButton rb = (RadioButton) o;
097: if (rb.getGroup() != null)
098: throw new IllegalStateException("rb.getGroup() != null");
099: l.add(index, rb);
100: modCount++;
101: rb.setGroup(this );
102: if (rb.isChecked())
103: rb.setChecked(true); //Cause the checked state of the button to get in sync with the group.
104: }
105:
106: public RadioButton get(int index) {
107: return l.get(index);
108: }
109:
110: public RadioButton set(int index, RadioButton o) {
111: RadioButton rb = (RadioButton) o;
112: if (rb.getGroup() != null)
113: throw new IllegalStateException("rb.getGroup() != null");
114: RadioButton ret = (RadioButton) l.set(index, rb);
115: ret.setGroup(null);
116: if (checked == ret)
117: checked = null;
118: rb.setGroup(this );
119: if (rb.isChecked())
120: rb.setChecked(true); //Cause the checked state of the button to get in sync with the group.
121: return ret;
122: }
123:
124: public RadioButton remove(int index) {
125: modCount++;
126: RadioButton ret = (RadioButton) l.remove(index);
127: ret.setGroup(null);
128: if (checked == ret)
129: checked = null;
130: return ret;
131: }
132:
133: public int size() {
134: return l.size();
135: }
136:
137: /**
138: * Adds a PropertyChangeListener to each radio button component in the group.
139: * @param propertyName
140: * @param listener
141: */
142: public final void addPropertyChangeListener(
143: String propertyName, PropertyChangeListener listener) {
144: for (RadioButton rb : l) {
145: rb.addPropertyChangeListener(propertyName, listener);
146: }
147: }
148:
149: /**
150: * Adds a PropertyChangeListener to each radio button component in the group.
151: * @param propertyNames
152: * @param listener
153: */
154: public final void addPropertyChangeListener(
155: String[] propertyNames, PropertyChangeListener listener) {
156: for (RadioButton rb : l) {
157: rb.addPropertyChangeListener(propertyNames, listener);
158: }
159: }
160:
161: /**
162: * Removes a preexisting PropertyChangeListener from each component in the group.
163: * @param listener the listener to remove
164: */
165: public final void removePropertyChangeListener(
166: PropertyChangeListener listener) {
167: if (listener == null)
168: return;
169:
170: for (RadioButton rb : l) {
171: rb.removePropertyChangeListener(listener);
172: }
173: }
174:
175: public final void addActionListener(String action,
176: ActionListener listener) {
177: for (RadioButton rb : l) {
178: rb.addActionListener(action, listener);
179: }
180:
181: }
182:
183: public final void addActionListener(String[] actions,
184: ActionListener listener) {
185: for (RadioButton rb : l) {
186: rb.addActionListener(actions, listener);
187: }
188: }
189:
190: public final void removeActionListener(ActionListener listener) {
191: if (listener == null)
192: return;
193:
194: for (RadioButton rb : l) {
195: rb.removeActionListener(listener);
196: }
197: }
198:
199: public final void fireAction(ActionEvent ev) {
200: for (RadioButton rb : l) {
201: rb.fireAction(ev);
202: }
203: }
204:
205: public final void fireAction(String action) {
206: for (RadioButton rb : l) {
207: rb.fireAction(action);
208: }
209: }
210:
211: public boolean isEnabled() {
212: boolean enabled = true;
213:
214: for (RadioButton rb : l) {
215: if (!rb.isEnabled()) {
216: enabled = false;
217: break;
218: }
219: }
220:
221: return enabled;
222: }
223:
224: public void setEnabled(boolean enabled) {
225: for (RadioButton rb : l) {
226: rb.setEnabled(enabled);
227: }
228: }
229:
230: public boolean isVisible() {
231: boolean visible = true;
232:
233: for (RadioButton rb : l) {
234: if (!rb.isVisible()) {
235: visible = false;
236: break;
237: }
238: }
239:
240: return visible;
241: }
242:
243: public void setVisible(boolean visible) {
244: for (RadioButton rb : l) {
245: rb.setVisible(visible);
246: }
247: }
248:
249: public Object getUserObject() {
250: Object obj = null;
251:
252: for (RadioButton rb : l) {
253: obj = rb.getUserObject();
254: if (obj != null)
255: break;
256: }
257:
258: return obj;
259: }
260:
261: public void setUserObject(Object userObject) {
262: for (RadioButton rb : l) {
263: rb.setUserObject(userObject);
264: }
265: }
266:
267: /**
268: *
269: * @return
270: */
271: public RadioButton getChecked() {
272: return checked;
273: }
274:
275: /**
276: *
277: * @param rb
278: */
279: public void setChecked(RadioButton rb) {
280: rb.setChecked(true);
281: }
282: }
283:
284: public static final String PROPERTY_GROUP = "group";
285:
286: private boolean checked;
287: private Group group;
288:
289: /**
290: * Constructs a RadioButton with no text.
291: */
292: public RadioButton() {
293:
294: }
295:
296: /**
297: * Constructs a RadioButton with the specified text.
298: * @param text the text
299: */
300: public RadioButton(String text) {
301: setText(text);
302: }
303:
304: /**
305: * Constructs a new RadioButton with the specified text and initial checked state.
306: * @param text the text to display on the right side of the RadioButton.
307: * @param checked the initial checked state
308: */
309: public RadioButton(String text, boolean checked) {
310: setText(text);
311: setChecked(checked);
312: }
313:
314: /**
315: * Constructs a new RadioButton with the specified text, false checked state and group.
316: * @param group the RadioButton.Group for the RadioButton
317: * @param text the text to display on the right side of the RadioButton.
318: * @throws IllegalArgumentException if <code>group</code> is null
319: */
320: public RadioButton(RadioButton.Group group, String text) {
321: this (group, text, false);
322: }
323:
324: /**
325: * Constructs a new RadioButton with the specified text, initial checked state and group.
326: * @param group the RadioButton.Group for the RadioButton
327: * @param text the text to display on the right side of the RadioButton.
328: * @param checked the initial checked state
329: * @throws IllegalArgumentException if <code>group</code> is null
330: */
331: public RadioButton(RadioButton.Group group, String text,
332: boolean checked) {
333: if (group == null)
334: throw new IllegalArgumentException("group == null");
335: setText(text);
336: setChecked(checked);
337: group.add(this );
338: }
339:
340: /**
341: * Constructs a new RadioButton with the specified text, false checked state and group.
342: * @param sibling a RadioButton that has a group this RadioButton should become a member of.
343: * @param text the text to display on the right side of the RadioButton.
344: * @throws IllegalArgumentException if <code>sibling</code> is null
345: */
346: public RadioButton(RadioButton sibling, String text) {
347: this (sibling, text, false);
348: }
349:
350: /**
351: * Constructs a new RadioButton with the specified text, initial checked state and group.
352: * NOTE: If the specified <code>sibling</code> is not a member of a <code>RadioButton.Group</code>
353: * then a RadioButton.Group will be constructed and both the <code>sibling</code> and <code>this</code>
354: * RadioButton will be added to it.
355: * @param sibling a RadioButton that has a group this RadioButton should become a member of.
356: * @param text the text to display on the right side of the RadioButton.
357: * @param checked the initial checked state
358: * @throws IllegalArgumentException if <code>sibling</code> is null
359: */
360: public RadioButton(RadioButton sibling, String text, boolean checked) {
361: if (sibling == null)
362: throw new IllegalArgumentException("sibling == null");
363: setText(text);
364: setChecked(checked);
365: RadioButton.Group group = sibling.getGroup();
366:
367: if (group == null) {
368: group = new RadioButton.Group();
369: group.add(sibling);
370: }
371:
372: group.add(this );
373: }
374:
375: /**
376: * Returns the Group that this radio button is a part of.
377: * @return a radio button Group
378: */
379: public Group getGroup() {
380: return group;
381: }
382:
383: private void setGroup(Group group) {
384: Group oldGroup = this .group;
385: this .group = group;
386: firePropertyChange(this , PROPERTY_GROUP, oldGroup, group);
387: }
388:
389: public boolean isChecked() {
390: return checked;
391: }
392:
393: public void setChecked(boolean checked) {
394: boolean oldChecked = this .checked;
395: this .checked = checked;
396:
397: if (group != null) {
398: if (checked) {
399: for (RadioButton rb : group.l) {
400: if (rb != this )
401: rb.setChecked(false);
402: }
403:
404: group.checked = this;
405: } else if (group.checked == this)
406: group.checked = null;
407: }
408:
409: firePropertyChange(this, PROPERTY_CHECKED, oldChecked, checked);
410: }
411: }
|