Source for javax.swing.plaf.basic.BasicButtonListener

   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:      */
  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:      */
 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: }