diff --git a/WorldPainter/WPGUI/src/main/java/org/pepsoft/worldpainter/tools/scripts/ScriptRunner.java b/WorldPainter/WPGUI/src/main/java/org/pepsoft/worldpainter/tools/scripts/ScriptRunner.java index 515264430..69f4f34b4 100644 --- a/WorldPainter/WPGUI/src/main/java/org/pepsoft/worldpainter/tools/scripts/ScriptRunner.java +++ b/WorldPainter/WPGUI/src/main/java/org/pepsoft/worldpainter/tools/scripts/ScriptRunner.java @@ -65,19 +65,21 @@ public ScriptRunner(Window parent, World2 world, Dimension dimension, Collection setupScript((File) jComboBox1.getSelectedItem()); } setControlStates(); - + getRootPane().setDefaultButton(jButton2); scaleToUI(); pack(); setLocationRelativeTo(parent); } + private static HashMap scriptPropertyMap = new HashMap(); + private void setControlStates() { jButton2.setEnabled((jComboBox1.getSelectedItem() != null) && ((File) jComboBox1.getSelectedItem()).isFile() && ((scriptDescriptor == null) || scriptDescriptor.isValid())); } - + private void selectFile() { Set extensions = new HashSet<>(); SCRIPT_ENGINE_MANAGER.getEngineFactories().forEach(factory -> extensions.addAll(factory.getExtensions())); @@ -145,9 +147,9 @@ private void setupScript(File script) { } boolean allFieldsOptional = true; for (ParameterDescriptor paramDescriptor: scriptDescriptor.parameterDescriptors) { - boolean showAsMandatory = (! paramDescriptor.optional) && ((paramDescriptor instanceof FileParameterDescriptor) || (paramDescriptor instanceof FloatParameterDescriptor) || (paramDescriptor instanceof StringParameterDescriptor)); + boolean showAsMandatory = (!paramDescriptor.optional) && ((paramDescriptor instanceof FileParameterDescriptor) || (paramDescriptor instanceof FloatParameterDescriptor) || (paramDescriptor instanceof StringParameterDescriptor)); JLabel label = new JLabel(((paramDescriptor.displayName != null) ? paramDescriptor.displayName : paramDescriptor.name) + (showAsMandatory ? "*:" : ":")); - allFieldsOptional &= ! showAsMandatory; + allFieldsOptional &= !showAsMandatory; JComponent editor = paramDescriptor.getEditor(); label.setLabelFor(editor); if (paramDescriptor.description != null) { @@ -160,6 +162,7 @@ private void setupScript(File script) { addlastOnLine(panelDescriptor, editor); paramDescriptor.setChangeListener(e -> setControlStates()); } + scriptDescriptor.loadValuesIntoEditors(); if (! allFieldsOptional) { addlastOnLine(panelDescriptor, new JLabel("* mandatory parameter")); } @@ -193,7 +196,7 @@ private void addlastOnLine(JPanel panel, JComponent component) { constraints.gridwidth = GridBagConstraints.REMAINDER; panel.add(component, constraints); } - + private ScriptDescriptor analyseScript(File script) { if (! script.isFile()) { return null; @@ -294,8 +297,44 @@ private ScriptDescriptor analyseScript(File script) { throw new IllegalArgumentException("Invalid key \"" + key + "\" in script descriptor"); } }); - return descriptor; + + ScriptDescriptor usedDescriptor = selectDescriptor(scriptPropertyMap, descriptor); + return usedDescriptor; + } + } + + /** + * selects the descriptor to use for the script. + *

+ * If the oldDescriptor map has a descriptor with the same name and same parameter names, the old one is used. + * if not, the new one is used. + * + * @param oldDescriptors + * @param newDescriptor + * @return + */ + public static ScriptDescriptor selectDescriptor(final HashMap oldDescriptors, ScriptDescriptor newDescriptor) { + if (newDescriptor.name == null || !oldDescriptors.containsKey(newDescriptor.name)) + return newDescriptor; + + ScriptDescriptor mappedDescriptor = oldDescriptors.get(newDescriptor.name); + + boolean paramsMissing = !newDescriptor.parameterDescriptors.stream().allMatch( + p -> hasDescriptorWithNameAndType(mappedDescriptor.parameterDescriptors, p)); + if (paramsMissing) + return newDescriptor; + + return mappedDescriptor; + + } + + public static boolean hasDescriptorWithNameAndType(List list, ParameterDescriptor descriptorA) { + for (ParameterDescriptor descriptorB : list) { + if (descriptorB.name.equals(descriptorA.name) && descriptorB.getClass().equals(descriptorA.getClass())) + return true; + } + return false; } private void run() { @@ -311,6 +350,9 @@ private void run() { final Map params; if (scriptDescriptor != null) { params = scriptDescriptor.getValues(); + scriptDescriptor.saveValuesFromEditors(); + if (scriptDescriptor.name != null) + scriptPropertyMap.put(scriptDescriptor.name, scriptDescriptor); if (scriptDescriptor.name != null) { scriptName = scriptDescriptor.name; } else { @@ -689,6 +731,17 @@ boolean isValid() { return parameterDescriptors.stream().allMatch(p -> p.isEditorValid()); } + void saveValuesFromEditors() { + parameterDescriptors.forEach(p -> p.setInternalValue(p.getValue())); + } + + void loadValuesIntoEditors() { + parameterDescriptors.forEach(p -> { + if (p.getInternalValue() != null) + p.setValue(p.getInternalValue()); + }); + } + Map getValues() { Map values = new HashMap<>(); parameterDescriptors.forEach(p -> { @@ -716,6 +769,16 @@ E getEditor() { return editor; } + private T internalValue; + + T getInternalValue() { + return internalValue; + } + + public void setInternalValue(T internalValue) { + this.internalValue = internalValue; + } + boolean isEditorValid() { return true; } @@ -751,6 +814,13 @@ protected void notifyChangeListener() { } static class StringParameterDescriptor extends ParameterDescriptor { + public StringParameterDescriptor(String name) { + this.name = name; + } + + public StringParameterDescriptor() { + } + @Override protected JTextField createEditor() { JTextField field = new JTextField(defaultValue); @@ -796,6 +866,15 @@ void setValue(String value) { } static class IntegerParameterDescriptor extends ParameterDescriptor { + public IntegerParameterDescriptor(String name) { + super(); + this.name = name; + } + + public IntegerParameterDescriptor() { + super(); + } + @Override protected JSpinner createEditor() { JSpinner spinner = new JSpinner(); diff --git a/WorldPainter/WPGUI/src/test/java/org/pepsoft/worldpainter/tools/scripts/ScriptRunnerTest.java b/WorldPainter/WPGUI/src/test/java/org/pepsoft/worldpainter/tools/scripts/ScriptRunnerTest.java new file mode 100644 index 000000000..1c1263b73 --- /dev/null +++ b/WorldPainter/WPGUI/src/test/java/org/pepsoft/worldpainter/tools/scripts/ScriptRunnerTest.java @@ -0,0 +1,47 @@ +package org.pepsoft.worldpainter.tools.scripts; + +import org.junit.Test; +import java.util.HashMap; +import java.util.Objects; + +public class ScriptRunnerTest { + @Test + public void testChooseScriptDescriptor() { + HashMap map = new HashMap<>(); + + //empty map + final ScriptRunner.ScriptDescriptor myNewScriptParams = new ScriptRunner.ScriptDescriptor(); + assert ScriptRunner.selectDescriptor(map, myNewScriptParams) == myNewScriptParams; //should be same object + + //map with null key + map.put(null, new ScriptRunner.ScriptDescriptor()); + assert ScriptRunner.selectDescriptor(map, myNewScriptParams) == myNewScriptParams; //should be same object + + final String descriptorName = "myName"; + + myNewScriptParams.name = descriptorName; + myNewScriptParams.parameterDescriptors.add(new ScriptRunner.IntegerParameterDescriptor("an Integer parameter")); + assert myNewScriptParams.parameterDescriptors.size() == 1; + + + ScriptRunner.ScriptDescriptor oldScriptParams = new ScriptRunner.ScriptDescriptor(); + oldScriptParams.name = descriptorName; + map.put(descriptorName, oldScriptParams); + + //name match but parameter mismatch + assert ScriptRunner.selectDescriptor(map, myNewScriptParams) == myNewScriptParams; //should be same object + + //name match and parameter match + oldScriptParams.parameterDescriptors.add(new ScriptRunner.IntegerParameterDescriptor("an Integer parameter")); + assert Objects.equals(oldScriptParams.name, myNewScriptParams.name); + assert Objects.equals(oldScriptParams.parameterDescriptors.get(0).name, myNewScriptParams.parameterDescriptors.get(0).name); + assert map.get(descriptorName) == oldScriptParams; //should be same object + + assert ScriptRunner.selectDescriptor(map, myNewScriptParams) == oldScriptParams; //should be same object + + //name match, parameter name match, parameter type mismatch + oldScriptParams.parameterDescriptors.set(0, new ScriptRunner.StringParameterDescriptor("an Integer parameter")); + assert ScriptRunner.selectDescriptor(map, myNewScriptParams) == myNewScriptParams; //should be same object + + } +} \ No newline at end of file