PageRenderTime 53ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

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

#
Java | 400 lines | 212 code | 52 blank | 136 comment | 40 complexity | 7aab0cb85c103cb34df44604946791f9 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 3917 2001-11-25 03:42:16Z 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. //{{{ addKeyBinding() method
  57. /**
  58. * Adds a key binding to this input handler.
  59. * @param keyBinding The key binding (the format of this is
  60. * input-handler specific)
  61. * @param action The action
  62. */
  63. public abstract void addKeyBinding(String keyBinding, EditAction action);
  64. //}}}
  65. //{{{ removeKeyBinding() method
  66. /**
  67. * Removes a key binding from this input handler.
  68. * @param keyBinding The key binding
  69. */
  70. public abstract void removeKeyBinding(String keyBinding);
  71. //}}}
  72. //{{{ removeAllKeyBindings() method
  73. /**
  74. * Removes all key bindings from this input handler.
  75. */
  76. public abstract void removeAllKeyBindings();
  77. //}}}
  78. //{{{ isPrefixActive() method
  79. /**
  80. * Returns if a prefix key has been pressed.
  81. */
  82. public boolean isPrefixActive()
  83. {
  84. return false;
  85. } //}}}
  86. //{{{ isRepeatEnabled() method
  87. /**
  88. * Returns if repeating is enabled. When repeating is enabled,
  89. * actions will be executed multiple times. This is usually
  90. * invoked with a special key stroke in the input handler.
  91. */
  92. public boolean isRepeatEnabled()
  93. {
  94. return repeat;
  95. } //}}}
  96. //{{{ setRepeatEnabled() method
  97. /**
  98. * Enables repeating. When repeating is enabled, actions will be
  99. * executed multiple times. Once repeating is enabled, the input
  100. * handler should read a number from the keyboard.
  101. */
  102. public void setRepeatEnabled(boolean repeat)
  103. {
  104. boolean oldRepeat = this.repeat;
  105. this.repeat = repeat;
  106. repeatCount = 0;
  107. if(oldRepeat != repeat)
  108. view.getStatus().setMessage(null);
  109. } //}}}
  110. //{{{ getRepeatCount() method
  111. /**
  112. * Returns the number of times the next action will be repeated.
  113. */
  114. public int getRepeatCount()
  115. {
  116. return (repeat && repeatCount > 0 ? repeatCount : 1);
  117. } //}}}
  118. //{{{ setRepeatCount() method
  119. /**
  120. * Sets the number of times the next action will be repeated.
  121. * @param repeatCount The repeat count
  122. */
  123. public void setRepeatCount(int repeatCount)
  124. {
  125. boolean oldRepeat = this.repeat;
  126. repeat = true;
  127. this.repeatCount = repeatCount;
  128. if(oldRepeat != repeat)
  129. view.getStatus().setMessage(null);
  130. } //}}}
  131. //{{{ getLastAction() method
  132. /**
  133. * Returns the last executed action.
  134. * @since jEdit 2.5pre5
  135. */
  136. public EditAction getLastAction()
  137. {
  138. return lastAction;
  139. } //}}}
  140. //{{{ getLastActionCount() method
  141. /**
  142. * Returns the number of times the last action was executed.
  143. * @since jEdit 2.5pre5
  144. */
  145. public int getLastActionCount()
  146. {
  147. return lastActionCount;
  148. } //}}}
  149. //{{{ readNextChar() method
  150. /**
  151. * Invokes the specified BeanShell code, replacing __char__ in the
  152. * code with the next input character.
  153. * @param msg The prompt to display in the status bar
  154. * @param code The code
  155. * @since jEdit 3.2pre2
  156. */
  157. public void readNextChar(String msg, String code)
  158. {
  159. view.getStatus().setMessage(msg);
  160. readNextChar(code);
  161. } //}}}
  162. //{{{ readNextChar() method
  163. /**
  164. * @deprecated Use the other form of this method instead
  165. */
  166. public void readNextChar(String code)
  167. {
  168. readNextChar = code;
  169. } //}}}
  170. //{{{ resetLastActionCount() method
  171. /**
  172. * Resets the last action count. This should be called when an
  173. * editing operation that is not an action is invoked, for example
  174. * a mouse click.
  175. * @since jEdit 4.0pre1
  176. */
  177. public void resetLastActionCount()
  178. {
  179. lastAction = null;
  180. lastActionCount = 0;
  181. } //}}}
  182. //{{{ invokeAction() method
  183. /**
  184. * Invokes the specified action, repeating and recording it as
  185. * necessary.
  186. * @param action The action
  187. * @param source The event source
  188. */
  189. public void invokeAction(EditAction action)
  190. {
  191. Buffer buffer = view.getBuffer();
  192. if(buffer.insideCompoundEdit())
  193. buffer.endCompoundEdit();
  194. // remember the last executed action
  195. if(lastAction == action)
  196. lastActionCount++;
  197. else
  198. {
  199. lastAction = action;
  200. lastActionCount = 1;
  201. }
  202. // remember old values, in case action changes them
  203. boolean _repeat = repeat;
  204. int _repeatCount = getRepeatCount();
  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 = jEdit.getProperty(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. repeat = false;
  225. repeatCount = 0;
  226. view.getStatus().setMessage(null);
  227. return;
  228. }
  229. }
  230. try
  231. {
  232. buffer.beginCompoundEdit();
  233. for(int i = 0; i < _repeatCount; i++)
  234. action.invoke(view);
  235. }
  236. finally
  237. {
  238. buffer.endCompoundEdit();
  239. }
  240. }
  241. Macros.Recorder recorder = view.getMacroRecorder();
  242. if(recorder != null && !action.noRecord())
  243. recorder.record(_repeatCount,action.getCode());
  244. // If repeat was true originally, clear it
  245. // Otherwise it might have been set by the action, etc
  246. if(_repeat)
  247. {
  248. // first of all, if this action set a
  249. // readNextChar, do not clear the repeat
  250. if(readNextChar != null)
  251. return;
  252. repeat = false;
  253. repeatCount = 0;
  254. view.getStatus().setMessage(null);
  255. }
  256. } //}}}
  257. //{{{ Protected members
  258. private static final int REPEAT_COUNT_THRESHOLD = 20;
  259. //{{{ Instance variables
  260. protected View view;
  261. protected boolean repeat;
  262. protected int repeatCount;
  263. protected EditAction lastAction;
  264. protected int lastActionCount;
  265. protected String readNextChar;
  266. //}}}
  267. //{{{ userInput() method
  268. protected void userInput(char ch)
  269. {
  270. lastAction = null;
  271. if(readNextChar != null)
  272. invokeReadNextChar(ch);
  273. else
  274. {
  275. JEditTextArea textArea = view.getTextArea();
  276. Buffer buffer = view.getBuffer();
  277. if(!buffer.insideCompoundEdit())
  278. buffer.beginCompoundEdit();
  279. int _repeatCount = getRepeatCount();
  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. repeat = false;
  296. repeatCount = 0;
  297. view.getStatus().setMessage(null);
  298. return;
  299. }
  300. }
  301. for(int i = 0; i < _repeatCount; i++)
  302. textArea.userInput(ch);
  303. }
  304. Macros.Recorder recorder = view.getMacroRecorder();
  305. if(recorder != null)
  306. recorder.record(_repeatCount,ch);
  307. }
  308. setRepeatEnabled(false);
  309. } //}}}
  310. //{{{ invokeReadNextChar() method
  311. protected void invokeReadNextChar(char ch)
  312. {
  313. Buffer buffer = view.getBuffer();
  314. if(buffer.insideCompoundEdit())
  315. buffer.endCompoundEdit();
  316. String charStr = MiscUtilities.charsToEscapes(String.valueOf(ch));
  317. // this might be a bit slow if __char__ occurs a lot
  318. int index;
  319. while((index = readNextChar.indexOf("__char__")) != -1)
  320. {
  321. readNextChar = readNextChar.substring(0,index)
  322. + '\'' + charStr + '\''
  323. + readNextChar.substring(index + 8);
  324. }
  325. Macros.Recorder recorder = view.getMacroRecorder();
  326. if(recorder != null)
  327. recorder.record(getRepeatCount(),readNextChar);
  328. if(getRepeatCount() != 1)
  329. {
  330. try
  331. {
  332. buffer.beginCompoundEdit();
  333. BeanShell.eval(view,"for(int i = 1; i < "
  334. + getRepeatCount() + "; i++)\n{\n"
  335. + readNextChar + "\n}",false);
  336. }
  337. finally
  338. {
  339. buffer.endCompoundEdit();
  340. }
  341. }
  342. else
  343. BeanShell.eval(view,readNextChar,false);
  344. readNextChar = null;
  345. view.getStatus().setMessage(null);
  346. } //}}}
  347. //}}}
  348. }