001/* BasicRadioButtonUI.java
002   Copyright (C) 2002, 2004, 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
038
039package javax.swing.plaf.basic;
040
041import java.awt.Color;
042import java.awt.Dimension;
043import java.awt.Font;
044import java.awt.Graphics;
045import java.awt.Insets;
046import java.awt.Rectangle;
047
048import javax.swing.AbstractButton;
049import javax.swing.ButtonModel;
050import javax.swing.Icon;
051import javax.swing.JComponent;
052import javax.swing.SwingUtilities;
053import javax.swing.UIManager;
054import javax.swing.plaf.ComponentUI;
055import javax.swing.text.View;
056
057/**
058 * The BasicLookAndFeel UI implementation for
059 * {@link javax.swing.JRadioButton}s.
060 */
061public class BasicRadioButtonUI extends BasicToggleButtonUI
062{
063  /**
064   * The default icon for JRadioButtons. The default icon displays the usual
065   * RadioButton and is sensible to the selection state of the button,
066   * and can be used both as normal icon as well as selectedIcon.
067   */
068  protected Icon icon;
069
070  /**
071   * Creates and returns a new instance of <code>BasicRadioButtonUI</code>.
072   *
073   * @return a new instance of <code>BasicRadioButtonUI</code>
074   */
075  public static ComponentUI createUI(final JComponent c)
076  {
077    return new BasicRadioButtonUI();
078  }
079
080  /**
081   * Creates a new instance of <code>BasicButtonUI</code>.
082   */
083  public BasicRadioButtonUI()
084  {
085    // nothing to do
086  }
087
088  /**
089   * Installs defaults from the Look &amp; Feel table on the specified
090   * button.
091   *
092   * @param b the button on which to install the defaults
093   */
094  protected void installDefaults(AbstractButton b)
095  {
096    super.installDefaults(b);
097    icon = UIManager.getIcon(getPropertyPrefix() + "icon");
098  }
099
100  /**
101   * Returns the prefix used for UIDefaults properties. This is
102   * <code>RadioButton</code> in this case.
103   *
104   * @return the prefix used for UIDefaults properties
105   */
106  protected String getPropertyPrefix()
107  {
108    return "RadioButton.";
109  }
110
111  /**
112   * Returns the default icon for JRadioButtons.
113   * The default icon displays the usual
114   * RadioButton and is sensible to the selection state of the button,
115   * and can be used both as normal icon as well as selectedIcon.
116   *
117   * @return the default icon for JRadioButtons
118   */
119  public Icon getDefaultIcon()
120  {
121    return icon;
122  }
123
124  /**
125   * Paints the RadioButton.
126   *
127   * @param g the Graphics context to paint with
128   * @param c the button to paint
129   */
130  public void paint(Graphics g, JComponent c)
131  {
132    AbstractButton b = (AbstractButton) c;
133    Dimension size = c.getSize();
134    Insets i = b.getInsets();
135    textR.x = 0;
136    textR.y = 0;
137    textR.width = 0;
138    textR.height = 0;
139    iconR.x = 0;
140    iconR.y = 0;
141    iconR.width = 0;
142    iconR.height = 0;
143    viewR.x = i.left;
144    viewR.y = i.right;
145    viewR.width = size.width - i.left - i.right;
146    viewR.height = size.height - i.top - i.bottom;
147
148    Font f = c.getFont();
149
150    g.setFont(f);
151
152    // This is the icon that we use for layout.
153    Icon icon = b.getIcon();
154    if (icon == null)
155      icon = getDefaultIcon();
156
157    // Figure out the correct icon.
158    Icon currentIcon = getCurrentIcon(b);
159
160    // Do the layout.
161    String text = SwingUtilities.layoutCompoundLabel(c, g.getFontMetrics(f),
162       b.getText(), currentIcon == null ? getDefaultIcon() : currentIcon,
163       b.getVerticalAlignment(), b.getHorizontalAlignment(),
164       b.getVerticalTextPosition(), b.getHorizontalTextPosition(),
165       viewR, iconR, textR, b.getIconTextGap());
166
167    // .. and paint it.
168    if (currentIcon != null)
169      currentIcon.paintIcon(c, g, iconR.x, iconR.y);
170
171    // Paint text and focus indicator.
172    if (text != null)
173      {
174        // Maybe render HTML in the radio button.
175        View v = (View) c.getClientProperty(BasicHTML.propertyKey);
176        if (v != null)
177          v.paint(g, textR);
178        else
179          paintText(g, b, textR, text);
180
181        // Paint focus indicator if necessary.
182        if (b.hasFocus() && b.isFocusPainted()
183            && textR.width > 0 && textR.height > 0)
184          paintFocus(g, textR, size);
185      }
186  }
187
188  /**
189   * Determines the icon to be displayed for the specified radio button.
190   *
191   * @param b the radio button
192   *
193   * @return the icon
194   */
195  private Icon getCurrentIcon(AbstractButton b)
196  {
197    ButtonModel m = b.getModel();
198    Icon currentIcon = b.getIcon();
199
200    if (currentIcon == null)
201      {
202        currentIcon = getDefaultIcon();
203      }
204    else
205      {
206        if (! m.isEnabled())
207          {
208            if (m.isSelected())
209              currentIcon = b.getDisabledSelectedIcon();
210            else
211              currentIcon = b.getDisabledIcon();
212          }
213        else if (m.isPressed() && m.isArmed())
214          {
215            currentIcon = b.getPressedIcon();
216            if (currentIcon == null)
217              currentIcon = b.getSelectedIcon();
218          }
219        else if (m.isSelected())
220          {
221            if (b.isRolloverEnabled() && m.isRollover())
222              {
223                currentIcon = b.getRolloverSelectedIcon();
224                if (currentIcon == null)
225                  currentIcon = b.getSelectedIcon();
226              }
227            else
228              currentIcon = b.getSelectedIcon();
229          }
230        else if (b.isRolloverEnabled() && m.isRollover())
231          {
232            currentIcon = b.getRolloverIcon();
233          }
234        if (currentIcon == null)
235          currentIcon = b.getIcon();
236      }
237    return currentIcon;
238  }
239
240  public Dimension getPreferredSize(JComponent c)
241  {
242    // This is basically the same code as in
243    // BasicGraphicsUtils.getPreferredButtonSize() but takes the default icon
244    // property into account. JRadioButton and subclasses always have an icon:
245    // the check box. If the user explicitly changes it with setIcon() that
246    // one will be used for layout calculations and painting instead.
247    // The other icon properties are ignored.
248    AbstractButton b = (AbstractButton) c;
249
250    Insets insets = b.getInsets();
251
252    String text = b.getText();
253    Icon i = b.getIcon();
254    if (i == null)
255      i = getDefaultIcon();
256
257    textR.x = 0;
258    textR.y = 0;
259    textR.width = 0;
260    textR.height = 0;
261    iconR.x = 0;
262    iconR.y = 0;
263    iconR.width = 0;
264    iconR.height = 0;
265    viewR.x = 0;
266    viewR.y = 0;
267    viewR.width = Short.MAX_VALUE;
268    viewR.height = Short.MAX_VALUE;
269
270    SwingUtilities.layoutCompoundLabel(b, // for the component orientation
271                                       b.getFontMetrics(b.getFont()),
272                                       text, i, b.getVerticalAlignment(),
273                                       b.getHorizontalAlignment(),
274                                       b.getVerticalTextPosition(),
275                                       b.getHorizontalTextPosition(),
276                                       viewR, iconR, textR,
277                                       text == null ? 0 : b.getIconTextGap());
278
279    Rectangle r = SwingUtilities.computeUnion(textR.x, textR.y, textR.width,
280                                              textR.height, iconR);
281
282    return new Dimension(insets.left + r.width + insets.right,
283                         insets.top + r.height + insets.bottom);
284  }
285
286  /**
287   * Paints the focus indicator for JRadioButtons.
288   *
289   * @param g the graphics context
290   * @param tr the rectangle for the text label
291   * @param size the size of the <code>JRadioButton</code> component.
292   */
293  protected void paintFocus(Graphics g, Rectangle tr, Dimension size)
294  {
295    Color focusColor = UIManager.getColor(getPropertyPrefix() + ".focus");
296    Color saved = g.getColor();
297    g.setColor(focusColor);
298    g.drawRect(tr.x, tr.y, tr.width, tr.height);
299    g.setColor(saved);
300  }
301}