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