From 3b778b88c314955439017bf4714bc3588de0f9b2 Mon Sep 17 00:00:00 2001 From: Patrik Harag Date: Thu, 23 Nov 2023 20:46:34 +0100 Subject: [PATCH] Restore the scripting editor --- .../dialog/script/EngineCellFactory.java | 39 +++++++ .../extension/dialog/script/ScriptDialog.java | 77 +++++++++++++ .../dialog/script/ScriptDialogController.java | 107 ++++++++++++++++++ .../script/ModuleToolBarScriptDialog.java | 40 +++++++ .../module/script/ScriptDialogService.java | 48 ++++++++ .../java/cz/hartrik/sg2/app/sandbox/Main.java | 8 +- .../hartrik/sg2/app/sandbox/MainModules.java | 2 + .../dialog/about/version history - beta.html | 4 +- .../extension/dialog/script/ScriptDialog.fxml | 38 +++++++ .../dialog/script/Strings.properties | 3 + .../dialog/script/Strings_cs_CZ.properties | 3 + .../extension/dialog/script/icon - script.png | Bin 0 -> 799 bytes 12 files changed, 363 insertions(+), 6 deletions(-) create mode 100644 src/main/java/cz/hartrik/sg2/app/extension/dialog/script/EngineCellFactory.java create mode 100644 src/main/java/cz/hartrik/sg2/app/extension/dialog/script/ScriptDialog.java create mode 100644 src/main/java/cz/hartrik/sg2/app/extension/dialog/script/ScriptDialogController.java create mode 100644 src/main/java/cz/hartrik/sg2/app/module/script/ModuleToolBarScriptDialog.java create mode 100644 src/main/java/cz/hartrik/sg2/app/module/script/ScriptDialogService.java create mode 100644 src/main/resources/cz/hartrik/sg2/app/extension/dialog/script/ScriptDialog.fxml create mode 100644 src/main/resources/cz/hartrik/sg2/app/extension/dialog/script/Strings.properties create mode 100644 src/main/resources/cz/hartrik/sg2/app/extension/dialog/script/Strings_cs_CZ.properties create mode 100644 src/main/resources/cz/hartrik/sg2/app/extension/dialog/script/icon - script.png diff --git a/src/main/java/cz/hartrik/sg2/app/extension/dialog/script/EngineCellFactory.java b/src/main/java/cz/hartrik/sg2/app/extension/dialog/script/EngineCellFactory.java new file mode 100644 index 0000000..e41bcf8 --- /dev/null +++ b/src/main/java/cz/hartrik/sg2/app/extension/dialog/script/EngineCellFactory.java @@ -0,0 +1,39 @@ + +package cz.hartrik.sg2.app.extension.dialog.script; + +import javafx.scene.control.ListCell; +import javafx.scene.control.ListView; +import javafx.util.Callback; +import javax.script.ScriptEngineFactory; + +/** + * Formátuje položky objektu {@link ScriptEngineFactory}. + * + * @version 2014-06-28 + * @author Patrik Harag + */ +public class EngineCellFactory implements + Callback, ListCell> { + + @Override + public ListCell call( + ListView param) { + + return new ListCell() { + + @Override + public void updateItem(ScriptEngineFactory item, boolean empty) { + super.updateItem(item, empty); + + setText((empty || item == null) + ? null + : format(item)); + } + }; + } + + protected String format(ScriptEngineFactory factory) { + return factory.getLanguageName() + " (" + factory.getEngineName() + ")"; + } + +} \ No newline at end of file diff --git a/src/main/java/cz/hartrik/sg2/app/extension/dialog/script/ScriptDialog.java b/src/main/java/cz/hartrik/sg2/app/extension/dialog/script/ScriptDialog.java new file mode 100644 index 0000000..118ded7 --- /dev/null +++ b/src/main/java/cz/hartrik/sg2/app/extension/dialog/script/ScriptDialog.java @@ -0,0 +1,77 @@ + +package cz.hartrik.sg2.app.extension.dialog.script; + +import cz.hartrik.common.io.NioUtil; +import cz.hartrik.common.io.Resources; +import cz.hartrik.common.ui.javafx.FXMLControlledStage; +import java.util.Map; +import java.util.ResourceBundle; +import java.util.function.Supplier; +import javafx.stage.Modality; +import javafx.stage.Window; + +/** + * Dialog s textovými poli pro zdrojový kód a výstup, combo boxem pro výběr + * libovolného podporovaného skriptovacího enginu a tlačítky pro vyhodnocení + * a zkopírování výstupu.

+ * + * Vyhodnocení je také možné provést zmáčknutím ctrl + space.

+ * + * Dialog může pokročilému uživateli umožnit vytvořit si vlastní výstup z + * aplikace. + * + * @version 2023-11-23 + * @author Patrik Harag + */ +public class ScriptDialog extends FXMLControlledStage { + + private static final String PACKAGE = "/cz/hartrik/sg2/app/extension/dialog/script/"; + + public static final String PATH_FXML = PACKAGE + "ScriptDialog.fxml"; + public static final String PATH_FRAME_ICON = PACKAGE + "icon - script.png"; + public static final String PATH_PROPERTIES = NioUtil.dottedPath(PACKAGE) + "Strings"; + + // --- konstruktory + + /** + * Vytvoří novou instanci. Všechny parametry mohou být null. + * + * @param owner nadřazené okno, může být null + * @param bindings objekty, které budou ve skriptu přístupné + * (název proměnné - objekt) + * @param defaultEngine jméno enginu, který bude po zobrazení vybrán + * @param defaultCode výchozí zdrojový kód + */ + public ScriptDialog(Window owner, Map> bindings, + String defaultEngine, String defaultCode) { + + super(ScriptDialog.class.getResource(PATH_FXML), + ResourceBundle.getBundle(PATH_PROPERTIES)); + + controller.bindings = bindings; + controller.defaultCode = (defaultCode == null ? "" : defaultCode); + controller.defaultEngine = defaultEngine; + + initOwner(owner); + getIcons().setAll(Resources.image(PATH_FRAME_ICON)); + + setMinWidth(500); + setMinHeight(300); + + initModality(Modality.APPLICATION_MODAL); + } + + // settery + + public void setPreCode(String code) { + controller.preCode = code; + } + + public void setBindings(Map> bindings) { + controller.bindings = bindings; + } + + public void addBindings(Map> bindings) { + controller.bindings.putAll(bindings); + } +} \ No newline at end of file diff --git a/src/main/java/cz/hartrik/sg2/app/extension/dialog/script/ScriptDialogController.java b/src/main/java/cz/hartrik/sg2/app/extension/dialog/script/ScriptDialogController.java new file mode 100644 index 0000000..3b6f519 --- /dev/null +++ b/src/main/java/cz/hartrik/sg2/app/extension/dialog/script/ScriptDialogController.java @@ -0,0 +1,107 @@ + +package cz.hartrik.sg2.app.extension.dialog.script; + +import cz.hartrik.common.io.ClipboardUtil; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.net.URL; +import java.util.List; +import java.util.Map; +import java.util.ResourceBundle; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import javafx.application.Platform; +import javafx.fxml.FXML; +import javafx.fxml.Initializable; +import javafx.scene.control.ComboBox; +import javafx.scene.control.TextArea; +import javafx.util.Pair; +import javax.script.ScriptContext; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; +import javax.script.ScriptEngineManager; + +/** + * Kontroler FXML dokumentu. + * + * @version 2023-11-23 + * @author Patrik Harag + */ +public class ScriptDialogController implements Initializable { + + public String defaultCode = ""; + public String defaultEngine = "js"; + public Map> bindings; + public String preCode = ""; + + @FXML protected TextArea codeEditor; + @FXML protected TextArea outputArea; + @FXML protected ComboBox engineComboBox; + + @Override + public void initialize(URL url, ResourceBundle rb) { + Platform.runLater(() -> { + codeEditor.setText(defaultCode); + + ScriptEngineManager manager = new ScriptEngineManager(); + EngineCellFactory cellFactory = new EngineCellFactory(); + engineComboBox.setButtonCell(cellFactory.call(null)); + engineComboBox.setCellFactory(cellFactory); + engineComboBox.getItems().addAll(manager.getEngineFactories()); + + List factories = manager.getEngineFactories(); + ScriptEngineFactory factory = getFactory(defaultEngine, factories); + if (factory == null) + factory = getFactory("js", factories); + + engineComboBox.getSelectionModel().select(factory); + }); + } + + protected static ScriptEngineFactory getFactory( + String name, List factories) { + + for (ScriptEngineFactory factory : factories) + if (factory.getNames().contains(name)) + return factory; + + return null; + } + + @FXML + public void eval() { + ScriptEngine engine = engineComboBox.getSelectionModel() + .getSelectedItem().getScriptEngine(); + + if (bindings != null) { + Map collect = bindings.entrySet().stream() + .map(entry -> new Pair<>(entry.getKey(), entry.getValue().get())) + .collect(Collectors.toMap(Pair::getKey, Pair::getValue)); + + engine.getBindings(ScriptContext.ENGINE_SCOPE).putAll(collect); + } + + StringWriter outSW = new StringWriter(); + PrintWriter outPW = new PrintWriter(outSW); + engine.getContext().setWriter(outPW); + + try { + if (!preCode.isEmpty()) + engine.eval(preCode); + + engine.eval(codeEditor.getText()); + + } catch (Exception ex) { + outputArea.setText(ex.toString()); + return; + } + + outputArea.setText(outSW.getBuffer().toString()); + } + + @FXML + public void copy() { + ClipboardUtil.copy(outputArea.getText()); + } + +} \ No newline at end of file diff --git a/src/main/java/cz/hartrik/sg2/app/module/script/ModuleToolBarScriptDialog.java b/src/main/java/cz/hartrik/sg2/app/module/script/ModuleToolBarScriptDialog.java new file mode 100644 index 0000000..132857c --- /dev/null +++ b/src/main/java/cz/hartrik/sg2/app/module/script/ModuleToolBarScriptDialog.java @@ -0,0 +1,40 @@ + +package cz.hartrik.sg2.app.module.script; + +import cz.hartrik.sg2.app.Application; +import cz.hartrik.sg2.app.extension.dialog.script.ScriptDialog; +import cz.hartrik.sg2.app.module.ApplicationModule; +import cz.hartrik.sg2.app.service.Require; +import javafx.scene.control.Button; +import javafx.scene.image.ImageView; + +/** + * Modul přidá do toolbaru tlačítko vyvolávající scriptovací dialog. + * + * @version 2016-07-10 + * @author Patrik Harag + */ +@Require(ScriptDialogService.class) +public class ModuleToolBarScriptDialog implements ApplicationModule { + + private final String text; + + public ModuleToolBarScriptDialog(String text) { + this.text = text; + } + + @Override + public void init(Application app) { + ImageView icon = new ImageView(ScriptDialog.PATH_FRAME_ICON); + icon.setFitHeight(16); + icon.setFitWidth(16); + + Button button = new Button(text, icon); + button.setOnAction((e) -> { + app.getServiceManager().run(ScriptDialogService.SERVICE_SHOW_SCRIPT_DIALOG); + }); + + app.getController().getToolBar().getItems().add(button); + } + +} \ No newline at end of file diff --git a/src/main/java/cz/hartrik/sg2/app/module/script/ScriptDialogService.java b/src/main/java/cz/hartrik/sg2/app/module/script/ScriptDialogService.java new file mode 100644 index 0000000..fe87cff --- /dev/null +++ b/src/main/java/cz/hartrik/sg2/app/module/script/ScriptDialogService.java @@ -0,0 +1,48 @@ + +package cz.hartrik.sg2.app.module.script; + +import cz.hartrik.sg2.app.Application; +import cz.hartrik.sg2.app.Frame; +import cz.hartrik.sg2.app.Strings; +import cz.hartrik.sg2.app.extension.dialog.script.ScriptDialog; +import cz.hartrik.sg2.app.service.Service; +import cz.hartrik.sg2.app.service.ServiceProvider; +import java.util.Map; +import java.util.function.Supplier; + +/** + * Poskytuje službu scriptovacího dialogu. + * + * @version 2023-11-23 + * @author Patrik Harag + */ +@ServiceProvider +public class ScriptDialogService { + + public static final String SERVICE_SHOW_SCRIPT_DIALOG = "script-dialog"; + + private ScriptDialog dialog; + + @Service(SERVICE_SHOW_SCRIPT_DIALOG) + public void showScriptDialog(Application app) { + if (dialog == null) + dialog = createDialog(app.getStage(), app); + + app.getSyncTools().pauseProcessor(dialog::showAndWait); + } + + private ScriptDialog createDialog(Frame owner, Application app) { + JSPublicAPI api = new JSPublicAPI(app); + Map> map = api.getBindings(); + String def = api.defaultCode(); + + ScriptDialog dialog = new ScriptDialog(owner, map, "js", def); + dialog.setWidth(700); + dialog.setMinHeight(500); + dialog.setTitle(Strings.get("module.script.scripting-dialog")); + dialog.setPreCode(api.loadInitCode()); + + return dialog; + } + +} \ No newline at end of file diff --git a/src/main/java/cz/hartrik/sg2/app/sandbox/Main.java b/src/main/java/cz/hartrik/sg2/app/sandbox/Main.java index 5631b17..cc0adaa 100644 --- a/src/main/java/cz/hartrik/sg2/app/sandbox/Main.java +++ b/src/main/java/cz/hartrik/sg2/app/sandbox/Main.java @@ -21,7 +21,7 @@ /** * Vstupní třída. * - * @version 2022-10-26 + * @version 2023-11-23 * @author Patrik Harag */ public class Main extends javafx.application.Application { @@ -30,10 +30,10 @@ public class Main extends javafx.application.Application { private static final String LOGGING_CONFIG = "/logging.properties"; public static final String APP_NAME = "Sand Game 2"; - public static final String APP_VERSION = "2.04 Beta J11"; - public static final String APP_VERSION_DATE = "2022-10-26"; + public static final String APP_VERSION = "2.04 Beta J11 hotfix 2"; + public static final String APP_VERSION_DATE = "2023-11-23"; public static final String APP_TITLE = APP_NAME + " (" + APP_VERSION + ")"; - public static final String APP_AUTHOR = "© 2022 Patrik Harag\npatrik.harag@gmail.com"; + public static final String APP_AUTHOR = "© 2023 Patrik Harag\npatrik.harag@gmail.com"; public static final String APP_WEB = "https://github.com/Hartrik/Sand-Game-2"; public static final String ICON = "icon - sg2.png"; diff --git a/src/main/java/cz/hartrik/sg2/app/sandbox/MainModules.java b/src/main/java/cz/hartrik/sg2/app/sandbox/MainModules.java index aa6d2e2..17cf1a6 100644 --- a/src/main/java/cz/hartrik/sg2/app/sandbox/MainModules.java +++ b/src/main/java/cz/hartrik/sg2/app/sandbox/MainModules.java @@ -14,6 +14,7 @@ import cz.hartrik.sg2.app.module.options.*; import cz.hartrik.sg2.app.module.script.CreateScriptSubmodule; import cz.hartrik.sg2.app.module.script.MenuModuleScriptFolder; +import cz.hartrik.sg2.app.module.script.ModuleToolBarScriptDialog; import cz.hartrik.sg2.app.module.tools.PasteSaveSubmodule; import cz.hartrik.sg2.app.module.tools.RandomizerSubmodule; import cz.hartrik.sg2.app.module.tools.ShapesSubmodule; @@ -115,6 +116,7 @@ public static ApplicationModule[] modules() { new ModuleToolBarScale(), new ModuleToolBarSimpleButton(Strings.get("module.edit.fill"), EditServices.SERVICE_EDIT_FILL), new ModuleToolBarSimpleButton(Strings.get("module.io.scr"), ScreenshotService.SERVICE_SCREENSHOT), + new ModuleToolBarScriptDialog(Strings.get("module.script.scripting-dialog")), new ModuleDragAndDropIO(ioManager), }; diff --git a/src/main/resources/cz/hartrik/sg2/app/extension/dialog/about/version history - beta.html b/src/main/resources/cz/hartrik/sg2/app/extension/dialog/about/version history - beta.html index 1508f09..b127878 100644 --- a/src/main/resources/cz/hartrik/sg2/app/extension/dialog/about/version history - beta.html +++ b/src/main/resources/cz/hartrik/sg2/app/extension/dialog/about/version history - beta.html @@ -128,11 +128,11 @@

Historie verzí - Beta

2.04 Beta for Java 11 - 2022‑10‑26 + 2023‑11‑23 • migrace na Javu 11
• migrace na Maven, zjednodušení projektové struktury
- • odebrání scriptovacího dialogu (přestal fungovat)
+ • nahrazení scriptovacího dialogu (přestal fungovat)
diff --git a/src/main/resources/cz/hartrik/sg2/app/extension/dialog/script/ScriptDialog.fxml b/src/main/resources/cz/hartrik/sg2/app/extension/dialog/script/ScriptDialog.fxml new file mode 100644 index 0000000..e4acb77 --- /dev/null +++ b/src/main/resources/cz/hartrik/sg2/app/extension/dialog/script/ScriptDialog.fxml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + +