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 }