package net.codjo.dataprocess.gui.util.editor;
import java.awt.Color;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.Element;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
/**
*
*/
public class ColoredEditorDocument extends DefaultStyledDocument {
public static final String STYLE_NORMAL = "__style__std__normal";
public static final String STYLE_COMMENT_SINGLE_LINE = "__style__std__comment_single_line";
public static final String STYLE_COMMENT_MULTI_LINE = "__style__std__comment_multi_line";
public static final String STYLE_NUMBER = "__style__std__number";
private Element rootElement;
private Map<String, MutableAttributeSet> styles = new HashMap<String, MutableAttributeSet>();
private Map<String, String> keywordsToStyle = new HashMap<String, String>();
private Pattern singleLineCommentDelimter = Pattern.compile("//");
private Pattern patternNumberDelimter =
Pattern.compile("[\\s|,|=|\\*|/]+[-+]?[0-9]*\\.?[0-9]+[\\s|,|\\n]");
private Pattern multiLineCommentDelimiterStart = Pattern.compile("/\\*");
private Pattern multiLineCommentDelimiterEnd = Pattern.compile("\\*/");
private boolean singleLineCommentActivated = true;
private boolean multiLineCommentActivated = true;
public ColoredEditorDocument() {
putProperty(DefaultEditorKit.EndOfLineStringProperty, "\n");
rootElement = getDefaultRootElement();
recordStyle(STYLE_COMMENT_SINGLE_LINE, Color.gray, false, true, false);
recordStyle(STYLE_COMMENT_MULTI_LINE, Color.gray, false, true, false);
recordStyle(STYLE_NORMAL, Color.black, false, false, false);
recordStyle(STYLE_NUMBER, Color.RED, false, true, false);
}
public void disableSingleLineComment() {
singleLineCommentActivated = false;
}
public void disableMultiLineComment() {
multiLineCommentActivated = false;
}
public void enableSingleLineComment(String pattern) {
singleLineCommentActivated = true;
singleLineCommentDelimter = Pattern.compile(pattern);
}
public void enableMuVoidLineComment(String patternStart, String patternEnd) {
multiLineCommentActivated = true;
multiLineCommentDelimiterStart = Pattern.compile(patternStart);
multiLineCommentDelimiterEnd = Pattern.compile(patternEnd);
}
@Override
public void insertString(int offset, String str, AttributeSet attr) throws BadLocationException {
super.insertString(offset, str, attr);
processChangedLines(offset, str.length());
}
@Override
public void remove(int offset, int length) throws BadLocationException {
super.remove(offset, length);
processChangedLines(offset, length);
}
public void processChangedLines(int offset, int length) throws BadLocationException {
String text = getText(0, getLength());
highlightString(0, getLength(), true, STYLE_NORMAL);
highlightKeywords(text);
if (singleLineCommentActivated) {
highlightMultipleLineComment(text);
}
if (multiLineCommentActivated) {
highlightSingleLineComment(text);
}
highlightNumber(text);
}
private void highlightKeywords(String text) {
Set keyw = keywordsToStyle.keySet();
for (Object aKeyw : keyw) {
String keyword = (String)aKeyw;
String styleName = keywordsToStyle.get(keyword);
Pattern pattern = Pattern.compile("\\b" + keyword + "\\b");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
highlightString(matcher.start(), keyword.length(), true, styleName);
}
}
}
private void highlightNumber(String text) {
Matcher matcher = patternNumberDelimter.matcher(text);
while (matcher.find()) {
highlightString(matcher.start(), matcher.end() - matcher.start(), true, STYLE_NUMBER);
}
}
private void highlightMultipleLineComment(String text) {
Matcher mlcStart = multiLineCommentDelimiterStart.matcher(text);
Matcher mlcEnd = multiLineCommentDelimiterEnd.matcher(text);
while (mlcStart.find()) {
if (mlcEnd.find(mlcStart.end())) {
highlightString(mlcStart.start(), (mlcEnd.end() - mlcStart.start()), true,
STYLE_COMMENT_MULTI_LINE);
}
else {
highlightString(mlcStart.start(), getLength(), true, STYLE_COMMENT_MULTI_LINE);
}
}
}
private void highlightSingleLineComment(String text) {
Matcher slc = singleLineCommentDelimter.matcher(text);
while (slc.find()) {
int line = rootElement.getElementIndex(slc.start());
int endOffset = rootElement.getElement(line).getEndOffset() - 1;
highlightString(slc.start(), (endOffset - slc.start()), true, STYLE_COMMENT_SINGLE_LINE);
}
}
public void highlightString(int begin, int length, boolean replace, String styleName) {
MutableAttributeSet style = styles.get(styleName);
setCharacterAttributes(begin, length, style, replace);
}
// public String getLine(String content, int line)
// {
// Element lineElement = rootElement.getElement( line );
// return content.substring(lineElement.getStartOffset(), lineElement.getEndOffset() - 1);
// }
public void recordStyle(String styleName, Color color, boolean bold, boolean italic, boolean underLine) {
MutableAttributeSet style = new SimpleAttributeSet();
StyleConstants.setForeground(style, color);
StyleConstants.setBold(style, bold);
StyleConstants.setItalic(style, italic);
StyleConstants.setUnderline(style, underLine);
if (styles.get(styleName) != null) {
styles.remove(styleName);
}
styles.put(styleName, style);
}
public void recordKeyWord(String keyword, String styleName) throws IllegalArgumentException {
if (styles.get(styleName) == null) {
throw new IllegalArgumentException("Unknown styleName :'" + styleName + "'");
}
keywordsToStyle.put(keyword, styleName);
}
}