0001: package workbench.gui.editor;
0002:
0003: /*
0004: * InputHandler.java - Manages key bindings and executes actions
0005: * Copyright (C) 1999 Slava Pestov
0006: *
0007: * You may use and modify this package for any purpose. Redistribution is
0008: * permitted, in both source and binary form, provided that this notice
0009: * remains intact in all source distributions of this package.
0010: */
0011:
0012: import java.awt.Component;
0013: import java.awt.event.ActionEvent;
0014: import java.awt.event.ActionListener;
0015: import java.awt.event.KeyAdapter;
0016: import java.awt.event.KeyEvent;
0017: import java.util.EventObject;
0018: import java.util.HashMap;
0019: import java.util.Iterator;
0020:
0021: import javax.swing.JPopupMenu;
0022: import javax.swing.KeyStroke;
0023: import javax.swing.text.BadLocationException;
0024: import workbench.resource.Settings;
0025:
0026: /**
0027: * An input handler converts the user's key strokes into concrete actions.
0028: * It also takes care of macro recording and action repetition.<p>
0029: *
0030: * This class provides all the necessary support code for an input
0031: * handler, but doesn't actually do any key binding logic. It is up
0032: * to the implementations of this class to do so.
0033: *
0034: * @author Slava Pestov
0035: * @version $Id: InputHandler.java,v 1.26 2007/10/19 18:06:50 thomas Exp $
0036: * @see DefaultInputHandler
0037: */
0038: public abstract class InputHandler extends KeyAdapter {
0039: /**
0040: * If this client property is set to Boolean.TRUE on the text area,
0041: * the home/end keys will support 'smart' BRIEF-like behaviour
0042: * (one press = start/end of line, two presses = start/end of
0043: * viewscreen, three presses = start/end of document). By default,
0044: * this property is not set.
0045: */
0046: public static final String SMART_HOME_END_PROPERTY = "InputHandler.homeEnd";
0047:
0048: public static final ActionListener BACKSPACE = new backspace();
0049: public static final ActionListener BACKSPACE_WORD = new backspace_word();
0050: public static final ActionListener DELETE = new delete();
0051: public static final ActionListener DELETE_WORD = new delete_word();
0052: public static final ActionListener END = new end(false);
0053: public static final ActionListener DOCUMENT_END = new document_end(
0054: false);
0055: public static final ActionListener SELECT_END = new end(true);
0056: public static final ActionListener SELECT_DOC_END = new document_end(
0057: true);
0058: public static final ActionListener INSERT_BREAK = new insert_break();
0059: public static final ActionListener INSERT_TAB = new insert_tab();
0060: public static final ActionListener HOME = new home(false);
0061: public static final ActionListener DOCUMENT_HOME = new document_home(
0062: false);
0063: public static final ActionListener SELECT_HOME = new home(true);
0064: public static final ActionListener SELECT_DOC_HOME = new document_home(
0065: true);
0066: public static final ActionListener NEXT_CHAR = new next_char(false);
0067: public static final ActionListener NEXT_LINE = new next_line(false);
0068: public static final ActionListener NEXT_PAGE = new next_page(false);
0069: public static final ActionListener NEXT_WORD = new next_word(false);
0070: public static final ActionListener SELECT_NEXT_CHAR = new next_char(
0071: true);
0072: public static final ActionListener SELECT_NEXT_LINE = new next_line(
0073: true);
0074: public static final ActionListener SELECT_NEXT_PAGE = new next_page(
0075: true);
0076: public static final ActionListener SELECT_NEXT_WORD = new next_word(
0077: true);
0078: public static final ActionListener OVERWRITE = new overwrite();
0079: public static final ActionListener PREV_CHAR = new prev_char(false);
0080: public static final ActionListener PREV_LINE = new prev_line(false);
0081: public static final ActionListener PREV_PAGE = new prev_page(false);
0082: public static final ActionListener PREV_WORD = new prev_word(false);
0083: public static final ActionListener SELECT_PREV_CHAR = new prev_char(
0084: true);
0085: public static final ActionListener SELECT_PREV_LINE = new prev_line(
0086: true);
0087: public static final ActionListener SELECT_PREV_PAGE = new prev_page(
0088: true);
0089: public static final ActionListener SELECT_PREV_WORD = new prev_word(
0090: true);
0091: public static final ActionListener REPEAT = new repeat();
0092: public static final ActionListener TOGGLE_RECT = new toggle_rect();
0093: public static final ActionListener MAKE_UPPER_CASE = new make_upper();
0094: public static final ActionListener MAKE_LOWER_CASE = new make_lower();
0095: public static final ActionListener UNDO = new undo();
0096: public static final ActionListener REDO = new redo();
0097: //public static final ActionListener MATCH_BRACKET = new match_bracket();
0098:
0099: // Default action
0100: public static final ActionListener INSERT_CHAR = new insert_char();
0101:
0102: private static HashMap actions;
0103:
0104: static {
0105: actions = new HashMap();
0106: actions.put("backspace", BACKSPACE);
0107: actions.put("backspace-word", BACKSPACE_WORD);
0108: actions.put("delete", DELETE);
0109: actions.put("delete-word", DELETE_WORD);
0110: actions.put("end", END);
0111: actions.put("select-end", SELECT_END);
0112: actions.put("document-end", DOCUMENT_END);
0113: actions.put("select-doc-end", SELECT_DOC_END);
0114: actions.put("insert-break", INSERT_BREAK);
0115: actions.put("insert-tab", INSERT_TAB);
0116: actions.put("home", HOME);
0117: actions.put("select-home", SELECT_HOME);
0118: actions.put("document-home", DOCUMENT_HOME);
0119: actions.put("select-doc-home", SELECT_DOC_HOME);
0120: actions.put("next-char", NEXT_CHAR);
0121: actions.put("next-line", NEXT_LINE);
0122: actions.put("next-page", NEXT_PAGE);
0123: actions.put("next-word", NEXT_WORD);
0124: actions.put("select-next-char", SELECT_NEXT_CHAR);
0125: actions.put("select-next-line", SELECT_NEXT_LINE);
0126: actions.put("select-next-page", SELECT_NEXT_PAGE);
0127: actions.put("select-next-word", SELECT_NEXT_WORD);
0128: actions.put("overwrite", OVERWRITE);
0129: actions.put("prev-char", PREV_CHAR);
0130: actions.put("prev-line", PREV_LINE);
0131: actions.put("prev-page", PREV_PAGE);
0132: actions.put("prev-word", PREV_WORD);
0133: actions.put("select-prev-char", SELECT_PREV_CHAR);
0134: actions.put("select-prev-line", SELECT_PREV_LINE);
0135: actions.put("select-prev-page", SELECT_PREV_PAGE);
0136: actions.put("select-prev-word", SELECT_PREV_WORD);
0137: actions.put("repeat", REPEAT);
0138: actions.put("toggle-rect", TOGGLE_RECT);
0139: actions.put("insert-char", INSERT_CHAR);
0140: }
0141:
0142: /**
0143: * Returns a named text area action.
0144: * @param name The action name
0145: */
0146: public static ActionListener getAction(String name) {
0147: return (ActionListener) actions.get(name);
0148: }
0149:
0150: /**
0151: * Returns the name of the specified text area action.
0152: * @param listener The action
0153: */
0154: public static String getActionName(ActionListener listener) {
0155: Iterator itr = getActions();
0156: while (itr.hasNext()) {
0157: String name = (String) itr.next();
0158: ActionListener _listener = getAction(name);
0159: if (_listener == listener)
0160: return name;
0161: }
0162: return null;
0163: }
0164:
0165: /**
0166: * Returns an enumeration of all available actions.
0167: */
0168: public static Iterator getActions() {
0169: return actions.keySet().iterator();
0170: }
0171:
0172: /**
0173: * Adds the default key bindings to this input handler.
0174: * This should not be called in the constructor of this
0175: * input handler, because applications might load the
0176: * key bindings from a file, etc.
0177: */
0178: public abstract void addDefaultKeyBindings();
0179:
0180: /**
0181: * Adds a key binding to this input handler.
0182: * @param keyBinding The key binding (the format of this is
0183: * input-handler specific)
0184: * @param action The action
0185: */
0186: public abstract void addKeyBinding(String keyBinding,
0187: ActionListener action);
0188:
0189: public abstract void addKeyBinding(KeyStroke aKey,
0190: ActionListener action);
0191:
0192: /**
0193: * Removes a key binding from this input handler.
0194: * @param key The key binding
0195: */
0196: public abstract void removeKeyBinding(KeyStroke key);
0197:
0198: /**
0199: * Removes all key bindings from this input handler.
0200: */
0201: public abstract void removeAllKeyBindings();
0202:
0203: /**
0204: * Grabs the next key typed event and invokes the specified
0205: * action with the key as a the action command.
0206: * @param listener The Listener
0207: */
0208: public void grabNextKeyStroke(ActionListener listener) {
0209: grabAction = listener;
0210: }
0211:
0212: /**
0213: * Returns if repeating is enabled. When repeating is enabled,
0214: * actions will be executed multiple times. This is usually
0215: * invoked with a special key stroke in the input handler.
0216: */
0217: public boolean isRepeatEnabled() {
0218: return repeat;
0219: }
0220:
0221: /**
0222: * Enables repeating. When repeating is enabled, actions will be
0223: * executed multiple times. Once repeating is enabled, the input
0224: * handler should read a number from the keyboard.
0225: */
0226: public void setRepeatEnabled(boolean repeat) {
0227: this .repeat = repeat;
0228: }
0229:
0230: /**
0231: * Returns the number of times the next action will be repeated.
0232: */
0233: public int getRepeatCount() {
0234: return (repeat ? Math.max(1, repeatCount) : 1);
0235: }
0236:
0237: /**
0238: * Sets the number of times the next action will be repeated.
0239: * @param repeatCount The repeat count
0240: */
0241: public void setRepeatCount(int repeatCount) {
0242: this .repeatCount = repeatCount;
0243: }
0244:
0245: /**
0246: * Returns the macro recorder. If this is non-null, all executed
0247: * actions should be forwarded to the recorder.
0248: */
0249: public InputHandler.MacroRecorder getMacroRecorder() {
0250: return recorder;
0251: }
0252:
0253: /**
0254: * Sets the macro recorder. If this is non-null, all executed
0255: * actions should be forwarded to the recorder.
0256: * @param recorder The macro recorder
0257: */
0258: public void setMacroRecorder(InputHandler.MacroRecorder recorder) {
0259: this .recorder = recorder;
0260: }
0261:
0262: /**
0263: * Returns a copy of this input handler that shares the same
0264: * key bindings. Setting key bindings in the copy will also
0265: * set them in the original.
0266: */
0267: public abstract InputHandler copy();
0268:
0269: /**
0270: * Executes the specified action, repeating and recording it as
0271: * necessary.
0272: * @param listener The action listener
0273: * @param source The event source
0274: * @param actionCommand The action command
0275: */
0276: public void executeAction(ActionListener listener, Object source,
0277: String actionCommand) {
0278: // create event
0279: ActionEvent evt = new ActionEvent(source,
0280: ActionEvent.ACTION_PERFORMED, actionCommand);
0281:
0282: // don't do anything if the action is a wrapper
0283: // (like EditAction.Wrapper)
0284: if (listener instanceof Wrapper) {
0285: listener.actionPerformed(evt);
0286: return;
0287: }
0288:
0289: // remember old values, in case action changes them
0290: boolean _repeat = repeat;
0291: int _repeatCount = getRepeatCount();
0292:
0293: // execute the action
0294: if (listener instanceof InputHandler.NonRepeatable) {
0295: listener.actionPerformed(evt);
0296: } else {
0297: for (int i = 0; i < Math.max(1, repeatCount); i++) {
0298: listener.actionPerformed(evt);
0299: }
0300: }
0301:
0302: // do recording. Notice that we do no recording whatsoever
0303: // for actions that grab keys
0304: if (grabAction == null) {
0305: if (recorder != null) {
0306: if (!(listener instanceof InputHandler.NonRecordable)) {
0307: if (_repeatCount != 1) {
0308: recorder.actionPerformed(REPEAT, String
0309: .valueOf(_repeatCount));
0310: }
0311: recorder.actionPerformed(listener, actionCommand);
0312: }
0313: }
0314:
0315: // If repeat was true originally, clear it
0316: // Otherwise it might have been set by the action, etc
0317: if (_repeat) {
0318: repeat = false;
0319: repeatCount = 0;
0320: }
0321: }
0322: }
0323:
0324: /**
0325: * Returns the text area that fired the specified event.
0326: * @param evt The event
0327: */
0328: public static JEditTextArea getTextArea(EventObject evt) {
0329: if (evt != null) {
0330: Object o = evt.getSource();
0331: if (o instanceof Component) {
0332: // find the parent text area
0333: Component c = (Component) o;
0334: for (;;) {
0335: if (c instanceof JEditTextArea)
0336: return (JEditTextArea) c;
0337: else if (c == null)
0338: break;
0339: if (c instanceof JPopupMenu)
0340: c = ((JPopupMenu) c).getInvoker();
0341: else
0342: c = c.getParent();
0343: }
0344: }
0345: }
0346:
0347: // this shouldn't happen
0348: System.err.println("BUG: getTextArea() returning null");
0349: System.err.println("Report this to Slava Pestov <sp@gjt.org>");
0350: return null;
0351: }
0352:
0353: // protected members
0354:
0355: /**
0356: * If a key is being grabbed, this method should be called with
0357: * the appropriate key event. It executes the grab action with
0358: * the typed character as the parameter.
0359: */
0360: protected void handleGrabAction(KeyEvent evt) {
0361: // Clear it *before* it is executed so that executeAction()
0362: // resets the repeat count
0363: ActionListener _grabAction = grabAction;
0364: grabAction = null;
0365: executeAction(_grabAction, evt.getSource(), String.valueOf(evt
0366: .getKeyChar()));
0367: }
0368:
0369: // protected members
0370: protected ActionListener grabAction;
0371: protected boolean repeat;
0372: protected int repeatCount;
0373: protected InputHandler.MacroRecorder recorder;
0374:
0375: /**
0376: * If an action implements this interface, it should not be repeated.
0377: * Instead, it will handle the repetition itself.
0378: */
0379: public interface NonRepeatable {
0380: }
0381:
0382: /**
0383: * If an action implements this interface, it should not be recorded
0384: * by the macro recorder. Instead, it will do its own recording.
0385: */
0386: public interface NonRecordable {
0387: }
0388:
0389: /**
0390: * For use by EditAction.Wrapper only.
0391: * @since jEdit 2.2final
0392: */
0393: public interface Wrapper {
0394: }
0395:
0396: /**
0397: * Macro recorder.
0398: */
0399: public interface MacroRecorder {
0400: void actionPerformed(ActionListener listener,
0401: String actionCommand);
0402: }
0403:
0404: public static class redo implements ActionListener {
0405: public void actionPerformed(ActionEvent evt) {
0406: JEditTextArea textArea = getTextArea(evt);
0407: textArea.redo();
0408: }
0409: }
0410:
0411: public static class undo implements ActionListener {
0412: public void actionPerformed(ActionEvent evt) {
0413: JEditTextArea textArea = getTextArea(evt);
0414: textArea.undo();
0415: }
0416: }
0417:
0418: public static class make_upper implements ActionListener {
0419: public void actionPerformed(ActionEvent evt) {
0420: JEditTextArea textArea = getTextArea(evt);
0421:
0422: if (!textArea.isEditable()) {
0423: textArea.getToolkit().beep();
0424: return;
0425: } else {
0426: String sel = textArea.getSelectedText();
0427: if (sel == null || sel.length() == 0)
0428: return;
0429: int start = textArea.getSelectionStart();
0430: int end = textArea.getSelectionEnd();
0431: sel = sel.toUpperCase();
0432: textArea.setSelectedText(sel);
0433: textArea.select(start, end);
0434: }
0435: }
0436: }
0437:
0438: public static class make_lower implements ActionListener {
0439: public void actionPerformed(ActionEvent evt) {
0440: JEditTextArea textArea = getTextArea(evt);
0441:
0442: if (!textArea.isEditable()) {
0443: textArea.getToolkit().beep();
0444: return;
0445: } else {
0446: String sel = textArea.getSelectedText();
0447: if (sel == null || sel.length() == 0)
0448: return;
0449: int start = textArea.getSelectionStart();
0450: int end = textArea.getSelectionEnd();
0451: sel = sel.toLowerCase();
0452: textArea.setSelectedText(sel);
0453: textArea.select(start, end);
0454: }
0455: }
0456: }
0457:
0458: public static class backspace implements ActionListener {
0459: public void actionPerformed(ActionEvent evt) {
0460: JEditTextArea textArea = getTextArea(evt);
0461:
0462: if (!textArea.isEditable()) {
0463: textArea.getToolkit().beep();
0464: return;
0465: }
0466:
0467: if (textArea.getSelectionStart() != textArea
0468: .getSelectionEnd()) {
0469: textArea.setSelectedText("");
0470: } else {
0471: int caret = textArea.getCaretPosition();
0472: if (caret == 0) {
0473: textArea.getToolkit().beep();
0474: return;
0475: }
0476: int linePos = textArea.getCaretPositionInLine(textArea
0477: .getCaretLine());
0478: SyntaxDocument doc = textArea.getDocument();
0479: try {
0480: doc.remove(caret - 1, 1);
0481: } catch (BadLocationException bl) {
0482: bl.printStackTrace();
0483: }
0484: }
0485: }
0486: }
0487:
0488: public static class backspace_word implements ActionListener {
0489: public void actionPerformed(ActionEvent evt) {
0490: JEditTextArea textArea = getTextArea(evt);
0491: int start = textArea.getSelectionStart();
0492: if (start != textArea.getSelectionEnd()) {
0493: textArea.setSelectedText("");
0494: }
0495:
0496: int line = textArea.getCaretLine();
0497: int lineStart = textArea.getLineStartOffset(line);
0498: int caret = start - lineStart;
0499:
0500: String lineText = textArea.getLineText(textArea
0501: .getCaretLine());
0502:
0503: if (caret == 0) {
0504: if (lineStart == 0) {
0505: textArea.getToolkit().beep();
0506: return;
0507: }
0508: caret--;
0509: } else {
0510: caret = TextUtilities.findWordStart(lineText, caret);
0511: }
0512:
0513: try {
0514: textArea.getDocument().remove(caret + lineStart,
0515: start - (caret + lineStart));
0516: } catch (BadLocationException bl) {
0517: bl.printStackTrace();
0518: }
0519: }
0520: }
0521:
0522: public static class delete implements ActionListener {
0523: public void actionPerformed(ActionEvent evt) {
0524: JEditTextArea textArea = getTextArea(evt);
0525:
0526: if (!textArea.isEditable()) {
0527: textArea.getToolkit().beep();
0528: return;
0529: }
0530:
0531: if (textArea.getSelectionStart() != textArea
0532: .getSelectionEnd()) {
0533: textArea.setSelectedText("");
0534: } else {
0535: int caret = textArea.getCaretPosition();
0536: if (caret == textArea.getDocumentLength()) {
0537: textArea.getToolkit().beep();
0538: return;
0539: }
0540: try {
0541: textArea.getDocument().remove(caret, 1);
0542: } catch (BadLocationException bl) {
0543: bl.printStackTrace();
0544: }
0545: }
0546: }
0547: }
0548:
0549: public static class delete_word implements ActionListener {
0550: public void actionPerformed(ActionEvent evt) {
0551: JEditTextArea textArea = getTextArea(evt);
0552: int start = textArea.getSelectionStart();
0553: if (start != textArea.getSelectionEnd()) {
0554: textArea.setSelectedText("");
0555: }
0556:
0557: int line = textArea.getCaretLine();
0558: int lineStart = textArea.getLineStartOffset(line);
0559: int caret = start - lineStart;
0560:
0561: String lineText = textArea.getLineText(textArea
0562: .getCaretLine());
0563:
0564: if (caret == lineText.length()) {
0565: if (lineStart + caret == textArea.getDocumentLength()) {
0566: textArea.getToolkit().beep();
0567: return;
0568: }
0569: caret++;
0570: } else {
0571: caret = TextUtilities.findWordEnd(lineText, caret);
0572: }
0573:
0574: try {
0575: textArea.getDocument().remove(start,
0576: (caret + lineStart) - start);
0577: } catch (BadLocationException bl) {
0578: bl.printStackTrace();
0579: }
0580: }
0581: }
0582:
0583: public static class end implements ActionListener {
0584: private final boolean select;
0585:
0586: public end(boolean select) {
0587: this .select = select;
0588: }
0589:
0590: public void actionPerformed(ActionEvent evt) {
0591: JEditTextArea textArea = getTextArea(evt);
0592:
0593: int line = textArea.getCaretLine();
0594: int caret = textArea.getCaretPosition();
0595:
0596: int lastOfLine = textArea.getLineEndOffset(line) - 1;
0597: int lastVisibleLine = textArea.getFirstLine()
0598: + textArea.getVisibleLines();
0599: if (lastVisibleLine >= textArea.getLineCount()) {
0600: lastVisibleLine = Math.min(textArea.getLineCount() - 1,
0601: lastVisibleLine);
0602: } else {
0603: lastVisibleLine -= (textArea.getElectricScroll() + 1);
0604: }
0605:
0606: int lastVisible = textArea
0607: .getLineEndOffset(lastVisibleLine) - 1;
0608: int lastDocument = textArea.getDocumentLength();
0609:
0610: if (caret == lastDocument) {
0611: textArea.getToolkit().beep();
0612: if (!select) {
0613: textArea.selectNone();
0614: }
0615: return;
0616: } else if (!Boolean.TRUE.equals(textArea
0617: .getClientProperty(SMART_HOME_END_PROPERTY)))
0618: caret = lastOfLine;
0619: else if (caret == lastVisible)
0620: caret = lastDocument;
0621: else if (caret == lastOfLine)
0622: caret = lastVisible;
0623: else
0624: caret = lastOfLine;
0625:
0626: if (select)
0627: textArea.select(textArea.getMarkPosition(), caret);
0628: else
0629: textArea.setCaretPosition(caret);
0630: }
0631: }
0632:
0633: public static class document_end implements ActionListener {
0634: private boolean select;
0635:
0636: public document_end(boolean select) {
0637: this .select = select;
0638: }
0639:
0640: public void actionPerformed(ActionEvent evt) {
0641: JEditTextArea textArea = getTextArea(evt);
0642: if (select) {
0643: textArea.select(textArea.getMarkPosition(), textArea
0644: .getDocumentLength());
0645: } else {
0646: textArea.selectNone();
0647: textArea.setCaretPosition(textArea.getDocumentLength());
0648: }
0649: }
0650: }
0651:
0652: public static class home implements ActionListener {
0653: private boolean select;
0654:
0655: public home(boolean select) {
0656: this .select = select;
0657: }
0658:
0659: public void actionPerformed(ActionEvent evt) {
0660: JEditTextArea textArea = getTextArea(evt);
0661:
0662: int caret = textArea.getCaretPosition();
0663:
0664: int firstLine = textArea.getFirstLine();
0665:
0666: int firstOfLine = textArea.getLineStartOffset(textArea
0667: .getCaretLine());
0668: int firstVisibleLine = (firstLine == 0 ? 0 : firstLine
0669: + textArea.getElectricScroll());
0670: int firstVisible = textArea
0671: .getLineStartOffset(firstVisibleLine);
0672:
0673: if (caret == 0) {
0674: textArea.getToolkit().beep();
0675: if (!select)
0676: textArea.selectNone();
0677: return;
0678: } else if (!Boolean.TRUE.equals(textArea
0679: .getClientProperty(SMART_HOME_END_PROPERTY)))
0680: caret = firstOfLine;
0681: else if (caret == firstVisible)
0682: caret = 0;
0683: else if (caret == firstOfLine)
0684: caret = firstVisible;
0685: else
0686: caret = firstOfLine;
0687:
0688: if (select) {
0689: textArea.select(textArea.getMarkPosition(), caret);
0690: } else {
0691: textArea.selectNone();
0692: textArea.setCaretPosition(caret);
0693: }
0694: }
0695: }
0696:
0697: public static class document_home implements ActionListener {
0698: private boolean select;
0699:
0700: public document_home(boolean select) {
0701: this .select = select;
0702: }
0703:
0704: public void actionPerformed(ActionEvent evt) {
0705: JEditTextArea textArea = getTextArea(evt);
0706: if (select)
0707: textArea.select(textArea.getMarkPosition(), 0);
0708: else
0709: textArea.setCaretPosition(0);
0710: }
0711: }
0712:
0713: public static class insert_break implements ActionListener {
0714: public void actionPerformed(ActionEvent evt) {
0715: JEditTextArea textArea = getTextArea(evt);
0716:
0717: if (!textArea.isEditable()) {
0718: textArea.getToolkit().beep();
0719: return;
0720: }
0721:
0722: textArea.setSelectedText("\n");
0723: }
0724: }
0725:
0726: public static class insert_tab implements ActionListener {
0727: public void actionPerformed(ActionEvent evt) {
0728: JEditTextArea textArea = getTextArea(evt);
0729:
0730: if (!textArea.isEditable()) {
0731: textArea.getToolkit().beep();
0732: return;
0733: }
0734:
0735: textArea.overwriteSetSelectedText("\t");
0736: }
0737: }
0738:
0739: public static class next_char implements ActionListener {
0740: private boolean select;
0741:
0742: public next_char(boolean select) {
0743: this .select = select;
0744: }
0745:
0746: public void actionPerformed(ActionEvent evt) {
0747: JEditTextArea textArea = getTextArea(evt);
0748: int caret = textArea.getCaretPosition();
0749: if (caret == textArea.getDocumentLength()) {
0750: textArea.getToolkit().beep();
0751: if (!select)
0752: textArea.selectNone();
0753: return;
0754: }
0755:
0756: if (select)
0757: textArea.select(textArea.getMarkPosition(), caret + 1);
0758: else
0759: textArea.setCaretPosition(caret + 1);
0760: }
0761: }
0762:
0763: public static class next_line implements ActionListener {
0764: private boolean select;
0765:
0766: public next_line(boolean select) {
0767: this .select = select;
0768: }
0769:
0770: public void actionPerformed(ActionEvent evt) {
0771: JEditTextArea textArea = getTextArea(evt);
0772: int caret = textArea.getCaretPosition();
0773: int line = textArea.getCaretLine();
0774:
0775: if (line == textArea.getLineCount() - 1) {
0776: textArea.getToolkit().beep();
0777: if (!select)
0778: textArea.selectNone();
0779: return;
0780: }
0781:
0782: int magic = textArea.getMagicCaretPosition();
0783: if (magic == -1) {
0784: magic = textArea.offsetToX(line, caret
0785: - textArea.getLineStartOffset(line));
0786: }
0787:
0788: caret = textArea.getLineStartOffset(line + 1)
0789: + textArea.xToOffset(line + 1, magic);
0790:
0791: if (select)
0792: textArea.select(textArea.getMarkPosition(), caret);
0793: else
0794: textArea.setCaretPosition(caret);
0795:
0796: textArea.setMagicCaretPosition(magic);
0797: }
0798: }
0799:
0800: public static class next_page implements ActionListener {
0801: private boolean select;
0802:
0803: public next_page(boolean select) {
0804: this .select = select;
0805: }
0806:
0807: public void actionPerformed(ActionEvent evt) {
0808: JEditTextArea textArea = getTextArea(evt);
0809: int lineCount = textArea.getLineCount();
0810: int firstLine = textArea.getFirstLine();
0811: int visibleLines = textArea.getVisibleLines();
0812: int line = textArea.getCaretLine();
0813:
0814: firstLine += visibleLines;
0815:
0816: if (firstLine + visibleLines >= lineCount - 1)
0817: firstLine = lineCount - visibleLines;
0818:
0819: textArea.setFirstLine(firstLine);
0820:
0821: int caret = textArea.getLineStartOffset(Math.min(textArea
0822: .getLineCount() - 1, line + visibleLines));
0823:
0824: if (select)
0825: textArea.select(textArea.getMarkPosition(), caret);
0826: else
0827: textArea.setCaretPosition(caret);
0828: }
0829: }
0830:
0831: public static class next_word implements ActionListener {
0832: private boolean select;
0833:
0834: public next_word(boolean select) {
0835: this .select = select;
0836: }
0837:
0838: public void actionPerformed(ActionEvent evt) {
0839: JEditTextArea textArea = getTextArea(evt);
0840: int caret = textArea.getCaretPosition();
0841: int line = textArea.getCaretLine();
0842: int lineStart = textArea.getLineStartOffset(line);
0843: caret -= lineStart;
0844:
0845: String lineText = textArea.getLineText(textArea
0846: .getCaretLine());
0847:
0848: if (caret == lineText.length()) {
0849: if (lineStart + caret == textArea.getDocumentLength()) {
0850: textArea.getToolkit().beep();
0851: return;
0852: }
0853: caret++;
0854: } else {
0855: caret = TextUtilities.findWordEnd(lineText, caret);
0856: }
0857:
0858: if (select)
0859: textArea.select(textArea.getMarkPosition(), lineStart
0860: + caret);
0861: else
0862: textArea.setCaretPosition(lineStart + caret);
0863: }
0864: }
0865:
0866: public static class overwrite implements ActionListener {
0867: public void actionPerformed(ActionEvent evt) {
0868: JEditTextArea textArea = getTextArea(evt);
0869: textArea
0870: .setOverwriteEnabled(!textArea.isOverwriteEnabled());
0871: }
0872: }
0873:
0874: public static class prev_char implements ActionListener {
0875: private boolean select;
0876:
0877: public prev_char(boolean select) {
0878: this .select = select;
0879: }
0880:
0881: public void actionPerformed(ActionEvent evt) {
0882: JEditTextArea textArea = getTextArea(evt);
0883: int caret = textArea.getCaretPosition();
0884: if (caret == 0) {
0885: textArea.getToolkit().beep();
0886: if (!select)
0887: textArea.selectNone();
0888: return;
0889: }
0890:
0891: if (select)
0892: textArea.select(textArea.getMarkPosition(), caret - 1);
0893: else
0894: textArea.setCaretPosition(caret - 1);
0895: }
0896: }
0897:
0898: public static class prev_line implements ActionListener {
0899: private boolean select;
0900:
0901: public prev_line(boolean select) {
0902: this .select = select;
0903: }
0904:
0905: public void actionPerformed(ActionEvent evt) {
0906: JEditTextArea textArea = getTextArea(evt);
0907: int caret = textArea.getCaretPosition();
0908: int line = textArea.getCaretLine();
0909:
0910: if (line == 0) {
0911: textArea.getToolkit().beep();
0912: if (!select)
0913: textArea.selectNone();
0914: return;
0915: }
0916:
0917: int magic = textArea.getMagicCaretPosition();
0918: if (magic == -1) {
0919: magic = textArea.offsetToX(line, caret
0920: - textArea.getLineStartOffset(line));
0921: }
0922:
0923: caret = textArea.getLineStartOffset(line - 1)
0924: + textArea.xToOffset(line - 1, magic);
0925:
0926: if (select)
0927: textArea.select(textArea.getMarkPosition(), caret);
0928: else
0929: textArea.setCaretPosition(caret);
0930:
0931: textArea.setMagicCaretPosition(magic);
0932: }
0933: }
0934:
0935: public static class prev_page implements ActionListener {
0936: private boolean select;
0937:
0938: public prev_page(boolean select) {
0939: this .select = select;
0940: }
0941:
0942: public void actionPerformed(ActionEvent evt) {
0943: JEditTextArea textArea = getTextArea(evt);
0944: int firstLine = textArea.getFirstLine();
0945: int visibleLines = textArea.getVisibleLines();
0946: int line = textArea.getCaretLine();
0947:
0948: if (firstLine < visibleLines)
0949: firstLine = visibleLines;
0950:
0951: textArea.setFirstLine(firstLine - visibleLines);
0952:
0953: int caret = textArea.getLineStartOffset(Math.max(0, line
0954: - visibleLines));
0955:
0956: if (select)
0957: textArea.select(textArea.getMarkPosition(), caret);
0958: else
0959: textArea.setCaretPosition(caret);
0960: }
0961: }
0962:
0963: public static class prev_word implements ActionListener {
0964: private boolean select;
0965:
0966: public prev_word(boolean select) {
0967: this .select = select;
0968: }
0969:
0970: public void actionPerformed(ActionEvent evt) {
0971: JEditTextArea textArea = getTextArea(evt);
0972: int caret = textArea.getCaretPosition();
0973: int line = textArea.getCaretLine();
0974: int lineStart = textArea.getLineStartOffset(line);
0975: caret -= lineStart;
0976:
0977: String lineText = textArea.getLineText(textArea
0978: .getCaretLine());
0979:
0980: if (caret == 0) {
0981: if (lineStart == 0) {
0982: textArea.getToolkit().beep();
0983: return;
0984: }
0985: caret--;
0986: } else {
0987: caret = TextUtilities.findWordStart(lineText, caret);
0988: }
0989:
0990: if (select)
0991: textArea.select(textArea.getMarkPosition(), lineStart
0992: + caret);
0993: else
0994: textArea.setCaretPosition(lineStart + caret);
0995: }
0996: }
0997:
0998: public static class repeat implements ActionListener,
0999: InputHandler.NonRecordable {
1000: public void actionPerformed(ActionEvent evt) {
1001: JEditTextArea textArea = getTextArea(evt);
1002: textArea.getInputHandler().setRepeatEnabled(true);
1003: String actionCommand = evt.getActionCommand();
1004: if (actionCommand != null) {
1005: textArea.getInputHandler().setRepeatCount(
1006: Integer.parseInt(actionCommand));
1007: }
1008: }
1009: }
1010:
1011: public static class toggle_rect implements ActionListener {
1012: public void actionPerformed(ActionEvent evt) {
1013: JEditTextArea textArea = getTextArea(evt);
1014: textArea.setSelectionRectangular(!textArea
1015: .isSelectionRectangular());
1016: }
1017: }
1018:
1019: public static class insert_char implements ActionListener,
1020: InputHandler.NonRepeatable {
1021: public void actionPerformed(ActionEvent evt) {
1022: JEditTextArea textArea = getTextArea(evt);
1023: String str = evt.getActionCommand();
1024: int repeatCount = textArea.getInputHandler()
1025: .getRepeatCount();
1026:
1027: if (textArea.isEditable()) {
1028: StringBuilder buf = new StringBuilder();
1029: for (int i = 0; i < repeatCount; i++)
1030: buf.append(str);
1031: textArea.overwriteSetSelectedText(buf.toString());
1032: } else {
1033: textArea.getToolkit().beep();
1034: }
1035: }
1036: }
1037: }
|