PageRenderTime 50ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-5-pre1/org/gjt/sp/jedit/input/AbstractInputHandler.java

#
Java | 424 lines | 220 code | 46 blank | 158 comment | 25 complexity | 88927f514e4d5523025dbbf77d442efb MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. * AbstractInputHandler.java - Manages key bindings and executes actions
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 2006 Matthieu Casanova
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21. */
  22. package org.gjt.sp.jedit.input;
  23. import org.gjt.sp.jedit.gui.KeyEventTranslator;
  24. import org.gjt.sp.jedit.Debug;
  25. import org.gjt.sp.util.Log;
  26. import java.awt.event.KeyListener;
  27. import java.awt.event.KeyEvent;
  28. import java.util.Hashtable;
  29. import java.util.StringTokenizer;
  30. import org.gjt.sp.jedit.JEditAbstractEditAction;
  31. import org.gjt.sp.jedit.gui.ShortcutPrefixActiveEvent;
  32. /**
  33. * The abstract input handler manage the keyboard handling.
  34. * The entry point is
  35. * {@link #processKeyEvent(java.awt.event.KeyEvent, int, boolean)}
  36. *
  37. * @author Matthieu Casanova
  38. * @version $Id: FoldHandler.java 5568 2006-07-10 20:52:23Z kpouer $
  39. */
  40. public abstract class AbstractInputHandler<E extends JEditAbstractEditAction>
  41. {
  42. protected int lastActionCount;
  43. /** This listener will receive keyboard events if it is not null. */
  44. protected KeyListener keyEventInterceptor;
  45. protected String readNextChar;
  46. protected int repeatCount;
  47. protected E lastAction;
  48. protected static final int REPEAT_COUNT_THRESHOLD = 20;
  49. //{{{ AbstractInputHandler constructor
  50. public AbstractInputHandler()
  51. {
  52. repeatCount = 1;
  53. } //}}}
  54. //{{{ addKeyBinding() method
  55. /**
  56. * Adds a key binding to this input handler. The key binding is
  57. * a list of white space separated key strokes of the form
  58. * <i>[modifiers+]key</i> where modifier is C for Control, A for Alt,
  59. * or S for Shift, and key is either a character (a-z) or a field
  60. * name in the KeyEvent class prefixed with VK_ (e.g., BACK_SPACE)
  61. * @param keyBinding The key binding
  62. * @param action The action
  63. * @since jEdit 4.2pre1
  64. */
  65. public void addKeyBinding(String keyBinding, String action)
  66. {
  67. addKeyBinding(keyBinding,(Object)action);
  68. } //}}}
  69. //{{{ addKeyBinding() method
  70. /**
  71. * Adds a key binding to this input handler. The key binding is
  72. * a list of white space separated key strokes of the form
  73. * <i>[modifiers+]key</i> where modifier is C for Control, A for Alt,
  74. * or S for Shift, and key is either a character (a-z) or a field
  75. * name in the KeyEvent class prefixed with VK_ (e.g., BACK_SPACE)
  76. * @param keyBinding The key binding
  77. * @param action The action
  78. */
  79. public void addKeyBinding(String keyBinding, E action)
  80. {
  81. addKeyBinding(keyBinding,(Object)action);
  82. } //}}}
  83. //{{{ addKeyBinding() method
  84. /**
  85. * Adds a key binding to this input handler. The key binding is
  86. * a list of white space separated key strokes of the form
  87. * <i>[modifiers+]key</i> where modifier is C for Control, A for Alt,
  88. * or S for Shift, and key is either a character (a-z) or a field
  89. * name in the KeyEvent class prefixed with VK_ (e.g., BACK_SPACE)
  90. * @param keyBinding The key binding
  91. * @param action The action
  92. * @since jEdit 4.3pre1
  93. */
  94. public void addKeyBinding(String keyBinding, Object action)
  95. {
  96. Hashtable current = bindings;
  97. String prefixStr = null;
  98. StringTokenizer st = new StringTokenizer(keyBinding);
  99. while(st.hasMoreTokens())
  100. {
  101. String keyCodeStr = st.nextToken();
  102. if(prefixStr == null)
  103. prefixStr = keyCodeStr;
  104. else
  105. prefixStr = prefixStr + " " + keyCodeStr;
  106. KeyEventTranslator.Key keyStroke = KeyEventTranslator.parseKey(keyCodeStr);
  107. if(keyStroke == null)
  108. return;
  109. if(st.hasMoreTokens())
  110. {
  111. Object o = current.get(keyStroke);
  112. if(o instanceof Hashtable)
  113. current = (Hashtable)o;
  114. else
  115. {
  116. Hashtable hash = new Hashtable();
  117. hash.put(PREFIX_STR,prefixStr);
  118. o = hash;
  119. current.put(keyStroke,o);
  120. current = (Hashtable)o;
  121. }
  122. }
  123. else
  124. current.put(keyStroke,action);
  125. }
  126. } //}}}
  127. //{{{ removeKeyBinding() method
  128. /**
  129. * Removes a key binding from this input handler. This is not yet
  130. * implemented.
  131. * @param keyBinding The key binding
  132. */
  133. public void removeKeyBinding(String keyBinding)
  134. {
  135. Hashtable current = bindings;
  136. StringTokenizer st = new StringTokenizer(keyBinding);
  137. while(st.hasMoreTokens())
  138. {
  139. String keyCodeStr = st.nextToken();
  140. KeyEventTranslator.Key keyStroke = KeyEventTranslator.parseKey(keyCodeStr);
  141. if(keyStroke == null)
  142. return;
  143. if(st.hasMoreTokens())
  144. {
  145. Object o = current.get(keyStroke);
  146. if(o instanceof Hashtable)
  147. current = ((Hashtable)o);
  148. else if(o != null)
  149. {
  150. // we have binding foo
  151. // but user asks to remove foo bar?
  152. current.remove(keyStroke);
  153. return;
  154. }
  155. else
  156. {
  157. // user asks to remove non-existent
  158. return;
  159. }
  160. }
  161. else
  162. current.remove(keyStroke);
  163. }
  164. } //}}}
  165. //{{{ removeAllKeyBindings() method
  166. /**
  167. * Removes all key bindings from this input handler.
  168. */
  169. public void removeAllKeyBindings()
  170. {
  171. bindings.clear();
  172. } //}}}
  173. //{{{ getKeyBinding() method
  174. /**
  175. * Returns either an edit action, or a hashtable if the specified key
  176. * is a prefix.
  177. * @param keyBinding The key binding
  178. * @since jEdit 3.2pre5
  179. */
  180. public Object getKeyBinding(String keyBinding)
  181. {
  182. Hashtable current = bindings;
  183. StringTokenizer st = new StringTokenizer(keyBinding);
  184. while(st.hasMoreTokens())
  185. {
  186. KeyEventTranslator.Key keyStroke = KeyEventTranslator.parseKey(
  187. st.nextToken());
  188. if(keyStroke == null)
  189. return null;
  190. if(st.hasMoreTokens())
  191. {
  192. Object o = current.get(keyStroke);
  193. if(o instanceof Hashtable)
  194. {
  195. if(!st.hasMoreTokens())
  196. return o;
  197. else
  198. current = (Hashtable)o;
  199. }
  200. else
  201. return o;
  202. }
  203. else
  204. {
  205. return current.get(keyStroke);
  206. }
  207. }
  208. return null;
  209. } //}}}
  210. //{{{ getLastActionCount() method
  211. /**
  212. * Returns the number of times the last action was executed.
  213. * It can be used with smartHome and smartEnd
  214. * @return the number of times the last action was executed
  215. * @since jEdit 2.5pre5
  216. */
  217. public int getLastActionCount()
  218. {
  219. return lastActionCount;
  220. } //}}}
  221. //{{{ resetLastActionCount() method
  222. /**
  223. * Resets the last action count. This should be called when an
  224. * editing operation that is not an action is invoked, for example
  225. * a mouse click.
  226. * @since jEdit 4.0pre1
  227. */
  228. public void resetLastActionCount()
  229. {
  230. lastActionCount = 0;
  231. } //}}}
  232. //{{{ getKeyEventInterceptor() method
  233. public KeyListener getKeyEventInterceptor()
  234. {
  235. return keyEventInterceptor;
  236. } //}}}
  237. //{{{ setKeyEventInterceptor() method
  238. /**
  239. * Sets the listener that will handle all key events in this
  240. * view. For example, the complete word command uses this so
  241. * that all key events are passed to the word list popup while
  242. * it is visible.
  243. * @param keyEventInterceptor the KeyListener that will receive the events
  244. */
  245. public void setKeyEventInterceptor(KeyListener keyEventInterceptor)
  246. {
  247. this.keyEventInterceptor = keyEventInterceptor;
  248. } //}}}
  249. //{{{ isPrefixActive() method
  250. /**
  251. * Returns if a prefix key has been pressed.
  252. */
  253. public boolean isPrefixActive()
  254. {
  255. return readNextChar != null;
  256. } //}}}
  257. //{{{ setBindings() method
  258. /**
  259. * Replace the set of key bindings.
  260. * @since jEdit 4.3pre1
  261. */
  262. public void setBindings(Hashtable bindings)
  263. {
  264. this.bindings = this.currentBindings = bindings;
  265. } //}}}
  266. //{{{ setCurrentBindings() method
  267. public void setCurrentBindings(Hashtable bindings)
  268. {
  269. currentBindings = bindings;
  270. } //}}}
  271. //{{{ handleKey() method
  272. /**
  273. * Handles a keystroke.
  274. * @param keyStroke The key stroke.
  275. * @param dryRun only calculate the return value, do not have any other effect
  276. * @return true if the input could be handled.
  277. * @since jEdit 4.3pre7
  278. */
  279. public abstract boolean handleKey(KeyEventTranslator.Key keyStroke,boolean dryRun);
  280. //}}}
  281. //{{{ processKeyEvent() method
  282. /**
  283. * Process a keyboard event.
  284. * This is the entry point of the keyboard handling
  285. *
  286. * @param evt the keyboard event
  287. * @param from the source, it can be {@link org.gjt.sp.jedit.View#VIEW},
  288. * {@link org.gjt.sp.jedit.View#ACTION_BAR} or {@link org.gjt.sp.jedit.View#TEXT_AREA}
  289. * @param global tell if the event comes from the DefaultKeyboardFocusManager or not
  290. */
  291. public abstract void processKeyEvent(KeyEvent evt, int from, boolean global);
  292. //}}}
  293. //{{{ sendShortcutPrefixOff() method
  294. protected void sendShortcutPrefixOff()
  295. {
  296. if(shortcutOn)
  297. {
  298. ShortcutPrefixActiveEvent.firePrefixStateChange(null, false);
  299. shortcutOn = false;
  300. }
  301. } //}}}
  302. public abstract void invokeAction(String action);
  303. public abstract void invokeAction(E action);
  304. //{{{ toString() method
  305. /**
  306. * Return a String representation of the keyboard event for
  307. * debugging purpose.
  308. *
  309. * @param evt the keyboard event
  310. * @return a String representation for this keyboard event
  311. * @since jEdit 4.3pre15
  312. */
  313. public static String toString(KeyEvent evt)
  314. {
  315. String id;
  316. switch(evt.getID())
  317. {
  318. case KeyEvent.KEY_PRESSED:
  319. id = "KEY_PRESSED";
  320. break;
  321. case KeyEvent.KEY_RELEASED:
  322. id = "KEY_RELEASED";
  323. break;
  324. case KeyEvent.KEY_TYPED:
  325. id = "KEY_TYPED";
  326. break;
  327. default:
  328. id = "unknown type";
  329. break;
  330. }
  331. StringBuilder b = new StringBuilder(50);
  332. b.append(id);
  333. b.append(",keyCode=0x").append(Integer.toString(evt.getKeyCode(), 16));
  334. b.append(",keyChar=0x").append(Integer.toString(evt.getKeyChar(), 16));
  335. b.append(",modifiers=0x").append(Integer.toString(evt.getModifiers(), 16));
  336. b.append(",consumed=");
  337. b.append(evt.isConsumed()?'1':'0');
  338. return b.toString();
  339. } //}}}
  340. //{{{ processKeyEventKeyStrokeHandling() method
  341. /**
  342. *
  343. * @param evt the keyboard event
  344. * @param from the source, it can be {@link org.gjt.sp.jedit.View#VIEW},
  345. * {@link org.gjt.sp.jedit.View#ACTION_BAR} or {@link org.gjt.sp.jedit.View#TEXT_AREA}
  346. * @param mode the mode is "press" or "type" and is used for debug only
  347. * @param global tell if the event comes from the DefaultKeyboardFocusManager or not
  348. */
  349. protected void processKeyEventKeyStrokeHandling(KeyEvent evt, int from, String mode, boolean global)
  350. {
  351. KeyEventTranslator.Key keyStroke = KeyEventTranslator.translateKeyEvent(evt);
  352. if(keyStroke != null)
  353. {
  354. keyStroke.setIsFromGlobalContext(global);
  355. if(Debug.DUMP_KEY_EVENTS)
  356. {
  357. Log.log(Log.DEBUG,this,"Translated (key "+mode+"): "+keyStroke+" from "+from);
  358. }
  359. boolean consumed = false;
  360. if(handleKey(keyStroke, false))
  361. {
  362. evt.consume();
  363. consumed = true;
  364. }
  365. if(Debug.DUMP_KEY_EVENTS)
  366. {
  367. Log.log(Log.DEBUG,this,"Translated (key "+mode+"): "+keyStroke+" from "+from+": consumed="+consumed+'.');
  368. }
  369. }
  370. } //}}}
  371. //{{{ Private members
  372. // Stores prefix name in bindings hashtable
  373. public static Object PREFIX_STR = "PREFIX_STR";
  374. protected boolean shortcutOn = false;
  375. protected Hashtable bindings;
  376. protected Hashtable currentBindings;
  377. //}}}
  378. }