001/* ButtonGroup.java --
002   Copyright (C) 2002, 2006, Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038package javax.swing;
039
040import java.io.Serializable;
041import java.util.Enumeration;
042import java.util.Vector;
043
044
045/**
046 * Logically groups a set of buttons, so that only one of the buttons in
047 * a <code>ButtonGroup</code> can be selected at the same time. If one
048 * button in a <code>ButtonGroup</code> is selected, all other buttons
049 * are automatically deselected.
050 *
051 * While <code>ButtonGroup</code> can be used for all buttons that are derived
052 * from {@link AbstractButton}, it is normally only used for
053 * {@link JRadioButton}s, {@link JRadioButtonMenuItem}s and
054 * {@link JToggleButton}s.
055 *
056 * You could use it for {@link JCheckBox}es, but for the sake of usability
057 * this is strongly discouraged because the common expectation of checkboxes
058 * is that the user is allowed to make multiple selections.
059 *
060 * It makes no sense to put {@link JButton}s or {@link JMenuItem}s in
061 * a <code>ButtonGroup</code> because they don't implement the
062 * <code>selected</code> semantics.
063 *
064 * @author original author unknown
065 */
066public class ButtonGroup implements Serializable
067{
068  private static final long serialVersionUID = 4259076101881721375L;
069
070  /** Stores references to the buttons added to this button group. */
071  protected Vector<AbstractButton> buttons = new Vector<AbstractButton>();
072
073  /** The currently selected button model. */
074  ButtonModel sel;
075
076  /**
077   * Creates a new button group.
078   */
079  public ButtonGroup()
080  {
081    // Nothing to do here.
082  }
083
084  /**
085   * Adds a button to this group.  If the button is in the selected state, then:
086   * <ul>
087   *   <li>if the group has no current selection, the new button becomes the
088   *     selected button for the group;</li>
089   *   <li>if the group already has a selected button, the new button is set to
090   *     "not selected".</li>
091   * </ul>
092   *
093   * @param b the button to add (<code>null</code> is ignored).
094   */
095  public void add(AbstractButton b)
096  {
097    if (b == null)
098      return;
099    b.getModel().setGroup(this);
100    if (b.isSelected())
101      {
102        if (sel == null)
103          sel = b.getModel();
104        else
105          b.setSelected(false);
106      }
107    buttons.addElement(b);
108  }
109
110  /**
111   * Removes the specified button from this group.  If the button is the
112   * selected button, the current selection is set to <code>null</code>.
113   * The group for the removed button's model is set to <code>null</code>.
114   *
115   * @param b the button to remove (<code>null</code> is ignored).
116   */
117  public void remove(AbstractButton b)
118  {
119    if (b == null)
120      return;
121    b.getModel().setGroup(null);
122    if (b.getModel() == sel)
123      sel = null;
124    buttons.removeElement(b);
125  }
126
127  /**
128   * Returns the currently added buttons.
129   *
130   * @return <code>Enumeration</code> over all added buttons
131   */
132  public Enumeration<AbstractButton> getElements()
133  {
134    return buttons.elements();
135  }
136
137  /**
138   * Returns the currently selected button model.
139   *
140   * @return the currently selected button model, null if none was selected
141   *         yet
142   */
143  public ButtonModel getSelection()
144  {
145    return sel;
146  }
147
148  /**
149   * Returns the button that has the specified model, or <code>null</code> if
150   * there is no such button in the group.
151   *
152   * @param m  the button model.
153   *
154   * @return The button that has the specified model, or <code>null</code>.
155   */
156  AbstractButton findButton(ButtonModel m)
157  {
158    for (int i = 0; i < buttons.size(); i++)
159      {
160        AbstractButton a = (AbstractButton) buttons.get(i);
161        if (a.getModel() == m)
162          return a;
163      }
164    return null;
165  }
166
167  /**
168   * Sets the currently selected button model. Only one button of a group can
169   * be selected at a time.
170   *
171   * @param m the model to select
172   * @param b true if this button is to be selected, false otherwise
173   */
174  public void setSelected(ButtonModel m, boolean b)
175  {
176    if ((sel != m || b) && (! b || sel == m))
177      return;
178
179    if (b && sel != m)
180      {
181        ButtonModel old = sel;
182        sel = m;
183
184        if (old != null)
185          old.setSelected(false);
186
187        if (m != null)
188          sel.setSelected(true);
189
190        AbstractButton button = findButton(old);
191        if (button != null)
192          button.repaint();
193      }
194    else if (!b && sel == m)
195      m.setSelected(true);
196  }
197
198  /**
199   * Checks if the given <code>ButtonModel</code> is selected in this button
200   * group.
201   *
202   * @param m  the button model (<code>null</code> permitted).
203   *
204   * @return <code>true</code> if <code>m</code> is the selected button model
205   *     in this group, and <code>false</code> otherwise.
206   */
207  public boolean isSelected(ButtonModel m)
208  {
209    return m == sel;
210  }
211
212  /**
213   * Return the number of buttons in this button group.
214   *
215   * @return the number of buttons
216   *
217   * @since 1.3
218   */
219  public int getButtonCount()
220  {
221    return buttons.size();
222  }
223}