PageRenderTime 43ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

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

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