001: /*
002: * Copyright (C) 2005 - 2008 JasperSoft Corporation. All rights reserved.
003: * http://www.jaspersoft.com.
004: *
005: * Unless you have purchased a commercial license agreement from JasperSoft,
006: * the following license terms apply:
007: *
008: * This program is free software; you can redistribute it and/or modify
009: * it under the terms of the GNU General Public License version 2 as published by
010: * the Free Software Foundation.
011: *
012: * This program is distributed WITHOUT ANY WARRANTY; and without the
013: * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
014: * See the GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, see http://www.gnu.org/licenses/gpl.txt
018: * or write to:
019: *
020: * Free Software Foundation, Inc.,
021: * 59 Temple Place - Suite 330,
022: * Boston, MA USA 02111-1307
023: *
024: *
025: *
026: *
027: * DefaultInputHandler.java
028: *
029: */
030:
031: package org.syntax.jedit;
032:
033: import javax.swing.KeyStroke;
034: import java.awt.event.*;
035: import java.awt.Toolkit;
036: import java.util.Hashtable;
037: import java.util.StringTokenizer;
038:
039: /**
040: * The default input handler. It maps sequences of keystrokes into actions
041: * and inserts key typed events into the text area.
042: * @author Slava Pestov
043: * @version $Id: DefaultInputHandler.java 1167 2008-01-15 18:49:05Z gtoffoli $
044: */
045: public class DefaultInputHandler extends InputHandler {
046: /**
047: * Creates a new input handler with no key bindings defined.
048: */
049: public DefaultInputHandler() {
050: bindings = currentBindings = new Hashtable();
051: }
052:
053: /**
054: * Sets up the default key bindings.
055: */
056: public void addDefaultKeyBindings() {
057: addKeyBinding("BACK_SPACE", BACKSPACE);
058: addKeyBinding("C+BACK_SPACE", BACKSPACE_WORD);
059: addKeyBinding("DELETE", DELETE);
060: addKeyBinding("C+DELETE", DELETE_WORD);
061:
062: addKeyBinding("ENTER", INSERT_BREAK);
063: addKeyBinding("TAB", INSERT_TAB);
064:
065: addKeyBinding("INSERT", OVERWRITE);
066: addKeyBinding("C+\\", TOGGLE_RECT);
067:
068: addKeyBinding("HOME", HOME);
069: addKeyBinding("END", END);
070: addKeyBinding("C+A", SELECT_ALL);
071: addKeyBinding("S+HOME", SELECT_HOME);
072: addKeyBinding("S+END", SELECT_END);
073: addKeyBinding("C+HOME", DOCUMENT_HOME);
074: addKeyBinding("C+END", DOCUMENT_END);
075: addKeyBinding("CS+HOME", SELECT_DOC_HOME);
076: addKeyBinding("CS+END", SELECT_DOC_END);
077:
078: addKeyBinding("PAGE_UP", PREV_PAGE);
079: addKeyBinding("PAGE_DOWN", NEXT_PAGE);
080: addKeyBinding("S+PAGE_UP", SELECT_PREV_PAGE);
081: addKeyBinding("S+PAGE_DOWN", SELECT_NEXT_PAGE);
082:
083: addKeyBinding("LEFT", PREV_CHAR);
084: addKeyBinding("S+LEFT", SELECT_PREV_CHAR);
085: addKeyBinding("C+LEFT", PREV_WORD);
086: addKeyBinding("CS+LEFT", SELECT_PREV_WORD);
087: addKeyBinding("RIGHT", NEXT_CHAR);
088: addKeyBinding("S+RIGHT", SELECT_NEXT_CHAR);
089: addKeyBinding("C+RIGHT", NEXT_WORD);
090: addKeyBinding("CS+RIGHT", SELECT_NEXT_WORD);
091: addKeyBinding("UP", PREV_LINE);
092: addKeyBinding("S+UP", SELECT_PREV_LINE);
093: addKeyBinding("DOWN", NEXT_LINE);
094: addKeyBinding("S+DOWN", SELECT_NEXT_LINE);
095:
096: addKeyBinding("C+ENTER", REPEAT);
097:
098: // Clipboard
099: addKeyBinding("C+C", CLIP_COPY);
100: addKeyBinding("C+V", CLIP_PASTE);
101: addKeyBinding("C+X", CLIP_CUT);
102:
103: addKeyBinding("C+Z", UNDO);
104: addKeyBinding("C+Y", REDO);
105: }
106:
107: /**
108: * Adds a key binding to this input handler. The key binding is
109: * a list of white space separated key strokes of the form
110: * <i>[modifiers+]key</i> where modifier is C for Control, A for Alt,
111: * or S for Shift, and key is either a character (a-z) or a field
112: * name in the KeyEvent class prefixed with VK_ (e.g., BACK_SPACE)
113: * @param keyBinding The key binding
114: * @param action The action
115: */
116: public void addKeyBinding(String keyBinding, ActionListener action) {
117: Hashtable current = bindings;
118:
119: StringTokenizer st = new StringTokenizer(keyBinding);
120: while (st.hasMoreTokens()) {
121: KeyStroke keyStroke = parseKeyStroke(st.nextToken());
122: if (keyStroke == null)
123: return;
124:
125: if (st.hasMoreTokens()) {
126: Object o = current.get(keyStroke);
127: if (o instanceof Hashtable)
128: current = (Hashtable) o;
129: else {
130: o = new Hashtable();
131: current.put(keyStroke, o);
132: current = (Hashtable) o;
133: }
134: } else
135: current.put(keyStroke, action);
136: }
137: }
138:
139: /**
140: * Removes a key binding from this input handler. This is not yet
141: * implemented.
142: * @param keyBinding The key binding
143: */
144: public void removeKeyBinding(String keyBinding) {
145: throw new InternalError("Not yet implemented");
146: }
147:
148: /**
149: * Removes all key bindings from this input handler.
150: */
151: public void removeAllKeyBindings() {
152: bindings.clear();
153: }
154:
155: /**
156: * Returns a copy of this input handler that shares the same
157: * key bindings. Setting key bindings in the copy will also
158: * set them in the original.
159: */
160: public InputHandler copy() {
161: return new DefaultInputHandler(this );
162: }
163:
164: /**
165: * Handle a key pressed event. This will look up the binding for
166: * the key stroke and execute it.
167: */
168: public void keyPressed(KeyEvent evt) {
169: int keyCode = evt.getKeyCode();
170: int modifiers = evt.getModifiers();
171:
172: if (keyCode == KeyEvent.VK_CONTROL
173: || keyCode == KeyEvent.VK_SHIFT
174: || keyCode == KeyEvent.VK_ALT
175: || keyCode == KeyEvent.VK_META)
176: return;
177:
178: if ((modifiers & ~KeyEvent.SHIFT_MASK) != 0
179: || evt.isActionKey()
180: || keyCode == KeyEvent.VK_BACK_SPACE
181: || keyCode == KeyEvent.VK_DELETE
182: || keyCode == KeyEvent.VK_ENTER
183: || keyCode == KeyEvent.VK_TAB
184: || keyCode == KeyEvent.VK_ESCAPE) {
185: if (grabAction != null) {
186: handleGrabAction(evt);
187: return;
188: }
189:
190: KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode,
191: modifiers);
192: Object o = currentBindings.get(keyStroke);
193: if (o == null) {
194: // Don't beep if the user presses some
195: // key we don't know about unless a
196: // prefix is active. Otherwise it will
197: // beep when caps lock is pressed, etc.
198: if (currentBindings != bindings) {
199: Toolkit.getDefaultToolkit().beep();
200: // F10 should be passed on, but C+e F10
201: // shouldn't
202: repeatCount = 0;
203: repeat = false;
204: evt.consume();
205: }
206: currentBindings = bindings;
207: return;
208: } else if (o instanceof ActionListener) {
209: currentBindings = bindings;
210: executeAction(((ActionListener) o), evt.getSource(),
211: null);
212:
213: evt.consume();
214: return;
215: } else if (o instanceof Hashtable) {
216: currentBindings = (Hashtable) o;
217: evt.consume();
218: return;
219: }
220: }
221: }
222:
223: /**
224: * Handle a key typed event. This inserts the key into the text area.
225: */
226: public void keyTyped(KeyEvent evt) {
227: int modifiers = evt.getModifiers();
228: char c = evt.getKeyChar();
229: if (c != KeyEvent.CHAR_UNDEFINED)
230: //&& (modifiers & KeyEvent.ALT_MASK) == 0)
231: {
232: if (c >= 0x20 && c != 0x7f) {
233: KeyStroke keyStroke = KeyStroke.getKeyStroke(Character
234: .toUpperCase(c));
235: Object o = currentBindings.get(keyStroke);
236:
237: if (o instanceof Hashtable) {
238: currentBindings = (Hashtable) o;
239: return;
240: } else if (o instanceof ActionListener) {
241: currentBindings = bindings;
242: executeAction((ActionListener) o, evt.getSource(),
243: String.valueOf(c));
244: return;
245: }
246:
247: currentBindings = bindings;
248:
249: if (grabAction != null) {
250: handleGrabAction(evt);
251: return;
252: }
253:
254: // 0-9 adds another 'digit' to the repeat number
255: if (repeat && Character.isDigit(c)) {
256: repeatCount *= 10;
257: repeatCount += (c - '0');
258: return;
259: }
260:
261: executeAction(INSERT_CHAR, evt.getSource(), String
262: .valueOf(evt.getKeyChar()));
263:
264: repeatCount = 0;
265: repeat = false;
266: }
267: }
268: }
269:
270: /**
271: * Converts a string to a keystroke. The string should be of the
272: * form <i>modifiers</i>+<i>shortcut</i> where <i>modifiers</i>
273: * is any combination of A for Alt, C for Control, S for Shift
274: * or M for Meta, and <i>shortcut</i> is either a single character,
275: * or a keycode name from the <code>KeyEvent</code> class, without
276: * the <code>VK_</code> prefix.
277: * @param keyStroke A string description of the key stroke
278: */
279: public static KeyStroke parseKeyStroke(String keyStroke) {
280: if (keyStroke == null)
281: return null;
282: int modifiers = 0;
283: int index = keyStroke.indexOf('+');
284: if (index != -1) {
285: for (int i = 0; i < index; i++) {
286: switch (Character.toUpperCase(keyStroke.charAt(i))) {
287: case 'A':
288: modifiers |= InputEvent.ALT_MASK;
289: break;
290: case 'C':
291: modifiers |= InputEvent.CTRL_MASK;
292: break;
293: case 'M':
294: modifiers |= InputEvent.META_MASK;
295: break;
296: case 'S':
297: modifiers |= InputEvent.SHIFT_MASK;
298: break;
299: }
300: }
301: }
302: String key = keyStroke.substring(index + 1);
303: if (key.length() == 1) {
304: char ch = Character.toUpperCase(key.charAt(0));
305: if (modifiers == 0)
306: return KeyStroke.getKeyStroke(ch);
307: else
308: return KeyStroke.getKeyStroke(ch, modifiers);
309: } else if (key.length() == 0) {
310: System.err.println("Invalid key stroke: " + keyStroke);
311: return null;
312: } else {
313: int ch;
314:
315: try {
316: ch = KeyEvent.class.getField("VK_".concat(key)).getInt(
317: null);
318: } catch (Exception e) {
319: System.err.println("Invalid key stroke: " + keyStroke);
320: return null;
321: }
322:
323: return KeyStroke.getKeyStroke(ch, modifiers);
324: }
325: }
326:
327: // private members
328: private Hashtable bindings;
329: private Hashtable currentBindings;
330:
331: private DefaultInputHandler(DefaultInputHandler copy) {
332: bindings = currentBindings = copy.bindings;
333: }
334:
335: }
|