001    /* ButtonGroup.java --
002       Copyright (C) 2002, 2006, Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath 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 for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    package javax.swing;
039    
040    import java.io.Serializable;
041    import java.util.Enumeration;
042    import 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     */
066    public 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    }