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