From 170ce13c05723cc00d2c2bb67390093a65d9c3bc Mon Sep 17 00:00:00 2001 From: Sampo Niskanen Date: Fri, 1 Mar 2013 08:41:47 +0200 Subject: [PATCH] Data model refactoring --- core/resources/l10n/messages.properties | 23 +++ .../defaults/ResourceDecalImage.java | 6 +- .../openrocket/file/GeneralRocketSaver.java | 130 +++++++-------- .../net/sf/openrocket/file/RocketSaver.java | 18 --- .../file/openrocket/OpenRocketSaver.java | 10 +- .../DeploymentConfigurationHandler.java | 53 +++--- .../openrocket/importt/DocumentConfig.java | 18 ++- .../file/openrocket/importt/DoubleSetter.java | 29 +++- .../file/openrocket/importt/EnumSetter.java | 20 ++- .../importt/IgnitionConfigurationHandler.java | 28 ++-- .../openrocket/importt/MotorMountHandler.java | 19 +-- .../StageSeparationConfigurationHandler.java | 44 +++-- .../savers/RecoveryDeviceSaver.java | 39 ++--- .../savers/RocketComponentSaver.java | 44 +++-- .../file/openrocket/savers/RocketSaver.java | 6 +- .../file/openrocket/savers/StageSaver.java | 41 ++--- .../simplesax/AbstractElementHandler.java | 17 ++ .../gui/adaptors/BasicEnumModel.java | 48 ------ .../gui/configdialog/MotorConfig.java | 2 +- .../gui/configdialog/StageConfig.java | 5 +- .../customexpression/OperatorSelector.java | 82 ++++++---- .../DeploymentSelectionDialog.java | 147 +++++++++++++++++ .../FlightConfigurationDialog.java | 18 +-- .../FlightConfigurationModel.java | 98 ----------- .../IgnitionSelectionDialog.java | 107 ++++++++++++ .../MotorConfigurationPanel.java | 32 ++-- .../MotorConfigurationTableModel.java | 41 ++--- .../RecoveryConfigurationPanel.java | 152 ++++++++++-------- .../RenameConfigDialog.java | 34 ++-- .../SelectDeploymentConfigDialog.java | 145 ----------------- .../SelectIgnitionConfigDialog.java | 116 ------------- .../SelectSeparationConfigDialog.java | 107 ------------ .../SeparationConfigurationPanel.java | 149 +++++++++-------- .../SeparationSelectionDialog.java | 91 +++++++++++ .../optimization/SimulationModifierTree.java | 10 +- .../componenttree/ComponentTreeRenderer.java | 2 +- .../DefaultSimulationModifierService.java | 48 +++--- .../openrocket/rocketcomponent/BodyTube.java | 2 +- .../IgnitionConfiguration.java | 6 +- .../openrocket/rocketcomponent/InnerTube.java | 2 +- .../rocketcomponent/MotorConfiguration.java | 13 ++ .../MotorFlightConfigurationImpl.java | 18 +++ .../BasicEventSimulationEngine.java | 2 +- .../net/sf/openrocket/util/Reflection.java | 26 ++- core/src/net/sf/openrocket/util/TextUtil.java | 60 ++++--- .../net/sf/openrocket/util/TextUtilTest.java | 11 ++ 46 files changed, 1085 insertions(+), 1034 deletions(-) delete mode 100644 core/src/net/sf/openrocket/gui/adaptors/BasicEnumModel.java create mode 100644 core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/DeploymentSelectionDialog.java delete mode 100644 core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/FlightConfigurationModel.java create mode 100644 core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/IgnitionSelectionDialog.java delete mode 100644 core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/SelectDeploymentConfigDialog.java delete mode 100644 core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/SelectIgnitionConfigDialog.java delete mode 100644 core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/SelectSeparationConfigDialog.java create mode 100644 core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/SeparationSelectionDialog.java create mode 100644 core/src/net/sf/openrocket/rocketcomponent/MotorFlightConfigurationImpl.java diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index 8d6457153..f15466ed8 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -1361,6 +1361,15 @@ RecoveryDevice.DeployEvent.CURRENT_STAGE_SEPARATION = Current stage separation RecoveryDevice.DeployEvent.LOWER_STAGE_SEPARATION = Lower stage separation RecoveryDevice.DeployEvent.NEVER = Never +RecoveryDevice.DeployEvent.short.LAUNCH = Launch +RecoveryDevice.DeployEvent.short.EJECTION = Ejection charge +RecoveryDevice.DeployEvent.short.APOGEE = Apogee +RecoveryDevice.DeployEvent.short.ALTITUDE = Altitude +RecoveryDevice.DeployEvent.short.CURRENT_STAGE_SEPARATION = Current stage separation +RecoveryDevice.DeployEvent.short.LOWER_STAGE_SEPARATION = Lower stage separation +RecoveryDevice.DeployEvent.short.NEVER = Never + + ! FlightEvent FlightEvent.Type.LAUNCH = Launch FlightEvent.Type.IGNITION = Motor ignition @@ -1828,7 +1837,21 @@ MotorConfigurationPanel.btn.selectIgnition = Select ignition MotorConfigurationPanel.btn.resetIgnition = Reset ignition MotorConfigurationTableModel.table.ignition.default = Default ({0}) +RecoveryConfigurationPanel.table.deployment.default = Default ({0}) +SeparationConfigurationPanel.table.separation.default = Default ({0}) +IgnitionSelectionDialog.opt.title = Which flight configurations are affected: +IgnitionSelectionDialog.opt.default = Change the default ignition event for this motor +IgnitionSelectionDialog.opt.override = Override for the {0} flight configuration only + +DeploymentSelectionDialog.opt.title = Which flight configurations are affected: +DeploymentSelectionDialog.opt.default = Change the default deployment event for this recovery device +DeploymentSelectionDialog.opt.override = Override for the {0} flight configuration only + +SeparationSelectionDialog.lbl.separation = Stage separation at: +SeparationSelectionDialog.opt.title = Which flight configurations are affected: +SeparationSelectionDialog.opt.default = Change the default separation event for this stage +SeparationSelectionDialog.opt.override = Override for the {0} flight configuration only MotorConfigurationPanel.description = Select the motors and motor ignition events of your rocket.
Motor mounts: Select which components function as motor mounts.
Motor configurations: Select the motor and ignition event for each motor mount. diff --git a/core/src/net/sf/openrocket/appearance/defaults/ResourceDecalImage.java b/core/src/net/sf/openrocket/appearance/defaults/ResourceDecalImage.java index bea3b8d76..1110cd6d0 100644 --- a/core/src/net/sf/openrocket/appearance/defaults/ResourceDecalImage.java +++ b/core/src/net/sf/openrocket/appearance/defaults/ResourceDecalImage.java @@ -4,9 +4,9 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.util.EventListener; import net.sf.openrocket.appearance.DecalImage; +import net.sf.openrocket.util.StateChangeListener; class ResourceDecalImage implements DecalImage { @@ -38,12 +38,12 @@ class ResourceDecalImage implements DecalImage { } @Override - public void addChangeListener(EventListener listener) { + public void addChangeListener(StateChangeListener listener) { //Unimplemented, this can not change } @Override - public void removeChangeListener(EventListener listener) { + public void removeChangeListener(StateChangeListener listener) { //Unimplemented, this can not change } diff --git a/core/src/net/sf/openrocket/file/GeneralRocketSaver.java b/core/src/net/sf/openrocket/file/GeneralRocketSaver.java index 61644ac53..877435ab2 100644 --- a/core/src/net/sf/openrocket/file/GeneralRocketSaver.java +++ b/core/src/net/sf/openrocket/file/GeneralRocketSaver.java @@ -24,13 +24,13 @@ import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.util.MathUtil; public class GeneralRocketSaver { - + /** * Interface which can be implemented by the caller to receive progress information. * */ public interface SavingProgress { - + /** * Inform the callback of the current progress. * It is guaranteed that the value will be an integer between 0 and 100 representing @@ -40,10 +40,10 @@ public class GeneralRocketSaver { * * @param progress int value between 0 and 100 representing percent complete. */ - public void setProgress( int progress ); - + public void setProgress(int progress); + } - + /** * Save the document to the specified file using the default storage options. * @@ -54,7 +54,7 @@ public class GeneralRocketSaver { public final void save(File dest, OpenRocketDocument document) throws IOException { save(dest, document, document.getDefaultStorageOptions()); } - + /** * Save the document to the specified file using the given storage options. * @@ -64,9 +64,9 @@ public class GeneralRocketSaver { * @throws IOException in case of an I/O error. */ public final void save(File dest, OpenRocketDocument document, StorageOptions options) throws IOException { - save( dest, document, options, null ); + save(dest, document, options, null); } - + /** * Save the document to a file with default StorageOptions and a SavingProgress callback object. * @@ -75,10 +75,10 @@ public class GeneralRocketSaver { * @param progress a SavingProgress object used to provide progress information * @throws IOException in case of an I/O error. */ - public final void save(File dest, OpenRocketDocument doc, SavingProgress progress ) throws IOException { - save( dest, doc, doc.getDefaultStorageOptions(), progress ); + public final void save(File dest, OpenRocketDocument doc, SavingProgress progress) throws IOException { + save(dest, doc, doc.getDefaultStorageOptions(), progress); } - + /** * Save the document to a file with the given StorageOptions and a SavingProgress callback object. * @@ -88,40 +88,40 @@ public class GeneralRocketSaver { * @param progress a SavingProgress object used to provide progress information * @throws IOException in case of an I/O error. */ - public final void save(File dest, OpenRocketDocument doc, StorageOptions opts, SavingProgress progress ) throws IOException { - + public final void save(File dest, OpenRocketDocument doc, StorageOptions opts, SavingProgress progress) throws IOException { + // This method is the core operational method. It saves the document into a new (hopefully unique) // file, then if the save is successful, it will copy the file over the old one. // Write to a temporary file in the same directory as the specified file. - File temporaryNewFile = File.createTempFile("ORSave", ".tmp", dest.getParentFile() ); + File temporaryNewFile = File.createTempFile("ORSave", ".tmp", dest.getParentFile()); - OutputStream s = new BufferedOutputStream( new FileOutputStream(temporaryNewFile)); + OutputStream s = new BufferedOutputStream(new FileOutputStream(temporaryNewFile)); - if ( progress != null ) { + if (progress != null) { long estimatedSize = this.estimateFileSize(doc, opts); - s = new ProgressOutputStream( s, estimatedSize, progress ); + s = new ProgressOutputStream(s, estimatedSize, progress); } try { save(dest.getName(), s, doc, opts); } finally { s.close(); } - + // Move the temporary new file over the specified file. boolean destExists = dest.exists(); - File oldBackupFile = new File( dest.getParentFile(), dest.getName() + "-bak"); + File oldBackupFile = new File(dest.getParentFile(), dest.getName() + "-bak"); - if ( destExists ) { + if (destExists) { dest.renameTo(oldBackupFile); } // since we created the temporary new file in the same directory as the dest file, // it is on the same filesystem, so File.renameTo will work just fine. boolean success = temporaryNewFile.renameTo(dest); - if ( success ) { - if ( destExists ) { + if (success) { + if (destExists) { oldBackupFile.delete(); } } @@ -137,138 +137,138 @@ public class GeneralRocketSaver { * @return the estimated number of bytes the storage would take. */ public long estimateFileSize(OpenRocketDocument doc, StorageOptions options) { - if ( options.getFileType() == StorageOptions.FileType.ROCKSIM ) { + if (options.getFileType() == StorageOptions.FileType.ROCKSIM) { return new RocksimSaver().estimateFileSize(doc, options); } else { - return new OpenRocketSaver().estimateFileSize(doc,options); + return new OpenRocketSaver().estimateFileSize(doc, options); } } - - private void save(String fileName, OutputStream output, OpenRocketDocument document, StorageOptions options) throws IOException { - + + private void save(String fileName, OutputStream output, OpenRocketDocument document, StorageOptions options) throws IOException { + // For now, we don't save decal inforamtion in ROCKSIM files, so don't do anything // which follows. // TODO - add support for decals in ROCKSIM files? - if ( options.getFileType() == FileType.ROCKSIM ) { + if (options.getFileType() == FileType.ROCKSIM) { saveInternal(output, document, options); output.close(); return; } - + Set usedDecals = new TreeSet(); // Look for all decals used in the rocket. - for( RocketComponent c : document.getRocket() ) { - if ( c.getAppearance() == null ) { + for (RocketComponent c : document.getRocket()) { + if (c.getAppearance() == null) { continue; } Appearance ap = c.getAppearance(); - if ( ap.getTexture() == null ) { + if (ap.getTexture() == null) { continue; } - + Decal decal = ap.getTexture(); - + usedDecals.add(decal.getImage()); } - - saveAllPartsZipFile(fileName, output, document, options, usedDecals); + + saveAllPartsZipFile(output, document, options, usedDecals); } - public void saveAllPartsZipFile(String fileName, OutputStream output, OpenRocketDocument document, StorageOptions options, Set decals) throws IOException { + public void saveAllPartsZipFile(OutputStream output, OpenRocketDocument document, StorageOptions options, Set decals) throws IOException { // Open a zip stream to write to. ZipOutputStream zos = new ZipOutputStream(output); zos.setLevel(9); // big try block to close the zos. try { - - - ZipEntry mainFile = new ZipEntry(fileName); + + + ZipEntry mainFile = new ZipEntry("rocket.ork"); zos.putNextEntry(mainFile); - saveInternal(zos,document,options); + saveInternal(zos, document, options); zos.closeEntry(); - + // Now we write out all the decal images files. - - for( DecalImage image : decals ) { - + + for (DecalImage image : decals) { + String name = image.getName(); ZipEntry decal = new ZipEntry(name); zos.putNextEntry(decal); - + InputStream is = image.getBytes(); int bytesRead = 0; byte[] buffer = new byte[2048]; - while( (bytesRead = is.read(buffer)) > 0 ) { + while ((bytesRead = is.read(buffer)) > 0) { zos.write(buffer, 0, bytesRead); } zos.closeEntry(); } - + zos.flush(); } finally { zos.close(); } - - + + } - + // package scope for testing. - + private void saveInternal(OutputStream output, OpenRocketDocument document, StorageOptions options) throws IOException { - - if ( options.getFileType() == StorageOptions.FileType.ROCKSIM ) { + + if (options.getFileType() == StorageOptions.FileType.ROCKSIM) { new RocksimSaver().save(output, document, options); } else { new OpenRocketSaver().save(output, document, options); } } - + private static class ProgressOutputStream extends FilterOutputStream { - + private long estimatedSize; private long bytesWritten = 0; private SavingProgress progressCallback; - - ProgressOutputStream( OutputStream ostream, long estimatedSize, SavingProgress progressCallback ) { + + ProgressOutputStream(OutputStream ostream, long estimatedSize, SavingProgress progressCallback) { super(ostream); this.estimatedSize = estimatedSize; this.progressCallback = progressCallback; } - + @Override public void write(int b) throws IOException { super.write(b); bytesWritten++; updateProgress(); } - + @Override public void write(byte[] b) throws IOException { super.write(b); bytesWritten += b.length; updateProgress(); } - + @Override public void write(byte[] b, int off, int len) throws IOException { super.write(b, off, len); bytesWritten += len; updateProgress(); } - + private void updateProgress() { if (progressCallback != null) { int p = 50; - if ( estimatedSize > 0 ) { - p = (int) Math.floor( bytesWritten * 100.0 / estimatedSize ); + if (estimatedSize > 0) { + p = (int) Math.floor(bytesWritten * 100.0 / estimatedSize); p = MathUtil.clamp(p, 0, 100); } progressCallback.setProgress(p); } } - + } } diff --git a/core/src/net/sf/openrocket/file/RocketSaver.java b/core/src/net/sf/openrocket/file/RocketSaver.java index 30b13cd62..b731c7f75 100644 --- a/core/src/net/sf/openrocket/file/RocketSaver.java +++ b/core/src/net/sf/openrocket/file/RocketSaver.java @@ -40,22 +40,4 @@ public abstract class RocketSaver { * @return the estimated number of bytes the storage would take. */ public abstract long estimateFileSize(OpenRocketDocument doc, StorageOptions options); - - public static String escapeXML(String s) { - - s = s.replace("&", "&"); - s = s.replace("<", "<"); - s = s.replace(">", ">"); - s = s.replace("\"","""); - s = s.replace("'", "'"); - - for (int i=0; i < s.length(); i++) { - char n = s.charAt(i); - if (((n < 32) && (n != 9) && (n != 10) && (n != 13)) || (n == 127)) { - s = s.substring(0,i) + "&#" + ((int)n) + ";" + s.substring(i+1); - } - } - - return s; - } } diff --git a/core/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java b/core/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java index 3c9b01c86..479341684 100644 --- a/core/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java +++ b/core/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java @@ -354,7 +354,7 @@ public class OpenRocketSaver extends RocketSaver { writeln(""); indent++; - writeln("" + escapeXML(simulation.getName()) + ""); + writeln("" + TextUtil.escapeXML(simulation.getName()) + ""); // TODO: MEDIUM: Other simulators/calculators writeln("RK4Simulator"); @@ -392,7 +392,7 @@ public class OpenRocketSaver extends RocketSaver { for (String s : simulation.getSimulationListeners()) { - writeElement("listener", escapeXML(s)); + writeElement("listener", TextUtil.escapeXML(s)); } // Write basic simulation data @@ -423,7 +423,7 @@ public class OpenRocketSaver extends RocketSaver { indent++; for (Warning w : data.getWarningSet()) { - writeElement("warning", escapeXML(w.toString())); + writeElement("warning", TextUtil.escapeXML(w.toString())); } // Check whether to store data @@ -471,7 +471,7 @@ public class OpenRocketSaver extends RocketSaver { // Build the tag StringBuilder sb = new StringBuilder(); sb.append(" 0) sb.append(","); - sb.append(escapeXML(types[i].getName())); + sb.append(TextUtil.escapeXML(types[i].getName())); } sb.append("\">"); writeln(sb.toString()); diff --git a/core/src/net/sf/openrocket/file/openrocket/importt/DeploymentConfigurationHandler.java b/core/src/net/sf/openrocket/file/openrocket/importt/DeploymentConfigurationHandler.java index 3c5863bef..e40992bbb 100644 --- a/core/src/net/sf/openrocket/file/openrocket/importt/DeploymentConfigurationHandler.java +++ b/core/src/net/sf/openrocket/file/openrocket/importt/DeploymentConfigurationHandler.java @@ -15,49 +15,66 @@ import net.sf.openrocket.rocketcomponent.RecoveryDevice; import org.xml.sax.SAXException; class DeploymentConfigurationHandler extends AbstractElementHandler { + private final RecoveryDevice recoveryDevice; - private DeploymentConfiguration config; - - public DeploymentConfigurationHandler( RecoveryDevice recoveryDevice, DocumentLoadingContext context ) { - this.recoveryDevice = recoveryDevice; - config = new DeploymentConfiguration(); + + private DeployEvent event = null; + private double delay = Double.NaN; + private double altitude = Double.NaN; + + public DeploymentConfigurationHandler(RecoveryDevice component, DocumentLoadingContext context) { + this.recoveryDevice = component; } - + + public DeploymentConfiguration getConfiguration(DeploymentConfiguration def) { + DeploymentConfiguration config = def.clone(); + if (event != null) { + config.setDeployEvent(event); + } + if (!Double.isNaN(delay)) { + config.setDeployDelay(delay); + } + if (!Double.isNaN(altitude)) { + config.setDeployAltitude(altitude); + } + return config; + } + @Override public ElementHandler openElement(String element, HashMap attributes, WarningSet warnings) throws SAXException { return PlainTextHandler.INSTANCE; } - + @Override public void closeElement(String element, HashMap attributes, String content, WarningSet warnings) throws SAXException { content = content.trim(); - if ( "deployevent".equals(element) ) { - DeployEvent type = (DeployEvent) DocumentConfig.findEnum(content, DeployEvent.class); - if ( type == null ) { + if ("deployevent".equals(element)) { + event = (DeployEvent) DocumentConfig.findEnum(content, DeployEvent.class); + if (event == null) { warnings.add(Warning.FILE_INVALID_PARAMETER); return; } - config.setDeployEvent( type ); return; - } else if ( "deployaltitude".equals(element) ) { - config.setDeployAltitude( Double.parseDouble(content)); + } else if ("deploydelay".equals(element)) { + delay = parseDouble(content, warnings, Warning.FILE_INVALID_PARAMETER); return; - } else if ( "deploydelay".equals(element) ) { - config.setDeployDelay( Double.parseDouble(content)); + } else if ("deployaltitude".equals(element)) { + altitude = parseDouble(content, warnings, Warning.FILE_INVALID_PARAMETER); return; } super.closeElement(element, attributes, content, warnings); - + } - + @Override public void endHandler(String element, HashMap attributes, String content, WarningSet warnings) throws SAXException { String configId = attributes.get("configid"); - recoveryDevice.setFlightConfiguration(configId, config); + DeploymentConfiguration def = recoveryDevice.getDeploymentConfiguration().getDefault(); + recoveryDevice.getDeploymentConfiguration().set(configId, getConfiguration(def)); } } \ No newline at end of file diff --git a/core/src/net/sf/openrocket/file/openrocket/importt/DocumentConfig.java b/core/src/net/sf/openrocket/file/openrocket/importt/DocumentConfig.java index dbf897a5c..dc14486d0 100644 --- a/core/src/net/sf/openrocket/file/openrocket/importt/DocumentConfig.java +++ b/core/src/net/sf/openrocket/file/openrocket/importt/DocumentConfig.java @@ -10,6 +10,7 @@ import net.sf.openrocket.rocketcomponent.BodyComponent; import net.sf.openrocket.rocketcomponent.BodyTube; import net.sf.openrocket.rocketcomponent.Bulkhead; import net.sf.openrocket.rocketcomponent.CenteringRing; +import net.sf.openrocket.rocketcomponent.DeploymentConfiguration; import net.sf.openrocket.rocketcomponent.DeploymentConfiguration.DeployEvent; import net.sf.openrocket.rocketcomponent.EllipticalFinSet; import net.sf.openrocket.rocketcomponent.EngineBlock; @@ -47,7 +48,7 @@ import net.sf.openrocket.util.Reflection; class DocumentConfig { /* Remember to update OpenRocketSaver as well! */ - public static final String[] SUPPORTED_VERSIONS = { "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6"}; + public static final String[] SUPPORTED_VERSIONS = { "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6" }; /** * Divisor used in converting an integer version to the point-represented version. @@ -327,12 +328,15 @@ class DocumentConfig { "auto", Reflection.findMethod(RecoveryDevice.class, "setCDAutomatic", boolean.class))); setters.put("RecoveryDevice:deployevent", new EnumSetter( - Reflection.findMethod(RecoveryDevice.class, "setDefaultDeployEvent", DeployEvent.class), + Reflection.findMethod(RecoveryDevice.class, "getDeploymentConfiguration"), + Reflection.findMethod(DeploymentConfiguration.class, "setDeployEvent", DeployEvent.class), DeployEvent.class)); setters.put("RecoveryDevice:deployaltitude", new DoubleSetter( - Reflection.findMethod(RecoveryDevice.class, "setDefaultDeployAltitude", double.class))); + Reflection.findMethod(RecoveryDevice.class, "getDeploymentConfiguration"), + Reflection.findMethod(DeploymentConfiguration.class, "setDeployAltitude", double.class))); setters.put("RecoveryDevice:deploydelay", new DoubleSetter( - Reflection.findMethod(RecoveryDevice.class, "setDefaultDeployDelay", double.class))); + Reflection.findMethod(RecoveryDevice.class, "getDeploymentConfiguration"), + Reflection.findMethod(DeploymentConfiguration.class, "setDeployDelay", double.class))); setters.put("RecoveryDevice:material", new MaterialSetter( Reflection.findMethod(RecoveryDevice.class, "setMaterial", Material.class), Material.Type.SURFACE)); @@ -368,10 +372,12 @@ class DocumentConfig { // Stage setters.put("Stage:separationevent", new EnumSetter( - Reflection.findMethod(Stage.class, "setDefaultSeparationEvent", StageSeparationConfiguration.SeparationEvent.class), + Reflection.findMethod(Stage.class, "getStageSeparationConfiguration"), + Reflection.findMethod(StageSeparationConfiguration.class, "setSeparationEvent", StageSeparationConfiguration.SeparationEvent.class), StageSeparationConfiguration.SeparationEvent.class)); setters.put("Stage:separationdelay", new DoubleSetter( - Reflection.findMethod(Stage.class, "setDefaultSeparationDelay", double.class))); + Reflection.findMethod(Stage.class, "getStageSeparationConfiguration"), + Reflection.findMethod(StageSeparationConfiguration.class, "setSeparationDelay", double.class))); } diff --git a/core/src/net/sf/openrocket/file/openrocket/importt/DoubleSetter.java b/core/src/net/sf/openrocket/file/openrocket/importt/DoubleSetter.java index a7a50b9b2..9fdd3e9f3 100644 --- a/core/src/net/sf/openrocket/file/openrocket/importt/DoubleSetter.java +++ b/core/src/net/sf/openrocket/file/openrocket/importt/DoubleSetter.java @@ -4,12 +4,15 @@ import java.util.HashMap; import net.sf.openrocket.aerodynamics.Warning; import net.sf.openrocket.aerodynamics.WarningSet; +import net.sf.openrocket.rocketcomponent.FlightConfiguration; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.util.Reflection; +import net.sf.openrocket.util.Reflection.Method; //// DoubleSetter - sets a double value or (alternatively) if a specific string is encountered //// calls a setXXX(boolean) method. class DoubleSetter implements Setter { + private final Reflection.Method configGetter; private final Reflection.Method setMethod; private final String specialString; private final Reflection.Method specialMethod; @@ -21,6 +24,7 @@ class DoubleSetter implements Setter { */ public DoubleSetter(Reflection.Method set) { this.setMethod = set; + this.configGetter = null; this.specialString = null; this.specialMethod = null; this.multiplier = 1.0; @@ -33,6 +37,7 @@ class DoubleSetter implements Setter { */ public DoubleSetter(Reflection.Method set, double mul) { this.setMethod = set; + this.configGetter = null; this.specialString = null; this.specialMethod = null; this.multiplier = mul; @@ -49,12 +54,27 @@ class DoubleSetter implements Setter { public DoubleSetter(Reflection.Method set, String special, Reflection.Method specialMethod) { this.setMethod = set; + this.configGetter = null; this.specialString = special; this.specialMethod = specialMethod; this.multiplier = 1.0; } + /** + * Set a double value of the default configuration of a FlightConfiguration object. + * + * @param configGetter getter method for the FlightConfiguration object + * @param setter setter method for the configuration object + */ + public DoubleSetter(Method configGetter, Method setter) { + this.setMethod = setter; + this.configGetter = configGetter; + this.specialString = null; + this.specialMethod = null; + this.multiplier = 1.0; + } + @Override public void set(RocketComponent c, String s, HashMap attributes, WarningSet warnings) { @@ -70,7 +90,14 @@ class DoubleSetter implements Setter { // Normal case try { double d = Double.parseDouble(s); - setMethod.invoke(c, d * multiplier); + + if (configGetter == null) { + setMethod.invoke(c, d * multiplier); + } else { + FlightConfiguration config = (FlightConfiguration) configGetter.invoke(c); + Object obj = config.getDefault(); + setMethod.invoke(obj, d * multiplier); + } } catch (NumberFormatException e) { warnings.add(Warning.FILE_INVALID_PARAMETER); } diff --git a/core/src/net/sf/openrocket/file/openrocket/importt/EnumSetter.java b/core/src/net/sf/openrocket/file/openrocket/importt/EnumSetter.java index 8b93becbd..55ceaac34 100644 --- a/core/src/net/sf/openrocket/file/openrocket/importt/EnumSetter.java +++ b/core/src/net/sf/openrocket/file/openrocket/importt/EnumSetter.java @@ -4,16 +4,24 @@ import java.util.HashMap; import net.sf.openrocket.aerodynamics.Warning; import net.sf.openrocket.aerodynamics.WarningSet; +import net.sf.openrocket.rocketcomponent.FlightConfiguration; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.util.Reflection; +import net.sf.openrocket.util.Reflection.Method; //// EnumSetter - sets a generic enum type class EnumSetter> implements Setter { + private final Reflection.Method configurationGetter; private final Reflection.Method setter; private final Class enumClass; - public EnumSetter(Reflection.Method set, Class enumClass) { - this.setter = set; + public EnumSetter(Reflection.Method setter, Class enumClass) { + this(null, setter, enumClass); + } + + public EnumSetter(Method configurationGetter, Method setter, Class enumClass) { + this.configurationGetter = configurationGetter; + this.setter = setter; this.enumClass = enumClass; } @@ -27,6 +35,12 @@ class EnumSetter> implements Setter { return; } - setter.invoke(c, setEnum); + if (configurationGetter == null) { + setter.invoke(c, setEnum); + } else { + FlightConfiguration config = (FlightConfiguration) configurationGetter.invoke(c); + Object obj = config.getDefault(); + setter.invoke(obj, setEnum); + } } } \ No newline at end of file diff --git a/core/src/net/sf/openrocket/file/openrocket/importt/IgnitionConfigurationHandler.java b/core/src/net/sf/openrocket/file/openrocket/importt/IgnitionConfigurationHandler.java index 8ec701c5c..ee02dbc07 100644 --- a/core/src/net/sf/openrocket/file/openrocket/importt/IgnitionConfigurationHandler.java +++ b/core/src/net/sf/openrocket/file/openrocket/importt/IgnitionConfigurationHandler.java @@ -9,21 +9,19 @@ import net.sf.openrocket.file.DocumentLoadingContext; import net.sf.openrocket.file.simplesax.AbstractElementHandler; import net.sf.openrocket.file.simplesax.ElementHandler; import net.sf.openrocket.file.simplesax.PlainTextHandler; -import net.sf.openrocket.rocketcomponent.MotorConfiguration; +import net.sf.openrocket.rocketcomponent.IgnitionConfiguration; +import net.sf.openrocket.rocketcomponent.IgnitionConfiguration.IgnitionEvent; import org.xml.sax.SAXException; class IgnitionConfigurationHandler extends AbstractElementHandler { - /** File version where latest digest format was introduced */ - private static final int MOTOR_DIGEST_VERSION = 104; - - private final DocumentLoadingContext context; private Double ignitionDelay = null; - private MotorConfiguration.IgnitionEvent ignitionEvent = null; + private IgnitionEvent ignitionEvent = null; + public IgnitionConfigurationHandler(DocumentLoadingContext context) { - this.context = context; + } @@ -34,13 +32,17 @@ class IgnitionConfigurationHandler extends AbstractElementHandler { } - public Double getIgnitionDelay() { - return ignitionDelay; + public IgnitionConfiguration getConfiguration(IgnitionConfiguration def) { + IgnitionConfiguration config = def.clone(); + if (ignitionEvent != null) { + config.setIgnitionEvent(ignitionEvent); + } + if (ignitionDelay != null) { + config.setIgnitionDelay(ignitionDelay); + } + return config; } - public MotorConfiguration.IgnitionEvent getIgnitionEvent() { - return ignitionEvent; - } @Override public void closeElement(String element, HashMap attributes, @@ -50,7 +52,7 @@ class IgnitionConfigurationHandler extends AbstractElementHandler { if (element.equals("ignitionevent")) { - for (MotorConfiguration.IgnitionEvent e : MotorConfiguration.IgnitionEvent.values()) { + for (IgnitionEvent e : IgnitionEvent.values()) { if (e.name().toLowerCase(Locale.ENGLISH).replaceAll("_", "").equals(content)) { ignitionEvent = e; break; diff --git a/core/src/net/sf/openrocket/file/openrocket/importt/MotorMountHandler.java b/core/src/net/sf/openrocket/file/openrocket/importt/MotorMountHandler.java index 8efec835c..e723edab1 100644 --- a/core/src/net/sf/openrocket/file/openrocket/importt/MotorMountHandler.java +++ b/core/src/net/sf/openrocket/file/openrocket/importt/MotorMountHandler.java @@ -9,7 +9,6 @@ import net.sf.openrocket.file.DocumentLoadingContext; import net.sf.openrocket.file.simplesax.AbstractElementHandler; import net.sf.openrocket.file.simplesax.ElementHandler; import net.sf.openrocket.file.simplesax.PlainTextHandler; -import net.sf.openrocket.motor.Motor; import net.sf.openrocket.rocketcomponent.IgnitionConfiguration; import net.sf.openrocket.rocketcomponent.MotorConfiguration; import net.sf.openrocket.rocketcomponent.MotorMount; @@ -65,9 +64,11 @@ class MotorMountHandler extends AbstractElementHandler { return; } - Motor motor = motorHandler.getMotor(warnings); - mount.setMotor(id, motor); - mount.setMotorDelay(id, motorHandler.getDelay(warnings)); + MotorConfiguration config = new MotorConfiguration(); + config.setMotor(motorHandler.getMotor(warnings)); + config.setEjectionDelay(motorHandler.getDelay(warnings)); + mount.getMotorConfiguration().set(id, config); + return; } @@ -77,9 +78,9 @@ class MotorMountHandler extends AbstractElementHandler { warnings.add(Warning.fromString("Illegal motor specification, ignoring.")); return; } - MotorConfiguration motorConfig = mount.getFlightConfiguration(id); - motorConfig.setIgnitionEvent(ignitionConfigHandler.getIgnitionEvent()); - motorConfig.setIgnitionDelay(ignitionConfigHandler.getIgnitionDelay()); + + IgnitionConfiguration def = mount.getIgnitionConfiguration().getDefault(); + mount.getIgnitionConfiguration().set(id, ignitionConfigHandler.getConfiguration(def)); return; } @@ -95,7 +96,7 @@ class MotorMountHandler extends AbstractElementHandler { warnings.add(Warning.fromString("Unknown ignition event type '" + content + "', ignoring.")); return; } - mount.setDefaultIgnitionEvent(event); + mount.getIgnitionConfiguration().getDefault().setIgnitionEvent(event); return; } @@ -107,7 +108,7 @@ class MotorMountHandler extends AbstractElementHandler { warnings.add(Warning.fromString("Illegal ignition delay specified, ignoring.")); return; } - mount.setDefaultIgnitionDelay(d); + mount.getIgnitionConfiguration().getDefault().setIgnitionDelay(d); return; } diff --git a/core/src/net/sf/openrocket/file/openrocket/importt/StageSeparationConfigurationHandler.java b/core/src/net/sf/openrocket/file/openrocket/importt/StageSeparationConfigurationHandler.java index 0b3c42393..a349c91df 100644 --- a/core/src/net/sf/openrocket/file/openrocket/importt/StageSeparationConfigurationHandler.java +++ b/core/src/net/sf/openrocket/file/openrocket/importt/StageSeparationConfigurationHandler.java @@ -16,45 +16,59 @@ import org.xml.sax.SAXException; class StageSeparationConfigurationHandler extends AbstractElementHandler { private final Stage stage; - private StageSeparationConfiguration config; - - public StageSeparationConfigurationHandler( Stage stage, DocumentLoadingContext context ) { + + private SeparationEvent event = null; + private double delay = Double.NaN; + + public StageSeparationConfigurationHandler(Stage stage, DocumentLoadingContext context) { this.stage = stage; - config = new StageSeparationConfiguration(); } - + + + public StageSeparationConfiguration getConfiguration(StageSeparationConfiguration def) { + StageSeparationConfiguration config = def.clone(); + if (event != null) { + config.setSeparationEvent(event); + } + if (!Double.isNaN(delay)) { + config.setSeparationDelay(delay); + } + return config; + } + + @Override public ElementHandler openElement(String element, HashMap attributes, WarningSet warnings) throws SAXException { return PlainTextHandler.INSTANCE; } - + @Override public void closeElement(String element, HashMap attributes, String content, WarningSet warnings) throws SAXException { content = content.trim(); - if ( "separationevent".equals(element) ) { - SeparationEvent type = (SeparationEvent) DocumentConfig.findEnum(content, SeparationEvent.class); - if ( type == null ) { + if ("separationevent".equals(element)) { + event = (SeparationEvent) DocumentConfig.findEnum(content, SeparationEvent.class); + if (event == null) { warnings.add(Warning.FILE_INVALID_PARAMETER); return; } - config.setSeparationEvent( type ); return; - } else if ( "separationdelay".equals(element) ) { - config.setSeparationDelay( Double.parseDouble(content)); + } else if ("separationdelay".equals(element)) { + delay = parseDouble(content, warnings, Warning.FILE_INVALID_PARAMETER); return; } super.closeElement(element, attributes, content, warnings); - + } - + @Override public void endHandler(String element, HashMap attributes, String content, WarningSet warnings) throws SAXException { String configId = attributes.get("configid"); - stage.setFlightConfiguration(configId, config); + StageSeparationConfiguration def = stage.getStageSeparationConfiguration().getDefault(); + stage.getStageSeparationConfiguration().set(configId, getConfiguration(def)); } } \ No newline at end of file diff --git a/core/src/net/sf/openrocket/file/openrocket/savers/RecoveryDeviceSaver.java b/core/src/net/sf/openrocket/file/openrocket/savers/RecoveryDeviceSaver.java index cfc16275a..e4f06442d 100644 --- a/core/src/net/sf/openrocket/file/openrocket/savers/RecoveryDeviceSaver.java +++ b/core/src/net/sf/openrocket/file/openrocket/savers/RecoveryDeviceSaver.java @@ -10,48 +10,49 @@ import net.sf.openrocket.rocketcomponent.Rocket; public class RecoveryDeviceSaver extends MassObjectSaver { - + @Override protected void addParams(net.sf.openrocket.rocketcomponent.RocketComponent c, List elements) { super.addParams(c, elements); - + RecoveryDevice dev = (RecoveryDevice) c; - + if (dev.isCDAutomatic()) elements.add("auto"); else elements.add("" + dev.getCD() + ""); - - DeploymentConfiguration defaultConfig = dev.getDefaultFlightConfiguration(); - elements.addAll( deploymentConfiguration(defaultConfig, false)); elements.add(materialParam(dev.getMaterial())); - + + // NOTE: Default config must be BEFORE overridden config for proper backward compatibility later on + DeploymentConfiguration defaultConfig = dev.getDeploymentConfiguration().getDefault(); + elements.addAll(deploymentConfiguration(defaultConfig, false)); + Rocket rocket = c.getRocket(); // Note - getFlightConfigurationIDs returns at least one element. The first element // is null and means "default". String[] configs = rocket.getFlightConfigurationIDs(); - if ( configs.length > 1 ) { - - for( String id : configs ) { - if ( id == null ) { + if (configs.length > 1) { + + for (String id : configs) { + if (id == null) { continue; } - DeploymentConfiguration config = dev.getFlightConfiguration(id); - if ( config == null ) { + if (dev.getDeploymentConfiguration().isDefault(id)) { continue; } + DeploymentConfiguration config = dev.getDeploymentConfiguration().get(id); elements.add(""); - elements.addAll( deploymentConfiguration(config, true) ); + elements.addAll(deploymentConfiguration(config, true)); elements.add(""); } } } - - private List deploymentConfiguration( DeploymentConfiguration config, boolean indent ) { + + private List deploymentConfiguration(DeploymentConfiguration config, boolean indent) { List elements = new ArrayList(3); - elements.add((indent?" ": "") + "" + config.getDeployEvent().name().toLowerCase(Locale.ENGLISH).replace("_", "") + ""); - elements.add((indent?" ": "") + "" + config.getDeployAltitude() + ""); - elements.add((indent?" ": "") + "" + config.getDeployDelay() + ""); + elements.add((indent ? " " : "") + "" + config.getDeployEvent().name().toLowerCase(Locale.ENGLISH).replace("_", "") + ""); + elements.add((indent ? " " : "") + "" + config.getDeployAltitude() + ""); + elements.add((indent ? " " : "") + "" + config.getDeployDelay() + ""); return elements; } diff --git a/core/src/net/sf/openrocket/file/openrocket/savers/RocketComponentSaver.java b/core/src/net/sf/openrocket/file/openrocket/savers/RocketComponentSaver.java index adda3e115..7df686e5a 100644 --- a/core/src/net/sf/openrocket/file/openrocket/savers/RocketComponentSaver.java +++ b/core/src/net/sf/openrocket/file/openrocket/savers/RocketComponentSaver.java @@ -8,13 +8,13 @@ import java.util.Locale; import net.sf.openrocket.appearance.Appearance; import net.sf.openrocket.appearance.Decal; import net.sf.openrocket.appearance.Decal.EdgeMode; -import net.sf.openrocket.file.RocketSaver; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.material.Material; import net.sf.openrocket.motor.Motor; import net.sf.openrocket.motor.ThrustCurveMotor; import net.sf.openrocket.preset.ComponentPreset; import net.sf.openrocket.rocketcomponent.ComponentAssembly; +import net.sf.openrocket.rocketcomponent.IgnitionConfiguration; import net.sf.openrocket.rocketcomponent.MotorConfiguration; import net.sf.openrocket.rocketcomponent.MotorMount; import net.sf.openrocket.rocketcomponent.Rocket; @@ -24,6 +24,7 @@ import net.sf.openrocket.util.BugException; import net.sf.openrocket.util.Color; import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.LineStyle; +import net.sf.openrocket.util.TextUtil; public class RocketComponentSaver { private static final Translator trans = Application.getTranslator(); @@ -33,7 +34,7 @@ public class RocketComponentSaver { } protected void addParams(net.sf.openrocket.rocketcomponent.RocketComponent c, List elements) { - elements.add("" + RocketSaver.escapeXML(c.getName()) + ""); + elements.add("" + TextUtil.escapeXML(c.getName()) + ""); ComponentPreset preset = c.getPresetComponent(); if (preset != null) { @@ -104,7 +105,7 @@ public class RocketComponentSaver { // Comment if (c.getComment().length() > 0) { - elements.add("" + RocketSaver.escapeXML(c.getComment()) + ""); + elements.add("" + TextUtil.escapeXML(c.getComment()) + ""); } } @@ -136,7 +137,7 @@ public class RocketComponentSaver { String baseName = trans.getBaseText("material", mat.getName()); - return str + " density=\"" + mat.getDensity() + "\">" + RocketSaver.escapeXML(baseName) + ""; + return str + " density=\"" + mat.getDensity() + "\">" + TextUtil.escapeXML(baseName) + ""; } @@ -148,11 +149,15 @@ public class RocketComponentSaver { elements.add(""); + // NOTE: Default config must be BEFORE overridden config for proper backward compatibility later on + elements.add(" " + + mount.getIgnitionConfiguration().getDefault().getIgnitionEvent().name().toLowerCase(Locale.ENGLISH).replace("_", "") + + ""); + elements.add(" " + mount.getIgnitionConfiguration().getDefault().getIgnitionDelay() + ""); + elements.add(" " + mount.getMotorOverhang() + ""); + for (String id : motorConfigIDs) { - MotorConfiguration motorConfig = mount.getFlightConfiguration(id); - if (motorConfig == null) { - continue; - } + MotorConfiguration motorConfig = mount.getMotorConfiguration().get(id); Motor motor = motorConfig.getMotor(); // Nothing is stored if no motor loaded if (motor == null) @@ -164,11 +169,11 @@ public class RocketComponentSaver { } if (motor instanceof ThrustCurveMotor) { ThrustCurveMotor m = (ThrustCurveMotor) motor; - elements.add(" " + RocketSaver.escapeXML(m.getManufacturer().getSimpleName()) + + elements.add(" " + TextUtil.escapeXML(m.getManufacturer().getSimpleName()) + ""); elements.add(" " + m.getDigest() + ""); } - elements.add(" " + RocketSaver.escapeXML(motor.getDesignation()) + ""); + elements.add(" " + TextUtil.escapeXML(motor.getDesignation()) + ""); elements.add(" " + motor.getDiameter() + ""); elements.add(" " + motor.getLength() + ""); @@ -181,27 +186,16 @@ public class RocketComponentSaver { elements.add(" "); - if (motorConfig.getIgnitionEvent() != null || motorConfig.getIgnitionDelay() != null) { + if (!mount.getIgnitionConfiguration().isDefault(id)) { + IgnitionConfiguration ignition = mount.getIgnitionConfiguration().get(id); elements.add(" "); - - if (motorConfig.getIgnitionEvent() != null) { - elements.add(" " + motorConfig.getIgnitionEvent().name().toLowerCase(Locale.ENGLISH).replace("_", "") + ""); - } - if (motorConfig.getIgnitionDelay() != null) { - elements.add(" " + motorConfig.getIgnitionDelay() + ""); - } - + elements.add(" " + ignition.getIgnitionEvent().name().toLowerCase(Locale.ENGLISH).replace("_", "") + ""); + elements.add(" " + ignition.getIgnitionDelay() + ""); elements.add(" "); } } - elements.add(" " - + mount.getDefaultIgnitionEvent().name().toLowerCase(Locale.ENGLISH).replace("_", "") - + ""); - elements.add(" " + mount.getDefaultIgnitionDelay() + ""); - elements.add(" " + mount.getMotorOverhang() + ""); - elements.add(""); return elements; diff --git a/core/src/net/sf/openrocket/file/openrocket/savers/RocketSaver.java b/core/src/net/sf/openrocket/file/openrocket/savers/RocketSaver.java index 3a58bed5d..257e072c1 100644 --- a/core/src/net/sf/openrocket/file/openrocket/savers/RocketSaver.java +++ b/core/src/net/sf/openrocket/file/openrocket/savers/RocketSaver.java @@ -29,12 +29,12 @@ public class RocketSaver extends RocketComponentSaver { if (rocket.getDesigner().length() > 0) { elements.add("" - + net.sf.openrocket.file.RocketSaver.escapeXML(rocket.getDesigner()) + + net.sf.openrocket.util.TextUtil.escapeXML(rocket.getDesigner()) + ""); } if (rocket.getRevision().length() > 0) { elements.add("" - + net.sf.openrocket.file.RocketSaver.escapeXML(rocket.getRevision()) + + net.sf.openrocket.util.TextUtil.escapeXML(rocket.getRevision()) + ""); } @@ -52,7 +52,7 @@ public class RocketSaver extends RocketComponentSaver { if (rocket.getFlightConfigurationName(id) == "") { str += "/>"; } else { - str += ">" + net.sf.openrocket.file.RocketSaver.escapeXML(rocket.getFlightConfigurationName(id)) + str += ">" + net.sf.openrocket.util.TextUtil.escapeXML(rocket.getFlightConfigurationName(id)) + ""; } elements.add(str); diff --git a/core/src/net/sf/openrocket/file/openrocket/savers/StageSaver.java b/core/src/net/sf/openrocket/file/openrocket/savers/StageSaver.java index 33bdd4986..fb875379f 100644 --- a/core/src/net/sf/openrocket/file/openrocket/savers/StageSaver.java +++ b/core/src/net/sf/openrocket/file/openrocket/savers/StageSaver.java @@ -10,56 +10,57 @@ import net.sf.openrocket.rocketcomponent.Stage; import net.sf.openrocket.rocketcomponent.StageSeparationConfiguration; public class StageSaver extends ComponentAssemblySaver { - + private static final StageSaver instance = new StageSaver(); - + public static ArrayList getElements(net.sf.openrocket.rocketcomponent.RocketComponent c) { ArrayList list = new ArrayList(); - + list.add(""); instance.addParams(c, list); list.add(""); - + return list; } - + @Override protected void addParams(RocketComponent c, List elements) { super.addParams(c, elements); Stage stage = (Stage) c; - + if (stage.getStageNumber() > 0) { - elements.addAll( separationConfig( stage.getDefaultFlightConfiguration(), false)); - + // NOTE: Default config must be BEFORE overridden config for proper backward compatibility later on + elements.addAll(separationConfig(stage.getStageSeparationConfiguration().getDefault(), false)); + Rocket rocket = stage.getRocket(); // Note - getFlightConfigurationIDs returns at least one element. The first element // is null and means "default". String[] configs = rocket.getFlightConfigurationIDs(); - if ( configs.length > 1 ) { - - for( String id : configs ) { - if ( id == null ) { + if (configs.length > 1) { + + for (String id : configs) { + if (id == null) { continue; } - StageSeparationConfiguration config = stage.getFlightConfiguration(id); - if ( config == null ) { + if (stage.getStageSeparationConfiguration().isDefault(id)) { continue; } + StageSeparationConfiguration config = stage.getStageSeparationConfiguration().get(id); elements.add(""); - elements.addAll( separationConfig(config, true) ); + elements.addAll(separationConfig(config, true)); elements.add(""); } } } } - - private List separationConfig( StageSeparationConfiguration config, boolean indent ) { + + private List separationConfig(StageSeparationConfiguration config, boolean indent) { List elements = new ArrayList(2); - elements.add((indent?" ":"")+ "" + elements.add((indent ? " " : "") + "" + config.getSeparationEvent().name().toLowerCase(Locale.ENGLISH).replace("_", "") + ""); - elements.add((indent?" ":"")+ "" + config.getSeparationDelay() + ""); + elements.add((indent ? " " : "") + "" + config.getSeparationDelay() + ""); return elements; - + } } diff --git a/core/src/net/sf/openrocket/file/simplesax/AbstractElementHandler.java b/core/src/net/sf/openrocket/file/simplesax/AbstractElementHandler.java index 208f68c01..3085d2ffe 100644 --- a/core/src/net/sf/openrocket/file/simplesax/AbstractElementHandler.java +++ b/core/src/net/sf/openrocket/file/simplesax/AbstractElementHandler.java @@ -51,4 +51,21 @@ public abstract class AbstractElementHandler implements ElementHandler { // No-op } + + /** + * Helper method for parsing a double value safely. + * + * @param str the string to parse + * @param warnings the warning set + * @param warn the warning to add if the value fails to parse + * @return the double value, or NaN if an error occurred + */ + protected double parseDouble(String str, WarningSet warnings, Warning warn) { + try { + return Double.parseDouble(str); + } catch (NumberFormatException e) { + warnings.add(warn); + return Double.NaN; + } + } } diff --git a/core/src/net/sf/openrocket/gui/adaptors/BasicEnumModel.java b/core/src/net/sf/openrocket/gui/adaptors/BasicEnumModel.java deleted file mode 100644 index 37b512645..000000000 --- a/core/src/net/sf/openrocket/gui/adaptors/BasicEnumModel.java +++ /dev/null @@ -1,48 +0,0 @@ -package net.sf.openrocket.gui.adaptors; - -import javax.swing.AbstractListModel; -import javax.swing.ComboBoxModel; - - -public class BasicEnumModel> extends AbstractListModel implements ComboBoxModel { - - private final String nullText; - - private final Enum[] values; - private Enum currentValue = null; - - public BasicEnumModel( Class> clazz ) { - this(clazz, null); - } - - @SuppressWarnings("unchecked") - public BasicEnumModel(Class> clazz, String nullText) { - this.values = clazz.getEnumConstants(); - this.nullText = nullText; - } - - @Override - public void setSelectedItem(Object anItem) { - currentValue = (Enum) anItem; - } - - @Override - public Object getSelectedItem() { - if (currentValue==null) - return nullText; - return currentValue; - } - - @Override - public Object getElementAt(int index) { - if (values[index] == null) - return nullText; - return values[index]; - } - - @Override - public int getSize() { - return values.length; - } - -} diff --git a/core/src/net/sf/openrocket/gui/configdialog/MotorConfig.java b/core/src/net/sf/openrocket/gui/configdialog/MotorConfig.java index 15dbf881b..2974e768f 100644 --- a/core/src/net/sf/openrocket/gui/configdialog/MotorConfig.java +++ b/core/src/net/sf/openrocket/gui/configdialog/MotorConfig.java @@ -144,7 +144,7 @@ public class MotorConfig extends JPanel { //// plus panel.add(new JLabel(trans.get("MotorCfg.lbl.plus")), "gap indent, skip 1, span, split"); - dm = new DoubleModel(ignitionConfig, "Delay", 0); + dm = new DoubleModel(ignitionConfig, "IgnitionDelay", 0); spin = new JSpinner(dm.getSpinnerModel()); spin.setEditor(new SpinnerEditor(spin, 3)); panel.add(spin, "gap rel rel"); diff --git a/core/src/net/sf/openrocket/gui/configdialog/StageConfig.java b/core/src/net/sf/openrocket/gui/configdialog/StageConfig.java index c7e76e875..08e6a57b9 100644 --- a/core/src/net/sf/openrocket/gui/configdialog/StageConfig.java +++ b/core/src/net/sf/openrocket/gui/configdialog/StageConfig.java @@ -40,13 +40,14 @@ public class StageConfig extends RocketComponentConfig { // Select separation event panel.add(new StyledLabel(trans.get("separation.lbl.title"), Style.BOLD), "spanx, wrap rel"); - JComboBox combo = new JComboBox(new EnumModel(stage, "DefaultSeparationEvent")); + StageSeparationConfiguration config = stage.getStageSeparationConfiguration().getDefault(); + JComboBox combo = new JComboBox(new EnumModel(config, "SeparationEvent")); panel.add(combo, ""); // ... and delay panel.add(new JLabel(trans.get("separation.lbl.plus")), ""); - DoubleModel dm = new DoubleModel(stage, "DefaultSeparationDelay", 0); + DoubleModel dm = new DoubleModel(config, "SeparationDelay", 0); JSpinner spin = new JSpinner(dm.getSpinnerModel()); spin.setEditor(new SpinnerEditor(spin)); panel.add(spin, "width 45"); diff --git a/core/src/net/sf/openrocket/gui/customexpression/OperatorSelector.java b/core/src/net/sf/openrocket/gui/customexpression/OperatorSelector.java index 4a66d15ee..a4daa254c 100644 --- a/core/src/net/sf/openrocket/gui/customexpression/OperatorSelector.java +++ b/core/src/net/sf/openrocket/gui/customexpression/OperatorSelector.java @@ -26,13 +26,12 @@ import net.miginfocom.swing.MigLayout; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.logging.LogHelper; import net.sf.openrocket.startup.Application; -import net.sf.openrocket.util.TextUtil; public class OperatorSelector extends JDialog { private static final Translator trans = Application.getTranslator(); private static final LogHelper log = Application.getLogger(); - + @SuppressWarnings("unused") private final Window parentWindow; @@ -40,7 +39,7 @@ public class OperatorSelector extends JDialog { private final OperatorTableModel tableModel; private final ExpressionBuilderDialog parentBuilder; - public OperatorSelector(Window parent, final ExpressionBuilderDialog parentBuilder){ + public OperatorSelector(Window parent, final ExpressionBuilderDialog parentBuilder) { super(parent, trans.get("CustomOperatorSelector.title"), JDialog.ModalityType.DOCUMENT_MODAL); @@ -57,19 +56,19 @@ public class OperatorSelector extends JDialog { table.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); int width = table.getColumnModel().getTotalColumnWidth(); - table.getColumnModel().getColumn(0).setPreferredWidth( (int) (.1 * width)); - table.getColumnModel().getColumn(1).setPreferredWidth( (int) (.9 * width)); + table.getColumnModel().getColumn(0).setPreferredWidth((int) (.1 * width)); + table.getColumnModel().getColumn(1).setPreferredWidth((int) (.9 * width)); table.setAutoCreateRowSorter(true); - table.addMouseMotionListener(new MouseMotionAdapter(){ + table.addMouseMotionListener(new MouseMotionAdapter() { @Override - public void mouseMoved(MouseEvent e){ + public void mouseMoved(MouseEvent e) { Point p = e.getPoint(); int row = table.rowAtPoint(p); int col = table.columnAtPoint(p); - if (col == 1 && row > -1){ + if (col == 1 && row > -1) { String description = String.valueOf(table.getValueAt(row, 1)); - description = TextUtil.wrap(description, 60); + description = wrap(description, 60); table.setToolTipText(description); } else { table.setToolTipText(null); @@ -77,29 +76,37 @@ public class OperatorSelector extends JDialog { } }); - table.addMouseListener(new MouseListener(){ + table.addMouseListener(new MouseListener() { @Override - public void mouseClicked(MouseEvent e){ - if (e.getClickCount() == 2){ + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == 2) { log.debug("Selected operator by double clicking."); selectOperator(); } } + @Override - public void mouseEntered(MouseEvent e) {} + public void mouseEntered(MouseEvent e) { + } + @Override - public void mouseExited(MouseEvent e) {} + public void mouseExited(MouseEvent e) { + } + @Override - public void mousePressed(MouseEvent e) {} + public void mousePressed(MouseEvent e) { + } + @Override - public void mouseReleased(MouseEvent e) {} - } ); + public void mouseReleased(MouseEvent e) { + } + }); InputMap inputMap = table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); ActionMap actionMap = table.getActionMap(); KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0); inputMap.put(enter, "select"); - actionMap.put("select", new AbstractAction(){ + actionMap.put("select", new AbstractAction() { @Override public void actionPerformed(ActionEvent arg0) { log.debug("Selected operator by enter key"); @@ -110,16 +117,16 @@ public class OperatorSelector extends JDialog { JScrollPane scrollPane = new JScrollPane(table); table.setFillsViewportHeight(true); table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { - @Override - public void valueChanged(ListSelectionEvent e){ - if (table.getSelectedRowCount() == 1){ - insertButton.setEnabled(true); - } - else { - insertButton.setEnabled(false); - } + @Override + public void valueChanged(ListSelectionEvent e) { + if (table.getSelectedRowCount() == 1) { + insertButton.setEnabled(true); } - }); + else { + insertButton.setEnabled(false); + } + } + }); mainPanel.add(scrollPane, "wrap, push, grow"); @@ -142,17 +149,32 @@ public class OperatorSelector extends JDialog { }); insertButton.setEnabled(false); // disabled by default, only enable when a variable selected mainPanel.add(insertButton, "right, width :100:200, wrap"); - + this.add(mainPanel); this.validate(); this.pack(); - this.setLocationByPlatform(true); + this.setLocationByPlatform(true); } - private void selectOperator(){ + private void selectOperator() { int row = table.getSelectedRow(); String str = table.getValueAt(row, 0).toString(); parentBuilder.pasteIntoExpression(str); OperatorSelector.this.dispose(); } + + + /* + * Returns a word-wrapped version of given input string using HTML syntax, wrapped to len characters. + */ + private String wrap(String in, int len) { + in = in.trim(); + if (in.length() < len) + return in; + if (in.substring(0, len).contains("\n")) + return in.substring(0, in.indexOf("\n")).trim() + "\n\n" + wrap(in.substring(in.indexOf("\n") + 1), len); + int place = Math.max(Math.max(in.lastIndexOf(" ", len), in.lastIndexOf("\t", len)), in.lastIndexOf("-", len)); + return "" + in.substring(0, place).trim() + "
" + wrap(in.substring(place), len); + } + } diff --git a/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/DeploymentSelectionDialog.java b/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/DeploymentSelectionDialog.java new file mode 100644 index 000000000..41d03cb8b --- /dev/null +++ b/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/DeploymentSelectionDialog.java @@ -0,0 +1,147 @@ +package net.sf.openrocket.gui.dialogs.flightconfiguration; + +import java.awt.Dialog; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.ButtonGroup; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.JSlider; +import javax.swing.JSpinner; + +import net.miginfocom.swing.MigLayout; +import net.sf.openrocket.gui.SpinnerEditor; +import net.sf.openrocket.gui.adaptors.DoubleModel; +import net.sf.openrocket.gui.adaptors.EnumModel; +import net.sf.openrocket.gui.components.BasicSlider; +import net.sf.openrocket.gui.components.UnitSelector; +import net.sf.openrocket.gui.util.GUIUtil; +import net.sf.openrocket.l10n.Translator; +import net.sf.openrocket.rocketcomponent.DeploymentConfiguration; +import net.sf.openrocket.rocketcomponent.DeploymentConfiguration.DeployEvent; +import net.sf.openrocket.rocketcomponent.RecoveryDevice; +import net.sf.openrocket.rocketcomponent.Rocket; +import net.sf.openrocket.startup.Application; +import net.sf.openrocket.unit.UnitGroup; + +public class DeploymentSelectionDialog extends JDialog { + + private static final Translator trans = Application.getTranslator(); + + private final DeploymentConfiguration newConfiguration; + + private final JLabel altText; + private final JSpinner altSpinner; + private final UnitSelector altUnit; + private final JSlider altSlider; + + DeploymentSelectionDialog(JDialog parent, final Rocket rocket, final RecoveryDevice component) { + super(parent, trans.get("edtmotorconfdlg.title.Selectdeploymentconf"), Dialog.ModalityType.APPLICATION_MODAL); + + final String id = rocket.getDefaultConfiguration().getFlightConfigurationID(); + + newConfiguration = component.getDeploymentConfiguration().get(id).clone(); + + JPanel panel = new JPanel(new MigLayout("fill")); + + panel.add(new JLabel(trans.get("DeploymentSelectionDialog.opt.title")), "span, wrap rel"); + final JRadioButton defaultButton = new JRadioButton(trans.get("DeploymentSelectionDialog.opt.default"), true); + panel.add(defaultButton, "span, gapleft para, wrap rel"); + String str = trans.get("DeploymentSelectionDialog.opt.override"); + str = str.replace("{0}", rocket.getFlightConfigurationNameOrDescription(id)); + final JRadioButton overrideButton = new JRadioButton(str, false); + panel.add(overrideButton, "span, gapleft para, wrap para"); + + ButtonGroup buttonGroup = new ButtonGroup(); + buttonGroup.add(defaultButton); + buttonGroup.add(overrideButton); + + + //// Deployment + //// Deploys at: + panel.add(new JLabel(trans.get("ParachuteCfg.lbl.Deploysat")), ""); + + final JComboBox event = new JComboBox(new EnumModel(newConfiguration, "DeployEvent")); + panel.add(event, "spanx 3, growx, wrap"); + + // ... and delay + //// plus + panel.add(new JLabel(trans.get("ParachuteCfg.lbl.plusdelay")), "right"); + + final DoubleModel delay = new DoubleModel(newConfiguration, "DeployDelay", UnitGroup.UNITS_SHORT_TIME, 0); + final JSpinner delaySpinner = new JSpinner(delay.getSpinnerModel()); + delaySpinner.setEditor(new SpinnerEditor(delaySpinner, 3)); + panel.add(delaySpinner, "spanx, split"); + + //// seconds + panel.add(new JLabel(trans.get("ParachuteCfg.lbl.seconds")), "wrap paragraph"); + + // Altitude: + altText = new JLabel(trans.get("ParachuteCfg.lbl.Altitude")); + panel.add(altText); + + final DoubleModel alt = new DoubleModel(newConfiguration, "DeployAltitude", UnitGroup.UNITS_DISTANCE, 0); + + altSpinner = new JSpinner(alt.getSpinnerModel()); + altSpinner.setEditor(new SpinnerEditor(altSpinner)); + panel.add(altSpinner, "growx"); + altUnit = new UnitSelector(alt); + panel.add(altUnit, "growx"); + altSlider = new BasicSlider(alt.getSliderModel(100, 1000)); + panel.add(altSlider, "w 100lp, wrap"); + + event.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + updateState(); + } + }); + updateState(); + + panel.add(new JPanel(), "span, split, growx"); + + JButton okButton = new JButton(trans.get("button.ok")); + okButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (defaultButton.isSelected()) { + component.getDeploymentConfiguration().setDefault(newConfiguration); + } else { + component.getDeploymentConfiguration().set(id, newConfiguration); + } + DeploymentSelectionDialog.this.setVisible(false); + } + }); + + panel.add(okButton, "sizegroup btn"); + + JButton cancel = new JButton(trans.get("button.cancel")); + cancel.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + DeploymentSelectionDialog.this.setVisible(false); + } + }); + + panel.add(cancel, "sizegroup btn"); + + this.setContentPane(panel); + GUIUtil.setDisposableDialogOptions(this, okButton); + } + + + private void updateState() { + boolean enabled = (newConfiguration.getDeployEvent() == DeployEvent.ALTITUDE); + altText.setEnabled(enabled); + altSpinner.setEnabled(enabled); + altUnit.setEnabled(enabled); + altSlider.setEnabled(enabled); + } + + +} diff --git a/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/FlightConfigurationDialog.java b/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/FlightConfigurationDialog.java index 41191f070..4cc28bdeb 100644 --- a/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/FlightConfigurationDialog.java +++ b/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/FlightConfigurationDialog.java @@ -16,6 +16,7 @@ import javax.swing.JTabbedPane; import net.miginfocom.swing.MigLayout; import net.sf.openrocket.document.OpenRocketDocument; +import net.sf.openrocket.gui.adaptors.FlightConfigurationModel; import net.sf.openrocket.gui.main.BasicFrame; import net.sf.openrocket.gui.util.GUIUtil; import net.sf.openrocket.l10n.Translator; @@ -23,9 +24,13 @@ import net.sf.openrocket.rocketcomponent.Rocket; import net.sf.openrocket.rocketvisitors.CopyFlightConfigurationVisitor; import net.sf.openrocket.startup.Application; +/** + * Dialog for configuring all flight-configuration specific properties. + * Content of individual tabs are in separate classes. + */ public class FlightConfigurationDialog extends JDialog { - static final Translator trans = Application.getTranslator(); + private static final Translator trans = Application.getTranslator(); private final Rocket rocket; @@ -58,7 +63,7 @@ public class FlightConfigurationDialog extends JDialog { JLabel label = new JLabel("Selected Configuration:"); panel.add(label); - flightConfigurationModel = new FlightConfigurationModel(this, rocket.getDefaultConfiguration()); + flightConfigurationModel = new FlightConfigurationModel(rocket.getDefaultConfiguration()); JComboBox configSelector = new JComboBox(flightConfigurationModel); panel.add(configSelector, "gapright para"); @@ -78,7 +83,7 @@ public class FlightConfigurationDialog extends JDialog { renameConfButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - new RenameConfigDialog(rocket, FlightConfigurationDialog.this).setVisible(true); + new RenameConfigDialog(FlightConfigurationDialog.this, rocket).setVisible(true); } }); panel.add(renameConfButton); @@ -111,7 +116,6 @@ public class FlightConfigurationDialog extends JDialog { //// Motor tabs motorConfigurationPanel = new MotorConfigurationPanel(this, rocket); tabs.add(trans.get("edtmotorconfdlg.lbl.Motortab"), motorConfigurationPanel); - //// Recovery tab recoveryConfigurationPanel = new RecoveryConfigurationPanel(this, rocket); tabs.add(trans.get("edtmotorconfdlg.lbl.Recoverytab"), recoveryConfigurationPanel); @@ -122,6 +126,7 @@ public class FlightConfigurationDialog extends JDialog { tabs.add(trans.get("edtmotorconfdlg.lbl.Stagetab"), separationConfigurationPanel); } + //// Close button JButton close = new JButton(trans.get("dlg.but.close")); close.addActionListener(new ActionListener() { @@ -168,7 +173,6 @@ public class FlightConfigurationDialog extends JDialog { currentID = rocket.newFlightConfigurationID(); rocket.getDefaultConfiguration().setFlightConfigurationID(currentID); motorConfigurationPanel.fireTableDataChanged(); - flightConfigurationModel.fireContentsUpdated(); recoveryConfigurationPanel.fireTableDataChanged(); separationConfigurationPanel.fireTableDataChanged(); updateButtonState(); @@ -185,7 +189,6 @@ public class FlightConfigurationDialog extends JDialog { // Copy the name. this.changeConfigurationName(oldName); motorConfigurationPanel.fireTableDataChanged(); - flightConfigurationModel.fireContentsUpdated(); recoveryConfigurationPanel.fireTableDataChanged(); separationConfigurationPanel.fireTableDataChanged(); updateButtonState(); @@ -193,7 +196,6 @@ public class FlightConfigurationDialog extends JDialog { public void changeConfigurationName(String newName) { rocket.setFlightConfigurationName(currentID, newName); - flightConfigurationModel.fireContentsUpdated(); } public void removeConfiguration() { @@ -202,7 +204,6 @@ public class FlightConfigurationDialog extends JDialog { rocket.removeFlightConfigurationID(currentID); rocket.getDefaultConfiguration().setFlightConfigurationID(null); motorConfigurationPanel.fireTableDataChanged(); - flightConfigurationModel.fireContentsUpdated(); recoveryConfigurationPanel.fireTableDataChanged(); separationConfigurationPanel.fireTableDataChanged(); updateButtonState(); @@ -212,7 +213,6 @@ public class FlightConfigurationDialog extends JDialog { * Call this from other panels when a change might cause the names of the configurations to change. */ public void fireContentsUpdated() { - flightConfigurationModel.fireContentsUpdated(); } private void updateButtonState() { diff --git a/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/FlightConfigurationModel.java b/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/FlightConfigurationModel.java deleted file mode 100644 index cb2bd7a94..000000000 --- a/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/FlightConfigurationModel.java +++ /dev/null @@ -1,98 +0,0 @@ -package net.sf.openrocket.gui.dialogs.flightconfiguration; - -import java.util.HashMap; -import java.util.Map; - -import javax.swing.DefaultComboBoxModel; - -import net.sf.openrocket.rocketcomponent.Configuration; -import net.sf.openrocket.rocketcomponent.Rocket; - -public class FlightConfigurationModel extends DefaultComboBoxModel { - - private final Configuration config; - private final Rocket rocket; - - private Map map = new HashMap(); - - private final FlightConfigurationDialog flightConfigurationDialog; - - public FlightConfigurationModel(FlightConfigurationDialog flightConfigurationDialog, Configuration config) { - this.flightConfigurationDialog = flightConfigurationDialog; - this.config = config; - this.rocket = config.getRocket(); - } - - void fireContentsUpdated() { - fireContentsChanged(this, 0, rocket.getFlightConfigurationIDs().length); - } - - @Override - public Object getElementAt(int index) { - String[] ids = rocket.getFlightConfigurationIDs(); - if (index < 0 || index >= ids.length) - return null; - - return get(ids[index]); - } - - @Override - public int getSize() { - return rocket.getFlightConfigurationIDs().length; - } - - @Override - public Object getSelectedItem() { - return get(config.getFlightConfigurationID()); - } - - @Override - public void setSelectedItem(Object item) { - if (item == null) { - // Clear selection - huh? - return; - } - if (!(item instanceof ID)) { - throw new IllegalArgumentException("MotorConfigurationModel item="+item); - } - - ID idObject = (ID) item; - flightConfigurationDialog.selectConfiguration(idObject.getID()); - } - - /* - * The ID class is an adapter, that contains the actual configuration ID, - * but gives the configuration description as its String representation. - * The get(id) method retrieves ID objects and caches them for reuse. - */ - - private ID get(String id) { - ID idObject = map.get(id); - if (idObject != null) - return idObject; - - idObject = new ID(id); - map.put(id, idObject); - return idObject; - } - - - private class ID { - private final String id; - - public ID(String id) { - this.id = id; - } - - public String getID() { - return id; - } - - @Override - public String toString() { - return rocket.getFlightConfigurationNameOrDescription(id); - } - } - -} - diff --git a/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/IgnitionSelectionDialog.java b/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/IgnitionSelectionDialog.java new file mode 100644 index 000000000..c0fd12e45 --- /dev/null +++ b/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/IgnitionSelectionDialog.java @@ -0,0 +1,107 @@ +package net.sf.openrocket.gui.dialogs.flightconfiguration; + +import java.awt.Dialog; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.ButtonGroup; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.JSpinner; + +import net.miginfocom.swing.MigLayout; +import net.sf.openrocket.gui.SpinnerEditor; +import net.sf.openrocket.gui.adaptors.DoubleModel; +import net.sf.openrocket.gui.adaptors.EnumModel; +import net.sf.openrocket.gui.util.GUIUtil; +import net.sf.openrocket.l10n.Translator; +import net.sf.openrocket.rocketcomponent.IgnitionConfiguration; +import net.sf.openrocket.rocketcomponent.IgnitionConfiguration.IgnitionEvent; +import net.sf.openrocket.rocketcomponent.MotorMount; +import net.sf.openrocket.rocketcomponent.Rocket; +import net.sf.openrocket.startup.Application; +import net.sf.openrocket.unit.UnitGroup; + +public class IgnitionSelectionDialog extends JDialog { + + private static final Translator trans = Application.getTranslator(); + + + private IgnitionConfiguration newConfiguration; + + IgnitionSelectionDialog(JDialog parent, final Rocket rocket, final MotorMount component) { + super(parent, trans.get("edtmotorconfdlg.title.Selectignitionconf"), Dialog.ModalityType.APPLICATION_MODAL); + final String id = rocket.getDefaultConfiguration().getFlightConfigurationID(); + + newConfiguration = component.getIgnitionConfiguration().get(id).clone(); + + JPanel panel = new JPanel(new MigLayout("fill")); + + panel.add(new JLabel(trans.get("IgnitionSelectionDialog.opt.title")), "span, wrap rel"); + final JRadioButton defaultButton = new JRadioButton(trans.get("IgnitionSelectionDialog.opt.default"), true); + panel.add(defaultButton, "span, gapleft para, wrap rel"); + String str = trans.get("IgnitionSelectionDialog.opt.override"); + str = str.replace("{0}", rocket.getFlightConfigurationNameOrDescription(id)); + final JRadioButton overrideButton = new JRadioButton(str, false); + panel.add(overrideButton, "span, gapleft para, wrap para"); + + ButtonGroup buttonGroup = new ButtonGroup(); + buttonGroup.add(defaultButton); + buttonGroup.add(overrideButton); + + // Select ignition event + //// Ignition at: + panel.add(new JLabel(trans.get("MotorCfg.lbl.Ignitionat")), ""); + + final JComboBox event = new JComboBox(new EnumModel(newConfiguration, "IgnitionEvent")); + panel.add(event, "growx, wrap"); + + // ... and delay + //// plus + panel.add(new JLabel(trans.get("MotorCfg.lbl.plus")), "gap indent, skip 1, span, split"); + + DoubleModel delay = new DoubleModel(newConfiguration, "IgnitionDelay", UnitGroup.UNITS_SHORT_TIME, 0); + JSpinner spin = new JSpinner(delay.getSpinnerModel()); + spin.setEditor(new SpinnerEditor(spin, 3)); + panel.add(spin, "gap rel rel"); + + //// seconds + panel.add(new JLabel(trans.get("MotorCfg.lbl.seconds")), "wrap unrel"); + + + panel.add(new JPanel(), "span, split, growx"); + + JButton okButton = new JButton(trans.get("button.ok")); + okButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (defaultButton.isSelected()) { + component.getIgnitionConfiguration().setDefault(newConfiguration); + } else { + component.getIgnitionConfiguration().set(id, newConfiguration); + } + IgnitionSelectionDialog.this.setVisible(false); + } + }); + + panel.add(okButton, "sizegroup btn"); + + JButton cancel = new JButton(trans.get("button.cancel")); + cancel.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + IgnitionSelectionDialog.this.setVisible(false); + } + }); + + panel.add(cancel, "sizegroup btn"); + + this.setContentPane(panel); + + GUIUtil.setDisposableDialogOptions(this, okButton); + } +} diff --git a/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/MotorConfigurationPanel.java b/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/MotorConfigurationPanel.java index 5308d06b9..4ce43ffc6 100644 --- a/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/MotorConfigurationPanel.java +++ b/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/MotorConfigurationPanel.java @@ -22,6 +22,7 @@ import net.sf.openrocket.gui.dialogs.motor.MotorChooserDialog; import net.sf.openrocket.gui.util.GUIUtil; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.motor.Motor; +import net.sf.openrocket.rocketcomponent.MotorConfiguration; import net.sf.openrocket.rocketcomponent.MotorMount; import net.sf.openrocket.rocketcomponent.Rocket; import net.sf.openrocket.rocketcomponent.RocketComponent; @@ -87,6 +88,7 @@ public class MotorConfigurationPanel extends JPanel { public void mouseClicked(MouseEvent e) { updateButtonState(); if (e.getClickCount() == 2) { + // FIXME: Double-click on ignition column should select ignition // Double-click edits motor selectMotor(); } @@ -177,23 +179,27 @@ public class MotorConfigurationPanel extends JPanel { } private void selectMotor() { - String currentID = rocket.getDefaultConfiguration().getFlightConfigurationID(); - MotorMount currentMount = getCurrentMount(); - if (currentID == null || currentMount == null) + String id = rocket.getDefaultConfiguration().getFlightConfigurationID(); + MotorMount mount = getCurrentMount(); + if (id == null || mount == null) return; + MotorConfiguration config = mount.getMotorConfiguration().get(id); + MotorChooserDialog dialog = new MotorChooserDialog( - currentMount.getMotor(currentID), - currentMount.getMotorDelay(currentID), - currentMount.getMotorMountDiameter(), + config.getMotor(), + config.getEjectionDelay(), + mount.getMotorMountDiameter(), flightConfigurationDialog); dialog.setVisible(true); Motor m = dialog.getSelectedMotor(); double d = dialog.getSelectedDelay(); if (m != null) { - currentMount.setMotor(currentID, m); - currentMount.setMotorDelay(currentID, d); + config = new MotorConfiguration(); + config.setMotor(m); + config.setEjectionDelay(d); + mount.getMotorConfiguration().set(id, config); } flightConfigurationDialog.fireContentsUpdated(); @@ -202,12 +208,12 @@ public class MotorConfigurationPanel extends JPanel { } private void removeMotor() { - String currentID = rocket.getDefaultConfiguration().getFlightConfigurationID(); - MotorMount currentMount = getCurrentMount(); - if (currentID == null || currentMount == null) + String id = rocket.getDefaultConfiguration().getFlightConfigurationID(); + MotorMount mount = getCurrentMount(); + if (id == null || mount == null) return; - currentMount.setMotor(currentID, null); + mount.getMotorConfiguration().resetDefault(id); flightConfigurationDialog.fireContentsUpdated(); configurationTableModel.fireTableDataChanged(); @@ -220,7 +226,7 @@ public class MotorConfigurationPanel extends JPanel { if (currentID == null || currentMount == null) return; - SelectIgnitionConfigDialog dialog = new SelectIgnitionConfigDialog( + IgnitionSelectionDialog dialog = new IgnitionSelectionDialog( this.flightConfigurationDialog, rocket, currentMount); diff --git a/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/MotorConfigurationTableModel.java b/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/MotorConfigurationTableModel.java index 10919d939..ce900e72f 100644 --- a/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/MotorConfigurationTableModel.java +++ b/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/MotorConfigurationTableModel.java @@ -19,12 +19,12 @@ import net.sf.openrocket.util.Coordinate; */ class MotorConfigurationTableModel extends AbstractTableModel { - private Translator trans = Application.getTranslator(); + private static final Translator trans = Application.getTranslator(); - private final static String NONE = FlightConfigurationDialog.trans.get("edtmotorconfdlg.tbl.None"); - private final static String MOTOR_MOUNT = FlightConfigurationDialog.trans.get("edtmotorconfdlg.tbl.Mountheader"); - private final static String MOTOR = FlightConfigurationDialog.trans.get("edtmotorconfdlg.tbl.Motorheader"); - private final static String IGNITION = FlightConfigurationDialog.trans.get("edtmotorconfdlg.tbl.Ignitionheader"); + private static final String NONE = trans.get("edtmotorconfdlg.tbl.None"); + private static final String MOTOR_MOUNT = trans.get("edtmotorconfdlg.tbl.Mountheader"); + private static final String MOTOR = trans.get("edtmotorconfdlg.tbl.Motorheader"); + private static final String IGNITION = trans.get("edtmotorconfdlg.tbl.Ignitionheader"); private final Rocket rocket; @@ -63,13 +63,14 @@ class MotorConfigurationTableModel extends AbstractTableModel { } case 1: { MotorMount mount = findMount(row); - String currentID = rocket.getDefaultConfiguration().getFlightConfigurationID(); - Motor motor = mount.getMotor(currentID); + String id = rocket.getDefaultConfiguration().getFlightConfigurationID(); + MotorConfiguration config = mount.getMotorConfiguration().get(id); + Motor motor = config.getMotor(); if (motor == null) return NONE; - String str = motor.getDesignation(mount.getMotorDelay(currentID)); + String str = motor.getDesignation(config.getEjectionDelay()); int count = getMountMultiplicity(mount); if (count > 1) { str = "" + count + Chars.TIMES + " " + str; @@ -124,26 +125,16 @@ class MotorConfigurationTableModel extends AbstractTableModel { private String getIgnitionEventString(int row) { - String currentID = rocket.getDefaultConfiguration().getFlightConfigurationID(); + String id = rocket.getDefaultConfiguration().getFlightConfigurationID(); MotorMount mount = findMount(row); - MotorConfiguration motorConfig = mount.getFlightConfiguration(currentID); - if (motorConfig == null) { - return NONE; - } + IgnitionConfiguration ignitionConfig = mount.getIgnitionConfiguration().get(id); - IgnitionConfiguration.IgnitionEvent ignition = motorConfig.getIgnitionEvent(); - Double ignitionDelay = motorConfig.getIgnitionDelay(); - boolean isDefault = (ignition == null); + IgnitionConfiguration.IgnitionEvent ignitionEvent = ignitionConfig.getIgnitionEvent(); + Double ignitionDelay = ignitionConfig.getIgnitionDelay(); + boolean isDefault = mount.getIgnitionConfiguration().isDefault(id); - if (ignition == null) { - ignition = mount.getDefaultIgnitionEvent(); - } - if (ignitionDelay == null) { - ignitionDelay = mount.getDefaultIgnitionDelay(); - } - - String str = trans.get("MotorMount.IgnitionEvent.short." + ignition.name()); - if (ignitionDelay > 0) { + String str = trans.get("MotorMount.IgnitionEvent.short." + ignitionEvent.name()); + if (ignitionDelay > 0.001) { str = str + " + " + UnitGroup.UNITS_SHORT_TIME.toStringUnit(ignitionDelay); } if (isDefault) { diff --git a/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/RecoveryConfigurationPanel.java b/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/RecoveryConfigurationPanel.java index c313da3e5..939ca1029 100644 --- a/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/RecoveryConfigurationPanel.java +++ b/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/RecoveryConfigurationPanel.java @@ -15,60 +15,57 @@ import javax.swing.ListSelectionModel; import javax.swing.table.AbstractTableModel; import net.miginfocom.swing.MigLayout; +import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.rocketcomponent.DeploymentConfiguration; +import net.sf.openrocket.rocketcomponent.DeploymentConfiguration.DeployEvent; import net.sf.openrocket.rocketcomponent.RecoveryDevice; import net.sf.openrocket.rocketcomponent.Rocket; import net.sf.openrocket.rocketcomponent.RocketComponent; +import net.sf.openrocket.startup.Application; +import net.sf.openrocket.unit.UnitGroup; public class RecoveryConfigurationPanel extends JPanel { - + + private Translator trans = Application.getTranslator(); + + private final FlightConfigurationDialog flightConfigurationDialog; private final Rocket rocket; private final RecoveryTableModel recoveryTableModel; + private final JTable recoveryTable; private final JButton selectDeploymentButton; private final JButton resetDeploymentButton; - private RecoveryDevice selectedComponent; - - RecoveryConfigurationPanel( FlightConfigurationDialog flightConfigurationDialog, Rocket rocket ) { - super( new MigLayout("fill") ); + + RecoveryConfigurationPanel(FlightConfigurationDialog flightConfigurationDialog, Rocket rocket) { + super(new MigLayout("fill")); this.flightConfigurationDialog = flightConfigurationDialog; this.rocket = rocket; - + //// Recovery selection recoveryTableModel = new RecoveryTableModel(); - JTable table = new JTable( recoveryTableModel ); - table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - table.setRowSelectionAllowed(true); - table.addMouseListener(new MouseAdapter() { + recoveryTable = new JTable(recoveryTableModel); + recoveryTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + recoveryTable.setRowSelectionAllowed(true); + recoveryTable.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { JTable table = (JTable) e.getComponent(); - int row = table.getSelectedRow(); - - if ( row >= 0 ) { - selectedComponent = findRecoveryDevice(row); - } else { - selectedComponent = null; - } - - if (e.getClickCount() == 1) { - // Single click updates selection - updateButtonState(); - } else if (e.getClickCount() == 2) { + updateButtonState(); + + if (e.getClickCount() == 2) { // Double-click edits selectDeployment(); } - } }); - - JScrollPane scroll = new JScrollPane(table); + + JScrollPane scroll = new JScrollPane(recoveryTable); this.add(scroll, "span, grow, wrap"); - + //// Select deployment - selectDeploymentButton = new JButton(FlightConfigurationDialog.trans.get("edtmotorconfdlg.but.Selectdeployment")); + selectDeploymentButton = new JButton(trans.get("edtmotorconfdlg.but.Selectdeployment")); selectDeploymentButton.setEnabled(false); selectDeploymentButton.addActionListener(new ActionListener() { @Override @@ -77,9 +74,9 @@ public class RecoveryConfigurationPanel extends JPanel { } }); this.add(selectDeploymentButton, "skip, split, sizegroup button"); - + //// Reset deployment - resetDeploymentButton = new JButton(FlightConfigurationDialog.trans.get("edtmotorconfdlg.but.Resetdeployment")); + resetDeploymentButton = new JButton(trans.get("edtmotorconfdlg.but.Resetdeployment")); resetDeploymentButton.setEnabled(false); resetDeploymentButton.addActionListener(new ActionListener() { @Override @@ -87,100 +84,127 @@ public class RecoveryConfigurationPanel extends JPanel { resetDeployment(); } }); - this.add(resetDeploymentButton,"sizegroup button, wrap"); - + this.add(resetDeploymentButton, "sizegroup button, wrap"); } public void fireTableDataChanged() { - selectedComponent = null; recoveryTableModel.fireTableDataChanged(); updateButtonState(); } private void selectDeployment() { - JDialog d = new SelectDeploymentConfigDialog( flightConfigurationDialog, rocket, selectedComponent ); + RecoveryDevice c = getSelectedComponent(); + if (c == null) { + return; + } + JDialog d = new DeploymentSelectionDialog(flightConfigurationDialog, rocket, c); d.setVisible(true); fireTableDataChanged(); } private void resetDeployment() { - selectedComponent.setFlightConfiguration(rocket.getDefaultConfiguration().getFlightConfigurationID(), null); + RecoveryDevice c = getSelectedComponent(); + if (c == null) { + return; + } + String id = rocket.getDefaultConfiguration().getFlightConfigurationID(); + c.getDeploymentConfiguration().resetDefault(id); fireTableDataChanged(); } public void updateButtonState() { - boolean componentSelected = selectedComponent != null; - boolean isDefaulted = true; - if ( componentSelected ) { - isDefaulted = selectedComponent.getFlightConfiguration(rocket.getDefaultConfiguration().getFlightConfigurationID()) == null; - } + boolean componentSelected = getSelectedComponent() != null; selectDeploymentButton.setEnabled(componentSelected); - resetDeploymentButton.setEnabled(componentSelected & ! isDefaulted); + resetDeploymentButton.setEnabled(componentSelected); } - private RecoveryDevice findRecoveryDevice( int count ) { + + private RecoveryDevice getSelectedComponent() { + int row = recoveryTable.getSelectedRow(); + return findRecoveryDevice(row); + } + + private RecoveryDevice findRecoveryDevice(int count) { RecoveryDevice d = null; Iterator it = rocket.iterator(); - while( it.hasNext() && count >= 0 ) { + while (it.hasNext() && count >= 0) { RocketComponent c = it.next(); - if ( c instanceof RecoveryDevice ) { + if (c instanceof RecoveryDevice) { d = (RecoveryDevice) c; count--; } } return d; } - + + + private class RecoveryTableModel extends AbstractTableModel { - + @Override public int getRowCount() { int count = 0; Iterator it = rocket.iterator(); - while( it.hasNext() ) { + while (it.hasNext()) { RocketComponent c = it.next(); - if ( c instanceof RecoveryDevice ) { - count ++; + if (c instanceof RecoveryDevice) { + count++; } } return count; } - + @Override public int getColumnCount() { return 2; } - + @Override public Object getValueAt(int rowIndex, int columnIndex) { - RecoveryDevice d = RecoveryConfigurationPanel.this.findRecoveryDevice(rowIndex); - switch ( columnIndex ) { + RecoveryDevice d = findRecoveryDevice(rowIndex); + switch (columnIndex) { case 0: return d.getName(); case 1: - DeploymentConfiguration deployConfig = d.getFlightConfiguration(rocket.getDefaultConfiguration().getFlightConfigurationID()); - if ( deployConfig == null ) { - return "[" + d.getDefaultFlightConfiguration().toString() + "]"; - } else { - return deployConfig.toString(); + String id = rocket.getDefaultConfiguration().getFlightConfigurationID(); + DeploymentConfiguration config = d.getDeploymentConfiguration().get(id); + boolean isDefault = d.getDeploymentConfiguration().isDefault(id); + + String str; + + str = trans.get("RecoveryDevice.DeployEvent.short." + config.getDeployEvent().name()); + if (config.getDeployEvent() == DeployEvent.ALTITUDE) { + str += " " + UnitGroup.UNITS_DISTANCE.toStringUnit(config.getDeployAltitude()); } + if (config.getDeployDelay() > 0.001) { + str += " + " + UnitGroup.UNITS_SHORT_TIME.toStringUnit(config.getDeployDelay()); + } + + + if (isDefault) { + String def = trans.get("table.deployment.default"); + str = def.replace("{0}", str); + } + return str; + + default: + throw new IndexOutOfBoundsException("columnIndex=" + columnIndex); } - return null; } - + @Override public String getColumnName(int column) { - switch ( column ) { + switch (column) { case 0: - return FlightConfigurationDialog.trans.get("edtmotorconfdlg.tbl.Recoveryheader"); + return trans.get("edtmotorconfdlg.tbl.Recoveryheader"); case 1: - return FlightConfigurationDialog.trans.get("edtmotorconfdlg.tbl.Deploymentheader"); + return trans.get("edtmotorconfdlg.tbl.Deploymentheader"); default: return ""; } } - + } - + } diff --git a/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/RenameConfigDialog.java b/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/RenameConfigDialog.java index 16b56e0f9..df2845118 100644 --- a/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/RenameConfigDialog.java +++ b/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/RenameConfigDialog.java @@ -10,23 +10,27 @@ import javax.swing.JPanel; import javax.swing.JTextArea; import net.miginfocom.swing.MigLayout; +import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.rocketcomponent.Configuration; import net.sf.openrocket.rocketcomponent.Rocket; +import net.sf.openrocket.startup.Application; public class RenameConfigDialog extends JDialog { - RenameConfigDialog( final Rocket rocket, final FlightConfigurationDialog parent ) { - super(parent, FlightConfigurationDialog.trans.get("edtmotorconfdlg.title.Renameconf"),Dialog.ModalityType.APPLICATION_MODAL); + private static final Translator trans = Application.getTranslator(); + + RenameConfigDialog(final FlightConfigurationDialog parent, final Rocket rocket) { + super(parent, trans.get("edtmotorconfdlg.title.Renameconf"), Dialog.ModalityType.APPLICATION_MODAL); final Configuration config = rocket.getDefaultConfiguration(); JPanel panel = new JPanel(new MigLayout("fill")); - final JTextArea textbox = new JTextArea( config.getFlightConfigurationDescription() ); + final JTextArea textbox = new JTextArea(config.getFlightConfigurationDescription()); panel.add(textbox, "span, w 200lp, wrap"); JButton okButton = new JButton("Ok"); - okButton.addActionListener( new ActionListener() { - + okButton.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { parent.changeConfigurationName(textbox.getText()); @@ -35,11 +39,11 @@ public class RenameConfigDialog extends JDialog { }); - panel.add( okButton ); + panel.add(okButton); JButton defaultButton = new JButton("Reset to default"); - defaultButton.addActionListener( new ActionListener() { - + defaultButton.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { parent.changeConfigurationName(null); @@ -48,11 +52,11 @@ public class RenameConfigDialog extends JDialog { }); - panel.add( defaultButton ); + panel.add(defaultButton); JButton cancel = new JButton("Cancel"); - cancel.addActionListener( new ActionListener() { - + cancel.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { RenameConfigDialog.this.setVisible(false); @@ -60,13 +64,13 @@ public class RenameConfigDialog extends JDialog { }); - panel.add( cancel ); - + panel.add(cancel); + this.setContentPane(panel); this.validate(); this.pack(); this.setLocationByPlatform(true); - + } - + } diff --git a/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/SelectDeploymentConfigDialog.java b/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/SelectDeploymentConfigDialog.java deleted file mode 100644 index cb754c156..000000000 --- a/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/SelectDeploymentConfigDialog.java +++ /dev/null @@ -1,145 +0,0 @@ -package net.sf.openrocket.gui.dialogs.flightconfiguration; - -import java.awt.Dialog; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -import javax.swing.JButton; -import javax.swing.JComboBox; -import javax.swing.JDialog; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JSpinner; - -import net.miginfocom.swing.MigLayout; -import net.sf.openrocket.gui.SpinnerEditor; -import net.sf.openrocket.gui.adaptors.BasicEnumModel; -import net.sf.openrocket.gui.adaptors.DoubleModel; -import net.sf.openrocket.gui.components.BasicSlider; -import net.sf.openrocket.gui.components.UnitSelector; -import net.sf.openrocket.rocketcomponent.DeploymentConfiguration; -import net.sf.openrocket.rocketcomponent.DeploymentConfiguration.DeployEvent; -import net.sf.openrocket.rocketcomponent.RecoveryDevice; -import net.sf.openrocket.rocketcomponent.Rocket; -import net.sf.openrocket.unit.UnitGroup; - -public class SelectDeploymentConfigDialog extends JDialog { - - DeploymentConfiguration newConfiguration; - - - SelectDeploymentConfigDialog( JDialog parent, final Rocket rocket, final RecoveryDevice component ) { - super(parent, FlightConfigurationDialog.trans.get("edtmotorconfdlg.title.Selectdeploymentconf"),Dialog.ModalityType.APPLICATION_MODAL); - - final String configId = rocket.getDefaultConfiguration().getFlightConfigurationID(); - - newConfiguration = component.getFlightConfiguration(configId); - if ( newConfiguration == null ) { - newConfiguration = component.getDefaultFlightConfiguration().clone(); - } else { - // Clone the existing so cancel works. When the user selects OK, this configuration - // is put back in there. - newConfiguration = newConfiguration.clone(); - } - - JPanel panel = new JPanel(new MigLayout("fill")); - - //// Deployment - //// Deploys at: - panel.add(new JLabel(FlightConfigurationDialog.trans.get("ParachuteCfg.lbl.Deploysat")), ""); - - final JComboBox event = new JComboBox(new BasicEnumModel(DeployEvent.class)); - event.setSelectedItem( newConfiguration.getDeployEvent() ); - panel.add(event, "spanx 3, growx, wrap"); - - // ... and delay - //// plus - panel.add(new JLabel(FlightConfigurationDialog.trans.get("ParachuteCfg.lbl.plusdelay")), "right"); - - final DoubleModel delay = new DoubleModel(newConfiguration.getDeployDelay(), UnitGroup.UNITS_NONE, 0); - final JSpinner delaySpinner = new JSpinner( delay.getSpinnerModel() ); - delaySpinner.setEditor(new SpinnerEditor(delaySpinner,3)); - panel.add(delaySpinner, "spanx, split"); - - //// seconds - panel.add(new JLabel(FlightConfigurationDialog.trans.get("ParachuteCfg.lbl.seconds")), "wrap paragraph"); - - // Altitude: - JLabel label = new JLabel(FlightConfigurationDialog.trans.get("ParachuteCfg.lbl.Altitude")); - panel.add(label); - - final DoubleModel alt = new DoubleModel(newConfiguration.getDeployAltitude(), UnitGroup.UNITS_DISTANCE, 0); - - final JSpinner altSpinner = new JSpinner(alt.getSpinnerModel()); - altSpinner.setEditor(new SpinnerEditor(altSpinner)); - panel.add(altSpinner, "growx"); - UnitSelector unit = new UnitSelector(alt); - panel.add(unit, "growx"); - BasicSlider slider = new BasicSlider(alt.getSliderModel(100, 1000)); - panel.add(slider, "w 100lp, wrap"); - - event.addActionListener( new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - if ( event.getSelectedItem() == DeployEvent.ALTITUDE ) { - altSpinner.setEnabled(true); - } else { - altSpinner.setEnabled(false); - } - - } - - }); - - // Set the value of the combo box at the end to take advantage of the action listener above. - event.setSelectedItem( newConfiguration.getDeployEvent() ); - - JButton okButton = new JButton(FlightConfigurationDialog.trans.get("button.ok")); - okButton.addActionListener( new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - - //// extract deployment type; - DeployEvent deployEvent = (DeployEvent) event.getSelectedItem(); - newConfiguration.setDeployEvent(deployEvent); - - //// extract deployment time; - double deployDelay = delay.getValue(); - newConfiguration.setDeployDelay(deployDelay); - - //// extract altitude; - double deployAltitude = alt.getValue(); - newConfiguration.setDeployAltitude(deployAltitude); - - component.setFlightConfiguration(configId, newConfiguration); - - SelectDeploymentConfigDialog.this.setVisible(false); - } - - }); - - panel.add( okButton ); - - JButton cancel = new JButton(FlightConfigurationDialog.trans.get("button.cancel")); - cancel.addActionListener( new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - SelectDeploymentConfigDialog.this.setVisible(false); - } - - }); - - panel.add( cancel ); - - this.setContentPane(panel); - this.validate(); - this.pack(); - this.setLocationByPlatform(true); - - } - - -} diff --git a/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/SelectIgnitionConfigDialog.java b/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/SelectIgnitionConfigDialog.java deleted file mode 100644 index 94a4e23cd..000000000 --- a/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/SelectIgnitionConfigDialog.java +++ /dev/null @@ -1,116 +0,0 @@ -package net.sf.openrocket.gui.dialogs.flightconfiguration; - -import java.awt.Dialog; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -import javax.swing.JButton; -import javax.swing.JComboBox; -import javax.swing.JDialog; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JSpinner; - -import net.miginfocom.swing.MigLayout; -import net.sf.openrocket.gui.SpinnerEditor; -import net.sf.openrocket.gui.adaptors.BasicEnumModel; -import net.sf.openrocket.gui.adaptors.DoubleModel; -import net.sf.openrocket.rocketcomponent.IgnitionConfiguration; -import net.sf.openrocket.rocketcomponent.IgnitionConfiguration.IgnitionEvent; -import net.sf.openrocket.rocketcomponent.MotorConfiguration; -import net.sf.openrocket.rocketcomponent.MotorMount; -import net.sf.openrocket.rocketcomponent.Rocket; -import net.sf.openrocket.unit.UnitGroup; - -public class SelectIgnitionConfigDialog extends JDialog { - - MotorConfiguration newConfiguration; - - SelectIgnitionConfigDialog(JDialog parent, final Rocket rocket, final MotorMount component) { - super(parent, FlightConfigurationDialog.trans.get("edtmotorconfdlg.title.Selectignitionconf"), Dialog.ModalityType.APPLICATION_MODAL); - final String configId = rocket.getDefaultConfiguration().getFlightConfigurationID(); - - newConfiguration = component.getFlightConfiguration(configId); - if (newConfiguration == null) { - newConfiguration = component.getDefaultFlightConfiguration().clone(); - } else { - // Clone the existing so cancel works. When the user selects OK, this configuration - // is put back in there. - newConfiguration = newConfiguration.clone(); - } - // MotorConfiguration is a little wierd. It is possible for the MotorConfiguration - // to be non-null (for example, a motor is selected) but the ignition spec is null - // (ignition is not overridden). In order to accomodate this, we need to test - // for IgnitionEvent and copy from the default config. - if (newConfiguration.getIgnitionEvent() == null) { - MotorConfiguration oldConfig = component.getDefaultFlightConfiguration(); - newConfiguration.setIgnitionDelay(oldConfig.getIgnitionDelay()); - newConfiguration.setIgnitionEvent(oldConfig.getIgnitionEvent()); - } - - JPanel panel = new JPanel(new MigLayout("fill")); - - // Select ignition event - //// Ignition at: - panel.add(new JLabel(FlightConfigurationDialog.trans.get("MotorCfg.lbl.Ignitionat")), ""); - - final JComboBox event = new JComboBox(new BasicEnumModel(IgnitionConfiguration.IgnitionEvent.class)); - event.setSelectedItem(newConfiguration.getIgnitionEvent()); - panel.add(event, "growx, wrap"); - - // ... and delay - //// plus - panel.add(new JLabel(FlightConfigurationDialog.trans.get("MotorCfg.lbl.plus")), "gap indent, skip 1, span, split"); - - Double delayValue = newConfiguration.getIgnitionDelay(); - final DoubleModel delay = new DoubleModel((delayValue == null ? 0 : delayValue.doubleValue()), UnitGroup.UNITS_NONE, 0d); - JSpinner spin = new JSpinner(delay.getSpinnerModel()); - spin.setEditor(new SpinnerEditor(spin, 3)); - panel.add(spin, "gap rel rel"); - - //// seconds - panel.add(new JLabel(FlightConfigurationDialog.trans.get("MotorCfg.lbl.seconds")), "wrap unrel"); - - JButton okButton = new JButton(FlightConfigurationDialog.trans.get("button.ok")); - okButton.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - - //// extract ignition event type; - IgnitionConfiguration.IgnitionEvent ignitionEvent = (IgnitionConfiguration.IgnitionEvent) event.getSelectedItem(); - newConfiguration.setIgnitionEvent(ignitionEvent); - - //// extract ignition delay time; - double ignitionDelay = delay.getValue(); - newConfiguration.setIgnitionDelay(ignitionDelay); - - - component.setFlightConfiguration(configId, newConfiguration); - - SelectIgnitionConfigDialog.this.setVisible(false); - } - - }); - - panel.add(okButton); - - JButton cancel = new JButton(FlightConfigurationDialog.trans.get("button.cancel")); - cancel.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - SelectIgnitionConfigDialog.this.setVisible(false); - } - - }); - - panel.add(cancel); - - this.setContentPane(panel); - this.validate(); - this.pack(); - this.setLocationByPlatform(true); - - } -} diff --git a/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/SelectSeparationConfigDialog.java b/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/SelectSeparationConfigDialog.java deleted file mode 100644 index 1d761aa2c..000000000 --- a/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/SelectSeparationConfigDialog.java +++ /dev/null @@ -1,107 +0,0 @@ -package net.sf.openrocket.gui.dialogs.flightconfiguration; - -import java.awt.Dialog; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -import javax.swing.JButton; -import javax.swing.JComboBox; -import javax.swing.JDialog; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JSpinner; - -import net.miginfocom.swing.MigLayout; -import net.sf.openrocket.gui.SpinnerEditor; -import net.sf.openrocket.gui.adaptors.BasicEnumModel; -import net.sf.openrocket.gui.adaptors.DoubleModel; -import net.sf.openrocket.gui.components.StyledLabel; -import net.sf.openrocket.gui.components.StyledLabel.Style; -import net.sf.openrocket.rocketcomponent.Rocket; -import net.sf.openrocket.rocketcomponent.Stage; -import net.sf.openrocket.rocketcomponent.StageSeparationConfiguration; -import net.sf.openrocket.rocketcomponent.StageSeparationConfiguration.SeparationEvent; -import net.sf.openrocket.unit.UnitGroup; - -public class SelectSeparationConfigDialog extends JDialog { - - StageSeparationConfiguration newConfiguration; - - SelectSeparationConfigDialog( JDialog parent, final Rocket rocket, final Stage component ) { - super(parent, FlightConfigurationDialog.trans.get("edtmotorconfdlg.title.Selectseparationconf"),Dialog.ModalityType.APPLICATION_MODAL); - final String configId = rocket.getDefaultConfiguration().getFlightConfigurationID(); - - newConfiguration = component.getFlightConfiguration(configId); - if ( newConfiguration == null ) { - newConfiguration = component.getDefaultFlightConfiguration().clone(); - } else { - // Clone the existing so cancel works. When the user selects OK, this configuration - // is put back in there. - newConfiguration = newConfiguration.clone(); - } - - JPanel panel = new JPanel(new MigLayout("fill")); - - // Select separation event - panel.add(new StyledLabel(FlightConfigurationDialog.trans.get("StageConfig.separation.lbl.title"), Style.BOLD), "spanx, wrap rel"); - - final JComboBox event = new JComboBox(new BasicEnumModel(SeparationEvent.class)); - event.setSelectedItem( newConfiguration.getSeparationEvent() ); - panel.add(event, ""); - - // ... and delay - panel.add(new JLabel(FlightConfigurationDialog.trans.get("StageConfig.separation.lbl.plus")), ""); - - final DoubleModel delay = new DoubleModel(newConfiguration.getSeparationDelay(), UnitGroup.UNITS_NONE, 0); - JSpinner spin = new JSpinner(delay.getSpinnerModel()); - spin.setEditor(new SpinnerEditor(spin)); - panel.add(spin, "width 45"); - - //// seconds - panel.add(new JLabel(FlightConfigurationDialog.trans.get("StageConfig.separation.lbl.seconds")), "wrap unrel"); - - - JButton okButton = new JButton(FlightConfigurationDialog.trans.get("button.ok")); - okButton.addActionListener( new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - - //// extract event type; - SeparationEvent eventType = (SeparationEvent) event.getSelectedItem(); - newConfiguration.setSeparationEvent(eventType); - - //// extract delay time; - double separationDelay = delay.getValue(); - newConfiguration.setSeparationDelay(separationDelay); - - component.setFlightConfiguration(configId, newConfiguration); - - SelectSeparationConfigDialog.this.setVisible(false); - } - - }); - - panel.add( okButton ); - - JButton cancel = new JButton(FlightConfigurationDialog.trans.get("button.cancel")); - cancel.addActionListener( new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - SelectSeparationConfigDialog.this.setVisible(false); - } - - }); - - panel.add( cancel ); - - this.setContentPane(panel); - this.validate(); - this.pack(); - this.setLocationByPlatform(true); - - } - - -} diff --git a/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/SeparationConfigurationPanel.java b/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/SeparationConfigurationPanel.java index 4312e1e21..05be8b880 100644 --- a/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/SeparationConfigurationPanel.java +++ b/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/SeparationConfigurationPanel.java @@ -15,78 +15,74 @@ import javax.swing.ListSelectionModel; import javax.swing.table.AbstractTableModel; import net.miginfocom.swing.MigLayout; +import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.rocketcomponent.Rocket; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.rocketcomponent.Stage; import net.sf.openrocket.rocketcomponent.StageSeparationConfiguration; +import net.sf.openrocket.rocketcomponent.StageSeparationConfiguration.SeparationEvent; +import net.sf.openrocket.startup.Application; public class SeparationConfigurationPanel extends JPanel { - + + private static final Translator trans = Application.getTranslator(); + private final FlightConfigurationDialog flightConfigurationDialog; private final Rocket rocket; private final Stage[] stages; - + + private final JTable separationTable; private final SeparationTableModel separationTableModel; private final JButton selectSeparationButton; private final JButton resetDeploymentButton; - - private Stage selectedComponent; - - SeparationConfigurationPanel( FlightConfigurationDialog flightConfigurationDialog, Rocket rocket ) { - super( new MigLayout("fill") ); + + + SeparationConfigurationPanel(FlightConfigurationDialog flightConfigurationDialog, Rocket rocket) { + super(new MigLayout("fill")); this.flightConfigurationDialog = flightConfigurationDialog; this.rocket = rocket; - - int stageCount = rocket.getStageCount() -1; + + + int stageCount = rocket.getStageCount() - 1; stages = new Stage[stageCount]; Iterator it = rocket.iterator(); { int stageIndex = -1; - while( it.hasNext() ) { + while (it.hasNext()) { RocketComponent c = it.next(); - if ( c instanceof Stage ) { - if ( stageIndex >= 0 ){ + if (c instanceof Stage) { + if (stageIndex >= 0) { stages[stageIndex] = (Stage) c; } stageIndex++; } } } - + //// Recovery selection separationTableModel = new SeparationTableModel(); - JTable table = new JTable( separationTableModel ); - table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - table.setRowSelectionAllowed(true); - table.addMouseListener(new MouseAdapter() { + separationTable = new JTable(separationTableModel); + separationTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + separationTable.setRowSelectionAllowed(true); + separationTable.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { - JTable table = (JTable) e.getComponent(); - int row = table.getSelectedRow(); - int column = table.getSelectedColumn(); - - if ( row >= 0 ) { - selectedComponent = stages[row]; - } else { - selectedComponent = null; - } - if (e.getClickCount() == 1) { + // FIXME: Listen to selection change, not clicks // Single click updates selection updateButtonState(); } else if (e.getClickCount() == 2) { // Double-click edits selectDeployment(); } - } }); - - JScrollPane scroll = new JScrollPane(table); + + JScrollPane scroll = new JScrollPane(separationTable); this.add(scroll, "span, grow, wrap"); - + //// Select deployment - selectSeparationButton = new JButton(FlightConfigurationDialog.trans.get("edtmotorconfdlg.but.Selectseparation")); + selectSeparationButton = new JButton(trans.get("edtmotorconfdlg.but.Selectseparation")); selectSeparationButton.setEnabled(false); selectSeparationButton.addActionListener(new ActionListener() { @Override @@ -95,9 +91,9 @@ public class SeparationConfigurationPanel extends JPanel { } }); this.add(selectSeparationButton, "skip, split, sizegroup button"); - + //// Reset deployment - resetDeploymentButton = new JButton(FlightConfigurationDialog.trans.get("edtmotorconfdlg.but.Resetseparation")); + resetDeploymentButton = new JButton(trans.get("edtmotorconfdlg.but.Resetseparation")); resetDeploymentButton.setEnabled(false); resetDeploymentButton.addActionListener(new ActionListener() { @Override @@ -105,79 +101,100 @@ public class SeparationConfigurationPanel extends JPanel { resetDeployment(); } }); - this.add(resetDeploymentButton,"sizegroup button, wrap"); - + this.add(resetDeploymentButton, "sizegroup button, wrap"); + } - + public void fireTableDataChanged() { - selectedComponent = null; separationTableModel.fireTableDataChanged(); updateButtonState(); } - + + private Stage getSelectedStage() { + int row = separationTable.getSelectedRow(); + if (row >= 0 && row < stages.length) { + return stages[row]; + } + return null; + } + private void selectDeployment() { - JDialog d = new SelectSeparationConfigDialog( flightConfigurationDialog, rocket, selectedComponent ); + Stage stage = getSelectedStage(); + if (stage == null) { + return; + } + JDialog d = new SeparationSelectionDialog(flightConfigurationDialog, rocket, stage); d.setVisible(true); fireTableDataChanged(); } - + private void resetDeployment() { - selectedComponent.setFlightConfiguration(rocket.getDefaultConfiguration().getFlightConfigurationID(), null); + Stage stage = getSelectedStage(); + if (stage == null) { + return; + } + String id = rocket.getDefaultConfiguration().getFlightConfigurationID(); + stage.getStageSeparationConfiguration().resetDefault(id); fireTableDataChanged(); } - + public void updateButtonState() { - boolean componentSelected = selectedComponent != null; - boolean isDefaulted = true; - if ( componentSelected ) { - isDefaulted = selectedComponent.getFlightConfiguration(rocket.getDefaultConfiguration().getFlightConfigurationID()) == null; - } + boolean componentSelected = getSelectedStage() != null; selectSeparationButton.setEnabled(componentSelected); - resetDeploymentButton.setEnabled(componentSelected & ! isDefaulted); + resetDeploymentButton.setEnabled(componentSelected); } - + private class SeparationTableModel extends AbstractTableModel { - + @Override public int getRowCount() { return stages.length; } - + @Override public int getColumnCount() { return 2; } - + @Override public Object getValueAt(int rowIndex, int columnIndex) { Stage d = SeparationConfigurationPanel.this.stages[rowIndex]; - switch ( columnIndex ) { + switch (columnIndex) { case 0: return d.getName(); case 1: - StageSeparationConfiguration separationConfig = d.getFlightConfiguration(rocket.getDefaultConfiguration().getFlightConfigurationID()); - if ( separationConfig == null ) { - return "[" + d.getDefaultFlightConfiguration().toString() + "]"; + String id = rocket.getDefaultConfiguration().getFlightConfigurationID(); + StageSeparationConfiguration separationConfig = d.getStageSeparationConfiguration().get(id); + + SeparationEvent event = separationConfig.getSeparationEvent(); + String str = event.toString(); + + if (d.getStageSeparationConfiguration().isDefault(id)) { + str = trans.get("SeparationConfigurationPanel.table.separation.default"); + str = str.replace("{0}", event.toString()); } else { - return separationConfig.toString(); + str = event.toString(); } + return str; + + default: + throw new IndexOutOfBoundsException("column=" + columnIndex); } - - return null; + } - + @Override public String getColumnName(int column) { - switch ( column ) { + switch (column) { case 0: - return FlightConfigurationDialog.trans.get("edtmotorconfdlg.tbl.Stageheader"); + return trans.get("edtmotorconfdlg.tbl.Stageheader"); case 1: - return FlightConfigurationDialog.trans.get("edtmotorconfdlg.tbl.Separationheader"); + return trans.get("edtmotorconfdlg.tbl.Separationheader"); default: return ""; } } - + } - + } diff --git a/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/SeparationSelectionDialog.java b/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/SeparationSelectionDialog.java new file mode 100644 index 000000000..daf6afddb --- /dev/null +++ b/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/SeparationSelectionDialog.java @@ -0,0 +1,91 @@ +package net.sf.openrocket.gui.dialogs.flightconfiguration; + +import java.awt.Dialog; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSpinner; + +import net.miginfocom.swing.MigLayout; +import net.sf.openrocket.gui.SpinnerEditor; +import net.sf.openrocket.gui.adaptors.DoubleModel; +import net.sf.openrocket.gui.adaptors.EnumModel; +import net.sf.openrocket.gui.util.GUIUtil; +import net.sf.openrocket.l10n.Translator; +import net.sf.openrocket.rocketcomponent.Rocket; +import net.sf.openrocket.rocketcomponent.Stage; +import net.sf.openrocket.rocketcomponent.StageSeparationConfiguration; +import net.sf.openrocket.rocketcomponent.StageSeparationConfiguration.SeparationEvent; +import net.sf.openrocket.startup.Application; +import net.sf.openrocket.unit.UnitGroup; + +public class SeparationSelectionDialog extends JDialog { + + private static final Translator trans = Application.getTranslator(); + + private StageSeparationConfiguration newConfiguration; + + SeparationSelectionDialog(JDialog parent, final Rocket rocket, final Stage component) { + super(parent, trans.get("edtmotorconfdlg.title.Selectseparationconf"), Dialog.ModalityType.APPLICATION_MODAL); + final String id = rocket.getDefaultConfiguration().getFlightConfigurationID(); + + newConfiguration = component.getStageSeparationConfiguration().get(id).clone(); + + + JPanel panel = new JPanel(new MigLayout("fill")); + + // FIXME: Edit Default or override option + + // Select separation event + panel.add(new JLabel(trans.get("SeparationSelectionDialog.lbl.separation")), ""); + + final JComboBox event = new JComboBox(new EnumModel(newConfiguration, "SeparationEvent")); + event.setSelectedItem(newConfiguration.getSeparationEvent()); + panel.add(event, "wrap rel"); + + // ... and delay + panel.add(new JLabel(trans.get("StageConfig.separation.lbl.plus")), "alignx 100%"); + + final DoubleModel delay = new DoubleModel(newConfiguration, "SeparationDelay", UnitGroup.UNITS_SHORT_TIME, 0); + JSpinner spin = new JSpinner(delay.getSpinnerModel()); + spin.setEditor(new SpinnerEditor(spin, 3)); + panel.add(spin, "span, split"); + + //// seconds + panel.add(new JLabel(trans.get("StageConfig.separation.lbl.seconds")), "wrap para"); + + + panel.add(new JPanel(), "span, split, growx"); + + JButton okButton = new JButton(trans.get("button.ok")); + okButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + component.getStageSeparationConfiguration().set(id, newConfiguration); + SeparationSelectionDialog.this.setVisible(false); + } + }); + + panel.add(okButton, "sizegroup btn"); + + JButton cancel = new JButton(trans.get("button.cancel")); + cancel.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + SeparationSelectionDialog.this.setVisible(false); + } + }); + + panel.add(cancel, "sizegroup btn"); + + this.setContentPane(panel); + + GUIUtil.setDisposableDialogOptions(this, okButton); + } + +} diff --git a/core/src/net/sf/openrocket/gui/dialogs/optimization/SimulationModifierTree.java b/core/src/net/sf/openrocket/gui/dialogs/optimization/SimulationModifierTree.java index 663c79b83..c18c98060 100644 --- a/core/src/net/sf/openrocket/gui/dialogs/optimization/SimulationModifierTree.java +++ b/core/src/net/sf/openrocket/gui/dialogs/optimization/SimulationModifierTree.java @@ -119,8 +119,8 @@ public class SimulationModifierTree extends BasicTree { } - - + + public class ComponentModifierTreeRenderer extends DefaultTreeCellRenderer { private Font componentFont; private Font stringFont; @@ -142,7 +142,7 @@ public class SimulationModifierTree extends BasicTree { makeFonts(); } - + // Customize based on line type Object object = ((DefaultMutableTreeNode) value).getUserObject(); @@ -150,7 +150,7 @@ public class SimulationModifierTree extends BasicTree { // Set icon (for rocket components, null for others) setIcon(ComponentIcons.getSmallIcon(object.getClass())); - + // Set text color/style if (object instanceof RocketComponent) { setForeground(Color.GRAY); @@ -160,7 +160,7 @@ public class SimulationModifierTree extends BasicTree { RocketComponent c = (RocketComponent) object; String comment = c.getComment().trim(); if (comment.length() > 0) { - comment = TextUtil.htmlEncode(comment); + comment = TextUtil.escapeXML(comment); comment = "" + comment.replace("\n", "
"); this.setToolTipText(comment); } else { diff --git a/core/src/net/sf/openrocket/gui/main/componenttree/ComponentTreeRenderer.java b/core/src/net/sf/openrocket/gui/main/componenttree/ComponentTreeRenderer.java index 6fe9fe1d9..de9982b58 100644 --- a/core/src/net/sf/openrocket/gui/main/componenttree/ComponentTreeRenderer.java +++ b/core/src/net/sf/openrocket/gui/main/componenttree/ComponentTreeRenderer.java @@ -48,7 +48,7 @@ public class ComponentTreeRenderer extends DefaultTreeCellRenderer { String comment = c.getComment().trim(); if (comment.length() > 0) { - comment = TextUtil.htmlEncode(comment); + comment = TextUtil.escapeXML(comment); comment = comment.replace("\n", "
"); sb.append("
").append(comment); } diff --git a/core/src/net/sf/openrocket/optimization/services/DefaultSimulationModifierService.java b/core/src/net/sf/openrocket/optimization/services/DefaultSimulationModifierService.java index 9a1f2405f..a04a3c1b1 100644 --- a/core/src/net/sf/openrocket/optimization/services/DefaultSimulationModifierService.java +++ b/core/src/net/sf/openrocket/optimization/services/DefaultSimulationModifierService.java @@ -14,7 +14,6 @@ import net.sf.openrocket.optimization.general.OptimizationException; import net.sf.openrocket.optimization.rocketoptimization.SimulationModifier; import net.sf.openrocket.optimization.rocketoptimization.modifiers.GenericComponentModifier; import net.sf.openrocket.rocketcomponent.BodyTube; -import net.sf.openrocket.rocketcomponent.DeploymentConfiguration.DeployEvent; import net.sf.openrocket.rocketcomponent.EllipticalFinSet; import net.sf.openrocket.rocketcomponent.FinSet; import net.sf.openrocket.rocketcomponent.FreeformFinSet; @@ -24,7 +23,6 @@ import net.sf.openrocket.rocketcomponent.MassComponent; import net.sf.openrocket.rocketcomponent.MotorMount; import net.sf.openrocket.rocketcomponent.NoseCone; import net.sf.openrocket.rocketcomponent.Parachute; -import net.sf.openrocket.rocketcomponent.RecoveryDevice; import net.sf.openrocket.rocketcomponent.Rocket; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.rocketcomponent.Streamer; @@ -243,29 +241,31 @@ public class DefaultSimulationModifierService implements SimulationModifierServi } + // FIXME: Reimplement for flight-configuration controlled modifiers + // Recovery device deployment altitude and delay - if (c instanceof RecoveryDevice) { - RecoveryDevice device = (RecoveryDevice) c; - - SimulationModifier mod = new GenericComponentModifier( - trans.get("optimization.modifier.recoverydevice.deployDelay"), - trans.get("optimization.modifier.recoverydevice.deployDelay.desc"), - c, UnitGroup.UNITS_SHORT_TIME, - 1.0, c.getClass(), c.getID(), "DefaultDeployDelay"); - mod.setMinValue(0); - mod.setMaxValue(10); - modifiers.add(mod); - - if (device.getDefaultDeployEvent() == DeployEvent.ALTITUDE) { - mod = new GenericComponentModifier( - trans.get("optimization.modifier.recoverydevice.deployAltitude"), - trans.get("optimization.modifier.recoverydevice.deployAltitude.desc"), - c, UnitGroup.UNITS_DISTANCE, - 1.0, c.getClass(), c.getID(), "DefaultDeployAltitude"); - setDefaultMinMax(mod, simulation); - modifiers.add(mod); - } - } + // if (c instanceof RecoveryDevice) { + // RecoveryDevice device = (RecoveryDevice) c; + // + // SimulationModifier mod = new GenericComponentModifier( + // trans.get("optimization.modifier.recoverydevice.deployDelay"), + // trans.get("optimization.modifier.recoverydevice.deployDelay.desc"), + // c, UnitGroup.UNITS_SHORT_TIME, + // 1.0, c.getClass(), c.getID(), "DefaultDeployDelay"); + // mod.setMinValue(0); + // mod.setMaxValue(10); + // modifiers.add(mod); + // + // if (device.getDefaultDeployEvent() == DeployEvent.ALTITUDE) { + // mod = new GenericComponentModifier( + // trans.get("optimization.modifier.recoverydevice.deployAltitude"), + // trans.get("optimization.modifier.recoverydevice.deployAltitude.desc"), + // c, UnitGroup.UNITS_DISTANCE, + // 1.0, c.getClass(), c.getID(), "DefaultDeployAltitude"); + // setDefaultMinMax(mod, simulation); + // modifiers.add(mod); + // } + // } // Conditional shape parameter of Transition diff --git a/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java b/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java index c983b80d7..ccfc387f8 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java +++ b/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java @@ -38,7 +38,7 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial this.outerRadius = DEFAULT_RADIUS; this.autoRadius = true; - this.motorConfigurations = new FlightConfigurationImpl(this, ComponentChangeEvent.MOTOR_CHANGE, new MotorConfiguration()); + this.motorConfigurations = new MotorFlightConfigurationImpl(this, ComponentChangeEvent.MOTOR_CHANGE, MotorConfiguration.NO_MOTORS); this.ignitionConfigurations = new FlightConfigurationImpl(this, ComponentChangeEvent.EVENT_CHANGE, new IgnitionConfiguration()); } diff --git a/core/src/net/sf/openrocket/rocketcomponent/IgnitionConfiguration.java b/core/src/net/sf/openrocket/rocketcomponent/IgnitionConfiguration.java index 9dda39175..984c18059 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/IgnitionConfiguration.java +++ b/core/src/net/sf/openrocket/rocketcomponent/IgnitionConfiguration.java @@ -9,7 +9,7 @@ import net.sf.openrocket.util.StateChangeListener; public class IgnitionConfiguration implements FlightConfigurableParameter { - public static enum IgnitionEvent { + public enum IgnitionEvent { //// Automatic (launch or ejection charge) AUTOMATIC("MotorMount.IgnitionEvent.AUTOMATIC") { @Override @@ -104,11 +104,11 @@ public class IgnitionConfiguration implements FlightConfigurableParameter(this, ComponentChangeEvent.MOTOR_CHANGE, new MotorConfiguration()); + this.motorConfigurations = new MotorFlightConfigurationImpl(this, ComponentChangeEvent.MOTOR_CHANGE, MotorConfiguration.NO_MOTORS); this.ignitionConfigurations = new FlightConfigurationImpl(this, ComponentChangeEvent.EVENT_CHANGE, new IgnitionConfiguration()); } diff --git a/core/src/net/sf/openrocket/rocketcomponent/MotorConfiguration.java b/core/src/net/sf/openrocket/rocketcomponent/MotorConfiguration.java index 1e22a9fca..b04e82ca3 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/MotorConfiguration.java +++ b/core/src/net/sf/openrocket/rocketcomponent/MotorConfiguration.java @@ -15,6 +15,19 @@ import net.sf.openrocket.util.Utils; */ public class MotorConfiguration implements FlightConfigurableParameter { + /** Immutable configuration with no motor and zero delay. */ + public static final MotorConfiguration NO_MOTORS = new MotorConfiguration() { + @Override + public void setMotor(Motor motor) { + throw new UnsupportedOperationException("Trying to modify immutable no-motors configuration"); + }; + + @Override + public void setEjectionDelay(double delay) { + throw new UnsupportedOperationException("Trying to modify immutable no-motors configuration"); + }; + }; + private final List listeners = new ArrayList(); private Motor motor; diff --git a/core/src/net/sf/openrocket/rocketcomponent/MotorFlightConfigurationImpl.java b/core/src/net/sf/openrocket/rocketcomponent/MotorFlightConfigurationImpl.java new file mode 100644 index 000000000..8be3a841a --- /dev/null +++ b/core/src/net/sf/openrocket/rocketcomponent/MotorFlightConfigurationImpl.java @@ -0,0 +1,18 @@ +package net.sf.openrocket.rocketcomponent; + +/** + * FlightConfiguration implementation that prevents changing the default value. + * This is used for motors, where the default value is always no motor. + */ +public class MotorFlightConfigurationImpl> extends FlightConfigurationImpl { + + public MotorFlightConfigurationImpl(RocketComponent component, int eventType, E defaultValue) { + super(component, eventType, defaultValue); + } + + @Override + public void setDefault(E value) { + throw new UnsupportedOperationException("Cannot change default value of motor configuration"); + } + +} diff --git a/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java b/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java index cfd569196..e8aeaff3b 100644 --- a/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java +++ b/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java @@ -243,7 +243,7 @@ public class BasicEventSimulationEngine implements SimulationEngine { Coordinate position = positions[i]; MotorId id = new MotorId(component.getID(), i + 1); motors.addMotor(id, motor.getInstance(), motorConfig.getEjectionDelay(), mount, - ignitionConfig.getIgnitionEvent(), ignitionConfig.getDelay(), position); + ignitionConfig.getIgnitionEvent(), ignitionConfig.getIgnitionDelay(), position); } } } diff --git a/core/src/net/sf/openrocket/util/Reflection.java b/core/src/net/sf/openrocket/util/Reflection.java index b3c66f62b..a5e39d282 100644 --- a/core/src/net/sf/openrocket/util/Reflection.java +++ b/core/src/net/sf/openrocket/util/Reflection.java @@ -2,14 +2,13 @@ package net.sf.openrocket.util; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; import net.sf.openrocket.rocketcomponent.RocketComponent; public class Reflection { - private static final String ROCKETCOMPONENT_PACKAGE = "net.sf.openrocket.rocketcomponent"; - /** * Simple wrapper class that converts the Method.invoke() exceptions into suitable * RuntimeExceptions. @@ -88,25 +87,24 @@ public class Reflection { } - + /** - * Find a method from the rocket component classes. + * Find a method from a class. * Throws an exception if method not found. */ - public static Reflection.Method findMethod( - Class componentClass, - String method, Class... params) { - Reflection.Method m = findMethod(ROCKETCOMPONENT_PACKAGE, componentClass, - "", method, params); - if (m == null) { - throw new BugException("Could not find method for componentClass=" - + componentClass + " method=" + method); + public static Reflection.Method findMethod(Class c, String method, Class... params) { + + java.lang.reflect.Method m; + try { + m = c.getMethod(method, params); + return new Reflection.Method(m); + } catch (NoSuchMethodException e) { + throw new BugException("Could not find method " + method + "(" + Arrays.toString(params) + ") from class " + c); } - return m; } - + public static Reflection.Method findMethod(String pack, RocketComponent component, String method, Class... params) { return findMethod(pack, component.getClass(), "", method, params); diff --git a/core/src/net/sf/openrocket/util/TextUtil.java b/core/src/net/sf/openrocket/util/TextUtil.java index a3d6b1ee8..41d7a2692 100644 --- a/core/src/net/sf/openrocket/util/TextUtil.java +++ b/core/src/net/sf/openrocket/util/TextUtil.java @@ -42,9 +42,9 @@ public class TextUtil { } /** - * Return a string of the double value with suitable precision (5 digits). - * The string is the shortest representation of the value including the - * required precision. + * Return a string of the double value with suitable precision for storage. + * The string is the shortest representation of the value including at least + * 5 digits of precision. * * @param d the value to present. * @return a representation with suitable precision. @@ -172,26 +172,42 @@ public class TextUtil { return sb.toString(); } - - public static String htmlEncode(String s) { - s = s.replace("&", "&"); - s = s.replace("\"", """); - s = s.replace("<", "<"); - s = s.replace(">", ">"); - return s; - } - - /* - * Returns a word-wrapped version of given input string using HTML syntax, wrapped to len characters. + /** + * Escape a string as XML or HTML. Encodes the following characters: + *
    + *
  • less than, greater than + *
  • quotation mark, apostrophe + *
  • ampersand + *
  • all control characters except newline, carriage return and tab + *
+ * + * The result is both valid XML and HTML 2.0. The majority of characters are left unchanged. */ - public static String wrap(String in, int len) { - in = in.trim(); - if (in.length() < len) - return in; - if (in.substring(0, len).contains("\n")) - return in.substring(0, in.indexOf("\n")).trim() + "\n\n" + wrap(in.substring(in.indexOf("\n") + 1), len); - int place = Math.max(Math.max(in.lastIndexOf(" ", len), in.lastIndexOf("\t", len)), in.lastIndexOf("-", len)); - return "" + in.substring(0, place).trim() + "
" + wrap(in.substring(place), len); + public static String escapeXML(String s) { + StringBuilder sb = new StringBuilder(s.length()); + + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + + if (c == '&') { + sb.append("&"); + } else if (c == '<') { + sb.append("<"); + } else if (c == '>') { + sb.append(">"); + } else if (c == '"') { + sb.append("""); + } else if (((c < 32) && (c != '\t') && (c != '\n') && (c != '\r')) || (c == '\'') || (c == 127)) { + // ' is not used since it's not standard HTML, use numerical escape instead + sb.append("&#").append((int) c).append(';'); + } else { + sb.append(c); + } + } + + return sb.toString(); } + + } diff --git a/core/test/net/sf/openrocket/util/TextUtilTest.java b/core/test/net/sf/openrocket/util/TextUtilTest.java index a408b3c38..e3b2558a3 100644 --- a/core/test/net/sf/openrocket/util/TextUtilTest.java +++ b/core/test/net/sf/openrocket/util/TextUtilTest.java @@ -278,4 +278,15 @@ public class TextUtilTest { } } + + @Test + public void testEscapeXML() { + assertEquals("", TextUtil.escapeXML("")); + assertEquals("foo&bar", TextUtil.escapeXML("foo&bar")); + assertEquals("<html>&", TextUtil.escapeXML("&")); + assertEquals(""'", TextUtil.escapeXML("\"'")); + assertEquals("foo\n\r\tbar", TextUtil.escapeXML("foo\n\r\tbar")); + assertEquals("foo�bar", TextUtil.escapeXML("foo" + ((char) 0) + ((char) 1) + ((char) 31) + ((char) 127) + "bar")); + } + }