📄 acltextarea.java
字号:
}
protected void fireCaretEvent() {
Object[] listeners = listenerList.getListenerList();
for (int i = listeners.length - 2; i >= 0; i--) {
if (listeners[i] == CaretListener.class) {
((CaretListener)listeners[i + 1]).caretUpdate(caretEvent);
}
}
}
protected void updateBracketHighlight(int newCaretPosition) {
if (newCaretPosition == 0) {
bracketPosition = bracketLine = -1;
return;
}
try {
int offset = TextUtilities.findMatchingBracket(
document, newCaretPosition - 1);
if (offset != -1) {
bracketLine = getLineOfOffset(offset);
bracketPosition = offset - getLineStartOffset(bracketLine);
return;
}
}
catch (BadLocationException bl) {
bl.printStackTrace();
}
bracketLine = bracketPosition = -1;
}
protected void documentChanged(DocumentEvent evt) {
DocumentEvent.ElementChange ch = evt.getChange(
document.getDefaultRootElement());
int count;
if (ch == null) {
count = 0;
}
else {
count = ch.getChildrenAdded().length -
ch.getChildrenRemoved().length;
}
if (count == 0) {
int line = getLineOfOffset(evt.getOffset());
painter._invalidateLine(line);
}
else {
int index = ch.getIndex();
painter._invalidateLineRange(index, Math.max(getLineCount(),
firstLine + visibleLines));
updateScrollBars();
}
}
public static class TextUtilities {
/**
* Returns the offset of the bracket matching the one at the specified
* offset of the document, or -1 if the bracket is unmatched (or if the
* character is not a bracket).
*
* @param doc The document
* @param offset The offset
* @return Description of the Returned Value
* @exception BadLocationException If an out-of-bounds access was
* attempted on the document text
*/
public static int findMatchingBracket(Document doc, int offset)
throws BadLocationException {
if (doc.getLength() == 0) {
return -1;
}
char c = doc.getText(offset, 1).charAt(0);
char cprime;// c` - corresponding character
boolean direction;// true = back, false = forward
switch (c) {
case '(':
cprime = ')';
direction = false;
break;
case ')':
cprime = '(';
direction = true;
break;
case '[':
cprime = ']';
direction = false;
break;
case ']':
cprime = '[';
direction = true;
break;
case '{':
cprime = '}';
direction = false;
break;
case '}':
cprime = '{';
direction = true;
break;
default:
return -1;
}
int count;
// How to merge these two cases is left as an exercise
// for the reader.
// Go back or forward
if (direction) {
// Count is 1 initially because we have already
// `found' one closing bracket
count = 1;
// Get text[0,offset-1];
String text = doc.getText(0, offset);
// Scan backwards
for (int i = offset - 1; i >= 0; i--) {
// If text[i] == c, we have found another
// closing bracket, therefore we will need
// two opening brackets to complete the
// match.
char x = text.charAt(i);
if (x == c) {
count++;
}
// If text[i] == cprime, we have found a
// opening bracket, so we return i if
// --count == 0
else if (x == cprime) {
if (--count == 0) {
return i;
}
}
}
}
else {
// Count is 1 initially because we have already
// `found' one opening bracket
count = 1;
// So we don't have to + 1 in every loop
offset++;
// Number of characters to check
int len = doc.getLength() - offset;
// Get text[offset+1,len];
String text = doc.getText(offset, len);
// Scan forwards
for (int i = 0; i < len; i++) {
// If text[i] == c, we have found another
// opening bracket, therefore we will need
// two closing brackets to complete the
// match.
char x = text.charAt(i);
if (x == c) {
count++;
}
// If text[i] == cprime, we have found an
// closing bracket, so we return i if
// --count == 0
else if (x == cprime) {
if (--count == 0) {
return i + offset;
}
}
}
}
// Nothing found
return -1;
}
}
static class CaretBlinker implements ActionListener {
public void actionPerformed(ActionEvent evt) {
if (focusedComponent != null
&& focusedComponent.hasFocus()) {
focusedComponent.blinkCaret();
}
}
}
private static class InputHandler implements KeyListener {
/**
* Creates a new input handler with no key bindings defined.
*/
public InputHandler() {
bindings = currentBindings = new Hashtable();
}
public static ACLTextArea 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 ACLTextArea) {
return (ACLTextArea)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;
}
/**
* Converts a string to a keystroke. The string should be of the form <i>
* modifiers</i> +<i>shortcut</i> where <i>modifiers</i> is any
* combination of A for Alt, C for Control, S for Shift or M for Meta,
* and <i>shortcut </i> is either a single character, or a keycode name
* from the <code>KeyEvent</code> class, without the <code>VK_</code>
* prefix.
*
* @param keyStroke A string description of the key stroke
* @return Description of the Returned Value
*/
public static KeyStroke parseKeyStroke(String keyStroke) {
if (keyStroke == null) {
return null;
}
int modifiers = 0;
int ch = '\0';
int index = keyStroke.indexOf('+');
if (index != -1) {
for (int i = 0; i < index; i++) {
switch (Character.toUpperCase(keyStroke.charAt(i))) {
case 'A':
modifiers |= InputEvent.ALT_MASK;
break;
case 'C':
modifiers |= InputEvent.CTRL_MASK;
break;
case 'M':
modifiers |= InputEvent.META_MASK;
break;
case 'S':
modifiers |= InputEvent.SHIFT_MASK;
break;
}
}
}
String key = keyStroke.substring(index + 1);
if (key.length() == 1) {
ch = Character.toUpperCase(key.charAt(0));
}
else if (key.length() == 0) {
System.err.println("Invalid key stroke: " + keyStroke);
return null;
}
else {
try {
ch = KeyEvent.class.getField("VK_".concat(key))
.getInt(null);
}
catch (Exception e) {
System.err.println("Invalid key stroke: "
+ keyStroke);
return null;
}
}
return KeyStroke.getKeyStroke(ch, modifiers);
}
/**
* Sets up the default key bindings.
*/
public void addDefaultKeyBindings() {
addKeyBinding("BACK_SPACE", BACKSPACE);
addKeyBinding("DELETE", DELETE);
addKeyBinding("ENTER", INSERT_BREAK);
addKeyBinding("TAB", INSERT_TAB);
addKeyBinding("INSERT", OVERWRITE);
addKeyBinding("HOME", HOME);
addKeyBinding("END", END);
addKeyBinding("S+HOME", SELECT_HOME);
addKeyBinding("S+END", SELECT_END);
addKeyBinding("PAGE_UP", PREV_PAGE);
addKeyBinding("PAGE_DOWN", NEXT_PAGE);
addKeyBinding("S+PAGE_UP", SELECT_PREV_PAGE);
addKeyBinding("S+PAGE_DOWN", SELECT_NEXT_PAGE);
addKeyBinding("LEFT", PREV_CHAR);
addKeyBinding("S+LEFT", SELECT_PREV_CHAR);
addKeyBinding("C+LEFT", PREV_WORD);
addKeyBinding("CS+LEFT", SELECT_PREV_WORD);
addKeyBinding("RIGHT", NEXT_CHAR);
addKeyBinding("S+RIGHT", SELECT_NEXT_CHAR);
addKeyBinding("C+RIGHT", NEXT_WORD);
addKeyBinding("CS+RIGHT", SELECT_NEXT_WORD);
addKeyBinding("UP", PREV_LINE);
addKeyBinding("S+UP", SELECT_PREV_LINE);
addKeyBinding("DOWN", NEXT_LINE);
addKeyBinding("S+DOWN", SELECT_NEXT_LINE);
}
/**
* Adds a key binding to this input handler. The key binding is a list of
* white space separated key strokes of the form <i>[modifiers+]key</i>
* where modifier is C for Control, A for Alt, or S for Shift, and key is
* either a character (a-z) or a field name in the KeyEvent class
* prefixed with VK_ (e.g., BACK_SPACE)
*
* @param keyBinding The key binding
* @param action The action
*/
public void addKeyBinding(String keyBinding, ActionListener action) {
Hashtable current = bindings;
StringTokenizer st = new StringTokenizer(keyBinding);
while (st.hasMoreTokens()) {
KeyStroke keyStroke = parseKeyStroke(st.nextToken());
if (keyStroke == null) {
return;
}
if (st.hasMoreTokens()) {
Object o = current.get(keyStroke);
if (o instanceof Hashtable) {
current = (Hashtable)o;
}
else {
o = new Hashtable();
current.put(keyStroke, o);
current = (Hashtable)o;
}
}
else {
current.put(keyStroke, action);
}
}
}
/**
* Removes a key binding from this input handler. This is not yet
* implemented.
*
* @param keyBinding The key binding
*/
public void removeKeyBinding(String keyBinding) {
throw new InternalError("Not yet implemented");
}
/**
* Removes all key bindings from this input handler.
*/
public void removeAllKeyBindings() {
bindings.clear();
}
/**
* Handle a key pressed event. This will look up the binding for the key
* stroke and execute it.
*
* @param evt Description of Parameter
*/
public void keyPressed(KeyEvent evt) {
int keyCode = evt.getKeyCode();
int modifiers = evt.getModifiers();
if ((modifiers & ~KeyEvent.SHIFT_MASK) != 0
|| evt.isActionKey()
|| keyCode == KeyEvent.VK_BACK_SPACE
|| keyCode == KeyEvent.VK_DELETE
|| keyCode == KeyEvent.VK_ENTER
|| keyCode == KeyEvent.VK_TAB) {
KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode,
modifiers);
Object o = currentBindings.get(keyStroke);
if (o == null) {
// Don't beep if the user presses some
// key we don't know about unless a
// prefix is active. Otherwise it will
// beep when caps lock is pressed, etc.
if (currentBindings != bindings) {
Toolkit.getDefaultToolkit().beep();
// F10 should be passed on, but C+e F10
// shouldn't
evt.consume();
}
currentBindings = bindings;
return;
}
else if (o instanceof ActionListener) {
((ActionListener)o).actionPerformed(
new ActionEvent(evt.getSource(),
ActionEvent.ACTION_PERFORMED,
null, modifiers));
currentBindings = bindings;
evt.consume();
return;
}
else if (o instanceof Hashtable) {
currentBindings = (Hashtable)o;
evt.consume();
return;
}
else if (keyCode != KeyEvent.VK_ALT
&& keyCode != KeyEvent.VK_CONTROL
&& keyCode != KeyEvent.VK_SHIFT
&& keyCode != KeyEvent.VK_META) {
return;
}
}
}
/**
* Handle a key released event. These are ignored.
*
* @param evt Description of Parameter
*/
public void keyReleased(KeyEvent evt) {
}
/**
* Handle a key typed event. This inserts the key into the text area.
*
* @param evt Description of Parameter
*/
public void keyTyped(KeyEvent evt) {
int modifiers = evt.getModifiers();
char c = evt.getKeyChar();
if (c != KeyEvent.CHAR_UNDEFINED &&
(modifiers & KeyEvent.ALT_MASK) == 0) {
if (c >= 0x20 && c != 0x7f) {
ACLTextArea textArea = getTextArea(evt);
if (!textArea.isEditable()) {
textArea.getToolkit().beep();
return;
}
currentBindings = bindings;
textArea.overwriteSetSelectedText(String.valueOf(c));
}
}
}
public static class backspace implements ActionListener {
public void actionPerformed(ActionEvent evt) {
ACLTextArea textArea = getTextArea(evt);
if (!textArea.isEditable()) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -