001/* BasicButtonListener.java -- 002 Copyright (C) 2004, 2005 Free Software Foundation, Inc. 003 004This file is part of GNU Classpath. 005 006GNU Classpath is free software; you can redistribute it and/or modify 007it under the terms of the GNU General Public License as published by 008the Free Software Foundation; either version 2, or (at your option) 009any later version. 010 011GNU Classpath is distributed in the hope that it will be useful, but 012WITHOUT ANY WARRANTY; without even the implied warranty of 013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014General Public License for more details. 015 016You should have received a copy of the GNU General Public License 017along with GNU Classpath; see the file COPYING. If not, write to the 018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 01902110-1301 USA. 020 021Linking this library statically or dynamically with other modules is 022making a combined work based on this library. Thus, the terms and 023conditions of the GNU General Public License cover the whole 024combination. 025 026As a special exception, the copyright holders of this library give you 027permission to link this library with independent modules to produce an 028executable, regardless of the license terms of these independent 029modules, and to copy and distribute the resulting executable under 030terms of your choice, provided that you also meet, for each linked 031independent module, the terms and conditions of the license of that 032module. An independent module is a module which is not derived from 033or based on this library. If you modify this library, you may extend 034this exception to your version of the library, but you are not 035obligated to do so. If you do not wish to do so, delete this 036exception statement from your version. */ 037 038 039package javax.swing.plaf.basic; 040 041import gnu.classpath.SystemProperties; 042 043import java.awt.event.ActionEvent; 044import java.awt.event.FocusEvent; 045import java.awt.event.FocusListener; 046import java.awt.event.MouseEvent; 047import java.awt.event.MouseListener; 048import java.awt.event.MouseMotionListener; 049import java.awt.font.FontRenderContext; 050import java.awt.font.TextLayout; 051import java.awt.geom.AffineTransform; 052import java.beans.PropertyChangeEvent; 053import java.beans.PropertyChangeListener; 054 055import javax.swing.AbstractAction; 056import javax.swing.AbstractButton; 057import javax.swing.Action; 058import javax.swing.ActionMap; 059import javax.swing.ButtonModel; 060import javax.swing.InputMap; 061import javax.swing.JComponent; 062import javax.swing.SwingUtilities; 063import javax.swing.UIManager; 064import javax.swing.event.ChangeEvent; 065import javax.swing.event.ChangeListener; 066import javax.swing.plaf.ActionMapUIResource; 067import javax.swing.plaf.ButtonUI; 068 069public class BasicButtonListener 070 implements MouseListener, MouseMotionListener, FocusListener, ChangeListener, 071 PropertyChangeListener 072{ 073 /** 074 * Implements the keyboard action for Swing buttons. 075 */ 076 private class ButtonAction 077 extends AbstractAction 078 { 079 /** 080 * The key for pressed action. 081 */ 082 static final String PRESSED = "pressed"; 083 084 /** 085 * The key for released action. 086 */ 087 static final String RELEASED = "released"; 088 089 /** 090 * Performs the action. 091 */ 092 public void actionPerformed(ActionEvent event) 093 { 094 Object cmd = getValue("__command__"); 095 AbstractButton b = (AbstractButton) event.getSource(); 096 ButtonModel m = b.getModel(); 097 if (PRESSED.equals(cmd)) 098 { 099 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 */ 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 130 public BasicButtonListener(AbstractButton b) 131 { 132 // Do nothing here. 133 } 134 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 */ 169 protected void checkOpacity(AbstractButton b) 170 { 171 b.setOpaque(b.isContentAreaFilled()); 172 } 173 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 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 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 */ 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 257 public void uninstallKeyboardActions(JComponent c) 258 { 259 SwingUtilities.replaceUIActionMap(c, null); 260 SwingUtilities.replaceUIInputMap(c, JComponent.WHEN_FOCUSED, null); 261 } 262 263 public void stateChanged(ChangeEvent e) 264 { 265 // Need to repaint when the button state changes. 266 ((AbstractButton) e.getSource()).repaint(); 267 } 268 269 public void mouseMoved(MouseEvent e) 270 { 271 // Nothing to do here. 272 } 273 274 public void mouseDragged(MouseEvent e) 275 { 276 // Nothing to do here. 277 } 278 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 */ 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 */ 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 */ 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 */ 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}