mirror of
https://github.com/frosch95/SmartCSV.fx.git
synced 2026-04-11 13:38:23 +02:00
support of RichTextFX to have syntax highlighting in the groovy edit field of validation editor
This commit is contained in:
@@ -32,18 +32,29 @@ import javafx.fxml.FXML;
|
||||
import javafx.scene.control.*;
|
||||
import ninja.javafx.smartcsv.fx.FXMLController;
|
||||
import ninja.javafx.smartcsv.validation.ValidationConfiguration;
|
||||
import org.fxmisc.richtext.CodeArea;
|
||||
import org.fxmisc.richtext.LineNumberFactory;
|
||||
import org.fxmisc.richtext.StyleSpans;
|
||||
import org.fxmisc.richtext.StyleSpansBuilder;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
/**
|
||||
* controller for editing column validations
|
||||
*
|
||||
* RichText groovy highlighting code is based on the java example of
|
||||
* https://github.com/TomasMikula/RichTextFX
|
||||
*/
|
||||
@Component
|
||||
public class ValidationEditorController extends FXMLController {
|
||||
@@ -51,6 +62,39 @@ public class ValidationEditorController extends FXMLController {
|
||||
private StringProperty selectedColumn = new SimpleStringProperty();
|
||||
private ValidationConfiguration validationConfiguration;
|
||||
|
||||
private static final String[] KEYWORDS = new String[] {
|
||||
"abstract", "assert", "boolean", "break", "byte",
|
||||
"case", "catch", "char", "class",
|
||||
"continue", "def", "default", "do", "double", "else",
|
||||
"enum", "extends", "false", "final", "finally", "float",
|
||||
"for", "if", "implements", "import", "in",
|
||||
"instanceof", "int", "interface", "length", "long", "native",
|
||||
"new", "null", "package", "private", "property", "protected", "public",
|
||||
"return", "short", "static", "super",
|
||||
"switch", "synchronized", "this", "threadsafe", "throw", "throws",
|
||||
"transient", "true", "try", "void", "volatile", "while"
|
||||
};
|
||||
|
||||
private static final String KEYWORD_PATTERN = "\\b(" + String.join("|", KEYWORDS) + ")\\b";
|
||||
private static final String PAREN_PATTERN = "\\(|\\)";
|
||||
private static final String BRACE_PATTERN = "\\{|\\}";
|
||||
private static final String BRACKET_PATTERN = "\\[|\\]";
|
||||
private static final String SEMICOLON_PATTERN = "\\;";
|
||||
private static final String STRING_PATTERN = "\"([^\"\\\\]|\\\\.)*\"";
|
||||
private static final String STRING2_PATTERN = "'([^'\\\\]|\\\\.)*'";
|
||||
private static final String COMMENT_PATTERN = "//[^\n]*" + "|" + "/\\*(.|\\R)*?\\*/";
|
||||
|
||||
private static final Pattern PATTERN = Pattern.compile(
|
||||
"(?<KEYWORD>" + KEYWORD_PATTERN + ")"
|
||||
+ "|(?<PAREN>" + PAREN_PATTERN + ")"
|
||||
+ "|(?<BRACE>" + BRACE_PATTERN + ")"
|
||||
+ "|(?<BRACKET>" + BRACKET_PATTERN + ")"
|
||||
+ "|(?<SEMICOLON>" + SEMICOLON_PATTERN + ")"
|
||||
+ "|(?<STRING>" + STRING_PATTERN + ")"
|
||||
+ "|(?<STRING2>" + STRING2_PATTERN + ")"
|
||||
+ "|(?<COMMENT>" + COMMENT_PATTERN + ")"
|
||||
);
|
||||
|
||||
@FXML
|
||||
private CheckBox notEmptyRuleCheckBox;
|
||||
|
||||
@@ -79,7 +123,7 @@ public class ValidationEditorController extends FXMLController {
|
||||
private TextField valueOfRuleTextField;
|
||||
|
||||
@FXML
|
||||
private TextArea groovyRuleTextArea;
|
||||
private CodeArea groovyRuleTextArea;
|
||||
|
||||
@FXML
|
||||
private CheckBox enableNotEmptyRule;
|
||||
@@ -133,7 +177,7 @@ public class ValidationEditorController extends FXMLController {
|
||||
initTextInputControl(dateformatRuleTextField, enableDateRule);
|
||||
initTextInputControl(regexpRuleTextField, enableRegexpRule);
|
||||
initTextInputControl(valueOfRuleTextField, enableValueOfRule);
|
||||
initTextInputControl(groovyRuleTextArea, enableGroovyRule);
|
||||
initCodeAreaControl(groovyRuleTextArea, enableGroovyRule);
|
||||
|
||||
selectedColumn.addListener(observable -> {
|
||||
updateForm();
|
||||
@@ -275,7 +319,7 @@ public class ValidationEditorController extends FXMLController {
|
||||
enableValueOfRule
|
||||
);
|
||||
|
||||
updateTextInputControl(
|
||||
updateCodeAreaControl(
|
||||
groovyRuleTextArea,
|
||||
validationConfiguration.getGroovyRuleFor(getSelectedColumn()),
|
||||
enableGroovyRule
|
||||
@@ -318,6 +362,15 @@ public class ValidationEditorController extends FXMLController {
|
||||
}
|
||||
}
|
||||
|
||||
private void updateCodeAreaControl(CodeArea rule, String value, CheckBox ruleEnabled) {
|
||||
if (value == null) {
|
||||
ruleEnabled.setSelected(false);
|
||||
} else {
|
||||
ruleEnabled.setSelected(true);
|
||||
rule.replaceText(0, 0, value);
|
||||
}
|
||||
}
|
||||
|
||||
private void initCheckBox(CheckBox rule, CheckBox ruleEnabled) {
|
||||
rule.disableProperty().bind(ruleEnabled.selectedProperty().not());
|
||||
ruleEnabled.selectedProperty().addListener((observable, oldValue, newValue) -> {
|
||||
@@ -345,4 +398,43 @@ public class ValidationEditorController extends FXMLController {
|
||||
});
|
||||
}
|
||||
|
||||
private void initCodeAreaControl(CodeArea rule, CheckBox ruleEnabled) {
|
||||
rule.disableProperty().bind(ruleEnabled.selectedProperty().not());
|
||||
ruleEnabled.selectedProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (!newValue) {
|
||||
rule.clear();
|
||||
}
|
||||
});
|
||||
rule.setParagraphGraphicFactory(LineNumberFactory.get(rule));
|
||||
rule.richChanges()
|
||||
.filter(ch -> !ch.getInserted().equals(ch.getRemoved())) // XXX
|
||||
.subscribe(change -> {
|
||||
rule.setStyleSpans(0, computeHighlighting(rule.getText()));
|
||||
});
|
||||
}
|
||||
|
||||
private static StyleSpans<Collection<String>> computeHighlighting(String text) {
|
||||
Matcher matcher = PATTERN.matcher(text);
|
||||
int lastKwEnd = 0;
|
||||
StyleSpansBuilder<Collection<String>> spansBuilder
|
||||
= new StyleSpansBuilder<>();
|
||||
while(matcher.find()) {
|
||||
String styleClass =
|
||||
matcher.group("KEYWORD") != null ? "keyword" :
|
||||
matcher.group("PAREN") != null ? "paren" :
|
||||
matcher.group("BRACE") != null ? "brace" :
|
||||
matcher.group("BRACKET") != null ? "bracket" :
|
||||
matcher.group("SEMICOLON") != null ? "semicolon" :
|
||||
matcher.group("STRING") != null ? "string" :
|
||||
matcher.group("STRING2") != null ? "string" :
|
||||
matcher.group("COMMENT") != null ? "comment" :
|
||||
null; /* never happens */ assert styleClass != null;
|
||||
spansBuilder.add(Collections.emptyList(), matcher.start() - lastKwEnd);
|
||||
spansBuilder.add(Collections.singleton(styleClass), matcher.end() - matcher.start());
|
||||
lastKwEnd = matcher.end();
|
||||
}
|
||||
spansBuilder.add(Collections.emptyList(), text.length() - lastKwEnd);
|
||||
return spansBuilder.create();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user