mirror of
https://github.com/arduino/Arduino.git
synced 2025-01-29 18:52:13 +01:00
removing files from the old editor
This commit is contained in:
parent
e70545948c
commit
2e497c6c47
@ -1,273 +0,0 @@
|
||||
/*
|
||||
* CTokenMarker.java - C token marker
|
||||
* Copyright (C) 1998, 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.
|
||||
*/
|
||||
|
||||
package processing.app.syntax;
|
||||
|
||||
import javax.swing.text.Segment;
|
||||
|
||||
/**
|
||||
* C token marker.
|
||||
*
|
||||
* @author Slava Pestov
|
||||
*/
|
||||
public class CTokenMarker extends TokenMarker
|
||||
{
|
||||
public CTokenMarker()
|
||||
{
|
||||
this(true,getKeywords());
|
||||
}
|
||||
|
||||
public CTokenMarker(boolean cpp, KeywordMap keywords)
|
||||
{
|
||||
this.cpp = cpp;
|
||||
this.keywords = keywords;
|
||||
}
|
||||
|
||||
public byte markTokensImpl(byte token, Segment line, int lineIndex)
|
||||
{
|
||||
char[] array = line.array;
|
||||
int offset = line.offset;
|
||||
lastOffset = offset;
|
||||
lastKeyword = offset;
|
||||
int mlength = line.count + offset;
|
||||
boolean backslash = false;
|
||||
|
||||
loop: for(int i = offset; i < mlength; i++)
|
||||
{
|
||||
int i1 = (i+1);
|
||||
|
||||
char c = array[i];
|
||||
if(c == '\\')
|
||||
{
|
||||
backslash = !backslash;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(token)
|
||||
{
|
||||
case Token.NULL:
|
||||
switch(c)
|
||||
{
|
||||
case '#':
|
||||
if(backslash)
|
||||
backslash = false;
|
||||
else if(cpp)
|
||||
{
|
||||
if(doKeyword(line,i,c))
|
||||
break;
|
||||
addToken(i - lastOffset,token);
|
||||
addToken(mlength - i,Token.KEYWORD2);
|
||||
lastOffset = lastKeyword = mlength;
|
||||
break loop;
|
||||
}
|
||||
break;
|
||||
case '"':
|
||||
doKeyword(line,i,c);
|
||||
if(backslash)
|
||||
backslash = false;
|
||||
else
|
||||
{
|
||||
addToken(i - lastOffset,token);
|
||||
token = Token.LITERAL1;
|
||||
lastOffset = lastKeyword = i;
|
||||
}
|
||||
break;
|
||||
case '\'':
|
||||
doKeyword(line,i,c);
|
||||
if(backslash)
|
||||
backslash = false;
|
||||
else
|
||||
{
|
||||
addToken(i - lastOffset,token);
|
||||
token = Token.LITERAL2;
|
||||
lastOffset = lastKeyword = i;
|
||||
}
|
||||
break;
|
||||
case ':':
|
||||
if(lastKeyword == offset)
|
||||
{
|
||||
if(doKeyword(line,i,c))
|
||||
break;
|
||||
backslash = false;
|
||||
addToken(i1 - lastOffset,Token.LABEL);
|
||||
lastOffset = lastKeyword = i1;
|
||||
}
|
||||
else if(doKeyword(line,i,c))
|
||||
break;
|
||||
break;
|
||||
case '/':
|
||||
backslash = false;
|
||||
doKeyword(line,i,c);
|
||||
if(mlength - i > 1)
|
||||
{
|
||||
switch(array[i1])
|
||||
{
|
||||
case '*':
|
||||
addToken(i - lastOffset,token);
|
||||
lastOffset = lastKeyword = i;
|
||||
if(mlength - i > 2 && array[i+2] == '*')
|
||||
token = Token.COMMENT2;
|
||||
else
|
||||
token = Token.COMMENT1;
|
||||
break;
|
||||
case '/':
|
||||
addToken(i - lastOffset,token);
|
||||
addToken(mlength - i,Token.COMMENT1);
|
||||
lastOffset = lastKeyword = mlength;
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
backslash = false;
|
||||
if(!Character.isLetterOrDigit(c)
|
||||
&& c != '_')
|
||||
doKeyword(line,i,c);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Token.COMMENT1:
|
||||
case Token.COMMENT2:
|
||||
backslash = false;
|
||||
if(c == '*' && mlength - i > 1)
|
||||
{
|
||||
if(array[i1] == '/')
|
||||
{
|
||||
i++;
|
||||
addToken((i+1) - lastOffset,token);
|
||||
token = Token.NULL;
|
||||
lastOffset = lastKeyword = i+1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Token.LITERAL1:
|
||||
if(backslash)
|
||||
backslash = false;
|
||||
else if(c == '"')
|
||||
{
|
||||
addToken(i1 - lastOffset,token);
|
||||
token = Token.NULL;
|
||||
lastOffset = lastKeyword = i1;
|
||||
}
|
||||
break;
|
||||
case Token.LITERAL2:
|
||||
if(backslash)
|
||||
backslash = false;
|
||||
else if(c == '\'')
|
||||
{
|
||||
addToken(i1 - lastOffset,Token.LITERAL1);
|
||||
token = Token.NULL;
|
||||
lastOffset = lastKeyword = i1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new InternalError("Invalid state: "
|
||||
+ token);
|
||||
}
|
||||
}
|
||||
|
||||
if(token == Token.NULL)
|
||||
doKeyword(line,mlength,'\0');
|
||||
|
||||
switch(token)
|
||||
{
|
||||
case Token.LITERAL1:
|
||||
case Token.LITERAL2:
|
||||
addToken(mlength - lastOffset,Token.INVALID);
|
||||
token = Token.NULL;
|
||||
break;
|
||||
case Token.KEYWORD2:
|
||||
addToken(mlength - lastOffset,token);
|
||||
if (!backslash) token = Token.NULL;
|
||||
addToken(mlength - lastOffset,token);
|
||||
break;
|
||||
default:
|
||||
addToken(mlength - lastOffset,token);
|
||||
break;
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
public static KeywordMap getKeywords()
|
||||
{
|
||||
if(cKeywords == null)
|
||||
{
|
||||
cKeywords = new KeywordMap(false);
|
||||
cKeywords.add("char",Token.KEYWORD3);
|
||||
cKeywords.add("double",Token.KEYWORD3);
|
||||
cKeywords.add("enum",Token.KEYWORD3);
|
||||
cKeywords.add("float",Token.KEYWORD3);
|
||||
cKeywords.add("int",Token.KEYWORD3);
|
||||
cKeywords.add("long",Token.KEYWORD3);
|
||||
cKeywords.add("short",Token.KEYWORD3);
|
||||
cKeywords.add("signed",Token.KEYWORD3);
|
||||
cKeywords.add("struct",Token.KEYWORD3);
|
||||
cKeywords.add("typedef",Token.KEYWORD3);
|
||||
cKeywords.add("union",Token.KEYWORD3);
|
||||
cKeywords.add("unsigned",Token.KEYWORD3);
|
||||
cKeywords.add("void",Token.KEYWORD3);
|
||||
cKeywords.add("auto",Token.KEYWORD1);
|
||||
cKeywords.add("const",Token.KEYWORD1);
|
||||
cKeywords.add("extern",Token.KEYWORD1);
|
||||
cKeywords.add("register",Token.KEYWORD1);
|
||||
cKeywords.add("static",Token.KEYWORD1);
|
||||
cKeywords.add("volatile",Token.KEYWORD1);
|
||||
cKeywords.add("break",Token.KEYWORD1);
|
||||
cKeywords.add("case",Token.KEYWORD1);
|
||||
cKeywords.add("continue",Token.KEYWORD1);
|
||||
cKeywords.add("default",Token.KEYWORD1);
|
||||
cKeywords.add("do",Token.KEYWORD1);
|
||||
cKeywords.add("else",Token.KEYWORD1);
|
||||
cKeywords.add("for",Token.KEYWORD1);
|
||||
cKeywords.add("goto",Token.KEYWORD1);
|
||||
cKeywords.add("if",Token.KEYWORD1);
|
||||
cKeywords.add("return",Token.KEYWORD1);
|
||||
cKeywords.add("sizeof",Token.KEYWORD1);
|
||||
cKeywords.add("switch",Token.KEYWORD1);
|
||||
cKeywords.add("while",Token.KEYWORD1);
|
||||
cKeywords.add("asm",Token.KEYWORD2);
|
||||
cKeywords.add("asmlinkage",Token.KEYWORD2);
|
||||
cKeywords.add("far",Token.KEYWORD2);
|
||||
cKeywords.add("huge",Token.KEYWORD2);
|
||||
cKeywords.add("inline",Token.KEYWORD2);
|
||||
cKeywords.add("near",Token.KEYWORD2);
|
||||
cKeywords.add("pascal",Token.KEYWORD2);
|
||||
cKeywords.add("true",Token.LITERAL2);
|
||||
cKeywords.add("false",Token.LITERAL2);
|
||||
cKeywords.add("NULL",Token.LITERAL2);
|
||||
}
|
||||
return cKeywords;
|
||||
}
|
||||
|
||||
// private members
|
||||
private static KeywordMap cKeywords;
|
||||
|
||||
private boolean cpp;
|
||||
private KeywordMap keywords;
|
||||
private int lastOffset;
|
||||
private int lastKeyword;
|
||||
|
||||
private boolean doKeyword(Segment line, int i, char c)
|
||||
{
|
||||
int i1 = i+1;
|
||||
|
||||
int len = i - lastKeyword;
|
||||
byte id = keywords.lookup(line,lastKeyword,len);
|
||||
if(id != Token.NULL)
|
||||
{
|
||||
if(lastKeyword != lastOffset)
|
||||
addToken(lastKeyword - lastOffset,Token.NULL);
|
||||
addToken(len,id);
|
||||
lastOffset = i;
|
||||
}
|
||||
lastKeyword = i1;
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,373 +0,0 @@
|
||||
/*
|
||||
* DefaultInputHandler.java - Default implementation of an input handler
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package processing.app.syntax;
|
||||
|
||||
import javax.swing.KeyStroke;
|
||||
import java.awt.event.*;
|
||||
import java.awt.Toolkit;
|
||||
import java.util.Hashtable;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* The default input handler. It maps sequences of keystrokes into actions
|
||||
* and inserts key typed events into the text area.
|
||||
* @author Slava Pestov
|
||||
*/
|
||||
public class DefaultInputHandler extends InputHandler
|
||||
{
|
||||
/**
|
||||
* Creates a new input handler with no key bindings defined.
|
||||
*/
|
||||
public DefaultInputHandler()
|
||||
{
|
||||
bindings = currentBindings = new Hashtable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the default key bindings.
|
||||
*/
|
||||
public void addDefaultKeyBindings()
|
||||
{
|
||||
addKeyBinding("BACK_SPACE",BACKSPACE);
|
||||
addKeyBinding("C+BACK_SPACE",BACKSPACE_WORD);
|
||||
addKeyBinding("DELETE",DELETE);
|
||||
addKeyBinding("C+DELETE",DELETE_WORD);
|
||||
|
||||
addKeyBinding("ENTER",INSERT_BREAK);
|
||||
addKeyBinding("TAB",INSERT_TAB);
|
||||
|
||||
addKeyBinding("INSERT",OVERWRITE);
|
||||
addKeyBinding("C+\\",TOGGLE_RECT);
|
||||
|
||||
addKeyBinding("HOME",HOME);
|
||||
addKeyBinding("END",END);
|
||||
addKeyBinding("S+HOME",SELECT_HOME);
|
||||
addKeyBinding("S+END",SELECT_END);
|
||||
addKeyBinding("C+HOME",DOCUMENT_HOME);
|
||||
addKeyBinding("C+END",DOCUMENT_END);
|
||||
addKeyBinding("CS+HOME",SELECT_DOC_HOME);
|
||||
addKeyBinding("CS+END",SELECT_DOC_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);
|
||||
|
||||
addKeyBinding("C+ENTER",REPEAT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 InputHandler copy()
|
||||
{
|
||||
return new DefaultInputHandler(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a key pressed event. This will look up the binding for
|
||||
* the key stroke and execute it.
|
||||
*/
|
||||
public void keyPressed(KeyEvent evt)
|
||||
{
|
||||
int keyCode = evt.getKeyCode();
|
||||
int modifiers = evt.getModifiers();
|
||||
|
||||
// moved this earlier so it doesn't get random meta clicks
|
||||
if (keyCode == KeyEvent.VK_CONTROL ||
|
||||
keyCode == KeyEvent.VK_SHIFT ||
|
||||
keyCode == KeyEvent.VK_ALT ||
|
||||
keyCode == KeyEvent.VK_META) {
|
||||
return;
|
||||
}
|
||||
|
||||
// don't get command-s or other menu key equivs on mac
|
||||
// unless it's something that's specifically bound (cmd-left or right)
|
||||
//if ((modifiers & KeyEvent.META_MASK) != 0) return;
|
||||
if ((modifiers & KeyEvent.META_MASK) != 0) {
|
||||
KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode, modifiers);
|
||||
if (currentBindings.get(keyStroke) == null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
char keyChar = evt.getKeyChar();
|
||||
System.out.println("code=" + keyCode + " char=" + keyChar +
|
||||
" charint=" + ((int)keyChar));
|
||||
System.out.println("other codes " + KeyEvent.VK_ALT + " " +
|
||||
KeyEvent.VK_META);
|
||||
*/
|
||||
|
||||
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
|
||||
|| keyCode == KeyEvent.VK_ESCAPE)
|
||||
{
|
||||
if(grabAction != null)
|
||||
{
|
||||
handleGrabAction(evt);
|
||||
return;
|
||||
}
|
||||
|
||||
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
|
||||
repeatCount = 0;
|
||||
repeat = false;
|
||||
evt.consume();
|
||||
}
|
||||
currentBindings = bindings;
|
||||
return;
|
||||
}
|
||||
else if(o instanceof ActionListener)
|
||||
{
|
||||
currentBindings = bindings;
|
||||
|
||||
executeAction(((ActionListener)o),
|
||||
evt.getSource(),null);
|
||||
|
||||
evt.consume();
|
||||
return;
|
||||
}
|
||||
else if(o instanceof Hashtable)
|
||||
{
|
||||
currentBindings = (Hashtable)o;
|
||||
evt.consume();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a key typed event. This inserts the key into the text area.
|
||||
*/
|
||||
public void keyTyped(KeyEvent evt)
|
||||
{
|
||||
int modifiers = evt.getModifiers();
|
||||
char c = evt.getKeyChar();
|
||||
|
||||
// this is the apple/cmd key on macosx.. so menu commands
|
||||
// were being passed through as legit keys.. added this line
|
||||
// in an attempt to prevent.
|
||||
if ((modifiers & KeyEvent.META_MASK) != 0) return;
|
||||
|
||||
if (c != KeyEvent.CHAR_UNDEFINED) // &&
|
||||
// (modifiers & KeyEvent.ALT_MASK) == 0)
|
||||
{
|
||||
if(c >= 0x20 && c != 0x7f)
|
||||
{
|
||||
KeyStroke keyStroke = KeyStroke.getKeyStroke(
|
||||
Character.toUpperCase(c));
|
||||
Object o = currentBindings.get(keyStroke);
|
||||
|
||||
if(o instanceof Hashtable)
|
||||
{
|
||||
currentBindings = (Hashtable)o;
|
||||
return;
|
||||
}
|
||||
else if(o instanceof ActionListener)
|
||||
{
|
||||
currentBindings = bindings;
|
||||
executeAction((ActionListener)o,
|
||||
evt.getSource(),
|
||||
String.valueOf(c));
|
||||
return;
|
||||
}
|
||||
|
||||
currentBindings = bindings;
|
||||
|
||||
if(grabAction != null)
|
||||
{
|
||||
handleGrabAction(evt);
|
||||
return;
|
||||
}
|
||||
|
||||
// 0-9 adds another 'digit' to the repeat number
|
||||
if(repeat && Character.isDigit(c))
|
||||
{
|
||||
repeatCount *= 10;
|
||||
repeatCount += (c - '0');
|
||||
return;
|
||||
}
|
||||
|
||||
executeAction(INSERT_CHAR,evt.getSource(),
|
||||
String.valueOf(evt.getKeyChar()));
|
||||
|
||||
repeatCount = 0;
|
||||
repeat = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public static KeyStroke parseKeyStroke(String keyStroke)
|
||||
{
|
||||
if(keyStroke == null)
|
||||
return null;
|
||||
int modifiers = 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)
|
||||
{
|
||||
char ch = Character.toUpperCase(key.charAt(0));
|
||||
if(modifiers == 0)
|
||||
return KeyStroke.getKeyStroke(ch);
|
||||
else
|
||||
return KeyStroke.getKeyStroke(ch,modifiers);
|
||||
}
|
||||
else if(key.length() == 0)
|
||||
{
|
||||
System.err.println("Invalid key stroke: " + keyStroke);
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
int ch;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// private members
|
||||
private Hashtable bindings;
|
||||
private Hashtable currentBindings;
|
||||
|
||||
private DefaultInputHandler(DefaultInputHandler copy)
|
||||
{
|
||||
bindings = currentBindings = copy.bindings;
|
||||
}
|
||||
}
|
@ -1,1135 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package processing.app.syntax;
|
||||
|
||||
import javax.swing.text.*;
|
||||
import javax.swing.JPopupMenu;
|
||||
import java.awt.event.*;
|
||||
import java.awt.Component;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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 backspace_word();
|
||||
public static final ActionListener DELETE = new delete();
|
||||
public static final ActionListener DELETE_WORD = new delete_word();
|
||||
public static final ActionListener END = new end(false);
|
||||
public static final ActionListener DOCUMENT_END = new document_end(false);
|
||||
public static final ActionListener SELECT_END = new end(true);
|
||||
public static final ActionListener SELECT_DOC_END = new document_end(true);
|
||||
public static final ActionListener INSERT_BREAK = new insert_break();
|
||||
public static final ActionListener INSERT_TAB = new insert_tab();
|
||||
public static final ActionListener HOME = new home(false);
|
||||
public static final ActionListener DOCUMENT_HOME = new document_home(false);
|
||||
public static final ActionListener SELECT_HOME = new home(true);
|
||||
public static final ActionListener SELECT_DOC_HOME = new document_home(true);
|
||||
public static final ActionListener NEXT_CHAR = new next_char(false);
|
||||
public static final ActionListener NEXT_LINE = new next_line(false);
|
||||
public static final ActionListener NEXT_PAGE = new next_page(false);
|
||||
public static final ActionListener NEXT_WORD = new next_word(false);
|
||||
public static final ActionListener SELECT_NEXT_CHAR = new next_char(true);
|
||||
public static final ActionListener SELECT_NEXT_LINE = new next_line(true);
|
||||
public static final ActionListener SELECT_NEXT_PAGE = new next_page(true);
|
||||
public static final ActionListener SELECT_NEXT_WORD = new next_word(true);
|
||||
public static final ActionListener OVERWRITE = new overwrite();
|
||||
public static final ActionListener PREV_CHAR = new prev_char(false);
|
||||
public static final ActionListener PREV_LINE = new prev_line(false);
|
||||
public static final ActionListener PREV_PAGE = new prev_page(false);
|
||||
public static final ActionListener PREV_WORD = new prev_word(false);
|
||||
public static final ActionListener SELECT_PREV_CHAR = new prev_char(true);
|
||||
public static final ActionListener SELECT_PREV_LINE = new prev_line(true);
|
||||
public static final ActionListener SELECT_PREV_PAGE = new prev_page(true);
|
||||
public static final ActionListener SELECT_PREV_WORD = new prev_word(true);
|
||||
public static final ActionListener REPEAT = new repeat();
|
||||
public static final ActionListener TOGGLE_RECT = new toggle_rect();
|
||||
public static final ActionListener CLIPBOARD_CUT = new clipboard_cut(); // [fry]
|
||||
public static final ActionListener CLIPBOARD_COPY = new clipboard_copy();
|
||||
public static final ActionListener CLIPBOARD_PASTE = new clipboard_paste();
|
||||
|
||||
// Default action
|
||||
public static final ActionListener INSERT_CHAR = new insert_char();
|
||||
|
||||
private static Hashtable actions;
|
||||
|
||||
static
|
||||
{
|
||||
actions = new Hashtable();
|
||||
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-cut",CLIPBOARD_CUT);
|
||||
actions.put("clipboard-copy",CLIPBOARD_COPY);
|
||||
actions.put("clipboard-paste",CLIPBOARD_PASTE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a named text area action.
|
||||
* @param name The action name
|
||||
*/
|
||||
public static ActionListener getAction(String name)
|
||||
{
|
||||
return (ActionListener)actions.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the specified text area action.
|
||||
* @param listener The action
|
||||
*/
|
||||
public static String getActionName(ActionListener listener)
|
||||
{
|
||||
Enumeration en = getActions();
|
||||
while(en.hasMoreElements())
|
||||
{
|
||||
String name = (String)en.nextElement();
|
||||
ActionListener _listener = getAction(name);
|
||||
if(_listener == listener) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an enumeration of all available actions.
|
||||
*/
|
||||
public static Enumeration 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.getSelectionStop())
|
||||
{
|
||||
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 backspace_word implements ActionListener
|
||||
{
|
||||
public void actionPerformed(ActionEvent evt)
|
||||
{
|
||||
JEditTextArea textArea = getTextArea(evt);
|
||||
int start = textArea.getSelectionStart();
|
||||
if(start != textArea.getSelectionStop())
|
||||
{
|
||||
textArea.setSelectedText("");
|
||||
}
|
||||
|
||||
int line = textArea.getCaretLine();
|
||||
int lineStart = textArea.getLineStartOffset(line);
|
||||
int caret = start - lineStart;
|
||||
|
||||
String lineText = textArea.getLineText(textArea
|
||||
.getCaretLine());
|
||||
|
||||
if(caret == 0)
|
||||
{
|
||||
if(lineStart == 0)
|
||||
{
|
||||
textArea.getToolkit().beep();
|
||||
return;
|
||||
}
|
||||
caret--;
|
||||
}
|
||||
else
|
||||
{
|
||||
String noWordSep = (String)textArea.getDocument().getProperty("noWordSep");
|
||||
caret = TextUtilities.findWordStart(lineText,caret,noWordSep);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
textArea.getDocument().remove(
|
||||
caret + lineStart,
|
||||
start - (caret + lineStart));
|
||||
}
|
||||
catch(BadLocationException bl)
|
||||
{
|
||||
bl.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class delete implements ActionListener
|
||||
{
|
||||
public void actionPerformed(ActionEvent evt)
|
||||
{
|
||||
JEditTextArea textArea = getTextArea(evt);
|
||||
|
||||
if(!textArea.isEditable())
|
||||
{
|
||||
textArea.getToolkit().beep();
|
||||
return;
|
||||
}
|
||||
|
||||
if(textArea.getSelectionStart()
|
||||
!= textArea.getSelectionStop())
|
||||
{
|
||||
textArea.setSelectedText("");
|
||||
}
|
||||
else
|
||||
{
|
||||
int caret = textArea.getCaretPosition();
|
||||
if(caret == textArea.getDocumentLength())
|
||||
{
|
||||
textArea.getToolkit().beep();
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
textArea.getDocument().remove(caret,1);
|
||||
}
|
||||
catch(BadLocationException bl)
|
||||
{
|
||||
bl.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class delete_word implements ActionListener
|
||||
{
|
||||
public void actionPerformed(ActionEvent evt)
|
||||
{
|
||||
JEditTextArea textArea = getTextArea(evt);
|
||||
int start = textArea.getSelectionStart();
|
||||
if(start != textArea.getSelectionStop())
|
||||
{
|
||||
textArea.setSelectedText("");
|
||||
}
|
||||
|
||||
int line = textArea.getCaretLine();
|
||||
int lineStart = textArea.getLineStartOffset(line);
|
||||
int caret = start - lineStart;
|
||||
|
||||
String lineText = textArea.getLineText(textArea
|
||||
.getCaretLine());
|
||||
|
||||
if(caret == lineText.length())
|
||||
{
|
||||
if(lineStart + caret == textArea.getDocumentLength())
|
||||
{
|
||||
textArea.getToolkit().beep();
|
||||
return;
|
||||
}
|
||||
caret++;
|
||||
}
|
||||
else
|
||||
{
|
||||
String noWordSep = (String)textArea.getDocument().getProperty("noWordSep");
|
||||
caret = TextUtilities.findWordEnd(lineText,caret,noWordSep);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
textArea.getDocument().remove(start,
|
||||
(caret + lineStart) - start);
|
||||
}
|
||||
catch(BadLocationException bl)
|
||||
{
|
||||
bl.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class end implements ActionListener
|
||||
{
|
||||
private boolean select;
|
||||
|
||||
public end(boolean select)
|
||||
{
|
||||
this.select = select;
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent evt)
|
||||
{
|
||||
JEditTextArea textArea = getTextArea(evt);
|
||||
|
||||
int caret = textArea.getCaretPosition();
|
||||
|
||||
int lastOfLine = textArea.getLineStopOffset(
|
||||
textArea.getCaretLine()) - 1;
|
||||
int lastVisibleLine = textArea.getFirstLine()
|
||||
+ textArea.getVisibleLines();
|
||||
if(lastVisibleLine >= textArea.getLineCount())
|
||||
{
|
||||
lastVisibleLine = Math.min(textArea.getLineCount() - 1,
|
||||
lastVisibleLine);
|
||||
}
|
||||
else
|
||||
lastVisibleLine -= (textArea.getElectricScroll() + 1);
|
||||
|
||||
int lastVisible = textArea.getLineStopOffset(lastVisibleLine) - 1;
|
||||
int lastDocument = textArea.getDocumentLength();
|
||||
|
||||
if(caret == lastDocument)
|
||||
{
|
||||
textArea.getToolkit().beep();
|
||||
return;
|
||||
}
|
||||
else if(!Boolean.TRUE.equals(textArea.getClientProperty(
|
||||
SMART_HOME_END_PROPERTY)))
|
||||
caret = lastOfLine;
|
||||
else if(caret == lastVisible)
|
||||
caret = lastDocument;
|
||||
else if(caret == lastOfLine)
|
||||
caret = lastVisible;
|
||||
else
|
||||
caret = lastOfLine;
|
||||
|
||||
if(select)
|
||||
textArea.select(textArea.getMarkPosition(),caret);
|
||||
else
|
||||
textArea.setCaretPosition(caret);
|
||||
}
|
||||
}
|
||||
|
||||
public static class document_end implements ActionListener
|
||||
{
|
||||
private boolean select;
|
||||
|
||||
public document_end(boolean select)
|
||||
{
|
||||
this.select = select;
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent evt)
|
||||
{
|
||||
JEditTextArea textArea = getTextArea(evt);
|
||||
if(select)
|
||||
textArea.select(textArea.getMarkPosition(),
|
||||
textArea.getDocumentLength());
|
||||
else
|
||||
textArea.setCaretPosition(textArea
|
||||
.getDocumentLength());
|
||||
}
|
||||
}
|
||||
|
||||
public static class home implements ActionListener
|
||||
{
|
||||
private boolean select;
|
||||
|
||||
public home(boolean select)
|
||||
{
|
||||
this.select = select;
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent evt)
|
||||
{
|
||||
JEditTextArea textArea = getTextArea(evt);
|
||||
|
||||
int caret = textArea.getCaretPosition();
|
||||
|
||||
int firstLine = textArea.getFirstLine();
|
||||
|
||||
int firstOfLine = textArea.getLineStartOffset(
|
||||
textArea.getCaretLine());
|
||||
int firstVisibleLine = (firstLine == 0 ? 0 :
|
||||
firstLine + textArea.getElectricScroll());
|
||||
int firstVisible = textArea.getLineStartOffset(
|
||||
firstVisibleLine);
|
||||
|
||||
if(caret == 0)
|
||||
{
|
||||
textArea.getToolkit().beep();
|
||||
return;
|
||||
}
|
||||
else if(!Boolean.TRUE.equals(textArea.getClientProperty(
|
||||
SMART_HOME_END_PROPERTY)))
|
||||
caret = firstOfLine;
|
||||
else if(caret == firstVisible)
|
||||
caret = 0;
|
||||
else if(caret == firstOfLine)
|
||||
caret = firstVisible;
|
||||
else
|
||||
caret = firstOfLine;
|
||||
|
||||
if(select)
|
||||
textArea.select(textArea.getMarkPosition(),caret);
|
||||
else
|
||||
textArea.setCaretPosition(caret);
|
||||
}
|
||||
}
|
||||
|
||||
public static class document_home implements ActionListener
|
||||
{
|
||||
private boolean select;
|
||||
|
||||
public document_home(boolean select)
|
||||
{
|
||||
this.select = select;
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent evt)
|
||||
{
|
||||
JEditTextArea textArea = getTextArea(evt);
|
||||
if(select)
|
||||
textArea.select(textArea.getMarkPosition(),0);
|
||||
else
|
||||
textArea.setCaretPosition(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static class insert_break implements ActionListener
|
||||
{
|
||||
public void actionPerformed(ActionEvent evt)
|
||||
{
|
||||
JEditTextArea textArea = getTextArea(evt);
|
||||
|
||||
if(!textArea.isEditable())
|
||||
{
|
||||
textArea.getToolkit().beep();
|
||||
return;
|
||||
}
|
||||
|
||||
textArea.setSelectedText("\n");
|
||||
}
|
||||
}
|
||||
|
||||
public static class insert_tab implements ActionListener
|
||||
{
|
||||
public void actionPerformed(ActionEvent evt)
|
||||
{
|
||||
JEditTextArea textArea = getTextArea(evt);
|
||||
|
||||
if(!textArea.isEditable())
|
||||
{
|
||||
textArea.getToolkit().beep();
|
||||
return;
|
||||
}
|
||||
|
||||
textArea.overwriteSetSelectedText("\t");
|
||||
}
|
||||
}
|
||||
|
||||
public static class next_char implements ActionListener
|
||||
{
|
||||
private boolean select;
|
||||
|
||||
public next_char(boolean select)
|
||||
{
|
||||
this.select = select;
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent evt)
|
||||
{
|
||||
JEditTextArea textArea = getTextArea(evt);
|
||||
int caret = textArea.getCaretPosition();
|
||||
|
||||
if(caret == textArea.getDocumentLength())
|
||||
{
|
||||
if (textArea.getSelectionStart() !=
|
||||
textArea.getSelectionStop()) {
|
||||
// just move to the end of the selection
|
||||
textArea.select(caret, caret);
|
||||
} else {
|
||||
// beep at the user for being annoying
|
||||
textArea.getToolkit().beep();
|
||||
}
|
||||
|
||||
} else if (select) {
|
||||
textArea.select(textArea.getMarkPosition(), caret+1);
|
||||
|
||||
} else {
|
||||
int start = textArea.getSelectionStart();
|
||||
int end = textArea.getSelectionStop();
|
||||
if (start != end) {
|
||||
textArea.select(end, end);
|
||||
} else {
|
||||
textArea.setCaretPosition(caret + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class next_line implements ActionListener
|
||||
{
|
||||
private boolean select;
|
||||
|
||||
public next_line(boolean select)
|
||||
{
|
||||
this.select = select;
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent evt)
|
||||
{
|
||||
JEditTextArea textArea = getTextArea(evt);
|
||||
int caret = textArea.getCaretPosition();
|
||||
int line = textArea.getCaretLine();
|
||||
|
||||
if(line == textArea.getLineCount() - 1)
|
||||
{
|
||||
//textArea.getToolkit().beep();
|
||||
int doc = textArea.getDocumentLength();
|
||||
if (select) {
|
||||
textArea.select(textArea.getMarkPosition(), doc);
|
||||
} else {
|
||||
textArea.setCaretPosition(doc);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int magic = textArea.getMagicCaretPosition();
|
||||
if(magic == -1)
|
||||
{
|
||||
magic = textArea.offsetToX(line,
|
||||
caret - textArea.getLineStartOffset(line));
|
||||
}
|
||||
|
||||
caret = textArea.getLineStartOffset(line + 1)
|
||||
+ textArea.xToOffset(line + 1,magic);
|
||||
if(select)
|
||||
textArea.select(textArea.getMarkPosition(),caret);
|
||||
else
|
||||
textArea.setCaretPosition(caret);
|
||||
textArea.setMagicCaretPosition(magic);
|
||||
}
|
||||
}
|
||||
|
||||
public static class next_page implements ActionListener
|
||||
{
|
||||
private boolean select;
|
||||
|
||||
public next_page(boolean select)
|
||||
{
|
||||
this.select = select;
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent evt)
|
||||
{
|
||||
JEditTextArea textArea = getTextArea(evt);
|
||||
int lineCount = textArea.getLineCount();
|
||||
int firstLine = textArea.getFirstLine();
|
||||
int visibleLines = textArea.getVisibleLines();
|
||||
int line = textArea.getCaretLine();
|
||||
|
||||
firstLine += visibleLines;
|
||||
|
||||
if(firstLine + visibleLines >= lineCount - 1)
|
||||
firstLine = lineCount - visibleLines;
|
||||
|
||||
textArea.setFirstLine(firstLine);
|
||||
|
||||
int caret = textArea.getLineStartOffset(
|
||||
Math.min(textArea.getLineCount() - 1,
|
||||
line + visibleLines));
|
||||
if(select)
|
||||
textArea.select(textArea.getMarkPosition(),caret);
|
||||
else
|
||||
textArea.setCaretPosition(caret);
|
||||
}
|
||||
}
|
||||
|
||||
public static class next_word implements ActionListener
|
||||
{
|
||||
private boolean select;
|
||||
|
||||
public next_word(boolean select)
|
||||
{
|
||||
this.select = select;
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent evt)
|
||||
{
|
||||
JEditTextArea textArea = getTextArea(evt);
|
||||
int caret = textArea.getCaretPosition();
|
||||
int line = textArea.getCaretLine();
|
||||
int lineStart = textArea.getLineStartOffset(line);
|
||||
caret -= lineStart;
|
||||
|
||||
String lineText = textArea.getLineText(textArea
|
||||
.getCaretLine());
|
||||
|
||||
if(caret == lineText.length())
|
||||
{
|
||||
if(lineStart + caret == textArea.getDocumentLength())
|
||||
{
|
||||
textArea.getToolkit().beep();
|
||||
return;
|
||||
}
|
||||
caret++;
|
||||
}
|
||||
else
|
||||
{
|
||||
String noWordSep = (String)textArea.getDocument().getProperty("noWordSep");
|
||||
caret = TextUtilities.findWordEnd(lineText,caret,noWordSep);
|
||||
}
|
||||
|
||||
if(select)
|
||||
textArea.select(textArea.getMarkPosition(),
|
||||
lineStart + caret);
|
||||
else
|
||||
textArea.setCaretPosition(lineStart + caret);
|
||||
}
|
||||
}
|
||||
|
||||
public static class overwrite implements ActionListener
|
||||
{
|
||||
public void actionPerformed(ActionEvent evt)
|
||||
{
|
||||
JEditTextArea textArea = getTextArea(evt);
|
||||
textArea.setOverwriteEnabled(
|
||||
!textArea.isOverwriteEnabled());
|
||||
}
|
||||
}
|
||||
|
||||
public static class prev_char implements ActionListener
|
||||
{
|
||||
private boolean select;
|
||||
|
||||
public prev_char(boolean select)
|
||||
{
|
||||
this.select = select;
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent evt)
|
||||
{
|
||||
JEditTextArea textArea = getTextArea(evt);
|
||||
int caret = textArea.getCaretPosition();
|
||||
if(caret == 0)
|
||||
{
|
||||
textArea.getToolkit().beep();
|
||||
return;
|
||||
}
|
||||
|
||||
if (select) {
|
||||
textArea.select(textArea.getMarkPosition(), caret-1);
|
||||
} else {
|
||||
int start = textArea.getSelectionStart();
|
||||
int end = textArea.getSelectionStop();
|
||||
if (start != end) {
|
||||
textArea.select(start, start);
|
||||
} else {
|
||||
textArea.setCaretPosition(caret - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class prev_line implements ActionListener
|
||||
{
|
||||
private boolean select;
|
||||
|
||||
public prev_line(boolean select)
|
||||
{
|
||||
this.select = select;
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent evt)
|
||||
{
|
||||
JEditTextArea textArea = getTextArea(evt);
|
||||
int caret = textArea.getCaretPosition();
|
||||
int line = textArea.getCaretLine();
|
||||
|
||||
if(line == 0)
|
||||
{
|
||||
if (select) {
|
||||
if (textArea.getSelectionStart() != 0) {
|
||||
textArea.select(textArea.getMarkPosition(), 0);
|
||||
}
|
||||
} else {
|
||||
textArea.setCaretPosition(0);
|
||||
}
|
||||
//textArea.getToolkit().beep();
|
||||
return;
|
||||
}
|
||||
|
||||
int magic = textArea.getMagicCaretPosition();
|
||||
if(magic == -1)
|
||||
{
|
||||
magic = textArea.offsetToX(line,
|
||||
caret - textArea.getLineStartOffset(line));
|
||||
}
|
||||
|
||||
caret = textArea.getLineStartOffset(line - 1)
|
||||
+ textArea.xToOffset(line - 1,magic);
|
||||
if(select)
|
||||
textArea.select(textArea.getMarkPosition(),caret);
|
||||
else
|
||||
textArea.setCaretPosition(caret);
|
||||
textArea.setMagicCaretPosition(magic);
|
||||
}
|
||||
}
|
||||
|
||||
public static class prev_page implements ActionListener
|
||||
{
|
||||
private boolean select;
|
||||
|
||||
public prev_page(boolean select)
|
||||
{
|
||||
this.select = select;
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent evt)
|
||||
{
|
||||
JEditTextArea textArea = getTextArea(evt);
|
||||
int firstLine = textArea.getFirstLine();
|
||||
int visibleLines = textArea.getVisibleLines();
|
||||
int line = textArea.getCaretLine();
|
||||
|
||||
if(firstLine < visibleLines)
|
||||
firstLine = visibleLines;
|
||||
|
||||
textArea.setFirstLine(firstLine - visibleLines);
|
||||
|
||||
int caret = textArea.getLineStartOffset(
|
||||
Math.max(0,line - visibleLines));
|
||||
if(select)
|
||||
textArea.select(textArea.getMarkPosition(),caret);
|
||||
else
|
||||
textArea.setCaretPosition(caret);
|
||||
}
|
||||
}
|
||||
|
||||
public static class prev_word implements ActionListener
|
||||
{
|
||||
private boolean select;
|
||||
|
||||
public prev_word(boolean select)
|
||||
{
|
||||
this.select = select;
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent evt)
|
||||
{
|
||||
JEditTextArea textArea = getTextArea(evt);
|
||||
int caret = textArea.getCaretPosition();
|
||||
int line = textArea.getCaretLine();
|
||||
int lineStart = textArea.getLineStartOffset(line);
|
||||
caret -= lineStart;
|
||||
|
||||
String lineText = textArea.getLineText(textArea
|
||||
.getCaretLine());
|
||||
|
||||
if(caret == 0)
|
||||
{
|
||||
if(lineStart == 0)
|
||||
{
|
||||
textArea.getToolkit().beep();
|
||||
return;
|
||||
}
|
||||
caret--;
|
||||
}
|
||||
else
|
||||
{
|
||||
String noWordSep = (String)textArea.getDocument().getProperty("noWordSep");
|
||||
caret = TextUtilities.findWordStart(lineText,caret,noWordSep);
|
||||
}
|
||||
|
||||
if(select)
|
||||
textArea.select(textArea.getMarkPosition(),
|
||||
lineStart + caret);
|
||||
else
|
||||
textArea.setCaretPosition(lineStart + caret);
|
||||
}
|
||||
}
|
||||
|
||||
public static class repeat implements ActionListener,
|
||||
InputHandler.NonRecordable
|
||||
{
|
||||
public void actionPerformed(ActionEvent evt)
|
||||
{
|
||||
JEditTextArea textArea = getTextArea(evt);
|
||||
textArea.getInputHandler().setRepeatEnabled(true);
|
||||
String actionCommand = evt.getActionCommand();
|
||||
if(actionCommand != null)
|
||||
{
|
||||
textArea.getInputHandler().setRepeatCount(
|
||||
Integer.parseInt(actionCommand));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class toggle_rect implements ActionListener
|
||||
{
|
||||
public void actionPerformed(ActionEvent evt)
|
||||
{
|
||||
JEditTextArea textArea = getTextArea(evt);
|
||||
textArea.setSelectionRectangular(
|
||||
!textArea.isSelectionRectangular());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class clipboard_cut implements ActionListener
|
||||
{
|
||||
public void actionPerformed(ActionEvent evt)
|
||||
{
|
||||
getTextArea(evt).cut();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class clipboard_copy implements ActionListener
|
||||
{
|
||||
public void actionPerformed(ActionEvent evt)
|
||||
{
|
||||
getTextArea(evt).copy();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class clipboard_paste implements ActionListener
|
||||
{
|
||||
public void actionPerformed(ActionEvent evt)
|
||||
{
|
||||
getTextArea(evt).paste();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class insert_char implements ActionListener,
|
||||
InputHandler.NonRepeatable
|
||||
{
|
||||
public void actionPerformed(ActionEvent evt)
|
||||
{
|
||||
JEditTextArea textArea = getTextArea(evt);
|
||||
String str = evt.getActionCommand();
|
||||
int repeatCount = textArea.getInputHandler().getRepeatCount();
|
||||
|
||||
if(textArea.isEditable())
|
||||
{
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for(int i = 0; i < repeatCount; i++)
|
||||
buf.append(str);
|
||||
textArea.overwriteSetSelectedText(buf.toString());
|
||||
}
|
||||
else
|
||||
{
|
||||
textArea.getToolkit().beep();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,2448 +0,0 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
* JEditTextArea.java - jEdit's text component
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package processing.app.syntax;
|
||||
|
||||
import processing.app.*;
|
||||
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.text.*;
|
||||
import javax.swing.undo.*;
|
||||
import javax.swing.*;
|
||||
|
||||
import java.awt.datatransfer.*;
|
||||
import java.awt.event.*;
|
||||
import java.awt.*;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Vector;
|
||||
import java.awt.im.InputMethodRequests;
|
||||
|
||||
import processing.app.syntax.im.InputMethodSupport;
|
||||
|
||||
/**
|
||||
* jEdit's text area component. It is more suited for editing program
|
||||
* source code than JEditorPane, because it drops the unnecessary features
|
||||
* (images, variable-width lines, and so on) and adds a whole bunch of
|
||||
* useful goodies such as:
|
||||
* <ul>
|
||||
* <li>More flexible key binding scheme
|
||||
* <li>Supports macro recorders
|
||||
* <li>Rectangular selection
|
||||
* <li>Bracket highlighting
|
||||
* <li>Syntax highlighting
|
||||
* <li>Command repetition
|
||||
* <li>Block caret can be enabled
|
||||
* </ul>
|
||||
* It is also faster and doesn't have as many problems. It can be used
|
||||
* in other applications; the only other part of jEdit it depends on is
|
||||
* the syntax package.<p>
|
||||
*
|
||||
* To use it in your app, treat it like any other component, for example:
|
||||
* <pre>JEditTextArea ta = new JEditTextArea();
|
||||
* ta.setTokenMarker(new JavaTokenMarker());
|
||||
* ta.setText("public class Test {\n"
|
||||
* + " public static void main(String[] args) {\n"
|
||||
* + " System.out.println(\"Hello World\");\n"
|
||||
* + " }\n"
|
||||
* + "}");</pre>
|
||||
*
|
||||
* @author Slava Pestov
|
||||
*/
|
||||
public class JEditTextArea extends JComponent
|
||||
{
|
||||
/**
|
||||
* Adding components with this name to the text area will place
|
||||
* them left of the horizontal scroll bar. In jEdit, the status
|
||||
* bar is added this way.
|
||||
*/
|
||||
public static String LEFT_OF_SCROLLBAR = "los";
|
||||
|
||||
/**
|
||||
* Creates a new JEditTextArea with the default settings.
|
||||
*/
|
||||
/*
|
||||
public JEditTextArea()
|
||||
{
|
||||
this(TextAreaDefaults.getDefaults());
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a new JEditTextArea with the specified settings.
|
||||
* @param defaults The default settings
|
||||
*/
|
||||
public JEditTextArea(TextAreaDefaults defaults)
|
||||
{
|
||||
// Enable the necessary events
|
||||
enableEvents(AWTEvent.KEY_EVENT_MASK);
|
||||
|
||||
// Initialize some misc. stuff
|
||||
painter = new TextAreaPainter(this,defaults);
|
||||
editorLineNumbers = new TextAreaLineNumbers(this,defaults);
|
||||
documentHandler = new DocumentHandler();
|
||||
eventListenerList = new EventListenerList();
|
||||
caretEvent = new MutableCaretEvent();
|
||||
lineSegment = new Segment();
|
||||
bracketLine = bracketPosition = -1;
|
||||
blink = true;
|
||||
|
||||
// Initialize the GUI
|
||||
setLayout(new ScrollLayout());
|
||||
add(LEFT, editorLineNumbers);
|
||||
add(CENTER, painter);
|
||||
add(RIGHT, vertical = new JScrollBar(JScrollBar.VERTICAL));
|
||||
add(BOTTOM, horizontal = new JScrollBar(JScrollBar.HORIZONTAL));
|
||||
|
||||
// Add some event listeners
|
||||
vertical.addAdjustmentListener(new AdjustHandler());
|
||||
horizontal.addAdjustmentListener(new AdjustHandler());
|
||||
painter.addComponentListener(new ComponentHandler());
|
||||
painter.addMouseListener(new MouseHandler());
|
||||
painter.addMouseMotionListener(new DragHandler());
|
||||
addFocusListener(new FocusHandler());
|
||||
// send tab keys through to the text area
|
||||
// http://dev.processing.org/bugs/show_bug.cgi?id=1267
|
||||
setFocusTraversalKeysEnabled(false);
|
||||
|
||||
// Load the defaults
|
||||
setInputHandler(defaults.inputHandler);
|
||||
setDocument(defaults.document);
|
||||
editable = defaults.editable;
|
||||
caretVisible = defaults.caretVisible;
|
||||
caretBlinks = defaults.caretBlinks;
|
||||
electricScroll = defaults.electricScroll;
|
||||
|
||||
// We don't seem to get the initial focus event?
|
||||
focusedComponent = this;
|
||||
|
||||
addMouseWheelListener(new MouseWheelListener() {
|
||||
public void mouseWheelMoved(MouseWheelEvent e) {
|
||||
if (!scrollBarsInitialized) return;
|
||||
int amt = e.getWheelRotation();
|
||||
vertical.setValue(vertical.getValue() + amt * 3);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline Input Method Support for Japanese.
|
||||
*/
|
||||
private InputMethodSupport inputMethodSupport = null;
|
||||
public InputMethodRequests getInputMethodRequests() {
|
||||
if (inputMethodSupport == null) {
|
||||
inputMethodSupport = new InputMethodSupport(this);
|
||||
}
|
||||
return inputMethodSupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current position of the vertical scroll bar. [fry]
|
||||
*/
|
||||
public int getScrollPosition() {
|
||||
return vertical.getValue();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set position of the vertical scroll bar. [fry]
|
||||
*/
|
||||
public void setScrollPosition(int what) {
|
||||
vertical.setValue(what);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns if this component can be traversed by pressing
|
||||
* the Tab key. This returns false.
|
||||
*/
|
||||
// public final boolean isManagingFocus() {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns the object responsible for painting this text area.
|
||||
*/
|
||||
public final TextAreaPainter getPainter() {
|
||||
return painter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the input handler.
|
||||
*/
|
||||
public final InputHandler getInputHandler() {
|
||||
return inputHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the input handler.
|
||||
* @param inputHandler The new input handler
|
||||
*/
|
||||
public void setInputHandler(InputHandler inputHandler) {
|
||||
this.inputHandler = inputHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the caret is blinking, false otherwise.
|
||||
*/
|
||||
public final boolean isCaretBlinkEnabled() {
|
||||
return caretBlinks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles caret blinking.
|
||||
* @param caretBlinks True if the caret should blink, false otherwise
|
||||
*/
|
||||
public void setCaretBlinkEnabled(boolean caretBlinks) {
|
||||
this.caretBlinks = caretBlinks;
|
||||
if(!caretBlinks)
|
||||
blink = false;
|
||||
|
||||
painter.invalidateSelectedLines();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the caret is visible, false otherwise.
|
||||
*/
|
||||
public final boolean isCaretVisible() {
|
||||
return (!caretBlinks || blink) && caretVisible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if the caret should be visible.
|
||||
* @param caretVisible True if the caret should be visible, false
|
||||
* otherwise
|
||||
*/
|
||||
public void setCaretVisible(boolean caretVisible) {
|
||||
this.caretVisible = caretVisible;
|
||||
blink = true;
|
||||
|
||||
painter.invalidateSelectedLines();
|
||||
}
|
||||
|
||||
/**
|
||||
* Blinks the caret.
|
||||
*/
|
||||
public final void blinkCaret() {
|
||||
if (caretBlinks) {
|
||||
blink = !blink;
|
||||
painter.invalidateSelectedLines();
|
||||
} else {
|
||||
blink = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of lines from the top and button of the
|
||||
* text area that are always visible.
|
||||
*/
|
||||
public final int getElectricScroll() {
|
||||
return electricScroll;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number of lines from the top and bottom of the text
|
||||
* area that are always visible
|
||||
* @param electricScroll The number of lines always visible from
|
||||
* the top or bottom
|
||||
*/
|
||||
public final void setElectricScroll(int electricScroll) {
|
||||
this.electricScroll = electricScroll;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Updates the state of the scroll bars. This should be called
|
||||
* if the number of lines in the document changes, or when the
|
||||
* size of the text are changes.
|
||||
*/
|
||||
public void updateScrollBars() {
|
||||
if (vertical != null && visibleLines != 0) {
|
||||
vertical.setValues(firstLine,visibleLines,0,getLineCount());
|
||||
vertical.setUnitIncrement(2);
|
||||
vertical.setBlockIncrement(visibleLines);
|
||||
}
|
||||
|
||||
//if (horizontal != null && width != 0) {
|
||||
if ((horizontal != null) && (painter.getWidth() != 0)) {
|
||||
//int value = horizontal.getValue();
|
||||
//System.out.println("updateScrollBars");
|
||||
//int width = painter.getWidth();
|
||||
int lineCount = getLineCount();
|
||||
int maxLineLength = 0;
|
||||
for (int i = 0; i < lineCount; i++) {
|
||||
int lineLength = getLineLength(i);
|
||||
if (lineLength > maxLineLength) {
|
||||
maxLineLength = lineLength;
|
||||
}
|
||||
}
|
||||
int charWidth = painter.getFontMetrics().charWidth('w');
|
||||
int width = maxLineLength * charWidth;
|
||||
int painterWidth = painter.getWidth();
|
||||
//System.out.println("max line len " + maxLineLength);
|
||||
//System.out.println("width " + width);
|
||||
//System.out.println("text area width " + painter.getWidth());
|
||||
|
||||
// this was the default, but it's enormous
|
||||
//horizontal.setValues(-horizontalOffset,width,0,width * 5);
|
||||
|
||||
// something more reasonable, though this is a bad solution
|
||||
//horizontal.setValues(-horizontalOffset,width,0,width * 2);
|
||||
|
||||
// in general.. time to start looking at that other syntax pkg
|
||||
// since most code should fit the window horizontally, just use
|
||||
// the default settings for the width, this is a nicer solution
|
||||
// until a better update mechanism can be implemented [fry]
|
||||
|
||||
//horizontal.setValues(0, width, 0, width);
|
||||
//0, width - horizontalOffset);
|
||||
// works, from pre-75 versions of p5
|
||||
//horizontal.setValues(-horizontalOffset, width, 0, width);
|
||||
|
||||
// gets weird when writing to the end of lines
|
||||
//horizontal.setValues(value, painterWidth, 0, width);
|
||||
|
||||
// seems to work, implemented for 0075
|
||||
horizontal.setValues(-horizontalOffset, painterWidth, 0, width);
|
||||
|
||||
//horizontal.setUnitIncrement(painter.getFontMetrics().charWidth('w'));
|
||||
horizontal.setUnitIncrement(charWidth);
|
||||
horizontal.setBlockIncrement(width / 2);
|
||||
}
|
||||
updateLineNumbers();
|
||||
}
|
||||
|
||||
private void updateLineNumbers() {
|
||||
if (editorLineNumbers != null) {
|
||||
editorLineNumbers.updateLineNumbers(getFirstLine() + 1, Math.min(getFirstLine() + getVisibleLines() + 1, getLineCount()));
|
||||
editorLineNumbers.updateWidthForNumDigits(String.valueOf(getLineCount()).length());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the line displayed at the text area's origin.
|
||||
*/
|
||||
public final int getFirstLine() {
|
||||
return firstLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the line displayed at the text area's origin without
|
||||
* updating the scroll bars.
|
||||
*/
|
||||
public void setFirstLine(int firstLine) {
|
||||
if (firstLine == this.firstLine) return;
|
||||
|
||||
this.firstLine = firstLine;
|
||||
if (firstLine != vertical.getValue()) {
|
||||
updateScrollBars();
|
||||
}
|
||||
repaintEditor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of lines visible in this text area.
|
||||
*/
|
||||
public final int getVisibleLines() {
|
||||
return visibleLines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recalculates the number of visible lines. This should not
|
||||
* be called directly.
|
||||
*/
|
||||
public final void recalculateVisibleLines() {
|
||||
if (painter == null) return;
|
||||
|
||||
int height = painter.getHeight();
|
||||
int lineHeight = painter.getFontMetrics().getHeight();
|
||||
visibleLines = height / lineHeight;
|
||||
updateScrollBars();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the horizontal offset of drawn lines.
|
||||
*/
|
||||
public final int getHorizontalOffset() {
|
||||
return horizontalOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the horizontal offset of drawn lines. This can be used to
|
||||
* implement horizontal scrolling.
|
||||
* @param horizontalOffset offset The new horizontal offset
|
||||
*/
|
||||
public void setHorizontalOffset(int horizontalOffset)
|
||||
{
|
||||
if(horizontalOffset == this.horizontalOffset)
|
||||
return;
|
||||
this.horizontalOffset = horizontalOffset;
|
||||
if(horizontalOffset != horizontal.getValue())
|
||||
updateScrollBars();
|
||||
repaintEditor();
|
||||
}
|
||||
|
||||
/**
|
||||
* A fast way of changing both the first line and horizontal
|
||||
* offset.
|
||||
* @param firstLine The new first line
|
||||
* @param horizontalOffset The new horizontal offset
|
||||
* @return True if any of the values were changed, false otherwise
|
||||
*/
|
||||
public boolean setOrigin(int firstLine, int horizontalOffset)
|
||||
{
|
||||
boolean changed = false;
|
||||
//int oldFirstLine = this.firstLine;
|
||||
|
||||
if(horizontalOffset != this.horizontalOffset)
|
||||
{
|
||||
this.horizontalOffset = horizontalOffset;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if(firstLine != this.firstLine)
|
||||
{
|
||||
this.firstLine = firstLine;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if(changed)
|
||||
{
|
||||
updateScrollBars();
|
||||
repaintEditor();
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
private void repaintEditor() {
|
||||
painter.repaint();
|
||||
updateLineNumbers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the caret is visible by scrolling the text area if
|
||||
* necessary.
|
||||
* @return True if scrolling was actually performed, false if the
|
||||
* caret was already visible
|
||||
*/
|
||||
public boolean scrollToCaret()
|
||||
{
|
||||
int line = getCaretLine();
|
||||
int lineStart = getLineStartOffset(line);
|
||||
int offset = Math.max(0,Math.min(getLineLength(line) - 1,
|
||||
getCaretPosition() - lineStart));
|
||||
|
||||
return scrollTo(line,offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the specified line and offset is visible by scrolling
|
||||
* the text area if necessary.
|
||||
* @param line The line to scroll to
|
||||
* @param offset The offset in the line to scroll to
|
||||
* @return True if scrolling was actually performed, false if the
|
||||
* line and offset was already visible
|
||||
*/
|
||||
public boolean scrollTo(int line, int offset)
|
||||
{
|
||||
// visibleLines == 0 before the component is realized
|
||||
// we can't do any proper scrolling then, so we have
|
||||
// this hack...
|
||||
if (visibleLines == 0) {
|
||||
setFirstLine(Math.max(0,line - electricScroll));
|
||||
return true;
|
||||
}
|
||||
|
||||
int newFirstLine = firstLine;
|
||||
int newHorizontalOffset = horizontalOffset;
|
||||
|
||||
if(line < firstLine + electricScroll) {
|
||||
newFirstLine = Math.max(0,line - electricScroll);
|
||||
|
||||
} else if(line + electricScroll >= firstLine + visibleLines) {
|
||||
newFirstLine = (line - visibleLines) + electricScroll + 1;
|
||||
if(newFirstLine + visibleLines >= getLineCount())
|
||||
newFirstLine = getLineCount() - visibleLines;
|
||||
if(newFirstLine < 0)
|
||||
newFirstLine = 0;
|
||||
}
|
||||
|
||||
int x = _offsetToX(line,offset);
|
||||
int width = painter.getFontMetrics().charWidth('w');
|
||||
|
||||
if(x < 0) {
|
||||
newHorizontalOffset = Math.min(0,horizontalOffset - x + width + 5);
|
||||
} else if(x + width >= painter.getWidth()) {
|
||||
newHorizontalOffset = horizontalOffset +
|
||||
(painter.getWidth() - x) - width - 5;
|
||||
}
|
||||
|
||||
return setOrigin(newFirstLine,newHorizontalOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a line index to a y co-ordinate.
|
||||
* @param line The line
|
||||
*/
|
||||
public int lineToY(int line)
|
||||
{
|
||||
FontMetrics fm = painter.getFontMetrics();
|
||||
return (line - firstLine) * fm.getHeight()
|
||||
- (fm.getLeading() + fm.getMaxDescent());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a y co-ordinate to a line index.
|
||||
* @param y The y co-ordinate
|
||||
*/
|
||||
public int yToLine(int y)
|
||||
{
|
||||
FontMetrics fm = painter.getFontMetrics();
|
||||
int height = fm.getHeight();
|
||||
return Math.max(0,Math.min(getLineCount() - 1,
|
||||
y / height + firstLine));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an offset in a line into an x co-ordinate. This is a
|
||||
* slow version that can be used any time.
|
||||
* @param line The line
|
||||
* @param offset The offset, from the start of the line
|
||||
*/
|
||||
public final int offsetToX(int line, int offset)
|
||||
{
|
||||
// don't use cached tokens
|
||||
painter.currentLineTokens = null;
|
||||
return _offsetToX(line,offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an offset in a line into an x co-ordinate. This is a
|
||||
* fast version that should only be used if no changes were made
|
||||
* to the text since the last repaint.
|
||||
* @param line The line
|
||||
* @param offset The offset, from the start of the line
|
||||
*/
|
||||
public int _offsetToX(int line, int offset)
|
||||
{
|
||||
TokenMarker tokenMarker = getTokenMarker();
|
||||
|
||||
/* Use painter's cached info for speed */
|
||||
FontMetrics fm = painter.getFontMetrics();
|
||||
|
||||
getLineText(line,lineSegment);
|
||||
|
||||
int segmentOffset = lineSegment.offset;
|
||||
int x = horizontalOffset;
|
||||
|
||||
/* If syntax coloring is disabled, do simple translation */
|
||||
if(tokenMarker == null)
|
||||
{
|
||||
lineSegment.count = offset;
|
||||
return x + Utilities.getTabbedTextWidth(lineSegment,
|
||||
fm,x,painter,0);
|
||||
}
|
||||
/* If syntax coloring is enabled, we have to do this because
|
||||
* tokens can vary in width */
|
||||
else
|
||||
{
|
||||
Token tokens;
|
||||
if(painter.currentLineIndex == line
|
||||
&& painter.currentLineTokens != null)
|
||||
tokens = painter.currentLineTokens;
|
||||
else
|
||||
{
|
||||
painter.currentLineIndex = line;
|
||||
tokens = painter.currentLineTokens
|
||||
= tokenMarker.markTokens(lineSegment,line);
|
||||
}
|
||||
|
||||
//Toolkit toolkit = painter.getToolkit();
|
||||
Font defaultFont = painter.getFont();
|
||||
SyntaxStyle[] styles = painter.getStyles();
|
||||
|
||||
for(;;)
|
||||
{
|
||||
byte id = tokens.id;
|
||||
if(id == Token.END)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
if(id == Token.NULL)
|
||||
fm = painter.getFontMetrics();
|
||||
else
|
||||
fm = styles[id].getFontMetrics(defaultFont, this);
|
||||
|
||||
int length = tokens.length;
|
||||
|
||||
if(offset + segmentOffset < lineSegment.offset + length)
|
||||
{
|
||||
lineSegment.count = offset - (lineSegment.offset - segmentOffset);
|
||||
return x + Utilities.getTabbedTextWidth(
|
||||
lineSegment,fm,x,painter,0);
|
||||
}
|
||||
else
|
||||
{
|
||||
lineSegment.count = length;
|
||||
x += Utilities.getTabbedTextWidth(
|
||||
lineSegment,fm,x,painter,0);
|
||||
lineSegment.offset += length;
|
||||
}
|
||||
tokens = tokens.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an x co-ordinate to an offset within a line.
|
||||
* @param line The line
|
||||
* @param x The x co-ordinate
|
||||
*/
|
||||
public int xToOffset(int line, int x)
|
||||
{
|
||||
TokenMarker tokenMarker = getTokenMarker();
|
||||
|
||||
/* Use painter's cached info for speed */
|
||||
FontMetrics fm = painter.getFontMetrics();
|
||||
|
||||
getLineText(line,lineSegment);
|
||||
|
||||
char[] segmentArray = lineSegment.array;
|
||||
int segmentOffset = lineSegment.offset;
|
||||
int segmentCount = lineSegment.count;
|
||||
|
||||
int width = horizontalOffset;
|
||||
|
||||
if(tokenMarker == null)
|
||||
{
|
||||
for(int i = 0; i < segmentCount; i++)
|
||||
{
|
||||
char c = segmentArray[i + segmentOffset];
|
||||
int charWidth;
|
||||
if(c == '\t')
|
||||
charWidth = (int)painter.nextTabStop(width,i)
|
||||
- width;
|
||||
else
|
||||
charWidth = fm.charWidth(c);
|
||||
|
||||
if(painter.isBlockCaretEnabled())
|
||||
{
|
||||
if(x - charWidth <= width)
|
||||
return i;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(x - charWidth / 2 <= width)
|
||||
return i;
|
||||
}
|
||||
|
||||
width += charWidth;
|
||||
}
|
||||
|
||||
return segmentCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
Token tokens;
|
||||
if(painter.currentLineIndex == line && painter
|
||||
.currentLineTokens != null)
|
||||
tokens = painter.currentLineTokens;
|
||||
else
|
||||
{
|
||||
painter.currentLineIndex = line;
|
||||
tokens = painter.currentLineTokens
|
||||
= tokenMarker.markTokens(lineSegment,line);
|
||||
}
|
||||
|
||||
int offset = 0;
|
||||
//Toolkit toolkit = painter.getToolkit();
|
||||
Font defaultFont = painter.getFont();
|
||||
SyntaxStyle[] styles = painter.getStyles();
|
||||
|
||||
for(;;)
|
||||
{
|
||||
byte id = tokens.id;
|
||||
if(id == Token.END)
|
||||
return offset;
|
||||
|
||||
if(id == Token.NULL)
|
||||
fm = painter.getFontMetrics();
|
||||
else
|
||||
fm = styles[id].getFontMetrics(defaultFont, this);
|
||||
|
||||
int length = tokens.length;
|
||||
|
||||
for(int i = 0; i < length; i++)
|
||||
{
|
||||
char c = segmentArray[segmentOffset + offset + i];
|
||||
int charWidth;
|
||||
if(c == '\t')
|
||||
charWidth = (int)painter.nextTabStop(width,offset + i)
|
||||
- width;
|
||||
else
|
||||
charWidth = fm.charWidth(c);
|
||||
|
||||
if(painter.isBlockCaretEnabled())
|
||||
{
|
||||
if(x - charWidth <= width)
|
||||
return offset + i;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(x - charWidth / 2 <= width)
|
||||
return offset + i;
|
||||
}
|
||||
|
||||
width += charWidth;
|
||||
}
|
||||
|
||||
offset += length;
|
||||
tokens = tokens.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a point to an offset, from the start of the text.
|
||||
* @param x The x co-ordinate of the point
|
||||
* @param y The y co-ordinate of the point
|
||||
*/
|
||||
public int xyToOffset(int x, int y)
|
||||
{
|
||||
int line = yToLine(y);
|
||||
int start = getLineStartOffset(line);
|
||||
return start + xToOffset(line,x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the document this text area is editing.
|
||||
*/
|
||||
public final SyntaxDocument getDocument()
|
||||
{
|
||||
return document;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the document this text area is editing.
|
||||
* @param document The document
|
||||
*/
|
||||
public void setDocument(SyntaxDocument document) {
|
||||
if (this.document == document)
|
||||
return;
|
||||
if (this.document != null)
|
||||
this.document.removeDocumentListener(documentHandler);
|
||||
this.document = document;
|
||||
|
||||
document.addDocumentListener(documentHandler);
|
||||
|
||||
select(0, 0);
|
||||
updateScrollBars();
|
||||
repaintEditor();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set document with a twist, includes the old caret
|
||||
* and scroll positions, added for p5. [fry]
|
||||
*/
|
||||
public void setDocument(SyntaxDocument document,
|
||||
int start, int stop, int scroll) {
|
||||
if (this.document == document)
|
||||
return;
|
||||
if (this.document != null)
|
||||
this.document.removeDocumentListener(documentHandler);
|
||||
this.document = document;
|
||||
|
||||
document.addDocumentListener(documentHandler);
|
||||
|
||||
select(start, stop);
|
||||
updateScrollBars();
|
||||
setScrollPosition(scroll);
|
||||
repaintEditor();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the document's token marker. Equivalent to calling
|
||||
* <code>getDocument().getTokenMarker()</code>.
|
||||
*/
|
||||
public final TokenMarker getTokenMarker()
|
||||
{
|
||||
return document.getTokenMarker();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the document's token marker. Equivalent to caling
|
||||
* <code>getDocument().setTokenMarker()</code>.
|
||||
* @param tokenMarker The token marker
|
||||
*/
|
||||
public final void setTokenMarker(TokenMarker tokenMarker)
|
||||
{
|
||||
document.setTokenMarker(tokenMarker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the document. Equivalent to calling
|
||||
* <code>getDocument().getLength()</code>.
|
||||
*/
|
||||
public final int getDocumentLength()
|
||||
{
|
||||
return document.getLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of lines in the document.
|
||||
*/
|
||||
public final int getLineCount()
|
||||
{
|
||||
if (document != null) {
|
||||
return document.getDefaultRootElement().getElementCount();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the line containing the specified offset.
|
||||
* @param offset The offset
|
||||
*/
|
||||
public final int getLineOfOffset(int offset)
|
||||
{
|
||||
return document.getDefaultRootElement().getElementIndex(offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the start offset of the specified line.
|
||||
* @param line The line
|
||||
* @return The start offset of the specified line, or -1 if the line is
|
||||
* invalid
|
||||
*/
|
||||
public int getLineStartOffset(int line)
|
||||
{
|
||||
Element lineElement = document.getDefaultRootElement()
|
||||
.getElement(line);
|
||||
if(lineElement == null)
|
||||
return -1;
|
||||
else
|
||||
return lineElement.getStartOffset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the end offset of the specified line.
|
||||
* @param line The line
|
||||
* @return The end offset of the specified line, or -1 if the line is
|
||||
* invalid.
|
||||
*/
|
||||
public int getLineStopOffset(int line)
|
||||
{
|
||||
Element lineElement = document.getDefaultRootElement()
|
||||
.getElement(line);
|
||||
if(lineElement == null)
|
||||
return -1;
|
||||
else
|
||||
return lineElement.getEndOffset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the end offset of the specified line, but not past the end of the text
|
||||
* @param line The line
|
||||
* @return The end offset of the specified line, safe to use for a selection, or -1 if the line is
|
||||
* invalid.
|
||||
*/
|
||||
public int getSafeLineStopOffset(int line)
|
||||
{
|
||||
return Math.min(getLineStopOffset(line),getDocumentLength());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the specified line.
|
||||
* @param line The line
|
||||
*/
|
||||
public int getLineLength(int line)
|
||||
{
|
||||
Element lineElement = document.getDefaultRootElement()
|
||||
.getElement(line);
|
||||
if(lineElement == null)
|
||||
return -1;
|
||||
else
|
||||
return lineElement.getEndOffset()
|
||||
- lineElement.getStartOffset() - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entire text of this text area.
|
||||
*/
|
||||
public String getText()
|
||||
{
|
||||
try
|
||||
{
|
||||
return document.getText(0,document.getLength());
|
||||
}
|
||||
catch(BadLocationException bl)
|
||||
{
|
||||
bl.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the entire text of this text area.
|
||||
*/
|
||||
public void setText(String text)
|
||||
{
|
||||
try {
|
||||
document.beginCompoundEdit();
|
||||
document.remove(0,document.getLength());
|
||||
document.insertString(0,text,null);
|
||||
|
||||
} catch (BadLocationException bl) {
|
||||
bl.printStackTrace();
|
||||
|
||||
} finally {
|
||||
document.endCompoundEdit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the specified substring of the document.
|
||||
* @param start The start offset
|
||||
* @param len The length of the substring
|
||||
* @return The substring, or null if the offsets are invalid
|
||||
*/
|
||||
public final String getText(int start, int len)
|
||||
{
|
||||
try
|
||||
{
|
||||
return document.getText(start,len);
|
||||
}
|
||||
catch(BadLocationException bl)
|
||||
{
|
||||
bl.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the specified substring of the document into a segment.
|
||||
* If the offsets are invalid, the segment will contain a null string.
|
||||
* @param start The start offset
|
||||
* @param len The length of the substring
|
||||
* @param segment The segment
|
||||
*/
|
||||
public final void getText(int start, int len, Segment segment)
|
||||
{
|
||||
try
|
||||
{
|
||||
document.getText(start,len,segment);
|
||||
}
|
||||
catch(BadLocationException bl)
|
||||
{
|
||||
bl.printStackTrace();
|
||||
segment.offset = segment.count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the text on the specified line.
|
||||
* @param lineIndex The line
|
||||
* @return The text, or null if the line is invalid
|
||||
*/
|
||||
public final String getLineText(int lineIndex)
|
||||
{
|
||||
int start = getLineStartOffset(lineIndex);
|
||||
return getText(start,getLineStopOffset(lineIndex) - start - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the text on the specified line into a segment. If the line
|
||||
* is invalid, the segment will contain a null string.
|
||||
* @param lineIndex The line
|
||||
*/
|
||||
public final void getLineText(int lineIndex, Segment segment)
|
||||
{
|
||||
int start = getLineStartOffset(lineIndex);
|
||||
getText(start,getLineStopOffset(lineIndex) - start - 1,segment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the selection start offset.
|
||||
*/
|
||||
public final int getSelectionStart()
|
||||
{
|
||||
return selectionStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offset where the selection starts on the specified
|
||||
* line.
|
||||
*/
|
||||
public int getSelectionStart(int line)
|
||||
{
|
||||
if(line == selectionStartLine)
|
||||
return selectionStart;
|
||||
else if(rectSelect)
|
||||
{
|
||||
Element map = document.getDefaultRootElement();
|
||||
int start = selectionStart - map.getElement(selectionStartLine)
|
||||
.getStartOffset();
|
||||
|
||||
Element lineElement = map.getElement(line);
|
||||
int lineStart = lineElement.getStartOffset();
|
||||
int lineEnd = lineElement.getEndOffset() - 1;
|
||||
return Math.min(lineEnd,lineStart + start);
|
||||
}
|
||||
else
|
||||
return getLineStartOffset(line);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the selection start line.
|
||||
*/
|
||||
public final int getSelectionStartLine()
|
||||
{
|
||||
return selectionStartLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the selection start. The new selection will be the new
|
||||
* selection start and the old selection end.
|
||||
* @param selectionStart The selection start
|
||||
* @see #select(int,int)
|
||||
*/
|
||||
public final void setSelectionStart(int selectionStart)
|
||||
{
|
||||
select(selectionStart,selectionEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the selection end offset.
|
||||
*/
|
||||
public final int getSelectionStop()
|
||||
{
|
||||
return selectionEnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offset where the selection ends on the specified
|
||||
* line.
|
||||
*/
|
||||
public int getSelectionStop(int line)
|
||||
{
|
||||
if(line == selectionEndLine)
|
||||
return selectionEnd;
|
||||
else if(rectSelect)
|
||||
{
|
||||
Element map = document.getDefaultRootElement();
|
||||
int end = selectionEnd - map.getElement(selectionEndLine)
|
||||
.getStartOffset();
|
||||
|
||||
Element lineElement = map.getElement(line);
|
||||
int lineStart = lineElement.getStartOffset();
|
||||
int lineEnd = lineElement.getEndOffset() - 1;
|
||||
return Math.min(lineEnd,lineStart + end);
|
||||
}
|
||||
else
|
||||
return getLineStopOffset(line) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the selection end line.
|
||||
*/
|
||||
public final int getSelectionStopLine()
|
||||
{
|
||||
return selectionEndLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the selection end. The new selection will be the old
|
||||
* selection start and the bew selection end.
|
||||
* @param selectionEnd The selection end
|
||||
* @see #select(int,int)
|
||||
*/
|
||||
public final void setSelectionEnd(int selectionEnd)
|
||||
{
|
||||
select(selectionStart,selectionEnd);
|
||||
}
|
||||
|
||||
|
||||
public final boolean isSelectionActive()
|
||||
{
|
||||
return(selectionStart != selectionEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the caret position. This will either be the selection
|
||||
* start or the selection end, depending on which direction the
|
||||
* selection was made in.
|
||||
*/
|
||||
public final int getCaretPosition()
|
||||
{
|
||||
return (biasLeft ? selectionStart : selectionEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the caret line.
|
||||
*/
|
||||
public final int getCaretLine()
|
||||
{
|
||||
return (biasLeft ? selectionStartLine : selectionEndLine);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mark position. This will be the opposite selection
|
||||
* bound to the caret position.
|
||||
* @see #getCaretPosition()
|
||||
*/
|
||||
public final int getMarkPosition()
|
||||
{
|
||||
return (biasLeft ? selectionEnd : selectionStart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mark line.
|
||||
*/
|
||||
public final int getMarkLine()
|
||||
{
|
||||
return (biasLeft ? selectionEndLine : selectionStartLine);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the caret position. The new selection will consist of the
|
||||
* caret position only (hence no text will be selected)
|
||||
* @param caret The caret position
|
||||
* @see #select(int,int)
|
||||
*/
|
||||
public final void setCaretPosition(int caret)
|
||||
{
|
||||
select(caret,caret);
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects all text in the document.
|
||||
*/
|
||||
public final void selectAll()
|
||||
{
|
||||
select(0,getDocumentLength());
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the mark to the caret position.
|
||||
*/
|
||||
public final void selectNone()
|
||||
{
|
||||
select(getCaretPosition(),getCaretPosition());
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects from the start offset to the end offset. This is the
|
||||
* general selection method used by all other selecting methods.
|
||||
* The caret position will be start if start < end, and end
|
||||
* if end > start.
|
||||
* @param start The start offset
|
||||
* @param end The end offset
|
||||
*/
|
||||
public void select(int start, int end)
|
||||
{
|
||||
int newStart, newEnd;
|
||||
boolean newBias;
|
||||
if(start <= end)
|
||||
{
|
||||
newStart = start;
|
||||
newEnd = end;
|
||||
newBias = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
newStart = end;
|
||||
newEnd = start;
|
||||
newBias = true;
|
||||
}
|
||||
|
||||
if (newEnd > getDocumentLength()) {
|
||||
newEnd = getDocumentLength();
|
||||
}
|
||||
|
||||
if(newStart < 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Bounds out of"
|
||||
+ " range: " + newStart + "," +
|
||||
newEnd + " [" + getDocumentLength() + "]");
|
||||
}
|
||||
|
||||
// If the new position is the same as the old, we don't
|
||||
// do all this crap, however we still do the stuff at
|
||||
// the end (clearing magic position, scrolling)
|
||||
if(newStart != selectionStart || newEnd != selectionEnd
|
||||
|| newBias != biasLeft)
|
||||
{
|
||||
int newStartLine = getLineOfOffset(newStart);
|
||||
int newEndLine = getLineOfOffset(newEnd);
|
||||
|
||||
if(painter.isBracketHighlightEnabled())
|
||||
{
|
||||
if(bracketLine != -1)
|
||||
painter.invalidateLine(bracketLine);
|
||||
updateBracketHighlight(end);
|
||||
if(bracketLine != -1)
|
||||
painter.invalidateLine(bracketLine);
|
||||
}
|
||||
|
||||
painter.invalidateLineRange(selectionStartLine,selectionEndLine);
|
||||
painter.invalidateLineRange(newStartLine,newEndLine);
|
||||
|
||||
document.addUndoableEdit(new CaretUndo(selectionStart,selectionEnd));
|
||||
|
||||
selectionStart = newStart;
|
||||
selectionEnd = newEnd;
|
||||
selectionStartLine = newStartLine;
|
||||
selectionEndLine = newEndLine;
|
||||
biasLeft = newBias;
|
||||
|
||||
if (newStart != newEnd) {
|
||||
Clipboard unixclipboard = getToolkit().getSystemSelection();
|
||||
if (unixclipboard != null) {
|
||||
String selection = getSelectedText();
|
||||
if (selection != null) {
|
||||
unixclipboard.setContents(new StringSelection(selection), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fireCaretEvent();
|
||||
}
|
||||
|
||||
// When the user is typing, etc, we don't want the caret
|
||||
// to blink
|
||||
blink = true;
|
||||
caretTimer.restart();
|
||||
|
||||
// Disable rectangle select if selection start = selection end
|
||||
if(selectionStart == selectionEnd)
|
||||
rectSelect = false;
|
||||
|
||||
// Clear the `magic' caret position used by up/down
|
||||
magicCaret = -1;
|
||||
|
||||
scrollToCaret();
|
||||
|
||||
// notify the line number feller
|
||||
if (editorLineStatus != null) {
|
||||
editorLineStatus.set(selectionStartLine, selectionEndLine);
|
||||
//System.out.println("why " + selectionStartLine + " " + selectionEndLine);
|
||||
//System.out.println(getLineOfOffset(start) + " " +
|
||||
// getLineOfOffset(end));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isWordCharacter( char ch, String noWordSep )
|
||||
{
|
||||
return Character.isLetterOrDigit(ch) || ch=='_' || noWordSep.indexOf(ch) != -1;
|
||||
}
|
||||
|
||||
protected void setNewSelectionWord( int line, int offset )
|
||||
{
|
||||
if (getLineLength(line) == 0) {
|
||||
newSelectionStart = getLineStartOffset(line);
|
||||
newSelectionEnd = newSelectionStart;
|
||||
return;
|
||||
}
|
||||
|
||||
String noWordSep = (String)document.getProperty("noWordSep");
|
||||
if(noWordSep == null)
|
||||
noWordSep = "";
|
||||
|
||||
String lineText = getLineText(line);
|
||||
|
||||
int wordStart = 0;
|
||||
int wordEnd = lineText.length();
|
||||
|
||||
char ch = lineText.charAt(Math.max(0,offset - 1));
|
||||
|
||||
// special case for whitespace (fry 0122, bug #348)
|
||||
// this is really nasty.. turns out that double-clicking any non-letter
|
||||
// or digit char gets lumped together.. sooo, this quickly gets messy,
|
||||
// because really it needs to check whether the chars are of the same
|
||||
// type.. so a double space or double - might be grouped together,
|
||||
// but what about a +=1? do + and - get grouped but not the 1? blech,
|
||||
// coming back to this later. it's not a difficult fix, just a
|
||||
// time-consuming one to track down all the proper cases.
|
||||
/*
|
||||
if (ch == ' ') {
|
||||
//System.out.println("yeehaa");
|
||||
|
||||
for(int i = offset - 1; i >= 0; i--) {
|
||||
if (lineText.charAt(i) == ' ') {
|
||||
wordStart = i;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for(int i = offset; i < lineText.length(); i++) {
|
||||
if (lineText.charAt(i) == ' ') {
|
||||
wordEnd = i + 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
*/
|
||||
|
||||
// If the user clicked on a non-letter char,
|
||||
// we select the surrounding non-letters
|
||||
boolean selectNoLetter = !isWordCharacter(ch,noWordSep);
|
||||
|
||||
for(int i = offset - 1; i >= 0; i--) {
|
||||
ch = lineText.charAt(i);
|
||||
if (selectNoLetter ^ !isWordCharacter(ch,noWordSep)) {
|
||||
wordStart = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = offset; i < lineText.length(); i++) {
|
||||
ch = lineText.charAt(i);
|
||||
if(selectNoLetter ^ !isWordCharacter(ch,noWordSep)) {
|
||||
wordEnd = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//}
|
||||
int lineStart = getLineStartOffset(line);
|
||||
|
||||
newSelectionStart = lineStart + wordStart;
|
||||
newSelectionEnd = lineStart + wordEnd;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the selected text, or null if no selection is active.
|
||||
*/
|
||||
public final String getSelectedText()
|
||||
{
|
||||
if(selectionStart == selectionEnd)
|
||||
return null;
|
||||
|
||||
if(rectSelect)
|
||||
{
|
||||
// Return each row of the selection on a new line
|
||||
|
||||
Element map = document.getDefaultRootElement();
|
||||
|
||||
int start = selectionStart - map.getElement(selectionStartLine)
|
||||
.getStartOffset();
|
||||
int end = selectionEnd - map.getElement(selectionEndLine)
|
||||
.getStartOffset();
|
||||
|
||||
// Certain rectangles satisfy this condition...
|
||||
if(end < start)
|
||||
{
|
||||
int tmp = end;
|
||||
end = start;
|
||||
start = tmp;
|
||||
}
|
||||
|
||||
StringBuffer buf = new StringBuffer();
|
||||
Segment seg = new Segment();
|
||||
|
||||
for(int i = selectionStartLine; i <= selectionEndLine; i++)
|
||||
{
|
||||
Element lineElement = map.getElement(i);
|
||||
int lineStart = lineElement.getStartOffset();
|
||||
int lineEnd = lineElement.getEndOffset() - 1;
|
||||
int lineLen = lineEnd - lineStart;
|
||||
|
||||
lineStart = Math.min(lineStart + start,lineEnd);
|
||||
lineLen = Math.min(end - start,lineEnd - lineStart);
|
||||
|
||||
getText(lineStart,lineLen,seg);
|
||||
buf.append(seg.array,seg.offset,seg.count);
|
||||
|
||||
if(i != selectionEndLine)
|
||||
buf.append('\n');
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
return getText(selectionStart,
|
||||
selectionEnd - selectionStart);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the selection with the specified text.
|
||||
* @param selectedText The replacement text for the selection
|
||||
*/
|
||||
public void setSelectedText(String selectedText)
|
||||
{
|
||||
if(!editable)
|
||||
{
|
||||
throw new InternalError("Text component"
|
||||
+ " read only");
|
||||
}
|
||||
|
||||
document.beginCompoundEdit();
|
||||
|
||||
try
|
||||
{
|
||||
if(rectSelect)
|
||||
{
|
||||
Element map = document.getDefaultRootElement();
|
||||
|
||||
int start = selectionStart - map.getElement(selectionStartLine)
|
||||
.getStartOffset();
|
||||
int end = selectionEnd - map.getElement(selectionEndLine)
|
||||
.getStartOffset();
|
||||
|
||||
// Certain rectangles satisfy this condition...
|
||||
if(end < start)
|
||||
{
|
||||
int tmp = end;
|
||||
end = start;
|
||||
start = tmp;
|
||||
}
|
||||
|
||||
int lastNewline = 0;
|
||||
int currNewline = 0;
|
||||
|
||||
for(int i = selectionStartLine; i <= selectionEndLine; i++)
|
||||
{
|
||||
Element lineElement = map.getElement(i);
|
||||
int lineStart = lineElement.getStartOffset();
|
||||
int lineEnd = lineElement.getEndOffset() - 1;
|
||||
int rectStart = Math.min(lineEnd,lineStart + start);
|
||||
|
||||
document.remove(rectStart,Math.min(lineEnd - rectStart,
|
||||
end - start));
|
||||
|
||||
if(selectedText == null)
|
||||
continue;
|
||||
|
||||
currNewline = selectedText.indexOf('\n',lastNewline);
|
||||
if(currNewline == -1)
|
||||
currNewline = selectedText.length();
|
||||
|
||||
document.insertString(rectStart,selectedText
|
||||
.substring(lastNewline,currNewline),null);
|
||||
|
||||
lastNewline = Math.min(selectedText.length(),
|
||||
currNewline + 1);
|
||||
}
|
||||
|
||||
if(selectedText != null &&
|
||||
currNewline != selectedText.length())
|
||||
{
|
||||
int offset = map.getElement(selectionEndLine)
|
||||
.getEndOffset() - 1;
|
||||
document.insertString(offset,"\n",null);
|
||||
document.insertString(offset + 1,selectedText
|
||||
.substring(currNewline + 1),null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
document.remove(selectionStart,
|
||||
selectionEnd - selectionStart);
|
||||
if(selectedText != null)
|
||||
{
|
||||
document.insertString(selectionStart,
|
||||
selectedText,null);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(BadLocationException bl)
|
||||
{
|
||||
bl.printStackTrace();
|
||||
throw new InternalError("Cannot replace"
|
||||
+ " selection");
|
||||
}
|
||||
// No matter what happends... stops us from leaving document
|
||||
// in a bad state
|
||||
finally
|
||||
{
|
||||
document.endCompoundEdit();
|
||||
}
|
||||
|
||||
setCaretPosition(selectionEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this text area is editable, false otherwise.
|
||||
*/
|
||||
public final boolean isEditable()
|
||||
{
|
||||
return editable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if this component is editable.
|
||||
* @param editable True if this text area should be editable,
|
||||
* false otherwise
|
||||
*/
|
||||
public final void setEditable(boolean editable)
|
||||
{
|
||||
this.editable = editable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the right click popup menu.
|
||||
*/
|
||||
public final JPopupMenu getRightClickPopup()
|
||||
{
|
||||
return popup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the right click popup menu.
|
||||
* @param popup The popup
|
||||
*/
|
||||
//public final void setRightClickPopup(EditPopupMenu popup)
|
||||
public final void setRightClickPopup(JPopupMenu popup)
|
||||
{
|
||||
this.popup = popup;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the `magic' caret position. This can be used to preserve
|
||||
* the column position when moving up and down lines.
|
||||
*/
|
||||
public final int getMagicCaretPosition()
|
||||
{
|
||||
return magicCaret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the `magic' caret position. This can be used to preserve
|
||||
* the column position when moving up and down lines.
|
||||
* @param magicCaret The magic caret position
|
||||
*/
|
||||
public final void setMagicCaretPosition(int magicCaret)
|
||||
{
|
||||
this.magicCaret = magicCaret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to <code>setSelectedText()</code>, but overstrikes the
|
||||
* appropriate number of characters if overwrite mode is enabled.
|
||||
* @param str The string
|
||||
* @see #setSelectedText(String)
|
||||
* @see #isOverwriteEnabled()
|
||||
*/
|
||||
public void overwriteSetSelectedText(String str)
|
||||
{
|
||||
// Don't overstrike if there is a selection
|
||||
if(!overwrite || selectionStart != selectionEnd)
|
||||
{
|
||||
setSelectedText(str);
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't overstrike if we're on the end of
|
||||
// the line
|
||||
int caret = getCaretPosition();
|
||||
int caretLineEnd = getLineStopOffset(getCaretLine());
|
||||
if(caretLineEnd - caret <= str.length())
|
||||
{
|
||||
setSelectedText(str);
|
||||
return;
|
||||
}
|
||||
|
||||
document.beginCompoundEdit();
|
||||
|
||||
try
|
||||
{
|
||||
document.remove(caret,str.length());
|
||||
document.insertString(caret,str,null);
|
||||
}
|
||||
catch(BadLocationException bl)
|
||||
{
|
||||
bl.printStackTrace();
|
||||
}
|
||||
finally
|
||||
{
|
||||
document.endCompoundEdit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if overwrite mode is enabled, false otherwise.
|
||||
*/
|
||||
public final boolean isOverwriteEnabled()
|
||||
{
|
||||
return overwrite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if overwrite mode should be enabled.
|
||||
* @param overwrite True if overwrite mode should be enabled,
|
||||
* false otherwise.
|
||||
*/
|
||||
public final void setOverwriteEnabled(boolean overwrite)
|
||||
{
|
||||
this.overwrite = overwrite;
|
||||
painter.invalidateSelectedLines();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the selection is rectangular, false otherwise.
|
||||
*/
|
||||
public final boolean isSelectionRectangular()
|
||||
{
|
||||
return rectSelect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if the selection should be rectangular.
|
||||
* @param rectSelect True if the selection should be rectangular,
|
||||
* false otherwise.
|
||||
*/
|
||||
public final void setSelectionRectangular(boolean rectSelect)
|
||||
{
|
||||
this.rectSelect = rectSelect;
|
||||
painter.invalidateSelectedLines();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the position of the highlighted bracket (the bracket
|
||||
* matching the one before the caret)
|
||||
*/
|
||||
public final int getBracketPosition()
|
||||
{
|
||||
return bracketPosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the line of the highlighted bracket (the bracket
|
||||
* matching the one before the caret)
|
||||
*/
|
||||
public final int getBracketLine()
|
||||
{
|
||||
return bracketLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a caret change listener to this text area.
|
||||
* @param listener The listener
|
||||
*/
|
||||
public final void addCaretListener(CaretListener listener)
|
||||
{
|
||||
eventListenerList.add(CaretListener.class,listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a caret change listener from this text area.
|
||||
* @param listener The listener
|
||||
*/
|
||||
public final void removeCaretListener(CaretListener listener)
|
||||
{
|
||||
eventListenerList.remove(CaretListener.class,listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the selected text from the text area and places it
|
||||
* into the clipboard.
|
||||
*/
|
||||
public void cut()
|
||||
{
|
||||
if(editable)
|
||||
{
|
||||
copy();
|
||||
setSelectedText("");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Places the selected text into the clipboard.
|
||||
*/
|
||||
public void copy()
|
||||
{
|
||||
if(selectionStart != selectionEnd)
|
||||
{
|
||||
Clipboard clipboard = getToolkit().getSystemClipboard();
|
||||
|
||||
String selection = getSelectedText();
|
||||
|
||||
int repeatCount = inputHandler.getRepeatCount();
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for(int i = 0; i < repeatCount; i++)
|
||||
buf.append(selection);
|
||||
|
||||
Transferable t = new StringSelection(buf.toString());
|
||||
clipboard.setContents(t, null);
|
||||
|
||||
Clipboard unixclipboard = getToolkit().getSystemSelection();
|
||||
if (unixclipboard != null) unixclipboard.setContents(t, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the clipboard contents into the text.
|
||||
*/
|
||||
public void paste() {
|
||||
if (editable) {
|
||||
Clipboard clipboard = getToolkit().getSystemClipboard();
|
||||
try {
|
||||
// The MacOS MRJ doesn't convert \r to \n, so do it here
|
||||
String selection = ((String)clipboard.getContents(this).getTransferData(DataFlavor.stringFlavor)).replace('\r','\n');
|
||||
|
||||
// particularly on macosx when pasting from safari,
|
||||
// replace unicode x00A0 (non-breaking space)
|
||||
// with just a plain space. [fry 030929]
|
||||
selection = selection.replace('\u00A0', ' ');
|
||||
|
||||
int repeatCount = inputHandler.getRepeatCount();
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (int i = 0; i < repeatCount; i++)
|
||||
buf.append(selection);
|
||||
selection = buf.toString();
|
||||
setSelectedText(selection);
|
||||
|
||||
} catch(Exception e) {
|
||||
getToolkit().beep();
|
||||
System.err.println("Clipboard does not contain a string");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the AWT when this component is removed from it's parent.
|
||||
* This stops clears the currently focused component.
|
||||
*/
|
||||
public void removeNotify()
|
||||
{
|
||||
super.removeNotify();
|
||||
if(focusedComponent == this)
|
||||
focusedComponent = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards key events directly to the input handler.
|
||||
* This is slightly faster than using a KeyListener
|
||||
* because some Swing overhead is avoided.
|
||||
*/
|
||||
public EditorListener editorListener;
|
||||
|
||||
/**
|
||||
* The component that tracks the current line number.
|
||||
*/
|
||||
public EditorLineStatus editorLineStatus;
|
||||
|
||||
|
||||
public void processKeyEvent(KeyEvent evt) {
|
||||
// this had to be added in Processing 007X, because the menu key
|
||||
// events weren't making it up to the frame.
|
||||
super.processKeyEvent(evt);
|
||||
|
||||
//System.out.println("jedittextarea: " + evt);
|
||||
//System.out.println();
|
||||
if (inputHandler == null) return;
|
||||
|
||||
switch(evt.getID()) {
|
||||
case KeyEvent.KEY_TYPED:
|
||||
if ((editorListener == null) || !editorListener.keyTyped(evt)) {
|
||||
inputHandler.keyTyped(evt);
|
||||
}
|
||||
break;
|
||||
case KeyEvent.KEY_PRESSED:
|
||||
if ((editorListener == null) || !editorListener.keyPressed(evt)) {
|
||||
inputHandler.keyPressed(evt);
|
||||
}
|
||||
break;
|
||||
case KeyEvent.KEY_RELEASED:
|
||||
inputHandler.keyReleased(evt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// protected members
|
||||
protected static String LEFT = "left";
|
||||
protected static String CENTER = "center";
|
||||
protected static String RIGHT = "right";
|
||||
protected static String BOTTOM = "bottom";
|
||||
|
||||
protected static JEditTextArea focusedComponent;
|
||||
protected static Timer caretTimer;
|
||||
|
||||
protected TextAreaPainter painter;
|
||||
protected TextAreaLineNumbers editorLineNumbers;
|
||||
|
||||
//protected EditPopupMenu popup;
|
||||
protected JPopupMenu popup;
|
||||
|
||||
protected EventListenerList eventListenerList;
|
||||
protected MutableCaretEvent caretEvent;
|
||||
|
||||
protected boolean caretBlinks;
|
||||
protected boolean caretVisible;
|
||||
protected boolean blink;
|
||||
|
||||
protected boolean editable;
|
||||
|
||||
protected int firstLine;
|
||||
protected int visibleLines;
|
||||
protected int electricScroll;
|
||||
|
||||
protected int horizontalOffset;
|
||||
|
||||
protected JScrollBar vertical;
|
||||
protected JScrollBar horizontal;
|
||||
protected boolean scrollBarsInitialized;
|
||||
|
||||
protected InputHandler inputHandler;
|
||||
protected SyntaxDocument document;
|
||||
protected DocumentHandler documentHandler;
|
||||
|
||||
protected Segment lineSegment;
|
||||
|
||||
protected int selectionStart;
|
||||
protected int selectionStartLine;
|
||||
protected int selectionEnd;
|
||||
protected int selectionEndLine;
|
||||
protected boolean biasLeft;
|
||||
|
||||
protected int newSelectionStart; // hack to get around lack of multiple returns in Java
|
||||
protected int newSelectionEnd;
|
||||
|
||||
protected boolean selectWord;
|
||||
protected boolean selectLine;
|
||||
protected int selectionAncorStart;
|
||||
protected int selectionAncorEnd;
|
||||
|
||||
protected int bracketPosition;
|
||||
protected int bracketLine;
|
||||
|
||||
protected int magicCaret;
|
||||
protected boolean overwrite;
|
||||
protected boolean rectSelect;
|
||||
|
||||
|
||||
protected void fireCaretEvent()
|
||||
{
|
||||
Object[] listeners = eventListenerList.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;
|
||||
|
||||
int line = getLineOfOffset(evt.getOffset());
|
||||
if(count == 0)
|
||||
{
|
||||
painter.invalidateLine(line);
|
||||
}
|
||||
// do magic stuff
|
||||
else if(line < firstLine)
|
||||
{
|
||||
setFirstLine(firstLine + count);
|
||||
}
|
||||
// end of magic stuff
|
||||
else
|
||||
{
|
||||
painter.invalidateLineRange(line,firstLine + visibleLines);
|
||||
updateScrollBars();
|
||||
}
|
||||
}
|
||||
|
||||
class ScrollLayout implements LayoutManager
|
||||
{
|
||||
//final int LEFT_EXTRA = 5;
|
||||
|
||||
public void addLayoutComponent(String name, Component comp)
|
||||
{
|
||||
if(name.equals(LEFT))
|
||||
left = comp;
|
||||
else if(name.equals(CENTER))
|
||||
center = comp;
|
||||
else if(name.equals(RIGHT))
|
||||
right = comp;
|
||||
else if(name.equals(BOTTOM))
|
||||
bottom = comp;
|
||||
else if(name.equals(LEFT_OF_SCROLLBAR))
|
||||
leftOfScrollBar.addElement(comp);
|
||||
}
|
||||
|
||||
public void removeLayoutComponent(Component comp)
|
||||
{
|
||||
if(left == comp)
|
||||
left = null;
|
||||
if(center == comp)
|
||||
center = null;
|
||||
if(right == comp)
|
||||
right = null;
|
||||
if(bottom == comp)
|
||||
bottom = null;
|
||||
else
|
||||
leftOfScrollBar.removeElement(comp);
|
||||
}
|
||||
|
||||
public Dimension preferredLayoutSize(Container parent)
|
||||
{
|
||||
Dimension dim = new Dimension();
|
||||
Insets insets = getInsets();
|
||||
dim.width = insets.left + insets.right;
|
||||
dim.height = insets.top + insets.bottom;
|
||||
|
||||
Dimension centerPref = center.getPreferredSize();
|
||||
dim.width += centerPref.width;
|
||||
dim.height += centerPref.height;
|
||||
Dimension leftPref = left.getPreferredSize();
|
||||
dim.width += leftPref.width;
|
||||
Dimension rightPref = right.getPreferredSize();
|
||||
dim.width += rightPref.width;
|
||||
Dimension bottomPref = bottom.getPreferredSize();
|
||||
dim.height += bottomPref.height;
|
||||
|
||||
return dim;
|
||||
}
|
||||
|
||||
public Dimension minimumLayoutSize(Container parent)
|
||||
{
|
||||
Dimension dim = new Dimension();
|
||||
Insets insets = getInsets();
|
||||
dim.width = insets.left + insets.right;
|
||||
dim.height = insets.top + insets.bottom;
|
||||
|
||||
Dimension centerPref = center.getMinimumSize();
|
||||
dim.width += centerPref.width;
|
||||
dim.height += centerPref.height;
|
||||
Dimension leftPref = left.getMinimumSize();
|
||||
dim.width += leftPref.width;
|
||||
Dimension rightPref = right.getMinimumSize();
|
||||
dim.width += rightPref.width;
|
||||
Dimension bottomPref = bottom.getMinimumSize();
|
||||
dim.height += bottomPref.height;
|
||||
|
||||
dim.height += 5;
|
||||
|
||||
return dim;
|
||||
}
|
||||
|
||||
public void layoutContainer(Container parent)
|
||||
{
|
||||
Dimension size = parent.getSize();
|
||||
Insets insets = parent.getInsets();
|
||||
int itop = insets.top;
|
||||
int ileft = insets.left;
|
||||
int ibottom = insets.bottom;
|
||||
int iright = insets.right;
|
||||
|
||||
int leftWidth = left.getSize().width;
|
||||
int rightWidth = right.getPreferredSize().width;
|
||||
int bottomHeight = bottom.getPreferredSize().height;
|
||||
int centerWidth = size.width - leftWidth - rightWidth - ileft - iright;
|
||||
int centerHeight = size.height - bottomHeight - itop - ibottom;
|
||||
|
||||
left.setBounds(ileft,
|
||||
itop,
|
||||
leftWidth,
|
||||
centerHeight);
|
||||
|
||||
ileft += leftWidth;
|
||||
|
||||
center.setBounds(ileft, // + LEFT_EXTRA,
|
||||
itop,
|
||||
centerWidth, // - LEFT_EXTRA,
|
||||
centerHeight);
|
||||
|
||||
right.setBounds(ileft + centerWidth,
|
||||
itop,
|
||||
rightWidth,
|
||||
centerHeight);
|
||||
|
||||
// Lay out all status components, in order
|
||||
Enumeration status = leftOfScrollBar.elements();
|
||||
while (status.hasMoreElements()) {
|
||||
Component comp = (Component)status.nextElement();
|
||||
Dimension dim = comp.getPreferredSize();
|
||||
comp.setBounds(ileft,
|
||||
itop + centerHeight,
|
||||
dim.width,
|
||||
bottomHeight);
|
||||
ileft += dim.width;
|
||||
}
|
||||
|
||||
bottom.setBounds(ileft,
|
||||
itop + centerHeight,
|
||||
size.width - rightWidth - ileft - iright,
|
||||
bottomHeight);
|
||||
}
|
||||
|
||||
// private members
|
||||
private Component left;
|
||||
private Component center;
|
||||
private Component right;
|
||||
private Component bottom;
|
||||
private Vector leftOfScrollBar = new Vector();
|
||||
}
|
||||
|
||||
static class CaretBlinker implements ActionListener
|
||||
{
|
||||
public void actionPerformed(ActionEvent evt)
|
||||
{
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if(focusedComponent != null
|
||||
&& focusedComponent.hasFocus())
|
||||
focusedComponent.blinkCaret();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class MutableCaretEvent extends CaretEvent
|
||||
{
|
||||
MutableCaretEvent()
|
||||
{
|
||||
super(JEditTextArea.this);
|
||||
}
|
||||
|
||||
public int getDot()
|
||||
{
|
||||
return getCaretPosition();
|
||||
}
|
||||
|
||||
public int getMark()
|
||||
{
|
||||
return getMarkPosition();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#ifdef JDK14
|
||||
class WheelHandler implements MouseWheelListener {
|
||||
|
||||
public void mouseWheelMoved(MouseWheelEvent e) {
|
||||
if (!scrollBarsInitialized) return;
|
||||
|
||||
int amt = e.getWheelRotation();
|
||||
//System.out.println(amt);
|
||||
vertical.setValue(vertical.getValue() + amt * wheelMultiplier);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
|
||||
class AdjustHandler implements AdjustmentListener
|
||||
{
|
||||
public void adjustmentValueChanged(final AdjustmentEvent evt)
|
||||
{
|
||||
if(!scrollBarsInitialized)
|
||||
return;
|
||||
|
||||
// If this is not done, mousePressed events accumilate
|
||||
// and the result is that scrolling doesn't stop after
|
||||
// the mouse is released
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run()
|
||||
{
|
||||
if(evt.getAdjustable() == vertical)
|
||||
setFirstLine(vertical.getValue());
|
||||
else
|
||||
setHorizontalOffset(-horizontal.getValue());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class ComponentHandler extends ComponentAdapter
|
||||
{
|
||||
public void componentResized(ComponentEvent evt)
|
||||
{
|
||||
recalculateVisibleLines();
|
||||
scrollBarsInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
class DocumentHandler implements DocumentListener
|
||||
{
|
||||
public void insertUpdate(DocumentEvent evt)
|
||||
{
|
||||
documentChanged(evt);
|
||||
|
||||
int offset = evt.getOffset();
|
||||
int length = evt.getLength();
|
||||
|
||||
int newStart;
|
||||
int newEnd;
|
||||
|
||||
if (selectionStart > offset ||
|
||||
(selectionStart == selectionEnd && selectionStart == offset))
|
||||
newStart = selectionStart + length;
|
||||
else
|
||||
newStart = selectionStart;
|
||||
|
||||
if(selectionEnd >= offset)
|
||||
newEnd = selectionEnd + length;
|
||||
else
|
||||
newEnd = selectionEnd;
|
||||
|
||||
select(newStart,newEnd);
|
||||
}
|
||||
|
||||
public void removeUpdate(DocumentEvent evt)
|
||||
{
|
||||
documentChanged(evt);
|
||||
|
||||
int offset = evt.getOffset();
|
||||
int length = evt.getLength();
|
||||
|
||||
int newStart;
|
||||
int newEnd;
|
||||
|
||||
if(selectionStart > offset)
|
||||
{
|
||||
if(selectionStart > offset + length)
|
||||
newStart = selectionStart - length;
|
||||
else
|
||||
newStart = offset;
|
||||
}
|
||||
else
|
||||
newStart = selectionStart;
|
||||
|
||||
if(selectionEnd > offset)
|
||||
{
|
||||
if(selectionEnd > offset + length)
|
||||
newEnd = selectionEnd - length;
|
||||
else
|
||||
newEnd = offset;
|
||||
}
|
||||
else
|
||||
newEnd = selectionEnd;
|
||||
|
||||
select(newStart,newEnd);
|
||||
}
|
||||
|
||||
public void changedUpdate(DocumentEvent evt)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
class DragHandler implements MouseMotionListener
|
||||
{
|
||||
public void mouseDragged(MouseEvent evt)
|
||||
{
|
||||
if (popup != null && popup.isVisible()) return;
|
||||
|
||||
if ( !selectWord && !selectLine ) {
|
||||
setSelectionRectangular((evt.getModifiers()
|
||||
& InputEvent.CTRL_MASK) != 0);
|
||||
select(getMarkPosition(),xyToOffset(evt.getX(),evt.getY()));
|
||||
} else {
|
||||
int line = yToLine(evt.getY());
|
||||
if ( selectWord ) {
|
||||
setNewSelectionWord( line, xToOffset(line,evt.getX()) );
|
||||
} else {
|
||||
newSelectionStart = getLineStartOffset(line);
|
||||
newSelectionEnd = getSafeLineStopOffset(line);
|
||||
}
|
||||
if ( newSelectionStart < selectionAncorStart ) {
|
||||
select(newSelectionStart,selectionAncorEnd);
|
||||
} else if ( newSelectionEnd > selectionAncorEnd ) {
|
||||
select(selectionAncorStart,newSelectionEnd);
|
||||
} else {
|
||||
select(newSelectionStart,newSelectionEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final Cursor normalCursor = new Cursor(Cursor.DEFAULT_CURSOR);
|
||||
final Cursor handCursor = new Cursor(Cursor.HAND_CURSOR);
|
||||
|
||||
public void mouseMoved(MouseEvent evt) {
|
||||
int line = yToLine(evt.getY());
|
||||
int offset = xToOffset(line, evt.getX());
|
||||
boolean wantHandCursor = checkClickedURL(getLineText(line), offset) != null;
|
||||
JComponent src = (JComponent) evt.getSource();
|
||||
if (wantHandCursor)
|
||||
src.setCursor(handCursor);
|
||||
else
|
||||
src.setCursor(normalCursor);
|
||||
}
|
||||
}
|
||||
|
||||
class FocusHandler implements FocusListener
|
||||
{
|
||||
public void focusGained(FocusEvent evt)
|
||||
{
|
||||
//System.out.println("JEditTextArea: focusGained");
|
||||
setCaretVisible(true);
|
||||
focusedComponent = JEditTextArea.this;
|
||||
}
|
||||
|
||||
public void focusLost(FocusEvent evt)
|
||||
{
|
||||
//System.out.println("JEditTextArea: focusLost");
|
||||
setCaretVisible(false);
|
||||
focusedComponent = null;
|
||||
}
|
||||
}
|
||||
|
||||
public String checkClickedURL(String line, int offset) {
|
||||
String[] parse = SyntaxUtilities.parseCommentUrls(line);
|
||||
if (parse==null)
|
||||
return null;
|
||||
int start = parse[0].length();
|
||||
int stop = start + parse[1].length();
|
||||
if (offset<start|| offset>stop)
|
||||
return null;
|
||||
return parse[1];
|
||||
}
|
||||
|
||||
class MouseHandler extends MouseAdapter
|
||||
{
|
||||
public void mousePressed(MouseEvent evt)
|
||||
{
|
||||
requestFocus();
|
||||
|
||||
// Focus events not fired sometimes?
|
||||
setCaretVisible(true);
|
||||
focusedComponent = JEditTextArea.this;
|
||||
|
||||
// isPopupTrigger wasn't working for danh on windows
|
||||
boolean trigger = (evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0;
|
||||
// but it's required for macosx, since control-click does
|
||||
// the same thing as a right-mouse click
|
||||
if (!trigger && evt.isPopupTrigger()) trigger = true;
|
||||
|
||||
if (trigger && (popup != null)) {
|
||||
popup.show(painter,evt.getX(),evt.getY());
|
||||
return;
|
||||
}
|
||||
|
||||
// on Linux, middle button pastes selected text
|
||||
if ((evt.getModifiers() & InputEvent.BUTTON2_MASK) != 0) {
|
||||
Clipboard unixclipboard = getToolkit().getSystemSelection();
|
||||
if (unixclipboard != null) {
|
||||
Transferable t = unixclipboard.getContents(null);
|
||||
if (t != null && t.isDataFlavorSupported(DataFlavor.stringFlavor)) {
|
||||
try {
|
||||
String s = (String)t.getTransferData(DataFlavor.stringFlavor);
|
||||
s = s.replace('\u00A0', ' ');
|
||||
if (editable) setSelectedText(s);
|
||||
} catch (Exception e) {
|
||||
System.err.println(e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int line = yToLine(evt.getY());
|
||||
int offset = xToOffset(line,evt.getX());
|
||||
int dot = getLineStartOffset(line) + offset;
|
||||
|
||||
selectLine = false;
|
||||
selectWord = false;
|
||||
|
||||
switch(evt.getClickCount()) {
|
||||
|
||||
case 1:
|
||||
doSingleClick(evt,line,offset,dot);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// It uses the bracket matching stuff, so
|
||||
// it can throw a BLE
|
||||
try {
|
||||
doDoubleClick(evt,line,offset,dot);
|
||||
} catch(BadLocationException bl) {
|
||||
bl.printStackTrace();
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
doTripleClick(evt,line,offset,dot);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void doSingleClick(MouseEvent evt, int line,
|
||||
int offset, int dot) {
|
||||
// Check for click on urls
|
||||
String clickedURL = checkClickedURL(getLineText(line), offset);
|
||||
if (clickedURL != null) {
|
||||
Base.openURL(clickedURL);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((evt.getModifiers() & InputEvent.SHIFT_MASK) != 0) {
|
||||
rectSelect = (evt.getModifiers() & InputEvent.CTRL_MASK) != 0;
|
||||
select(getMarkPosition(),dot);
|
||||
} else {
|
||||
setCaretPosition(dot);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void doDoubleClick(MouseEvent evt, int line,
|
||||
int offset, int dot) throws BadLocationException
|
||||
{
|
||||
// Ignore empty lines
|
||||
if (getLineLength(line) == 0)
|
||||
return;
|
||||
|
||||
try {
|
||||
int bracket = TextUtilities.findMatchingBracket(document,
|
||||
Math.max(0,dot - 1));
|
||||
if (bracket != -1) {
|
||||
int mark = getMarkPosition();
|
||||
// Hack
|
||||
if (bracket > mark) {
|
||||
bracket++;
|
||||
mark--;
|
||||
}
|
||||
select(mark,bracket);
|
||||
return;
|
||||
}
|
||||
} catch(BadLocationException bl) {
|
||||
bl.printStackTrace();
|
||||
}
|
||||
|
||||
setNewSelectionWord( line, offset );
|
||||
select(newSelectionStart,newSelectionEnd);
|
||||
selectWord = true;
|
||||
selectionAncorStart = selectionStart;
|
||||
selectionAncorEnd = selectionEnd;
|
||||
|
||||
/*
|
||||
String lineText = getLineText(line);
|
||||
String noWordSep = (String)document.getProperty("noWordSep");
|
||||
int wordStart = TextUtilities.findWordStart(lineText,offset,noWordSep);
|
||||
int wordEnd = TextUtilities.findWordEnd(lineText,offset,noWordSep);
|
||||
|
||||
int lineStart = getLineStartOffset(line);
|
||||
select(lineStart + wordStart,lineStart + wordEnd);
|
||||
*/
|
||||
}
|
||||
|
||||
private void doTripleClick(MouseEvent evt, int line,
|
||||
int offset, int dot)
|
||||
{
|
||||
selectLine = true;
|
||||
select(getLineStartOffset(line),getSafeLineStopOffset(line));
|
||||
selectionAncorStart = selectionStart;
|
||||
selectionAncorEnd = selectionEnd;
|
||||
}
|
||||
}
|
||||
|
||||
class CaretUndo extends AbstractUndoableEdit
|
||||
{
|
||||
private int start;
|
||||
private int end;
|
||||
|
||||
CaretUndo(int start, int end)
|
||||
{
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
public boolean isSignificant()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getPresentationName()
|
||||
{
|
||||
return "caret move";
|
||||
}
|
||||
|
||||
public void undo() throws CannotUndoException
|
||||
{
|
||||
super.undo();
|
||||
|
||||
select(start,end);
|
||||
}
|
||||
|
||||
public void redo() throws CannotRedoException
|
||||
{
|
||||
super.redo();
|
||||
|
||||
select(start,end);
|
||||
}
|
||||
|
||||
public boolean addEdit(UndoableEdit edit)
|
||||
{
|
||||
if(edit instanceof CaretUndo)
|
||||
{
|
||||
CaretUndo cedit = (CaretUndo)edit;
|
||||
start = cedit.start;
|
||||
end = cedit.end;
|
||||
cedit.die();
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
{
|
||||
caretTimer = new Timer(500,new CaretBlinker());
|
||||
caretTimer.setInitialDelay(500);
|
||||
caretTimer.start();
|
||||
}
|
||||
|
||||
public void setDisplayLineNumbers(boolean displayLineNumbers) {
|
||||
editorLineNumbers.setDisplayLineNumbers(displayLineNumbers);
|
||||
}
|
||||
}
|
@ -1,139 +0,0 @@
|
||||
/*
|
||||
* KeywordMap.java - Fast keyword->id map
|
||||
* Copyright (C) 1998, 1999 Slava Pestov
|
||||
* Copyright (C) 1999 Mike Dillon
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package processing.app.syntax;
|
||||
|
||||
import javax.swing.text.Segment;
|
||||
|
||||
/**
|
||||
* A <code>KeywordMap</code> is similar to a hashtable in that it maps keys
|
||||
* to values. However, the `keys' are Swing segments. This allows lookups of
|
||||
* text substrings without the overhead of creating a new string object.
|
||||
* <p>
|
||||
* This class is used by <code>CTokenMarker</code> to map keywords to ids.
|
||||
*
|
||||
* @author Slava Pestov, Mike Dillon
|
||||
*/
|
||||
public class KeywordMap
|
||||
{
|
||||
/**
|
||||
* Creates a new <code>KeywordMap</code>.
|
||||
* @param ignoreCase True if keys are case insensitive
|
||||
*/
|
||||
public KeywordMap(boolean ignoreCase)
|
||||
{
|
||||
this(ignoreCase, 52);
|
||||
this.ignoreCase = ignoreCase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>KeywordMap</code>.
|
||||
* @param ignoreCase True if the keys are case insensitive
|
||||
* @param mapLength The number of `buckets' to create.
|
||||
* A value of 52 will give good performance for most maps.
|
||||
*/
|
||||
public KeywordMap(boolean ignoreCase, int mapLength)
|
||||
{
|
||||
this.mapLength = mapLength;
|
||||
this.ignoreCase = ignoreCase;
|
||||
map = new Keyword[mapLength];
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up a key.
|
||||
* @param text The text segment
|
||||
* @param offset The offset of the substring within the text segment
|
||||
* @param length The length of the substring
|
||||
*/
|
||||
public byte lookup(Segment text, int offset, int length)
|
||||
{
|
||||
if(length == 0)
|
||||
return Token.NULL;
|
||||
Keyword k = map[getSegmentMapKey(text, offset, length)];
|
||||
while(k != null)
|
||||
{
|
||||
if(length != k.keyword.length)
|
||||
{
|
||||
k = k.next;
|
||||
continue;
|
||||
}
|
||||
if(SyntaxUtilities.regionMatches(ignoreCase,text,offset,
|
||||
k.keyword))
|
||||
return k.id;
|
||||
k = k.next;
|
||||
}
|
||||
return Token.NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a key-value mapping.
|
||||
* @param keyword The key
|
||||
* @param id The value
|
||||
*/
|
||||
public void add(String keyword, byte id)
|
||||
{
|
||||
int key = getStringMapKey(keyword);
|
||||
map[key] = new Keyword(keyword.toCharArray(),id,map[key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the keyword map is set to be case insensitive,
|
||||
* false otherwise.
|
||||
*/
|
||||
public boolean getIgnoreCase()
|
||||
{
|
||||
return ignoreCase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if the keyword map should be case insensitive.
|
||||
* @param ignoreCase True if the keyword map should be case
|
||||
* insensitive, false otherwise
|
||||
*/
|
||||
public void setIgnoreCase(boolean ignoreCase)
|
||||
{
|
||||
this.ignoreCase = ignoreCase;
|
||||
}
|
||||
|
||||
// protected members
|
||||
protected int mapLength;
|
||||
|
||||
protected int getStringMapKey(String s)
|
||||
{
|
||||
return (Character.toUpperCase(s.charAt(0)) +
|
||||
Character.toUpperCase(s.charAt(s.length()-1)))
|
||||
% mapLength;
|
||||
}
|
||||
|
||||
protected int getSegmentMapKey(Segment s, int off, int len)
|
||||
{
|
||||
return (Character.toUpperCase(s.array[off]) +
|
||||
Character.toUpperCase(s.array[off + len - 1]))
|
||||
% mapLength;
|
||||
}
|
||||
|
||||
// private members
|
||||
class Keyword
|
||||
{
|
||||
public Keyword(char[] keyword, byte id, Keyword next)
|
||||
{
|
||||
this.keyword = keyword;
|
||||
this.id = id;
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
public char[] keyword;
|
||||
public byte id;
|
||||
public Keyword next;
|
||||
}
|
||||
|
||||
private Keyword[] map;
|
||||
private boolean ignoreCase;
|
||||
}
|
@ -1,211 +0,0 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
PdeTextAreaDefaults - grabs font/color settings for the editor
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2004-06 Ben Fry and Casey Reas
|
||||
Copyright (c) 2001-03 Massachusetts Institute of Technology
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.app.syntax;
|
||||
|
||||
import processing.app.*;
|
||||
import processing.app.helpers.OSUtils;
|
||||
|
||||
|
||||
public class PdeTextAreaDefaults extends TextAreaDefaults {
|
||||
|
||||
public PdeTextAreaDefaults() {
|
||||
|
||||
inputHandler = new DefaultInputHandler();
|
||||
//inputHandler.addDefaultKeyBindings(); // 0122
|
||||
|
||||
// use option on mac for text edit controls that are ctrl on windows/linux
|
||||
String mod = OSUtils.isMacOS() ? "A" : "C";
|
||||
|
||||
// right now, ctrl-up/down is select up/down, but mod should be
|
||||
// used instead, because the mac expects it to be option(alt)
|
||||
|
||||
inputHandler.addKeyBinding("BACK_SPACE", InputHandler.BACKSPACE);
|
||||
// for 0122, shift-backspace is delete, for 0176, it's now a preference,
|
||||
// to prevent holy warriors from attacking me for it.
|
||||
if (PreferencesData.getBoolean("editor.keys.shift_backspace_is_delete")) {
|
||||
inputHandler.addKeyBinding("S+BACK_SPACE", InputHandler.DELETE);
|
||||
} else {
|
||||
inputHandler.addKeyBinding("S+BACK_SPACE", InputHandler.BACKSPACE);
|
||||
}
|
||||
|
||||
inputHandler.addKeyBinding("DELETE", InputHandler.DELETE);
|
||||
inputHandler.addKeyBinding("S+DELETE", InputHandler.DELETE);
|
||||
|
||||
// the following two were changing for 0122 for better mac/pc compatability
|
||||
inputHandler.addKeyBinding(mod+"+BACK_SPACE", InputHandler.BACKSPACE_WORD);
|
||||
inputHandler.addKeyBinding(mod+"+DELETE", InputHandler.DELETE_WORD);
|
||||
|
||||
// handled by listener, don't bother here
|
||||
//inputHandler.addKeyBinding("ENTER", InputHandler.INSERT_BREAK);
|
||||
//inputHandler.addKeyBinding("TAB", InputHandler.INSERT_TAB);
|
||||
|
||||
inputHandler.addKeyBinding("INSERT", InputHandler.OVERWRITE);
|
||||
|
||||
// http://dev.processing.org/bugs/show_bug.cgi?id=162
|
||||
// added for 0176, though the bindings do not appear relevant for osx
|
||||
if (PreferencesData.getBoolean("editor.keys.alternative_cut_copy_paste")) {
|
||||
inputHandler.addKeyBinding("C+INSERT", InputHandler.CLIPBOARD_COPY);
|
||||
inputHandler.addKeyBinding("S+INSERT", InputHandler.CLIPBOARD_PASTE);
|
||||
inputHandler.addKeyBinding("S+DELETE", InputHandler.CLIPBOARD_CUT);
|
||||
}
|
||||
|
||||
// disabling for 0122, not sure what this does
|
||||
//inputHandler.addKeyBinding("C+\\", InputHandler.TOGGLE_RECT);
|
||||
|
||||
// for 0122, these have been changed for better compatibility
|
||||
// HOME and END now mean the beginning/end of the document
|
||||
// for 0176 changed this to a preference so that the Mac OS X people
|
||||
// can get the "normal" behavior as well if they prefer.
|
||||
if (PreferencesData.getBoolean("editor.keys.home_and_end_travel_far")) {
|
||||
inputHandler.addKeyBinding("HOME", InputHandler.DOCUMENT_HOME);
|
||||
inputHandler.addKeyBinding("END", InputHandler.DOCUMENT_END);
|
||||
inputHandler.addKeyBinding("S+HOME", InputHandler.SELECT_DOC_HOME);
|
||||
inputHandler.addKeyBinding("S+END", InputHandler.SELECT_DOC_END);
|
||||
} else {
|
||||
// for 0123 added the proper windows defaults
|
||||
inputHandler.addKeyBinding("HOME", InputHandler.HOME);
|
||||
inputHandler.addKeyBinding("END", InputHandler.END);
|
||||
inputHandler.addKeyBinding("S+HOME", InputHandler.SELECT_HOME);
|
||||
inputHandler.addKeyBinding("S+END", InputHandler.SELECT_END);
|
||||
inputHandler.addKeyBinding("C+HOME", InputHandler.DOCUMENT_HOME);
|
||||
inputHandler.addKeyBinding("C+END", InputHandler.DOCUMENT_END);
|
||||
inputHandler.addKeyBinding("CS+HOME", InputHandler.SELECT_DOC_HOME);
|
||||
inputHandler.addKeyBinding("CS+END", InputHandler.SELECT_DOC_END);
|
||||
}
|
||||
|
||||
if (OSUtils.isMacOS()) {
|
||||
inputHandler.addKeyBinding("M+LEFT", InputHandler.HOME);
|
||||
inputHandler.addKeyBinding("M+RIGHT", InputHandler.END);
|
||||
inputHandler.addKeyBinding("MS+LEFT", InputHandler.SELECT_HOME); // 0122
|
||||
inputHandler.addKeyBinding("MS+RIGHT", InputHandler.SELECT_END); // 0122
|
||||
} else {
|
||||
inputHandler.addKeyBinding("C+LEFT", InputHandler.HOME); // 0122
|
||||
inputHandler.addKeyBinding("C+RIGHT", InputHandler.END); // 0122
|
||||
inputHandler.addKeyBinding("CS+HOME", InputHandler.SELECT_HOME); // 0122
|
||||
inputHandler.addKeyBinding("CS+END", InputHandler.SELECT_END); // 0122
|
||||
}
|
||||
|
||||
inputHandler.addKeyBinding("PAGE_UP", InputHandler.PREV_PAGE);
|
||||
inputHandler.addKeyBinding("PAGE_DOWN", InputHandler.NEXT_PAGE);
|
||||
inputHandler.addKeyBinding("S+PAGE_UP", InputHandler.SELECT_PREV_PAGE);
|
||||
inputHandler.addKeyBinding("S+PAGE_DOWN", InputHandler.SELECT_NEXT_PAGE);
|
||||
|
||||
inputHandler.addKeyBinding("LEFT", InputHandler.PREV_CHAR);
|
||||
inputHandler.addKeyBinding("S+LEFT", InputHandler.SELECT_PREV_CHAR);
|
||||
inputHandler.addKeyBinding(mod + "+LEFT", InputHandler.PREV_WORD);
|
||||
inputHandler.addKeyBinding(mod + "S+LEFT", InputHandler.SELECT_PREV_WORD);
|
||||
inputHandler.addKeyBinding("RIGHT", InputHandler.NEXT_CHAR);
|
||||
inputHandler.addKeyBinding("S+RIGHT", InputHandler.SELECT_NEXT_CHAR);
|
||||
inputHandler.addKeyBinding(mod + "+RIGHT", InputHandler.NEXT_WORD);
|
||||
inputHandler.addKeyBinding(mod + "S+RIGHT", InputHandler.SELECT_NEXT_WORD);
|
||||
|
||||
inputHandler.addKeyBinding("UP", InputHandler.PREV_LINE);
|
||||
inputHandler.addKeyBinding(mod + "+UP", InputHandler.PREV_LINE); // p5
|
||||
inputHandler.addKeyBinding("S+UP", InputHandler.SELECT_PREV_LINE);
|
||||
inputHandler.addKeyBinding("DOWN", InputHandler.NEXT_LINE);
|
||||
inputHandler.addKeyBinding(mod + "+DOWN", InputHandler.NEXT_LINE); // p5
|
||||
inputHandler.addKeyBinding("S+DOWN", InputHandler.SELECT_NEXT_LINE);
|
||||
|
||||
inputHandler.addKeyBinding("MS+UP", InputHandler.SELECT_DOC_HOME);
|
||||
inputHandler.addKeyBinding("CS+UP", InputHandler.SELECT_DOC_HOME);
|
||||
inputHandler.addKeyBinding("MS+DOWN", InputHandler.SELECT_DOC_END);
|
||||
inputHandler.addKeyBinding("CS+DOWN", InputHandler.SELECT_DOC_END);
|
||||
|
||||
inputHandler.addKeyBinding(mod + "+ENTER", InputHandler.REPEAT);
|
||||
|
||||
document = new SyntaxDocument();
|
||||
editable = true;
|
||||
electricScroll = 3;
|
||||
|
||||
cols = 80;
|
||||
rows = 15;
|
||||
|
||||
|
||||
// moved from SyntaxUtilities
|
||||
//DEFAULTS.styles = SyntaxUtilities.getDefaultSyntaxStyles();
|
||||
|
||||
styles = new SyntaxStyle[Token.ID_COUNT];
|
||||
|
||||
// comments
|
||||
styles[Token.COMMENT1] = Theme.getStyle("comment1");
|
||||
styles[Token.COMMENT2] = Theme.getStyle("comment2");
|
||||
|
||||
// abstract, final, private
|
||||
styles[Token.KEYWORD1] = Theme.getStyle("keyword1");
|
||||
|
||||
// beginShape, point, line
|
||||
styles[Token.KEYWORD2] = Theme.getStyle("keyword2");
|
||||
|
||||
// byte, char, short, color
|
||||
styles[Token.KEYWORD3] = Theme.getStyle("keyword3");
|
||||
|
||||
// constants: null, true, this, RGB, TWO_PI
|
||||
styles[Token.LITERAL1] = Theme.getStyle("literal1");
|
||||
|
||||
// p5 built in variables: mouseX, width, pixels
|
||||
styles[Token.LITERAL2] = Theme.getStyle("literal2");
|
||||
|
||||
// ??
|
||||
styles[Token.LABEL] = Theme.getStyle("label");
|
||||
|
||||
// http://arduino.cc/
|
||||
styles[Token.URL] = Theme.getStyle("url");
|
||||
|
||||
// + - = /
|
||||
styles[Token.OPERATOR] = Theme.getStyle("operator");
|
||||
|
||||
// area that's not in use by the text (replaced with tildes)
|
||||
styles[Token.INVALID] = Theme.getStyle("invalid");
|
||||
|
||||
|
||||
// moved from TextAreaPainter
|
||||
|
||||
font = PreferencesData.getFont("editor.font");
|
||||
|
||||
fgcolor = Theme.getColor("editor.fgcolor");
|
||||
bgcolor = Theme.getColor("editor.bgcolor");
|
||||
|
||||
caretVisible = true;
|
||||
caretBlinks = PreferencesData.getBoolean("editor.caret.blink");
|
||||
caretColor = Theme.getColor("editor.caret.color");
|
||||
|
||||
selectionColor = Theme.getColor("editor.selection.color");
|
||||
|
||||
lineHighlight =
|
||||
Theme.getBoolean("editor.linehighlight");
|
||||
lineHighlightColor =
|
||||
Theme.getColor("editor.linehighlight.color");
|
||||
|
||||
bracketHighlight =
|
||||
Theme.getBoolean("editor.brackethighlight");
|
||||
bracketHighlightColor =
|
||||
Theme.getColor("editor.brackethighlight.color");
|
||||
|
||||
eolMarkers = Theme.getBoolean("editor.eolmarkers");
|
||||
eolMarkerColor = Theme.getColor("editor.eolmarkers.color");
|
||||
|
||||
paintInvalid = Theme.getBoolean("editor.invalid");
|
||||
}
|
||||
}
|
@ -1,165 +0,0 @@
|
||||
/*
|
||||
* SyntaxDocument.java - Document that can be tokenized
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package processing.app.syntax;
|
||||
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.text.*;
|
||||
import javax.swing.undo.UndoableEdit;
|
||||
|
||||
/**
|
||||
* A document implementation that can be tokenized by the syntax highlighting
|
||||
* system.
|
||||
*
|
||||
* @author Slava Pestov
|
||||
*/
|
||||
public class SyntaxDocument extends PlainDocument
|
||||
{
|
||||
/**
|
||||
* Returns the token marker that is to be used to split lines
|
||||
* of this document up into tokens. May return null if this
|
||||
* document is not to be colorized.
|
||||
*/
|
||||
public TokenMarker getTokenMarker()
|
||||
{
|
||||
return tokenMarker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the token marker that is to be used to split lines of
|
||||
* this document up into tokens. May throw an exception if
|
||||
* this is not supported for this type of document.
|
||||
* @param tm The new token marker
|
||||
*/
|
||||
public void setTokenMarker(TokenMarker tm)
|
||||
{
|
||||
tokenMarker = tm;
|
||||
if(tm == null)
|
||||
return;
|
||||
tokenMarker.insertLines(0,getDefaultRootElement()
|
||||
.getElementCount());
|
||||
tokenizeLines();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reparses the document, by passing all lines to the token
|
||||
* marker. This should be called after the document is first
|
||||
* loaded.
|
||||
*/
|
||||
public void tokenizeLines()
|
||||
{
|
||||
tokenizeLines(0,getDefaultRootElement().getElementCount());
|
||||
}
|
||||
|
||||
/**
|
||||
* Reparses the document, by passing the specified lines to the
|
||||
* token marker. This should be called after a large quantity of
|
||||
* text is first inserted.
|
||||
* @param start The first line to parse
|
||||
* @param len The number of lines, after the first one to parse
|
||||
*/
|
||||
public void tokenizeLines(int start, int len)
|
||||
{
|
||||
if(tokenMarker == null || !tokenMarker.supportsMultilineTokens())
|
||||
return;
|
||||
|
||||
Segment lineSegment = new Segment();
|
||||
Element map = getDefaultRootElement();
|
||||
|
||||
len += start;
|
||||
|
||||
try
|
||||
{
|
||||
for(int i = start; i < len; i++)
|
||||
{
|
||||
Element lineElement = map.getElement(i);
|
||||
int lineStart = lineElement.getStartOffset();
|
||||
getText(lineStart,lineElement.getEndOffset()
|
||||
- lineStart - 1,lineSegment);
|
||||
tokenMarker.markTokens(lineSegment,i);
|
||||
}
|
||||
}
|
||||
catch(BadLocationException bl)
|
||||
{
|
||||
bl.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a compound edit that can be undone in one operation.
|
||||
* Subclasses that implement undo should override this method;
|
||||
* this class has no undo functionality so this method is
|
||||
* empty.
|
||||
*/
|
||||
public void beginCompoundEdit() {}
|
||||
|
||||
/**
|
||||
* Ends a compound edit that can be undone in one operation.
|
||||
* Subclasses that implement undo should override this method;
|
||||
* this class has no undo functionality so this method is
|
||||
* empty.
|
||||
*/
|
||||
public void endCompoundEdit() {}
|
||||
|
||||
/**
|
||||
* Adds an undoable edit to this document's undo list. The edit
|
||||
* should be ignored if something is currently being undone.
|
||||
* @param edit The undoable edit
|
||||
*
|
||||
* @since jEdit 2.2pre1
|
||||
*/
|
||||
public void addUndoableEdit(UndoableEdit edit) {}
|
||||
|
||||
// protected members
|
||||
protected TokenMarker tokenMarker;
|
||||
|
||||
/**
|
||||
* We overwrite this method to update the token marker
|
||||
* state immediately so that any event listeners get a
|
||||
* consistent token marker.
|
||||
*/
|
||||
protected void fireInsertUpdate(DocumentEvent evt)
|
||||
{
|
||||
if(tokenMarker != null)
|
||||
{
|
||||
DocumentEvent.ElementChange ch = evt.getChange(
|
||||
getDefaultRootElement());
|
||||
if(ch != null)
|
||||
{
|
||||
tokenMarker.insertLines(ch.getIndex() + 1,
|
||||
ch.getChildrenAdded().length -
|
||||
ch.getChildrenRemoved().length);
|
||||
}
|
||||
}
|
||||
|
||||
super.fireInsertUpdate(evt);
|
||||
}
|
||||
|
||||
/**
|
||||
* We overwrite this method to update the token marker
|
||||
* state immediately so that any event listeners get a
|
||||
* consistent token marker.
|
||||
*/
|
||||
protected void fireRemoveUpdate(DocumentEvent evt)
|
||||
{
|
||||
if(tokenMarker != null)
|
||||
{
|
||||
DocumentEvent.ElementChange ch = evt.getChange(
|
||||
getDefaultRootElement());
|
||||
if(ch != null)
|
||||
{
|
||||
tokenMarker.deleteLines(ch.getIndex() + 1,
|
||||
ch.getChildrenRemoved().length -
|
||||
ch.getChildrenAdded().length);
|
||||
}
|
||||
}
|
||||
|
||||
super.fireRemoveUpdate(evt);
|
||||
}
|
||||
}
|
@ -1,163 +0,0 @@
|
||||
/*
|
||||
* SyntaxStyle.java - A simple text style class
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package processing.app.syntax;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.font.TextAttribute;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
|
||||
|
||||
/**
|
||||
* A simple text style class. It can specify the color, italic flag,
|
||||
* and bold flag of a run of text.
|
||||
* @author Slava Pestov
|
||||
*/
|
||||
public class SyntaxStyle
|
||||
{
|
||||
/**
|
||||
* Creates a new SyntaxStyle.
|
||||
* @param color The text color
|
||||
* @param italic True if the text should be italics
|
||||
* @param bold True if the text should be bold
|
||||
*/
|
||||
public SyntaxStyle(Color color, boolean italic, boolean bold, boolean underlined)
|
||||
{
|
||||
this.color = color;
|
||||
this.italic = italic;
|
||||
this.bold = bold;
|
||||
this.underlined = underlined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the color specified in this style.
|
||||
*/
|
||||
public Color getColor()
|
||||
{
|
||||
return color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if no font styles are enabled.
|
||||
*/
|
||||
public boolean isPlain()
|
||||
{
|
||||
return !(bold || italic || underlined);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if italics is enabled for this style.
|
||||
*/
|
||||
public boolean isItalic()
|
||||
{
|
||||
return italic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if boldface is enabled for this style.
|
||||
*/
|
||||
public boolean isBold()
|
||||
{
|
||||
return bold;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if underline is enabled for this style.
|
||||
*/
|
||||
public boolean isUnderlined() {
|
||||
return underlined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the specified font, but with the style's bold, underline and
|
||||
* italic flags applied.
|
||||
*/
|
||||
public Font getStyledFont(Font font)
|
||||
{
|
||||
if(font == null)
|
||||
throw new NullPointerException("font param must not"
|
||||
+ " be null");
|
||||
if(font.equals(lastFont))
|
||||
return lastStyledFont;
|
||||
lastFont = font;
|
||||
|
||||
lastStyledFont = new Font(font.getFamily(),
|
||||
(bold ? Font.BOLD : 0)
|
||||
| (italic ? Font.ITALIC : 0),
|
||||
font.getSize());
|
||||
if (underlined) {
|
||||
Map<TextAttribute, Object> attr = new Hashtable<TextAttribute, Object>();
|
||||
attr.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
|
||||
lastStyledFont = lastStyledFont.deriveFont(attr);
|
||||
}
|
||||
return lastStyledFont;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the font metrics for the styled font.
|
||||
*/
|
||||
public FontMetrics getFontMetrics(Font font, JComponent comp)
|
||||
{
|
||||
if(font == null)
|
||||
throw new NullPointerException("font param must not"
|
||||
+ " be null");
|
||||
if(font.equals(lastFont) && fontMetrics != null)
|
||||
return fontMetrics;
|
||||
lastFont = font;
|
||||
lastStyledFont = new Font(font.getFamily(),
|
||||
(bold ? Font.BOLD : 0)
|
||||
| (italic ? Font.ITALIC : 0),
|
||||
font.getSize());
|
||||
if (underlined) {
|
||||
Map<TextAttribute, Object> attr = new Hashtable<TextAttribute, Object>();
|
||||
attr.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
|
||||
lastStyledFont = lastStyledFont.deriveFont(attr);
|
||||
}
|
||||
//fontMetrics = Toolkit.getDefaultToolkit().getFontMetrics(lastStyledFont);
|
||||
fontMetrics = comp.getFontMetrics(lastStyledFont);
|
||||
return fontMetrics;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the foreground color and font of the specified graphics
|
||||
* context to that specified in this style.
|
||||
* @param gfx The graphics context
|
||||
* @param font The font to add the styles to
|
||||
*/
|
||||
public void setGraphicsFlags(Graphics gfx, Font font)
|
||||
{
|
||||
Font _font = getStyledFont(font);
|
||||
gfx.setFont(_font);
|
||||
gfx.setColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this object.
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
return getClass().getName() + "[color=" + color +
|
||||
(italic ? ",italic" : "") +
|
||||
(bold ? ",bold" : "") +
|
||||
(underlined ? ",underlined" : "") +
|
||||
"]";
|
||||
}
|
||||
|
||||
// private members
|
||||
private Color color;
|
||||
private boolean italic;
|
||||
private boolean bold;
|
||||
private boolean underlined;
|
||||
private Font lastFont;
|
||||
private Font lastStyledFont;
|
||||
private FontMetrics fontMetrics;
|
||||
}
|
@ -1,226 +0,0 @@
|
||||
/*
|
||||
* SyntaxUtilities.java - Utility functions used by syntax colorizing
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package processing.app.syntax;
|
||||
|
||||
import javax.swing.text.*;
|
||||
import java.awt.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
||||
/**
|
||||
* Class with several utility functions used by jEdit's syntax colorizing
|
||||
* subsystem.
|
||||
*
|
||||
* @author Slava Pestov
|
||||
*/
|
||||
public class SyntaxUtilities
|
||||
{
|
||||
/**
|
||||
* Checks if a subregion of a <code>Segment</code> is equal to a
|
||||
* string.
|
||||
* @param ignoreCase True if case should be ignored, false otherwise
|
||||
* @param text The segment
|
||||
* @param offset The offset into the segment
|
||||
* @param match The string to match
|
||||
*/
|
||||
public static boolean regionMatches(boolean ignoreCase, Segment text,
|
||||
int offset, String match)
|
||||
{
|
||||
int length = offset + match.length();
|
||||
char[] textArray = text.array;
|
||||
if(length > text.offset + text.count)
|
||||
return false;
|
||||
for(int i = offset, j = 0; i < length; i++, j++)
|
||||
{
|
||||
char c1 = textArray[i];
|
||||
char c2 = match.charAt(j);
|
||||
if(ignoreCase)
|
||||
{
|
||||
c1 = Character.toUpperCase(c1);
|
||||
c2 = Character.toUpperCase(c2);
|
||||
}
|
||||
if(c1 != c2)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if a subregion of a <code>Segment</code> is equal to a
|
||||
* character array.
|
||||
* @param ignoreCase True if case should be ignored, false otherwise
|
||||
* @param text The segment
|
||||
* @param offset The offset into the segment
|
||||
* @param match The character array to match
|
||||
*/
|
||||
public static boolean regionMatches(boolean ignoreCase, Segment text,
|
||||
int offset, char[] match)
|
||||
{
|
||||
int length = offset + match.length;
|
||||
char[] textArray = text.array;
|
||||
if(length > text.offset + text.count)
|
||||
return false;
|
||||
for(int i = offset, j = 0; i < length; i++, j++)
|
||||
{
|
||||
char c1 = textArray[i];
|
||||
char c2 = match[j];
|
||||
if(ignoreCase)
|
||||
{
|
||||
c1 = Character.toUpperCase(c1);
|
||||
c2 = Character.toUpperCase(c2);
|
||||
}
|
||||
if(c1 != c2)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the default style table. This can be passed to the
|
||||
* <code>setStyles()</code> method of <code>SyntaxDocument</code>
|
||||
* to use the default syntax styles.
|
||||
*/
|
||||
public static SyntaxStyle[] getDefaultSyntaxStyles()
|
||||
{
|
||||
SyntaxStyle[] styles = new SyntaxStyle[Token.ID_COUNT];
|
||||
|
||||
styles[Token.COMMENT1] = new SyntaxStyle(Color.black,true,false,false);
|
||||
styles[Token.COMMENT2] = new SyntaxStyle(new Color(0x990033),true,false,false);
|
||||
styles[Token.KEYWORD1] = new SyntaxStyle(Color.black,false,true,false);
|
||||
styles[Token.KEYWORD2] = new SyntaxStyle(Color.magenta,false,false,false);
|
||||
styles[Token.KEYWORD3] = new SyntaxStyle(new Color(0x009600),false,false,false);
|
||||
styles[Token.LITERAL1] = new SyntaxStyle(new Color(0x650099),false,false,false);
|
||||
styles[Token.LITERAL2] = new SyntaxStyle(new Color(0x650099),false,true,false);
|
||||
styles[Token.LABEL] = new SyntaxStyle(new Color(0x990033),false,true,false);
|
||||
styles[Token.OPERATOR] = new SyntaxStyle(Color.black,false,true,false);
|
||||
styles[Token.URL] = new SyntaxStyle(Color.blue,true,false,false);
|
||||
styles[Token.INVALID] = new SyntaxStyle(Color.red,false,true,false);
|
||||
|
||||
return styles;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Paints the specified line onto the graphics context. Note that this
|
||||
* method munges the offset and count values of the segment.
|
||||
* @param line The line segment
|
||||
* @param tokens The token list for the line
|
||||
* @param styles The syntax style list
|
||||
* @param expander The tab expander used to determine tab stops. May
|
||||
* be null
|
||||
* @param gfx The graphics context
|
||||
* @param x The x co-ordinate
|
||||
* @param y The y co-ordinate
|
||||
* @return The x co-ordinate, plus the width of the painted string
|
||||
*/
|
||||
public static int paintSyntaxLine(Segment line, Token tokens,
|
||||
SyntaxStyle[] styles,
|
||||
TabExpander expander, Graphics gfx,
|
||||
int x, int y)
|
||||
{
|
||||
Font defaultFont = gfx.getFont();
|
||||
Color defaultColor = gfx.getColor();
|
||||
|
||||
for(;;)
|
||||
{
|
||||
byte id = tokens.id;
|
||||
if(id == Token.END)
|
||||
break;
|
||||
|
||||
int length = tokens.length;
|
||||
if(id == Token.NULL)
|
||||
{
|
||||
if(!defaultColor.equals(gfx.getColor()))
|
||||
gfx.setColor(defaultColor);
|
||||
if(!defaultFont.equals(gfx.getFont()))
|
||||
gfx.setFont(defaultFont);
|
||||
}
|
||||
else
|
||||
styles[id].setGraphicsFlags(gfx,defaultFont);
|
||||
|
||||
line.count = length;
|
||||
if (id == Token.COMMENT1 || id == Token.COMMENT2)
|
||||
x = drawTabbedCommentsText(line, x, y, gfx, expander, styles, styles[id]);
|
||||
else
|
||||
x = Utilities.drawTabbedText(line, x, y, gfx, expander, 0);
|
||||
line.offset += length;
|
||||
|
||||
tokens = tokens.next;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse comments and identify "@schematics <b><something></b>" pattern.
|
||||
*
|
||||
* @param line
|
||||
* A string to parse
|
||||
* @return <b>null</b> if the pattern is not found, otherwise an array of
|
||||
* String is returned: the elements with index 0, 1 and 2 are
|
||||
* respectively the preamble, the <b><something></b> stuff, and
|
||||
* the remaining part of the string.
|
||||
*/
|
||||
public static String[] parseCommentUrls(String line) {
|
||||
Matcher m = urlPattern.matcher(line.toString());
|
||||
if (!m.find())
|
||||
return null;
|
||||
|
||||
String res[] = new String[3];
|
||||
res[0] = line.substring(0, m.start(1));
|
||||
res[1] = line.substring(m.start(1), m.end(1));
|
||||
res[2] = line.substring(m.end(1));
|
||||
// System.out.println("0 =>"+res[0]+"<\n1 =>"+res[1]+"< \n2 =>"+res[2]+"<");
|
||||
return res;
|
||||
}
|
||||
|
||||
static private Pattern urlPattern = Pattern.compile(
|
||||
"((?:https?|ftp)://" + // ( Protocol
|
||||
"(?:(?:[\\w_\\-]+:)?[\\w_\\-]+@)?" + // Username and password
|
||||
"(?:[\\w_\\-]+\\.)+[\\w_\\-]+" + // Domain name
|
||||
"(?::[0-9]{1,5})?" + // Port
|
||||
"(?:/[\\w_\\-./?%&=+]*)?)" + // Path )
|
||||
"(?:\\s|$)"); // whitespace or EOL
|
||||
|
||||
public static Segment stringToSegment(String v) {
|
||||
return new Segment(v.toCharArray(), 0, v.length());
|
||||
}
|
||||
|
||||
private static int drawTabbedCommentsText(Segment line, int x, int y,
|
||||
Graphics gfx, TabExpander expander, SyntaxStyle[] styles,
|
||||
SyntaxStyle commentStyle) {
|
||||
|
||||
String parse[] = parseCommentUrls(line.toString());
|
||||
if (parse == null)
|
||||
// Revert to plain writing.
|
||||
return Utilities.drawTabbedText(line, x, y, gfx, expander, 0);
|
||||
Segment pre = stringToSegment(parse[0]);
|
||||
Segment tag = stringToSegment(parse[1]);
|
||||
Segment post = stringToSegment(parse[2]);
|
||||
|
||||
if (pre.count>0)
|
||||
x = Utilities.drawTabbedText(pre, x, y, gfx, expander, 0);
|
||||
|
||||
Font f = gfx.getFont();
|
||||
styles[Token.URL].setGraphicsFlags(gfx, f);
|
||||
x = Utilities.drawTabbedText(tag, x, y, gfx, expander, 0);
|
||||
|
||||
commentStyle.setGraphicsFlags(gfx, f);
|
||||
if (post.count>0)
|
||||
x = Utilities.drawTabbedText(post, x, y, gfx, expander, 0);
|
||||
return x;
|
||||
}
|
||||
|
||||
// private members
|
||||
private SyntaxUtilities() {}
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
/*
|
||||
* TextAreaDefaults.java - Encapsulates default values for various settings
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package processing.app.syntax;
|
||||
|
||||
import java.awt.*;
|
||||
//import javax.swing.JPopupMenu;
|
||||
|
||||
/**
|
||||
* Encapsulates default settings for a text area. This can be passed
|
||||
* to the constructor once the necessary fields have been filled out.
|
||||
* The advantage of doing this over calling lots of set() methods after
|
||||
* creating the text area is that this method is faster.
|
||||
*/
|
||||
public class TextAreaDefaults
|
||||
{
|
||||
private static TextAreaDefaults DEFAULTS;
|
||||
|
||||
public InputHandler inputHandler;
|
||||
public SyntaxDocument document;
|
||||
public boolean editable;
|
||||
|
||||
public boolean caretVisible;
|
||||
public boolean caretBlinks;
|
||||
public boolean blockCaret;
|
||||
public int electricScroll;
|
||||
|
||||
public int cols;
|
||||
public int rows;
|
||||
public SyntaxStyle[] styles;
|
||||
public Color caretColor;
|
||||
public Color selectionColor;
|
||||
public Color lineHighlightColor;
|
||||
public boolean lineHighlight;
|
||||
public Color bracketHighlightColor;
|
||||
public boolean bracketHighlight;
|
||||
public Color eolMarkerColor;
|
||||
public boolean eolMarkers;
|
||||
public boolean paintInvalid;
|
||||
|
||||
|
||||
// moved from TextAreaPainter [fry]
|
||||
public Font font;
|
||||
public Color fgcolor;
|
||||
public Color bgcolor;
|
||||
|
||||
//public JPopupMenu popup;
|
||||
|
||||
|
||||
/**
|
||||
* Returns a new TextAreaDefaults object with the default values filled
|
||||
* in.
|
||||
*/
|
||||
public static TextAreaDefaults getDefaults()
|
||||
{
|
||||
if (DEFAULTS == null) {
|
||||
DEFAULTS = new TextAreaDefaults();
|
||||
|
||||
DEFAULTS.inputHandler = new DefaultInputHandler();
|
||||
DEFAULTS.inputHandler.addDefaultKeyBindings();
|
||||
DEFAULTS.document = new SyntaxDocument();
|
||||
DEFAULTS.editable = true;
|
||||
|
||||
DEFAULTS.caretVisible = true;
|
||||
DEFAULTS.caretBlinks = true;
|
||||
DEFAULTS.electricScroll = 3;
|
||||
|
||||
DEFAULTS.cols = 80;
|
||||
DEFAULTS.rows = 25;
|
||||
DEFAULTS.styles = SyntaxUtilities.getDefaultSyntaxStyles();
|
||||
DEFAULTS.caretColor = Color.red;
|
||||
DEFAULTS.selectionColor = new Color(0xccccff);
|
||||
DEFAULTS.lineHighlightColor = new Color(0xe0e0e0);
|
||||
DEFAULTS.lineHighlight = true;
|
||||
DEFAULTS.bracketHighlightColor = Color.black;
|
||||
DEFAULTS.bracketHighlight = true;
|
||||
DEFAULTS.eolMarkerColor = new Color(0x009999);
|
||||
DEFAULTS.eolMarkers = true;
|
||||
DEFAULTS.paintInvalid = true;
|
||||
}
|
||||
|
||||
return DEFAULTS;
|
||||
}
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
/*
|
||||
* TextAreaLineNumbers.java - Show line numbers for the open file in the editor
|
||||
* Copyright (C) 2013 Cayci Gorlitsky
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package processing.app.syntax;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
import javax.swing.border.MatteBorder;
|
||||
|
||||
public class TextAreaLineNumbers extends TextAreaPainter {
|
||||
|
||||
private final int LEFT_INDENT = 6;
|
||||
private final int RIGHT_INDENT = 6;
|
||||
private final int RIGHT_BORDER_WIDTH = 1;
|
||||
private final int PADDING_WIDTH = LEFT_INDENT + RIGHT_INDENT + RIGHT_BORDER_WIDTH;
|
||||
|
||||
private final int MIN_WIDTH;
|
||||
private final int DIGIT_WIDTH;
|
||||
private final int MIN_NUM_DIGITS = 2;
|
||||
|
||||
private int currStartNum = 0;
|
||||
private int currEndNum = 0;
|
||||
private int currNumDigits = MIN_NUM_DIGITS;
|
||||
|
||||
|
||||
|
||||
public TextAreaLineNumbers(JEditTextArea textArea, TextAreaDefaults defaults) {
|
||||
super(textArea, defaults);
|
||||
DIGIT_WIDTH = getFontMetrics(getFont()).stringWidth("0");
|
||||
MIN_WIDTH = DIGIT_WIDTH * MIN_NUM_DIGITS + PADDING_WIDTH;
|
||||
setEnabled(false);
|
||||
setBorder(new MatteBorder(0, 0, 0, RIGHT_BORDER_WIDTH, new Color(240, 240, 240)));
|
||||
}
|
||||
|
||||
public void updateLineNumbers(int startNum, int endNum) {
|
||||
if (currStartNum == startNum && currEndNum == endNum) {
|
||||
return;
|
||||
}
|
||||
currStartNum = startNum;
|
||||
currEndNum = endNum;
|
||||
|
||||
invalidate();
|
||||
repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint(Graphics gfx) {
|
||||
super.paint(gfx);
|
||||
getBorder().paintBorder(this, gfx, 0, 0, getSize().width, getSize().height);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintLine(Graphics gfx, TokenMarker tokenMarker,
|
||||
int line, int x)
|
||||
{
|
||||
currentLineIndex = line;
|
||||
gfx.setFont(getFont());
|
||||
gfx.setColor(Color.GRAY);
|
||||
int y = textArea.lineToY(line);
|
||||
int startX = getBounds().x + getBounds().width;
|
||||
if (line >= 0 && line < textArea.getLineCount()) {
|
||||
String lineNumberString = String.valueOf(line+1);
|
||||
int lineStartX = startX - RIGHT_BORDER_WIDTH - RIGHT_INDENT - fm.stringWidth(lineNumberString);
|
||||
gfx.drawString(lineNumberString,lineStartX,y + fm.getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
public void updateWidthForNumDigits(int numDigits) {
|
||||
if (currNumDigits == numDigits) {
|
||||
return;
|
||||
}
|
||||
currNumDigits = numDigits;
|
||||
|
||||
if (isVisible()) {
|
||||
updateBounds();
|
||||
invalidate();
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
public void setDisplayLineNumbers(boolean displayLineNumbers) {
|
||||
setVisible(displayLineNumbers);
|
||||
if (displayLineNumbers) {
|
||||
updateBounds();
|
||||
} else {
|
||||
setBounds(new Rectangle(0, getHeight()));
|
||||
}
|
||||
invalidate();
|
||||
repaint();
|
||||
}
|
||||
|
||||
private void updateBounds() {
|
||||
if (isVisible()) {
|
||||
setBounds(new Rectangle(Math.max(MIN_WIDTH, DIGIT_WIDTH * currNumDigits + PADDING_WIDTH), getHeight()));
|
||||
textArea.validate();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,787 +0,0 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
* TextAreaPainter.java - Paints the text area
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package processing.app.syntax;
|
||||
|
||||
import processing.app.*;
|
||||
import processing.app.syntax.im.CompositionTextPainter;
|
||||
|
||||
import javax.swing.ToolTipManager;
|
||||
import javax.swing.text.*;
|
||||
import javax.swing.JComponent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.*;
|
||||
import java.awt.print.*;
|
||||
|
||||
/**
|
||||
* The text area repaint manager. It performs double buffering and paints
|
||||
* lines of text.
|
||||
* @author Slava Pestov
|
||||
*/
|
||||
public class TextAreaPainter extends JComponent
|
||||
implements TabExpander, Printable
|
||||
{
|
||||
/** True if inside printing, will handle disabling the highlight */
|
||||
boolean printing;
|
||||
/** Current setting for editor.antialias preference */
|
||||
boolean antialias;
|
||||
|
||||
/** A specific painter composed by the InputMethod.*/
|
||||
protected CompositionTextPainter compositionTextPainter;
|
||||
|
||||
/**
|
||||
* Creates a new repaint manager. This should be not be called
|
||||
* directly.
|
||||
*/
|
||||
public TextAreaPainter(JEditTextArea textArea, TextAreaDefaults defaults)
|
||||
{
|
||||
this.textArea = textArea;
|
||||
|
||||
setAutoscrolls(true);
|
||||
setDoubleBuffered(true);
|
||||
setOpaque(true);
|
||||
|
||||
ToolTipManager.sharedInstance().registerComponent(this);
|
||||
|
||||
currentLine = new Segment();
|
||||
currentLineIndex = -1;
|
||||
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
|
||||
|
||||
setFont(defaults.font);
|
||||
setForeground(defaults.fgcolor);
|
||||
setBackground(defaults.bgcolor);
|
||||
|
||||
antialias = PreferencesData.getBoolean("editor.antialias");
|
||||
|
||||
blockCaret = defaults.blockCaret;
|
||||
styles = defaults.styles;
|
||||
cols = defaults.cols;
|
||||
rows = defaults.rows;
|
||||
caretColor = defaults.caretColor;
|
||||
selectionColor = defaults.selectionColor;
|
||||
lineHighlightColor = defaults.lineHighlightColor;
|
||||
lineHighlight = defaults.lineHighlight;
|
||||
bracketHighlightColor = defaults.bracketHighlightColor;
|
||||
bracketHighlight = defaults.bracketHighlight;
|
||||
paintInvalid = defaults.paintInvalid;
|
||||
eolMarkerColor = defaults.eolMarkerColor;
|
||||
eolMarkers = defaults.eolMarkers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get CompositionTextPainter. if CompositionTextPainter is not created, create it.
|
||||
*/
|
||||
public CompositionTextPainter getCompositionTextpainter(){
|
||||
if(compositionTextPainter == null){
|
||||
compositionTextPainter = new CompositionTextPainter(textArea);
|
||||
}
|
||||
return compositionTextPainter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if this component can be traversed by pressing the
|
||||
* Tab key. This returns false.
|
||||
*/
|
||||
// public final boolean isManagingFocus()
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns the syntax styles used to paint colorized text. Entry <i>n</i>
|
||||
* will be used to paint tokens with id = <i>n</i>.
|
||||
* @see processing.app.syntax.Token
|
||||
*/
|
||||
public final SyntaxStyle[] getStyles()
|
||||
{
|
||||
return styles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the syntax styles used to paint colorized text. Entry <i>n</i>
|
||||
* will be used to paint tokens with id = <i>n</i>.
|
||||
* @param styles The syntax styles
|
||||
* @see processing.app.syntax.Token
|
||||
*/
|
||||
public final void setStyles(SyntaxStyle[] styles)
|
||||
{
|
||||
this.styles = styles;
|
||||
repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the caret color.
|
||||
*/
|
||||
public final Color getCaretColor()
|
||||
{
|
||||
return caretColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the caret color.
|
||||
* @param caretColor The caret color
|
||||
*/
|
||||
public final void setCaretColor(Color caretColor)
|
||||
{
|
||||
this.caretColor = caretColor;
|
||||
invalidateSelectedLines();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the selection color.
|
||||
*/
|
||||
public final Color getSelectionColor()
|
||||
{
|
||||
return selectionColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the selection color.
|
||||
* @param selectionColor The selection color
|
||||
*/
|
||||
public final void setSelectionColor(Color selectionColor)
|
||||
{
|
||||
this.selectionColor = selectionColor;
|
||||
invalidateSelectedLines();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the line highlight color.
|
||||
*/
|
||||
public final Color getLineHighlightColor()
|
||||
{
|
||||
return lineHighlightColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the line highlight color.
|
||||
* @param lineHighlightColor The line highlight color
|
||||
*/
|
||||
public final void setLineHighlightColor(Color lineHighlightColor)
|
||||
{
|
||||
this.lineHighlightColor = lineHighlightColor;
|
||||
invalidateSelectedLines();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if line highlight is enabled, false otherwise.
|
||||
*/
|
||||
public final boolean isLineHighlightEnabled()
|
||||
{
|
||||
return lineHighlight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables current line highlighting.
|
||||
* @param lineHighlight True if current line highlight
|
||||
* should be enabled, false otherwise
|
||||
*/
|
||||
public final void setLineHighlightEnabled(boolean lineHighlight)
|
||||
{
|
||||
this.lineHighlight = lineHighlight;
|
||||
invalidateSelectedLines();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bracket highlight color.
|
||||
*/
|
||||
public final Color getBracketHighlightColor()
|
||||
{
|
||||
return bracketHighlightColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bracket highlight color.
|
||||
* @param bracketHighlightColor The bracket highlight color
|
||||
*/
|
||||
public final void setBracketHighlightColor(Color bracketHighlightColor)
|
||||
{
|
||||
this.bracketHighlightColor = bracketHighlightColor;
|
||||
invalidateLine(textArea.getBracketLine());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if bracket highlighting is enabled, false otherwise.
|
||||
* When bracket highlighting is enabled, the bracket matching the
|
||||
* one before the caret (if any) is highlighted.
|
||||
*/
|
||||
public final boolean isBracketHighlightEnabled()
|
||||
{
|
||||
return bracketHighlight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables bracket highlighting.
|
||||
* When bracket highlighting is enabled, the bracket matching the
|
||||
* one before the caret (if any) is highlighted.
|
||||
* @param bracketHighlight True if bracket highlighting should be
|
||||
* enabled, false otherwise
|
||||
*/
|
||||
public final void setBracketHighlightEnabled(boolean bracketHighlight)
|
||||
{
|
||||
this.bracketHighlight = bracketHighlight;
|
||||
invalidateLine(textArea.getBracketLine());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the caret should be drawn as a block, false otherwise.
|
||||
*/
|
||||
public final boolean isBlockCaretEnabled()
|
||||
{
|
||||
return blockCaret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if the caret should be drawn as a block, false otherwise.
|
||||
* @param blockCaret True if the caret should be drawn as a block,
|
||||
* false otherwise.
|
||||
*/
|
||||
public final void setBlockCaretEnabled(boolean blockCaret)
|
||||
{
|
||||
this.blockCaret = blockCaret;
|
||||
invalidateSelectedLines();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the EOL marker color.
|
||||
*/
|
||||
public final Color getEOLMarkerColor()
|
||||
{
|
||||
return eolMarkerColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the EOL marker color.
|
||||
* @param eolMarkerColor The EOL marker color
|
||||
*/
|
||||
public final void setEOLMarkerColor(Color eolMarkerColor)
|
||||
{
|
||||
this.eolMarkerColor = eolMarkerColor;
|
||||
repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if EOL markers are drawn, false otherwise.
|
||||
*/
|
||||
public final boolean getEOLMarkersPainted()
|
||||
{
|
||||
return eolMarkers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if EOL markers are to be drawn.
|
||||
* @param eolMarkers True if EOL markers should be drawn, false otherwise
|
||||
*/
|
||||
public final void setEOLMarkersPainted(boolean eolMarkers)
|
||||
{
|
||||
this.eolMarkers = eolMarkers;
|
||||
repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if invalid lines are painted as red tildes (~),
|
||||
* false otherwise.
|
||||
*/
|
||||
public boolean getInvalidLinesPainted()
|
||||
{
|
||||
return paintInvalid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if invalid lines are to be painted as red tildes.
|
||||
* @param paintInvalid True if invalid lines should be drawn, false otherwise
|
||||
*/
|
||||
public void setInvalidLinesPainted(boolean paintInvalid)
|
||||
{
|
||||
this.paintInvalid = paintInvalid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a custom highlight painter.
|
||||
* @param highlight The highlight
|
||||
*/
|
||||
public void addCustomHighlight(Highlight highlight)
|
||||
{
|
||||
highlight.init(textArea,highlights);
|
||||
highlights = highlight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight interface.
|
||||
*/
|
||||
public interface Highlight
|
||||
{
|
||||
/**
|
||||
* Called after the highlight painter has been added.
|
||||
* @param textArea The text area
|
||||
* @param next The painter this one should delegate to
|
||||
*/
|
||||
void init(JEditTextArea textArea, Highlight next);
|
||||
|
||||
/**
|
||||
* This should paint the highlight and delgate to the
|
||||
* next highlight painter.
|
||||
* @param gfx The graphics context
|
||||
* @param line The line number
|
||||
* @param y The y co-ordinate of the line
|
||||
*/
|
||||
void paintHighlight(Graphics gfx, int line, int y);
|
||||
|
||||
/**
|
||||
* Returns the tool tip to display at the specified
|
||||
* location. If this highlighter doesn't know what to
|
||||
* display, it should delegate to the next highlight
|
||||
* painter.
|
||||
* @param evt The mouse event
|
||||
*/
|
||||
String getToolTipText(MouseEvent evt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tool tip to display at the specified location.
|
||||
* @param evt The mouse event
|
||||
*/
|
||||
public String getToolTipText(MouseEvent evt)
|
||||
{
|
||||
if(highlights != null)
|
||||
return highlights.getToolTipText(evt);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the font metrics used by this component.
|
||||
*/
|
||||
public FontMetrics getFontMetrics()
|
||||
{
|
||||
return fm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the font for this component. This is overridden to update the
|
||||
* cached font metrics and to recalculate which lines are visible.
|
||||
* @param font The font
|
||||
*/
|
||||
public void setFont(Font font)
|
||||
{
|
||||
super.setFont(font);
|
||||
fm = super.getFontMetrics(font);
|
||||
textArea.recalculateVisibleLines();
|
||||
}
|
||||
|
||||
/**
|
||||
* Repaints the text.
|
||||
* @param gfx The graphics context
|
||||
*/
|
||||
public void paint(Graphics gfx)
|
||||
{
|
||||
Graphics2D g2 = (Graphics2D) gfx;
|
||||
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
|
||||
antialias ?
|
||||
RenderingHints.VALUE_TEXT_ANTIALIAS_ON :
|
||||
RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
|
||||
|
||||
tabSize = fm.charWidth(' ') * ((Integer)textArea.getDocument().getProperty(PlainDocument.tabSizeAttribute)).intValue();
|
||||
|
||||
Rectangle clipRect = gfx.getClipBounds();
|
||||
|
||||
gfx.setColor(getBackground());
|
||||
gfx.fillRect(clipRect.x,clipRect.y,clipRect.width,clipRect.height);
|
||||
|
||||
// We don't use yToLine() here because that method doesn't
|
||||
// return lines past the end of the document
|
||||
int height = fm.getHeight();
|
||||
int firstLine = textArea.getFirstLine();
|
||||
int firstInvalid = firstLine + clipRect.y / height;
|
||||
// Because the clipRect's height is usually an even multiple
|
||||
// of the font height, we subtract 1 from it, otherwise one
|
||||
// too many lines will always be painted.
|
||||
int lastInvalid = firstLine + (clipRect.y + clipRect.height - 1) / height;
|
||||
|
||||
try {
|
||||
TokenMarker tokenMarker = textArea.getDocument().getTokenMarker();
|
||||
int x = textArea.getHorizontalOffset();
|
||||
|
||||
for (int line = firstInvalid; line <= lastInvalid; line++) {
|
||||
paintLine(gfx,tokenMarker,line,x);
|
||||
}
|
||||
|
||||
if (tokenMarker != null && tokenMarker.isNextLineRequested()) {
|
||||
int h = clipRect.y + clipRect.height;
|
||||
repaint(0,h,getWidth(),getHeight() - h);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("Error repainting line"
|
||||
+ " range {" + firstInvalid + ","
|
||||
+ lastInvalid + "}:");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public int print(Graphics g, PageFormat pageFormat, int pageIndex) {
|
||||
int lineHeight = fm.getHeight();
|
||||
int linesPerPage = (int) (pageFormat.getImageableHeight() / lineHeight);
|
||||
int lineCount = textArea.getLineCount();
|
||||
int lastPage = lineCount / linesPerPage;
|
||||
|
||||
if (pageIndex > lastPage) {
|
||||
return NO_SUCH_PAGE;
|
||||
|
||||
} else {
|
||||
Graphics2D g2d = (Graphics2D)g;
|
||||
TokenMarker tokenMarker = textArea.getDocument().getTokenMarker();
|
||||
int firstLine = pageIndex*linesPerPage;
|
||||
g2d.translate(Math.max(54, pageFormat.getImageableX()),
|
||||
pageFormat.getImageableY() - firstLine*lineHeight);
|
||||
printing = true;
|
||||
for (int line = firstLine; line < firstLine + linesPerPage; line++) {
|
||||
paintLine(g2d, tokenMarker, line, 0);
|
||||
}
|
||||
printing = false;
|
||||
return PAGE_EXISTS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Marks a line as needing a repaint.
|
||||
* @param line The line to invalidate
|
||||
*/
|
||||
public final void invalidateLine(int line)
|
||||
{
|
||||
repaint(0,textArea.lineToY(line) + fm.getMaxDescent() + fm.getLeading(),
|
||||
getWidth(),fm.getHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks a range of lines as needing a repaint.
|
||||
* @param firstLine The first line to invalidate
|
||||
* @param lastLine The last line to invalidate
|
||||
*/
|
||||
public final void invalidateLineRange(int firstLine, int lastLine)
|
||||
{
|
||||
repaint(0,textArea.lineToY(firstLine) +
|
||||
fm.getMaxDescent() + fm.getLeading(),
|
||||
getWidth(),(lastLine - firstLine + 1) * fm.getHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
* Repaints the lines containing the selection.
|
||||
*/
|
||||
public final void invalidateSelectedLines()
|
||||
{
|
||||
invalidateLineRange(textArea.getSelectionStartLine(),
|
||||
textArea.getSelectionStopLine());
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of TabExpander interface. Returns next tab stop after
|
||||
* a specified point.
|
||||
* @param x The x co-ordinate
|
||||
* @param tabOffset Ignored
|
||||
* @return The next tab stop after <i>x</i>
|
||||
*/
|
||||
public float nextTabStop(float x, int tabOffset)
|
||||
{
|
||||
int offset = textArea.getHorizontalOffset();
|
||||
int ntabs = ((int)x - offset) / tabSize;
|
||||
return (ntabs + 1) * tabSize + offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the painter's preferred size.
|
||||
*/
|
||||
public Dimension getPreferredSize()
|
||||
{
|
||||
Dimension dim = new Dimension();
|
||||
dim.width = fm.charWidth('w') * cols;
|
||||
dim.height = fm.getHeight() * rows;
|
||||
return dim;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the painter's minimum size.
|
||||
*/
|
||||
public Dimension getMinimumSize()
|
||||
{
|
||||
Dimension dim = new Dimension();
|
||||
dim.width = fm.charWidth('w') * 10;
|
||||
dim.height = fm.getHeight() * 4;
|
||||
return dim;
|
||||
}
|
||||
|
||||
// package-private members
|
||||
int currentLineIndex;
|
||||
Token currentLineTokens;
|
||||
Segment currentLine;
|
||||
|
||||
/**
|
||||
* Accessor used by tools that want to hook in and grab the formatting.
|
||||
*/
|
||||
public int getCurrentLineIndex() {
|
||||
return currentLineIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor used by tools that want to hook in and grab the formatting.
|
||||
*/
|
||||
public void setCurrentLineIndex(int what) {
|
||||
currentLineIndex = what;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor used by tools that want to hook in and grab the formatting.
|
||||
*/
|
||||
public Token getCurrentLineTokens() {
|
||||
return currentLineTokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor used by tools that want to hook in and grab the formatting.
|
||||
*/
|
||||
public void setCurrentLineTokens(Token tokens) {
|
||||
currentLineTokens = tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor used by tools that want to hook in and grab the formatting.
|
||||
*/
|
||||
public Segment getCurrentLine() {
|
||||
return currentLine;
|
||||
}
|
||||
|
||||
|
||||
// protected members
|
||||
protected JEditTextArea textArea;
|
||||
|
||||
protected SyntaxStyle[] styles;
|
||||
protected Color caretColor;
|
||||
protected Color selectionColor;
|
||||
protected Color lineHighlightColor;
|
||||
protected Color bracketHighlightColor;
|
||||
protected Color eolMarkerColor;
|
||||
|
||||
protected boolean blockCaret;
|
||||
protected boolean lineHighlight;
|
||||
protected boolean bracketHighlight;
|
||||
protected boolean paintInvalid;
|
||||
protected boolean eolMarkers;
|
||||
protected int cols;
|
||||
protected int rows;
|
||||
|
||||
protected int tabSize;
|
||||
protected FontMetrics fm;
|
||||
|
||||
protected Highlight highlights;
|
||||
|
||||
protected void paintLine(Graphics gfx, TokenMarker tokenMarker,
|
||||
int line, int x)
|
||||
{
|
||||
Font defaultFont = getFont();
|
||||
Color defaultColor = getForeground();
|
||||
|
||||
currentLineIndex = line;
|
||||
int y = textArea.lineToY(line);
|
||||
|
||||
if (line < 0 || line >= textArea.getLineCount()) {
|
||||
if (paintInvalid) {
|
||||
paintHighlight(gfx,line,y);
|
||||
styles[Token.INVALID].setGraphicsFlags(gfx,defaultFont);
|
||||
gfx.drawString("~",0,y + fm.getHeight());
|
||||
}
|
||||
} else if(tokenMarker == null) {
|
||||
paintPlainLine(gfx,line,defaultFont,defaultColor,x,y);
|
||||
} else {
|
||||
paintSyntaxLine(gfx,tokenMarker,line,defaultFont,
|
||||
defaultColor,x,y);
|
||||
}
|
||||
}
|
||||
|
||||
protected void paintPlainLine(Graphics gfx, int line, Font defaultFont,
|
||||
Color defaultColor, int x, int y)
|
||||
{
|
||||
paintHighlight(gfx,line,y);
|
||||
textArea.getLineText(line,currentLine);
|
||||
|
||||
gfx.setFont(defaultFont);
|
||||
gfx.setColor(defaultColor);
|
||||
|
||||
y += fm.getHeight();
|
||||
x = Utilities.drawTabbedText(currentLine,x,y,gfx,this,0);
|
||||
/*
|
||||
* Draw characters via input method.
|
||||
*/
|
||||
if (compositionTextPainter != null && compositionTextPainter.hasComposedTextLayout()) {
|
||||
compositionTextPainter.draw(gfx, lineHighlightColor);
|
||||
}
|
||||
if (eolMarkers) {
|
||||
gfx.setColor(eolMarkerColor);
|
||||
gfx.drawString(".",x,y);
|
||||
}
|
||||
}
|
||||
|
||||
protected void paintSyntaxLine(Graphics gfx, TokenMarker tokenMarker,
|
||||
int line, Font defaultFont,
|
||||
Color defaultColor, int x, int y)
|
||||
{
|
||||
textArea.getLineText(currentLineIndex,currentLine);
|
||||
currentLineTokens = tokenMarker.markTokens(currentLine,
|
||||
currentLineIndex);
|
||||
|
||||
paintHighlight(gfx,line,y);
|
||||
|
||||
gfx.setFont(defaultFont);
|
||||
gfx.setColor(defaultColor);
|
||||
y += fm.getHeight();
|
||||
x = SyntaxUtilities.paintSyntaxLine(currentLine,
|
||||
currentLineTokens,
|
||||
styles, this, gfx, x, y);
|
||||
/*
|
||||
* Draw characters via input method.
|
||||
*/
|
||||
if (compositionTextPainter != null && compositionTextPainter.hasComposedTextLayout()) {
|
||||
compositionTextPainter.draw(gfx, lineHighlightColor);
|
||||
}
|
||||
if (eolMarkers) {
|
||||
gfx.setColor(eolMarkerColor);
|
||||
gfx.drawString(".",x,y);
|
||||
}
|
||||
}
|
||||
|
||||
protected void paintHighlight(Graphics gfx, int line, int y)
|
||||
{
|
||||
if (!printing) {
|
||||
if (line >= textArea.getSelectionStartLine()
|
||||
&& line <= textArea.getSelectionStopLine())
|
||||
paintLineHighlight(gfx,line,y);
|
||||
|
||||
if (highlights != null)
|
||||
highlights.paintHighlight(gfx,line,y);
|
||||
|
||||
if (bracketHighlight && line == textArea.getBracketLine())
|
||||
paintBracketHighlight(gfx,line,y);
|
||||
|
||||
if (line == textArea.getCaretLine())
|
||||
paintCaret(gfx,line,y);
|
||||
}
|
||||
}
|
||||
|
||||
protected void paintLineHighlight(Graphics gfx, int line, int y)
|
||||
{
|
||||
int height = fm.getHeight();
|
||||
y += fm.getLeading() + fm.getMaxDescent();
|
||||
|
||||
int selectionStart = textArea.getSelectionStart();
|
||||
int selectionEnd = textArea.getSelectionStop();
|
||||
|
||||
if (selectionStart == selectionEnd) {
|
||||
if (lineHighlight) {
|
||||
gfx.setColor(lineHighlightColor);
|
||||
gfx.fillRect(0,y,getWidth(),height);
|
||||
}
|
||||
} else {
|
||||
gfx.setColor(selectionColor);
|
||||
|
||||
int selectionStartLine = textArea.getSelectionStartLine();
|
||||
int selectionEndLine = textArea.getSelectionStopLine();
|
||||
int lineStart = textArea.getLineStartOffset(line);
|
||||
|
||||
int x1, x2;
|
||||
if (textArea.isSelectionRectangular()) {
|
||||
int lineLen = textArea.getLineLength(line);
|
||||
x1 = textArea._offsetToX(line,Math.min(lineLen, selectionStart - textArea.getLineStartOffset(selectionStartLine)));
|
||||
x2 = textArea._offsetToX(line,Math.min(lineLen, selectionEnd - textArea.getLineStartOffset(selectionEndLine)));
|
||||
if (x1 == x2)
|
||||
x2++;
|
||||
} else if(selectionStartLine == selectionEndLine) {
|
||||
x1 = textArea._offsetToX(line, selectionStart - lineStart);
|
||||
x2 = textArea._offsetToX(line, selectionEnd - lineStart);
|
||||
} else if(line == selectionStartLine) {
|
||||
x1 = textArea._offsetToX(line, selectionStart - lineStart);
|
||||
x2 = getWidth();
|
||||
} else if(line == selectionEndLine) {
|
||||
//x1 = 0;
|
||||
// hack from stendahl to avoid doing weird side selection thing
|
||||
x1 = textArea._offsetToX(line, 0);
|
||||
// attempt at getting the gutter too, but doesn't seem to work
|
||||
//x1 = textArea._offsetToX(line, -textArea.getHorizontalOffset());
|
||||
x2 = textArea._offsetToX(line, selectionEnd - lineStart);
|
||||
} else {
|
||||
//x1 = 0;
|
||||
// hack from stendahl to avoid doing weird side selection thing
|
||||
x1 = textArea._offsetToX(line, 0);
|
||||
// attempt at getting the gutter too, but doesn't seem to work
|
||||
//x1 = textArea._offsetToX(line, -textArea.getHorizontalOffset());
|
||||
x2 = getWidth();
|
||||
}
|
||||
|
||||
// "inlined" min/max()
|
||||
gfx.fillRect(x1 > x2 ? x2 : x1,y,x1 > x2 ?
|
||||
(x1 - x2) : (x2 - x1),height);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void paintBracketHighlight(Graphics gfx, int line, int y)
|
||||
{
|
||||
int position = textArea.getBracketPosition();
|
||||
if(position == -1)
|
||||
return;
|
||||
y += fm.getLeading() + fm.getMaxDescent();
|
||||
int x = textArea._offsetToX(line,position);
|
||||
gfx.setColor(bracketHighlightColor);
|
||||
// Hack!!! Since there is no fast way to get the character
|
||||
// from the bracket matching routine, we use ( since all
|
||||
// brackets probably have the same width anyway
|
||||
gfx.drawRect(x,y,fm.charWidth('(') - 1,
|
||||
fm.getHeight() - 1);
|
||||
}
|
||||
|
||||
protected void paintCaret(Graphics gfx, int line, int y)
|
||||
{
|
||||
//System.out.println("painting caret " + line + " " + y);
|
||||
if (textArea.isCaretVisible()) {
|
||||
//System.out.println("caret is visible");
|
||||
int offset =
|
||||
textArea.getCaretPosition() - textArea.getLineStartOffset(line);
|
||||
int caretX = textArea._offsetToX(line, offset);
|
||||
int caretWidth = ((blockCaret ||
|
||||
textArea.isOverwriteEnabled()) ?
|
||||
fm.charWidth('w') : 1);
|
||||
y += fm.getLeading() + fm.getMaxDescent();
|
||||
int height = fm.getHeight();
|
||||
|
||||
//System.out.println("caretX, width = " + caretX + " " + caretWidth);
|
||||
|
||||
gfx.setColor(caretColor);
|
||||
|
||||
if (textArea.isOverwriteEnabled()) {
|
||||
gfx.fillRect(caretX,y + height - 1, caretWidth,1);
|
||||
|
||||
} else {
|
||||
// some machines don't like the drawRect for the single
|
||||
// pixel caret.. this caused a lot of hell because on that
|
||||
// minority of machines, the caret wouldn't show up past
|
||||
// the first column. the fix is to use drawLine() in
|
||||
// those cases, as a workaround.
|
||||
if (caretWidth == 1) {
|
||||
gfx.drawLine(caretX, y, caretX, y + height - 1);
|
||||
} else {
|
||||
gfx.drawRect(caretX, y, caretWidth - 1, height - 1);
|
||||
}
|
||||
//gfx.drawRect(caretX, y, caretWidth, height - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,183 +0,0 @@
|
||||
/*
|
||||
* TextUtilities.java - Utility functions used by the text area classes
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package processing.app.syntax;
|
||||
|
||||
import javax.swing.text.*;
|
||||
|
||||
/**
|
||||
* Class with several utility functions used by the text area component.
|
||||
* @author Slava Pestov
|
||||
*/
|
||||
public 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
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates the start of the word at the specified position.
|
||||
* @param line The text
|
||||
* @param pos The position
|
||||
*/
|
||||
public static int findWordStart(String line, int pos, String noWordSep)
|
||||
{
|
||||
char ch = line.charAt(pos - 1);
|
||||
|
||||
if(noWordSep == null)
|
||||
noWordSep = "";
|
||||
boolean selectNoLetter = (!Character.isLetterOrDigit(ch)
|
||||
&& noWordSep.indexOf(ch) == -1);
|
||||
|
||||
int wordStart = 0;
|
||||
for(int i = pos - 1; i >= 0; i--)
|
||||
{
|
||||
ch = line.charAt(i);
|
||||
if(selectNoLetter ^ (!Character.isLetterOrDigit(ch) &&
|
||||
noWordSep.indexOf(ch) == -1))
|
||||
{
|
||||
wordStart = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return wordStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates the end of the word at the specified position.
|
||||
* @param line The text
|
||||
* @param pos The position
|
||||
*/
|
||||
public static int findWordEnd(String line, int pos, String noWordSep)
|
||||
{
|
||||
char ch = line.charAt(pos);
|
||||
|
||||
if(noWordSep == null)
|
||||
noWordSep = "";
|
||||
boolean selectNoLetter = (!Character.isLetterOrDigit(ch)
|
||||
&& noWordSep.indexOf(ch) == -1);
|
||||
|
||||
int wordEnd = line.length();
|
||||
for(int i = pos; i < line.length(); i++)
|
||||
{
|
||||
ch = line.charAt(i);
|
||||
if(selectNoLetter ^ (!Character.isLetterOrDigit(ch) &&
|
||||
noWordSep.indexOf(ch) == -1))
|
||||
{
|
||||
wordEnd = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return wordEnd;
|
||||
}
|
||||
}
|
@ -1,341 +0,0 @@
|
||||
/*
|
||||
* TokenMarker.java - Generic token marker
|
||||
* Copyright (C) 1998, 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.
|
||||
*/
|
||||
|
||||
package processing.app.syntax;
|
||||
|
||||
import javax.swing.text.Segment;
|
||||
|
||||
/**
|
||||
* A token marker that splits lines of text into tokens. Each token carries
|
||||
* a length field and an indentification tag that can be mapped to a color
|
||||
* for painting that token.<p>
|
||||
*
|
||||
* For performance reasons, the linked list of tokens is reused after each
|
||||
* line is tokenized. Therefore, the return value of <code>markTokens</code>
|
||||
* should only be used for immediate painting. Notably, it cannot be
|
||||
* cached.
|
||||
*
|
||||
* @author Slava Pestov
|
||||
*/
|
||||
public abstract class TokenMarker
|
||||
{
|
||||
/**
|
||||
* A wrapper for the lower-level <code>markTokensImpl</code> method
|
||||
* that is called to split a line up into tokens.
|
||||
* @param line The line
|
||||
* @param lineIndex The line number
|
||||
*/
|
||||
public Token markTokens(Segment line, int lineIndex)
|
||||
{
|
||||
if(lineIndex >= length)
|
||||
{
|
||||
throw new IllegalArgumentException("Tokenizing invalid line: "
|
||||
+ lineIndex);
|
||||
}
|
||||
|
||||
lastToken = null;
|
||||
|
||||
LineInfo info = lineInfo[lineIndex];
|
||||
LineInfo prev;
|
||||
if(lineIndex == 0)
|
||||
prev = null;
|
||||
else
|
||||
prev = lineInfo[lineIndex - 1];
|
||||
|
||||
byte oldToken = info.token;
|
||||
byte token = markTokensImpl(prev == null ?
|
||||
Token.NULL : prev.token,line,lineIndex);
|
||||
|
||||
info.token = token;
|
||||
|
||||
/*
|
||||
* This is a foul hack. It stops nextLineRequested
|
||||
* from being cleared if the same line is marked twice.
|
||||
*
|
||||
* Why is this necessary? It's all JEditTextArea's fault.
|
||||
* When something is inserted into the text, firing a
|
||||
* document event, the insertUpdate() method shifts the
|
||||
* caret (if necessary) by the amount inserted.
|
||||
*
|
||||
* All caret movement is handled by the select() method,
|
||||
* which eventually pipes the new position to scrollTo()
|
||||
* and calls repaint().
|
||||
*
|
||||
* Note that at this point in time, the new line hasn't
|
||||
* yet been painted; the caret is moved first.
|
||||
*
|
||||
* scrollTo() calls offsetToX(), which tokenizes the line
|
||||
* unless it is being called on the last line painted
|
||||
* (in which case it uses the text area's painter cached
|
||||
* token list). What scrollTo() does next is irrelevant.
|
||||
*
|
||||
* After scrollTo() has done it's job, repaint() is
|
||||
* called, and eventually we end up in paintLine(), whose
|
||||
* job is to paint the changed line. It, too, calls
|
||||
* markTokens().
|
||||
*
|
||||
* The problem was that if the line started a multiline
|
||||
* token, the first markTokens() (done in offsetToX())
|
||||
* would set nextLineRequested (because the line end
|
||||
* token had changed) but the second would clear it
|
||||
* (because the line was the same that time) and therefore
|
||||
* paintLine() would never know that it needed to repaint
|
||||
* subsequent lines.
|
||||
*
|
||||
* This bug took me ages to track down, that's why I wrote
|
||||
* all the relevant info down so that others wouldn't
|
||||
* duplicate it.
|
||||
*/
|
||||
if(!(lastLine == lineIndex && nextLineRequested))
|
||||
nextLineRequested = (oldToken != token);
|
||||
|
||||
lastLine = lineIndex;
|
||||
|
||||
addToken(0,Token.END);
|
||||
|
||||
return firstToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* An abstract method that splits a line up into tokens. It
|
||||
* should parse the line, and call <code>addToken()</code> to
|
||||
* add syntax tokens to the token list. Then, it should return
|
||||
* the initial token type for the next line.<p>
|
||||
*
|
||||
* For example if the current line contains the start of a
|
||||
* multiline comment that doesn't end on that line, this method
|
||||
* should return the comment token type so that it continues on
|
||||
* the next line.
|
||||
*
|
||||
* @param token The initial token type for this line
|
||||
* @param line The line to be tokenized
|
||||
* @param lineIndex The index of the line in the document,
|
||||
* starting at 0
|
||||
* @return The initial token type for the next line
|
||||
*/
|
||||
protected abstract byte markTokensImpl(byte token, Segment line,
|
||||
int lineIndex);
|
||||
|
||||
/**
|
||||
* Returns if the token marker supports tokens that span multiple
|
||||
* lines. If this is true, the object using this token marker is
|
||||
* required to pass all lines in the document to the
|
||||
* <code>markTokens()</code> method (in turn).<p>
|
||||
*
|
||||
* The default implementation returns true; it should be overridden
|
||||
* to return false on simpler token markers for increased speed.
|
||||
*/
|
||||
public boolean supportsMultilineTokens()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Informs the token marker that lines have been inserted into
|
||||
* the document. This inserts a gap in the <code>lineInfo</code>
|
||||
* array.
|
||||
* @param index The first line number
|
||||
* @param lines The number of lines
|
||||
*/
|
||||
public void insertLines(int index, int lines)
|
||||
{
|
||||
if(lines <= 0)
|
||||
return;
|
||||
length += lines;
|
||||
ensureCapacity(length);
|
||||
int len = index + lines;
|
||||
System.arraycopy(lineInfo,index,lineInfo,len,
|
||||
lineInfo.length - len);
|
||||
|
||||
for(int i = index + lines - 1; i >= index; i--)
|
||||
{
|
||||
lineInfo[i] = new LineInfo();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Informs the token marker that line have been deleted from
|
||||
* the document. This removes the lines in question from the
|
||||
* <code>lineInfo</code> array.
|
||||
* @param index The first line number
|
||||
* @param lines The number of lines
|
||||
*/
|
||||
public void deleteLines(int index, int lines)
|
||||
{
|
||||
if (lines <= 0)
|
||||
return;
|
||||
int len = index + lines;
|
||||
length -= lines;
|
||||
System.arraycopy(lineInfo,len,lineInfo,
|
||||
index,lineInfo.length - len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of lines in this token marker.
|
||||
*/
|
||||
public int getLineCount()
|
||||
{
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the next line should be repainted. This
|
||||
* will return true after a line has been tokenized that starts
|
||||
* a multiline token that continues onto the next line.
|
||||
*/
|
||||
public boolean isNextLineRequested()
|
||||
{
|
||||
return nextLineRequested;
|
||||
}
|
||||
|
||||
// protected members
|
||||
|
||||
/**
|
||||
* The first token in the list. This should be used as the return
|
||||
* value from <code>markTokens()</code>.
|
||||
*/
|
||||
protected Token firstToken;
|
||||
|
||||
/**
|
||||
* The last token in the list. New tokens are added here.
|
||||
* This should be set to null before a new line is to be tokenized.
|
||||
*/
|
||||
protected Token lastToken;
|
||||
|
||||
/**
|
||||
* An array for storing information about lines. It is enlarged and
|
||||
* shrunk automatically by the <code>insertLines()</code> and
|
||||
* <code>deleteLines()</code> methods.
|
||||
*/
|
||||
protected LineInfo[] lineInfo;
|
||||
|
||||
/**
|
||||
* The number of lines in the model being tokenized. This can be
|
||||
* less than the length of the <code>lineInfo</code> array.
|
||||
*/
|
||||
protected int length;
|
||||
|
||||
/**
|
||||
* The last tokenized line.
|
||||
*/
|
||||
protected int lastLine;
|
||||
|
||||
/**
|
||||
* True if the next line should be painted.
|
||||
*/
|
||||
protected boolean nextLineRequested;
|
||||
|
||||
/**
|
||||
* Creates a new <code>TokenMarker</code>. This DOES NOT create
|
||||
* a lineInfo array; an initial call to <code>insertLines()</code>
|
||||
* does that.
|
||||
*/
|
||||
protected TokenMarker()
|
||||
{
|
||||
lastLine = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the <code>lineInfo</code> array can contain the
|
||||
* specified index. This enlarges it if necessary. No action is
|
||||
* taken if the array is large enough already.<p>
|
||||
*
|
||||
* It should be unnecessary to call this under normal
|
||||
* circumstances; <code>insertLine()</code> should take care of
|
||||
* enlarging the line info array automatically.
|
||||
*
|
||||
* @param index The array index
|
||||
*/
|
||||
protected void ensureCapacity(int index)
|
||||
{
|
||||
if(lineInfo == null)
|
||||
lineInfo = new LineInfo[index + 1];
|
||||
else if(lineInfo.length <= index)
|
||||
{
|
||||
LineInfo[] lineInfoN = new LineInfo[(index + 1) * 2];
|
||||
System.arraycopy(lineInfo,0,lineInfoN,0,
|
||||
lineInfo.length);
|
||||
lineInfo = lineInfoN;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a token to the token list.
|
||||
* @param length The length of the token
|
||||
* @param id The id of the token
|
||||
*/
|
||||
protected void addToken(int length, byte id)
|
||||
{
|
||||
if(id >= Token.INTERNAL_FIRST && id <= Token.INTERNAL_LAST)
|
||||
throw new InternalError("Invalid id: " + id);
|
||||
|
||||
if(length == 0 && id != Token.END)
|
||||
return;
|
||||
|
||||
if(firstToken == null)
|
||||
{
|
||||
firstToken = new Token(length,id);
|
||||
lastToken = firstToken;
|
||||
}
|
||||
else if(lastToken == null)
|
||||
{
|
||||
lastToken = firstToken;
|
||||
firstToken.length = length;
|
||||
firstToken.id = id;
|
||||
}
|
||||
else if(lastToken.next == null)
|
||||
{
|
||||
lastToken.next = new Token(length,id);
|
||||
lastToken = lastToken.next;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastToken = lastToken.next;
|
||||
lastToken.length = length;
|
||||
lastToken.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inner class for storing information about tokenized lines.
|
||||
*/
|
||||
public class LineInfo
|
||||
{
|
||||
/**
|
||||
* Creates a new LineInfo object with token = Token.NULL
|
||||
* and obj = null.
|
||||
*/
|
||||
public LineInfo()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new LineInfo object with the specified
|
||||
* parameters.
|
||||
*/
|
||||
public LineInfo(byte token, Object obj)
|
||||
{
|
||||
this.token = token;
|
||||
this.obj = obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* The id of the last token of the line.
|
||||
*/
|
||||
public byte token;
|
||||
|
||||
/**
|
||||
* This is for use by the token marker implementations
|
||||
* themselves. It can be used to store anything that
|
||||
* is an object and that needs to exist on a per-line
|
||||
* basis.
|
||||
*/
|
||||
public Object obj;
|
||||
}
|
||||
}
|
@ -1,198 +0,0 @@
|
||||
package processing.app.syntax.im;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.font.TextAttribute;
|
||||
import java.awt.font.TextLayout;
|
||||
import java.text.AttributedCharacterIterator;
|
||||
import java.text.AttributedString;
|
||||
|
||||
import javax.swing.text.BadLocationException;
|
||||
|
||||
import processing.app.syntax.JEditTextArea;
|
||||
import processing.app.syntax.TextAreaPainter;
|
||||
|
||||
/**
|
||||
* This class Manage texts from input method
|
||||
* by begin-process-end steps.
|
||||
*
|
||||
* First, if a user start inputing via input method,
|
||||
* beginCompositionText is called from InputMethodSupport.
|
||||
* Second, the user continues from input method, processCompositionText is called
|
||||
* and reflect user inputs to text area.
|
||||
* Finally the user try to commit text, endCompositionText is called.
|
||||
*
|
||||
* @author Takashi Maekawa (takachin@generative.info)
|
||||
*/
|
||||
|
||||
public class CompositionTextManager {
|
||||
private JEditTextArea textArea;
|
||||
private String prevComposeString;
|
||||
private int prevCommittedCount;
|
||||
private boolean isInputProcess;
|
||||
private int initialCaretPosition;
|
||||
public static final int COMPOSING_UNDERBAR_HEIGHT = 5;
|
||||
|
||||
/**
|
||||
* Create text manager class with a textarea.
|
||||
* @param textArea texarea component for PDE.
|
||||
*/
|
||||
public CompositionTextManager(JEditTextArea textArea) {
|
||||
this.textArea = textArea;
|
||||
prevComposeString = "";
|
||||
isInputProcess = false;
|
||||
prevCommittedCount = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this text manager is whether in input process or not.
|
||||
*/
|
||||
public boolean getIsInputProcess() {
|
||||
return isInputProcess;
|
||||
}
|
||||
/**
|
||||
* Insert full width space
|
||||
*/
|
||||
public void insertFullWidthSpace() {
|
||||
initialCaretPosition = textArea.getCaretPosition();
|
||||
int layoutCaretPosition = initialCaretPosition;
|
||||
try {
|
||||
textArea.getDocument().insertString(layoutCaretPosition, "\u3000", null);
|
||||
} catch (BadLocationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a user begins input from input method.
|
||||
* This method initializes text manager.
|
||||
*
|
||||
* @param text Text from InputMethodEvent.
|
||||
* @param commited_count Numbers of committed characters in text.
|
||||
*/
|
||||
public void beginCompositionText(AttributedCharacterIterator text, int committed_count) {
|
||||
isInputProcess = true;
|
||||
prevComposeString = "";
|
||||
initialCaretPosition = textArea.getCaretPosition();
|
||||
processCompositionText(text, committed_count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a user processing input characters and
|
||||
* select candidates from input method.
|
||||
*
|
||||
* @param text Text from InputMethodEvent.
|
||||
* @param commited_count Numbers of committed characters in text.
|
||||
*/
|
||||
public void processCompositionText(AttributedCharacterIterator text, int committed_count) {
|
||||
int layoutCaretPosition = initialCaretPosition + committed_count;
|
||||
CompositionTextPainter compositionPainter = textArea.getPainter().getCompositionTextpainter();
|
||||
compositionPainter.setComposedTextLayout(getTextLayout(text, committed_count), layoutCaretPosition);
|
||||
int textLength = text.getEndIndex() - text.getBeginIndex() - committed_count;
|
||||
StringBuffer unCommitedStringBuf = new StringBuffer(textLength);
|
||||
char c;
|
||||
for (c = text.setIndex(committed_count); c != AttributedCharacterIterator.DONE
|
||||
&& textLength > 0; c = text.next(), --textLength) {
|
||||
unCommitedStringBuf.append(c);
|
||||
}
|
||||
String unCommittedString = unCommitedStringBuf.toString();
|
||||
try {
|
||||
if(canRemovePreviousInput(committed_count)){
|
||||
textArea.getDocument().remove(layoutCaretPosition, prevComposeString.length());
|
||||
}
|
||||
textArea.getDocument().insertString(layoutCaretPosition, unCommittedString, null);
|
||||
if(committed_count > 0){
|
||||
initialCaretPosition = initialCaretPosition + committed_count;
|
||||
}
|
||||
prevComposeString = unCommittedString;
|
||||
prevCommittedCount = committed_count;
|
||||
} catch (BadLocationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean canRemovePreviousInput(int committed_count){
|
||||
return (prevCommittedCount == committed_count || prevCommittedCount > committed_count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a user fixed text from input method or delete all
|
||||
* composition text. This method resets CompositionTextPainter.
|
||||
*
|
||||
* @param text Text from InputMethodEvent.
|
||||
* @param commited_count Numbers of committed characters in text.
|
||||
*/
|
||||
public void endCompositionText(AttributedCharacterIterator text, int committed_count) {
|
||||
/*
|
||||
* If there are no committed characters, remove it all from textarea.
|
||||
* This case will happen if a user delete all composing characters by backspace or delete key.
|
||||
* If it does, these previous characters are needed to be deleted.
|
||||
*/
|
||||
if(committed_count == 0){
|
||||
removeNotCommittedText(text);
|
||||
}
|
||||
CompositionTextPainter compositionPainter = textArea.getPainter().getCompositionTextpainter();
|
||||
compositionPainter.invalidateComposedTextLayout(initialCaretPosition + committed_count);
|
||||
prevComposeString = "";
|
||||
isInputProcess = false;
|
||||
}
|
||||
|
||||
private void removeNotCommittedText(AttributedCharacterIterator text){
|
||||
if (prevComposeString.length() == 0) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
textArea.getDocument().remove(initialCaretPosition, prevComposeString.length());
|
||||
} catch (BadLocationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private TextLayout getTextLayout(AttributedCharacterIterator text, int committed_count) {
|
||||
AttributedString composed = new AttributedString(text, committed_count, text.getEndIndex());
|
||||
Font font = textArea.getPainter().getFont();
|
||||
FontRenderContext context = ((Graphics2D) (textArea.getPainter().getGraphics())).getFontRenderContext();
|
||||
composed.addAttribute(TextAttribute.FONT, font);
|
||||
TextLayout layout = new TextLayout(composed.getIterator(), context);
|
||||
return layout;
|
||||
}
|
||||
|
||||
private Point getCaretLocation() {
|
||||
Point loc = new Point();
|
||||
TextAreaPainter painter = textArea.getPainter();
|
||||
FontMetrics fm = painter.getFontMetrics();
|
||||
int offsetY = fm.getHeight() - COMPOSING_UNDERBAR_HEIGHT;
|
||||
int lineIndex = textArea.getCaretLine();
|
||||
loc.y = lineIndex * fm.getHeight() + offsetY;
|
||||
int offsetX = textArea.getCaretPosition()
|
||||
- textArea.getLineStartOffset(lineIndex);
|
||||
loc.x = textArea.offsetToX(lineIndex, offsetX);
|
||||
return loc;
|
||||
}
|
||||
|
||||
public Rectangle getTextLocation() {
|
||||
Point caret = getCaretLocation();
|
||||
return getCaretRectangle(caret.x, caret.y);
|
||||
}
|
||||
|
||||
private Rectangle getCaretRectangle(int x, int y) {
|
||||
TextAreaPainter painter = textArea.getPainter();
|
||||
Point origin = painter.getLocationOnScreen();
|
||||
int height = painter.getFontMetrics().getHeight();
|
||||
return new Rectangle(origin.x + x, origin.y + y, 0, height);
|
||||
}
|
||||
|
||||
public AttributedCharacterIterator getCommittedText(int beginIndex, int endIndex) {
|
||||
int length = endIndex - beginIndex;
|
||||
String textAreaString = textArea.getText(beginIndex, length);
|
||||
return new AttributedString(textAreaString).getIterator();
|
||||
}
|
||||
|
||||
public int getInsertPositionOffset() {
|
||||
return textArea.getCaretPosition() * -1;
|
||||
}
|
||||
}
|
@ -1,124 +0,0 @@
|
||||
package processing.app.syntax.im;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
import java.awt.font.TextLayout;
|
||||
|
||||
import processing.app.syntax.JEditTextArea;
|
||||
import processing.app.syntax.TextAreaPainter;
|
||||
|
||||
/**
|
||||
* Paint texts from input method. Text via input method are transmitted by
|
||||
* AttributedCaharacterIterator. This class helps the PDE's TextAreaPainter
|
||||
* to handle AttributedCaharacterIterator.
|
||||
*
|
||||
* For practical purposes, paint to textarea is done by TextLayout class.
|
||||
* Because TextLayout class is easy to draw composing texts. (For example,
|
||||
* draw underline composing texts, focus when select from candidates text.)
|
||||
*
|
||||
* @author Takashi Maekawa (takachin@generative.info)
|
||||
*/
|
||||
public class CompositionTextPainter {
|
||||
private TextLayout composedTextLayout;
|
||||
private int composedBeginCaretPosition = 0;
|
||||
private JEditTextArea textArea;
|
||||
|
||||
/**
|
||||
* Constructor for painter.
|
||||
* @param textarea textarea used by PDE.
|
||||
*/
|
||||
public CompositionTextPainter(JEditTextArea textArea) {
|
||||
this.textArea = textArea;
|
||||
composedTextLayout = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the painter has TextLayout.
|
||||
* If a user input via InputMethod, this result will return true.
|
||||
* @param textarea textarea used by PDE.
|
||||
*/
|
||||
public boolean hasComposedTextLayout() {
|
||||
return (composedTextLayout != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set TextLayout to the painter.
|
||||
* TextLayout will be created and set by CompositionTextManager.
|
||||
*
|
||||
* @see CompositionTextManager
|
||||
* @param textarea textarea used by PDE.
|
||||
*/
|
||||
public void setComposedTextLayout(TextLayout composedTextLayout, int composedStartCaretPosition) {
|
||||
this.composedTextLayout = composedTextLayout;
|
||||
this.composedBeginCaretPosition = composedStartCaretPosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate this TextLayout to set null.
|
||||
* If a user end input via InputMethod, this method will called from CompositionTextManager.endCompositionText
|
||||
*/
|
||||
public void invalidateComposedTextLayout(int composedEndCaretPosition) {
|
||||
this.composedTextLayout = null;
|
||||
this.composedBeginCaretPosition = composedEndCaretPosition;
|
||||
//this.composedBeginCaretPosition = textArea.getCaretPosition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw text via input method with composed text information.
|
||||
* This method can draw texts with some underlines to illustrate converting characters.
|
||||
*
|
||||
* This method is workaround for TextAreaPainter.
|
||||
* Because, TextAreaPainter can't treat AttributedCharacterIterator directly.
|
||||
* AttributedCharacterIterator has very important information when composing text.
|
||||
* It has a map where are converted characters and committed characters.
|
||||
* Ideally, changing TextAreaPainter method can treat AttributedCharacterIterator is better. But it's very tough!!
|
||||
* So I choose to write some code as a workaround.
|
||||
*
|
||||
* This draw method is proceeded with the following steps.
|
||||
* 1. Original TextAreaPainter draws characters.
|
||||
* 2. This refillComposedArea method erase previous paint characters by textarea's background color.
|
||||
* The refill area is only square that width and height defined by characters with input method.
|
||||
* 3. CompositionTextPainter.draw method paints composed text. It was actually drawn by TextLayout.
|
||||
*
|
||||
* @param gfx set TextAreaPainter's Graphics object.
|
||||
* @param fillBackGroundColor set textarea's background.
|
||||
*/
|
||||
public void draw(Graphics gfx, Color fillBackGroundColor) {
|
||||
assert(composedTextLayout != null);
|
||||
Point composedLoc = getCaretLocation();
|
||||
refillComposedArea(fillBackGroundColor, composedLoc.x, composedLoc.y);
|
||||
composedTextLayout.draw((Graphics2D) gfx, composedLoc.x, composedLoc.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill color to erase characters drawn by original TextAreaPainter.
|
||||
*
|
||||
* @param fillColor fill color to erase characters drawn by original TextAreaPainter method.
|
||||
* @param x x-coordinate where to fill.
|
||||
* @param y y-coordinate where to fill.
|
||||
*/
|
||||
private void refillComposedArea(Color fillColor, int x, int y) {
|
||||
Graphics gfx = textArea.getPainter().getGraphics();
|
||||
gfx.setColor(fillColor);
|
||||
FontMetrics fm = textArea.getPainter().getFontMetrics();
|
||||
int newY = y - (fm.getHeight() - CompositionTextManager.COMPOSING_UNDERBAR_HEIGHT);
|
||||
int paintHeight = fm.getHeight();
|
||||
int paintWidth = (int) composedTextLayout.getBounds().getWidth();
|
||||
gfx.fillRect(x, newY, paintWidth, paintHeight);
|
||||
}
|
||||
|
||||
private Point getCaretLocation() {
|
||||
Point loc = new Point();
|
||||
TextAreaPainter painter = textArea.getPainter();
|
||||
FontMetrics fm = painter.getFontMetrics();
|
||||
int offsetY = fm.getHeight() - CompositionTextManager.COMPOSING_UNDERBAR_HEIGHT;
|
||||
int lineIndex = textArea.getCaretLine();
|
||||
loc.y = lineIndex * fm.getHeight() + offsetY;
|
||||
int offsetX = composedBeginCaretPosition - textArea.getLineStartOffset(lineIndex);
|
||||
loc.x = textArea.offsetToX(lineIndex, offsetX);
|
||||
return loc;
|
||||
}
|
||||
}
|
@ -1,120 +0,0 @@
|
||||
package processing.app.syntax.im;
|
||||
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.InputMethodEvent;
|
||||
import java.awt.event.InputMethodListener;
|
||||
import java.awt.font.TextHitInfo;
|
||||
import java.awt.im.InputMethodRequests;
|
||||
import java.text.AttributedCharacterIterator;
|
||||
|
||||
import processing.app.syntax.JEditTextArea;
|
||||
|
||||
/**
|
||||
* Support in-line Japanese input for PDE. (Maybe Chinese, Korean and more)
|
||||
* This class is implemented by Java Input Method Framework and handles
|
||||
* If you would like to know more about Java Input Method Framework,
|
||||
* Please see http://java.sun.com/j2se/1.5.0/docs/guide/imf/
|
||||
*
|
||||
* This class is implemented to fix Bug #854.
|
||||
* http://dev.processing.org/bugs/show_bug.cgi?id=854
|
||||
*
|
||||
* @author Takashi Maekawa (takachin@generative.info)
|
||||
*/
|
||||
public class InputMethodSupport implements InputMethodRequests,
|
||||
InputMethodListener {
|
||||
|
||||
private int committed_count = 0;
|
||||
private CompositionTextManager textManager;
|
||||
|
||||
public InputMethodSupport(JEditTextArea textArea) {
|
||||
textManager = new CompositionTextManager(textArea);
|
||||
textArea.enableInputMethods(true);
|
||||
textArea.addInputMethodListener(this);
|
||||
}
|
||||
|
||||
public Rectangle getTextLocation(TextHitInfo offset) {
|
||||
return textManager.getTextLocation();
|
||||
}
|
||||
|
||||
public TextHitInfo getLocationOffset(int x, int y) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getInsertPositionOffset() {
|
||||
return textManager.getInsertPositionOffset();
|
||||
}
|
||||
|
||||
public AttributedCharacterIterator getCommittedText(int beginIndex,
|
||||
int endIndex, AttributedCharacterIterator.Attribute[] attributes) {
|
||||
return textManager.getCommittedText(beginIndex, endIndex);
|
||||
}
|
||||
|
||||
public int getCommittedTextLength() {
|
||||
return committed_count;
|
||||
}
|
||||
|
||||
public AttributedCharacterIterator cancelLatestCommittedText(
|
||||
AttributedCharacterIterator.Attribute[] attributes) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public AttributedCharacterIterator getSelectedText(
|
||||
AttributedCharacterIterator.Attribute[] attributes) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles events from InputMethod.
|
||||
* This method judges whether beginning of input or
|
||||
* progress of input or end and call related method.
|
||||
*
|
||||
* @param event event from Input Method.
|
||||
*/
|
||||
public void inputMethodTextChanged(InputMethodEvent event) {
|
||||
AttributedCharacterIterator text = event.getText();
|
||||
committed_count = event.getCommittedCharacterCount();
|
||||
if(isFullWidthSpaceInput(text)){
|
||||
textManager.insertFullWidthSpace();
|
||||
caretPositionChanged(event);
|
||||
return;
|
||||
}
|
||||
if(isBeginInputProcess(text, textManager)){
|
||||
textManager.beginCompositionText(text, committed_count);
|
||||
caretPositionChanged(event);
|
||||
return;
|
||||
}
|
||||
if (isInputProcess(text)){
|
||||
textManager.processCompositionText(text, committed_count);
|
||||
caretPositionChanged(event);
|
||||
return;
|
||||
}
|
||||
textManager.endCompositionText(text, committed_count);
|
||||
caretPositionChanged(event);
|
||||
}
|
||||
|
||||
private boolean isFullWidthSpaceInput(AttributedCharacterIterator text){
|
||||
if(text == null)
|
||||
return false;
|
||||
if(textManager.getIsInputProcess())
|
||||
return false;
|
||||
return (String.valueOf(text.first()).equals("\u3000"));
|
||||
}
|
||||
|
||||
private boolean isBeginInputProcess(AttributedCharacterIterator text, CompositionTextManager textManager){
|
||||
if(text == null)
|
||||
return false;
|
||||
if(textManager.getIsInputProcess())
|
||||
return false;
|
||||
return (isInputProcess(text));
|
||||
}
|
||||
|
||||
private boolean isInputProcess(AttributedCharacterIterator text){
|
||||
if(text == null)
|
||||
return false;
|
||||
return (text.getEndIndex() - (text.getBeginIndex() + committed_count) > 0);
|
||||
}
|
||||
|
||||
public void caretPositionChanged(InputMethodEvent event) {
|
||||
event.consume();
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
OLDSYNTAX PACKAGE README
|
||||
|
||||
I am placing the jEdit 2.2.1 syntax highlighting package in the public
|
||||
domain. This means it can be integrated into commercial programs, etc.
|
||||
|
||||
This package requires at least Java 1.1 and Swing 1.1. Syntax
|
||||
highlighting for the following file types is supported:
|
||||
|
||||
- C++, C
|
||||
- CORBA IDL
|
||||
- Eiffel
|
||||
- HTML
|
||||
- Java
|
||||
- Java properties
|
||||
- JavaScript
|
||||
- MS-DOS INI
|
||||
- MS-DOS batch files
|
||||
- Makefile
|
||||
- PHP
|
||||
- Perl
|
||||
- Python
|
||||
- TeX
|
||||
- Transact-SQL
|
||||
- Unix patch/diff
|
||||
- Unix shell script
|
||||
- XML
|
||||
|
||||
This package is undocumented; read the source (start by taking a look at
|
||||
JEditTextArea.java) to find out how to use it; it's really simple. Feel
|
||||
free to e-mail questions, queries, etc. to me, but keep in mind that
|
||||
this code is very old and I no longer maintain it. So if you find a bug,
|
||||
don't bother me about it; fix it yourself.
|
||||
|
||||
* Copyright
|
||||
|
||||
The jEdit 2.2.1 syntax highlighting package contains code that is
|
||||
Copyright 1998-1999 Slava Pestov, Artur Biesiadowski, Clancy Malcolm,
|
||||
Jonathan Revusky, Juha Lindfors and Mike Dillon.
|
||||
|
||||
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.
|
||||
|
||||
-- Slava Pestov
|
||||
25 September 2000
|
||||
<sp@gjt.org>
|
@ -1,108 +0,0 @@
|
||||
/*
|
||||
* This file is part of Arduino.
|
||||
*
|
||||
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
|
||||
*
|
||||
* Arduino is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* As a special exception, you may use this file as part of a free software
|
||||
* library without restriction. Specifically, if other files instantiate
|
||||
* templates or use macros or inline functions from this file, or you compile
|
||||
* this file and link it with other files to produce an executable, this
|
||||
* file does not by itself cause the resulting executable to be covered by
|
||||
* the GNU General Public License. This exception does not however
|
||||
* invalidate any other reasons why the executable file might be covered by
|
||||
* the GNU General Public License.
|
||||
*/
|
||||
|
||||
package processing.app.helpers;
|
||||
|
||||
import org.fest.swing.core.Robot;
|
||||
import org.fest.swing.driver.JComponentDriver;
|
||||
import org.fest.swing.edt.GuiActionRunner;
|
||||
import org.fest.swing.edt.GuiQuery;
|
||||
import processing.app.syntax.JEditTextArea;
|
||||
|
||||
public class JEditTextAreaComponentDriver extends JComponentDriver {
|
||||
|
||||
public JEditTextAreaComponentDriver(Robot robot) {
|
||||
super(robot);
|
||||
}
|
||||
|
||||
public void enterText(JEditTextArea target, String text) {
|
||||
focusAndWaitForFocusGain(target);
|
||||
robot.enterText(text);
|
||||
}
|
||||
|
||||
public void setText(final JEditTextArea target, final String text) {
|
||||
focusAndWaitForFocusGain(target);
|
||||
GuiActionRunner.execute(new GuiQuery<JEditTextArea>() {
|
||||
|
||||
protected JEditTextArea executeInEDT() {
|
||||
target.setText(text);
|
||||
return target;
|
||||
}
|
||||
|
||||
});
|
||||
robot.waitForIdle();
|
||||
}
|
||||
|
||||
public String getText(final JEditTextArea target) {
|
||||
focusAndWaitForFocusGain(target);
|
||||
return GuiActionRunner.execute(new GuiQuery<String>() {
|
||||
|
||||
protected String executeInEDT() {
|
||||
return target.getText();
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public JEditTextArea selectAll(final JEditTextArea target) {
|
||||
return GuiActionRunner.execute(new GuiQuery<JEditTextArea>() {
|
||||
|
||||
protected JEditTextArea executeInEDT() {
|
||||
target.selectAll();
|
||||
return target;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public Integer getCaretPosition(final JEditTextArea target) {
|
||||
focusAndWaitForFocusGain(target);
|
||||
return GuiActionRunner.execute(new GuiQuery<Integer>() {
|
||||
|
||||
protected Integer executeInEDT() {
|
||||
return target.getCaretPosition();
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public void setCaretPosition(final JEditTextArea target, final int caretPosition) {
|
||||
focusAndWaitForFocusGain(target);
|
||||
GuiActionRunner.execute(new GuiQuery<JEditTextArea>() {
|
||||
|
||||
protected JEditTextArea executeInEDT() {
|
||||
target.setCaretPosition(caretPosition);
|
||||
return target;
|
||||
}
|
||||
|
||||
});
|
||||
robot.waitForIdle();
|
||||
}
|
||||
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
/*
|
||||
* This file is part of Arduino.
|
||||
*
|
||||
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
|
||||
*
|
||||
* Arduino is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* As a special exception, you may use this file as part of a free software
|
||||
* library without restriction. Specifically, if other files instantiate
|
||||
* templates or use macros or inline functions from this file, or you compile
|
||||
* this file and link it with other files to produce an executable, this
|
||||
* file does not by itself cause the resulting executable to be covered by
|
||||
* the GNU General Public License. This exception does not however
|
||||
* invalidate any other reasons why the executable file might be covered by
|
||||
* the GNU General Public License.
|
||||
*/
|
||||
|
||||
package processing.app.helpers;
|
||||
|
||||
import org.fest.swing.core.ComponentMatcher;
|
||||
import processing.app.syntax.JEditTextArea;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
public class JEditTextAreaComponentMatcher implements ComponentMatcher {
|
||||
|
||||
private final String name;
|
||||
|
||||
public JEditTextAreaComponentMatcher(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Component component) {
|
||||
return component instanceof JEditTextArea && name.equals(component.getName());
|
||||
}
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
/*
|
||||
* This file is part of Arduino.
|
||||
*
|
||||
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
|
||||
*
|
||||
* Arduino is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* As a special exception, you may use this file as part of a free software
|
||||
* library without restriction. Specifically, if other files instantiate
|
||||
* templates or use macros or inline functions from this file, or you compile
|
||||
* this file and link it with other files to produce an executable, this
|
||||
* file does not by itself cause the resulting executable to be covered by
|
||||
* the GNU General Public License. This exception does not however
|
||||
* invalidate any other reasons why the executable file might be covered by
|
||||
* the GNU General Public License.
|
||||
*/
|
||||
|
||||
package processing.app.helpers;
|
||||
|
||||
import org.fest.swing.core.Robot;
|
||||
import org.fest.swing.fixture.ComponentFixture;
|
||||
import processing.app.syntax.JEditTextArea;
|
||||
|
||||
public class JEditTextAreaFixture extends ComponentFixture {
|
||||
|
||||
private final JEditTextAreaComponentDriver driver;
|
||||
|
||||
public JEditTextAreaFixture(Robot robot, Class type) {
|
||||
super(robot, type);
|
||||
this.driver = new JEditTextAreaComponentDriver(robot);
|
||||
}
|
||||
|
||||
public JEditTextAreaFixture(Robot robot, String name, Class type) {
|
||||
super(robot, name, type);
|
||||
this.driver = new JEditTextAreaComponentDriver(robot);
|
||||
}
|
||||
|
||||
public JEditTextAreaFixture(Robot robot, JEditTextArea target) {
|
||||
super(robot, target);
|
||||
this.driver = new JEditTextAreaComponentDriver(robot);
|
||||
}
|
||||
|
||||
public JEditTextAreaFixture enterText(String text) {
|
||||
driver.enterText((JEditTextArea) target, text);
|
||||
return this;
|
||||
}
|
||||
|
||||
public JEditTextAreaFixture setText(String text) {
|
||||
driver.setText((JEditTextArea) target, text);
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return driver.getText((JEditTextArea) target);
|
||||
}
|
||||
|
||||
public JEditTextAreaFixture selectAll() {
|
||||
driver.selectAll((JEditTextArea) target);
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getCaretPosition() {
|
||||
return driver.getCaretPosition((JEditTextArea) target);
|
||||
}
|
||||
|
||||
public void setCaretPosition(int caretPosition) {
|
||||
driver.setCaretPosition((JEditTextArea) target, caretPosition);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user