diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index 5a590191d..8088c874e 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -228,6 +228,10 @@ 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).
\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. '{manufacturers motors}' \u2192 'AeroTech M1350-0'
+ ! Example design dialog exdesigndlg.but.open = Open @@ -2265,6 +2269,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/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 f02f82540..000000000 --- a/core/src/net/sf/openrocket/formatting/MotorDescriptionSubstitutor.java +++ /dev/null @@ -1,158 +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.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(); - - Iterator iterator = rocket.iterator(); - while (iterator.hasNext()) { - RocketComponent c = iterator.next(); - - 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 != 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("")) - 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/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