JAL-1807 Bob's JalviewJS prototype first commit
[jalviewjs.git] / site / j2s / swingjs / plaf / JSButtonListener.java
1 /*
2  * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25
26 package swingjs.plaf;
27
28 import jsjava.awt.event.ActionEvent;
29 import jsjava.awt.event.FocusEvent;
30 import jsjava.awt.event.FocusListener;
31 import jsjava.awt.event.InputEvent;
32 import jsjava.awt.event.MouseEvent;
33 import jsjava.awt.event.MouseListener;
34 import jsjava.awt.event.MouseMotionListener;
35 import jsjava.beans.PropertyChangeEvent;
36 import jsjava.beans.PropertyChangeListener;
37 import jsjavax.swing.AbstractButton;
38 import jsjavax.swing.ButtonModel;
39 import jsjavax.swing.InputMap;
40 import jsjavax.swing.JComponent;
41 import jsjavax.swing.KeyStroke;
42 import jsjavax.swing.SwingUtilities;
43 import jsjavax.swing.event.ChangeEvent;
44 import jsjavax.swing.event.ChangeListener;
45 import jsjavax.swing.plaf.ComponentInputMapUIResource;
46 import jsjavax.swing.plaf.ComponentUI;
47 import jssun.swing.UIAction;
48
49 /**
50  * Button Listener
51  *
52  * @author Jeff Dinkins
53  * @author Arnaud Weber (keyboard UI support)
54  */
55
56 public class JSButtonListener implements MouseListener, MouseMotionListener,
57                                    FocusListener, ChangeListener, PropertyChangeListener
58 {
59     private long lastPressedTimestamp = -1;
60     private boolean shouldDiscardRelease = false;
61                 private AbstractButton btn;
62
63     /**
64      * Populates Buttons actions.
65      */
66     static void loadActionMap(LazyActionMap map) {
67         map.put(new Actions(Actions.PRESS));
68         map.put(new Actions(Actions.RELEASE));
69     }
70
71
72     public JSButtonListener(AbstractButton b) {
73         btn = b;
74     }
75
76         public void propertyChange(PropertyChangeEvent e) {
77                 String prop = e.getPropertyName();
78                 //System.out.println("JSButtonListener property change: " + prop + " " + e.getSource());
79                 if (prop == AbstractButton.MNEMONIC_CHANGED_PROPERTY) {
80                         updateMnemonicBinding((AbstractButton) e.getSource());
81                 } else if (prop == AbstractButton.CONTENT_AREA_FILLED_CHANGED_PROPERTY) {
82                         checkOpacity((AbstractButton) e.getSource());
83                 } else if (prop == AbstractButton.TEXT_CHANGED_PROPERTY || "font" == prop
84                                 || "foreground" == prop) {
85                         AbstractButton b = (AbstractButton) e.getSource();
86                         ((JSComponentUI) (Object) b.getUI()).notifyPropertyChanged(prop);
87                 }
88         }
89
90     protected void checkOpacity(AbstractButton b) {
91         b.setOpaque( b.isContentAreaFilled() );
92     }
93
94     /**
95      * Register default key actions: pressing space to "click" a
96      * button and registring the keyboard mnemonic (if any).
97      */
98     public void installKeyboardActions(JComponent c) {
99         AbstractButton b = (AbstractButton)c;
100         // Update the mnemonic binding.
101         updateMnemonicBinding(b);
102
103         LazyActionMap.installLazyActionMap(c, JSButtonListener.class,
104                                            "Button.actionMap");
105
106         InputMap km = getInputMap(JComponent.WHEN_FOCUSED, c);
107
108         SwingUtilities.replaceUIInputMap(c, JComponent.WHEN_FOCUSED, km);
109     }
110
111     /**
112      * Unregister's default key actions
113      */
114     public void uninstallKeyboardActions(JComponent c) {
115         SwingUtilities.replaceUIInputMap(c, JComponent.
116                                          WHEN_IN_FOCUSED_WINDOW, null);
117         SwingUtilities.replaceUIInputMap(c, JComponent.WHEN_FOCUSED, null);
118         SwingUtilities.replaceUIActionMap(c, null);
119     }
120
121     /**
122      * Returns the InputMap for condition <code>condition</code>. Called as
123      * part of <code>installKeyboardActions</code>.
124      */
125     InputMap getInputMap(int condition, JComponent c) {
126 //        if (condition == JComponent.WHEN_FOCUSED) {
127 //            BasicButtonUI ui = (BasicButtonUI)BasicLookAndFeel.getUIOfType(
128 //                         ((AbstractButton)c).getUI(), BasicButtonUI.class);
129 //            if (ui != null) {
130 //                return (InputMap)DefaultLookup.get(
131 //                             c, ui, ui.getPropertyPrefix() + "focusInputMap");
132 //            }
133 //        }
134         return null;
135     }
136
137     /**
138      * Resets the binding for the mnemonic in the WHEN_IN_FOCUSED_WINDOW
139      * UI InputMap.
140      */
141     void updateMnemonicBinding(AbstractButton b) {
142         int m = b.getMnemonic();
143         if(m != 0) {
144             InputMap map = SwingUtilities.getUIInputMap(
145                                 b, JComponent.WHEN_IN_FOCUSED_WINDOW);
146
147             if (map == null) {
148                 map = new ComponentInputMapUIResource(b);
149                 SwingUtilities.replaceUIInputMap(b,
150                                JComponent.WHEN_IN_FOCUSED_WINDOW, map);
151             }
152             map.clear();
153             map.put(KeyStroke.getKeyStroke(m, InputEvent.ALT_MASK, false),
154                     "pressed");
155             map.put(KeyStroke.getKeyStroke(m, InputEvent.ALT_MASK, true),
156                     "released");
157             map.put(KeyStroke.getKeyStroke(m, 0, true), "released");
158         }
159         else {
160             InputMap map = SwingUtilities.getUIInputMap(b, JComponent.
161                                              WHEN_IN_FOCUSED_WINDOW);
162             if (map != null) {
163                 map.clear();
164             }
165         }
166     }
167
168     public void stateChanged(ChangeEvent e) {
169         AbstractButton b = (AbstractButton) e.getSource();
170         b.repaint();
171     }
172
173     public void focusGained(FocusEvent e) {
174 //        AbstractButton b = (AbstractButton) e.getSource();
175 //        if (b instanceof JButton && ((JButton)b).isDefaultCapable()) {
176 //            JRootPane root = b.getRootPane();
177 //            if (root != null) {
178 //               BasicButtonUI ui = (BasicButtonUI)BasicLookAndFeel.getUIOfType(
179 //                         ((AbstractButton)b).getUI(), BasicButtonUI.class);
180 //               if (ui != null && DefaultLookup.getBoolean(b, ui,
181 //                                   ui.getPropertyPrefix() +
182 //                                   "defaultButtonFollowsFocus", true)) {
183 //                   root.putClientProperty("temporaryDefaultButton", b);
184 //                   root.setDefaultButton((JButton)b);
185 //                   root.putClientProperty("temporaryDefaultButton", null);
186 //               }
187 //            }
188 //        }
189 //        b.repaint();
190     }
191
192     public void focusLost(FocusEvent e) {
193         AbstractButton b = (AbstractButton) e.getSource();
194 //        JRootPane root = b.getRootPane();
195 //        if (root != null) {
196 //           JButton initialDefault = (JButton)root.getClientProperty("initialDefaultButton");
197 //           if (b != initialDefault) {
198 //               BasicButtonUI ui = (BasicButtonUI)BasicLookAndFeel.getUIOfType(
199 //                         ((AbstractButton)b).getUI(), BasicButtonUI.class);
200 //               if (ui != null && DefaultLookup.getBoolean(b, ui,
201 //                                   ui.getPropertyPrefix() +
202 //                                   "defaultButtonFollowsFocus", true)) {
203 //                   root.setDefaultButton(initialDefault);
204 //               }
205 //           }
206 //        }
207 //
208         ButtonModel model = b.getModel();
209         model.setArmed(false);
210         model.setPressed(false);
211 //
212 //        b.repaint();
213     }
214
215     public void mouseMoved(MouseEvent e) {
216     }
217
218
219     public void mouseDragged(MouseEvent e) {
220     }
221
222     public void mouseClicked(MouseEvent e) {
223     }
224
225         public void mousePressed(MouseEvent e) {
226                 if (SwingUtilities.isLeftMouseButton(e)) {
227                         AbstractButton b = (AbstractButton) e.getSource();
228                         if (!b.contains(e.getX(), e.getY()))
229                                 return;
230                         // We need to check the state before and after the button click 
231                         // for radio and checkboxes to make sure the DOM button actually got hit.
232                         // mousePress is an "arm"; mouseRelease is a "click"
233                         
234                         ((JSButtonUI) (ComponentUI) b.getUI()).verifyButtonClick(false);
235                         long multiClickThreshhold = b.getMultiClickThreshhold();
236                         long lastTime = lastPressedTimestamp;
237                         long currentTime = lastPressedTimestamp = e.getWhen();
238                         if (lastTime != -1 && currentTime - lastTime < multiClickThreshhold) {
239                                 shouldDiscardRelease = true;
240                                 return;
241                         }
242
243                         //System.out.println("JSButtonListener press " + b.getName() + " " + e);
244
245                         ButtonModel model = b.getModel();
246                         if (!model.isEnabled()) {
247                                 // Disabled buttons ignore all input...
248                                 return;
249                         }
250                         if (!model.isArmed()) {
251                                 // button not armed, should be
252                                 model.setArmed(true);
253                         }
254                         model.setPressed(true);
255                         if (!b.hasFocus() && b.isRequestFocusEnabled()) {
256                                 b.requestFocus();
257                         }
258                 }
259         };
260
261     public void mouseReleased(MouseEvent e) {
262         if (SwingUtilities.isLeftMouseButton(e)) {
263             // Support for multiClickThreshhold
264             if (shouldDiscardRelease) {
265                 shouldDiscardRelease = false;
266                 return;
267             }
268             AbstractButton b = (AbstractButton) e.getSource();
269                         if (!((JSButtonUI) (ComponentUI) b.getUI()).verifyButtonClick(true))
270                                 return;
271                         
272                         //System.out.println("JSButtonListener released " + b.getName() + " " + e);
273
274             ButtonModel model = b.getModel();
275             model.setPressed(false);
276             model.setArmed(false);
277         }
278     };
279
280     public void mouseEntered(MouseEvent e) {
281         AbstractButton b = (AbstractButton) e.getSource();
282         ButtonModel model = b.getModel();
283         if (b.isRolloverEnabled() && !SwingUtilities.isLeftMouseButton(e)) {
284             model.setRollover(true);
285         }
286         if (model.isPressed())
287                 model.setArmed(true);
288     };
289
290     public void mouseExited(MouseEvent e) {
291         AbstractButton b = (AbstractButton) e.getSource();
292         ButtonModel model = b.getModel();
293         if(b.isRolloverEnabled()) {
294             model.setRollover(false);
295         }
296         model.setArmed(false);
297     };
298
299
300     /**
301      * Actions for Buttons. Two types of action are supported:
302      * pressed: Moves the button to a pressed state
303      * released: Disarms the button.
304      */
305     private static class Actions extends UIAction {
306         private static final String PRESS = "pressed";
307         private static final String RELEASE = "released";
308
309         Actions(String name) {
310             super(name);
311         }
312
313         public void actionPerformed(ActionEvent e) {
314             AbstractButton b = (AbstractButton)e.getSource();
315             String key = getName();
316             if (key == PRESS) {
317                 ButtonModel model = b.getModel();
318                 model.setArmed(true);
319                 model.setPressed(true);
320                 if(!b.hasFocus()) {
321                     b.requestFocus();
322                 }
323             }
324             else if (key == RELEASE) {
325                 ButtonModel model = b.getModel();
326                 model.setPressed(false);
327                 model.setArmed(false);
328             }
329         }
330
331         public boolean isEnabled(Object sender) {
332             if(sender != null && (sender instanceof AbstractButton) &&
333                       !((AbstractButton)sender).getModel().isEnabled()) {
334                 return false;
335             } else {
336                 return true;
337             }
338         }
339     }
340 }
341