Data model refactoring

This commit is contained in:
Sampo Niskanen 2013-03-01 08:41:47 +02:00
parent 4c48ec48c9
commit 170ce13c05
46 changed files with 1085 additions and 1034 deletions

View File

@ -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 = <b>Select the motors and motor ignition events of your rocket.</b><br> <em>Motor mounts:</em> Select which components function as motor mounts.<br> <em>Motor configurations:</em> Select the motor and ignition event for each motor mount.

View File

@ -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
}

View File

@ -40,7 +40,7 @@ public class GeneralRocketSaver {
*
* @param progress int value between 0 and 100 representing percent complete.
*/
public void setProgress( int progress );
public void setProgress(int progress);
}
@ -64,7 +64,7 @@ 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);
}
/**
@ -75,8 +75,8 @@ 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);
}
/**
@ -88,19 +88,19 @@ 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);
@ -111,17 +111,17 @@ public class GeneralRocketSaver {
// 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,19 +137,19 @@ 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;
@ -158,12 +158,12 @@ public class GeneralRocketSaver {
Set<DecalImage> usedDecals = new TreeSet<DecalImage>();
// 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;
}
@ -172,10 +172,10 @@ public class GeneralRocketSaver {
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<DecalImage> decals) throws IOException {
public void saveAllPartsZipFile(OutputStream output, OpenRocketDocument document, StorageOptions options, Set<DecalImage> decals) throws IOException {
// Open a zip stream to write to.
ZipOutputStream zos = new ZipOutputStream(output);
@ -184,14 +184,14 @@ public class GeneralRocketSaver {
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);
@ -200,7 +200,7 @@ public class GeneralRocketSaver {
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();
@ -219,7 +219,7 @@ public class GeneralRocketSaver {
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);
@ -232,7 +232,7 @@ public class GeneralRocketSaver {
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;
@ -262,8 +262,8 @@ public class GeneralRocketSaver {
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);

View File

@ -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("&", "&amp;");
s = s.replace("<", "&lt;");
s = s.replace(">", "&gt;");
s = s.replace("\"","&quot;");
s = s.replace("'", "&apos;");
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;
}
}

View File

@ -354,7 +354,7 @@ public class OpenRocketSaver extends RocketSaver {
writeln("<simulation status=\"" + enumToXMLName(simulation.getStatus()) + "\">");
indent++;
writeln("<name>" + escapeXML(simulation.getName()) + "</name>");
writeln("<name>" + TextUtil.escapeXML(simulation.getName()) + "</name>");
// TODO: MEDIUM: Other simulators/calculators
writeln("<simulator>RK4Simulator</simulator>");
@ -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 <databranch> tag
StringBuilder sb = new StringBuilder();
sb.append("<databranch name=\"");
sb.append(escapeXML(branch.getBranchName()));
sb.append(TextUtil.escapeXML(branch.getBranchName()));
// Kevins version where typekeys are used
/*
@ -487,7 +487,7 @@ public class OpenRocketSaver extends RocketSaver {
for (int i = 0; i < types.length; i++) {
if (i > 0)
sb.append(",");
sb.append(escapeXML(types[i].getName()));
sb.append(TextUtil.escapeXML(types[i].getName()));
}
sb.append("\">");
writeln(sb.toString());

View File

@ -15,12 +15,29 @@ 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 final RecoveryDevice recoveryDevice;
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
@ -35,19 +52,18 @@ class DeploymentConfigurationHandler extends AbstractElementHandler {
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);
@ -57,7 +73,8 @@ class DeploymentConfigurationHandler extends AbstractElementHandler {
@Override
public void endHandler(String element, HashMap<String, String> 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));
}
}

View File

@ -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<DeployEvent>(
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<StageSeparationConfiguration.SeparationEvent>(
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)));
}

View File

@ -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<String, String> 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);
}

View File

@ -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<T extends Enum<T>> implements Setter {
private final Reflection.Method configurationGetter;
private final Reflection.Method setter;
private final Class<T> enumClass;
public EnumSetter(Reflection.Method set, Class<T> enumClass) {
this.setter = set;
public EnumSetter(Reflection.Method setter, Class<T> enumClass) {
this(null, setter, enumClass);
}
public EnumSetter(Method configurationGetter, Method setter, Class<T> enumClass) {
this.configurationGetter = configurationGetter;
this.setter = setter;
this.enumClass = enumClass;
}
@ -27,6 +35,12 @@ class EnumSetter<T extends Enum<T>> 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);
}
}
}

View File

@ -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<String, String> 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;

View File

@ -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;
}

View File

@ -16,13 +16,27 @@ 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<String, String> attributes, WarningSet warnings)
throws SAXException {
@ -35,16 +49,15 @@ class StageSeparationConfigurationHandler extends AbstractElementHandler {
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);
@ -54,7 +67,8 @@ class StageSeparationConfigurationHandler extends AbstractElementHandler {
@Override
public void endHandler(String element, HashMap<String, String> 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));
}
}

View File

@ -21,37 +21,38 @@ public class RecoveryDeviceSaver extends MassObjectSaver {
elements.add("<cd>auto</cd>");
else
elements.add("<cd>" + dev.getCD() + "</cd>");
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 ) {
if (configs.length > 1) {
for( String id : configs ) {
if ( id == null ) {
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("<deploymentconfiguration configid=\"" + id + "\">");
elements.addAll( deploymentConfiguration(config, true) );
elements.addAll(deploymentConfiguration(config, true));
elements.add("</deploymentconfiguration>");
}
}
}
private List<String> deploymentConfiguration( DeploymentConfiguration config, boolean indent ) {
private List<String> deploymentConfiguration(DeploymentConfiguration config, boolean indent) {
List<String> elements = new ArrayList<String>(3);
elements.add((indent?" ": "") + "<deployevent>" + config.getDeployEvent().name().toLowerCase(Locale.ENGLISH).replace("_", "") + "</deployevent>");
elements.add((indent?" ": "") + "<deployaltitude>" + config.getDeployAltitude() + "</deployaltitude>");
elements.add((indent?" ": "") + "<deploydelay>" + config.getDeployDelay() + "</deploydelay>");
elements.add((indent ? " " : "") + "<deployevent>" + config.getDeployEvent().name().toLowerCase(Locale.ENGLISH).replace("_", "") + "</deployevent>");
elements.add((indent ? " " : "") + "<deployaltitude>" + config.getDeployAltitude() + "</deployaltitude>");
elements.add((indent ? " " : "") + "<deploydelay>" + config.getDeployDelay() + "</deploydelay>");
return elements;
}

View File

@ -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<String> elements) {
elements.add("<name>" + RocketSaver.escapeXML(c.getName()) + "</name>");
elements.add("<name>" + TextUtil.escapeXML(c.getName()) + "</name>");
ComponentPreset preset = c.getPresetComponent();
if (preset != null) {
@ -104,7 +105,7 @@ public class RocketComponentSaver {
// Comment
if (c.getComment().length() > 0) {
elements.add("<comment>" + RocketSaver.escapeXML(c.getComment()) + "</comment>");
elements.add("<comment>" + TextUtil.escapeXML(c.getComment()) + "</comment>");
}
}
@ -136,7 +137,7 @@ public class RocketComponentSaver {
String baseName = trans.getBaseText("material", mat.getName());
return str + " density=\"" + mat.getDensity() + "\">" + RocketSaver.escapeXML(baseName) + "</" + tag + ">";
return str + " density=\"" + mat.getDensity() + "\">" + TextUtil.escapeXML(baseName) + "</" + tag + ">";
}
@ -148,11 +149,15 @@ public class RocketComponentSaver {
elements.add("<motormount>");
// NOTE: Default config must be BEFORE overridden config for proper backward compatibility later on
elements.add(" <ignitionevent>"
+ mount.getIgnitionConfiguration().getDefault().getIgnitionEvent().name().toLowerCase(Locale.ENGLISH).replace("_", "")
+ "</ignitionevent>");
elements.add(" <ignitiondelay>" + mount.getIgnitionConfiguration().getDefault().getIgnitionDelay() + "</ignitiondelay>");
elements.add(" <overhang>" + mount.getMotorOverhang() + "</overhang>");
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(" <manufacturer>" + RocketSaver.escapeXML(m.getManufacturer().getSimpleName()) +
elements.add(" <manufacturer>" + TextUtil.escapeXML(m.getManufacturer().getSimpleName()) +
"</manufacturer>");
elements.add(" <digest>" + m.getDigest() + "</digest>");
}
elements.add(" <designation>" + RocketSaver.escapeXML(motor.getDesignation()) + "</designation>");
elements.add(" <designation>" + TextUtil.escapeXML(motor.getDesignation()) + "</designation>");
elements.add(" <diameter>" + motor.getDiameter() + "</diameter>");
elements.add(" <length>" + motor.getLength() + "</length>");
@ -181,27 +186,16 @@ public class RocketComponentSaver {
elements.add(" </motor>");
if (motorConfig.getIgnitionEvent() != null || motorConfig.getIgnitionDelay() != null) {
if (!mount.getIgnitionConfiguration().isDefault(id)) {
IgnitionConfiguration ignition = mount.getIgnitionConfiguration().get(id);
elements.add(" <ignitionconfiguration configid=\"" + id + "\">");
if (motorConfig.getIgnitionEvent() != null) {
elements.add(" <ignitionevent>" + motorConfig.getIgnitionEvent().name().toLowerCase(Locale.ENGLISH).replace("_", "") + "</ignitionevent>");
}
if (motorConfig.getIgnitionDelay() != null) {
elements.add(" <ignitiondelay>" + motorConfig.getIgnitionDelay() + "</ignitiondelay>");
}
elements.add(" <ignitionevent>" + ignition.getIgnitionEvent().name().toLowerCase(Locale.ENGLISH).replace("_", "") + "</ignitionevent>");
elements.add(" <ignitiondelay>" + ignition.getIgnitionDelay() + "</ignitiondelay>");
elements.add(" </ignitionconfiguration>");
}
}
elements.add(" <ignitionevent>"
+ mount.getDefaultIgnitionEvent().name().toLowerCase(Locale.ENGLISH).replace("_", "")
+ "</ignitionevent>");
elements.add(" <ignitiondelay>" + mount.getDefaultIgnitionDelay() + "</ignitiondelay>");
elements.add(" <overhang>" + mount.getMotorOverhang() + "</overhang>");
elements.add("</motormount>");
return elements;

View File

@ -29,12 +29,12 @@ public class RocketSaver extends RocketComponentSaver {
if (rocket.getDesigner().length() > 0) {
elements.add("<designer>"
+ net.sf.openrocket.file.RocketSaver.escapeXML(rocket.getDesigner())
+ net.sf.openrocket.util.TextUtil.escapeXML(rocket.getDesigner())
+ "</designer>");
}
if (rocket.getRevision().length() > 0) {
elements.add("<revision>"
+ net.sf.openrocket.file.RocketSaver.escapeXML(rocket.getRevision())
+ net.sf.openrocket.util.TextUtil.escapeXML(rocket.getRevision())
+ "</revision>");
}
@ -52,7 +52,7 @@ public class RocketSaver extends RocketComponentSaver {
if (rocket.getFlightConfigurationName(id) == "") {
str += "/>";
} else {
str += "><name>" + net.sf.openrocket.file.RocketSaver.escapeXML(rocket.getFlightConfigurationName(id))
str += "><name>" + net.sf.openrocket.util.TextUtil.escapeXML(rocket.getFlightConfigurationName(id))
+ "</name></motorconfiguration>";
}
elements.add(str);

View File

@ -29,36 +29,37 @@ public class StageSaver extends ComponentAssemblySaver {
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 ) {
if (configs.length > 1) {
for( String id : configs ) {
if ( id == null ) {
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("<separationconfiguration configid=\"" + id + "\">");
elements.addAll( separationConfig(config, true) );
elements.addAll(separationConfig(config, true));
elements.add("</separationconfiguration>");
}
}
}
}
private List<String> separationConfig( StageSeparationConfiguration config, boolean indent ) {
private List<String> separationConfig(StageSeparationConfiguration config, boolean indent) {
List<String> elements = new ArrayList<String>(2);
elements.add((indent?" ":"")+ "<separationevent>"
elements.add((indent ? " " : "") + "<separationevent>"
+ config.getSeparationEvent().name().toLowerCase(Locale.ENGLISH).replace("_", "")
+ "</separationevent>");
elements.add((indent?" ":"")+ "<separationdelay>" + config.getSeparationDelay() + "</separationdelay>");
elements.add((indent ? " " : "") + "<separationdelay>" + config.getSeparationDelay() + "</separationdelay>");
return elements;
}

View File

@ -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;
}
}
}

View File

@ -1,48 +0,0 @@
package net.sf.openrocket.gui.adaptors;
import javax.swing.AbstractListModel;
import javax.swing.ComboBoxModel;
public class BasicEnumModel<T extends Enum<T>> extends AbstractListModel implements ComboBoxModel {
private final String nullText;
private final Enum<T>[] values;
private Enum<T> currentValue = null;
public BasicEnumModel( Class<? extends Enum<T>> clazz ) {
this(clazz, null);
}
@SuppressWarnings("unchecked")
public BasicEnumModel(Class<? extends Enum<T>> clazz, String nullText) {
this.values = clazz.getEnumConstants();
this.nullText = nullText;
}
@Override
public void setSelectedItem(Object anItem) {
currentValue = (Enum<T>) 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;
}
}

View File

@ -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");

View File

@ -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<StageSeparationConfiguration.SeparationEvent>(stage, "DefaultSeparationEvent"));
StageSeparationConfiguration config = stage.getStageSeparationConfiguration().getDefault();
JComboBox combo = new JComboBox(new EnumModel<StageSeparationConfiguration.SeparationEvent>(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");

View File

@ -26,7 +26,6 @@ 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 {
@ -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");
@ -149,10 +156,25 @@ public class OperatorSelector extends JDialog {
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 "<html>" + in.substring(0, place).trim() + "<br>" + wrap(in.substring(place), len);
}
}

View File

@ -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<DeployEvent>(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);
}
}

View File

@ -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() {

View File

@ -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<String, ID> map = new HashMap<String, ID>();
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);
}
}
}

View File

@ -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<IgnitionEvent>(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);
}
}

View File

@ -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);

View File

@ -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) {

View File

@ -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();
updateButtonState();
if ( row >= 0 ) {
selectedComponent = findRecoveryDevice(row);
} else {
selectedComponent = null;
}
if (e.getClickCount() == 1) {
// Single click updates selection
updateButtonState();
} else if (e.getClickCount() == 2) {
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
@ -79,7 +76,7 @@ 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,43 +84,52 @@ 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<RocketComponent> 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--;
}
@ -131,16 +137,18 @@ public class RecoveryConfigurationPanel extends JPanel {
return d;
}
private class RecoveryTableModel extends AbstractTableModel {
@Override
public int getRowCount() {
int count = 0;
Iterator<RocketComponent> 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;
@ -153,29 +161,45 @@ public class RecoveryConfigurationPanel extends JPanel {
@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 "";
}

View File

@ -10,22 +10,26 @@ 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) {
@ -35,10 +39,10 @@ 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) {
@ -48,10 +52,10 @@ 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) {
@ -60,7 +64,7 @@ public class RenameConfigDialog extends JDialog {
});
panel.add( cancel );
panel.add(cancel);
this.setContentPane(panel);
this.validate();

View File

@ -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>(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);
}
}

View File

@ -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>(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);
}
}

View File

@ -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>(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);
}
}

View File

@ -15,37 +15,43 @@ 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<RocketComponent> 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++;
@ -55,38 +61,28 @@ public class SeparationConfigurationPanel extends JPanel {
//// 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
@ -97,7 +93,7 @@ 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,35 +101,47 @@ 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 {
@ -151,28 +159,37 @@ public class SeparationConfigurationPanel extends JPanel {
@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 "";
}

View File

@ -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<SeparationEvent>(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);
}
}

View File

@ -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 = "<html>" + comment.replace("\n", "<br>");
this.setToolTipText(comment);
} else {

View File

@ -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", "<br>");
sb.append("<br>").append(comment);
}

View File

@ -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

View File

@ -38,7 +38,7 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial
this.outerRadius = DEFAULT_RADIUS;
this.autoRadius = true;
this.motorConfigurations = new FlightConfigurationImpl<MotorConfiguration>(this, ComponentChangeEvent.MOTOR_CHANGE, new MotorConfiguration());
this.motorConfigurations = new MotorFlightConfigurationImpl<MotorConfiguration>(this, ComponentChangeEvent.MOTOR_CHANGE, MotorConfiguration.NO_MOTORS);
this.ignitionConfigurations = new FlightConfigurationImpl<IgnitionConfiguration>(this, ComponentChangeEvent.EVENT_CHANGE, new IgnitionConfiguration());
}

View File

@ -9,7 +9,7 @@ import net.sf.openrocket.util.StateChangeListener;
public class IgnitionConfiguration implements FlightConfigurableParameter<IgnitionConfiguration> {
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<Igniti
}
public double getDelay() {
public double getIgnitionDelay() {
return delay;
}
public void setDelay(double delay) {
public void setIgnitionDelay(double delay) {
if (MathUtil.equals(delay, this.delay)) {
return;
}

View File

@ -40,7 +40,7 @@ public class InnerTube extends ThicknessRingComponent implements Clusterable, Ra
this.setInnerRadius(0.018 / 2);
this.setLength(0.070);
this.motorConfigurations = new FlightConfigurationImpl<MotorConfiguration>(this, ComponentChangeEvent.MOTOR_CHANGE, new MotorConfiguration());
this.motorConfigurations = new MotorFlightConfigurationImpl<MotorConfiguration>(this, ComponentChangeEvent.MOTOR_CHANGE, MotorConfiguration.NO_MOTORS);
this.ignitionConfigurations = new FlightConfigurationImpl<IgnitionConfiguration>(this, ComponentChangeEvent.EVENT_CHANGE, new IgnitionConfiguration());
}

View File

@ -15,6 +15,19 @@ import net.sf.openrocket.util.Utils;
*/
public class MotorConfiguration implements FlightConfigurableParameter<MotorConfiguration> {
/** 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<StateChangeListener> listeners = new ArrayList<StateChangeListener>();
private Motor motor;

View File

@ -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<E extends FlightConfigurableParameter<E>> extends FlightConfigurationImpl<E> {
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");
}
}

View File

@ -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);
}
}
}

View File

@ -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.
@ -90,19 +89,18 @@ 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<? extends RocketComponent> 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;
}

View File

@ -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("&", "&amp;");
s = s.replace("\"", "&quot;");
s = s.replace("<", "&lt;");
s = s.replace(">", "&gt;");
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:
* <ul>
* <li>less than, greater than
* <li>quotation mark, apostrophe
* <li>ampersand
* <li>all control characters except newline, carriage return and tab
* </ul>
*
* 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 "<html>" + in.substring(0, place).trim() + "<br>" + 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("&amp;");
} else if (c == '<') {
sb.append("&lt;");
} else if (c == '>') {
sb.append("&gt;");
} else if (c == '"') {
sb.append("&quot;");
} else if (((c < 32) && (c != '\t') && (c != '\n') && (c != '\r')) || (c == '\'') || (c == 127)) {
// &apos; 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();
}
}

View File

@ -278,4 +278,15 @@ public class TextUtilTest {
}
}
@Test
public void testEscapeXML() {
assertEquals("", TextUtil.escapeXML(""));
assertEquals("foo&amp;bar", TextUtil.escapeXML("foo&bar"));
assertEquals("&lt;html&gt;&amp;", TextUtil.escapeXML("<html>&"));
assertEquals("&quot;&#39;", TextUtil.escapeXML("\"'"));
assertEquals("foo\n\r\tbar", TextUtil.escapeXML("foo\n\r\tbar"));
assertEquals("foo&#0;&#1;&#31;&#127;bar", TextUtil.escapeXML("foo" + ((char) 0) + ((char) 1) + ((char) 31) + ((char) 127) + "bar"));
}
}