001: /*
002: * Copyright 2000,2005 wingS development team.
003: *
004: * This file is part of wingS (http://wingsframework.org).
005: *
006: * wingS is free software; you can redistribute it and/or modify
007: * it under the terms of the GNU Lesser General Public License
008: * as published by the Free Software Foundation; either version 2.1
009: * of the License, or (at your option) any later version.
010: *
011: * Please see COPYING for the complete licence.
012: */
013: package org.wings;
014:
015: import org.wings.session.SessionManager;
016: import javax.swing.event.EventListenerList;
017: import java.awt.event.ActionEvent;
018: import java.awt.event.ActionListener;
019: import java.io.Serializable;
020: import java.lang.reflect.Array;
021: import java.util.ArrayList;
022: import java.util.Collections;
023: import java.util.Enumeration;
024: import java.util.EventListener;
025: import java.util.Iterator;
026:
027: /**
028: * Used to create a multiple-exclusion scope for a set of buttons.
029: * <p/>
030: * Creating a set of buttons with the same ButtonGroup object means
031: * that turning "on" one of those buttons turns off all other buttons in the
032: * group.
033: * <p/>
034: * <p>A SButtonGroup can be used with any set of objects that inherit from
035: * {@link SAbstractButton}, because they support the selected state.
036: * <p/>
037: * <p>Initially, all buttons in the group are unselected. Once any button is
038: * selected, one button is always selected in the group. There is no way to
039: * turn a button programmatically to "off", in order to clear the button
040: * group.
041: * <p/>
042: * <p><em>Details:</em>The implementation of the button group is a
043: * bit tricky for the HTML generation. In HTML, groups of components are
044: * usually formed by giving them all the same name. The problem is, that
045: * any {@link SComponent}, especially the {@link SAbstractButton}, have globally
046: * <em>unique</em> names. So this implementation gives all buttons in the
047: * group the name of this SButtonGroup, and sets their <em>value</em> to
048: * their actual name. So a bit of dispatching is already done here.
049: *
050: * @author <a href="mailto:haaf@mercatis.de">Armin Haaf</a>
051: * @see javax.swing.ButtonGroup
052: */
053: public class SButtonGroup implements SDelayedEventModel, Serializable {
054: public static final String SELECTION_CHANGED = "SelectionChanged";
055:
056: protected final ArrayList buttons = new ArrayList(2);
057:
058: private SAbstractButton selection = null;
059:
060: /* */
061: private transient String componentId = null;
062:
063: protected final EventListenerList listenerList = new EventListenerList();
064:
065: /**
066: * indicates if we should fire event immediately when they arise, or if we
067: * should collect them for a later delivery
068: */
069: private boolean delayEvents = false;
070:
071: /**
072: * all delayed events are stored here.
073: */
074: protected final ArrayList delayedEvents = new ArrayList(2);
075:
076: public SButtonGroup() {
077: }
078:
079: /**
080: * Return a jvm wide unique id.
081: *
082: * @return an id
083: */
084: public final String getComponentId() {
085: if (componentId == null)
086: componentId = SessionManager.getSession().createUniqueId();
087: return componentId;
088: }
089:
090: protected void setSelection(SAbstractButton button) {
091: SAbstractButton oldSelection = selection;
092:
093: selection = button;
094:
095: if (oldSelection != null && oldSelection.getGroup() == this )
096: oldSelection.setSelected(false);
097:
098: if (selection != null)
099: selection.setSelected(true);
100:
101: fireActionPerformed(selection != null ? selection
102: .getActionCommand() : SELECTION_CHANGED);
103: }
104:
105: /*
106: * Konzeptionell richtiger waere hier SAbstractButton. Macht aber keinen
107: * Sinn. Macht nur Sinn abstract Checkboxes(eventuell nur RadioButtons ???).
108: */
109: /**
110: * adds a button to the group.
111: *
112: * @param button the button that is to be added
113: */
114: public void add(SAbstractButton button) {
115: if (buttons != null && !buttons.contains(button)) {
116: buttons.add(button);
117: button.setGroup(this );
118: if (selection == null && button.isSelected()) {
119: setSelection(button);
120: }
121: }
122: }
123:
124: /**
125: * removes a button from the group.
126: *
127: * @param button the button that is to be removed
128: */
129: public void remove(SAbstractButton button) {
130: if (button == null || button.getGroup() != this )
131: return;
132:
133: buttons.remove(button);
134: button.setGroup(null);
135:
136: if (button == selection) {
137: setSelection(null);
138: }
139: }
140:
141: /**
142: * removes all buttons from the group.
143: */
144: public void removeAll() {
145: while (buttons.size() > 0)
146: remove((SAbstractButton) buttons.get(0));
147: }
148:
149: /**
150: * Gets the button of the group that is selected.
151: * @see #setSelection(SAbstractButton)
152: * @return the selected button
153: */
154: public final SAbstractButton getSelection() {
155: return selection;
156: }
157:
158: /**
159: * Sets a button in the selected state. There can be only one button selected at a time.
160: *
161: * @param b the button.
162: * @param selected true if this button is to be selected, otherwise false.
163: */
164: public void setSelected(SAbstractButton b, boolean selected) {
165: if (selected && b != selection && b != null) {
166: setSelection(b);
167: }
168: // if button should be set to unselected, clear selection
169: if (!selected && b != null && b.equals(selection)) {
170: setSelection(null);
171:
172: }
173: }
174:
175: /**
176: * Returns the state of the button. True if the button is selected, false if not.
177: *
178: * @param button the button.
179: * @return true if the button is selected, otherwise false.
180: */
181: public boolean isSelected(SAbstractButton button) {
182: return button == getSelection();
183: }
184:
185: public Iterator iterator() {
186: return buttons.iterator();
187: }
188:
189: /**
190: * Gets all the buttons the group consists of.
191: * @return an enumeration of the buttons of the group
192: */
193: public Enumeration getElements() {
194: return Collections.enumeration(buttons);
195: }
196:
197: /**
198: * Gets the id of the component.
199: * @return the component id
200: */
201: public String getLowLevelEventId() {
202: return getComponentId();
203: }
204:
205: /**
206: * Adds an action listener to this group of buttons.
207: * If one of the buttons contained in this group gets selected, an action event will occur.
208: *
209: * @param listener
210: */
211: public void addActionListener(ActionListener listener) {
212: listenerList.add(ActionListener.class, listener);
213: }
214:
215: /**
216: * Removes the supplied Listener from the listener list
217: */
218: public void removeActionListener(ActionListener listener) {
219: listenerList.remove(ActionListener.class, listener);
220: }
221:
222: /**
223: * Returns an array of all the <code>ActionListener</code>s added
224: * to this group of buttons with addActionListener().
225: *
226: * @return all of the <code>ActionListener</code>s added or an empty
227: * array if no listeners have been added
228: */
229: public ActionListener[] getActionListeners() {
230: if (listenerList != null) {
231: return (ActionListener[]) listenerList
232: .getListeners(ActionListener.class);
233: } else {
234: return (ActionListener[]) Array.newInstance(
235: ActionListener.class, 0);
236: }
237: }
238:
239: /**
240: * Fire an ActionEvent at each registered listener.
241: */
242: protected void fireActionPerformed(String command) {
243: fireActionEvent(new ActionEvent(this ,
244: ActionEvent.ACTION_PERFORMED, command));
245: }
246:
247: /**
248: * Fire an ActionEvent at each registered listener.
249: */
250: protected void fireActionEvent(ActionEvent e) {
251: if (e == null)
252: return;
253:
254: if (delayEvents) {
255: delayedEvents.add(e);
256: return;
257: }
258:
259: // Guaranteed to return a non-null array
260: Object[] listeners = listenerList.getListenerList();
261: // Process the listeners last to first, notifying
262: // those that are interested in this event
263: for (int i = listeners.length - 2; i >= 0; i -= 2) {
264: if (listeners[i] == ActionListener.class) {
265: ((ActionListener) listeners[i + 1]).actionPerformed(e);
266: }
267: }
268: }
269:
270: public void setDelayEvents(boolean b) {
271: delayEvents = b;
272: }
273:
274: public boolean getDelayEvents() {
275: return delayEvents;
276: }
277:
278: public void fireDelayedIntermediateEvents() {
279: }
280:
281: public void fireDelayedFinalEvents() {
282: for (Iterator iter = delayedEvents.iterator(); iter.hasNext();) {
283: ActionEvent e = (ActionEvent) iter.next();
284:
285: fireActionEvent(e);
286: }
287: delayedEvents.clear();
288: }
289: }
|