PageRenderTime 38ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

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

#
Java | 382 lines | 245 code | 38 blank | 99 comment | 62 complexity | 131a069ceb51bd04e594ab9034d929a1 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. * TextAreaInputHandler.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. //{{{ Imports
  24. import org.gjt.sp.jedit.Debug;
  25. import org.gjt.sp.jedit.gui.KeyEventTranslator;
  26. import org.gjt.sp.jedit.gui.KeyEventWorkaround;
  27. import org.gjt.sp.jedit.textarea.TextArea;
  28. import org.gjt.sp.util.Log;
  29. import org.gjt.sp.util.StandardUtilities;
  30. import java.awt.*;
  31. import java.awt.event.KeyEvent;
  32. import java.util.Hashtable;
  33. import org.gjt.sp.jedit.JEditBeanShellAction;
  34. import org.gjt.sp.jedit.buffer.JEditBuffer;
  35. import org.gjt.sp.jedit.gui.ShortcutPrefixActiveEvent;
  36. //}}}
  37. /**
  38. * This class manage the key bindings and execute the actions binded on the
  39. * keyboard events for the standalone textarea.
  40. *
  41. * @author Matthieu Casanova
  42. * @version $Id: FoldHandler.java 5568 2006-07-10 20:52:23Z kpouer $
  43. */
  44. public abstract class TextAreaInputHandler extends AbstractInputHandler<JEditBeanShellAction>
  45. {
  46. private final TextArea textArea;
  47. //{{{ TextAreaInputHandler constructor
  48. protected TextAreaInputHandler(TextArea textArea)
  49. {
  50. this.textArea = textArea;
  51. bindings = currentBindings = new Hashtable();
  52. } //}}}
  53. //{{{ processKeyEvent() method
  54. /**
  55. * Forwards key events directly to the input handler.
  56. * This is slightly faster than using a KeyListener
  57. * because some Swing overhead is avoided.
  58. * @param evt the keyboard event
  59. * @param from the source of the event. Since this is the input handler of the textarea, it should always be 1
  60. * @param global it is only true if the event comes from the DefaultKeyboardFocusManager
  61. * @since 4.3pre7
  62. */
  63. @Override
  64. public void processKeyEvent(KeyEvent evt, int from, boolean global)
  65. {
  66. if(Debug.DUMP_KEY_EVENTS)
  67. {
  68. Log.log(Log.DEBUG,this,"Key event : "
  69. + toString(evt) + " from " + from);
  70. // Log.log(Log.DEBUG,this,view+".isFocused()="+view.isFocused()+'.',new Exception());
  71. }
  72. evt = _preprocessKeyEvent(evt);
  73. if(evt == null)
  74. return;
  75. if(Debug.DUMP_KEY_EVENTS)
  76. {
  77. Log.log(Log.DEBUG,this,"Key event after workaround: "
  78. + toString(evt) + " from " + from);
  79. }
  80. boolean focusOnTextArea = false;
  81. switch(evt.getID())
  82. {
  83. case KeyEvent.KEY_TYPED:
  84. // if the user pressed eg C+e n n in the
  85. // search bar we want focus to go back there
  86. // after the prefix is done
  87. if(keyEventInterceptor != null)
  88. keyEventInterceptor.keyTyped(evt);
  89. else if(isPrefixActive() || textArea.hasFocus())
  90. {
  91. processKeyEventKeyStrokeHandling(evt,from,"type ",global);
  92. }
  93. processKeyEventSub(focusOnTextArea);
  94. break;
  95. case KeyEvent.KEY_PRESSED:
  96. if(keyEventInterceptor != null)
  97. keyEventInterceptor.keyPressed(evt);
  98. else if(KeyEventWorkaround.isBindable(evt.getKeyCode()))
  99. {
  100. processKeyEventKeyStrokeHandling(evt,from,"press",global);
  101. processKeyEventSub(focusOnTextArea);
  102. }
  103. break;
  104. case KeyEvent.KEY_RELEASED:
  105. if(keyEventInterceptor != null)
  106. keyEventInterceptor.keyReleased(evt);
  107. break;
  108. }
  109. } //}}}
  110. //{{{ _preprocessKeyEvent() method
  111. /**
  112. * This method returns if the keyboard event can be handled or not.
  113. *
  114. * @param evt the keyboard event
  115. * @return null if the keyboard event cannot be handled, or the keyboard event itself
  116. * otherwise
  117. */
  118. private KeyEvent _preprocessKeyEvent(KeyEvent evt)
  119. {
  120. if(evt.isConsumed())
  121. return null;
  122. if(Debug.DUMP_KEY_EVENTS)
  123. {
  124. Log.log(Log.DEBUG,this,"Key event (preprocessing) : "
  125. + toString(evt));
  126. }
  127. return KeyEventWorkaround.processKeyEvent(evt);
  128. } //}}}
  129. //{{{ processKeyEventSub() method
  130. private void processKeyEventSub(boolean focusOnTextArea)
  131. {
  132. // this is a weird hack.
  133. // we don't want C+e a to insert 'a' in the
  134. // search bar if the search bar has focus...
  135. if (isPrefixActive() && focusOnTextArea)
  136. {
  137. textArea.requestFocus();
  138. }
  139. } //}}}
  140. //{{{ getAction() method
  141. protected abstract JEditBeanShellAction getAction(String action);
  142. //}}}
  143. //{{{ invokeAction() method
  144. /**
  145. * Invokes the specified action, repeating and recording it as
  146. * necessary.
  147. * @param action The action
  148. * @since jEdit 4.2pre1
  149. */
  150. @Override
  151. public void invokeAction(String action)
  152. {
  153. invokeAction(getAction(action));
  154. } //}}}
  155. //{{{ invokeAction() method
  156. /**
  157. * Invokes the specified action, repeating and recording it as
  158. * necessary.
  159. * @param action The action
  160. */
  161. @Override
  162. public void invokeAction(JEditBeanShellAction action)
  163. {
  164. JEditBuffer buffer = textArea.getBuffer();
  165. /* if(buffer.insideCompoundEdit())
  166. buffer.endCompoundEdit(); */
  167. // remember the last executed action
  168. if(!action.noRememberLast())
  169. {
  170. if(lastAction == action)
  171. lastActionCount++;
  172. else
  173. {
  174. lastAction = action;
  175. lastActionCount = 1;
  176. }
  177. }
  178. // remember old values, in case action changes them
  179. int _repeatCount = repeatCount;
  180. // execute the action
  181. if(action.noRepeat() || _repeatCount == 1)
  182. action.invoke(textArea);
  183. else
  184. {
  185. try
  186. {
  187. buffer.beginCompoundEdit();
  188. for(int i = 0; i < _repeatCount; i++)
  189. action.invoke(textArea);
  190. }
  191. finally
  192. {
  193. buffer.endCompoundEdit();
  194. }
  195. }
  196. // If repeat was true originally, clear it
  197. // Otherwise it might have been set by the action, etc
  198. if(_repeatCount != 1)
  199. {
  200. // first of all, if this action set a
  201. // readNextChar, do not clear the repeat
  202. if(readNextChar != null)
  203. return;
  204. repeatCount = 1;
  205. }
  206. } //}}}
  207. //{{{ handleKey() method
  208. /**
  209. * Handles the given keystroke.
  210. * @param keyStroke The key stroke
  211. * @param dryRun only calculate the return value, do not have any other effect
  212. * @since jEdit 4.2pre5
  213. */
  214. @Override
  215. public boolean handleKey(KeyEventTranslator.Key keyStroke,boolean dryRun)
  216. {
  217. char input = '\0';
  218. if(keyStroke.modifiers == null
  219. || keyStroke.modifiers.equals("S"))
  220. {
  221. switch(keyStroke.key)
  222. {
  223. case '\n':
  224. case '\t':
  225. input = (char)keyStroke.key;
  226. break;
  227. default:
  228. input = keyStroke.input;
  229. break;
  230. }
  231. }
  232. if(readNextChar != null)
  233. {
  234. if(input != '\0')
  235. {
  236. if (!dryRun)
  237. {
  238. setCurrentBindings(bindings);
  239. invokeReadNextChar(input);
  240. repeatCount = 1;
  241. }
  242. return true;
  243. }
  244. else
  245. {
  246. if (!dryRun)
  247. {
  248. readNextChar = null;
  249. }
  250. }
  251. }
  252. Object o = currentBindings.get(keyStroke);
  253. if(o == null)
  254. {
  255. if (!dryRun)
  256. {
  257. // Don't beep if the user presses some
  258. // key we don't know about unless a
  259. // prefix is active. Otherwise it will
  260. // beep when caps lock is pressed, etc.
  261. if(currentBindings != bindings)
  262. {
  263. Toolkit.getDefaultToolkit().beep();
  264. // F10 should be passed on, but C+e F10
  265. // shouldn't
  266. repeatCount = 1;
  267. setCurrentBindings(bindings);
  268. }
  269. else if(input != '\0')
  270. {
  271. if (!keyStroke.isFromGlobalContext())
  272. { // let user input be only local
  273. userInput(input);
  274. }
  275. }
  276. else
  277. {
  278. // this is retarded. excuse me while I drool
  279. // and make stupid noises
  280. if(KeyEventWorkaround.isNumericKeypad(keyStroke.key))
  281. KeyEventWorkaround.numericKeypadKey();
  282. }
  283. sendShortcutPrefixOff();
  284. }
  285. }
  286. else if(o instanceof Hashtable)
  287. {
  288. if (!dryRun)
  289. {
  290. setCurrentBindings((Hashtable)o);
  291. ShortcutPrefixActiveEvent.firePrefixStateChange(currentBindings, true);
  292. shortcutOn = true;
  293. }
  294. return true;
  295. }
  296. else if(o instanceof String)
  297. {
  298. if (!dryRun)
  299. {
  300. setCurrentBindings(bindings);
  301. sendShortcutPrefixOff();
  302. invokeAction((String)o);
  303. }
  304. return true;
  305. }
  306. else if(o instanceof JEditBeanShellAction)
  307. {
  308. if (!dryRun)
  309. {
  310. setCurrentBindings(bindings);
  311. sendShortcutPrefixOff();
  312. invokeAction((JEditBeanShellAction)o);
  313. }
  314. return true;
  315. }
  316. if (!dryRun)
  317. {
  318. sendShortcutPrefixOff();
  319. }
  320. return false;
  321. } //}}}
  322. //{{{ userInput() method
  323. protected void userInput(char ch)
  324. {
  325. lastActionCount = 0;
  326. if(repeatCount == 1)
  327. textArea.userInput(ch);
  328. repeatCount = 1;
  329. } //}}}
  330. //{{{ invokeReadNextChar() method
  331. protected void invokeReadNextChar(char ch)
  332. {
  333. String charStr = StandardUtilities.charsToEscapes(String.valueOf(ch));
  334. // this might be a bit slow if __char__ occurs a lot
  335. int index;
  336. while((index = readNextChar.indexOf("__char__")) != -1)
  337. {
  338. readNextChar = readNextChar.substring(0,index)
  339. + '\'' + charStr + '\''
  340. + readNextChar.substring(index + 8);
  341. }
  342. readNextChar = null;
  343. } //}}}
  344. }