001 /* BasicButtonListener.java -- 002 Copyright (C) 2004, 2005 Free Software Foundation, Inc. 003 004 This file is part of GNU Classpath. 005 006 GNU Classpath is free software; you can redistribute it and/or modify 007 it under the terms of the GNU General Public License as published by 008 the Free Software Foundation; either version 2, or (at your option) 009 any later version. 010 011 GNU Classpath is distributed in the hope that it will be useful, but 012 WITHOUT ANY WARRANTY; without even the implied warranty of 013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 General Public License for more details. 015 016 You should have received a copy of the GNU General Public License 017 along with GNU Classpath; see the file COPYING. If not, write to the 018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 019 02110-1301 USA. 020 021 Linking this library statically or dynamically with other modules is 022 making a combined work based on this library. Thus, the terms and 023 conditions of the GNU General Public License cover the whole 024 combination. 025 026 As a special exception, the copyright holders of this library give you 027 permission to link this library with independent modules to produce an 028 executable, regardless of the license terms of these independent 029 modules, and to copy and distribute the resulting executable under 030 terms of your choice, provided that you also meet, for each linked 031 independent module, the terms and conditions of the license of that 032 module. An independent module is a module which is not derived from 033 or based on this library. If you modify this library, you may extend 034 this exception to your version of the library, but you are not 035 obligated to do so. If you do not wish to do so, delete this 036 exception statement from your version. */ 037 038 039 package javax.swing.plaf.basic; 040 041 import gnu.classpath.SystemProperties; 042 043 import java.awt.event.ActionEvent; 044 import java.awt.event.FocusEvent; 045 import java.awt.event.FocusListener; 046 import java.awt.event.MouseEvent; 047 import java.awt.event.MouseListener; 048 import java.awt.event.MouseMotionListener; 049 import java.awt.font.FontRenderContext; 050 import java.awt.font.TextLayout; 051 import java.awt.geom.AffineTransform; 052 import java.beans.PropertyChangeEvent; 053 import java.beans.PropertyChangeListener; 054 055 import javax.swing.AbstractAction; 056 import javax.swing.AbstractButton; 057 import javax.swing.Action; 058 import javax.swing.ActionMap; 059 import javax.swing.ButtonModel; 060 import javax.swing.InputMap; 061 import javax.swing.JComponent; 062 import javax.swing.SwingUtilities; 063 import javax.swing.UIManager; 064 import javax.swing.event.ChangeEvent; 065 import javax.swing.event.ChangeListener; 066 import javax.swing.plaf.ActionMapUIResource; 067 import javax.swing.plaf.ButtonUI; 068 069 public 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 }