001    /* BasicRadioButtonUI.java
002       Copyright (C) 2002, 2004, 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    
039    package javax.swing.plaf.basic;
040    
041    import java.awt.Color;
042    import java.awt.Dimension;
043    import java.awt.Font;
044    import java.awt.Graphics;
045    import java.awt.Insets;
046    import java.awt.Rectangle;
047    
048    import javax.swing.AbstractButton;
049    import javax.swing.ButtonModel;
050    import javax.swing.Icon;
051    import javax.swing.JComponent;
052    import javax.swing.SwingUtilities;
053    import javax.swing.UIManager;
054    import javax.swing.plaf.ComponentUI;
055    import javax.swing.text.View;
056    
057    /**
058     * The BasicLookAndFeel UI implementation for
059     * {@link javax.swing.JRadioButton}s.
060     */
061    public 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    }