001 /*
002 * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package javax.swing.plaf.basic;
027
028 import sun.swing.DefaultLookup;
029 import sun.swing.UIAction;
030 import java.awt.*;
031 import java.awt.event.*;
032 import java.beans.*;
033 import javax.swing.*;
034 import javax.swing.event.*;
035 import javax.swing.plaf.ActionMapUIResource;
036 import javax.swing.plaf.ButtonUI;
037 import javax.swing.plaf.ComponentInputMapUIResource;
038
039 /**
040 * Button Listener
041 *
042 * @version 1.75 05/05/07
043 * @author Jeff Dinkins
044 * @author Arnaud Weber (keyboard UI support)
045 */
046
047 public class BasicButtonListener implements MouseListener,
048 MouseMotionListener, FocusListener, ChangeListener,
049 PropertyChangeListener {
050 private long lastPressedTimestamp = -1;
051 private boolean shouldDiscardRelease = false;
052
053 /**
054 * Populates Buttons actions.
055 */
056 static void loadActionMap(LazyActionMap map) {
057 map.put(new Actions(Actions.PRESS));
058 map.put(new Actions(Actions.RELEASE));
059 }
060
061 public BasicButtonListener(AbstractButton b) {
062 }
063
064 public void propertyChange(PropertyChangeEvent e) {
065 String prop = e.getPropertyName();
066 if (prop == AbstractButton.MNEMONIC_CHANGED_PROPERTY) {
067 updateMnemonicBinding((AbstractButton) e.getSource());
068 } else if (prop == AbstractButton.CONTENT_AREA_FILLED_CHANGED_PROPERTY) {
069 checkOpacity((AbstractButton) e.getSource());
070 } else if (prop == AbstractButton.TEXT_CHANGED_PROPERTY
071 || "font" == prop || "foreground" == prop) {
072 AbstractButton b = (AbstractButton) e.getSource();
073 BasicHTML.updateRenderer(b, b.getText());
074 }
075 }
076
077 protected void checkOpacity(AbstractButton b) {
078 b.setOpaque(b.isContentAreaFilled());
079 }
080
081 /**
082 * Register default key actions: pressing space to "click" a
083 * button and registring the keyboard mnemonic (if any).
084 */
085 public void installKeyboardActions(JComponent c) {
086 AbstractButton b = (AbstractButton) c;
087 // Update the mnemonic binding.
088 updateMnemonicBinding(b);
089
090 LazyActionMap.installLazyActionMap(c,
091 BasicButtonListener.class, "Button.actionMap");
092
093 InputMap km = getInputMap(JComponent.WHEN_FOCUSED, c);
094
095 SwingUtilities
096 .replaceUIInputMap(c, JComponent.WHEN_FOCUSED, km);
097 }
098
099 /**
100 * Unregister's default key actions
101 */
102 public void uninstallKeyboardActions(JComponent c) {
103 SwingUtilities.replaceUIInputMap(c,
104 JComponent.WHEN_IN_FOCUSED_WINDOW, null);
105 SwingUtilities.replaceUIInputMap(c, JComponent.WHEN_FOCUSED,
106 null);
107 SwingUtilities.replaceUIActionMap(c, null);
108 }
109
110 /**
111 * Returns the InputMap for condition <code>condition</code>. Called as
112 * part of <code>installKeyboardActions</code>.
113 */
114 InputMap getInputMap(int condition, JComponent c) {
115 if (condition == JComponent.WHEN_FOCUSED) {
116 BasicButtonUI ui = (BasicButtonUI) BasicLookAndFeel
117 .getUIOfType(((AbstractButton) c).getUI(),
118 BasicButtonUI.class);
119 if (ui != null) {
120 return (InputMap) DefaultLookup.get(c, ui, ui
121 .getPropertyPrefix()
122 + "focusInputMap");
123 }
124 }
125 return null;
126 }
127
128 /**
129 * Resets the binding for the mnemonic in the WHEN_IN_FOCUSED_WINDOW
130 * UI InputMap.
131 */
132 void updateMnemonicBinding(AbstractButton b) {
133 int m = b.getMnemonic();
134 if (m != 0) {
135 InputMap map = SwingUtilities.getUIInputMap(b,
136 JComponent.WHEN_IN_FOCUSED_WINDOW);
137
138 if (map == null) {
139 map = new ComponentInputMapUIResource(b);
140 SwingUtilities.replaceUIInputMap(b,
141 JComponent.WHEN_IN_FOCUSED_WINDOW, map);
142 }
143 map.clear();
144 map.put(KeyStroke.getKeyStroke(m, InputEvent.ALT_MASK,
145 false), "pressed");
146 map.put(KeyStroke
147 .getKeyStroke(m, InputEvent.ALT_MASK, true),
148 "released");
149 map.put(KeyStroke.getKeyStroke(m, 0, true), "released");
150 } else {
151 InputMap map = SwingUtilities.getUIInputMap(b,
152 JComponent.WHEN_IN_FOCUSED_WINDOW);
153 if (map != null) {
154 map.clear();
155 }
156 }
157 }
158
159 public void stateChanged(ChangeEvent e) {
160 AbstractButton b = (AbstractButton) e.getSource();
161 b.repaint();
162 }
163
164 public void focusGained(FocusEvent e) {
165 AbstractButton b = (AbstractButton) e.getSource();
166 if (b instanceof JButton && ((JButton) b).isDefaultCapable()) {
167 JRootPane root = b.getRootPane();
168 if (root != null) {
169 BasicButtonUI ui = (BasicButtonUI) BasicLookAndFeel
170 .getUIOfType(((AbstractButton) b).getUI(),
171 BasicButtonUI.class);
172 if (ui != null
173 && DefaultLookup.getBoolean(b, ui, ui
174 .getPropertyPrefix()
175 + "defaultButtonFollowsFocus", true)) {
176 root.putClientProperty("temporaryDefaultButton", b);
177 root.setDefaultButton((JButton) b);
178 root.putClientProperty("temporaryDefaultButton",
179 null);
180 }
181 }
182 }
183 b.repaint();
184 }
185
186 public void focusLost(FocusEvent e) {
187 AbstractButton b = (AbstractButton) e.getSource();
188 JRootPane root = b.getRootPane();
189 if (root != null) {
190 JButton initialDefault = (JButton) root
191 .getClientProperty("initialDefaultButton");
192 if (b != initialDefault) {
193 BasicButtonUI ui = (BasicButtonUI) BasicLookAndFeel
194 .getUIOfType(((AbstractButton) b).getUI(),
195 BasicButtonUI.class);
196 if (ui != null
197 && DefaultLookup.getBoolean(b, ui, ui
198 .getPropertyPrefix()
199 + "defaultButtonFollowsFocus", true)) {
200 root.setDefaultButton(initialDefault);
201 }
202 }
203 }
204
205 ButtonModel model = b.getModel();
206 model.setArmed(false);
207 model.setPressed(false);
208
209 b.repaint();
210 }
211
212 public void mouseMoved(MouseEvent e) {
213 }
214
215 public void mouseDragged(MouseEvent e) {
216 }
217
218 public void mouseClicked(MouseEvent e) {
219 }
220
221 public void mousePressed(MouseEvent e) {
222 if (SwingUtilities.isLeftMouseButton(e)) {
223 AbstractButton b = (AbstractButton) e.getSource();
224
225 if (b.contains(e.getX(), e.getY())) {
226 long multiClickThreshhold = b.getMultiClickThreshhold();
227 long lastTime = lastPressedTimestamp;
228 long currentTime = lastPressedTimestamp = e.getWhen();
229 if (lastTime != -1
230 && currentTime - lastTime < multiClickThreshhold) {
231 shouldDiscardRelease = true;
232 return;
233 }
234
235 ButtonModel model = b.getModel();
236 if (!model.isEnabled()) {
237 // Disabled buttons ignore all input...
238 return;
239 }
240 if (!model.isArmed()) {
241 // button not armed, should be
242 model.setArmed(true);
243 }
244 model.setPressed(true);
245 if (!b.hasFocus() && b.isRequestFocusEnabled()) {
246 b.requestFocus();
247 }
248 }
249 }
250 };
251
252 public void mouseReleased(MouseEvent e) {
253 if (SwingUtilities.isLeftMouseButton(e)) {
254 // Support for multiClickThreshhold
255 if (shouldDiscardRelease) {
256 shouldDiscardRelease = false;
257 return;
258 }
259 AbstractButton b = (AbstractButton) e.getSource();
260 ButtonModel model = b.getModel();
261 model.setPressed(false);
262 model.setArmed(false);
263 }
264 };
265
266 public void mouseEntered(MouseEvent e) {
267 AbstractButton b = (AbstractButton) e.getSource();
268 ButtonModel model = b.getModel();
269 if (b.isRolloverEnabled()
270 && !SwingUtilities.isLeftMouseButton(e)) {
271 model.setRollover(true);
272 }
273 if (model.isPressed())
274 model.setArmed(true);
275 };
276
277 public void mouseExited(MouseEvent e) {
278 AbstractButton b = (AbstractButton) e.getSource();
279 ButtonModel model = b.getModel();
280 if (b.isRolloverEnabled()) {
281 model.setRollover(false);
282 }
283 model.setArmed(false);
284 };
285
286 /**
287 * Actions for Buttons. Two types of action are supported:
288 * pressed: Moves the button to a pressed state
289 * released: Disarms the button.
290 */
291 private static class Actions extends UIAction {
292 private static final String PRESS = "pressed";
293 private static final String RELEASE = "released";
294
295 Actions(String name) {
296 super (name);
297 }
298
299 public void actionPerformed(ActionEvent e) {
300 AbstractButton b = (AbstractButton) e.getSource();
301 String key = getName();
302 if (key == PRESS) {
303 ButtonModel model = b.getModel();
304 model.setArmed(true);
305 model.setPressed(true);
306 if (!b.hasFocus()) {
307 b.requestFocus();
308 }
309 } else if (key == RELEASE) {
310 ButtonModel model = b.getModel();
311 model.setPressed(false);
312 model.setArmed(false);
313 }
314 }
315
316 public boolean isEnabled(Object sender) {
317 if (sender != null
318 && (sender instanceof AbstractButton)
319 && !((AbstractButton) sender).getModel()
320 .isEnabled()) {
321 return false;
322 } else {
323 return true;
324 }
325 }
326 }
327 }
|