KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > rice > cs > drjava > ui > KeyBindingManager


1 /*BEGIN_COPYRIGHT_BLOCK
2  *
3  * This file is part of DrJava. Download the current version of this project from http://www.drjava.org/
4  * or http://sourceforge.net/projects/drjava/
5  *
6  * DrJava Open Source License
7  *
8  * Copyright (C) 2001-2005 JavaPLT group at Rice University (javaplt@rice.edu). All rights reserved.
9  *
10  * Developed by: Java Programming Languages Team, Rice University, http://www.cs.rice.edu/~javaplt/
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
13  * documentation files (the "Software"), to deal with the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
15  * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
16  *
17  * - Redistributions of source code must retain the above copyright notice, this list of conditions and the
18  * following disclaimers.
19  * - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
20  * following disclaimers in the documentation and/or other materials provided with the distribution.
21  * - Neither the names of DrJava, the JavaPLT, Rice University, nor the names of its contributors may be used to
22  * endorse or promote products derived from this Software without specific prior written permission.
23  * - Products derived from this software may not be called "DrJava" nor use the term "DrJava" as part of their
24  * names without prior written permission from the JavaPLT group. For permission, write to javaplt@rice.edu.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
27  * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28  * CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
29  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30  * WITH THE SOFTWARE.
31  *
32  *END_COPYRIGHT_BLOCK*/

33
34 package edu.rice.cs.drjava.ui;
35
36 import edu.rice.cs.drjava.*;
37 import edu.rice.cs.drjava.config.*;
38 import javax.swing.*;
39 import java.util.*;
40 import java.awt.event.*;
41
42 /** Contains Hashtables that are used in the key-binding process along with methods to build them and access their
43   * contents. Performs the assigning of keys to actions, checking for and resolving conflicts, and setting appropriate
44   * menu accelerators.
45   * TODO: fix the design of our key binding scheme. We should be able to bind multiple keys to the same action!
46   * @version $Id: KeyBindingManager.java 4011 2006-09-22 15:31:42Z rcartwright $
47   */

48 public class KeyBindingManager {
49   
50   public static final KeyBindingManager Singleton = new KeyBindingManager();
51
52   private KeyBindingManager() { }
53   
54   // Key-binding configuration tables
55
private Hashtable<KeyStroke, KeyStrokeData> _keyToDataMap = new Hashtable<KeyStroke, KeyStrokeData>();
56   private Hashtable<Action, KeyStrokeData> _actionToDataMap = new Hashtable<Action, KeyStrokeData>();
57
58   private MainFrame _mainFrame = null;
59
60   // Needed to get the DefaultEditorKit actions from their names
61
private ActionMap _actionMap;
62
63   /** Should only check conflicts when the keyboard configuration options are first entered into the maps. Afterwards,
64     * the GUI configuration will warn the user about actions whose key-bindings will be overwritten in the GetKeyDialog,
65     * and the preferences panel will reflect the changes. When the user hit apply, no conflicts should exist in the
66     * preferences panel, and there should be no need to check for conflicts in the configuration.
67     */

68   private boolean _shouldCheckConflict = true;
69
70   public void setMainFrame (MainFrame mainFrame) { _mainFrame = mainFrame; }
71
72   /** Sets the ActionMap
73     * @param actionMap the ActionMap to set to
74     */

75   public void setActionMap (ActionMap actionMap) { _actionMap = actionMap; }
76
77   public void setShouldCheckConflict (boolean bool) { _shouldCheckConflict = bool; }
78   
79   public Enumeration getKeyStrokeData() { return _actionToDataMap.elements(); }
80
81   public void put(Option<KeyStroke> kso, Action a, JMenuItem jmi, String JavaDoc name) {
82     KeyStroke ks = DrJava.getConfig().getSetting(kso);
83     KeyStrokeData ksd = new KeyStrokeData(ks, a, jmi, name, kso);
84     _keyToDataMap.put(ks, ksd);
85     _actionToDataMap.put(a, ksd);
86
87     // check for shift-actions
88
if (kso != null) {
89       DrJava.getConfig().addOptionListener(kso, new KeyStrokeOptionListener(jmi, a, ks));
90     }
91   }
92
93   /** Takes a KeyStroke and gets its Action from the keyToActionMap
94     * @param ks KeyStroke to look up
95     * @return the corresponding Action or null if there is no Action associated with the KeyStroke
96     */

97   public Action get(KeyStroke ks) {
98     KeyStrokeData ksd = _keyToDataMap.get(ks);
99     if (ksd == null) return null;
100     return ksd.getAction();
101   }
102
103   public String JavaDoc getName(KeyStroke ks) {
104     KeyStrokeData ksd = _keyToDataMap.get(ks);
105     if (ksd == null) return null;
106     return ksd.getName();
107   }
108
109   public String JavaDoc getName(Action a) {
110     KeyStrokeData ksd = _actionToDataMap.get(a);
111     if (ksd == null) return null;
112     return ksd.getName();
113   }
114 /*
115  public void addListener(Option<KeyStroke> opt, JMenuItem jmi) {
116     KeyStroke ks = DrJava.getConfig().getSetting(opt);
117     Action a = _keyToActionMap.get(ks);
118     DrJava.getConfig().addOptionListener(opt, new KeyStrokeOptionListener(jmi, a, ks));
119   }
120 */

121   /** Assigns the selection action with the given name to the combination of the shift key and the given key stroke
122     * option. Also adds new KeyStrokOptionListeners to the non-shifted Actions
123     * @param opt the KeyStroke Option of the Action
124     * @param shiftS the name of the Selection Action
125     */

126   public void addShiftAction(Option<KeyStroke> opt, String JavaDoc shiftS) {
127     Action shiftA = _actionMap.get(shiftS);
128     addShiftAction(opt, shiftA);
129   }
130
131   /** Assigns the given selection action to the combination of the shift key and the given key stroke option.
132     * Also adds new KeyStrokOptionListeners to the non-shifted Actions
133     * @param opt the KeyStroke Option of the Action
134     * @param shiftA the Selection Action
135     */

136   public void addShiftAction(Option<KeyStroke> opt, Action shiftA) {
137     KeyStroke ks = DrJava.getConfig().getSetting(opt);
138
139     KeyStrokeData normal = _keyToDataMap.get(ks);
140     normal.setShiftAction(shiftA);
141
142     KeyStrokeData ksd = new KeyStrokeData(addShiftModifier(ks), shiftA, null, "Selection " + normal.getName(), null);
143
144     _keyToDataMap.put(addShiftModifier(ks), ksd);
145     _actionToDataMap.put(shiftA, ksd);
146   }
147
148   /** Takes a KeyStroke and returns a KeyStroke that is the same that has the shift modifier
149     * @param k a KeyStroke
150     * @return the same KeyStorke with the shift modifier
151     */

152   public KeyStroke addShiftModifier(KeyStroke k) {
153     return KeyStroke.getKeyStroke(k.getKeyCode(), k.getModifiers() | InputEvent.SHIFT_MASK, k.isOnKeyRelease() );
154   }
155
156   /** Inserts a KeyStroke/Action pair into the _keyToActionMap. Checks for conflicts and displays an option pane if
157     * they are any.
158     * @param ks the KeyStroke
159     * @param a the Action
160     * @return whether a map insertion was done
161     */

162   //precondition ks != KeyStrokeOption.NULL_KEYSTROKE
163
private boolean shouldUpdate(KeyStroke ks, Action a) {
164     if (ks == KeyStrokeOption.NULL_KEYSTROKE) {
165       // then there should be no keystroke for this action
166
return true;
167     }
168
169     if (!_keyToDataMap.containsKey(ks) ) {
170       // the key is not in the Hashtable, put it in
171
//_keyToActionMap.put(ks, a);
172
//need to update map
173
//KeyStrokeData data = _actionToDataMap.get(a);
174
//data.setKeyStroke(ks);
175
//_keyToDataMap.put(ks,data);
176

177       return true;
178     }
179     else if (_keyToDataMap.get(ks).getAction().equals(a)) {
180       // this KeyStroke/Action pair is already in the Hashtable
181
return false;
182     }
183     else { // key-binding conflict
184
if (_shouldCheckConflict) {
185         KeyStrokeOption opt = new KeyStrokeOption(null,null);
186         KeyStrokeData conflictKSD = _keyToDataMap.get(ks);
187         String JavaDoc key = opt.format(ks);
188         KeyStrokeData newKSD = _actionToDataMap.get(a);
189         String JavaDoc text = "\""+ key +"\"" + " is already assigned to \"" + conflictKSD.getName() +
190           "\".\nWould you like to assign \"" + key + "\" to \"" + newKSD.getName() + "\"?";
191         int rc = JOptionPane.showConfirmDialog(_mainFrame, text, "DrJava", JOptionPane.YES_NO_CANCEL_OPTION);
192
193         switch (rc) {
194           case JOptionPane.YES_OPTION:
195             return true;
196           case JOptionPane.NO_OPTION:
197             return false;
198           case JOptionPane.CLOSED_OPTION:
199             return false;
200           case JOptionPane.CANCEL_OPTION:
201             return false;
202           default:
203             throw new RuntimeException JavaDoc("Invalid rc: " + rc);
204         }
205       }
206       else return true;
207     }
208   }
209
210   /** A listener that can be attached to KeyStrokeOptions that automatically updates the Hashtables in
211     * KeyBindingManager, the corresponding selection Action bindings, and the menu accelerators
212     */

213   public class KeyStrokeOptionListener implements OptionListener<KeyStroke> {
214     protected JMenuItem _jmi; // the JMenuItem associated with this option
215
protected Action _a; // the Action associated with this option
216
protected KeyStroke _ks; // the old KeyStroke value
217

218     public KeyStrokeOptionListener(JMenuItem jmi, Action a, KeyStroke ks) {
219       _jmi = jmi;
220       _a = a;
221       _ks = ks;
222     }
223
224     public KeyStrokeOptionListener(Action a, KeyStroke ks) {
225       _jmi = null;
226       _a = a;
227       _ks = ks;
228     }
229
230     private void _updateMenuItem (KeyStrokeData data) {
231       JMenuItem jmi = data.getJMenuItem();
232
233       //Check associated Menu Item
234
// If jmi is null, this keystroke maps to an action that isn't in the menu
235
if (jmi != null) {
236         KeyStroke ks = data.getKeyStroke();
237         if (ks != KeyStrokeOption.NULL_KEYSTROKE) {
238           // If ks is NULL_KEYSTROKE, we don't want it "active", since some
239
// Windows keys generate NULL_KEYSTROKE
240
jmi.setAccelerator(ks);
241         }
242         else {
243           // Clear the menu item's accelerator
244
jmi.setAccelerator(null);
245         }
246       }
247     }
248
249     public void optionChanged(OptionEvent<KeyStroke> oce) {
250       if (shouldUpdate(oce.value, _a))
251       {
252         KeyStrokeData data = _actionToDataMap.get(_a);
253         if (data == null) {
254           // Nothing to change
255
return;
256         }
257
258         // Only remove the old keystroke from the map if it is currently mapped to our data. If not, our old
259
// keystroke has already been redefined and should not be removed!
260
if (data.equals(_keyToDataMap.get(_ks))) {
261           _keyToDataMap.remove(_ks);
262         }
263
264         //check for conflicting key binding
265
if (_keyToDataMap.containsKey(oce.value) && _shouldCheckConflict) {
266           //if new key in map, and shouldUpdate returns true, we are overwriting it
267
KeyStrokeData conflictKSD = _keyToDataMap.get(oce.value);
268           conflictKSD.setKeyStroke(KeyStrokeOption.NULL_KEYSTROKE);
269           _updateMenuItem(conflictKSD);
270           _keyToDataMap.remove(oce.value);
271           DrJava.getConfig().setSetting(conflictKSD.getOption(), KeyStrokeOption.NULL_KEYSTROKE);
272         }
273
274         if (oce.value != KeyStrokeOption.NULL_KEYSTROKE) {
275           _keyToDataMap.put(oce.value,data);
276         }
277         data.setKeyStroke(oce.value);
278         _updateMenuItem(data);
279
280         //Check associated shift-version's binding
281
Action shiftAction = data.getShiftAction();
282         if (shiftAction != null) {
283           //_keyToActionMap.remove(addShiftModifier(_ks));
284
KeyStrokeData shiftKSD = _actionToDataMap.get(shiftAction);
285           _keyToDataMap.remove(shiftKSD.getKeyStroke());
286           shiftKSD.setKeyStroke(addShiftModifier(oce.value));
287           _keyToDataMap.put(shiftKSD.getKeyStroke(), shiftKSD);
288           //mapInsert(addShiftModifier(oce.value), shiftAction);
289
}
290
291         _ks = oce.value;
292       }
293       else if (_ks != oce.value) {
294         DrJava.getConfig().setSetting(oce.option, _ks);
295       }
296     }
297   }
298
299   public static class KeyStrokeData {
300     private KeyStroke _ks;
301     private Action _a;
302     private JMenuItem _jmi;
303     private String JavaDoc _name;
304     private Option<KeyStroke> _kso;
305     private Action _shiftA;
306
307     public KeyStrokeData(KeyStroke ks, Action a, JMenuItem jmi, String JavaDoc name, Option<KeyStroke> kso) {
308       _ks = ks;
309       _a = a;
310       _jmi = jmi;
311       _name = name;
312       _kso = kso;
313       _shiftA = null;
314     }
315
316     public KeyStroke getKeyStroke() { return _ks; }
317     public Action getAction() { return _a; }
318     public JMenuItem getJMenuItem() { return _jmi; }
319     public String JavaDoc getName() { return _name; }
320     public Option<KeyStroke> getOption() { return _kso; }
321     public Action getShiftAction() { return _shiftA; }
322     
323     public void setKeyStroke(KeyStroke ks) { _ks = ks; }
324     public void setAction(Action a) { _a = a; }
325     public void setJMenuItem(JMenuItem jmi) { _jmi = jmi; }
326     public void setName(String JavaDoc name) { _name = name; }
327     public void setOption(Option<KeyStroke> kso) { _kso = kso; }
328     public void setShiftAction(Action shiftA) { _shiftA = shiftA; }
329   }
330 }
331
Popular Tags