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