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