I added HTML support for all kinds of buttons (JButton, JToggleButton, the menu stuff, and checkboxes/radiobuttons). This works to a certain degree, but the javax.swing.text.(html.)* stuff needs work. Maybe this helps pushing this a little more....

2006-08-04  Roman Kennke  <[EMAIL PROTECTED]>

        * javax/swing/SwingUtilities.java
        (layoutCompoundLabel(JComponent,FontMetrics,String,Icon,int,int,int,
         int,Rectangle,Rectangle,Rectangle,int)): Delegate to new
        layoutCompoundLabelImpl().
        (layoutCompoundLabel(FontMetrics,String,Icon,int,int,int,int,
         Rectangle,Rectangle,Rectangle,int)): Delegate to new
        layoutCompoundLabelImpl().
        (layoutCompoundLabelImpl): New helper method. Moved impl from
        layoutCompoundLabel() to here and added handling of HTML.
        * javax/swing/plaf/basic/BasicButtonUI.java
        (installUI): Update HTML view if appropriate.
        (uninstallUI): New method. Do the usual uninstallUI things
        and uninstall HTML view.
        (getMinimumSize): New method. Adjusts the minimum size
        by the HTML view minimum size.
        (getMaximumSize): New method. Adjusts the maximum size
        by the HTML view maximum size.
        (getPreferredSize): Pass the button's iconTextGap to the
        BasicGraphicsUtils method.
        (paint): Let HTML view paint the text, if present.
        * javax/swing/plaf/basic/BasicButtonListener.java
        (propertyChange): Update the HTML view when the button's
        text is changed.

/Roman
Index: javax/swing/SwingUtilities.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/SwingUtilities.java,v
retrieving revision 1.55
diff -u -1 -2 -r1.55 SwingUtilities.java
--- javax/swing/SwingUtilities.java	24 Jul 2006 12:45:14 -0000	1.55
+++ javax/swing/SwingUtilities.java	4 Aug 2006 11:08:41 -0000
@@ -52,24 +52,26 @@
 import java.awt.Shape;
 import java.awt.Window;
 import java.awt.event.ActionEvent;
 import java.awt.event.InputEvent;
 import java.awt.event.KeyEvent;
 import java.awt.event.MouseEvent;
 import java.lang.reflect.InvocationTargetException;
 
 import javax.accessibility.Accessible;
 import javax.accessibility.AccessibleStateSet;
 import javax.swing.plaf.ActionMapUIResource;
 import javax.swing.plaf.InputMapUIResource;
+import javax.swing.plaf.basic.BasicHTML;
+import javax.swing.text.View;
 
 /**
  * A number of static utility functions which are
  * useful when drawing swing components, dispatching events, or calculating
  * regions which need painting.
  *
  * @author Graydon Hoare ([EMAIL PROTECTED])
  * @author Andrew John Hughes ([EMAIL PROTECTED])
  */
 public class SwingUtilities
   implements SwingConstants
 {
@@ -742,30 +744,30 @@
           horizontalAlignment = RIGHT;
         else
           horizontalAlignment = LEFT;
       }
     else if (horizontalAlignment == TRAILING)
       {
         if (c.getComponentOrientation() == ComponentOrientation.RIGHT_TO_LEFT)
           horizontalAlignment = LEFT;
         else
           horizontalAlignment = RIGHT;
       }
     
-    return layoutCompoundLabel(fm, text, icon,
-                               verticalAlignment,
-                               horizontalAlignment,
-                               verticalTextPosition,
-                               horizontalTextPosition,
-                               viewR, iconR, textR, textIconGap);
+    return layoutCompoundLabelImpl(c, fm, text, icon,
+                                   verticalAlignment,
+                                   horizontalAlignment,
+                                   verticalTextPosition,
+                                   horizontalTextPosition,
+                                   viewR, iconR, textR, textIconGap);
   }
 
   /**
    * <p>Layout a "compound label" consisting of a text string and an icon
    * which is to be placed near the rendered text. Once the text and icon
    * are laid out, the text rectangle and icon rectangle parameters are
    * altered to store the calculated positions.</p>
    *
    * <p>The size of the text is calculated from the provided font metrics
    * object.  This object should be the metrics of the font you intend to
    * paint the label with.</p>
    *
@@ -820,53 +822,139 @@
   public static String layoutCompoundLabel(FontMetrics fm,
                                            String text,
                                            Icon icon,
                                            int verticalAlignment,
                                            int horizontalAlignment,
                                            int verticalTextPosition,
                                            int horizontalTextPosition,
                                            Rectangle viewR,
                                            Rectangle iconR,
                                            Rectangle textR,
                                            int textIconGap)
   {
+    return layoutCompoundLabelImpl(null, fm, text, icon, verticalAlignment,
+                                   horizontalAlignment, verticalTextPosition,
+                                   horizontalTextPosition, viewR, iconR, textR,
+                                   textIconGap);
+  }
+
+  /**
+   * <p>Layout a "compound label" consisting of a text string and an icon
+   * which is to be placed near the rendered text. Once the text and icon
+   * are laid out, the text rectangle and icon rectangle parameters are
+   * altered to store the calculated positions.</p>
+   *
+   * <p>The size of the text is calculated from the provided font metrics
+   * object.  This object should be the metrics of the font you intend to
+   * paint the label with.</p>
+   *
+   * <p>The position values control where the text is placed relative to
+   * the icon. The horizontal position value should be one of the constants
+   * <code>LEFT</code>, <code>RIGHT</code> or <code>CENTER</code>. The
+   * vertical position value should be one fo the constants
+   * <code>TOP</code>, <code>BOTTOM</code> or <code>CENTER</code>.</p>
+   *
+   * <p>The text-icon gap value controls the number of pixels between the
+   * icon and the text.</p>
+   *
+   * <p>The alignment values control where the text and icon are placed, as
+   * a combined unit, within the view rectangle. The horizontal alignment
+   * value should be one of the constants <code>LEFT</code>, <code>RIGHT</code> or
+   * <code>CENTER</code>. The vertical alignment valus should be one of the
+   * constants <code>TOP</code>, <code>BOTTOM</code> or
+   * <code>CENTER</code>.</p>
+   *
+   * <p>If the text and icon are equal to or larger than the view
+   * rectangle, the horizontal and vertical alignment values have no
+   * affect.</p>
+   *
+   * <p>Note that this method does <em>not</em> know how to deal with
+   * horizontal alignments or positions given as <code>LEADING</code> or
+   * <code>TRAILING</code> values. Use the other overloaded variant of this
+   * method if you wish to use such values.
+   *
+   * @param fm The font metrics used to measure the text
+   * @param text The text to place in the compound label
+   * @param icon The icon to place next to the text
+   * @param verticalAlignment The vertical alignment of the label relative
+   * to its component
+   * @param horizontalAlignment The horizontal alignment of the label
+   * relative to its component
+   * @param verticalTextPosition The vertical position of the label's text
+   * relative to its icon
+   * @param horizontalTextPosition The horizontal position of the label's
+   * text relative to its icon
+   * @param viewR The view rectangle, specifying the area which layout is
+   * constrained to
+   * @param iconR A rectangle which is modified to hold the laid-out
+   * position of the icon
+   * @param textR A rectangle which is modified to hold the laid-out
+   * position of the text
+   * @param textIconGap The distance between text and icon
+   *
+   * @return The string of characters, possibly truncated with an elipsis,
+   * which is laid out in this label
+   */
+  private static String layoutCompoundLabelImpl(JComponent c,
+                                                FontMetrics fm,
+                                                String text,
+                                                Icon icon,
+                                                int verticalAlignment,
+                                                int horizontalAlignment,
+                                                int verticalTextPosition,
+                                                int horizontalTextPosition,
+                                                Rectangle viewR,
+                                                Rectangle iconR,
+                                                Rectangle textR,
+                                                int textIconGap)
+  {
 
     // Work out basic height and width.
 
     if (icon == null)
       {
         textIconGap = 0;
         iconR.width = 0;
         iconR.height = 0;
       }
     else
       {
         iconR.width = icon.getIconWidth();
         iconR.height = icon.getIconHeight();
       }
     if (text == null || text.equals(""))
       {
         textIconGap = 0;
 	textR.width = 0;
 	textR.height = 0;
       }
     else
       {
-        int fromIndex = 0;
-        textR.width = fm.stringWidth(text);
-        textR.height = fm.getHeight(); 
-        while (text.indexOf('\n', fromIndex) != -1)
+        View html = c == null ? null
+                           : (View) c.getClientProperty(BasicHTML.propertyKey);
+        if (html != null)
+          {
+            textR.width = (int) html.getPreferredSpan(View.X_AXIS);
+            textR.height = (int) html.getPreferredSpan(View.Y_AXIS);
+          }
+        else
           {
-            textR.height += fm.getHeight();
-            fromIndex = text.indexOf('\n', fromIndex) + 1;
+            int fromIndex = 0;
+            textR.width = fm.stringWidth(text);
+            textR.height = fm.getHeight(); 
+            while (text.indexOf('\n', fromIndex) != -1)
+              {
+                textR.height += fm.getHeight();
+                fromIndex = text.indexOf('\n', fromIndex) + 1;
+              }
           }
       }
 
     // Work out the position of text and icon, assuming the top-left coord
     // starts at (0,0). We will fix that up momentarily, after these
     // "position" decisions are made and we look at alignment.
 
     switch (horizontalTextPosition)
       {
       case LEFT:
         textR.x = 0;
         iconR.x = textR.width + textIconGap;
Index: javax/swing/plaf/basic/BasicButtonListener.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicButtonListener.java,v
retrieving revision 1.16
diff -u -1 -2 -r1.16 BasicButtonListener.java
--- javax/swing/plaf/basic/BasicButtonListener.java	26 Jul 2006 19:23:01 -0000	1.16
+++ javax/swing/plaf/basic/BasicButtonListener.java	4 Aug 2006 11:08:41 -0000
@@ -64,38 +64,42 @@
   FocusListener, ChangeListener, PropertyChangeListener
 {
   public BasicButtonListener(AbstractButton b)
   {
     // Do nothing here.
   }
   
   public void propertyChange(PropertyChangeEvent e)
   {
     // Store the TextLayout for this in a client property for speed-up
     // painting of the label.
     String property = e.getPropertyName();
+    AbstractButton b = (AbstractButton) e.getSource();
     if ((property.equals(AbstractButton.TEXT_CHANGED_PROPERTY)
          || property.equals("font"))
         && SystemProperties.getProperty("gnu.javax.swing.noGraphics2D")
         == null)
       {
-        AbstractButton b = (AbstractButton) e.getSource();
         String text = b.getText();
         if (text == null)
           text = "";
         FontRenderContext frc = new FontRenderContext(new AffineTransform(),
                                                       false, false);
         TextLayout layout = new TextLayout(text, b.getFont(), frc);
         b.putClientProperty(BasicGraphicsUtils.CACHED_TEXT_LAYOUT, layout);
       }
+    if (property.equals(AbstractButton.TEXT_CHANGED_PROPERTY))
+      {
+        BasicHTML.updateRenderer(b, b.getText());
+      }
   }
   
   protected void checkOpacity(AbstractButton b) 
   {    
     // TODO: What should be done here?
   }
   
   public void focusGained(FocusEvent e) 
   {    
     if (e.getSource() instanceof AbstractButton)
       {
         AbstractButton button = (AbstractButton) e.getSource();
Index: javax/swing/plaf/basic/BasicButtonUI.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicButtonUI.java,v
retrieving revision 1.39
diff -u -1 -2 -r1.39 BasicButtonUI.java
--- javax/swing/plaf/basic/BasicButtonUI.java	21 Jun 2006 13:13:40 -0000	1.39
+++ javax/swing/plaf/basic/BasicButtonUI.java	4 Aug 2006 11:08:41 -0000
@@ -47,24 +47,25 @@
 import javax.swing.AbstractButton;
 import javax.swing.ButtonModel;
 import javax.swing.Icon;
 import javax.swing.InputMap;
 import javax.swing.JButton;
 import javax.swing.JComponent;
 import javax.swing.LookAndFeel;
 import javax.swing.SwingUtilities;
 import javax.swing.UIManager;
 import javax.swing.plaf.ButtonUI;
 import javax.swing.plaf.ComponentUI;
 import javax.swing.plaf.UIResource;
+import javax.swing.text.View;
 
 /**
  * A UI delegate for the [EMAIL PROTECTED] JButton} component.
  */
 public class BasicButtonUI extends ButtonUI
 {
   /**
    * A constant used to pad out elements in the button's layout and
    * preferred size calculations.
    */
   protected int defaultTextIconGap = 4;
 
@@ -246,40 +247,102 @@
    *
    * @param c The component to install the UI into
    */
   public void installUI(final JComponent c) 
   {
     super.installUI(c);
     if (c instanceof AbstractButton)
       {
         AbstractButton b = (AbstractButton) c;
         installDefaults(b);
         installListeners(b);
         installKeyboardActions(b);
+        BasicHTML.updateRenderer(b, b.getText());
       }
   }
 
   /**
+   * Uninstalls the UI from the component.
+   *
+   * @param c the component from which to uninstall the UI
+   */
+  public void uninstallUI(JComponent c)
+  {
+    if (c instanceof AbstractButton)
+      {
+        AbstractButton b = (AbstractButton) c;
+        uninstallKeyboardActions(b);
+        uninstallListeners(b);
+        uninstallDefaults(b);
+        BasicHTML.updateRenderer(b, "");
+      }
+  }
+
+  /**
+   * Calculates the minimum size for the specified component.
+   *
+   * @param c the component for which to compute the minimum size
+   *
+   * @return the minimum size for the specified component
+   */
+  public Dimension getMinimumSize(JComponent c)
+  {
+    Dimension size = getPreferredSize(c);
+    // When the HTML view has a minimum width different from the preferred
+    // width, then substract this here accordingly. The height is not
+    // affected by that.
+    View html = (View) c.getClientProperty(BasicHTML.propertyKey);
+    if (html != null)
+      {
+        size.width -= html.getPreferredSpan(View.X_AXIS)
+                      - html.getPreferredSpan(View.X_AXIS);
+      }
+    return size;
+  }
+
+  /**
+   * Calculates the maximum size for the specified component.
+   *
+   * @param c the component for which to compute the maximum size
+   *
+   * @return the maximum size for the specified component
+   */
+  public Dimension getMaximumSize(JComponent c)
+  {
+    Dimension size = getPreferredSize(c);
+    // When the HTML view has a maximum width different from the preferred
+    // width, then add this here accordingly. The height is not
+    // affected by that.
+    View html = (View) c.getClientProperty(BasicHTML.propertyKey);
+    if (html != null)
+      {
+        size.width += html.getMaximumSpan(View.X_AXIS)
+                      - html.getPreferredSpan(View.X_AXIS);
+      }
+    return size;
+  }
+
+  /**
    * Calculate the preferred size of this component, by delegating to
    * [EMAIL PROTECTED] BasicGraphicsUtils#getPreferredButtonSize}.
    *
    * @param c The component to measure
    *
    * @return The preferred dimensions of the component
    */
   public Dimension getPreferredSize(JComponent c) 
   {
     AbstractButton b = (AbstractButton) c;
-    Dimension d = BasicGraphicsUtils.getPreferredButtonSize(b, 
-        defaultTextIconGap + defaultTextShiftOffset);
+    Dimension d = BasicGraphicsUtils.getPreferredButtonSize(b,
+                                                           b.getIconTextGap());
     return d;
   }
 
   static Icon currentIcon(AbstractButton b)
   {
     Icon i = b.getIcon();
     ButtonModel model = b.getModel();
 
     if (model.isPressed() && b.getPressedIcon() != null && b.isEnabled())
       i = b.getPressedIcon();
 
     else if (model.isRollover())
@@ -335,25 +398,31 @@
                                                      b.getVerticalTextPosition(), 
                                                      b.getHorizontalTextPosition(),
                                                      vr, ir, tr, 
                                                      b.getIconTextGap() 
                                                      + defaultTextShiftOffset);
     
     if ((b.getModel().isArmed() && b.getModel().isPressed()) 
         || b.isSelected())
       paintButtonPressed(g, b);
 	
     paintIcon(g, c, ir);
     if (text != null)
-      paintText(g, b, tr, text);
+      {
+        View html = (View) b.getClientProperty(BasicHTML.propertyKey);
+        if (html != null)
+          html.paint(g, tr);
+        else
+          paintText(g, b, tr, text);
+      }
     if (b.isFocusOwner() && b.isFocusPainted())
       paintFocus(g, b, vr, tr, ir);
   }
 
   /**
    * Paint any focus decoration this [EMAIL PROTECTED] JComponent} might have.  The
    * component, which in this case will be an [EMAIL PROTECTED] AbstractButton},
    * should only have focus decoration painted if it has the focus, and its
    * "focusPainted" property is <code>true</code>.
    *
    * @param g Graphics context to paint with
    * @param b Button to paint the focus of

Reply via email to