PageRenderTime 40ms CodeModel.GetById 27ms app.highlight 9ms RepoModel.GetById 1ms app.codeStats 1ms

/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
  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
 23package org.gjt.sp.jedit.gui;
 24
 25//{{{ Imports
 26import javax.swing.JOptionPane;
 27import org.gjt.sp.jedit.textarea.JEditTextArea;
 28import org.gjt.sp.jedit.*;
 29//}}}
 30
 31/**
 32 * An input handler converts the user's key strokes into concrete actions.
 33 * It also takes care of macro recording and action repetition.<p>
 34 *
 35 * This class provides all the necessary support code for an input
 36 * handler, but doesn't actually do any key binding logic. It is up
 37 * to the implementations of this class to do so.
 38 *
 39 * @author Slava Pestov
 40 * @version $Id: InputHandler.java 4956 2004-01-14 04:36:50Z spestov $
 41 * @see org.gjt.sp.jedit.gui.DefaultInputHandler
 42 */
 43public abstract class InputHandler
 44{
 45	//{{{ InputHandler constructor
 46	/**
 47	 * Creates a new input handler.
 48	 * @param view The view
 49	 */
 50	public InputHandler(View view)
 51	{
 52		this.view = view;
 53		repeatCount = 1;
 54	} //}}}
 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, String action);
 64	//}}}
 65
 66	//{{{ addKeyBinding() method
 67	/**
 68	 * Adds a key binding to this input handler.
 69	 * @param keyBinding The key binding (the format of this is
 70	 * input-handler specific)
 71	 * @param action The action
 72	 */
 73	public abstract void addKeyBinding(String keyBinding, EditAction action);
 74	//}}}
 75
 76	//{{{ removeKeyBinding() method
 77	/**
 78	 * Removes a key binding from this input handler.
 79	 * @param keyBinding The key binding
 80	 */
 81	public abstract void removeKeyBinding(String keyBinding);
 82	//}}}
 83
 84	//{{{ removeAllKeyBindings() method
 85	/**
 86	 * Removes all key bindings from this input handler.
 87	 */
 88	public abstract void removeAllKeyBindings();
 89	//}}}
 90
 91	//{{{ isPrefixActive() method
 92	/**
 93	 * Returns if a prefix key has been pressed.
 94	 */
 95	public boolean isPrefixActive()
 96	{
 97		return readNextChar != null;
 98	} //}}}
 99
100	//{{{ handleKey() method
101	/**
102	 * Handles a keystroke.
103	 * @param keyStroke The key stroke.
104	 * @since jEdit 4.2pre5
105	 */
106	public abstract boolean handleKey(KeyEventTranslator.Key keyStroke);
107	//}}}
108
109	//{{{ getRepeatCount() method
110	/**
111	 * Returns the number of times the next action will be repeated.
112	 */
113	public int getRepeatCount()
114	{
115		return repeatCount;
116	} //}}}
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		int oldRepeatCount = this.repeatCount;
126		this.repeatCount = repeatCount;
127		if(oldRepeatCount != repeatCount)
128			view.getStatus().setMessage(null);
129	} //}}}
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
141	//{{{ getLastActionCount() method
142	/**
143	 * Returns the number of times the last action was executed.
144	 * @since jEdit 2.5pre5
145	 */
146	public int getLastActionCount()
147	{
148		return lastActionCount;
149	} //}}}
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
165	//{{{ readNextChar() method
166	/**
167	 * @deprecated Use the other form of this method instead
168	 */
169	public void readNextChar(String code)
170	{
171		readNextChar = code;
172	} //}}}
173
174	//{{{ resetLastActionCount() method
175	/**
176	 * Resets the last action count. This should be called when an
177	 * editing operation that is not an action is invoked, for example
178	 * a mouse click.
179	 * @since jEdit 4.0pre1
180	 */
181	public void resetLastActionCount()
182	{
183		lastActionCount = 0;
184	} //}}}
185
186	//{{{ invokeAction() method
187	/**
188	 * Invokes the specified action, repeating and recording it as
189	 * necessary.
190	 * @param action The action
191	 * @since jEdit 4.2pre1
192	 */
193	public void invokeAction(String action)
194	{
195		invokeAction(jEdit.getAction(action));
196	} //}}}
197
198	//{{{ invokeAction() method
199	/**
200	 * Invokes the specified action, repeating and recording it as
201	 * necessary.
202	 * @param action The action
203	 */
204	public void invokeAction(EditAction action)
205	{
206		Buffer buffer = view.getBuffer();
207
208		/* if(buffer.insideCompoundEdit())
209			buffer.endCompoundEdit(); */
210
211		// remember the last executed action
212		if(!action.noRememberLast())
213		{
214			HistoryModel.getModel("action").addItem(action.getName());
215			if(lastAction == action)
216				lastActionCount++;
217			else
218			{
219				lastAction = action;
220				lastActionCount = 1;
221			}
222		}
223
224		// remember old values, in case action changes them
225		int _repeatCount = repeatCount;
226
227		// execute the action
228		if(action.noRepeat() || _repeatCount == 1)
229			action.invoke(view);
230		else
231		{
232			// stop people doing dumb stuff like C+ENTER 100 C+n
233			if(_repeatCount > REPEAT_COUNT_THRESHOLD)
234			{
235				String label = action.getLabel();
236				if(label == null)
237					label = action.getName();
238				else
239					label = GUIUtilities.prettifyMenuLabel(label);
240
241				Object[] pp = { label, new Integer(_repeatCount) };
242
243				if(GUIUtilities.confirm(view,"large-repeat-count",pp,
244					JOptionPane.WARNING_MESSAGE,
245					JOptionPane.YES_NO_OPTION)
246					!= JOptionPane.YES_OPTION)
247				{
248					repeatCount = 1;
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(_repeatCount != 1)
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			repeatCount = 1;
282			view.getStatus().setMessage(null);
283		}
284	} //}}}
285
286	//{{{ invokeLastAction() method
287	public void invokeLastAction()
288	{
289		if(lastAction == null)
290			view.getToolkit().beep();
291		else
292			invokeAction(lastAction);
293	} //}}}
294
295	//{{{ Protected members
296	private static final int REPEAT_COUNT_THRESHOLD = 20;
297
298	//{{{ Instance variables
299	protected View view;
300	protected int repeatCount;
301
302	protected EditAction lastAction;
303	protected int lastActionCount;
304
305	protected String readNextChar;
306	//}}}
307
308	//{{{ userInput() method
309	protected void userInput(char ch)
310	{
311		lastActionCount = 0;
312
313		JEditTextArea textArea = view.getTextArea();
314
315		/* Buffer buffer = view.getBuffer();
316		if(!buffer.insideCompoundEdit())
317			buffer.beginCompoundEdit(); */
318
319		if(repeatCount == 1)
320			textArea.userInput(ch);
321		else
322		{
323			// stop people doing dumb stuff like C+ENTER 100 C+n
324			if(repeatCount > REPEAT_COUNT_THRESHOLD)
325			{
326				Object[] pp = { String.valueOf(ch),
327					new Integer(repeatCount) };
328
329				if(GUIUtilities.confirm(view,
330					"large-repeat-count.user-input",pp,
331					JOptionPane.WARNING_MESSAGE,
332					JOptionPane.YES_NO_OPTION)
333					!= JOptionPane.YES_OPTION)
334				{
335					repeatCount = 1;
336					view.getStatus().setMessage(null);
337					return;
338				}
339			}
340
341			Buffer buffer = view.getBuffer();
342			try
343			{
344				if(repeatCount != 1)
345					buffer.beginCompoundEdit();
346				for(int i = 0; i < repeatCount; i++)
347					textArea.userInput(ch);
348			}
349			finally
350			{
351				if(repeatCount != 1)
352					buffer.endCompoundEdit();
353			}
354		}
355
356		Macros.Recorder recorder = view.getMacroRecorder();
357
358		if(recorder != null)
359		{
360			recorder.recordInput(repeatCount,ch,
361				textArea.isOverwriteEnabled());
362		}
363
364		repeatCount = 1;
365	} //}}}
366
367	//{{{ invokeReadNextChar() method
368	protected void invokeReadNextChar(char ch)
369	{
370		Buffer buffer = view.getBuffer();
371
372		/* if(buffer.insideCompoundEdit())
373			buffer.endCompoundEdit(); */
374
375		String charStr = MiscUtilities.charsToEscapes(String.valueOf(ch));
376
377		// this might be a bit slow if __char__ occurs a lot
378		int index;
379		while((index = readNextChar.indexOf("__char__")) != -1)
380		{
381			readNextChar = readNextChar.substring(0,index)
382				+ '\'' + charStr + '\''
383				+ readNextChar.substring(index + 8);
384		}
385
386		Macros.Recorder recorder = view.getMacroRecorder();
387		if(recorder != null)
388			recorder.record(getRepeatCount(),readNextChar);
389
390		if(getRepeatCount() != 1)
391		{
392			try
393			{
394				buffer.beginCompoundEdit();
395
396				BeanShell.eval(view,BeanShell.getNameSpace(),
397					"for(int i = 1; i < "
398					+ getRepeatCount() + "; i++)\n{\n"
399					+ readNextChar + "\n}");
400			}
401			finally
402			{
403				buffer.endCompoundEdit();
404			}
405		}
406		else
407			BeanShell.eval(view,BeanShell.getNameSpace(),readNextChar);
408
409		readNextChar = null;
410
411		view.getStatus().setMessage(null);
412	} //}}}
413
414	//}}}
415}