PageRenderTime 50ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-0-pre5/org/gjt/sp/jedit/gui/InputHandler.java

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