View Javadoc

    1   /*
    2    * InputHandler.java - Manages key bindings and executes actions
    3    * Copyright (C) 1999 Slava Pestov
    4    *
    5    * You may use and modify this package for any purpose. Redistribution is
    6    * permitted, in both source and binary form, provided that this notice
    7    * remains intact in all source distributions of this package.
    8    */
    9
    10  package org.syntax.jedit;
    11
    12  import java.awt.Component;
    13  import java.awt.event.ActionEvent;
    14  import java.awt.event.ActionListener;
    15  import java.awt.event.KeyAdapter;
    16  import java.awt.event.KeyEvent;
    17  import java.util.Enumeration;
    18  import java.util.EventObject;
    19  import java.util.Hashtable;
    20
    21  import javax.swing.AbstractAction;
    22  import javax.swing.Action;
    23  import javax.swing.JPopupMenu;
    24  import javax.swing.text.BadLocationException;
    25
    26  import com.eviware.soapui.SoapUI;
    27  import com.eviware.soapui.support.UISupport;
    28
    29  /***
    30   * An input handler converts the user's key strokes into concrete actions.
    31   * It also takes care of macro recording and action repetition.<p>
    32   *
    33   * This class provides all the necessary support code for an input
    34   * handler, but doesn't actually do any key binding logic. It is up
    35   * to the implementations of this class to do so.
    36   *
    37   * @author Slava Pestov
    38   * @version $Id$
    39   * @see org.syntax.jedit.DefaultInputHandler
    40   *
    41   * 08/12/2002	Clipboard actions	(Oliver Henning)
    42   */
    43  public abstract class InputHandler extends KeyAdapter
    44  {
    45  	/***
    46  	 * If this client property is set to Boolean.TRUE on the text area,
    47  	 * the home/end keys will support 'smart' BRIEF-like behaviour
    48  	 * (one press = start/end of line, two presses = start/end of
    49  	 * viewscreen, three presses = start/end of document). By default,
    50  	 * this property is not set.
    51  	 */
    52  	public static final String SMART_HOME_END_PROPERTY = "InputHandler.homeEnd";
    53
    54  	public static final ActionListener BACKSPACE = new backspace();
    55  	public static final ActionListener BACKSPACE_WORD = new backspace_word();
    56  	public static final ActionListener DELETE = new delete();
    57  	public static final ActionListener DELETE_WORD = new delete_word();
    58  	public static final ActionListener END = new end(false);
    59  	public static final ActionListener DOCUMENT_END = new document_end(false);
    60  	public static final ActionListener SELECT_ALL = new select_all();
    61  	public static final ActionListener SELECT_END = new end(true);
    62  	public static final ActionListener SELECT_DOC_END = new document_end(true);
    63  	public static final ActionListener INSERT_BREAK = new insert_break();
    64  	public static final ActionListener INSERT_TAB = new insert_tab();
    65  	public static final ActionListener HOME = new home(false);
    66  	public static final ActionListener DOCUMENT_HOME = new document_home(false);
    67  	public static final ActionListener SELECT_HOME = new home(true);
    68  	public static final ActionListener SELECT_DOC_HOME = new document_home(true);
    69  	public static final ActionListener NEXT_CHAR = new next_char(false);
    70  	public static final ActionListener NEXT_LINE = new next_line(false);
    71  	public static final ActionListener NEXT_PAGE = new next_page(false);
    72  	public static final ActionListener NEXT_WORD = new next_word(false);
    73  	public static final ActionListener SELECT_NEXT_CHAR = new next_char(true);
    74  	public static final ActionListener SELECT_NEXT_LINE = new next_line(true);
    75  	public static final ActionListener SELECT_NEXT_PAGE = new next_page(true);
    76  	public static final ActionListener SELECT_NEXT_WORD = new next_word(true);
    77  	public static final ActionListener OVERWRITE = new overwrite();
    78  	public static final ActionListener PREV_CHAR = new prev_char(false);
    79  	public static final ActionListener PREV_LINE = new prev_line(false);
    80  	public static final ActionListener PREV_PAGE = new prev_page(false);
    81  	public static final ActionListener PREV_WORD = new prev_word(false);
    82  	public static final ActionListener SELECT_PREV_CHAR = new prev_char(true);
    83  	public static final ActionListener SELECT_PREV_LINE = new prev_line(true);
    84  	public static final ActionListener SELECT_PREV_PAGE = new prev_page(true);
    85  	public static final ActionListener SELECT_PREV_WORD = new prev_word(true);
    86  	public static final ActionListener REPEAT = new repeat();
    87  	public static final ActionListener TOGGLE_RECT = new toggle_rect();
    88  	// Clipboard
    89  	public static final Action CLIP_COPY = new clip_copy();
    90  	public static final Action CLIP_PASTE = new clip_paste();
    91  	public static final Action CLIP_CUT = new clip_cut();
    92
    93  	// Default action
    94  	public static final ActionListener INSERT_CHAR = new insert_char();
    95
    96  	private static Hashtable<String,ActionListener> actions;
    97
    98  	static
    99  	{
    100 		actions = new Hashtable<String,ActionListener>();
    101 		actions.put("backspace",BACKSPACE);
    102 		actions.put("backspace-word",BACKSPACE_WORD);
    103 		actions.put("delete",DELETE);
    104 		actions.put("delete-word",DELETE_WORD);
    105 		actions.put("end",END);
    106 		actions.put("select-all",SELECT_ALL);
    107 		actions.put("select-end",SELECT_END);
    108 		actions.put("document-end",DOCUMENT_END);
    109 		actions.put("select-doc-end",SELECT_DOC_END);
    110 		actions.put("insert-break",INSERT_BREAK);
    111 		actions.put("insert-tab",INSERT_TAB);
    112 		actions.put("home",HOME);
    113 		actions.put("select-home",SELECT_HOME);
    114 		actions.put("document-home",DOCUMENT_HOME);
    115 		actions.put("select-doc-home",SELECT_DOC_HOME);
    116 		actions.put("next-char",NEXT_CHAR);
    117 		actions.put("next-line",NEXT_LINE);
    118 		actions.put("next-page",NEXT_PAGE);
    119 		actions.put("next-word",NEXT_WORD);
    120 		actions.put("select-next-char",SELECT_NEXT_CHAR);
    121 		actions.put("select-next-line",SELECT_NEXT_LINE);
    122 		actions.put("select-next-page",SELECT_NEXT_PAGE);
    123 		actions.put("select-next-word",SELECT_NEXT_WORD);
    124 		actions.put("overwrite",OVERWRITE);
    125 		actions.put("prev-char",PREV_CHAR);
    126 		actions.put("prev-line",PREV_LINE);
    127 		actions.put("prev-page",PREV_PAGE);
    128 		actions.put("prev-word",PREV_WORD);
    129 		actions.put("select-prev-char",SELECT_PREV_CHAR);
    130 		actions.put("select-prev-line",SELECT_PREV_LINE);
    131 		actions.put("select-prev-page",SELECT_PREV_PAGE);
    132 		actions.put("select-prev-word",SELECT_PREV_WORD);
    133 		actions.put("repeat",REPEAT);
    134 		actions.put("toggle-rect",TOGGLE_RECT);
    135 		actions.put("insert-char",INSERT_CHAR);
    136 		actions.put("clipboard-copy",CLIP_COPY);
    137 		actions.put("clipboard-paste",CLIP_PASTE);
    138 		actions.put("clipboard-cut",CLIP_CUT);
    139 	}
    140
    141 	/***
    142 	 * Returns a named text area action.
    143 	 * @param name The action name
    144 	 */
    145 	public static ActionListener getAction(String name)
    146 	{
    147 		return (ActionListener)actions.get(name);
    148 	}
    149
    150 	/***
    151 	 * Returns the name of the specified text area action.
    152 	 * @param listener The action
    153 	 */
    154 	public static String getActionName(ActionListener listener)
    155 	{
    156 		Enumeration _enum = getActions();
    157 		while(_enum.hasMoreElements())
    158 		{
    159 			String name = (String)_enum.nextElement();
    160 			ActionListener _listener = getAction(name);
    161 			if(_listener == listener)
    162 				return name;
    163 		}
    164 		return null;
    165 	}
    166
    167 	/***
    168 	 * Returns an enumeration of all available actions.
    169 	 */
    170 	public static Enumeration getActions()
    171 	{
    172 		return actions.keys();
    173 	}
    174
    175 	/***
    176 	 * Adds the default key bindings to this input handler.
    177 	 * This should not be called in the constructor of this
    178 	 * input handler, because applications might load the
    179 	 * key bindings from a file, etc.
    180 	 */
    181 	public abstract void addDefaultKeyBindings();
    182
    183 	/***
    184 	 * Adds a key binding to this input handler.
    185 	 * @param keyBinding The key binding (the format of this is
    186 	 * input-handler specific)
    187 	 * @param action The action
    188 	 */
    189 	public abstract void addKeyBinding(String keyBinding, ActionListener action);
    190
    191 	/***
    192 	 * Removes a key binding from this input handler.
    193 	 * @param keyBinding The key binding
    194 	 */
    195 	public abstract void removeKeyBinding(String keyBinding);
    196
    197 	/***
    198 	 * Removes all key bindings from this input handler.
    199 	 */
    200 	public abstract void removeAllKeyBindings();
    201
    202 	/***
    203 	 * Grabs the next key typed event and invokes the specified
    204 	 * action with the key as a the action command.
    205 	 * @param action The action
    206 	 */
    207 	public void grabNextKeyStroke(ActionListener listener)
    208 	{
    209 		grabAction = listener;
    210 	}
    211
    212 	/***
    213 	 * Returns if repeating is enabled. When repeating is enabled,
    214 	 * actions will be executed multiple times. This is usually
    215 	 * invoked with a special key stroke in the input handler.
    216 	 */
    217 	public boolean isRepeatEnabled()
    218 	{
    219 		return repeat;
    220 	}
    221
    222 	/***
    223 	 * Enables repeating. When repeating is enabled, actions will be
    224 	 * executed multiple times. Once repeating is enabled, the input
    225 	 * handler should read a number from the keyboard.
    226 	 */
    227 	public void setRepeatEnabled(boolean repeat)
    228 	{
    229 		this.repeat = repeat;
    230 	}
    231
    232 	/***
    233 	 * Returns the number of times the next action will be repeated.
    234 	 */
    235 	public int getRepeatCount()
    236 	{
    237 		return (repeat ? Math.max(1,repeatCount) : 1);
    238 	}
    239
    240 	/***
    241 	 * Sets the number of times the next action will be repeated.
    242 	 * @param repeatCount The repeat count
    243 	 */
    244 	public void setRepeatCount(int repeatCount)
    245 	{
    246 		this.repeatCount = repeatCount;
    247 	}
    248
    249 	/***
    250 	 * Returns the macro recorder. If this is non-null, all executed
    251 	 * actions should be forwarded to the recorder.
    252 	 */
    253 	public InputHandler.MacroRecorder getMacroRecorder()
    254 	{
    255 		return recorder;
    256 	}
    257
    258 	/***
    259 	 * Sets the macro recorder. If this is non-null, all executed
    260 	 * actions should be forwarded to the recorder.
    261 	 * @param recorder The macro recorder
    262 	 */
    263 	public void setMacroRecorder(InputHandler.MacroRecorder recorder)
    264 	{
    265 		this.recorder = recorder;
    266 	}
    267
    268 	/***
    269 	 * Returns a copy of this input handler that shares the same
    270 	 * key bindings. Setting key bindings in the copy will also
    271 	 * set them in the original.
    272 	 */
    273 	public abstract InputHandler copy();
    274
    275 	/***
    276 	 * Executes the specified action, repeating and recording it as
    277 	 * necessary.
    278 	 * @param listener The action listener
    279 	 * @param source The event source
    280 	 * @param actionCommand The action command
    281 	 */
    282 	public void executeAction(ActionListener listener, Object source,
    283 		String actionCommand)
    284 	{
    285 		// create event
    286 		ActionEvent evt = new ActionEvent(source,
    287 			ActionEvent.ACTION_PERFORMED,
    288 			actionCommand);
    289
    290 		// don't do anything if the action is a wrapper
    291 		// (like EditAction.Wrapper)
    292 		if(listener instanceof Wrapper)
    293 		{
    294 			listener.actionPerformed(evt);
    295 			return;
    296 		}
    297
    298 		// remember old values, in case action changes them
    299 		boolean _repeat = repeat;
    300 		int _repeatCount = getRepeatCount();
    301
    302 		// execute the action
    303 		if(listener instanceof InputHandler.NonRepeatable)
    304 			listener.actionPerformed(evt);
    305 		else
    306 		{
    307 			for(int i = 0; i < Math.max(1,repeatCount); i++)
    308 				listener.actionPerformed(evt);
    309 		}
    310
    311 		// do recording. Notice that we do no recording whatsoever
    312 		// for actions that grab keys
    313 		if(grabAction == null)
    314 		{
    315 			if(recorder != null)
    316 			{
    317 				if(!(listener instanceof InputHandler.NonRecordable))
    318 				{
    319 					if(_repeatCount != 1)
    320 						recorder.actionPerformed(REPEAT,String.valueOf(_repeatCount));
    321
    322 					recorder.actionPerformed(listener,actionCommand);
    323 				}
    324 			}
    325
    326 			// If repeat was true originally, clear it
    327 			// Otherwise it might have been set by the action, etc
    328 			if(_repeat)
    329 			{
    330 				repeat = false;
    331 				repeatCount = 0;
    332 			}
    333 		}
    334 	}
    335
    336 	/***
    337 	 * Returns the text area that fired the specified event.
    338 	 * @param evt The event
    339 	 */
    340 	public static JEditTextArea getTextArea(EventObject evt)
    341 	{
    342 		if(evt != null)
    343 		{
    344 			Object o = evt.getSource();
    345 			if(o instanceof Component)
    346 			{
    347 				// find the parent text area
    348 				Component c = (Component)o;
    349 				for(;;)
    350 				{
    351 					if(c instanceof JEditTextArea)
    352 						return (JEditTextArea)c;
    353 					else if(c == null)
    354 						break;
    355 					if(c instanceof JPopupMenu)
    356 						c = ((JPopupMenu)c)
    357 							.getInvoker();
    358 					else
    359 						c = c.getParent();
    360 				}
    361 			}
    362 		}
    363
    364 		// this shouldn't happen
    365 		System.err.println("BUG: getTextArea() returning null");
    366 		System.err.println("Report this to Slava Pestov <sp@gjt.org>");
    367 		return null;
    368 	}
    369
    370 	// protected members
    371
    372 	/***
    373 	 * If a key is being grabbed, this method should be called with
    374 	 * the appropriate key event. It executes the grab action with
    375 	 * the typed character as the parameter.
    376 	 */
    377 	protected void handleGrabAction(KeyEvent evt)
    378 	{
    379 		// Clear it *before* it is executed so that executeAction()
    380 		// resets the repeat count
    381 		ActionListener _grabAction = grabAction;
    382 		grabAction = null;
    383 		executeAction(_grabAction,evt.getSource(),
    384 			String.valueOf(evt.getKeyChar()));
    385 	}
    386
    387 	// protected members
    388 	protected ActionListener grabAction;
    389 	protected boolean repeat;
    390 	protected int repeatCount;
    391 	protected InputHandler.MacroRecorder recorder;
    392
    393 	/***
    394 	 * If an action implements this interface, it should not be repeated.
    395 	 * Instead, it will handle the repetition itself.
    396 	 */
    397 	public interface NonRepeatable {}
    398
    399 	/***
    400 	 * If an action implements this interface, it should not be recorded
    401 	 * by the macro recorder. Instead, it will do its own recording.
    402 	 */
    403 	public interface NonRecordable {}
    404
    405 	/***
    406 	 * For use by EditAction.Wrapper only.
    407 	 * @since jEdit 2.2final
    408 	 */
    409 	public interface Wrapper {}
    410
    411 	/***
    412 	 * Macro recorder.
    413 	 */
    414 	public interface MacroRecorder
    415 	{
    416 		void actionPerformed(ActionListener listener,
    417 			String actionCommand);
    418 	}
    419
    420 	public static class backspace implements ActionListener
    421 	{
    422 		public void actionPerformed(ActionEvent evt)
    423 		{
    424 			JEditTextArea textArea = getTextArea(evt);
    425
    426 			if(!textArea.isEditable())
    427 			{
    428 				textArea.getToolkit().beep();
    429 				return;
    430 			}
    431
    432 			if(textArea.getSelectionStart()
    433 			   != textArea.getSelectionEnd())
    434 			{
    435 				textArea.setSelectedText("");
    436 			}
    437 			else
    438 			{
    439 				int caret = textArea.getCaretPosition();
    440 				if(caret == 0)
    441 				{
    442 					textArea.getToolkit().beep();
    443 					return;
    444 				}
    445 				try
    446 				{
    447 					textArea.getDocument().remove(caret - 1,1);
    448 				}
    449 				catch(BadLocationException bl)
    450 				{
    451 					SoapUI.logError( bl );
    452 				}
    453 			}
    454 		}
    455 	}
    456
    457 	public static class backspace_word implements ActionListener
    458 	{
    459 		public void actionPerformed(ActionEvent evt)
    460 		{
    461 			JEditTextArea textArea = getTextArea(evt);
    462 			int start = textArea.getSelectionStart();
    463 			if(start != textArea.getSelectionEnd())
    464 			{
    465 				textArea.setSelectedText("");
    466 			}
    467
    468 			int line = textArea.getCaretLine();
    469 			int lineStart = textArea.getLineStartOffset(line);
    470 			int caret = start - lineStart;
    471
    472 			String lineText = textArea.getLineText(textArea
    473 				.getCaretLine());
    474
    475 			if(caret == 0)
    476 			{
    477 				if(lineStart == 0)
    478 				{
    479 					textArea.getToolkit().beep();
    480 					return;
    481 				}
    482 				caret--;
    483 			}
    484 			else
    485 			{
    486 				String noWordSep = (String)textArea.getDocument().getProperty("noWordSep");
    487 				caret = TextUtilities.findWordStart(lineText,caret,noWordSep);
    488 			}
    489
    490 			try
    491 			{
    492 				textArea.getDocument().remove(
    493 						caret + lineStart,
    494 						start - (caret + lineStart));
    495 			}
    496 			catch(BadLocationException bl)
    497 			{
    498 				SoapUI.logError( bl );
    499 			}
    500 		}
    501 	}
    502
    503 	public static class delete implements ActionListener
    504 	{
    505 		public void actionPerformed(ActionEvent evt)
    506 		{
    507 			JEditTextArea textArea = getTextArea(evt);
    508
    509 			if(!textArea.isEditable())
    510 			{
    511 				textArea.getToolkit().beep();
    512 				return;
    513 			}
    514
    515 			if(textArea.getSelectionStart()
    516 			   != textArea.getSelectionEnd())
    517 			{
    518 				textArea.setSelectedText("");
    519 			}
    520 			else
    521 			{
    522 				int caret = textArea.getCaretPosition();
    523 				if(caret == textArea.getDocumentLength())
    524 				{
    525 					textArea.getToolkit().beep();
    526 					return;
    527 				}
    528 				try
    529 				{
    530 					textArea.getDocument().remove(caret,1);
    531 				}
    532 				catch(BadLocationException bl)
    533 				{
    534 					SoapUI.logError( bl );
    535 				}
    536 			}
    537 		}
    538 	}
    539
    540 	public static class delete_word implements ActionListener
    541 	{
    542 		public void actionPerformed(ActionEvent evt)
    543 		{
    544 			JEditTextArea textArea = getTextArea(evt);
    545 			int start = textArea.getSelectionStart();
    546 			if(start != textArea.getSelectionEnd())
    547 			{
    548 				textArea.setSelectedText("");
    549 			}
    550
    551 			int line = textArea.getCaretLine();
    552 			int lineStart = textArea.getLineStartOffset(line);
    553 			int caret = start - lineStart;
    554
    555 			String lineText = textArea.getLineText(textArea
    556 				.getCaretLine());
    557
    558 			if(caret == lineText.length())
    559 			{
    560 				if(lineStart + caret == textArea.getDocumentLength())
    561 				{
    562 					textArea.getToolkit().beep();
    563 					return;
    564 				}
    565 				caret++;
    566 			}
    567 			else
    568 			{
    569 				String noWordSep = (String)textArea.getDocument().getProperty("noWordSep");
    570 				caret = TextUtilities.findWordEnd(lineText,caret,noWordSep);
    571 			}
    572
    573 			try
    574 			{
    575 				textArea.getDocument().remove(start,
    576 					(caret + lineStart) - start);
    577 			}
    578 			catch(BadLocationException bl)
    579 			{
    580 				SoapUI.logError( bl );
    581 			}
    582 		}
    583 	}
    584
    585 	public static class end implements ActionListener
    586 	{
    587 		private boolean select;
    588
    589 		public end(boolean select)
    590 		{
    591 			this.select = select;
    592 		}
    593
    594 		public void actionPerformed(ActionEvent evt)
    595 		{
    596 			JEditTextArea textArea = getTextArea(evt);
    597
    598 			int caret = textArea.getCaretPosition();
    599
    600 			int lastOfLine = textArea.getLineEndOffset(
    601 				textArea.getCaretLine()) - 1;
    602 			int lastVisibleLine = textArea.getFirstLine()
    603 				+ textArea.getVisibleLines();
    604 			if(lastVisibleLine >= textArea.getLineCount())
    605 			{
    606 				lastVisibleLine = Math.min(textArea.getLineCount() - 1,
    607 					lastVisibleLine);
    608 			}
    609 			else
    610 				lastVisibleLine -= 1; //(textArea.getElectricScroll() + 1);
    611
    612 			int lastVisible = textArea.getLineEndOffset(lastVisibleLine) - 1;
    613 			int lastDocument = textArea.getDocumentLength();
    614
    615 			if(caret == lastDocument)
    616 			{
    617 				textArea.getToolkit().beep();
    618 				return;
    619 			}
    620 			else if(!Boolean.TRUE.equals(textArea.getClientProperty(
    621 				SMART_HOME_END_PROPERTY)))
    622 				caret = lastOfLine;
    623 			else if(caret == lastVisible)
    624 				caret = lastDocument;
    625 			else if(caret == lastOfLine)
    626 				caret = lastVisible;
    627 			else
    628 				caret = lastOfLine;
    629
    630 			if(select)
    631 				textArea.select(textArea.getMarkPosition(),caret);
    632 			else
    633 				textArea.setCaretPosition(caret);
    634 		}
    635 	}
    636
    637 	public static class select_all implements ActionListener {
    638 		public void actionPerformed(ActionEvent evt)
    639 		{
    640 			JEditTextArea textArea = getTextArea(evt);
    641 			textArea.selectAll();
    642 		}
    643 	}
    644
    645 	public static class document_end implements ActionListener
    646 	{
    647 		private boolean select;
    648
    649 		public document_end(boolean select)
    650 		{
    651 			this.select = select;
    652 		}
    653
    654 		public void actionPerformed(ActionEvent evt)
    655 		{
    656 			JEditTextArea textArea = getTextArea(evt);
    657 			if(select)
    658 				textArea.select(textArea.getMarkPosition(),
    659 					textArea.getDocumentLength());
    660 			else
    661 				textArea.setCaretPosition(textArea
    662 					.getDocumentLength());
    663 		}
    664 	}
    665
    666 	public static class home implements ActionListener
    667 	{
    668 		private boolean select;
    669
    670 		public home(boolean select)
    671 		{
    672 			this.select = select;
    673 		}
    674
    675 		public void actionPerformed(ActionEvent evt)
    676 		{
    677 			JEditTextArea textArea = getTextArea(evt);
    678
    679 			int caret = textArea.getCaretPosition();
    680
    681 			int firstLine = textArea.getFirstLine();
    682
    683 			int firstOfLine = textArea.getLineStartOffset(
    684 				textArea.getCaretLine());
    685 			int firstVisibleLine = (firstLine == 0 ? 0 :
    686 				firstLine + 1 );
    687 			int firstVisible = textArea.getLineStartOffset(
    688 				firstVisibleLine);
    689
    690 			if(caret == 0)
    691 			{
    692 				textArea.getToolkit().beep();
    693 				return;
    694 			}
    695 			else if(!Boolean.TRUE.equals(textArea.getClientProperty(
    696 				SMART_HOME_END_PROPERTY)))
    697 				caret = firstOfLine;
    698 			else if(caret == firstVisible)
    699 				caret = 0;
    700 			else if(caret == firstOfLine)
    701 				caret = firstVisible;
    702 			else
    703 				caret = firstOfLine;
    704
    705 			if(select)
    706 				textArea.select(textArea.getMarkPosition(),caret);
    707 			else
    708 				textArea.setCaretPosition(caret);
    709 		}
    710 	}
    711
    712 	public static class document_home implements ActionListener
    713 	{
    714 		private boolean select;
    715
    716 		public document_home(boolean select)
    717 		{
    718 			this.select = select;
    719 		}
    720
    721 		public void actionPerformed(ActionEvent evt)
    722 		{
    723 			JEditTextArea textArea = getTextArea(evt);
    724 			if(select)
    725 				textArea.select(textArea.getMarkPosition(),0);
    726 			else
    727 				textArea.setCaretPosition(0);
    728 		}
    729 	}
    730
    731 	public static class insert_break implements ActionListener
    732 	{
    733 		public void actionPerformed(ActionEvent evt)
    734 		{
    735 			JEditTextArea textArea = getTextArea(evt);
    736
    737 			if(!textArea.isEditable())
    738 			{
    739 				textArea.getToolkit().beep();
    740 				return;
    741 			}
    742
    743 			textArea.setSelectedText("\n");
    744 		}
    745 	}
    746
    747 	public static class insert_tab implements ActionListener
    748 	{
    749 		public void actionPerformed(ActionEvent evt)
    750 		{
    751 			JEditTextArea textArea = getTextArea(evt);
    752
    753 			if(!textArea.isEditable())
    754 			{
    755 				textArea.getToolkit().beep();
    756 				return;
    757 			}
    758
    759 			textArea.overwriteSetSelectedText("\t");
    760 		}
    761 	}
    762
    763 	public static class next_char implements ActionListener
    764 	{
    765 		private boolean select;
    766
    767 		public next_char(boolean select)
    768 		{
    769 			this.select = select;
    770 		}
    771
    772 		public void actionPerformed(ActionEvent evt)
    773 		{
    774 			JEditTextArea textArea = getTextArea(evt);
    775 			int caret = textArea.getCaretPosition();
    776 			if(caret == textArea.getDocumentLength())
    777 			{
    778 				textArea.getToolkit().beep();
    779 				return;
    780 			}
    781
    782 			if(select)
    783 				textArea.select(textArea.getMarkPosition(),
    784 					caret + 1);
    785 			else
    786 				textArea.setCaretPosition(caret + 1);
    787 		}
    788 	}
    789
    790 	public static class next_line implements ActionListener
    791 	{
    792 		private boolean select;
    793
    794 		public next_line(boolean select)
    795 		{
    796 			this.select = select;
    797 		}
    798
    799 		public void actionPerformed(ActionEvent evt)
    800 		{
    801 			JEditTextArea textArea = getTextArea(evt);
    802 			int caret = textArea.getCaretPosition();
    803 			int line = textArea.getCaretLine();
    804
    805 			if(line == textArea.getLineCount() - 1)
    806 			{
    807 				textArea.getToolkit().beep();
    808 				return;
    809 			}
    810
    811 			int magic = textArea.getMagicCaretPosition();
    812 			if(magic == -1)
    813 			{
    814 				magic = textArea.offsetToX(line,
    815 					caret - textArea.getLineStartOffset(line));
    816 			}
    817
    818 			caret = textArea.getLineStartOffset(line + 1)
    819 				+ textArea.xToOffset(line + 1,magic);
    820 			if(select)
    821 				textArea.select(textArea.getMarkPosition(),caret);
    822 			else
    823 				textArea.setCaretPosition(caret);
    824 			textArea.setMagicCaretPosition(magic);
    825 		}
    826 	}
    827
    828 	public static class next_page implements ActionListener
    829 	{
    830 		private boolean select;
    831
    832 		public next_page(boolean select)
    833 		{
    834 			this.select = select;
    835 		}
    836
    837 		public void actionPerformed(ActionEvent evt)
    838 		{
    839 			JEditTextArea textArea = getTextArea(evt);
    840 			int lineCount = textArea.getLineCount();
    841 			int firstLine = textArea.getFirstLine();
    842 			int visibleLines = textArea.getVisibleLines();
    843 			int line = textArea.getCaretLine();
    844
    845 			firstLine += visibleLines;
    846
    847 			if(firstLine + visibleLines >= lineCount - 1)
    848 				firstLine = lineCount - visibleLines;
    849
    850 			textArea.setFirstLine(firstLine);
    851
    852 			int caret = textArea.getLineStartOffset(
    853 				Math.min(textArea.getLineCount() - 1,
    854 				line + visibleLines));
    855 			if(select)
    856 				textArea.select(textArea.getMarkPosition(),caret);
    857 			else
    858 				textArea.setCaretPosition(caret);
    859 		}
    860 	}
    861
    862 	public static class next_word implements ActionListener
    863 	{
    864 		private boolean select;
    865
    866 		public next_word(boolean select)
    867 		{
    868 			this.select = select;
    869 		}
    870
    871 		public void actionPerformed(ActionEvent evt)
    872 		{
    873 			JEditTextArea textArea = getTextArea(evt);
    874 			int caret = textArea.getCaretPosition();
    875 			int line = textArea.getCaretLine();
    876 			int lineStart = textArea.getLineStartOffset(line);
    877 			caret -= lineStart;
    878
    879 			String lineText = textArea.getLineText(textArea
    880 				.getCaretLine());
    881
    882 			if(caret == lineText.length())
    883 			{
    884 				if(lineStart + caret == textArea.getDocumentLength())
    885 				{
    886 					textArea.getToolkit().beep();
    887 					return;
    888 				}
    889 				caret++;
    890 			}
    891 			else
    892 			{
    893 				String noWordSep = (String)textArea.getDocument().getProperty("noWordSep");
    894 				caret = TextUtilities.findWordEnd(lineText,caret,noWordSep);
    895 			}
    896
    897 			if(select)
    898 				textArea.select(textArea.getMarkPosition(),
    899 					lineStart + caret);
    900 			else
    901 				textArea.setCaretPosition(lineStart + caret);
    902 		}
    903 	}
    904
    905 	public static class overwrite implements ActionListener
    906 	{
    907 		public void actionPerformed(ActionEvent evt)
    908 		{
    909 			JEditTextArea textArea = getTextArea(evt);
    910 			textArea.setOverwriteEnabled(
    911 				!textArea.isOverwriteEnabled());
    912 		}
    913 	}
    914
    915 	public static class prev_char implements ActionListener
    916 	{
    917 		private boolean select;
    918
    919 		public prev_char(boolean select)
    920 		{
    921 			this.select = select;
    922 		}
    923
    924 		public void actionPerformed(ActionEvent evt)
    925 		{
    926 			JEditTextArea textArea = getTextArea(evt);
    927 			int caret = textArea.getCaretPosition();
    928 			if(caret == 0)
    929 			{
    930 				textArea.getToolkit().beep();
    931 				return;
    932 			}
    933
    934 			if(select)
    935 				textArea.select(textArea.getMarkPosition(),
    936 					caret - 1);
    937 			else
    938 				textArea.setCaretPosition(caret - 1);
    939 		}
    940 	}
    941
    942 	public static class prev_line implements ActionListener
    943 	{
    944 		private boolean select;
    945
    946 		public prev_line(boolean select)
    947 		{
    948 			this.select = select;
    949 		}
    950
    951 		public void actionPerformed(ActionEvent evt)
    952 		{
    953 			JEditTextArea textArea = getTextArea(evt);
    954 			int caret = textArea.getCaretPosition();
    955 			int line = textArea.getCaretLine();
    956
    957 			if(line == 0)
    958 			{
    959 				textArea.getToolkit().beep();
    960 				return;
    961 			}
    962
    963 			int magic = textArea.getMagicCaretPosition();
    964 			if(magic == -1)
    965 			{
    966 				magic = textArea.offsetToX(line,
    967 					caret - textArea.getLineStartOffset(line));
    968 			}
    969
    970 			caret = textArea.getLineStartOffset(line - 1)
    971 				+ textArea.xToOffset(line - 1,magic);
    972 			if(select)
    973 				textArea.select(textArea.getMarkPosition(),caret);
    974 			else
    975 				textArea.setCaretPosition(caret);
    976 			textArea.setMagicCaretPosition(magic);
    977 		}
    978 	}
    979
    980 	public static class prev_page implements ActionListener
    981 	{
    982 		private boolean select;
    983
    984 		public prev_page(boolean select)
    985 		{
    986 			this.select = select;
    987 		}
    988
    989 		public void actionPerformed(ActionEvent evt)
    990 		{
    991 			JEditTextArea textArea = getTextArea(evt);
    992 			int firstLine = textArea.getFirstLine();
    993 			int visibleLines = textArea.getVisibleLines();
    994 			int line = textArea.getCaretLine();
    995
    996 			if(firstLine < visibleLines)
    997 				firstLine = visibleLines;
    998
    999 			textArea.setFirstLine(firstLine - visibleLines);
    1000
    1001 			int caret = textArea.getLineStartOffset(
    1002 				Math.max(0,line - visibleLines));
    1003 			if(select)
    1004 				textArea.select(textArea.getMarkPosition(),caret);
    1005 			else
    1006 				textArea.setCaretPosition(caret);
    1007 		}
    1008 	}
    1009
    1010 	public static class prev_word implements ActionListener
    1011 	{
    1012 		private boolean select;
    1013
    1014 		public prev_word(boolean select)
    1015 		{
    1016 			this.select = select;
    1017 		}
    1018
    1019 		public void actionPerformed(ActionEvent evt)
    1020 		{
    1021 			JEditTextArea textArea = getTextArea(evt);
    1022 			int caret = textArea.getCaretPosition();
    1023 			int line = textArea.getCaretLine();
    1024 			int lineStart = textArea.getLineStartOffset(line);
    1025 			caret -= lineStart;
    1026
    1027 			String lineText = textArea.getLineText(textArea
    1028 				.getCaretLine());
    1029
    1030 			if(caret == 0)
    1031 			{
    1032 				if(lineStart == 0)
    1033 				{
    1034 					textArea.getToolkit().beep();
    1035 					return;
    1036 				}
    1037 				caret--;
    1038 			}
    1039 			else
    1040 			{
    1041 				String noWordSep = (String)textArea.getDocument().getProperty("noWordSep");
    1042 				caret = TextUtilities.findWordStart(lineText,caret,noWordSep);
    1043 			}
    1044
    1045 			if(select)
    1046 				textArea.select(textArea.getMarkPosition(),
    1047 					lineStart + caret);
    1048 			else
    1049 				textArea.setCaretPosition(lineStart + caret);
    1050 		}
    1051 	}
    1052
    1053 	public static class repeat implements ActionListener,
    1054 		InputHandler.NonRecordable
    1055 	{
    1056 		public void actionPerformed(ActionEvent evt)
    1057 		{
    1058 			JEditTextArea textArea = getTextArea(evt);
    1059 			textArea.getInputHandler().setRepeatEnabled(true);
    1060 			String actionCommand = evt.getActionCommand();
    1061 			if(actionCommand != null)
    1062 			{
    1063 				textArea.getInputHandler().setRepeatCount(
    1064 					Integer.parseInt(actionCommand));
    1065 			}
    1066 		}
    1067 	}
    1068
    1069 	public static class toggle_rect implements ActionListener
    1070 	{
    1071 		public void actionPerformed(ActionEvent evt)
    1072 		{
    1073 			JEditTextArea textArea = getTextArea(evt);
    1074 			textArea.setSelectionRectangular(
    1075 				!textArea.isSelectionRectangular());
    1076 		}
    1077 	}
    1078
    1079 	public static class insert_char implements ActionListener,
    1080 		InputHandler.NonRepeatable
    1081 	{
    1082 		public void actionPerformed(ActionEvent evt)
    1083 		{
    1084 			JEditTextArea textArea = getTextArea(evt);
    1085 			String str = evt.getActionCommand();
    1086 			int repeatCount = textArea.getInputHandler().getRepeatCount();
    1087
    1088 			if(textArea.isEditable())
    1089 			{
    1090 				StringBuffer buf = new StringBuffer();
    1091 				for(int i = 0; i < repeatCount; i++)
    1092 					buf.append(str);
    1093 				textArea.overwriteSetSelectedText(buf.toString());
    1094 			}
    1095 			else
    1096 			{
    1097 				textArea.getToolkit().beep();
    1098 			}
    1099 		}
    1100 	}
    1101
    1102 	public static class clip_copy extends AbstractAction {
    1103
    1104 		public clip_copy()
    1105 		{
    1106 			super( "Copy" );
    1107 			putValue( Action.ACCELERATOR_KEY, UISupport.getKeyStroke( "menu C" ));
    1108 		}
    1109
    1110 		public void actionPerformed(ActionEvent evt)
    1111 		{
    1112 			JEditTextArea textArea = getTextArea(evt);
    1113 			textArea.copy();
    1114 		}
    1115 	}
    1116
    1117 	public static class clip_paste extends AbstractAction {
    1118
    1119 		public clip_paste()
    1120 		{
    1121 			super( "Paste" );
    1122 			putValue( Action.ACCELERATOR_KEY, UISupport.getKeyStroke( "menu V" ));
    1123 		}
    1124
    1125 		public void actionPerformed(ActionEvent evt)
    1126 		{
    1127 			JEditTextArea textArea = getTextArea(evt);
    1128 			textArea.paste();
    1129 		}
    1130 	}
    1131
    1132 	public static class clip_cut extends AbstractAction {
    1133
    1134 		public clip_cut()
    1135 		{
    1136 			super( "Cut" );
    1137 			putValue( Action.ACCELERATOR_KEY, UISupport.getKeyStroke( "menu X" ));
    1138 		}
    1139
    1140 		public void actionPerformed(ActionEvent evt)
    1141 		{
    1142 			JEditTextArea textArea = getTextArea(evt);
    1143 			textArea.cut();
    1144 		}
    1145 	}
    1146 }