PageRenderTime 46ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-2-pre14/org/gjt/sp/jedit/gui/InputHandler.java

#
Java | 415 lines | 208 code | 54 blank | 153 comment | 41 complexity | a4bb9580136e62c525550b81e7949b46 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. * InputHandler.java - Manages key bindings and executes actions
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 1999, 2003 Slava Pestov
  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.gui;
  23. //{{{ Imports
  24. import javax.swing.JOptionPane;
  25. import org.gjt.sp.jedit.textarea.JEditTextArea;
  26. import org.gjt.sp.jedit.*;
  27. //}}}
  28. /**
  29. * An input handler converts the user's key strokes into concrete actions.
  30. * It also takes care of macro recording and action repetition.<p>
  31. *
  32. * This class provides all the necessary support code for an input
  33. * handler, but doesn't actually do any key binding logic. It is up
  34. * to the implementations of this class to do so.
  35. *
  36. * @author Slava Pestov
  37. * @version $Id: InputHandler.java 4956 2004-01-14 04:36:50Z spestov $
  38. * @see org.gjt.sp.jedit.gui.DefaultInputHandler
  39. */
  40. public abstract class InputHandler
  41. {
  42. //{{{ InputHandler constructor
  43. /**
  44. * Creates a new input handler.
  45. * @param view The view
  46. */
  47. public InputHandler(View view)
  48. {
  49. this.view = view;
  50. repeatCount = 1;
  51. } //}}}
  52. //{{{ addKeyBinding() method
  53. /**
  54. * Adds a key binding to this input handler.
  55. * @param keyBinding The key binding (the format of this is
  56. * input-handler specific)
  57. * @param action The action
  58. */
  59. public abstract void addKeyBinding(String keyBinding, String action);
  60. //}}}
  61. //{{{ addKeyBinding() method
  62. /**
  63. * Adds a key binding to this input handler.
  64. * @param keyBinding The key binding (the format of this is
  65. * input-handler specific)
  66. * @param action The action
  67. */
  68. public abstract void addKeyBinding(String keyBinding, EditAction action);
  69. //}}}
  70. //{{{ removeKeyBinding() method
  71. /**
  72. * Removes a key binding from this input handler.
  73. * @param keyBinding The key binding
  74. */
  75. public abstract void removeKeyBinding(String keyBinding);
  76. //}}}
  77. //{{{ removeAllKeyBindings() method
  78. /**
  79. * Removes all key bindings from this input handler.
  80. */
  81. public abstract void removeAllKeyBindings();
  82. //}}}
  83. //{{{ isPrefixActive() method
  84. /**
  85. * Returns if a prefix key has been pressed.
  86. */
  87. public boolean isPrefixActive()
  88. {
  89. return readNextChar != null;
  90. } //}}}
  91. //{{{ handleKey() method
  92. /**
  93. * Handles a keystroke.
  94. * @param keyStroke The key stroke.
  95. * @since jEdit 4.2pre5
  96. */
  97. public abstract boolean handleKey(KeyEventTranslator.Key keyStroke);
  98. //}}}
  99. //{{{ getRepeatCount() method
  100. /**
  101. * Returns the number of times the next action will be repeated.
  102. */
  103. public int getRepeatCount()
  104. {
  105. return repeatCount;
  106. } //}}}
  107. //{{{ setRepeatCount() method
  108. /**
  109. * Sets the number of times the next action will be repeated.
  110. * @param repeatCount The repeat count
  111. */
  112. public void setRepeatCount(int repeatCount)
  113. {
  114. int oldRepeatCount = this.repeatCount;
  115. this.repeatCount = repeatCount;
  116. if(oldRepeatCount != repeatCount)
  117. view.getStatus().setMessage(null);
  118. } //}}}
  119. //{{{ getLastAction() method
  120. /**
  121. * Returns the last executed action.
  122. * @since jEdit 2.5pre5
  123. */
  124. public EditAction getLastAction()
  125. {
  126. return lastAction;
  127. } //}}}
  128. //{{{ getLastActionCount() method
  129. /**
  130. * Returns the number of times the last action was executed.
  131. * @since jEdit 2.5pre5
  132. */
  133. public int getLastActionCount()
  134. {
  135. return lastActionCount;
  136. } //}}}
  137. //{{{ readNextChar() method
  138. /**
  139. * Invokes the specified BeanShell code, replacing __char__ in the
  140. * code with the next input character.
  141. * @param msg The prompt to display in the status bar
  142. * @param code The code
  143. * @since jEdit 3.2pre2
  144. */
  145. public void readNextChar(String msg, String code)
  146. {
  147. view.getStatus().setMessage(msg);
  148. readNextChar = code;
  149. } //}}}
  150. //{{{ readNextChar() method
  151. /**
  152. * @deprecated Use the other form of this method instead
  153. */
  154. public void readNextChar(String code)
  155. {
  156. readNextChar = code;
  157. } //}}}
  158. //{{{ resetLastActionCount() method
  159. /**
  160. * Resets the last action count. This should be called when an
  161. * editing operation that is not an action is invoked, for example
  162. * a mouse click.
  163. * @since jEdit 4.0pre1
  164. */
  165. public void resetLastActionCount()
  166. {
  167. lastActionCount = 0;
  168. } //}}}
  169. //{{{ invokeAction() method
  170. /**
  171. * Invokes the specified action, repeating and recording it as
  172. * necessary.
  173. * @param action The action
  174. * @since jEdit 4.2pre1
  175. */
  176. public void invokeAction(String action)
  177. {
  178. invokeAction(jEdit.getAction(action));
  179. } //}}}
  180. //{{{ invokeAction() method
  181. /**
  182. * Invokes the specified action, repeating and recording it as
  183. * necessary.
  184. * @param action The action
  185. */
  186. public void invokeAction(EditAction action)
  187. {
  188. Buffer buffer = view.getBuffer();
  189. /* if(buffer.insideCompoundEdit())
  190. buffer.endCompoundEdit(); */
  191. // remember the last executed action
  192. if(!action.noRememberLast())
  193. {
  194. HistoryModel.getModel("action").addItem(action.getName());
  195. if(lastAction == action)
  196. lastActionCount++;
  197. else
  198. {
  199. lastAction = action;
  200. lastActionCount = 1;
  201. }
  202. }
  203. // remember old values, in case action changes them
  204. int _repeatCount = repeatCount;
  205. // execute the action
  206. if(action.noRepeat() || _repeatCount == 1)
  207. action.invoke(view);
  208. else
  209. {
  210. // stop people doing dumb stuff like C+ENTER 100 C+n
  211. if(_repeatCount > REPEAT_COUNT_THRESHOLD)
  212. {
  213. String label = action.getLabel();
  214. if(label == null)
  215. label = action.getName();
  216. else
  217. label = GUIUtilities.prettifyMenuLabel(label);
  218. Object[] pp = { label, new Integer(_repeatCount) };
  219. if(GUIUtilities.confirm(view,"large-repeat-count",pp,
  220. JOptionPane.WARNING_MESSAGE,
  221. JOptionPane.YES_NO_OPTION)
  222. != JOptionPane.YES_OPTION)
  223. {
  224. repeatCount = 1;
  225. view.getStatus().setMessage(null);
  226. return;
  227. }
  228. }
  229. try
  230. {
  231. buffer.beginCompoundEdit();
  232. for(int i = 0; i < _repeatCount; i++)
  233. action.invoke(view);
  234. }
  235. finally
  236. {
  237. buffer.endCompoundEdit();
  238. }
  239. }
  240. Macros.Recorder recorder = view.getMacroRecorder();
  241. if(recorder != null && !action.noRecord())
  242. recorder.record(_repeatCount,action.getCode());
  243. // If repeat was true originally, clear it
  244. // Otherwise it might have been set by the action, etc
  245. if(_repeatCount != 1)
  246. {
  247. // first of all, if this action set a
  248. // readNextChar, do not clear the repeat
  249. if(readNextChar != null)
  250. return;
  251. repeatCount = 1;
  252. view.getStatus().setMessage(null);
  253. }
  254. } //}}}
  255. //{{{ invokeLastAction() method
  256. public void invokeLastAction()
  257. {
  258. if(lastAction == null)
  259. view.getToolkit().beep();
  260. else
  261. invokeAction(lastAction);
  262. } //}}}
  263. //{{{ Protected members
  264. private static final int REPEAT_COUNT_THRESHOLD = 20;
  265. //{{{ Instance variables
  266. protected View view;
  267. protected int repeatCount;
  268. protected EditAction lastAction;
  269. protected int lastActionCount;
  270. protected String readNextChar;
  271. //}}}
  272. //{{{ userInput() method
  273. protected void userInput(char ch)
  274. {
  275. lastActionCount = 0;
  276. JEditTextArea textArea = view.getTextArea();
  277. /* Buffer buffer = view.getBuffer();
  278. if(!buffer.insideCompoundEdit())
  279. buffer.beginCompoundEdit(); */
  280. if(repeatCount == 1)
  281. textArea.userInput(ch);
  282. else
  283. {
  284. // stop people doing dumb stuff like C+ENTER 100 C+n
  285. if(repeatCount > REPEAT_COUNT_THRESHOLD)
  286. {
  287. Object[] pp = { String.valueOf(ch),
  288. new Integer(repeatCount) };
  289. if(GUIUtilities.confirm(view,
  290. "large-repeat-count.user-input",pp,
  291. JOptionPane.WARNING_MESSAGE,
  292. JOptionPane.YES_NO_OPTION)
  293. != JOptionPane.YES_OPTION)
  294. {
  295. repeatCount = 1;
  296. view.getStatus().setMessage(null);
  297. return;
  298. }
  299. }
  300. Buffer buffer = view.getBuffer();
  301. try
  302. {
  303. if(repeatCount != 1)
  304. buffer.beginCompoundEdit();
  305. for(int i = 0; i < repeatCount; i++)
  306. textArea.userInput(ch);
  307. }
  308. finally
  309. {
  310. if(repeatCount != 1)
  311. buffer.endCompoundEdit();
  312. }
  313. }
  314. Macros.Recorder recorder = view.getMacroRecorder();
  315. if(recorder != null)
  316. {
  317. recorder.recordInput(repeatCount,ch,
  318. textArea.isOverwriteEnabled());
  319. }
  320. repeatCount = 1;
  321. } //}}}
  322. //{{{ invokeReadNextChar() method
  323. protected void invokeReadNextChar(char ch)
  324. {
  325. Buffer buffer = view.getBuffer();
  326. /* if(buffer.insideCompoundEdit())
  327. buffer.endCompoundEdit(); */
  328. String charStr = MiscUtilities.charsToEscapes(String.valueOf(ch));
  329. // this might be a bit slow if __char__ occurs a lot
  330. int index;
  331. while((index = readNextChar.indexOf("__char__")) != -1)
  332. {
  333. readNextChar = readNextChar.substring(0,index)
  334. + '\'' + charStr + '\''
  335. + readNextChar.substring(index + 8);
  336. }
  337. Macros.Recorder recorder = view.getMacroRecorder();
  338. if(recorder != null)
  339. recorder.record(getRepeatCount(),readNextChar);
  340. if(getRepeatCount() != 1)
  341. {
  342. try
  343. {
  344. buffer.beginCompoundEdit();
  345. BeanShell.eval(view,BeanShell.getNameSpace(),
  346. "for(int i = 1; i < "
  347. + getRepeatCount() + "; i++)\n{\n"
  348. + readNextChar + "\n}");
  349. }
  350. finally
  351. {
  352. buffer.endCompoundEdit();
  353. }
  354. }
  355. else
  356. BeanShell.eval(view,BeanShell.getNameSpace(),readNextChar);
  357. readNextChar = null;
  358. view.getStatus().setMessage(null);
  359. } //}}}
  360. //}}}
  361. }