From f38c8a48c959ff77ad4507f9c5583079f5fac03b Mon Sep 17 00:00:00 2001 From: SiboVG Date: Tue, 14 Feb 2023 04:59:44 +0000 Subject: [PATCH 1/9] Use proper substitutor for flight config name --- .../rocketcomponent/FlightConfiguration.java | 36 +++---------------- 1 file changed, 5 insertions(+), 31 deletions(-) diff --git a/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java b/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java index 889d0f6d7..1b2ec0f0d 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java +++ b/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java @@ -8,6 +8,7 @@ import java.util.Map; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; +import net.sf.openrocket.formatting.RocketDescriptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,6 +37,7 @@ public class FlightConfiguration implements FlightConfigurableParameter Date: Tue, 14 Feb 2023 05:00:48 +0000 Subject: [PATCH 2/9] [#2055] Add manufacturers substitutor --- core/resources/l10n/messages.properties | 1 + .../MotorManufacturerSubstitutor.java | 144 ++++++++++++++++++ 2 files changed, 145 insertions(+) create mode 100644 core/src/net/sf/openrocket/formatting/MotorManufacturerSubstitutor.java diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index e7f8ae5e9..df5bc30a7 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -2263,6 +2263,7 @@ SeparationSelectionDialog.opt.override = Override for the {0} flight configurati MotorConfigurationPanel.description = Select the motors and motor ignition events of the selected flight configuration.
Motor mounts: Select which components function as motor mounts.
Motor configurations: Select the motor and ignition event for each motor mount. MotorDescriptionSubstitutor.description = Motors in the configuration +MotorManufacturerSubstitutor.description = Motor manufacturers in the configuration !Photo Panel diff --git a/core/src/net/sf/openrocket/formatting/MotorManufacturerSubstitutor.java b/core/src/net/sf/openrocket/formatting/MotorManufacturerSubstitutor.java new file mode 100644 index 000000000..0c75ebe29 --- /dev/null +++ b/core/src/net/sf/openrocket/formatting/MotorManufacturerSubstitutor.java @@ -0,0 +1,144 @@ +package net.sf.openrocket.formatting; + +import com.google.inject.Inject; +import net.sf.openrocket.l10n.Translator; +import net.sf.openrocket.motor.Motor; +import net.sf.openrocket.motor.MotorConfiguration; +import net.sf.openrocket.motor.ThrustCurveMotor; +import net.sf.openrocket.plugin.Plugin; +import net.sf.openrocket.rocketcomponent.AxialStage; +import net.sf.openrocket.rocketcomponent.FlightConfigurationId; +import net.sf.openrocket.rocketcomponent.MotorMount; +import net.sf.openrocket.rocketcomponent.Rocket; +import net.sf.openrocket.rocketcomponent.RocketComponent; +import net.sf.openrocket.util.ArrayList; +import net.sf.openrocket.util.Chars; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Plugin +public class MotorManufacturerSubstitutor implements RocketSubstitutor { + public static final String SUBSTITUTION = "{manufacturers}"; + + @Inject + private Translator trans; + + @Override + public boolean containsSubstitution(String str) { + return str.contains(SUBSTITUTION); + } + + @Override + public String substitute(String str, Rocket rocket, FlightConfigurationId configId) { + String description = getMotorConfigurationManufacturer(rocket, configId); + return str.replace(SUBSTITUTION, description); + } + + @Override + public Map getDescriptions() { + Map desc = new HashMap<>(); + desc.put(SUBSTITUTION, trans.get("MotorManufacturerSubstitutor.description")); + return null; + } + + + + public String getMotorConfigurationManufacturer(Rocket rocket, FlightConfigurationId fcid) { + String manufacturers; + int motorCount = 0; + + // Generate the description + + // First iterate over each stage and store the manufacturer of each motor + List> list = new ArrayList<>(); + List currentList = Collections.emptyList(); + + for (RocketComponent c : rocket) { + if (c instanceof AxialStage) { + currentList = new ArrayList<>(); + list.add(currentList); + + } else if (c instanceof MotorMount) { + MotorMount mount = (MotorMount) c; + MotorConfiguration inst = mount.getMotorConfig(fcid); + Motor motor = inst.getMotor(); + + if (mount.isMotorMount() && motor instanceof ThrustCurveMotor) { + String manufacturer = ((ThrustCurveMotor) motor).getManufacturer().getDisplayName(); + + for (int i = 0; i < mount.getMotorCount(); i++) { + currentList.add(manufacturer); + motorCount++; + } + } + } + } + + if (motorCount == 0) { + return trans.get("Rocket.motorCount.Nomotor"); + } + + // Change multiple occurrences of a motor to n x motor + List stages = new ArrayList<>(); + + for (List stage : list) { + String stageName = ""; + String previous = null; + int count = 0; + + Collections.sort(stage); + for (String current : stage) { + if (current.equals(previous)) { + count++; + } else { + if (previous != null) { + String s = ""; + if (count > 1) { + s = "" + count + Chars.TIMES + previous; + } else { + s = previous; + } + + if (stageName.equals("")) + stageName = s; + else + stageName = stageName + "," + s; + } + + previous = current; + count = 1; + } + } + if (previous != null) { + String s = ""; + if (count > 1) { + s = "" + count + Chars.TIMES + previous; + } else { + s = previous; + } + + if (stageName.equals("")) + stageName = s; + else + stageName = stageName + "," + s; + } + stages.add(stageName); + } + + manufacturers = ""; + for (int i = 0; i < stages.size(); i++) { + String s = stages.get(i); + if (s.equals("")) + s = trans.get("Rocket.motorCount.noStageMotors"); + if (i == 0) + manufacturers = manufacturers + s; + else + manufacturers = manufacturers + "; " + s; + } + return manufacturers; + } +} + From 5fe03ed9f24a45693217b8c22d69bb5cd48585f5 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Tue, 14 Feb 2023 05:26:55 +0000 Subject: [PATCH 3/9] Add information on name tags --- core/resources/l10n/messages.properties | 3 +++ .../flightconfiguration/RenameConfigDialog.java | 14 ++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index df5bc30a7..cf604e801 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -228,6 +228,9 @@ edtmotorconfdlg.tbl.Separationheader = Separation RenameConfigDialog.title = Rename Configuration RenameConfigDialog.lbl.name = Name for flight configuration: RenameConfigDialog.but.reset = Reset to default +RenameConfigDialog.lbl.infoMotors = The text '{motors}' will be replaced with the motor designation(s). +RenameConfigDialog.lbl.infoManufacturers = The text '{manufacturers}' will be replaced with the motor manufacturer(s). + ! Example design dialog exdesigndlg.but.open = Open diff --git a/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/RenameConfigDialog.java b/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/RenameConfigDialog.java index b768b81b6..919bf1260 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/RenameConfigDialog.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/RenameConfigDialog.java @@ -1,5 +1,6 @@ package net.sf.openrocket.gui.dialogs.flightconfiguration; +import java.awt.Color; import java.awt.Dialog; import java.awt.Window; import java.awt.event.ActionEvent; @@ -12,6 +13,8 @@ import javax.swing.JPanel; import javax.swing.JTextField; import net.miginfocom.swing.MigLayout; +import net.sf.openrocket.gui.components.StyledLabel; +import net.sf.openrocket.gui.configdialog.CommonStrings; import net.sf.openrocket.gui.util.GUIUtil; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.rocketcomponent.FlightConfigurationId; @@ -28,7 +31,7 @@ public class RenameConfigDialog extends JDialog { JPanel panel = new JPanel(new MigLayout("fill")); - panel.add(new JLabel(trans.get("RenameConfigDialog.lbl.name")), "span, wrap rel"); + panel.add(new JLabel(trans.get("RenameConfigDialog.lbl.name") + " " + CommonStrings.dagger), "span, wrap rel"); final JTextField textbox = new JTextField(rocket.getFlightConfiguration(fcid).getNameRaw()); panel.add(textbox, "span, w 200lp, growx, wrap para"); @@ -63,7 +66,14 @@ public class RenameConfigDialog extends JDialog { RenameConfigDialog.this.setVisible(false); } }); - panel.add(cancel); + panel.add(cancel, "wrap para"); + + // {motors} & {manufacturers} info + String text = "" + CommonStrings.dagger + " " + trans.get("RenameConfigDialog.lbl.infoMotors") + + "
" + trans.get("RenameConfigDialog.lbl.infoManufacturers"); + StyledLabel info = new StyledLabel(text, -1); + info.setFontColor(Color.DARK_GRAY); + panel.add(info, "spanx, growx, wrap"); this.add(panel); From 813f0d5fc6554dfd35d3436ad078c70b6c814830 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Tue, 14 Feb 2023 16:32:59 +0000 Subject: [PATCH 4/9] Only search active stages in substitutor --- .../MotorDescriptionSubstitutor.java | 24 ++++++------------- .../MotorManufacturerSubstitutor.java | 6 +++-- .../FlightConfigurationTest.java | 1 + 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/core/src/net/sf/openrocket/formatting/MotorDescriptionSubstitutor.java b/core/src/net/sf/openrocket/formatting/MotorDescriptionSubstitutor.java index f02f82540..f8d90741f 100644 --- a/core/src/net/sf/openrocket/formatting/MotorDescriptionSubstitutor.java +++ b/core/src/net/sf/openrocket/formatting/MotorDescriptionSubstitutor.java @@ -13,6 +13,7 @@ import net.sf.openrocket.motor.Motor; import net.sf.openrocket.motor.MotorConfiguration; import net.sf.openrocket.plugin.Plugin; import net.sf.openrocket.rocketcomponent.AxialStage; +import net.sf.openrocket.rocketcomponent.FlightConfiguration; import net.sf.openrocket.rocketcomponent.FlightConfigurationId; import net.sf.openrocket.rocketcomponent.MotorMount; import net.sf.openrocket.rocketcomponent.Rocket; @@ -56,23 +57,19 @@ public class MotorDescriptionSubstitutor implements RocketSubstitutor { // First iterate over each stage and store the designations of each motor List> list = new ArrayList>(); List currentList = Collections.emptyList(); - - Iterator iterator = rocket.iterator(); - while (iterator.hasNext()) { - RocketComponent c = iterator.next(); - + + FlightConfiguration config = rocket.getFlightConfiguration(fcid); + for (RocketComponent c : rocket) { if (c instanceof AxialStage) { - - currentList = new ArrayList(); + currentList = new ArrayList<>(); list.add(currentList); } else if (c instanceof MotorMount) { - MotorMount mount = (MotorMount) c; MotorConfiguration inst = mount.getMotorConfig(fcid); Motor motor = inst.getMotor(); - if (mount.isMotorMount() && motor != null) { + if (mount.isMotorMount() && config.isComponentActive(mount) && motor != null) { String designation = motor.getDesignation(inst.getEjectionDelay()); for (int i = 0; i < mount.getMotorCount(); i++) { @@ -80,7 +77,6 @@ public class MotorDescriptionSubstitutor implements RocketSubstitutor { motorCount++; } } - } } @@ -99,11 +95,8 @@ public class MotorDescriptionSubstitutor implements RocketSubstitutor { Collections.sort(stage); for (String current : stage) { if (current.equals(previous)) { - count++; - } else { - if (previous != null) { String s = ""; if (count > 1) { @@ -117,10 +110,8 @@ public class MotorDescriptionSubstitutor implements RocketSubstitutor { else stageName = stageName + "," + s; } - previous = current; count = 1; - } } if (previous != null) { @@ -136,14 +127,13 @@ public class MotorDescriptionSubstitutor implements RocketSubstitutor { else stageName = stageName + "," + s; } - stages.add(stageName); } name = ""; for (int i = 0; i < stages.size(); i++) { String s = stages.get(i); - if (s.equals("")) + if (s.equals("") && config.isStageActive(i)) s = trans.get("Rocket.motorCount.noStageMotors"); if (i == 0) name = name + s; diff --git a/core/src/net/sf/openrocket/formatting/MotorManufacturerSubstitutor.java b/core/src/net/sf/openrocket/formatting/MotorManufacturerSubstitutor.java index 0c75ebe29..bafd73361 100644 --- a/core/src/net/sf/openrocket/formatting/MotorManufacturerSubstitutor.java +++ b/core/src/net/sf/openrocket/formatting/MotorManufacturerSubstitutor.java @@ -7,6 +7,7 @@ import net.sf.openrocket.motor.MotorConfiguration; import net.sf.openrocket.motor.ThrustCurveMotor; import net.sf.openrocket.plugin.Plugin; import net.sf.openrocket.rocketcomponent.AxialStage; +import net.sf.openrocket.rocketcomponent.FlightConfiguration; import net.sf.openrocket.rocketcomponent.FlightConfigurationId; import net.sf.openrocket.rocketcomponent.MotorMount; import net.sf.openrocket.rocketcomponent.Rocket; @@ -56,6 +57,7 @@ public class MotorManufacturerSubstitutor implements RocketSubstitutor { List> list = new ArrayList<>(); List currentList = Collections.emptyList(); + FlightConfiguration config = rocket.getFlightConfiguration(fcid); for (RocketComponent c : rocket) { if (c instanceof AxialStage) { currentList = new ArrayList<>(); @@ -66,7 +68,7 @@ public class MotorManufacturerSubstitutor implements RocketSubstitutor { MotorConfiguration inst = mount.getMotorConfig(fcid); Motor motor = inst.getMotor(); - if (mount.isMotorMount() && motor instanceof ThrustCurveMotor) { + if (mount.isMotorMount() && config.isComponentActive(mount) && motor instanceof ThrustCurveMotor) { String manufacturer = ((ThrustCurveMotor) motor).getManufacturer().getDisplayName(); for (int i = 0; i < mount.getMotorCount(); i++) { @@ -131,7 +133,7 @@ public class MotorManufacturerSubstitutor implements RocketSubstitutor { manufacturers = ""; for (int i = 0; i < stages.size(); i++) { String s = stages.get(i); - if (s.equals("")) + if (s.equals("") && config.isStageActive(i)) s = trans.get("Rocket.motorCount.noStageMotors"); if (i == 0) manufacturers = manufacturers + s; diff --git a/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java b/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java index b671af3b3..28fc058dd 100644 --- a/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java +++ b/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java @@ -584,6 +584,7 @@ public class FlightConfigurationTest extends BaseTestCase { public void testCopy() throws NoSuchFieldException, IllegalAccessException { Rocket rocket = TestRockets.makeFalcon9Heavy(); FlightConfiguration original = rocket.getSelectedConfiguration(); + original.setName("[{motors}] - [{manufacturers}]"); original.setOnlyStage(0); // vvvv Test Target vvvv From fb3a22d21006b3303cfa7a7ed773125fb8e1b307 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Tue, 14 Feb 2023 16:43:21 +0000 Subject: [PATCH 5/9] Add unit tests for config name --- .../FlightConfigurationTest.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java b/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java index 28fc058dd..5f871c52e 100644 --- a/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java +++ b/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java @@ -580,6 +580,26 @@ public class FlightConfigurationTest extends BaseTestCase { } + @Test + public void testName() { + Rocket rocket = TestRockets.makeFalcon9Heavy(); + FlightConfiguration selected = rocket.getSelectedConfiguration(); + selected.setName("[{motors}] - [{manufacturers}]"); + + selected.setAllStages(); + assertEquals("[[Rocket.motorCount.noStageMotors]; M1350-0; 4×G77-0] - [[Rocket.motorCount.noStageMotors]; AeroTech; 4×AeroTech]", selected.getName()); + + selected.setOnlyStage(0); + assertEquals("[[Rocket.motorCount.Nomotor]] - [[Rocket.motorCount.Nomotor]]", selected.getName()); + + selected.setOnlyStage(1); + assertEquals("[; M1350-0; ] - [; AeroTech; ]", selected.getName()); + + selected.setAllStages(); + selected._setStageActive(0, false); + assertEquals("[; M1350-0; 4×G77-0] - [; AeroTech; 4×AeroTech]", selected.getName()); + } + @Test public void testCopy() throws NoSuchFieldException, IllegalAccessException { Rocket rocket = TestRockets.makeFalcon9Heavy(); From 5b921eebaf1e448951d1215fbff0719ea9bba466 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Tue, 14 Feb 2023 19:23:54 +0100 Subject: [PATCH 6/9] Fix non-ASCII characters --- .../openrocket/rocketcomponent/FlightConfigurationTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java b/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java index 5f871c52e..b516ea05a 100644 --- a/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java +++ b/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java @@ -587,7 +587,7 @@ public class FlightConfigurationTest extends BaseTestCase { selected.setName("[{motors}] - [{manufacturers}]"); selected.setAllStages(); - assertEquals("[[Rocket.motorCount.noStageMotors]; M1350-0; 4×G77-0] - [[Rocket.motorCount.noStageMotors]; AeroTech; 4×AeroTech]", selected.getName()); + assertEquals("[[Rocket.motorCount.noStageMotors]; M1350-0; 4\u00D7G77-0] - [[Rocket.motorCount.noStageMotors]; AeroTech; 4\u00D7AeroTech]", selected.getName()); selected.setOnlyStage(0); assertEquals("[[Rocket.motorCount.Nomotor]] - [[Rocket.motorCount.Nomotor]]", selected.getName()); @@ -597,7 +597,7 @@ public class FlightConfigurationTest extends BaseTestCase { selected.setAllStages(); selected._setStageActive(0, false); - assertEquals("[; M1350-0; 4×G77-0] - [; AeroTech; 4×AeroTech]", selected.getName()); + assertEquals("[; M1350-0; 4\u00D7G77-0] - [; AeroTech; 4\u00D7AeroTech]", selected.getName()); } @Test From a621bed20a6b4f18412e9c7fe47ca84a3e571e06 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Thu, 23 Feb 2023 16:15:30 +0100 Subject: [PATCH 7/9] [#2068] Use generalized motor config substitutor --- core/resources/l10n/messages.properties | 5 +- .../MotorConfigurationSubstitutor.java | 250 ++++++++++++++++++ .../MotorDescriptionSubstitutor.java | 148 ----------- .../MotorManufacturerSubstitutor.java | 146 ---------- .../FlightConfigurationTest.java | 83 ++++++ .../RenameConfigDialog.java | 5 +- 6 files changed, 339 insertions(+), 298 deletions(-) create mode 100644 core/src/net/sf/openrocket/formatting/MotorConfigurationSubstitutor.java delete mode 100644 core/src/net/sf/openrocket/formatting/MotorDescriptionSubstitutor.java delete mode 100644 core/src/net/sf/openrocket/formatting/MotorManufacturerSubstitutor.java diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index cf604e801..ffd308eb6 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -228,8 +228,9 @@ edtmotorconfdlg.tbl.Separationheader = Separation RenameConfigDialog.title = Rename Configuration RenameConfigDialog.lbl.name = Name for flight configuration: RenameConfigDialog.but.reset = Reset to default -RenameConfigDialog.lbl.infoMotors = The text '{motors}' will be replaced with the motor designation(s). -RenameConfigDialog.lbl.infoManufacturers = The text '{manufacturers}' will be replaced with the motor manufacturer(s). +RenameConfigDialog.lbl.infoMotors = The text '{motors}' will be replaced with the motor designation(s).
\te.g. '{motors} \u2192 'M1350-0'
+RenameConfigDialog.lbl.infoManufacturers = The text '{manufacturers}' will be replaced with the motor manufacturer(s).
\te.g. '{manufacturers}' \u2192 'AeroTech'
+RenameConfigDialog.lbl.infoCombination = A combination of the above can be used.
\te.g. '{motors, manufacturers}' \u2192 'M1350-0, AeroTech'
! Example design dialog diff --git a/core/src/net/sf/openrocket/formatting/MotorConfigurationSubstitutor.java b/core/src/net/sf/openrocket/formatting/MotorConfigurationSubstitutor.java new file mode 100644 index 000000000..9c534d079 --- /dev/null +++ b/core/src/net/sf/openrocket/formatting/MotorConfigurationSubstitutor.java @@ -0,0 +1,250 @@ +package net.sf.openrocket.formatting; + +import com.google.inject.Inject; +import net.sf.openrocket.l10n.Translator; +import net.sf.openrocket.motor.Motor; +import net.sf.openrocket.motor.MotorConfiguration; +import net.sf.openrocket.motor.ThrustCurveMotor; +import net.sf.openrocket.plugin.Plugin; +import net.sf.openrocket.rocketcomponent.AxialStage; +import net.sf.openrocket.rocketcomponent.FlightConfiguration; +import net.sf.openrocket.rocketcomponent.FlightConfigurationId; +import net.sf.openrocket.rocketcomponent.MotorMount; +import net.sf.openrocket.rocketcomponent.Rocket; +import net.sf.openrocket.rocketcomponent.RocketComponent; +import net.sf.openrocket.util.ArrayList; +import net.sf.openrocket.util.Chars; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * General substitutor for motor configurations. This currently includes substitutions for + * - {motors} - the motor designation (e.g. "M1350-0") + * - {manufacturers} - the motor manufacturer (e.g. "AeroTech") + * - a combination of motors and manufacturers, e.g. {motors | manufacturers} -> "M1350-0 | AeroTech" + * You can choose which comes first and what the separator is. E.g. {manufacturers, motors} -> "AeroTech, M1350-0". + * + *

+ * This substitutor is added through injection. All substitutors with the "@Plugin" tag in the formatting package will + * be included automatically. + */ +@Plugin +public class MotorConfigurationSubstitutor implements RocketSubstitutor { + public static final String SUBSTITUTION_START = "{"; + public static final String SUBSTITUTION_END = "}"; + public static final String SUBSTITUTION_MOTORS = "motors"; + public static final String SUBSTITUTION_MANUFACTURERS = "manufacturers"; + + // Substitutions for combinations of motors and manufacturers + private static final String SUBSTITUTION_PATTERN = "\\" + SUBSTITUTION_START + + "(" + SUBSTITUTION_MOTORS + "|" + SUBSTITUTION_MANUFACTURERS + ")" + + "(.*?)" + + "(" + SUBSTITUTION_MOTORS + "|" + SUBSTITUTION_MANUFACTURERS + ")" + + "\\" + SUBSTITUTION_END; + + @Inject + private Translator trans; + + @Override + public boolean containsSubstitution(String input) { + return getSubstitutionContent(input) != null; + } + + @Override + public String substitute(String input, Rocket rocket, FlightConfigurationId configId) { + String description = getConfigurationSubstitution(input, rocket, configId); + String substitutionString = getSubstiutionString(input); + if (substitutionString != null) { + return input.replace(substitutionString, description); + } + return input; + } + + @Override + public Map getDescriptions() { + return null; + } + + public String getConfigurationSubstitution(String input, Rocket rocket, FlightConfigurationId fcid) { + StringBuilder configurations = new StringBuilder(); + int motorCount = 0; + + // Iterate over each stage and store the manufacturer of each motor + List> list = new ArrayList<>(); + List currentList = new ArrayList<>(); + + String[] content = getSubstitutionContent(input); + if (content == null) { + return ""; + } + + FlightConfiguration config = rocket.getFlightConfiguration(fcid); + for (RocketComponent c : rocket) { + if (c instanceof AxialStage) { + currentList = new ArrayList<>(); + list.add(currentList); + } else if (c instanceof MotorMount) { + MotorMount mount = (MotorMount) c; + MotorConfiguration inst = mount.getMotorConfig(fcid); + Motor motor = inst.getMotor(); + + if (mount.isMotorMount() && config.isComponentActive(mount) && (motor != null)) { + String motorDesignation = motor.getDesignation(inst.getEjectionDelay()); + String manufacturer = ""; + if (motor instanceof ThrustCurveMotor) { + manufacturer = ((ThrustCurveMotor) motor).getManufacturer().getDisplayName(); + } + + for (int i = 0; i < mount.getMotorCount(); i++) { + if (content.length == 2) { + if (SUBSTITUTION_MOTORS.equals(content[1])) { + currentList.add(motorDesignation); + } else if (SUBSTITUTION_MANUFACTURERS.equals(content[1])) { + currentList.add(manufacturer); + } else { + continue; + } + } else if (content.length == 4) { + String configString; + if (content[1].equals(SUBSTITUTION_MOTORS)) { + configString = motorDesignation; + } else if (content[1].equals(SUBSTITUTION_MANUFACTURERS)) { + configString = manufacturer; + } else { + continue; + } + configString += content[2]; + if (content[3].equals(SUBSTITUTION_MOTORS)) { + configString += motorDesignation; + } else if (content[3].equals(SUBSTITUTION_MANUFACTURERS)) { + configString += manufacturer; + } else { + continue; + } + currentList.add(configString); + } else { + continue; + } + motorCount++; + } + } + } + } + + if (motorCount == 0) { + return trans.get("Rocket.motorCount.Nomotor"); + } + + // Change multiple occurrences of a motor to n x motor + List stages = new ArrayList<>(); + for (List stage : list) { + String stageName = ""; + String previous = null; + int count = 0; + + Collections.sort(stage); + for (String current : stage) { + if (current.equals(previous)) { + count++; + } else { + if (previous != null) { + String s = count > 1 ? count + Chars.TIMES + previous : previous; + stageName = stageName.equals("") ? s : stageName + "," + s; + } + + previous = current; + count = 1; + } + } + + if (previous != null) { + String s = count > 1 ? "" + count + Chars.TIMES + previous : previous; + stageName = stageName.equals("") ? s : stageName + "," + s; + } + + stages.add(stageName); + } + + for (int i = 0; i < stages.size(); i++) { + String s = stages.get(i); + if (s.equals("") && config.isStageActive(i)) { + s = trans.get("Rocket.motorCount.noStageMotors"); + } + + configurations.append(i == 0 ? s : "; " + s); + } + + return configurations.toString(); + } + + /** + * Returns which string in input should be replaced, or null if no text needs to be replaced. + * @param input The input string + * @return The string to replace, or null if no text needs to be replaced. + */ + private static String getSubstiutionString(String input) { + String[] content = getSubstitutionContent(input); + if (content != null) { + return content[0]; + } + return null; + } + + /** + * Fills in the content of the substitution tag and the separator. + * If there are both a motor and a manufacturer substitution tag, the array will contain the following: + * [0] = The full tag, including substitution start and end + * [1] = The motor/manufacturer substitution tag, depending on which one was found first. + * if there are two substitution tags, the array will also contain the following: + * ([2] = The separator) + * ([3] = The motor/manufacturer substitution tag, depending on which one was found first.) + * @param input The input string + * @return The content of the substitution tag and the separator, or null if no text needs to be replaced. + */ + private static String[] getSubstitutionContent(String input) { + // First try with only the motors tag + String pattern = "\\" + SUBSTITUTION_START + "(" + SUBSTITUTION_MOTORS + ")" + "\\" + SUBSTITUTION_END; + Pattern regexPattern = Pattern.compile(pattern); + Matcher matcher = regexPattern.matcher(input); + if (matcher.find()) { + String[] content = new String[2]; + content[0] = matcher.group(0); + content[1] = matcher.group(1); + return content; + } + // First try with only the manufacturers tag + pattern = "\\" + SUBSTITUTION_START + "(" + SUBSTITUTION_MANUFACTURERS + ")" + "\\" + SUBSTITUTION_END; + regexPattern = Pattern.compile(pattern); + matcher = regexPattern.matcher(input); + if (matcher.find()) { + String[] content = new String[2]; + content[0] = matcher.group(0); + content[1] = matcher.group(1); + return content; + } + + // Then try combined patterns + pattern = SUBSTITUTION_PATTERN; + regexPattern = Pattern.compile(pattern); + matcher = regexPattern.matcher(input); + if (matcher.find()) { + String[] content = new String[4]; + content[0] = matcher.group(0); + content[1] = matcher.group(1); + if (matcher.groupCount() >= 3) { + content[2] = matcher.group(2); + content[3] = matcher.group(3); + for (int i = 4; i < matcher.groupCount(); i++) { + content[3] += matcher.group(i); + } + } + return content; + } + return null; + } +} + diff --git a/core/src/net/sf/openrocket/formatting/MotorDescriptionSubstitutor.java b/core/src/net/sf/openrocket/formatting/MotorDescriptionSubstitutor.java deleted file mode 100644 index f8d90741f..000000000 --- a/core/src/net/sf/openrocket/formatting/MotorDescriptionSubstitutor.java +++ /dev/null @@ -1,148 +0,0 @@ -package net.sf.openrocket.formatting; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import com.google.inject.Inject; - -import net.sf.openrocket.l10n.Translator; -import net.sf.openrocket.motor.Motor; -import net.sf.openrocket.motor.MotorConfiguration; -import net.sf.openrocket.plugin.Plugin; -import net.sf.openrocket.rocketcomponent.AxialStage; -import net.sf.openrocket.rocketcomponent.FlightConfiguration; -import net.sf.openrocket.rocketcomponent.FlightConfigurationId; -import net.sf.openrocket.rocketcomponent.MotorMount; -import net.sf.openrocket.rocketcomponent.Rocket; -import net.sf.openrocket.rocketcomponent.RocketComponent; -import net.sf.openrocket.util.ArrayList; -import net.sf.openrocket.util.Chars; - -@Plugin -public class MotorDescriptionSubstitutor implements RocketSubstitutor { - public static final String SUBSTITUTION = "{motors}"; - - @Inject - private Translator trans; - - @Override - public boolean containsSubstitution(String str) { - return str.contains(SUBSTITUTION); - } - - @Override - public String substitute(String str, Rocket rocket, FlightConfigurationId configId) { - String description = getMotorConfigurationDescription(rocket, configId); - return str.replace(SUBSTITUTION, description); - } - - @Override - public Map getDescriptions() { - Map desc = new HashMap(); - desc.put(SUBSTITUTION, trans.get("MotorDescriptionSubstitutor.description")); - return null; - } - - - - public String getMotorConfigurationDescription(Rocket rocket, FlightConfigurationId fcid) { - String name; - int motorCount = 0; - - // Generate the description - - // First iterate over each stage and store the designations of each motor - List> list = new ArrayList>(); - List currentList = Collections.emptyList(); - - FlightConfiguration config = rocket.getFlightConfiguration(fcid); - for (RocketComponent c : rocket) { - if (c instanceof AxialStage) { - currentList = new ArrayList<>(); - list.add(currentList); - - } else if (c instanceof MotorMount) { - MotorMount mount = (MotorMount) c; - MotorConfiguration inst = mount.getMotorConfig(fcid); - Motor motor = inst.getMotor(); - - if (mount.isMotorMount() && config.isComponentActive(mount) && motor != null) { - String designation = motor.getDesignation(inst.getEjectionDelay()); - - for (int i = 0; i < mount.getMotorCount(); i++) { - currentList.add(designation); - motorCount++; - } - } - } - } - - if (motorCount == 0) { - return trans.get("Rocket.motorCount.Nomotor"); - } - - // Change multiple occurrences of a motor to n x motor - List stages = new ArrayList(); - - for (List stage : list) { - String stageName = ""; - String previous = null; - int count = 0; - - Collections.sort(stage); - for (String current : stage) { - if (current.equals(previous)) { - count++; - } else { - if (previous != null) { - String s = ""; - if (count > 1) { - s = "" + count + Chars.TIMES + previous; - } else { - s = previous; - } - - if (stageName.equals("")) - stageName = s; - else - stageName = stageName + "," + s; - } - previous = current; - count = 1; - } - } - if (previous != null) { - String s = ""; - if (count > 1) { - s = "" + count + Chars.TIMES + previous; - } else { - s = previous; - } - - if (stageName.equals("")) - stageName = s; - else - stageName = stageName + "," + s; - } - stages.add(stageName); - } - - name = ""; - for (int i = 0; i < stages.size(); i++) { - String s = stages.get(i); - if (s.equals("") && config.isStageActive(i)) - s = trans.get("Rocket.motorCount.noStageMotors"); - if (i == 0) - name = name + s; - else - name = name + "; " + s; - } - return name; - } - - - -} diff --git a/core/src/net/sf/openrocket/formatting/MotorManufacturerSubstitutor.java b/core/src/net/sf/openrocket/formatting/MotorManufacturerSubstitutor.java deleted file mode 100644 index bafd73361..000000000 --- a/core/src/net/sf/openrocket/formatting/MotorManufacturerSubstitutor.java +++ /dev/null @@ -1,146 +0,0 @@ -package net.sf.openrocket.formatting; - -import com.google.inject.Inject; -import net.sf.openrocket.l10n.Translator; -import net.sf.openrocket.motor.Motor; -import net.sf.openrocket.motor.MotorConfiguration; -import net.sf.openrocket.motor.ThrustCurveMotor; -import net.sf.openrocket.plugin.Plugin; -import net.sf.openrocket.rocketcomponent.AxialStage; -import net.sf.openrocket.rocketcomponent.FlightConfiguration; -import net.sf.openrocket.rocketcomponent.FlightConfigurationId; -import net.sf.openrocket.rocketcomponent.MotorMount; -import net.sf.openrocket.rocketcomponent.Rocket; -import net.sf.openrocket.rocketcomponent.RocketComponent; -import net.sf.openrocket.util.ArrayList; -import net.sf.openrocket.util.Chars; - -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -@Plugin -public class MotorManufacturerSubstitutor implements RocketSubstitutor { - public static final String SUBSTITUTION = "{manufacturers}"; - - @Inject - private Translator trans; - - @Override - public boolean containsSubstitution(String str) { - return str.contains(SUBSTITUTION); - } - - @Override - public String substitute(String str, Rocket rocket, FlightConfigurationId configId) { - String description = getMotorConfigurationManufacturer(rocket, configId); - return str.replace(SUBSTITUTION, description); - } - - @Override - public Map getDescriptions() { - Map desc = new HashMap<>(); - desc.put(SUBSTITUTION, trans.get("MotorManufacturerSubstitutor.description")); - return null; - } - - - - public String getMotorConfigurationManufacturer(Rocket rocket, FlightConfigurationId fcid) { - String manufacturers; - int motorCount = 0; - - // Generate the description - - // First iterate over each stage and store the manufacturer of each motor - List> list = new ArrayList<>(); - List currentList = Collections.emptyList(); - - FlightConfiguration config = rocket.getFlightConfiguration(fcid); - for (RocketComponent c : rocket) { - if (c instanceof AxialStage) { - currentList = new ArrayList<>(); - list.add(currentList); - - } else if (c instanceof MotorMount) { - MotorMount mount = (MotorMount) c; - MotorConfiguration inst = mount.getMotorConfig(fcid); - Motor motor = inst.getMotor(); - - if (mount.isMotorMount() && config.isComponentActive(mount) && motor instanceof ThrustCurveMotor) { - String manufacturer = ((ThrustCurveMotor) motor).getManufacturer().getDisplayName(); - - for (int i = 0; i < mount.getMotorCount(); i++) { - currentList.add(manufacturer); - motorCount++; - } - } - } - } - - if (motorCount == 0) { - return trans.get("Rocket.motorCount.Nomotor"); - } - - // Change multiple occurrences of a motor to n x motor - List stages = new ArrayList<>(); - - for (List stage : list) { - String stageName = ""; - String previous = null; - int count = 0; - - Collections.sort(stage); - for (String current : stage) { - if (current.equals(previous)) { - count++; - } else { - if (previous != null) { - String s = ""; - if (count > 1) { - s = "" + count + Chars.TIMES + previous; - } else { - s = previous; - } - - if (stageName.equals("")) - stageName = s; - else - stageName = stageName + "," + s; - } - - previous = current; - count = 1; - } - } - if (previous != null) { - String s = ""; - if (count > 1) { - s = "" + count + Chars.TIMES + previous; - } else { - s = previous; - } - - if (stageName.equals("")) - stageName = s; - else - stageName = stageName + "," + s; - } - stages.add(stageName); - } - - manufacturers = ""; - for (int i = 0; i < stages.size(); i++) { - String s = stages.get(i); - if (s.equals("") && config.isStageActive(i)) - s = trans.get("Rocket.motorCount.noStageMotors"); - if (i == 0) - manufacturers = manufacturers + s; - else - manufacturers = manufacturers + "; " + s; - } - return manufacturers; - } -} - diff --git a/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java b/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java index b516ea05a..372d3f2de 100644 --- a/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java +++ b/core/test/net/sf/openrocket/rocketcomponent/FlightConfigurationTest.java @@ -584,6 +584,8 @@ public class FlightConfigurationTest extends BaseTestCase { public void testName() { Rocket rocket = TestRockets.makeFalcon9Heavy(); FlightConfiguration selected = rocket.getSelectedConfiguration(); + + // Test only motors or only manufacturers selected.setName("[{motors}] - [{manufacturers}]"); selected.setAllStages(); @@ -598,6 +600,87 @@ public class FlightConfigurationTest extends BaseTestCase { selected.setAllStages(); selected._setStageActive(0, false); assertEquals("[; M1350-0; 4\u00D7G77-0] - [; AeroTech; 4\u00D7AeroTech]", selected.getName()); + + + // Test combination of motors and manufacturers + selected.setName("[{motors manufacturers}] -- [{manufacturers}] - [{motors}]"); + + selected.setAllStages(); + assertEquals("[[Rocket.motorCount.noStageMotors]; M1350-0 AeroTech; 4\u00D7G77-0 AeroTech] -- [[Rocket.motorCount.noStageMotors]; AeroTech; 4\u00D7AeroTech] - [[Rocket.motorCount.noStageMotors]; M1350-0; 4\u00D7G77-0]", selected.getName()); + + selected.setOnlyStage(0); + assertEquals("[[Rocket.motorCount.Nomotor]] -- [[Rocket.motorCount.Nomotor]] - [[Rocket.motorCount.Nomotor]]", selected.getName()); + + selected.setOnlyStage(1); + assertEquals("[; M1350-0 AeroTech; ] -- [; AeroTech; ] - [; M1350-0; ]", selected.getName()); + + selected.setAllStages(); + selected._setStageActive(0, false); + assertEquals("[; M1350-0 AeroTech; 4\u00D7G77-0 AeroTech] -- [; AeroTech; 4\u00D7AeroTech] - [; M1350-0; 4\u00D7G77-0]", selected.getName()); + + // Test combination of manufacturers and motors + selected.setName("[{manufacturers | motors}]"); + + selected.setAllStages(); + assertEquals("[[Rocket.motorCount.noStageMotors]; AeroTech | M1350-0; 4\u00D7AeroTech | G77-0]", selected.getName()); + + selected.setOnlyStage(0); + assertEquals("[[Rocket.motorCount.Nomotor]]", selected.getName()); + + selected.setOnlyStage(1); + assertEquals("[; AeroTech | M1350-0; ]", selected.getName()); + + selected.setAllStages(); + selected._setStageActive(0, false); + assertEquals("[; AeroTech | M1350-0; 4\u00D7AeroTech | G77-0]", selected.getName()); + + // Test empty tags + selected.setName("{}"); + + selected.setAllStages(); + assertEquals("{}", selected.getName()); + + selected.setOnlyStage(0); + assertEquals("{}", selected.getName()); + + selected.setOnlyStage(1); + assertEquals("{}", selected.getName()); + + selected.setAllStages(); + selected._setStageActive(0, false); + assertEquals("{}", selected.getName()); + + // Test invalid tags (1) + selected.setName("{motorsm}"); + + selected.setAllStages(); + assertEquals("{motorsm}", selected.getName()); + + selected.setOnlyStage(0); + assertEquals("{motorsm}", selected.getName()); + + selected.setOnlyStage(1); + assertEquals("{motorsm}", selected.getName()); + + selected.setAllStages(); + selected._setStageActive(0, false); + assertEquals("{motorsm}", selected.getName()); + + // Test invalid tags (2) + selected.setName("{motors manufacturers '}"); + + selected.setAllStages(); + assertEquals("{motors manufacturers '}", selected.getName()); + + selected.setOnlyStage(0); + assertEquals("{motors manufacturers '}", selected.getName()); + + selected.setOnlyStage(1); + assertEquals("{motors manufacturers '}", selected.getName()); + + selected.setAllStages(); + selected._setStageActive(0, false); + assertEquals("{motors manufacturers '}", selected.getName()); } @Test diff --git a/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/RenameConfigDialog.java b/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/RenameConfigDialog.java index 919bf1260..ee295ee9f 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/RenameConfigDialog.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/flightconfiguration/RenameConfigDialog.java @@ -70,8 +70,9 @@ public class RenameConfigDialog extends JDialog { // {motors} & {manufacturers} info String text = "" + CommonStrings.dagger + " " + trans.get("RenameConfigDialog.lbl.infoMotors") - + "
" + trans.get("RenameConfigDialog.lbl.infoManufacturers"); - StyledLabel info = new StyledLabel(text, -1); + + trans.get("RenameConfigDialog.lbl.infoManufacturers") + + trans.get("RenameConfigDialog.lbl.infoCombination"); + StyledLabel info = new StyledLabel(text, -2); info.setFontColor(Color.DARK_GRAY); panel.add(info, "spanx, growx, wrap"); From c1c6bac0db41d47e2013daf251e1b530d1796a48 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Thu, 23 Feb 2023 18:41:22 +0100 Subject: [PATCH 8/9] [#2068] Use generalized motor config substitutor --- core/resources/l10n/messages.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index ffd308eb6..4198b6aae 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -230,7 +230,7 @@ RenameConfigDialog.lbl.name = Name for flight configuration: RenameConfigDialog.but.reset = Reset to default RenameConfigDialog.lbl.infoMotors = The text '{motors}' will be replaced with the motor designation(s).

\te.g. '{motors} \u2192 'M1350-0'
RenameConfigDialog.lbl.infoManufacturers = The text '{manufacturers}' will be replaced with the motor manufacturer(s).
\te.g. '{manufacturers}' \u2192 'AeroTech'
-RenameConfigDialog.lbl.infoCombination = A combination of the above can be used.
\te.g. '{motors, manufacturers}' \u2192 'M1350-0, AeroTech'
+RenameConfigDialog.lbl.infoCombination = A combination of the above can be used.
\te.g. '{motors manufacturers}' \u2192 'M1350-0 AeroTech'
! Example design dialog From 2acb1cae55ab0e4b1230ab4b26e7865f45a99614 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Thu, 23 Feb 2023 18:56:22 +0100 Subject: [PATCH 9/9] Update info text --- core/resources/l10n/messages.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index 4198b6aae..e98049aee 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -230,7 +230,7 @@ RenameConfigDialog.lbl.name = Name for flight configuration: RenameConfigDialog.but.reset = Reset to default RenameConfigDialog.lbl.infoMotors = The text '{motors}' will be replaced with the motor designation(s).
\te.g. '{motors} \u2192 'M1350-0'
RenameConfigDialog.lbl.infoManufacturers = The text '{manufacturers}' will be replaced with the motor manufacturer(s).
\te.g. '{manufacturers}' \u2192 'AeroTech'
-RenameConfigDialog.lbl.infoCombination = A combination of the above can be used.
\te.g. '{motors manufacturers}' \u2192 'M1350-0 AeroTech'
+RenameConfigDialog.lbl.infoCombination = A combination of the above can be used.
\te.g. '{manufacturers motors}' \u2192 'AeroTech M1350-0'
! Example design dialog