1. /*
  2. * @(#)BasicButtonUI.java 1.112 04/01/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing.plaf.basic;
  8. import com.sun.java.swing.SwingUtilities2;
  9. import java.awt.*;
  10. import java.awt.event.*;
  11. import java.io.Serializable;
  12. import javax.swing.*;
  13. import javax.swing.border.*;
  14. import java.awt.*;
  15. import java.awt.event.*;
  16. import javax.swing.plaf.ButtonUI;
  17. import javax.swing.plaf.UIResource;
  18. import javax.swing.plaf.ComponentUI;
  19. import javax.swing.text.View;
  20. /**
  21. * BasicButton implementation
  22. *
  23. * @version 1.112 01/19/04
  24. * @author Jeff Dinkins
  25. */
  26. public class BasicButtonUI extends ButtonUI{
  27. // Shared UI object
  28. private final static BasicButtonUI buttonUI = new BasicButtonUI();
  29. // Visual constants
  30. // NOTE: This is not used or set any where. Were we allowed to remove
  31. // fields, this would be removed.
  32. protected int defaultTextIconGap;
  33. // Amount to offset text, the value of this comes from
  34. // defaultTextShiftOffset once setTextShiftOffset has been invoked.
  35. private int shiftOffset = 0;
  36. // Value that is set in shiftOffset once setTextShiftOffset has been
  37. // invoked. The value of this comes from the defaults table.
  38. protected int defaultTextShiftOffset;
  39. private final static String propertyPrefix = "Button" + ".";
  40. // ********************************
  41. // Create PLAF
  42. // ********************************
  43. public static ComponentUI createUI(JComponent c) {
  44. return buttonUI;
  45. }
  46. protected String getPropertyPrefix() {
  47. return propertyPrefix;
  48. }
  49. // ********************************
  50. // Install PLAF
  51. // ********************************
  52. public void installUI(JComponent c) {
  53. installDefaults((AbstractButton) c);
  54. installListeners((AbstractButton) c);
  55. installKeyboardActions((AbstractButton) c);
  56. BasicHTML.updateRenderer(c, ((AbstractButton) c).getText());
  57. }
  58. protected void installDefaults(AbstractButton b) {
  59. // load shared instance defaults
  60. String pp = getPropertyPrefix();
  61. defaultTextShiftOffset = UIManager.getInt(pp + "textShiftOffset");
  62. // set the following defaults on the button
  63. if (b.isContentAreaFilled()) {
  64. LookAndFeel.installProperty(b, "opaque", Boolean.TRUE);
  65. } else {
  66. LookAndFeel.installProperty(b, "opaque", Boolean.FALSE);
  67. }
  68. if(b.getMargin() == null || (b.getMargin() instanceof UIResource)) {
  69. b.setMargin(UIManager.getInsets(pp + "margin"));
  70. }
  71. LookAndFeel.installColorsAndFont(b, pp + "background",
  72. pp + "foreground", pp + "font");
  73. LookAndFeel.installBorder(b, pp + "border");
  74. Object rollover = UIManager.get(pp + "rollover");
  75. if (rollover != null) {
  76. LookAndFeel.installProperty(b, "rolloverEnabled", rollover);
  77. }
  78. }
  79. protected void installListeners(AbstractButton b) {
  80. BasicButtonListener listener = createButtonListener(b);
  81. if(listener != null) {
  82. b.addMouseListener(listener);
  83. b.addMouseMotionListener(listener);
  84. b.addFocusListener(listener);
  85. b.addPropertyChangeListener(listener);
  86. b.addChangeListener(listener);
  87. }
  88. }
  89. protected void installKeyboardActions(AbstractButton b){
  90. BasicButtonListener listener = getButtonListener(b);
  91. if(listener != null) {
  92. listener.installKeyboardActions(b);
  93. }
  94. }
  95. // ********************************
  96. // Uninstall PLAF
  97. // ********************************
  98. public void uninstallUI(JComponent c) {
  99. uninstallKeyboardActions((AbstractButton) c);
  100. uninstallListeners((AbstractButton) c);
  101. uninstallDefaults((AbstractButton) c);
  102. BasicHTML.updateRenderer(c, "");
  103. }
  104. protected void uninstallKeyboardActions(AbstractButton b) {
  105. BasicButtonListener listener = getButtonListener(b);
  106. if(listener != null) {
  107. listener.uninstallKeyboardActions(b);
  108. }
  109. }
  110. protected void uninstallListeners(AbstractButton b) {
  111. BasicButtonListener listener = getButtonListener(b);
  112. if(listener != null) {
  113. b.removeMouseListener(listener);
  114. b.removeMouseListener(listener);
  115. b.removeMouseMotionListener(listener);
  116. b.removeFocusListener(listener);
  117. b.removeChangeListener(listener);
  118. b.removePropertyChangeListener(listener);
  119. }
  120. }
  121. protected void uninstallDefaults(AbstractButton b) {
  122. LookAndFeel.uninstallBorder(b);
  123. }
  124. // ********************************
  125. // Create Listeners
  126. // ********************************
  127. protected BasicButtonListener createButtonListener(AbstractButton b) {
  128. return new BasicButtonListener(b);
  129. }
  130. public int getDefaultTextIconGap(AbstractButton b) {
  131. return defaultTextIconGap;
  132. }
  133. /* These rectangles/insets are allocated once for all
  134. * ButtonUI.paint() calls. Re-using rectangles rather than
  135. * allocating them in each paint call substantially reduced the time
  136. * it took paint to run. Obviously, this method can't be re-entered.
  137. */
  138. private static Rectangle viewRect = new Rectangle();
  139. private static Rectangle textRect = new Rectangle();
  140. private static Rectangle iconRect = new Rectangle();
  141. // ********************************
  142. // Paint Methods
  143. // ********************************
  144. public void paint(Graphics g, JComponent c)
  145. {
  146. AbstractButton b = (AbstractButton) c;
  147. ButtonModel model = b.getModel();
  148. FontMetrics fm = SwingUtilities2.getFontMetrics(b, g);
  149. Insets i = c.getInsets();
  150. viewRect.x = i.left;
  151. viewRect.y = i.top;
  152. viewRect.width = b.getWidth() - (i.right + viewRect.x);
  153. viewRect.height = b.getHeight() - (i.bottom + viewRect.y);
  154. textRect.x = textRect.y = textRect.width = textRect.height = 0;
  155. iconRect.x = iconRect.y = iconRect.width = iconRect.height = 0;
  156. Font f = c.getFont();
  157. g.setFont(f);
  158. // layout the text and icon
  159. String text = SwingUtilities.layoutCompoundLabel(
  160. c, fm, b.getText(), b.getIcon(),
  161. b.getVerticalAlignment(), b.getHorizontalAlignment(),
  162. b.getVerticalTextPosition(), b.getHorizontalTextPosition(),
  163. viewRect, iconRect, textRect,
  164. b.getText() == null ? 0 : b.getIconTextGap());
  165. clearTextShiftOffset();
  166. // perform UI specific press action, e.g. Windows L&F shifts text
  167. if (model.isArmed() && model.isPressed()) {
  168. paintButtonPressed(g,b);
  169. }
  170. // Paint the Icon
  171. if(b.getIcon() != null) {
  172. paintIcon(g,c,iconRect);
  173. }
  174. if (text != null && !text.equals("")){
  175. View v = (View) c.getClientProperty(BasicHTML.propertyKey);
  176. if (v != null) {
  177. v.paint(g, textRect);
  178. } else {
  179. paintText(g, b, textRect, text);
  180. }
  181. }
  182. if (b.isFocusPainted() && b.hasFocus()) {
  183. // paint UI specific focus
  184. paintFocus(g,b,viewRect,textRect,iconRect);
  185. }
  186. }
  187. protected void paintIcon(Graphics g, JComponent c, Rectangle iconRect){
  188. AbstractButton b = (AbstractButton) c;
  189. ButtonModel model = b.getModel();
  190. Icon icon = b.getIcon();
  191. Icon tmpIcon = null;
  192. if(icon == null) {
  193. return;
  194. }
  195. if(!model.isEnabled()) {
  196. if(model.isSelected()) {
  197. tmpIcon = (Icon) b.getDisabledSelectedIcon();
  198. } else {
  199. tmpIcon = (Icon) b.getDisabledIcon();
  200. }
  201. } else if(model.isPressed() && model.isArmed()) {
  202. tmpIcon = (Icon) b.getPressedIcon();
  203. if(tmpIcon != null) {
  204. // revert back to 0 offset
  205. clearTextShiftOffset();
  206. }
  207. } else if(b.isRolloverEnabled() && model.isRollover()) {
  208. if(model.isSelected()) {
  209. tmpIcon = (Icon) b.getRolloverSelectedIcon();
  210. } else {
  211. tmpIcon = (Icon) b.getRolloverIcon();
  212. }
  213. } else if(model.isSelected()) {
  214. tmpIcon = (Icon) b.getSelectedIcon();
  215. }
  216. if(tmpIcon != null) {
  217. icon = tmpIcon;
  218. }
  219. if(model.isPressed() && model.isArmed()) {
  220. icon.paintIcon(c, g, iconRect.x + getTextShiftOffset(),
  221. iconRect.y + getTextShiftOffset());
  222. } else {
  223. icon.paintIcon(c, g, iconRect.x, iconRect.y);
  224. }
  225. }
  226. /**
  227. * As of Java 2 platform v 1.4 this method should not be used or overriden.
  228. * Use the paintText method which takes the AbstractButton argument.
  229. */
  230. protected void paintText(Graphics g, JComponent c, Rectangle textRect, String text) {
  231. AbstractButton b = (AbstractButton) c;
  232. ButtonModel model = b.getModel();
  233. FontMetrics fm = SwingUtilities2.getFontMetrics(c, g);
  234. int mnemonicIndex = b.getDisplayedMnemonicIndex();
  235. /* Draw the Text */
  236. if(model.isEnabled()) {
  237. /*** paint the text normally */
  238. g.setColor(b.getForeground());
  239. SwingUtilities2.drawStringUnderlineCharAt(c, g,text, mnemonicIndex,
  240. textRect.x + getTextShiftOffset(),
  241. textRect.y + fm.getAscent() + getTextShiftOffset());
  242. }
  243. else {
  244. /*** paint the text disabled ***/
  245. g.setColor(b.getBackground().brighter());
  246. SwingUtilities2.drawStringUnderlineCharAt(c, g,text, mnemonicIndex,
  247. textRect.x, textRect.y + fm.getAscent());
  248. g.setColor(b.getBackground().darker());
  249. SwingUtilities2.drawStringUnderlineCharAt(c, g,text, mnemonicIndex,
  250. textRect.x - 1, textRect.y + fm.getAscent() - 1);
  251. }
  252. }
  253. /**
  254. * Method which renders the text of the current button.
  255. * <p>
  256. * @param g Graphics context
  257. * @param b Current button to render
  258. * @param textRect Bounding rectangle to render the text.
  259. * @param text String to render
  260. * @since 1.4
  261. */
  262. protected void paintText(Graphics g, AbstractButton b, Rectangle textRect, String text) {
  263. paintText(g, (JComponent)b, textRect, text);
  264. }
  265. // Method signature defined here overriden in subclasses.
  266. // Perhaps this class should be abstract?
  267. protected void paintFocus(Graphics g, AbstractButton b,
  268. Rectangle viewRect, Rectangle textRect, Rectangle iconRect){
  269. }
  270. protected void paintButtonPressed(Graphics g, AbstractButton b){
  271. }
  272. protected void clearTextShiftOffset(){
  273. this.shiftOffset = 0;
  274. }
  275. protected void setTextShiftOffset(){
  276. this.shiftOffset = defaultTextShiftOffset;
  277. }
  278. protected int getTextShiftOffset() {
  279. return shiftOffset;
  280. }
  281. // ********************************
  282. // Layout Methods
  283. // ********************************
  284. public Dimension getMinimumSize(JComponent c) {
  285. Dimension d = getPreferredSize(c);
  286. View v = (View) c.getClientProperty(BasicHTML.propertyKey);
  287. if (v != null) {
  288. d.width -= v.getPreferredSpan(View.X_AXIS) - v.getMinimumSpan(View.X_AXIS);
  289. }
  290. return d;
  291. }
  292. public Dimension getPreferredSize(JComponent c) {
  293. AbstractButton b = (AbstractButton)c;
  294. return BasicGraphicsUtils.getPreferredButtonSize(b, b.getIconTextGap());
  295. }
  296. public Dimension getMaximumSize(JComponent c) {
  297. Dimension d = getPreferredSize(c);
  298. View v = (View) c.getClientProperty(BasicHTML.propertyKey);
  299. if (v != null) {
  300. d.width += v.getMaximumSpan(View.X_AXIS) - v.getPreferredSpan(View.X_AXIS);
  301. }
  302. return d;
  303. }
  304. /**
  305. * Returns the ButtonListener for the passed in Button, or null if one
  306. * could not be found.
  307. */
  308. private BasicButtonListener getButtonListener(AbstractButton b) {
  309. MouseMotionListener[] listeners = b.getMouseMotionListeners();
  310. if (listeners != null) {
  311. for (int counter = 0; counter < listeners.length; counter++) {
  312. if (listeners[counter] instanceof BasicButtonListener) {
  313. return (BasicButtonListener)listeners[counter];
  314. }
  315. }
  316. }
  317. return null;
  318. }
  319. }