Add error & warning dialog for RASAero exporting

This commit is contained in:
SiboVG 2023-03-27 22:31:52 +02:00
parent c5a2fc44df
commit 9667466fdb
18 changed files with 342 additions and 73 deletions

View File

@ -89,7 +89,12 @@ BasicFrame.dlg.title = Design not saved
BasicFrame.StageName.Sustainer = Sustainer
BasicFrame.WarningDialog.txt1 = The following problems were encountered while opening
BasicFrame.WarningDialog.txt2 = Some design features may not have been loaded correctly.
BasicFrame.WarningDialog.saving.txt1 = The following problems were encountered while saving
BasicFrame.WarningDialog.saving.txt2 = Some design features may not have exported correctly.
BasicFrame.WarningDialog.title = Warnings while opening file
BasicFrame.WarningDialog.saving.title = Warnings while opening file
BasicFrame.ErrorWarningDialog.txt1 = <html>Please <b>correct the errors</b>.</html>
BasicFrame.ErrorWarningDialog.saving.title = Errors/Warnings while saving file
! General error messages used in multiple contexts

View File

@ -21,12 +21,16 @@ import net.sf.openrocket.document.StorageOptions.FileType;
import net.sf.openrocket.file.openrocket.OpenRocketSaver;
import net.sf.openrocket.file.rasaero.export.RASAeroSaver;
import net.sf.openrocket.file.rocksim.export.RockSimSaver;
import net.sf.openrocket.logging.ErrorSet;
import net.sf.openrocket.logging.WarningSet;
import net.sf.openrocket.rocketcomponent.InsideColorComponent;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.util.DecalNotFoundException;
import net.sf.openrocket.util.MathUtil;
public class GeneralRocketSaver {
protected final WarningSet warnings = new WarningSet();
protected final ErrorSet errors = new ErrorSet();
/**
* Interface which can be implemented by the caller to receive progress information.
@ -234,16 +238,34 @@ public class GeneralRocketSaver {
private void saveInternal(OutputStream output, OpenRocketDocument document, StorageOptions options)
throws IOException {
warnings.clear();
errors.clear();
if (options.getFileType() == FileType.ROCKSIM) {
new RockSimSaver().save(output, document, options);
new RockSimSaver().save(output, document, options, warnings, errors);
} else if (options.getFileType() == FileType.RASAERO) {
new RASAeroSaver().save(output, document, options);
new RASAeroSaver().save(output, document, options, warnings, errors);
} else {
new OpenRocketSaver().save(output, document, options);
new OpenRocketSaver().save(output, document, options, warnings, errors);
}
}
/**
* Return a list of warnings generated during the saving process.
* @return a list of warnings generated during the saving process
*/
public WarningSet getWarnings() {
return warnings;
}
/**
* Return a list of errors generated during the saving process.
* @return a list of errors generated during the saving process
*/
public ErrorSet getErrors() {
return errors;
}
private static class ProgressOutputStream extends FilterOutputStream {
private final long estimatedSize;

View File

@ -3,23 +3,24 @@ package net.sf.openrocket.file;
import java.io.IOException;
import java.io.OutputStream;
import net.sf.openrocket.logging.ErrorSet;
import net.sf.openrocket.logging.WarningSet;
import net.sf.openrocket.document.OpenRocketDocument;
import net.sf.openrocket.document.StorageOptions;
public abstract class RocketSaver {
protected final WarningSet warnings = new WarningSet();
/**
* Save the document to the specified output stream using the default storage options.
*
* @param dest the destination stream.
* @param doc the document to save.
* @param warnings list to store save warnings to
* @param errors list to store save errors to
* @throws IOException in case of an I/O error.
*/
public final void save(OutputStream dest, OpenRocketDocument doc) throws IOException {
save(dest, doc, doc.getDefaultStorageOptions());
public final void save(OutputStream dest, OpenRocketDocument doc, WarningSet warnings, ErrorSet errors) throws IOException {
save(dest, doc, doc.getDefaultStorageOptions(), warnings, errors);
}
/**
@ -28,9 +29,11 @@ public abstract class RocketSaver {
* @param dest the destination stream.
* @param doc the document to save.
* @param options the storage options.
* @param warnings list to store save warnings to
* @param errors list to store save errors to
* @throws IOException in case of an I/O error.
*/
public abstract void save(OutputStream dest, OpenRocketDocument doc, StorageOptions options) throws IOException;
public abstract void save(OutputStream dest, OpenRocketDocument doc, StorageOptions options, WarningSet warnings, ErrorSet errors) throws IOException;
/**
* Provide an estimate of the file size when saving the document with the

View File

@ -8,6 +8,8 @@ import java.io.Writer;
import java.util.*;
import net.sf.openrocket.file.openrocket.savers.PhotoStudioSaver;
import net.sf.openrocket.logging.ErrorSet;
import net.sf.openrocket.logging.WarningSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -60,7 +62,7 @@ public class OpenRocketSaver extends RocketSaver {
private Writer dest;
@Override
public void save(OutputStream output, OpenRocketDocument document, StorageOptions options) throws IOException {
public void save(OutputStream output, OpenRocketDocument document, StorageOptions options, WarningSet warnings, ErrorSet errors) throws IOException {
log.info("Saving .ork file");

View File

@ -2,6 +2,8 @@ package net.sf.openrocket.file.rasaero.export;
import net.sf.openrocket.file.rasaero.CustomDoubleAdapter;
import net.sf.openrocket.file.rasaero.RASAeroCommonConstants;
import net.sf.openrocket.logging.ErrorSet;
import net.sf.openrocket.logging.WarningSet;
import net.sf.openrocket.rocketcomponent.AxialStage;
import net.sf.openrocket.rocketcomponent.BodyTube;
import net.sf.openrocket.rocketcomponent.NoseCone;
@ -43,16 +45,24 @@ public class BasePartDTO {
@XmlTransient
private final RocketComponent component;
@XmlTransient
private final WarningSet warnings;
@XmlTransient
private final ErrorSet errors;
/**
* We need a default no-args constructor.
*/
public BasePartDTO() {
this.component = null;
this.warnings = null;
this.errors = null;
}
protected BasePartDTO(RocketComponent component) throws RASAeroExportException {
protected BasePartDTO(RocketComponent component, WarningSet warnings, ErrorSet errors) throws RASAeroExportException {
this.component = component;
this.warnings = warnings;
this.errors = errors;
if (component instanceof BodyTube) {
setPartType(RASAeroCommonConstants.BODY_TUBE);

View File

@ -2,6 +2,8 @@ package net.sf.openrocket.file.rasaero.export;
import net.sf.openrocket.file.rasaero.CustomDoubleAdapter;
import net.sf.openrocket.file.rasaero.RASAeroCommonConstants;
import net.sf.openrocket.logging.ErrorSet;
import net.sf.openrocket.logging.WarningSet;
import net.sf.openrocket.rocketcomponent.BodyTube;
import javax.xml.bind.annotation.XmlAccessType;
@ -9,6 +11,7 @@ import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import net.sf.openrocket.file.rasaero.export.RASAeroSaver.RASAeroExportException;
@ -49,14 +52,25 @@ public class BodyTubeDTO extends BasePartDTO implements BodyTubeDTOAdapter {
@XmlElementRef(name = RASAeroCommonConstants.FIN, type = FinDTO.class)
private FinDTO fin;
@XmlTransient
private final WarningSet warnings;
@XmlTransient
private final ErrorSet errors;
/**
* We need a default no-args constructor.
*/
public BodyTubeDTO() { }
public BodyTubeDTO() {
this.warnings = null;
this.errors = null;
}
public BodyTubeDTO(BodyTube bodyTube) throws RASAeroExportException {
super(bodyTube);
applyBodyTubeSettings(bodyTube);
public BodyTubeDTO(BodyTube bodyTube, WarningSet warnings, ErrorSet errors) throws RASAeroExportException {
super(bodyTube, warnings, errors);
this.warnings = warnings;
this.errors = errors;
applyBodyTubeSettings(bodyTube, warnings, errors);
}
public Double getLaunchLugDiameter() {

View File

@ -1,6 +1,8 @@
package net.sf.openrocket.file.rasaero.export;
import net.sf.openrocket.file.rasaero.RASAeroCommonConstants;
import net.sf.openrocket.logging.ErrorSet;
import net.sf.openrocket.logging.WarningSet;
import net.sf.openrocket.rocketcomponent.BodyTube;
import net.sf.openrocket.rocketcomponent.LaunchLug;
import net.sf.openrocket.rocketcomponent.RailButton;
@ -10,17 +12,17 @@ import net.sf.openrocket.util.MathUtil;
import net.sf.openrocket.file.rasaero.export.RASAeroSaver.RASAeroExportException;
public interface BodyTubeDTOAdapter {
default void applyBodyTubeSettings(BodyTube bodyTube) throws RASAeroExportException {
default void applyBodyTubeSettings(BodyTube bodyTube, WarningSet warnings, ErrorSet errors) throws RASAeroExportException {
for (RocketComponent child : bodyTube.getChildren()) {
if (child instanceof TrapezoidFinSet) {
setFin(new FinDTO((TrapezoidFinSet) child));
} else if (child instanceof LaunchLug) {
if (!MathUtil.equals(getRailGuideDiameter(), 0) || !MathUtil.equals(getRailGuideHeight(), 0)) { // only one check on diameter or length should be sufficient, but just to be safe
//TODO: warning.add(String.format("Already added a rail button, ignoring launch lug '%s'", child.getName());
warnings.add(String.format("Already added a rail button, ignoring launch lug '%s'", child.getName()));
continue;
}
if (!MathUtil.equals(getLaunchShoeArea(), 0)) {
//TODO: warning.add(String.format("Already added a launch shoe, ignoring launch lug '%s'", child.getName());
warnings.add(String.format("Already added a launch shoe, ignoring launch lug '%s'", child.getName()));
continue;
}
@ -29,17 +31,18 @@ public interface BodyTubeDTOAdapter {
if (lug.getInstanceCount() == 2) {
setLaunchLugLength(lug.getLength() * RASAeroCommonConstants.OPENROCKET_TO_RASAERO_LENGTH);
} else {
//TODO:warnings.add(String.format("Instance count of '%s' not set to 2, defaulting to 2 and adjusting
// launch lug length accordingly.", lug.getName()")
warnings.add(String.format(
"Instance count of '%s' not set to 2, defaulting to 2 and adjusting launch lug length accordingly.",
lug.getName()));
setLaunchLugLength(lug.getLength() * lug.getInstanceCount() / 2 * RASAeroCommonConstants.OPENROCKET_TO_RASAERO_LENGTH);
}
} else if (child instanceof RailButton) {
if (!MathUtil.equals(getLaunchLugDiameter(), 0) || !MathUtil.equals(getLaunchLugLength(), 0)) { // only one check on diameter or length should be sufficient, but just to be safe
// TODO: warning.add(String.format("Already added a launch lug, ignoring rail button '%s'", child.getName()));
warnings.add(String.format("Already added a launch lug, ignoring rail button '%s'", child.getName()));
continue;
}
if (!MathUtil.equals(getLaunchShoeArea(), 0)) {
// TODO: warning.add(String.format("Already added a launch shoe, ignoring rail button '%s'", child.getName()));
warnings.add(String.format("Already added a launch shoe, ignoring rail button '%s'", child.getName()));
continue;
}
@ -48,10 +51,11 @@ public interface BodyTubeDTOAdapter {
setRailGuideHeight(button.getTotalHeight() * RASAeroCommonConstants.OPENROCKET_TO_RASAERO_LENGTH);
if (button.getInstanceCount() != 2) {
//TODO: warnings.add(String.format("Instance count of '%s' equals %d, defaulting to 2", button.getName(), button.getInstanceCount()));
warnings.add(String.format("Instance count of '%s' equals %d, defaulting to 2",
button.getName(), button.getInstanceCount()));
}
} else {
// TODO: warnings.add(String.format("Unsupported component '%s', ignoring.", child.getComponentName()));
warnings.add(String.format("Unsupported component '%s', ignoring.", child.getComponentName()));
}
}
}

View File

@ -2,6 +2,8 @@ package net.sf.openrocket.file.rasaero.export;
import net.sf.openrocket.file.rasaero.CustomDoubleAdapter;
import net.sf.openrocket.file.rasaero.RASAeroCommonConstants;
import net.sf.openrocket.logging.ErrorSet;
import net.sf.openrocket.logging.WarningSet;
import net.sf.openrocket.rocketcomponent.AxialStage;
import net.sf.openrocket.rocketcomponent.BodyTube;
import net.sf.openrocket.rocketcomponent.NoseCone;
@ -13,6 +15,7 @@ import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import net.sf.openrocket.file.rasaero.export.RASAeroSaver.RASAeroExportException;
@ -74,12 +77,28 @@ public class BoosterDTO implements BodyTubeDTOAdapter {
private FinDTO fin;
@XmlTransient
private final RocketComponent component;
@XmlTransient
private final WarningSet warnings;
@XmlTransient
private final ErrorSet errors;
/**
* We need a default, no-args constructor.
*/
public BoosterDTO() { }
public BoosterDTO() {
this.component = null;
this.warnings = null;
this.errors = null;
}
protected BoosterDTO(Rocket rocket, AxialStage stage, WarningSet warnings, ErrorSet errors) throws RASAeroExportException {
this.component = stage;
this.warnings = warnings;
this.errors = errors;
protected BoosterDTO(Rocket rocket, AxialStage stage) throws RASAeroExportException {
int stageNr = rocket.getChildPosition(stage); // Use this instead of stage.getStageNumber() in case there are parallel stages in the design
if (stageNr != 1 && stageNr != 2) {
throw new RASAeroExportException(String.format("Invalid stage number '%d' for booster stage '%s'", stageNr, stage.getName()));
@ -129,7 +148,7 @@ public class BoosterDTO implements BodyTubeDTOAdapter {
firstTube = (BodyTube) stage.getChild(0);
}
applyBodyTubeSettings(firstTube);
applyBodyTubeSettings(firstTube, warnings, errors);
TrapezoidFinSet finSet = getFinSetFromBodyTube(firstTube);
if (finSet == null) {
@ -144,6 +163,8 @@ public class BoosterDTO implements BodyTubeDTOAdapter {
setDiameter(firstTube.getOuterRadius() * 2 * RASAeroCommonConstants.OPENROCKET_TO_RASAERO_LENGTH);
setLocation(firstChild.getAxialOffset(AxialMethod.ABSOLUTE) * RASAeroCommonConstants.OPENROCKET_TO_RASAERO_LENGTH);
setColor(RASAeroCommonConstants.OPENROCKET_TO_RASAERO_COLOR(firstTube.getColor()));
// TODO: parse children for body tubes , transtitions etc.
}
private TrapezoidFinSet getFinSetFromBodyTube(BodyTube bodyTube) {
@ -168,6 +189,10 @@ public class BoosterDTO implements BodyTubeDTOAdapter {
}
public void setLength(Double length) {
if (MathUtil.equals(length, 0)) {
errors.add(String.format("Length of '%s' must be greater than 0", component.getName()));
return;
}
this.length = length;
}
@ -175,7 +200,10 @@ public class BoosterDTO implements BodyTubeDTOAdapter {
return diameter;
}
public void setDiameter(Double diameter) {
public void setDiameter(Double diameter) throws RASAeroExportException {
if (MathUtil.equals(diameter, 0)) {
throw new RASAeroExportException(String.format("Diameter of '%s' must be greater than 0", component.getName()));
}
this.diameter = diameter;
}
@ -183,7 +211,10 @@ public class BoosterDTO implements BodyTubeDTOAdapter {
return insideDiameter;
}
public void setInsideDiameter(Double insideDiameter) {
public void setInsideDiameter(Double insideDiameter) throws RASAeroExportException {
if (MathUtil.equals(insideDiameter, 0)) {
throw new RASAeroExportException(String.format("Inside diameter of '%s' must be greater than 0", component.getName()));
}
this.insideDiameter = insideDiameter;
}

View File

@ -2,6 +2,8 @@ package net.sf.openrocket.file.rasaero.export;
import net.sf.openrocket.file.rasaero.CustomDoubleAdapter;
import net.sf.openrocket.file.rasaero.RASAeroCommonConstants;
import net.sf.openrocket.logging.ErrorSet;
import net.sf.openrocket.logging.WarningSet;
import net.sf.openrocket.rocketcomponent.NoseCone;
import javax.xml.bind.annotation.XmlAccessType;
@ -31,8 +33,8 @@ public class NoseConeDTO extends BasePartDTO {
public NoseConeDTO() {
}
public NoseConeDTO(NoseCone noseCone) throws RASAeroExportException {
super(noseCone);
public NoseConeDTO(NoseCone noseCone, WarningSet warnings, ErrorSet errors) throws RASAeroExportException {
super(noseCone, warnings, errors);
NoseConeShapeSettings shapeSettings =
RASAeroCommonConstants.OPENROCKET_TO_RASAERO_SHAPE(noseCone.getShapeType(), noseCone.getShapeParameter());

View File

@ -3,12 +3,13 @@ package net.sf.openrocket.file.rasaero.export;
import net.sf.openrocket.document.OpenRocketDocument;
import net.sf.openrocket.document.StorageOptions;
import net.sf.openrocket.file.RocketSaver;
import net.sf.openrocket.logging.ErrorSet;
import net.sf.openrocket.logging.WarningSet;
import net.sf.openrocket.rocketcomponent.Rocket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import java.io.BufferedWriter;
import java.io.IOException;
@ -35,7 +36,7 @@ public class RASAeroSaver extends RocketSaver {
* @param doc the OR design
* @return RASAero-compliant XML
*/
public String marshalToRASAero(OpenRocketDocument doc) {
public String marshalToRASAero(OpenRocketDocument doc, WarningSet warnings, ErrorSet errors) {
try {
JAXBContext binder = JAXBContext.newInstance(RASAeroDocumentDTO.class);
Marshaller marshaller = binder.createMarshaller();
@ -43,10 +44,10 @@ public class RASAeroSaver extends RocketSaver {
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
StringWriter sw = new StringWriter();
marshaller.marshal(toRASAeroDocumentDTO(doc), sw);
marshaller.marshal(toRASAeroDocumentDTO(doc, warnings, errors), sw);
return sw.toString();
} catch (RASAeroExportException e) {
throw new RuntimeException(e);
errors.add(e.getMessage());
} catch (Exception e) {
log.error("Could not marshall a design to RASAero format. " + e.getMessage());
}
@ -55,28 +56,30 @@ public class RASAeroSaver extends RocketSaver {
}
@Override
public void save(OutputStream dest, OpenRocketDocument doc, StorageOptions options) throws IOException {
public void save(OutputStream dest, OpenRocketDocument doc, StorageOptions options, WarningSet warnings, ErrorSet errors) throws IOException {
log.info("Saving .CDX1 file");
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(dest, StandardCharsets.UTF_8));
writer.write(marshalToRASAero(doc));
writer.write(marshalToRASAero(doc, warnings, errors));
writer.flush();
}
@Override
public long estimateFileSize(OpenRocketDocument doc, StorageOptions options) {
return marshalToRASAero(doc).length();
return marshalToRASAero(doc, new WarningSet(), new ErrorSet()).length();
}
/**
* Root conversion method. It iterates over all subcomponents.
*
* @param doc the OR design
* @param warnings list to add export warnings to
* @param errors list to add export errors to
* @return a corresponding RASAero representation
*/
private RASAeroDocumentDTO toRASAeroDocumentDTO(OpenRocketDocument doc) throws RASAeroExportException {
private RASAeroDocumentDTO toRASAeroDocumentDTO(OpenRocketDocument doc, WarningSet warnings, ErrorSet errors) throws RASAeroExportException {
RASAeroDocumentDTO rad = new RASAeroDocumentDTO();
rad.setDesign(toRocketDesignDTO(doc.getRocket()));
rad.setDesign(toRocketDesignDTO(doc.getRocket(), warnings, errors));
return rad;
}
@ -86,8 +89,7 @@ public class RASAeroSaver extends RocketSaver {
* @param rocket the OR rocket to export the components from
* @return the RASAero rocket design
*/
private RocketDesignDTO toRocketDesignDTO(Rocket rocket) throws RASAeroExportException {
RocketDesignDTO result = new RocketDesignDTO(rocket);
return result;
private RocketDesignDTO toRocketDesignDTO(Rocket rocket, WarningSet warnings, ErrorSet errors) throws RASAeroExportException {
return new RocketDesignDTO(rocket, warnings, errors);
}
}

View File

@ -3,6 +3,8 @@ package net.sf.openrocket.file.rasaero.export;
import net.sf.openrocket.file.rasaero.CustomBooleanAdapter;
import net.sf.openrocket.file.rasaero.CustomDoubleAdapter;
import net.sf.openrocket.file.rasaero.RASAeroCommonConstants;
import net.sf.openrocket.logging.ErrorSet;
import net.sf.openrocket.logging.WarningSet;
import net.sf.openrocket.rocketcomponent.AxialStage;
import net.sf.openrocket.rocketcomponent.BodyTube;
import net.sf.openrocket.rocketcomponent.NoseCone;
@ -65,10 +67,10 @@ public class RocketDesignDTO {
@XmlElement(name = RASAeroCommonConstants.COMMENTS)
private String comments = "";
public RocketDesignDTO(Rocket rocket) throws RASAeroExportException {
public RocketDesignDTO(Rocket rocket, WarningSet warnings, ErrorSet errors) throws RASAeroExportException {
setComments(rocket.getComment());
if (rocket.getChildCount() > 3) {
throw new RASAeroExportException("Rocket should have no more then 3 stages (excl. boosters) in total");
warnings.add("Rocket should have no more then 3 stages (excl. boosters) in total.\nIgnoring other stages.");
}
setUseBooster1(rocket.getStageCount() >= 2);
setUseBooster2(rocket.getStageCount() == 3);
@ -77,30 +79,40 @@ public class RocketDesignDTO {
// Export components from sustainer
for (int i = 0; i < sustainer.getChildCount(); i++) {
RocketComponent component = sustainer.getChild(i);
if (i == 0 && !(component instanceof NoseCone)) {
throw new RASAeroExportException("First component of the sustainer must be a nose cone");
} else if (i == 1 && !(component instanceof BodyTube)) {
throw new RASAeroExportException("Second component of the sustainer must be a body tube");
}
if (component instanceof BodyTube) {
addExternalPart(new BodyTubeDTO((BodyTube) component));
} else if (component instanceof NoseCone) {
if (i != 0) {
throw new RASAeroExportException("A nose cone can only be the first component of the rocket");
try {
RocketComponent component = sustainer.getChild(i);
if (i == 0 && !(component instanceof NoseCone)) {
errors.add("First component of the sustainer must be a nose cone");
return;
} else if (i == 1 && !(component instanceof BodyTube)) {
errors.add("Second component of the sustainer must be a body tube");
return;
}
addExternalPart(new NoseConeDTO((NoseCone) component));
// Set the global surface finish to that of the first nose cone
setSurface(RASAeroCommonConstants.OPENROCKET_TO_RASAERO_SURFACE(((NoseCone) component).getFinish()));
}
else if (component instanceof Transition) {
addExternalPart(new TransitionDTO((Transition) component));
if (component instanceof BodyTube) {
addExternalPart(new BodyTubeDTO((BodyTube) component, warnings, errors));
} else if (component instanceof NoseCone) {
if (i != 0) {
errors.add("A nose cone can only be the first component of the rocket");
return;
}
addExternalPart(new NoseConeDTO((NoseCone) component, warnings, errors));
// Set the global surface finish to that of the first nose cone
setSurface(RASAeroCommonConstants.OPENROCKET_TO_RASAERO_SURFACE(((NoseCone) component).getFinish()));
} else if (component instanceof Transition) {
addExternalPart(new TransitionDTO((Transition) component, warnings, errors));
}
} catch (RASAeroExportException e) {
errors.add(e.getMessage());
}
}
// Export components from other stages
for (int i = 1; i < rocket.getChildCount(); i++) {
addBooster(new BoosterDTO(rocket, (AxialStage) rocket.getChild(i)));
for (int i = 1; i < Math.min(rocket.getChildCount(), 3); i++) {
try {
addBooster(new BoosterDTO(rocket, (AxialStage) rocket.getChild(i), warnings, errors));
} catch (RASAeroExportException e) {
errors.add(e.getMessage());
}
}
}

View File

@ -2,7 +2,8 @@ package net.sf.openrocket.file.rasaero.export;
import net.sf.openrocket.file.rasaero.CustomDoubleAdapter;
import net.sf.openrocket.file.rasaero.RASAeroCommonConstants;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.logging.ErrorSet;
import net.sf.openrocket.logging.WarningSet;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
@ -31,8 +32,8 @@ public class TransitionDTO extends BasePartDTO {
public TransitionDTO() {
}
public TransitionDTO(Transition transition) throws RASAeroExportException {
super(transition);
public TransitionDTO(Transition transition, WarningSet warnings, ErrorSet errors) throws RASAeroExportException {
super(transition, warnings, errors);
if (!transition.getShapeType().equals(Transition.Shape.CONICAL)) {
throw new RASAeroExportException("RASAero only supports conical transitions");

View File

@ -10,6 +10,8 @@ import java.nio.charset.StandardCharsets;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import net.sf.openrocket.logging.ErrorSet;
import net.sf.openrocket.logging.WarningSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -58,7 +60,7 @@ public class RockSimSaver extends RocketSaver {
}
@Override
public void save(OutputStream dest, OpenRocketDocument doc, StorageOptions options) throws IOException {
public void save(OutputStream dest, OpenRocketDocument doc, StorageOptions options, WarningSet warnings, ErrorSet errors) throws IOException {
log.info("Saving .rkt file");
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(dest, StandardCharsets.UTF_8));

View File

@ -11,6 +11,8 @@ import net.sf.openrocket.document.OpenRocketDocument;
import net.sf.openrocket.document.OpenRocketDocumentFactory;
import net.sf.openrocket.document.Simulation;
import net.sf.openrocket.file.openrocket.OpenRocketSaver;
import net.sf.openrocket.logging.ErrorSet;
import net.sf.openrocket.logging.WarningSet;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.material.Material.Type;
import net.sf.openrocket.motor.Manufacturer;
@ -1830,7 +1832,7 @@ public class TestRockets {
OpenRocketSaver saver = new OpenRocketSaver();
try {
FileOutputStream str = new FileOutputStream(filename);
saver.save(str, doc, null);
saver.save(str, doc, null, new WarningSet(), new ErrorSet());
}
catch (Exception e) {
System.err.println("exception " + e);

View File

@ -29,6 +29,8 @@ import net.sf.openrocket.file.RocketLoadException;
import net.sf.openrocket.file.motor.GeneralMotorLoader;
import net.sf.openrocket.l10n.DebugTranslator;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.logging.ErrorSet;
import net.sf.openrocket.logging.WarningSet;
import net.sf.openrocket.motor.Manufacturer;
import net.sf.openrocket.motor.Motor;
import net.sf.openrocket.motor.ThrustCurveMotor;
@ -363,7 +365,7 @@ public class OpenRocketSaverTest {
try {
file = File.createTempFile( TMP_DIR.getName(), ".ork");
out = new FileOutputStream(file);
this.saver.save(out, rocketDoc, options);
this.saver.save(out, rocketDoc, options, new WarningSet(), new ErrorSet());
} catch (FileNotFoundException e) {
fail("FileNotFound saving temp file in: " + TMP_DIR.getName() + ": " + e.getMessage());
} catch (IOException e) {

View File

@ -0,0 +1,128 @@
package net.sf.openrocket.gui.dialogs;
import net.miginfocom.swing.MigLayout;
import net.sf.openrocket.gui.components.StyledLabel;
import net.sf.openrocket.logging.Error;
import net.sf.openrocket.logging.ErrorSet;
import net.sf.openrocket.logging.Warning;
import net.sf.openrocket.logging.WarningSet;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JViewport;
import javax.swing.ListSelectionModel;
import java.awt.Color;
import java.awt.Component;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
/**
* A message dialog displaying errors and warnings.
*/
@SuppressWarnings("serial")
public abstract class ErrorWarningDialog {
public static void showErrorsAndWarnings(Component parent, Object message, String title, ErrorSet errors, WarningSet warnings) {
JPanel content = new JPanel(new MigLayout("ins 0, fillx"));
StyledLabel label = new StyledLabel("Errors");
label.setFontColor(net.sf.openrocket.util.Color.DARK_RED.toAWTColor());
content.add(label, "wrap, gaptop 15lp");
Error[] e = errors.toArray(new Error[0]);
final JList<Error> errorList = new JList<>(e);
errorList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
errorList.setCellRenderer(new ErrorListCellRenderer());
JScrollPane errorPane = new JScrollPane(errorList);
content.add(errorPane, "wrap, growx");
// Deselect items if clicked on blank region
errorList.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
int selectedIndex = errorList.locationToIndex(e.getPoint());
if (selectedIndex < 0 || !errorList.getCellBounds(0, errorList.getLastVisibleIndex()).contains(e.getPoint())) {
errorList.clearSelection();
}
}
});
content.add(new JSeparator(JSeparator.HORIZONTAL), "wrap");
content.add(new JLabel("Warnings:"), "wrap");
Warning[] w = warnings.toArray(new Warning[0]);
final JList<Warning> warningList = new JList<>(w);
warningList.setCellRenderer(new WarningListCellRenderer());
JScrollPane warningPane = new JScrollPane(warningList);
content.add(warningPane, "wrap, growx");
// Deselect items if clicked on blank region
warningList.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
int selectedIndex = warningList.locationToIndex(e.getPoint());
if (selectedIndex < 0 || !warningList.getCellBounds(0, warningList.getLastVisibleIndex()).contains(e.getPoint())) {
warningList.clearSelection();
}
}
});
JOptionPane.showMessageDialog(parent, new Object[] { message, content },
title, JOptionPane.WARNING_MESSAGE);
}
private static class ErrorListCellRenderer extends DefaultListCellRenderer {
@Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
// Alternating row colors
if (!isSelected) {
if (index % 2 == 0) {
label.setBackground(Color.WHITE);
} else {
label.setBackground(new Color(245, 245, 245));
}
}
// Text color
if (isSelected) {
label.setForeground(Color.WHITE);
} else {
label.setForeground(net.sf.openrocket.util.Color.DARK_RED.toAWTColor());
}
return label;
}
}
private static class WarningListCellRenderer extends DefaultListCellRenderer {
@Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
// Alternating row colors
if (!isSelected) {
if (index % 2 == 0) {
label.setBackground(Color.WHITE);
} else {
label.setBackground(new Color(245, 245, 245));
}
}
// Text color
if (isSelected) {
label.setForeground(Color.WHITE);
} else {
label.setForeground(Color.BLACK);
}
return label;
}
}
}

View File

@ -11,7 +11,7 @@ import net.sf.openrocket.logging.Warning;
import net.sf.openrocket.logging.WarningSet;
@SuppressWarnings("serial")
public class WarningDialog extends JDialog {
public abstract class WarningDialog {
public static void showWarnings(Component parent, Object message, String title, WarningSet warnings) {

View File

@ -49,6 +49,8 @@ import javax.swing.tree.DefaultTreeSelectionModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import net.miginfocom.swing.MigLayout;
import net.sf.openrocket.gui.dialogs.ErrorWarningDialog;
import net.sf.openrocket.logging.ErrorSet;
import net.sf.openrocket.logging.WarningSet;
import net.sf.openrocket.appearance.DecalImage;
import net.sf.openrocket.arch.SystemInfo;
@ -1466,8 +1468,33 @@ public class BasicFrame extends JFrame {
private boolean saveRASAeroFile(File file, StorageOptions options) {
try {
ROCKET_SAVER.save(file, document, options);
WarningSet warnings = ROCKET_SAVER.getWarnings();
ErrorSet errors = ROCKET_SAVER.getErrors();
if (errors.isEmpty()) {
WarningDialog.showWarnings(this,
new Object[]{
// // The following problems were encountered while saving
trans.get("BasicFrame.WarningDialog.saving.txt1") + " '" + file.getName() + "'.",
// // Some design features may not have been exported correctly.
trans.get("BasicFrame.WarningDialog.saving.txt2")
},
// // Warnings while opening file
trans.get("BasicFrame.WarningDialog.saving.title"), warnings);
} else {
ErrorWarningDialog.showErrorsAndWarnings(this,
new Object[]{
// // The following problems were encountered while saving
trans.get("BasicFrame.WarningDialog.saving.txt1") + " '" + file.getName() + "'.",
// // Please correct the errors.
trans.get("BasicFrame.ErrorWarningDialog.txt1")
},
// // Errors/Warnings while saving file
trans.get("BasicFrame.ErrorWarningDialog.saving.title"), errors, warnings);
}
// Do not update the save state of the document.
return true;
return errors.isEmpty();
} catch (IOException e) {
return false;
} catch (DecalNotFoundException decex) {