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