Skip to content

Commit

Permalink
Restore the scripting editor
Browse files Browse the repository at this point in the history
  • Loading branch information
Hartrik committed Nov 23, 2023
1 parent b75b4e1 commit 3b778b8
Show file tree
Hide file tree
Showing 12 changed files with 363 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -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<ListView<ScriptEngineFactory>, ListCell<ScriptEngineFactory>> {

@Override
public ListCell<ScriptEngineFactory> call(
ListView<ScriptEngineFactory> param) {

return new ListCell<ScriptEngineFactory>() {

@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() + ")";
}

}
Original file line number Diff line number Diff line change
@@ -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. <p>
*
* Vyhodnocení je také možné provést zmáčknutím <code>ctrl + space</code>. <p>
*
* 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<ScriptDialogController> {

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 <code>null</code>.
*
* @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<String, Supplier<?>> 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<String, Supplier<?>> bindings) {
controller.bindings = bindings;
}

public void addBindings(Map<String, Supplier<?>> bindings) {
controller.bindings.putAll(bindings);
}
}
Original file line number Diff line number Diff line change
@@ -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<String, Supplier<?>> bindings;
public String preCode = "";

@FXML protected TextArea codeEditor;
@FXML protected TextArea outputArea;
@FXML protected ComboBox<ScriptEngineFactory> 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<ScriptEngineFactory> 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<ScriptEngineFactory> 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<String, Object> 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());
}

}
Original file line number Diff line number Diff line change
@@ -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);
}

}
Original file line number Diff line number Diff line change
@@ -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<String, Supplier<?>> 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;
}

}
8 changes: 4 additions & 4 deletions src/main/java/cz/hartrik/sg2/app/sandbox/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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\n[email protected]";
public static final String APP_AUTHOR = 2023 Patrik Harag\n[email protected]";
public static final String APP_WEB = "https://github.com/Hartrik/Sand-Game-2";

public static final String ICON = "icon - sg2.png";
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/cz/hartrik/sg2/app/sandbox/MainModules.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,11 @@ <h3>Historie verzí - Beta</h3>
</tr>
<tr>
<td>2.04&nbsp;Beta for&nbsp;Java&nbsp;11</td>
<td>2022&#8209;10&#8209;26</td>
<td>2023&#8209;11&#8209;23</td>
<td>
&bull; migrace na Javu 11<br>
&bull; migrace na Maven, zjednodušení projektové struktury<br>
&bull; odebrání scriptovacího dialogu (přestal fungovat)<br>
&bull; nahrazení scriptovacího dialogu (přestal fungovat)<br>
</td>
</tr>
</tbody>
Expand Down
Loading

0 comments on commit 3b778b8

Please sign in to comment.