1 /* BasicButtonListener.java -- 2 Copyright (C) 2004, 2005 Free Software Foundation, Inc. 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 02110-1301 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 39 package javax.swing.plaf.basic; 40 41 import gnu.classpath.SystemProperties; 42 43 import java.awt.event.ActionEvent; 44 import java.awt.event.FocusEvent; 45 import java.awt.event.FocusListener; 46 import java.awt.event.MouseEvent; 47 import java.awt.event.MouseListener; 48 import java.awt.event.MouseMotionListener; 49 import java.awt.font.FontRenderContext; 50 import java.awt.font.TextLayout; 51 import java.awt.geom.AffineTransform; 52 import java.beans.PropertyChangeEvent; 53 import java.beans.PropertyChangeListener; 54 55 import javax.swing.AbstractAction; 56 import javax.swing.AbstractButton; 57 import javax.swing.Action; 58 import javax.swing.ActionMap; 59 import javax.swing.ButtonModel; 60 import javax.swing.InputMap; 61 import javax.swing.JComponent; 62 import javax.swing.SwingUtilities; 63 import javax.swing.UIManager; 64 import javax.swing.event.ChangeEvent; 65 import javax.swing.event.ChangeListener; 66 import javax.swing.plaf.ActionMapUIResource; 67 import javax.swing.plaf.ButtonUI; 68 69 public class BasicButtonListener 70 implements MouseListener, MouseMotionListener, FocusListener, ChangeListener, 71 PropertyChangeListener 72 { 73 /** 74 * Implements the keyboard action for Swing buttons. 75 */ 76 private class ButtonAction 77 extends AbstractAction 78 { 79 /** 80 * The key for pressed action. 81 */ 82 static final String PRESSED = "pressed"; 83 84 /** 85 * The key for released action. 86 */ 87 static final String RELEASED = "released"; 88 89 /** 90 * Performs the action. 91 */ actionPerformed(ActionEvent event)92 public void actionPerformed(ActionEvent event) 93 { 94 Object cmd = getValue("__command__"); 95 AbstractButton b = (AbstractButton) event.getSource(); 96 ButtonModel m = b.getModel(); 97 if (PRESSED.equals(cmd)) 98 { 99 m.setArmed(true); 100 m.setPressed(true); 101 if (! b.isFocusOwner()) 102 b.requestFocus(); 103 } 104 else if (RELEASED.equals(cmd)) 105 { 106 m.setPressed(false); 107 m.setArmed(false); 108 } 109 } 110 111 /** 112 * Indicates if this action is enabled. 113 * 114 * @param source the source of the action 115 * 116 * @return <code>true</code> when enabled, <code>false</code> otherwise 117 */ isEnabled(Object source)118 public boolean isEnabled(Object source) 119 { 120 boolean enabled = true; 121 if (source instanceof AbstractButton) 122 { 123 AbstractButton b = (AbstractButton) source; 124 enabled = b.isEnabled(); 125 } 126 return enabled; 127 } 128 } 129 BasicButtonListener(AbstractButton b)130 public BasicButtonListener(AbstractButton b) 131 { 132 // Do nothing here. 133 } 134 propertyChange(PropertyChangeEvent e)135 public void propertyChange(PropertyChangeEvent e) 136 { 137 // Store the TextLayout for this in a client property for speed-up 138 // painting of the label. 139 String property = e.getPropertyName(); 140 AbstractButton b = (AbstractButton) e.getSource(); 141 if ((property.equals(AbstractButton.TEXT_CHANGED_PROPERTY) 142 || property.equals("font")) 143 && SystemProperties.getProperty("gnu.javax.swing.noGraphics2D") 144 == null) 145 { 146 String text = b.getText(); 147 if (text == null) 148 text = ""; 149 FontRenderContext frc = new FontRenderContext(new AffineTransform(), 150 false, false); 151 TextLayout layout = new TextLayout(text, b.getFont(), frc); 152 b.putClientProperty(BasicGraphicsUtils.CACHED_TEXT_LAYOUT, layout); 153 154 // Update HTML renderer. 155 BasicHTML.updateRenderer(b, b.getText()); 156 } 157 else if (property.equals(AbstractButton.CONTENT_AREA_FILLED_CHANGED_PROPERTY)) 158 { 159 checkOpacity(b); 160 } 161 } 162 163 /** 164 * Checks the <code>contentAreaFilled</code> property and updates the 165 * opaque property of the button. 166 * 167 * @param b the button to check 168 */ checkOpacity(AbstractButton b)169 protected void checkOpacity(AbstractButton b) 170 { 171 b.setOpaque(b.isContentAreaFilled()); 172 } 173 focusGained(FocusEvent e)174 public void focusGained(FocusEvent e) 175 { 176 if (e.getSource() instanceof AbstractButton) 177 { 178 AbstractButton button = (AbstractButton) e.getSource(); 179 if (button.isFocusPainted()) 180 button.repaint(); 181 } 182 } 183 focusLost(FocusEvent e)184 public void focusLost(FocusEvent e) 185 { 186 if (e.getSource() instanceof AbstractButton) 187 { 188 AbstractButton button = (AbstractButton) e.getSource(); 189 if (button.isFocusPainted()) 190 button.repaint(); 191 } 192 } 193 installKeyboardActions(JComponent c)194 public void installKeyboardActions(JComponent c) 195 { 196 ButtonUI ui = ((AbstractButton) c).getUI(); 197 if (ui instanceof BasicButtonUI) 198 { 199 // Install InputMap. 200 BasicButtonUI basicUI = (BasicButtonUI) ui; 201 String prefix = basicUI.getPropertyPrefix(); 202 InputMap focusInputMap = 203 (InputMap) UIManager.get(prefix + "focusInputMap"); 204 SwingUtilities.replaceUIInputMap(c, JComponent.WHEN_FOCUSED, 205 focusInputMap); 206 207 ActionMap am = (ActionMap) UIManager.get(prefix + "actionMap"); 208 if (am == null) 209 { 210 am = createDefaultActionMap(); 211 UIManager.put(prefix + "actionMap", am); 212 } 213 SwingUtilities.replaceUIActionMap(c, am); 214 } 215 216 c.getActionMap().put("pressed", 217 new AbstractAction() 218 { 219 public void actionPerformed(ActionEvent e) 220 { 221 AbstractButton button = (AbstractButton) e.getSource(); 222 ButtonModel model = button.getModel(); 223 // It is important that these transitions happen in this order. 224 model.setArmed(true); 225 model.setPressed(true); 226 } 227 }); 228 229 c.getActionMap().put("released", 230 new AbstractAction() 231 { 232 public void actionPerformed(ActionEvent e) 233 { 234 AbstractButton button = (AbstractButton) e.getSource(); 235 ButtonModel model = button.getModel(); 236 // It is important that these transitions happen in this order. 237 model.setPressed(false); 238 model.setArmed(false); 239 } 240 }); 241 } 242 243 /** 244 * Creates and returns the default action map for Swing buttons. 245 * 246 * @return the default action map for Swing buttons 247 */ createDefaultActionMap()248 private ActionMap createDefaultActionMap() 249 { 250 Action action = new ButtonAction(); 251 ActionMapUIResource am = new ActionMapUIResource(); 252 am.put(ButtonAction.PRESSED, action); 253 am.put(ButtonAction.RELEASED, action); 254 return am; 255 } 256 uninstallKeyboardActions(JComponent c)257 public void uninstallKeyboardActions(JComponent c) 258 { 259 SwingUtilities.replaceUIActionMap(c, null); 260 SwingUtilities.replaceUIInputMap(c, JComponent.WHEN_FOCUSED, null); 261 } 262 stateChanged(ChangeEvent e)263 public void stateChanged(ChangeEvent e) 264 { 265 // Need to repaint when the button state changes. 266 ((AbstractButton) e.getSource()).repaint(); 267 } 268 mouseMoved(MouseEvent e)269 public void mouseMoved(MouseEvent e) 270 { 271 // Nothing to do here. 272 } 273 mouseDragged(MouseEvent e)274 public void mouseDragged(MouseEvent e) 275 { 276 // Nothing to do here. 277 } 278 mouseClicked(MouseEvent e)279 public void mouseClicked(MouseEvent e) 280 { 281 // Nothing to do here. 282 } 283 284 /** 285 * Accept a mouse press event and arm the button. 286 * 287 * @param e The mouse press event to accept 288 */ mousePressed(MouseEvent e)289 public void mousePressed(MouseEvent e) 290 { 291 if (e.getSource() instanceof AbstractButton) 292 { 293 AbstractButton button = (AbstractButton) e.getSource(); 294 ButtonModel model = button.getModel(); 295 if (SwingUtilities.isLeftMouseButton(e)) 296 { 297 // It is important that these transitions happen in this order. 298 model.setArmed(true); 299 model.setPressed(true); 300 301 if (! button.isFocusOwner() && button.isRequestFocusEnabled()) 302 button.requestFocus(); 303 } 304 } 305 } 306 307 /** 308 * Accept a mouse release event and set the button's 309 * "pressed" property to <code>true</code>, if the model 310 * is armed. If the model is not armed, ignore the event. 311 * 312 * @param e The mouse release event to accept 313 */ mouseReleased(MouseEvent e)314 public void mouseReleased(MouseEvent e) 315 { 316 if (e.getSource() instanceof AbstractButton) 317 { 318 AbstractButton button = (AbstractButton) e.getSource(); 319 ButtonModel model = button.getModel(); 320 if (e.getButton() == MouseEvent.BUTTON1) 321 { 322 // It is important that these transitions happen in this order. 323 model.setPressed(false); 324 model.setArmed(false); 325 } 326 } 327 } 328 329 /** 330 * Accept a mouse enter event and set the button's "rollover" property to 331 * <code>true</code>, if the button's "rolloverEnabled" property is 332 * <code>true</code>. If the button is currently armed and the mouse 333 * button is not held down, this enter event will also disarm the model. 334 * 335 * @param e The mouse enter event to accept 336 */ mouseEntered(MouseEvent e)337 public void mouseEntered(MouseEvent e) 338 { 339 if (e.getSource() instanceof AbstractButton) 340 { 341 AbstractButton button = (AbstractButton) e.getSource(); 342 ButtonModel model = button.getModel(); 343 if (button.isRolloverEnabled() 344 && ! SwingUtilities.isLeftMouseButton(e)) 345 model.setRollover(true); 346 347 if (model.isPressed()) 348 model.setArmed(true); 349 } 350 } 351 352 /** 353 * Accept a mouse exit event and set the button's model's "rollover" 354 * property to <code>false</code>, if it's "rolloverEnabled" property is 355 * <code>true</code>. Also disarm the button. 356 * 357 * @param e The mouse exit event to accept 358 */ mouseExited(MouseEvent e)359 public void mouseExited(MouseEvent e) 360 { 361 if (e.getSource() instanceof AbstractButton) 362 { 363 AbstractButton button = (AbstractButton) e.getSource(); 364 ButtonModel model = button.getModel(); 365 if (button.isRolloverEnabled()) 366 model.setRollover(false); 367 model.setArmed(false); 368 } 369 } 370 } 371