diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index eba889dc0..9404edba0 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -407,7 +407,7 @@ SimulationExtension.javacode.className = Fully-qualified Java class name: SimulationExtension.scripting.name = {language} script SimulationExtension.scripting.desc = Extend OpenRocket simulations by custom scripts. -SimulationExtension.scripting.script.label = JavaScript code: +SimulationExtension.scripting.language.label = Language: SimulationEditDialog.btn.plot = Plot SimulationEditDialog.btn.export = Export diff --git a/core/src/net/sf/openrocket/simulation/extension/impl/ScriptingExtension.java b/core/src/net/sf/openrocket/simulation/extension/impl/ScriptingExtension.java index 4cd1c7ef7..03785c036 100644 --- a/core/src/net/sf/openrocket/simulation/extension/impl/ScriptingExtension.java +++ b/core/src/net/sf/openrocket/simulation/extension/impl/ScriptingExtension.java @@ -13,10 +13,10 @@ import net.sf.openrocket.simulation.listeners.SimulationListener; public class ScriptingExtension extends AbstractSimulationExtension { - private static final String JS = "JavaScript"; + private static final String DEFAULT_LANGUAGE = "JavaScript"; public ScriptingExtension() { - setLanguage(JS); + setLanguage(DEFAULT_LANGUAGE); } @Override @@ -46,8 +46,7 @@ public class ScriptingExtension extends AbstractSimulationExtension { } public String getLanguage() { - // TODO: Support other languages - return JS; + return config.getString("language", DEFAULT_LANGUAGE); } public void setLanguage(String language) { @@ -57,7 +56,10 @@ public class ScriptingExtension extends AbstractSimulationExtension { SimulationListener getListener() throws SimulationException { ScriptEngineManager manager = new ScriptEngineManager(); - ScriptEngine engine = manager.getEngineByName("JavaScript"); + ScriptEngine engine = manager.getEngineByName(getLanguage()); + if (engine == null) { + throw new SimulationException("Your JRE does not support the scripting language '" + getLanguage() + "'"); + } try { engine.eval(getScript()); diff --git a/core/src/net/sf/openrocket/util/ScriptingUtil.java b/core/src/net/sf/openrocket/util/ScriptingUtil.java new file mode 100644 index 000000000..35653255c --- /dev/null +++ b/core/src/net/sf/openrocket/util/ScriptingUtil.java @@ -0,0 +1,53 @@ +package net.sf.openrocket.util; + +import java.util.Arrays; +import java.util.List; + +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; +import javax.script.ScriptEngineManager; + +public class ScriptingUtil { + + /** The name to be chosen from a list of alternatives. If not found, will use the default name. */ + private static final List PREFERRED_LANGUAGE_NAMES = Arrays.asList("JavaScript"); + + /** + * Return the preferred internal language name based on a script language name. + * + * @return the preferred language name, or null if the language is not supported. + */ + public static String getLanguage(String language) { + if (language == null) { + return null; + } + + ScriptEngineManager manager = new ScriptEngineManager(); + ScriptEngine engine = manager.getEngineByName(language); + if (engine == null) { + return null; + } + return getLanguage(engine.getFactory()); + } + + + public static List getLanguages() { + List langs = new ArrayList(); + ScriptEngineManager manager = new ScriptEngineManager(); + for (ScriptEngineFactory factory : manager.getEngineFactories()) { + langs.add(getLanguage(factory)); + } + return langs; + } + + + private static String getLanguage(ScriptEngineFactory factory) { + for (String name : factory.getNames()) { + if (PREFERRED_LANGUAGE_NAMES.contains(name)) { + return name; + } + } + + return factory.getLanguageName(); + } +} diff --git a/core/test/net/sf/openrocket/util/TestScriptingUtil.java b/core/test/net/sf/openrocket/util/TestScriptingUtil.java new file mode 100644 index 000000000..1d657f507 --- /dev/null +++ b/core/test/net/sf/openrocket/util/TestScriptingUtil.java @@ -0,0 +1,32 @@ +package net.sf.openrocket.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class TestScriptingUtil { + + /* + * Note: This class assumes that the JRE supports JavaScript scripting. + */ + + @Test + public void testGetLanguage() { + assertEquals(null, ScriptingUtil.getLanguage(null)); + assertEquals(null, ScriptingUtil.getLanguage("")); + assertEquals(null, ScriptingUtil.getLanguage("foobar")); + assertEquals("JavaScript", ScriptingUtil.getLanguage("JavaScript")); + assertEquals("JavaScript", ScriptingUtil.getLanguage("javascript")); + assertEquals("JavaScript", ScriptingUtil.getLanguage("ECMAScript")); + assertEquals("JavaScript", ScriptingUtil.getLanguage("js")); + } + + + @Test + public void testGetLanguages() { + assertTrue(ScriptingUtil.getLanguages().size() >= 1); + assertTrue(ScriptingUtil.getLanguages().contains("JavaScript")); + } + +} diff --git a/swing/src/net/sf/openrocket/simulation/extension/AbstractSwingSimulationExtensionConfigurator.java b/swing/src/net/sf/openrocket/simulation/extension/AbstractSwingSimulationExtensionConfigurator.java index 444c993fd..9c6af0ba8 100644 --- a/swing/src/net/sf/openrocket/simulation/extension/AbstractSwingSimulationExtensionConfigurator.java +++ b/swing/src/net/sf/openrocket/simulation/extension/AbstractSwingSimulationExtensionConfigurator.java @@ -24,6 +24,8 @@ public abstract class AbstractSwingSimulationExtensionConfigurator extensionClass; + private JDialog dialog; + protected AbstractSwingSimulationExtensionConfigurator(Class extensionClass) { this.extensionClass = extensionClass; } @@ -37,7 +39,7 @@ public abstract class AbstractSwingSimulationExtensionConfigurator { - protected ScriptingConfigurator() { + private JComboBox languageSelector; + private RSyntaxTextArea text; + + private ScriptingExtension extension; + private Simulation simulation; + + public ScriptingConfigurator() { super(ScriptingExtension.class); } @Override protected JComponent getConfigurationComponent(final ScriptingExtension extension, Simulation simulation, JPanel panel) { + this.extension = extension; + this.simulation = simulation; - panel.add(new StyledLabel(trans.get("SimulationExtension.scripting.script.label"), Style.BOLD), "wrap"); + panel.add(new StyledLabel(trans.get("SimulationExtension.scripting.language.label"), Style.BOLD), ""); - final RSyntaxTextArea text = new RSyntaxTextArea(extension.getScript(), 15, 60); + String[] languages = ScriptingUtil.getLanguages().toArray(new String[0]); + languageSelector = new JComboBox(languages); + languageSelector.setEditable(false); + languageSelector.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + setLanguage((String) languageSelector.getSelectedItem()); + } + }); + panel.add(languageSelector, "wrap para"); + + + text = new RSyntaxTextArea(extension.getScript(), 15, 60); text.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT); text.setCodeFoldingEnabled(true); text.setLineWrap(true); @@ -51,9 +79,44 @@ public class ScriptingConfigurator extends AbstractSwingSimulationExtensionConfi }); RTextScrollPane scroll = new RTextScrollPane(text); - panel.add(scroll, "grow"); + panel.add(scroll, "spanx, grow"); + + setLanguage(ScriptingUtil.getLanguage(extension.getLanguage())); return panel; } + private void setLanguage(String language) { + if (language == null) { + language = ""; + } + if (!language.equals(languageSelector.getSelectedItem())) { + languageSelector.setSelectedItem(language); + } + extension.setLanguage(language); + text.setSyntaxEditingStyle(findSyntaxLanguage(language)); + getDialog().setTitle(getTitle(extension, simulation)); + } + + private String findSyntaxLanguage(String language) { + ScriptEngineManager manager = new ScriptEngineManager(); + ScriptEngine engine = manager.getEngineByName(language); + + if (engine != null) { + Set supported = TokenMakerFactory.getDefaultInstance().keySet(); + for (String type : engine.getFactory().getMimeTypes()) { + if (supported.contains(type)) { + return type; + } + for (String match : supported) { + if (match.contains("/" + language.toLowerCase())) { + return match; + } + } + } + } + + return SyntaxConstants.SYNTAX_STYLE_NONE; + } + } diff --git a/swing/src/net/sf/openrocket/utils/Scripting.java b/swing/src/net/sf/openrocket/utils/Scripting.java new file mode 100644 index 000000000..ca1a2993d --- /dev/null +++ b/swing/src/net/sf/openrocket/utils/Scripting.java @@ -0,0 +1,38 @@ +package net.sf.openrocket.utils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.script.ScriptEngineFactory; +import javax.script.ScriptEngineManager; + +import org.fife.ui.rsyntaxtextarea.TokenMakerFactory; + +public class Scripting { + + public static void main(String[] args) { + System.out.println("Scripting APIs:"); + + ScriptEngineManager manager = new ScriptEngineManager(); + for (ScriptEngineFactory factory : manager.getEngineFactories()) { + System.out.println(" engineName=" + factory.getEngineName() + + " engineVersion=" + factory.getEngineVersion() + + " languageName=" + factory.getLanguageName() + + " languageVersion=" + factory.getLanguageVersion() + + " names=" + factory.getNames() + + " mimeTypes=" + factory.getMimeTypes() + + " extensions=" + factory.getExtensions()); + } + System.out.println(); + + System.out.println("RSyntaxTextArea supported syntax languages:"); + TokenMakerFactory f = TokenMakerFactory.getDefaultInstance(); + List list = new ArrayList(f.keySet()); + Collections.sort(list); + for (String type : list) { + System.out.println(" " + type); + } + System.out.println(); + } +}