com.scudata.ide.common.swing.JTextPaneEx Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of esproc Show documentation
Show all versions of esproc Show documentation
SPL(Structured Process Language) A programming language specially for structured data computing.
package com.scudata.ide.common.swing;
import java.awt.Color;
import java.awt.Point;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BoxView;
import javax.swing.text.ComponentView;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.Element;
import javax.swing.text.IconView;
import javax.swing.text.LabelView;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.ParagraphView;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledEditorKit;
import javax.swing.text.View;
import javax.swing.text.ViewFactory;
import com.scudata.cellset.INormalCell;
import com.scudata.cellset.datamodel.CellSet;
import com.scudata.cellset.datamodel.Command;
import com.scudata.cellset.datamodel.PgmNormalCell;
import com.scudata.common.CellLocation;
import com.scudata.common.Sentence;
import com.scudata.common.StringUtils;
import com.scudata.dm.Context;
import com.scudata.dm.KeyWord;
import com.scudata.expression.Expression;
import com.scudata.expression.IParam;
import com.scudata.ide.common.GC;
import com.scudata.ide.common.GM;
import com.scudata.ide.spl.GVSpl;
import com.scudata.ide.spl.control.SplControl;
/**
* JTextPane????չ?ࡣ
*
* ????ƥ?????ţ???????ʾ?ؼ??֡?
*/
public class JTextPaneEx extends JTextPane {
private static final long serialVersionUID = 1L;
/**
* ??ʽ?ĵ?????
*/
private DefaultStyledDocument doc;
/**
*
*/
private boolean matchEnabled = true;
/**
* ?Ƿ???ֹ?仯
*/
protected boolean preventChanged = false;
/**
* ???캯??
*/
public JTextPaneEx() {
super();
try {
this.setEditorKit(new WarpEditorKit());
init();
} catch (Exception e) {
GM.showException(e);
}
}
/**
* ?????Ƿ?ƥ??
*
* @param matchEnabled
*/
public void setMatchEnabled(boolean matchEnabled) {
this.matchEnabled = matchEnabled;
}
/**
* ?????ı?
*/
public void setText(String t) {
try {
preventChanged = true;
super.setText(t);
} finally {
preventChanged = false;
}
}
/**
* ??ʼ???ؼ?
*/
private void init() {
setFont(GC.font);
StyleContext sc = new StyleContext();
doc = new DefaultStyledDocument(sc);
this.setDocument(doc);
doc.addDocumentListener(new DocumentListener() {
public void insertUpdate(DocumentEvent e) {
docUpdate();
}
public void removeUpdate(DocumentEvent e) {
docUpdate();
}
public void changedUpdate(DocumentEvent e) {
docUpdate();
}
});
this.addKeyListener(new KeyAdapter() {
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
switch (key) {
case KeyEvent.VK_LEFT:
case KeyEvent.VK_RIGHT:
case KeyEvent.VK_UP:
case KeyEvent.VK_DOWN:
if (isMatching())
return;
if (getText() == null || getText().equals("")) {
return;
}
if (key == KeyEvent.VK_DOWN && e.isShiftDown()) {
return;
}
if ((key == KeyEvent.VK_DOWN || key == KeyEvent.VK_UP)
&& e.isAltDown()) {
return;
}
caretChanged(getCaretPosition());
return;
case KeyEvent.VK_HOME:
case KeyEvent.VK_END:
case KeyEvent.VK_PAGE_UP:
case KeyEvent.VK_PAGE_DOWN:
caretChanged(getCaretPosition());
return;
}
}
});
this.addCaretListener(new CaretListener() {
public void caretUpdate(CaretEvent e) {
caretChanged(e.getDot());
}
});
StyleConstants.setBold(AS_BRACKET, true);
StyleConstants.setForeground(AS_BRACKET, COLOR_BRACKET);
StyleConstants.setForeground(AS_KEY, COLOR_KEY);
}
protected boolean isMatching() {
return false;
}
/**
* ?????Ƿ???ֹ?仯
*
* @param preventChanged
*/
public void setPreventChange(boolean preventChanged) {
this.preventChanged = preventChanged;
}
/**
* ?ĵ?????
*/
protected void docUpdate() {
if (preventChanged)
return;
initRefCells(true);
}
// ̫?????ı?ͨ???????ݾͲ??????༭?ˣ?Ҫ??Ȼ̫????
private static final int STYLE_MAX_LENGTH = 100000;
/**
* ????ƶ?
*
* @param caret
* ???λ??
*/
public void caretChanged(int caret) {
if (!isVisible())
return;
if (preventChanged)
return;
if (!matchEnabled)
return;
caretChanged();
List total = new ArrayList();
String text = getText();
if (text != null && text.length() > STYLE_MAX_LENGTH)
return;
if (text != null && text.length() > 0) {
// ????
total.add(new CA(0, text.length(), AS_DEFAULT, true));
}
total.addAll(refCAs);
List carets = getCaretCAs(caret);
total.addAll(carets);
resetCAs(total);
}
/**
* ȡ???и?????ʾ??????
*
* @param caret
* @return
*/
private List getCaretCAs(int caret) {
List cas = new ArrayList();
List tmp;
tmp = matchKeyWords(caret);
if (tmp != null)
cas.addAll(tmp);
tmp = getBracketCAs(caret);
if (tmp != null)
cas.addAll(tmp);
return cas;
}
/**
* ????ƶ?
*/
protected void caretChanged() {
}
/**
* ƥ??ؼ???
*
* @param caret
* @return
*/
private List matchKeyWords(int caret) {
List cas = new ArrayList();
try {
String text = getText();
if (!StringUtils.isValidString(text) || text.startsWith("/"))
return cas;
for (int i = 0; i < text.length(); i++) {
int end = KeyWord.scanId(text, i);
if (end > i) {
String word = text.substring(i, end);
if (keyWords.contains(word)) {
cas.add(new CA(i, word.length(), AS_KEY, false));
i = end;
}
}
}
} catch (Throwable t) {
// t.printStackTrace();
}
return cas;
}
/**
* ȡƥ???????
*
* @param caret
* @return
*/
private List getBracketCAs(int caret) {
List cas = new ArrayList();
int[] brackets = matchBrackets(caret);
if (brackets == null)
return cas;
cas.add(new CA(brackets[0], 1, AS_BRACKET, false));
cas.add(new CA(brackets[1], 1, AS_BRACKET, false));
return cas;
}
/**
* ƥ??????
*
* @param caret
* @return
*/
private int[] matchBrackets(int caret) {
try {
String text = getText();
if (!StringUtils.isValidString(text))
return null;
if (caret >= text.length()) {
caret--;
}
int matchDot = -1;
int md = findBrackets(caret);
if (md > -1) {
matchDot = md;
} else if (caret > 0) {
caret--;
md = findBrackets(caret);
if (md > -1) {
matchDot = md;
}
}
if (matchDot > -1) {
return new int[] { caret, matchDot };
}
} catch (Throwable t) {
// t.printStackTrace();
}
return null;
}
/**
* ??????
*
* @param caret
* @return
*/
private int findBrackets(int caret) {
String text = getText();
char c = text.charAt(caret);
int inBrackets = 0;
if (c == '(') {
if (!isValidChar(caret)) {
return -1;
}
inBrackets++;
for (int i = caret + 1; i < text.length(); i++) {
char c1 = text.charAt(i);
if (c1 == '(') {
if (isValidChar(i)) {
inBrackets++;
}
} else if (c1 == ')') {
if (isValidChar(i)) {
inBrackets--;
if (inBrackets == 0) {
return i;
} else if (inBrackets < 0) { // ???Ų?ƥ??
return -1;
}
}
}
}
} else if (c == ')') {
if (!isValidChar(caret)) {
return -1;
}
inBrackets++;
for (int i = caret - 1; i >= 0; i--) {
char c1 = text.charAt(i);
if (c1 == ')') {
if (isValidChar(i)) {
inBrackets++;
}
} else if (c1 == '(') {
if (isValidChar(i)) {
inBrackets--;
if (inBrackets == 0) {
return i;
} else if (inBrackets < 0) { // ???Ų?ƥ??
return -1;
}
}
}
}
}
return -1;
}
/**
* ?ַ??Ƿ?Ϸ?
*
* @param index
* @return
*/
private boolean isValidChar(int index) {
return isValidString(index, 1);
}
/**
* ?ַ????Ƿ?Ϸ?
*
* @param index
* @param len
* @return
*/
private boolean isValidString(int index, int len) {
String text = getText();
int i = Sentence.indexOf(text, index,
text.substring(index, index + len), SEARCH_FLAG);
return index == i;
}
public Point getLocationOnScreen() {
try {
return super.getLocationOnScreen();
} catch (Throwable t) { // ??????
return new Point(0, 0);
}
}
/**
* ??ʼ?????ø?
*
* @param isUpdate
*/
public synchronized void initRefCells(boolean isUpdate) {
if (!matchEnabled)
return;
if (!isVisible())
return;
String text = getText();
if (text != null && text.length() > STYLE_MAX_LENGTH)
return;
List lastRefCells = new ArrayList();
if (refCells != null) {
lastRefCells.addAll(refCells);
}
refCells.clear();
try {
SplControl control = null;
CellSet cellSet = null;
if (GVSpl.splEditor != null) {
control = GVSpl.splEditor.getComponent();
if (control != null) {
cellSet = control.cellSet;
}
}
if (text != null && text.length() > 0) {
// ????
refCAs.add(new CA(0, text.length(), AS_DEFAULT, true));
}
if (cellSet != null && text != null) {
if (isUpdate) {
if (StringUtils.isValidString(text)
&& !text.startsWith("/")) {
Command cmd = null;
try {
cmd = Command.parse(text);
} catch (Exception ex) {
}
if (cmd != null) {
IParam param = cmd.getParam(control.cellSet,
new Context());
if (param != null)
param.getUsedCells(refCells);
} else {
Expression exp = new Expression(cellSet,
new Context(), text);
exp.getUsedCells(refCells);
}
}
} else {
CellLocation cl = control.getActiveCell();
PgmNormalCell activeCell = control.cellSet
.getPgmNormalCell(cl.getRow(), cl.getCol());
if (activeCell != null) {
activeCell.getUsedCells(refCells);
}
}
if (!refCells.isEmpty()) {
for (int i = 0; i < refCells.size(); i++) {
INormalCell cell = refCells.get(i);
if (cell != null) {
int colorIndex = i % REF_COLORS.length;
if (as[colorIndex] == null) {
as[colorIndex] = new SimpleAttributeSet();
StyleConstants.setForeground(as[colorIndex],
REF_COLORS[colorIndex]);
}
final String cellId = cell.getCellId();
int start = 0;
while (true) {
final int index = Sentence.indexOf(text, start,
cellId, SEARCH_FLAG);
if (index < 0)
break;
refCAs.add(new CA(index, cellId.length(),
as[colorIndex], false));
start = index + cellId.length();
}
}
}
}
}
List total = new ArrayList();
total.addAll(refCAs);
total.addAll(getCaretCAs(getCaretPosition()));
resetCAs(total);
if (control != null) {
// ?Ƚ?һ?£????????û??Ͳ?ˢ????
boolean isSame = false;
if (lastRefCells != null && refCells != null)
if (lastRefCells.size() == refCells.size()) {
isSame = true;
for (INormalCell cell1 : refCells) {
boolean hasCell = false;
for (INormalCell cell2 : lastRefCells) {
if (cell1.getRow() == cell2.getRow()
&& cell1.getCol() == cell2.getCol()) {
hasCell = true;
}
}
if (!hasCell) {
isSame = false;
break;
}
}
}
if (!isSame)
control.getContentPanel().repaint();
}
} catch (Throwable t) {
// t.printStackTrace();
}
}
/**
* ????ƥ???б?
*
* @param cas
*/
private synchronized void resetCAs(final List cas) {
if (cas == null)
return;
if (!cas.isEmpty()) {
SwingUtilities.invokeLater(new Thread() {
public void run() {
resetCAList(cas);
}
});
}
}
/**
* ????ƥ???????б?
*
* @param cas
*/
private synchronized void resetCAList(List cas) {
try {
preventChanged = true;
if (GVSpl.toolBarProperty != null)
GVSpl.toolBarProperty.preventAction = true;
for (CA ca : cas) {
doc.setCharacterAttributes(ca.offset, ca.length, ca.s,
ca.replace);
}
SwingUtilities.invokeLater(new Thread() {
public void run() {
repaint();
}
});
} finally {
if (GVSpl.toolBarProperty != null)
GVSpl.toolBarProperty.preventAction = false;
preventChanged = false;
}
}
/**
* ȡ???ø??б?
*
* @return
*/
public List getRefCells() {
return refCells;
}
/**
* ȡ???ø???ɫ
*
* @param row
* ?к?
* @param col
* ?к?
* @return
*/
public Color getRefCellColor(int row, int col) {
if (refCells == null || refCells.isEmpty())
return null;
for (int i = 0; i < refCells.size(); i++) {
INormalCell cell = refCells.get(i);
if (cell != null) {
if (cell.getRow() == row && cell.getCol() == col) {
return REF_COLORS[i % REF_COLORS.length];
}
}
}
return null;
}
/**
* ????ؼ???
*/
private static final String KEY_IF = "if";
private static final String KEY_ELSE = "else";
private static final String KEY_ELSEIF = "elseif";
private static final String KEY_FOR = "for";
private static final String KEY_NEXT = "next";
private static final String KEY_BREAK = "break";
private static final String KEY_FUNC = "func";
private static final String KEY_RETURN = "return";
private static final String KEY_END = "end";
private static final String KEY_RESULT = "result";
private static final String KEY_CLEAR = "clear";
private static final String KEY_FORK = "fork";
private static final String KEY_REDUCE = "reduce";
private static final String KEY_GOTO = "goto";
private static final String KEY_CHANNEL = "cursor";
/**
* ?ؼ??ּ???
*/
private static List keyWords = new ArrayList();
static {
keyWords.add(KEY_IF);
keyWords.add(KEY_ELSE);
keyWords.add(KEY_ELSEIF);
keyWords.add(KEY_FOR);
keyWords.add(KEY_NEXT);
keyWords.add(KEY_BREAK);
keyWords.add(KEY_FUNC);
keyWords.add(KEY_RETURN);
keyWords.add(KEY_END);
keyWords.add(KEY_RESULT);
keyWords.add(KEY_CLEAR);
keyWords.add(KEY_FORK);
keyWords.add(KEY_REDUCE);
keyWords.add(KEY_GOTO);
keyWords.add(KEY_CHANNEL);
}
/**
* ?????ɫѭ??ʹ?ã????????ٴ?0??ʼ
*/
private static final Color REF_COLOR1 = Color.BLUE;
private static final Color REF_COLOR2 = Color.RED;
private static final Color REF_COLOR3 = Color.PINK;
private static final Color REF_COLOR4 = Color.GREEN;
private static final Color REF_COLOR5 = Color.MAGENTA;
private static final Color REF_COLOR6 = Color.ORANGE;
private static final Color REF_COLOR7 = Color.CYAN;
private static final Color[] REF_COLORS = new Color[] { REF_COLOR1,
REF_COLOR2, REF_COLOR3, REF_COLOR4, REF_COLOR5, REF_COLOR6,
REF_COLOR7 };
private static final Color COLOR_BRACKET = Color.RED;
private static final Color COLOR_KEY = Color.BLUE;
/** ȱʡ */
private static final MutableAttributeSet AS_DEFAULT = new SimpleAttributeSet();
/** ƥ?????? */
private static final MutableAttributeSet AS_BRACKET = new SimpleAttributeSet();
/** ?ؼ??? */
private static final MutableAttributeSet AS_KEY = new SimpleAttributeSet();
/**
* ???õ?Ԫ????ɫ?ļ???
*/
private MutableAttributeSet[] as = new MutableAttributeSet[REF_COLORS.length];
/**
* ???????ø??ƥ??????
*/
private List refCAs = new ArrayList();
/**
* ???ø??б?
*/
private List refCells = new ArrayList();
/**
* ????????
*/
private final int SEARCH_FLAG = Sentence.IGNORE_PARS + Sentence.ONLY_PHRASE;
/**
* ?༭????
*
*/
private class WarpEditorKit extends StyledEditorKit {
private static final long serialVersionUID = 1L;
private ViewFactory defaultFactory = new WarpColumnFactory();
public ViewFactory getViewFactory() {
return defaultFactory;
}
}
/**
* ?й???
*/
private class WarpColumnFactory implements ViewFactory {
public View create(Element elem) {
String kind = elem.getName();
if (kind != null) {
if (kind.equals(AbstractDocument.ContentElementName)) {
return new WarpLabelView(elem);
} else if (kind.equals(AbstractDocument.ParagraphElementName)) {
return new ParagraphView(elem);
} else if (kind.equals(AbstractDocument.SectionElementName)) {
return new BoxView(elem, View.Y_AXIS);
} else if (kind.equals(StyleConstants.ComponentElementName)) {
return new ComponentView(elem);
} else if (kind.equals(StyleConstants.IconElementName)) {
return new IconView(elem);
}
}
return new LabelView(elem);
}
}
/**
* ??ǩ??ͼ
*
*/
private class WarpLabelView extends LabelView {
public WarpLabelView(Element elem) {
super(elem);
}
public float getMinimumSpan(int axis) {
switch (axis) {
case View.X_AXIS:
return 0;
case View.Y_AXIS:
return super.getMinimumSpan(axis);
default:
throw new IllegalArgumentException("Invalid axis: " + axis);
}
}
}
/**
* ƥ?䵽?ĸ?????ʾ??????
*
*/
class CA {
int offset;
int length;
AttributeSet s;
boolean replace;
public CA(int offset, int length, AttributeSet s, boolean replace) {
this.offset = offset;
this.length = length;
this.s = s;
this.replace = replace;
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy