1. /*
  2. * @(#)BasicButtonListener.java 1.54 01/03/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package com.sun.java.swing.plaf.gtk;
  11. import java.awt.*;
  12. import java.awt.event.*;
  13. import java.beans.*;
  14. import javax.swing.*;
  15. import javax.swing.event.*;
  16. import javax.swing.plaf.ActionMapUIResource;
  17. import javax.swing.plaf.ButtonUI;
  18. import javax.swing.plaf.ComponentInputMapUIResource;
  19. import javax.swing.plaf.basic.BasicHTML;
  20. /**
  21. * Button Listener
  22. *
  23. * @version 1.9, 01/23/03 (based on BasicButtonListener v 1.58)
  24. * @author Jeff Dinkins
  25. * @author Arnaud Weber (keyboard UI support)
  26. */
  27. class SynthButtonListener implements MouseListener,
  28. MouseMotionListener,FocusListener, ChangeListener,
  29. PropertyChangeListener, SynthEventListener, LazyActionMap.Loader
  30. {
  31. private static long lastPressedTimestamp = -1;
  32. private static boolean shouldDiscardRelease = false;
  33. public SynthButtonListener() {
  34. }
  35. public void propertyChange(PropertyChangeEvent e) {
  36. String prop = e.getPropertyName();
  37. AbstractButton button = (AbstractButton)e.getSource();
  38. if (AbstractButton.MNEMONIC_CHANGED_PROPERTY.equals(prop)) {
  39. updateMnemonicBinding(button);
  40. }
  41. else if (AbstractButton.CONTENT_AREA_FILLED_CHANGED_PROPERTY.equals(
  42. prop)) {
  43. checkOpacity(button);
  44. }
  45. else if (AbstractButton.TEXT_CHANGED_PROPERTY.equals(prop) ||
  46. "font".equals(prop) || "foreground".equals(prop)) {
  47. BasicHTML.updateRenderer(button, button.getText());
  48. }
  49. if (SynthLookAndFeel.shouldUpdateStyle(e)) {
  50. ButtonUI ui = button.getUI();
  51. if (ui != null && (ui instanceof SynthButtonUI)) {
  52. ((SynthButtonUI)ui).fetchStyle(button);
  53. }
  54. }
  55. }
  56. protected void checkOpacity(AbstractButton b) {
  57. b.setOpaque(b.isContentAreaFilled());
  58. }
  59. /**
  60. * Register default key actions: pressing space to "click" a
  61. * button and registring the keyboard mnemonic (if any).
  62. */
  63. public void installKeyboardActions(JComponent c) {
  64. AbstractButton b = (AbstractButton)c;
  65. // Update the mnemonic binding.
  66. updateMnemonicBinding(b);
  67. LazyActionMap.installLazyActionMap(c, this);
  68. InputMap km = getInputMap(JComponent.WHEN_FOCUSED, c);
  69. SwingUtilities.replaceUIInputMap(c, JComponent.WHEN_FOCUSED, km);
  70. }
  71. /**
  72. * Unregister's default key actions
  73. */
  74. public void uninstallKeyboardActions(JComponent c) {
  75. SwingUtilities.replaceUIInputMap(c, JComponent.WHEN_IN_FOCUSED_WINDOW,
  76. null);
  77. SwingUtilities.replaceUIInputMap(c, JComponent.WHEN_FOCUSED, null);
  78. SwingUtilities.replaceUIActionMap(c, null);
  79. }
  80. /**
  81. * Returns the InputMap for condition <code>condition</code>. Called as
  82. * part of <code>installKeyboardActions</code>.
  83. */
  84. InputMap getInputMap(int condition, JComponent c) {
  85. if (condition == JComponent.WHEN_FOCUSED) {
  86. ButtonUI ui = ((AbstractButton)c).getUI();
  87. if (ui != null && (ui instanceof SynthButtonUI)) {
  88. SynthButtonUI buttonUI = (SynthButtonUI)ui;
  89. SynthContext context = buttonUI.getContext(c,
  90. SynthConstants.ENABLED);
  91. InputMap map = (InputMap)context.getStyle().get(
  92. context, buttonUI.getPropertyPrefix() +"focusInputMap");
  93. context.dispose();
  94. return map;
  95. }
  96. }
  97. return null;
  98. }
  99. /**
  100. * Creates and returns the ActionMap to use for the button.
  101. */
  102. public void loadActionMap(JComponent c, ActionMap map) {
  103. map.put("pressed", new PressedAction((AbstractButton)c));
  104. map.put("released", new ReleasedAction((AbstractButton)c));
  105. }
  106. /**
  107. * Resets the binding for the mnemonic in the WHEN_IN_FOCUSED_WINDOW
  108. * UI InputMap.
  109. */
  110. void updateMnemonicBinding(AbstractButton b) {
  111. int m = b.getMnemonic();
  112. if (m != 0) {
  113. InputMap map = SwingUtilities.getUIInputMap(
  114. b, JComponent.WHEN_IN_FOCUSED_WINDOW);
  115. if (map == null) {
  116. map = new ComponentInputMapUIResource(b);
  117. SwingUtilities.replaceUIInputMap(b,
  118. JComponent.WHEN_IN_FOCUSED_WINDOW, map);
  119. }
  120. map.clear();
  121. map.put(KeyStroke.getKeyStroke(m, SynthLookAndFeel.
  122. getAcceleratorModifier(), false), "pressed");
  123. map.put(KeyStroke.getKeyStroke(m, SynthLookAndFeel.
  124. getAcceleratorModifier(), true), "released");
  125. map.put(KeyStroke.getKeyStroke(m, 0, true), "released");
  126. }
  127. else {
  128. InputMap map = SwingUtilities.getUIInputMap(b, JComponent.
  129. WHEN_IN_FOCUSED_WINDOW);
  130. if (map != null) {
  131. map.clear();
  132. }
  133. }
  134. }
  135. public void stateChanged(ChangeEvent e) {
  136. AbstractButton b = (AbstractButton) e.getSource();
  137. b.repaint();
  138. }
  139. public void focusGained(FocusEvent e) {
  140. AbstractButton b = (AbstractButton) e.getSource();
  141. if (defaultButtonFollowsFocus()) {
  142. if (b instanceof JButton && ((JButton)b).isDefaultCapable()) {
  143. JRootPane root = b.getRootPane();
  144. if (root != null) {
  145. JButton defaultButton = root.getDefaultButton();
  146. if (defaultButton != null) {
  147. root.putClientProperty("temporaryDefaultButton", b);
  148. root.setDefaultButton((JButton)b);
  149. root.putClientProperty("temporaryDefaultButton", null);
  150. }
  151. }
  152. }
  153. }
  154. b.repaint();
  155. }
  156. /**
  157. * Returns true if the default button should follow focus, the default.
  158. * A false return value means that the default button is only ever set
  159. * by the developer.
  160. */
  161. protected boolean defaultButtonFollowsFocus() {
  162. // PENDING: this should be a property.
  163. return false;
  164. }
  165. public void focusLost(FocusEvent e) {
  166. AbstractButton b = (AbstractButton) e.getSource();
  167. JRootPane root = b.getRootPane();
  168. if (root != null) {
  169. JButton initialDefault = (JButton)root.getClientProperty("initialDefaultButton");
  170. if (initialDefault != null && b != initialDefault) {
  171. root.setDefaultButton(initialDefault);
  172. }
  173. }
  174. b.getModel().setArmed(false);
  175. b.repaint();
  176. }
  177. public void mouseMoved(MouseEvent e) {
  178. }
  179. public void mouseDragged(MouseEvent e) {
  180. }
  181. public void mouseClicked(MouseEvent e) {
  182. }
  183. public void mousePressed(MouseEvent e) {
  184. if (SwingUtilities.isLeftMouseButton(e) ) {
  185. AbstractButton b = (AbstractButton) e.getSource();
  186. if(b.contains(e.getX(), e.getY())) {
  187. long multiClickThreshhold = b.getMultiClickThreshhold();
  188. long lastTime = lastPressedTimestamp;
  189. long currentTime = lastPressedTimestamp = e.getWhen();
  190. if (lastTime != -1 && currentTime - lastTime < multiClickThreshhold) {
  191. shouldDiscardRelease = true;
  192. return;
  193. }
  194. ButtonModel model = b.getModel();
  195. if (!model.isEnabled()) {
  196. // Disabled buttons ignore all input...
  197. return;
  198. }
  199. if (!model.isArmed()) {
  200. // button not armed, should be
  201. model.setArmed(true);
  202. }
  203. model.setPressed(true);
  204. if(!b.hasFocus() && b.isRequestFocusEnabled()) {
  205. b.requestFocus();
  206. }
  207. }
  208. }
  209. };
  210. public void mouseReleased(MouseEvent e) {
  211. // Support for multiClickThreshhold
  212. if (shouldDiscardRelease) {
  213. shouldDiscardRelease = false;
  214. return;
  215. }
  216. AbstractButton b = (AbstractButton) e.getSource();
  217. ButtonModel model = b.getModel();
  218. model.setPressed(false);
  219. model.setArmed(false);
  220. };
  221. public void mouseEntered(MouseEvent e) {
  222. AbstractButton b = (AbstractButton) e.getSource();
  223. ButtonModel model = b.getModel();
  224. if(b.isRolloverEnabled()) {
  225. model.setRollover(true);
  226. }
  227. if (model.isPressed())
  228. model.setArmed(true);
  229. };
  230. public void mouseExited(MouseEvent e) {
  231. AbstractButton b = (AbstractButton) e.getSource();
  232. ButtonModel model = b.getModel();
  233. if(b.isRolloverEnabled()) {
  234. model.setRollover(false);
  235. }
  236. model.setArmed(false);
  237. };
  238. static class PressedAction extends AbstractAction {
  239. AbstractButton b = null;
  240. PressedAction(AbstractButton b) {
  241. this.b = b;
  242. }
  243. public void actionPerformed(ActionEvent e) {
  244. ButtonModel model = b.getModel();
  245. model.setArmed(true);
  246. model.setPressed(true);
  247. if(!b.hasFocus()) {
  248. b.requestFocus();
  249. }
  250. }
  251. public boolean isEnabled() {
  252. if(!b.getModel().isEnabled()) {
  253. return false;
  254. } else {
  255. return true;
  256. }
  257. }
  258. }
  259. static class ReleasedAction extends AbstractAction {
  260. AbstractButton b = null;
  261. ReleasedAction(AbstractButton b) {
  262. this.b = b;
  263. }
  264. public void actionPerformed(ActionEvent e) {
  265. ButtonModel model = b.getModel();
  266. model.setPressed(false);
  267. model.setArmed(false);
  268. }
  269. public boolean isEnabled() {
  270. if(!b.getModel().isEnabled()) {
  271. return false;
  272. } else {
  273. return true;
  274. }
  275. }
  276. }
  277. }