gt: 			JEditTextArea textArea = getTextArea(evt);
context: /*
   *  RapidMiner
   *
   *  Copyright (C) 2001-2011 by Rapid-I and the contributors
   *
   *  Complete list of developers available at our web site:
   *
   *       http://rapid-i.com
   *
   *  This program is free software: you can redistribute it and/or modify
   *  it under the terms of the GNU Affero General Public License as published by
   *  the Free Software Foundation, either version 3 of the License, or
   *  (at your option) any later version.
   *
   *  This program is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU Affero General Public License for more details.
   *
   *  You should have received a copy of the GNU Affero General Public License
   *  along with this program.  If not, see http://www.gnu.org/licenses/.
   */
  package com.rapidminer.gui.tools.syntax;
  /*
   * InputHandler.java - Manages key bindings and executes actions
   * Copyright (C) 1999 Slava Pestov
   *
   * You may use and modify this package for any purpose. Redistribution is
   * permitted, in both source and binary form, provided that this notice
   * remains intact in all source distributions of this package.
   */
  
  import java.awt.Component;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
  import java.awt.event.InputEvent;
  import java.awt.event.KeyAdapter;
  import java.awt.event.KeyEvent;
  import java.util.Enumeration;
  import java.util.EventObject;
  import java.util.Hashtable;
  
  import javax.swing.AbstractAction;
  import javax.swing.Action;
  import javax.swing.JPopupMenu;
  import javax.swing.KeyStroke;
  import javax.swing.text.BadLocationException;
  
  import com.rapidminer.gui.dialog.SearchDialog;
  import com.rapidminer.gui.dialog.SearchableJEditTextArea;
  import com.rapidminer.gui.tools.IconSize;
  import com.rapidminer.tools.Tools;
  
  
  /**
   * An input handler converts the user's key strokes into concrete actions. It also takes care of macro recording and action repetition.
   * <p>
   * 
   * This class provides all the necessary support code for an input handler, but doesn't actually do any key binding logic. It is up to the implementations of this class to do so.
   * 
   * @author Slava Pestov, Ingo Mierswa
   */
  public abstract class InputHandler extends KeyAdapter {
  	/**
  	 * If this client property is set to Boolean.TRUE on the text area, the home/end keys will support 'smart' BRIEF-like behaviour (one press = start/end of line, two presses = start/end of viewscreen, three presses = start/end of document). By
  	 * default, this property is not set.
  	 */
  	public static final String SMART_HOME_END_PROPERTY = "InputHandler.homeEnd";
  
  	public static final ActionListener BACKSPACE = new Backspace();
  
  	public static final ActionListener BACKSPACE_WORD = new BackspaceWord();
  
  	public static final ActionListener DELETE = new Delete();
  
  	public static final ActionListener DELETE_WORD = new DeleteWord();
  
  	public static final ActionListener END = new End(false);
  
  	public static final ActionListener DOCUMENT_END = new DocumentEnd(false);
  
  	public static final ActionListener SELECT_END = new End(true);
  
  	public static final ActionListener SELECT_DOC_END = new DocumentEnd(true);
  
  	public static final ActionListener INSERT_BREAK = new InsertBreak();
  
  	public static final ActionListener INSERT_TAB = new InsertTab();
  
  	public static final ActionListener HOME = new Home(false);
  
  	public static final ActionListener DOCUMENT_HOME = new DocumentHome(false);
  
  	public static final ActionListener SELECT_HOME = new Home(true);
  
  	public static final ActionListener SELECT_DOC_HOME = new DocumentHome(true);
  
  	public static final ActionListener NEXT_CHAR = new NextChar(false);
  
  	public static final ActionListener NEXT_LINE = new NextLine(false);
  
  	public static final ActionListener NEXT_PAGE = new NextPage(false);
  
  	public static final ActionListener NEXT_WORD = new NextWord(false);
  
  	public static final ActionListener SELECT_NEXT_CHAR = new NextChar(true);
  
  	public static final ActionListener SELECT_NEXT_LINE = new NextLine(true);
  
  	public static final ActionListener SELECT_NEXT_PAGE = new NextPage(true);
  
  	public static final ActionListener SELECT_NEXT_WORD = new NextWord(true);
  
  	public static final ActionListener OVERWRITE = new Overwrite();
  
  	public static final ActionListener PREV_CHAR = new PrevChar(false);
  
  	public static final ActionListener PREV_LINE = new PrevLine(false);
  
  	public static final ActionListener PREV_PAGE = new PrevPage(false);
  
  	public static final ActionListener PREV_WORD = new PrevWord(false);
  
  	public static final ActionListener SELECT_PREV_CHAR = new PrevChar(true);
  
  	public static final ActionListener SELECT_PREV_LINE = new PrevLine(true);
  
  	public static final ActionListener SELECT_PREV_PAGE = new PrevPage(true);
  
  	public static final ActionListener SELECT_PREV_WORD = new PrevWord(true);
  
  	public static final ActionListener REPEAT = new Repeat();
  
  	public static final ActionListener TOGGLE_RECT = new ToggleRect();
  
  	// Default action
  	public static final ActionListener INSERT_CHAR = new insert_char();
  
  	// Clipboard
  	public static final Action CLIP_COPY = new ClipCopy();
  	
  	public static final Action CLIP_PASTE = new ClipPaste();
  	
  	public static final Action CLIP_CUT = new ClipCut();
  	
  	public static final Action SELECT_ALL = new SelectAll();
  	
  	public static final Action SEARCH_AND_REPLACE = new SearchAction(IconSize.SMALL);
  	
  	
  	private static Hashtable<String, ActionListener> actions;
  
  	static {
  		actions = new Hashtable<String, ActionListener>();
  		actions.put("backspace", BACKSPACE);
  		actions.put("backspace-word", BACKSPACE_WORD);
  		actions.put("delete", DELETE);
  		actions.put("delete-word", DELETE_WORD);
  		actions.put("end", END);
  		actions.put("select-end", SELECT_END);
  		actions.put("document-end", DOCUMENT_END);
  		actions.put("select-doc-end", SELECT_DOC_END);
  		actions.put("insert-break", INSERT_BREAK);
  		actions.put("insert-tab", INSERT_TAB);
  		actions.put("home", HOME);
  		actions.put("select-home", SELECT_HOME);
  		actions.put("document-home", DOCUMENT_HOME);
  		actions.put("select-doc-home", SELECT_DOC_HOME);
  		actions.put("next-char", NEXT_CHAR);
  		actions.put("next-line", NEXT_LINE);
  		actions.put("next-page", NEXT_PAGE);
  		actions.put("next-word", NEXT_WORD);
  		actions.put("select-next-char", SELECT_NEXT_CHAR);
  		actions.put("select-next-line", SELECT_NEXT_LINE);
  		actions.put("select-next-page", SELECT_NEXT_PAGE);
  		actions.put("select-next-word", SELECT_NEXT_WORD);
  		actions.put("overwrite", OVERWRITE);
  		actions.put("prev-char", PREV_CHAR);
  		actions.put("prev-line", PREV_LINE);
  		actions.put("prev-page", PREV_PAGE);
  		actions.put("prev-word", PREV_WORD);
  		actions.put("select-prev-char", SELECT_PREV_CHAR);
  		actions.put("select-prev-line", SELECT_PREV_LINE);
  		actions.put("select-prev-page", SELECT_PREV_PAGE);
  		actions.put("select-prev-word", SELECT_PREV_WORD);
  		actions.put("repeat", REPEAT);
  		actions.put("toggle-rect", TOGGLE_RECT);
  		actions.put("insert-char", INSERT_CHAR);
  		
  		actions.put("clipboard-copy", CLIP_COPY);
  		actions.put("clipboard-paste", CLIP_PASTE);
  		actions.put("clipboard-cut", CLIP_CUT);
  		actions.put("select-all", SELECT_ALL);
  	}
  
  	/**
  	 * Returns a named text area action.
  	 * 
  	 * @param name
  	 *            The action name
  	 */
  	public static ActionListener getAction(String name) {
  		return actions.get(name);
  	}
  
  	/**
  	 * Returns the name of the specified text area action.
  	 * 
  	 * @param listener
  	 *            The action
  	 */
  	public static String getActionName(ActionListener listener) {
  		Enumeration<String> enumeration = getActions();
  		while (enumeration.hasMoreElements()) {
  			String name = enumeration.nextElement();
  			ActionListener _listener = getAction(name);
  			if (_listener == listener)
  				return name;
  		}
  		return null;
  	}
  
  	/**
  	 * Returns an enumeration of all available actions.
  	 */
  	public static Enumeration<String> getActions() {
  		return actions.keys();
  	}
  
  	/**
  	 * Adds the default key bindings to this input handler. This should not be called in the constructor of this input handler, because applications might load the key bindings from a file, etc.
  	 */
  	public abstract void addDefaultKeyBindings();
  
  	/**
  	 * Adds a key binding to this input handler.
  	 * 
  	 * @param keyBinding
  	 *            The key binding (the format of this is input-handler specific)
  	 * @param action
  	 *            The action
  	 */
  	public abstract void addKeyBinding(String keyBinding, ActionListener action);
  
  	/**
  	 * Removes a key binding from this input handler.
  	 * 
  	 * @param keyBinding
  	 *            The key binding
  	 */
  	public abstract void removeKeyBinding(String keyBinding);
  
  	/**
  	 * Removes all key bindings from this input handler.
  	 */
  	public abstract void removeAllKeyBindings();
  
  	/**
  	 * Grabs the next key typed event and invokes the specified action with the key as a the action command.
  	 */
  	public void grabNextKeyStroke(ActionListener listener) {
  		grabAction = listener;
  	}
  
  	/**
  	 * Returns if repeating is enabled. When repeating is enabled, actions will be executed multiple times. This is usually invoked with a special key stroke in the input handler.
  	 */
  	public boolean isRepeatEnabled() {
  		return repeat;
  	}
  
  	/**
  	 * Enables repeating. When repeating is enabled, actions will be executed multiple times. Once repeating is enabled, the input handler should read a number from the keyboard.
  	 */
  	public void setRepeatEnabled(boolean repeat) {
  		this.repeat = repeat;
  	}
  
  	/**
  	 * Returns the number of times the next action will be repeated.
  	 */
  	public int getRepeatCount() {
  		return (repeat ? Math.max(1, repeatCount) : 1);
  	}
  
  	/**
  	 * Sets the number of times the next action will be repeated.
  	 * 
  	 * @param repeatCount
  	 *            The repeat count
  	 */
  	public void setRepeatCount(int repeatCount) {
  		this.repeatCount = repeatCount;
  	}
  
  	/**
  	 * Returns the macro recorder. If this is non-null, all executed actions should be forwarded to the recorder.
  	 */
  	public InputHandler.MacroRecorder getMacroRecorder() {
  		return recorder;
  	}
  
  	/**
  	 * Sets the macro recorder. If this is non-null, all executed actions should be forwarded to the recorder.
  	 * 
  	 * @param recorder
  	 *            The macro recorder
  	 */
  	public void setMacroRecorder(InputHandler.MacroRecorder recorder) {
  		this.recorder = recorder;
  	}
  
  	/**
  	 * Returns a copy of this input handler that shares the same key bindings. Setting key bindings in the copy will also set them in the original.
  	 */
  	public abstract InputHandler copy();
  
  	/**
  	 * Executes the specified action, repeating and recording it as necessary.
  	 * 
  	 * @param listener
  	 *            The action listener
  	 * @param source
  	 *            The event source
  	 * @param actionCommand
  	 *            The action command
  	 */
  	public void executeAction(ActionListener listener, Object source, String actionCommand) {
  		// create event
  		ActionEvent evt = new ActionEvent(source, ActionEvent.ACTION_PERFORMED, actionCommand);
  
  		// don't do anything if the action is a wrapper
  		// (like EditAction.Wrapper)
  		if (listener instanceof Wrapper) {
  			listener.actionPerformed(evt);
  			return;
  		}
  
  		// remember old values, in case action changes them
  		boolean _repeat = repeat;
  		int _repeatCount = getRepeatCount();
  
  		// execute the action
  		if (listener instanceof InputHandler.NonRepeatable)
  			listener.actionPerformed(evt);
  		else {
  			for (int i = 0; i < Math.max(1, repeatCount); i++)
  				listener.actionPerformed(evt);
  		}
  
  		// do recording. Notice that we do no recording whatsoever
  		// for actions that grab keys
  		if (grabAction == null) {
  			if (recorder != null) {
  				if (!(listener instanceof InputHandler.NonRecordable)) {
  					if (_repeatCount != 1)
  						recorder.actionPerformed(REPEAT, String.valueOf(_repeatCount));
  
  					recorder.actionPerformed(listener, actionCommand);
  				}
  			}
  
  			// If repeat was true originally, clear it
  			// Otherwise it might have been set by the action, etc
  			if (_repeat) {
  				repeat = false;
  				repeatCount = 0;
  			}
  		}
  	}
  
  	/**
  	 * Returns the text area that fired the specified event.
  	 * 
  	 * @param evt
  	 *            The event
  	 */
  	public static JEditTextArea getTextArea(EventObject evt) {
  		if (evt != null) {
  			Object o = evt.getSource();
  			if (o instanceof Component) {
  				// find the parent text area
  				Component c = (Component) o;
  				for (;;) {
  					if (c instanceof JEditTextArea)
  						return (JEditTextArea) c;
  					else if (c == null)
  						break;
  					if (c instanceof JPopupMenu)
  						c = ((JPopupMenu) c).getInvoker();
  					else
  						c = c.getParent();
  				}
  			}
  		}
  
  		// this shouldn't happen
  		//System.err.println("BUG: getTextArea() returning null");
  		//System.err.println("Report this to Slava Pestov <sp@gjt.org>");
  		return null;
  	}
  
  	// protected members
  
  	/**
  	 * If a key is being grabbed, this method should be called with the appropriate key event. It executes the grab action with the typed character as the parameter.
  	 */
  	protected void handleGrabAction(KeyEvent evt) {
  		// Clear it *before* it is executed so that executeAction()
  		// resets the repeat count
  		ActionListener _grabAction = grabAction;
  		grabAction = null;
  		executeAction(_grabAction, evt.getSource(), String.valueOf(evt.getKeyChar()));
  	}
  
  	// protected members
  	protected ActionListener grabAction;
  
  	protected boolean repeat;
  
  	protected int repeatCount;
  
  	protected InputHandler.MacroRecorder recorder;
  
  	/**
  	 * If an action implements this interface, it should not be repeated. Instead, it will handle the repetition itself.
  	 */
  	public interface NonRepeatable {
  	}
  
  	/**
  	 * If an action implements this interface, it should not be recorded by the macro recorder. Instead, it will do its own recording.
  	 */
  	public interface NonRecordable {
  	}
  
  	/**
  	 * For use by EditAction.Wrapper only.
  	 * 
  	 * @since jEdit 2.2final
  	 */
  	public interface Wrapper {
  	}
  
  	/**
  	 * Macro recorder.
  	 */
  	public interface MacroRecorder {
  		void actionPerformed(ActionListener listener, String actionCommand);
  	}
  
  	public static class Backspace implements ActionListener {
  		public void actionPerformed(ActionEvent evt) {
  			JEditTextArea textArea = getTextArea(evt);
  
  			if (!textArea.isEditable()) {
  				textArea.getToolkit().beep();
  				return;
  			}
  
  			if (textArea.getSelectionStart() != textArea.getSelectionEnd()) {
  				textArea.setSelectedText("");
  			} else {
  				int caret = textArea.getCaretPosition();
  				if (caret == 0) {
  					textArea.getToolkit().beep();
  					return;
  				}
  				try {
  					textArea.getDocument().remove(caret - 1, 1);
  				} catch (BadLocationException bl) {
  					bl.printStackTrace();
  				}
  			}
  		}
  	}
  
  	public static class BackspaceWord implements ActionListener {
  		public void actionPerformed(ActionEvent evt) {
  