All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bridje.jfx.ace.AceEditor Maven / Gradle / Ivy

package org.bridje.jfx.ace;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ChangeListener;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import netscape.javascript.JSObject;

/**
 * Control to edit code using Ace Editor version 1.2.6.
 * Example usage:
 * 

 *     //edit FTL code
 *     AceEditor editor = new AceEditor(AceEditor.Mode.FTL);
 *
 *     //fill content on ready
 *     editor.onReady(() -{@literal >} editor.setText("{@literal <}#ftl encoding='UTF-8'{@literal >}\n"));
 *
 *     //handle replacement of editor selected text
 *     editor.onReplace(text -{@literal >}
 *     {
 *          TextInputDialog dialog = new TextInputDialog("");
 *          dialog.setTitle("Replace...");
 *          dialog.setHeaderText("Please enter the replacement text.");
 *          dialog.setContentText("Replacement text:");
 *
 *          Optional<String> result = dialog.showAndWait();
 *          String replaceValue = "";
 *          if (result.isPresent())
 *          {
 *              replaceValue = result.get();
 *          }
 *          return replaceValue;
 *      });
 *
 *      //listen for text changes
 *      editor.textProperty()
 *            .addListener((observable, oldValue, newValue) -{@literal >} System.out.println(newValue));
 * 
*/ public final class AceEditor extends VBox { private static final Logger LOG = Logger.getLogger(AceEditor.class.getName()); private final ObjectProperty contextMenuProperty = new SimpleObjectProperty<>(); private final SimpleStringProperty textProperty = new SimpleStringProperty(""); private AceJsGate gate; private AceReadyListener readyListener; private final ChangeListener listener; private AceReplaceHandler replaceHandler; /** * Initialize control. * * @param mode indicates the language to edit. (FTL, JAVA, etc). * @see Ace Modes */ public AceEditor(AceMode mode) { WebView editor = new WebView(); loadContent(editor, mode); getChildren().add(editor); contextMenuProperty.addListener((observable, oldValue, newValue) -> { editor.setContextMenuEnabled(false); editor.setOnContextMenuRequested(e -> newValue.show(editor, e.getScreenX(), e.getScreenY())); }); setContextMenu(createDefaultContextMenu()); listener = (observable, oldValue, newValue) -> updateEditorContent(newValue); textProperty().addListener(listener); } /** * Called when editor has loaded. * * @param listener ready event listener. */ public final void onReady(AceReadyListener listener) { readyListener = listener; } /** * Obtains selected text on editor. * * @return selected text. */ public String findSelection() { if (gate != null) { Object raw = gate.exec("editorSelected"); if (raw != null) { return raw.toString(); } } return ""; } /** * Replaces selected text on editor. * * @param text replacement for selected text. */ public void replaceSelection(String text) { if (gate != null) { gate.exec("editorReplaceSelected", text); } } /** * Search and replace text on editor. * * @param oldValue text to search. * @param newValue new text. */ public void searchAndReplace(String oldValue, String newValue) { if (gate != null) { gate.exec("editorSearchAndReplace", oldValue, newValue); } } /** * The property for the context menu of this component. * * @return The property for the context menu of this component. */ public ObjectProperty contextMenuProperty() { return contextMenuProperty; } /** * The context menu of this component. * * @return The context menu of this component. */ public ContextMenu getContextMenu() { return contextMenuProperty.get(); } /** * The context menu of this component. * * @param value The context menu of this component. */ public void setContextMenu(ContextMenu value) { contextMenuProperty.set(value); } /** * Called after a replace has happend. * * @param handler The replace handler. */ public void onReplace(AceReplaceHandler handler) { replaceHandler = handler; } /** * The property for the content of the editor. * * @return The property for the content of the editor. */ public SimpleStringProperty textProperty() { return textProperty; } /** * The content of the editor. * * @return The content of the editor. */ public String getText() { return textProperty.get(); } /** * The content of the editor. * * @param text The content of the editor. */ public void setText(String text) { this.textProperty.set(text); } private ContextMenu createDefaultContextMenu() { ContextMenu contextMenu = new ContextMenu(); contextMenu.getItems().addAll( gateExecMenuItem("Cut", "editorCut"), gateExecMenuItem("Copy", "editorCopy"), gateExecMenuItem("Paste", "editorPaste"), gateExecMenuItem("Replace...", "editorReplace")); return contextMenu; } private MenuItem gateExecMenuItem(String title, String command) { MenuItem mi = new MenuItem(title); mi.setOnAction(event -> gateExec(command)); return mi; } private void gateExec(String command) { if (gate != null) gate.exec(command); } private void updateEditorContent(String text) { String realText = text; if(realText == null) realText = ""; gate.exec("editorContent", realText); } protected void setTextFromJs(String text) { textProperty().removeListener(listener); setText(text); textProperty().addListener(listener); } private void loadContent(WebView editor, AceMode aceMode) { AceMode mode = aceMode; WebEngine engine = editor.getEngine(); if (mode == null) mode = AceMode.JAVA; String strMode = "var mode = 'VALUE';\n{{mode-VALUE.js}}" .replaceAll("VALUE", mode.name().toLowerCase()); engine.loadContent(readContent("ace.html", true, strMode)); engine.getLoadWorker().stateProperty().addListener((observable, oldState, newState) -> { switch (newState) { case SUCCEEDED: JSObject js = (JSObject) engine.executeScript("window"); gate = new AceJsGate(AceEditor.this, js); if (readyListener != null) readyListener.ready(); break; default: break; } }); } private static String readContent(String resource, boolean replace, String mode) { InputStream stream = AceEditor.class.getResourceAsStream(resource); if (stream != null) { BufferedReader buf = new BufferedReader(new InputStreamReader(stream)); StringBuilder builder = new StringBuilder(); try { String line = buf.readLine(); while (line != null) { if (mode != null) line = line.replace("[[MODE]]", mode); if (replace) line = doReplace(line); builder.append(line).append("\n"); line = buf.readLine(); } } catch (IOException ignored) { LOG.log(Level.SEVERE, ignored.getMessage(), ignored); } return builder.toString(); } return ""; } private static String doReplace(String line) { int startIndex = line.indexOf("{{"); if (startIndex < 0) return line; int endIndex = line.indexOf("}}", startIndex); if (endIndex < 0) return line; String name = line.substring(startIndex + 2, endIndex); String replacement = readContent(name, false, null); endIndex += 3; if (endIndex > line.length()) endIndex = line.length(); return line.substring(0, startIndex) + replacement + line.substring(endIndex); } /** * Return the replace handler. * * @return The replace handler. */ public AceReplaceHandler getReplaceHandler() { return replaceHandler; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy