/**
* Copyright 2013
*
* HAN University of Applied Sciences
* Maik Diepenbroek
* Wouter Konecny
* Sjoerd van den Top
* Teun van Vegchel
* Niek Versteege
*
* See the file MIT-license.txt for copying permission.
*/
package nl.han.ica.app.models;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker;
import javafx.scene.web.WebView;
import org.apache.commons.lang3.StringEscapeUtils;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
/**
* Wrapper around a WebView containing a JavaScript code editor plugin. Provides easy means of communication between the
* Java and the JavaScript environments.
*/
public class CodeEditor {
private WebView webView;
private List<String> scriptCache;
private Logger logger;
/**
* The code editor constructor.
*
* @param webView The WebView where the editor is loaded in.
*/
public CodeEditor(WebView webView) {
logger = Logger.getLogger(getClass());
logger.info("Created CodeEditor");
scriptCache = new ArrayList<>();
this.webView = webView;
initializeWebView();
}
/**
* Sets the value of the Code Editor.
*
* @param value The value to set in the Code Editor.
*/
public void setValue(String value) {
StringBuilder script = new StringBuilder("editor.setValue('");
script.append(StringEscapeUtils.escapeEcmaScript(value));
script.append("')");
execute(script.toString());
}
/**
* Highlights the given line number in the Code Editor.
*
* @param lineNr The line number to highlight.
* @param textClassname The classname.
* @param backgroundClassName The background classname.
*/
public void highlightLine(int lineNr, String textClassname, String backgroundClassName) {
StringBuilder script = new StringBuilder("editor.setLineClass(");
script.append(lineNr).append(", ");
if (null != textClassname) {
script.append("'").append(textClassname).append("'");
} else {
script.append("null");
}
script.append(", ");
if (null != backgroundClassName) {
script.append("'").append(backgroundClassName).append("'");
} else {
script.append("null");
}
script.append(");");
execute(script.toString());
}
/**
* Highlights a part of a line or a block, for example one word or a few lines.
*
* @param lineBegin The line to start highlight.
* @param columnBegin The column to start highlighting.
* @param lineEnd The line where the highlighting ends.
* @param columnEnd The column where the highlighting stops.
* @param className The current class name.
*/
public void highlightText(int lineBegin, int columnBegin, int lineEnd, int columnEnd, String className) {
Position start = new Position(lineBegin - 1, columnBegin - 1);
Position end = new Position(lineEnd - 1, columnEnd);
StringBuilder script = new StringBuilder("editor.markText(");
script.append(start.toScript());
script.append(", ");
script.append(end.toScript());
script.append(", ");
script.append("'").append(className).append("'");
script.append(")");
execute(script.toString());
}
/**
* Initialize the webview that contains the browser environment for the CodeEditor.
*/
protected void initializeWebView() {
logger.info("Initialising web view");
webView.getEngine().load(getClass().getResource("/editor/editor.html").toExternalForm());
webView.getEngine().getLoadWorker().stateProperty().addListener(
new ChangeListener<Worker.State>() {
@Override
public void changed(ObservableValue ov, Worker.State oldState, Worker.State newState) {
if (newState == Worker.State.SUCCEEDED && !scriptCache.isEmpty()) {
for (String script : scriptCache) {
execute(script);
}
scriptCache.clear();
}
}
});
}
/**
* Execute a JavaScript script in the CodeEditor's browser environment.
*
* @param script The script to run
*/
protected void execute(final String script) {
logger.info("Executing javascript....");
if (webView.getEngine().getLoadWorker().getState() == Worker.State.SUCCEEDED) {
logger.info("Executing... " + script);
webView.getEngine().executeScript(script);
logger.info("Executed script");
} else {
logger.info("Adding script to cache");
scriptCache.add(script);
logger.info("Added script to cache");
}
}
/**
* Represents a line and column in the JavaScript Editor.
*/
public static class Position {
private int line;
private int column;
/**
* Instantiate a new Position.
*
* @param line The line number
* @param column The column number
*/
public Position(int line, int column) {
this.line = line;
this.column = column;
}
/**
* Outputs the position in JavaScript formatting that can be used by the CodeEditor.
*
* @return JavaScript representation of this position.
*/
public String toScript() {
StringBuilder script = new StringBuilder("{ ");
script.append("line: ").append(line);
script.append(", ");
script.append("ch: ").append(column);
script.append(" }");
return script.toString();
}
}
}