From f0ae25615eb993cf7af1a23eda7dd3f67d8ac081 Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Thu, 23 May 2013 11:01:21 -0500 Subject: [PATCH 01/14] Rework simulation ui. Added support for default flight conditions. Editing of flight conditions on multiple simulations. Changed exceptions generated in simulation to still produce data. --- core/resources/l10n/messages.properties | 10 +- .../sf/openrocket/aerodynamics/Warning.java | 3 + .../openrocket/gui/main/SimulationPanel.java | 160 ++++-- .../openrocket/gui/plot/SimulationPlot.java | 1 + .../gui/plot/SimulationPlotDialog.java | 12 +- .../gui/print/PrintSimulationWorker.java | 2 +- .../gui/scalefigure/RocketPanel.java | 2 +- .../SimulationEditDialog.java | 516 ++++++------------ .../gui/simulation/SimulationExportPanel.java | 436 +++++++++++++++ .../SimulationPlotExportDialog.java | 137 +++++ .../SimulationPlotPanel.java | 23 +- .../SimulationRunDialog.java | 2 +- .../simulation/SimulationWarningDialog.java | 32 ++ .../SimulationWorker.java | 3 +- .../BasicEventSimulationEngine.java | 10 +- .../simulation/BasicLandingStepper.java | 2 +- .../simulation/BasicTumbleStepper.java | 2 +- .../DefaultSimulationOptionFactory.java | 73 +++ .../sf/openrocket/simulation/FlightEvent.java | 7 +- .../simulation/SimulationOptions.java | 19 + .../simulation/SimulationStepper.java | 2 +- 21 files changed, 1011 insertions(+), 443 deletions(-) rename core/src/net/sf/openrocket/gui/{main => simulation}/SimulationEditDialog.java (73%) create mode 100644 core/src/net/sf/openrocket/gui/simulation/SimulationExportPanel.java create mode 100644 core/src/net/sf/openrocket/gui/simulation/SimulationPlotExportDialog.java rename core/src/net/sf/openrocket/gui/{plot => simulation}/SimulationPlotPanel.java (95%) rename core/src/net/sf/openrocket/gui/{main => simulation}/SimulationRunDialog.java (99%) create mode 100644 core/src/net/sf/openrocket/gui/simulation/SimulationWarningDialog.java rename core/src/net/sf/openrocket/gui/{main => simulation}/SimulationWorker.java (97%) create mode 100644 core/src/net/sf/openrocket/simulation/DefaultSimulationOptionFactory.java diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index b48b42d5f..153afa599 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -306,6 +306,7 @@ PreferencesDialog.lbl.languageEffect = The language will change the next time yo ! Simulation edit dialog simedtdlg.but.runsimulation = Run simulation simedtdlg.but.resettodefault = Reset to default +simedtdlg.but.savedefault = Save as default simedtdlg.but.add = Add simedtdlg.but.remove = Remove simedtdlg.title.Editsim = Edit simulation @@ -438,12 +439,6 @@ SimuRunDlg.lbl.Altitude = Altitude: SimuRunDlg.lbl.Velocity = Velocity: SimuRunDlg.msg.Unabletosim = Unable to simulate: SimuRunDlg.msg.errorOccurred = An error occurred during the simulation: -SimuRunDlg.msg.AnException1 = An exception occurred during the simulation: -SimuRunDlg.msg.AnException2 = Please report this as a bug along with the details below. -SimuRunDlg.msg.AssertionError1 = A computation error occurred during the simulation. -SimuRunDlg.msg.AssertionError2 = Please report this as a bug along with the details below. -SimuRunDlg.msg.unknownerror1 = An unknown error was encountered during the simulation. -SimuRunDlg.msg.unknownerror2 = The program may be unstable, you should save all your designs and restart OpenRocket now! RK4SimulationStepper.error.valuesTooLarge = Simulation values exceeded limits. Try selecting a shorter time step. @@ -468,7 +463,6 @@ SimExpPan.checkbox.Incflightevents = Include flight events SimExpPan.checkbox.ttip.Incflightevents = Include a comment line for every flight event. SimExpPan.lbl.Commentchar = Comment character: SimExpPan.lbl.ttip.Commentchar = The character(s) that mark a comment line. -SimExpPan.but.Exporttofile = Export to file... SimExpPan.Fileexists.desc1 = File \" SimExpPan.Fileexists.desc2 = \" exists. Overwrite? SimExpPan.Fileexists.title = File exists @@ -581,7 +575,6 @@ simplotpanel.lbl.Flightevents = Flight events: simplotpanel.but.All = All simplotpanel.but.None = None simplotpanel.but.NewYaxisplottype = New Y axis plot type -simplotpanel.but.Plotflight = Plot flight simplotpanel.lbl.Axis = Axis: simplotpanel.but.ttip.Removethisplot = Remove this plot simplotpanel.Desc = The data will be plotted in time order even if the X axis type is not time. @@ -1394,6 +1387,7 @@ FlightEvent.Type.GROUND_HIT = Ground hit FlightEvent.Type.SIMULATION_END = Simulation end FlightEvent.Type.ALTITUDE = Altitude change FlightEvent.Type.TUMBLE = Tumbling +FlightEvent.Type.EXCEPTION = Exception ! ThrustCurveMotorColumns TCurveMotorCol.MANUFACTURER = Manufacturer diff --git a/core/src/net/sf/openrocket/aerodynamics/Warning.java b/core/src/net/sf/openrocket/aerodynamics/Warning.java index 363606d72..b06876c22 100644 --- a/core/src/net/sf/openrocket/aerodynamics/Warning.java +++ b/core/src/net/sf/openrocket/aerodynamics/Warning.java @@ -325,4 +325,7 @@ public abstract class Warning { public static final Warning RECOVERY_LAUNCH_ROD = new Other(trans.get("Warning.RECOVERY_LAUNCH_ROD")); + + public static final Warning SIMULATION_EXCEPTION = + new Other("Exception during simulation"); } diff --git a/core/src/net/sf/openrocket/gui/main/SimulationPanel.java b/core/src/net/sf/openrocket/gui/main/SimulationPanel.java index 37df70c91..aa27ebc3a 100644 --- a/core/src/net/sf/openrocket/gui/main/SimulationPanel.java +++ b/core/src/net/sf/openrocket/gui/main/SimulationPanel.java @@ -23,9 +23,6 @@ import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.table.DefaultTableCellRenderer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import net.miginfocom.swing.MigLayout; import net.sf.openrocket.aerodynamics.Warning; import net.sf.openrocket.aerodynamics.WarningSet; @@ -38,6 +35,10 @@ import net.sf.openrocket.formatting.RocketDescriptor; import net.sf.openrocket.gui.adaptors.Column; import net.sf.openrocket.gui.adaptors.ColumnTableModel; import net.sf.openrocket.gui.components.StyledLabel; +import net.sf.openrocket.gui.simulation.SimulationEditDialog; +import net.sf.openrocket.gui.simulation.SimulationPlotExportDialog; +import net.sf.openrocket.gui.simulation.SimulationRunDialog; +import net.sf.openrocket.gui.simulation.SimulationWarningDialog; import net.sf.openrocket.gui.util.Icons; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.rocketcomponent.ComponentChangeEvent; @@ -48,6 +49,9 @@ import net.sf.openrocket.startup.Application; import net.sf.openrocket.startup.Preferences; import net.sf.openrocket.unit.UnitGroup; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class SimulationPanel extends JPanel { private static final Logger log = LoggerFactory.getLogger(SimulationPanel.class); private static final Translator trans = Application.getTranslator(); @@ -68,13 +72,14 @@ public class SimulationPanel extends JPanel { private final ColumnTableModel simulationTableModel; private final JTable simulationTable; + private final JButton editButton; + private final JButton runButton; + private final JButton deleteButton; + private final JButton plotButton; public SimulationPanel(OpenRocketDocument doc) { super(new MigLayout("fill", "[grow][][][][][][grow]")); - JButton button; - - this.document = doc; @@ -82,51 +87,54 @@ public class SimulationPanel extends JPanel { //////// The simulation action buttons //// New simulation button - button = new JButton(trans.get("simpanel.but.newsimulation")); - //// Add a new simulation - button.setToolTipText(trans.get("simpanel.but.ttip.newsimulation")); - button.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - Simulation sim = new Simulation(document.getRocket()); - sim.setName(document.getNextSimulationName()); - - int n = document.getSimulationCount(); - document.addSimulation(sim); - simulationTableModel.fireTableDataChanged(); - simulationTable.clearSelection(); - simulationTable.addRowSelectionInterval(n, n); - - openDialog(sim, SimulationEditDialog.EDIT); - } - }); - this.add(button, "skip 1, gapright para"); + { + JButton button = new JButton(trans.get("simpanel.but.newsimulation")); + //// Add a new simulation + button.setToolTipText(trans.get("simpanel.but.ttip.newsimulation")); + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + Simulation sim = new Simulation(document.getRocket()); + sim.setName(document.getNextSimulationName()); + + int n = document.getSimulationCount(); + document.addSimulation(sim); + simulationTableModel.fireTableDataChanged(); + simulationTable.clearSelection(); + simulationTable.addRowSelectionInterval(n, n); + + openDialog(sim); + } + }); + this.add(button, "skip 1, gapright para"); + } //// Edit simulation button - button = new JButton(trans.get("simpanel.but.editsimulation")); + editButton = new JButton(trans.get("simpanel.but.editsimulation")); //// Edit the selected simulation - button.setToolTipText(trans.get("simpanel.but.ttip.editsim")); - button.addActionListener(new ActionListener() { + editButton.setToolTipText(trans.get("simpanel.but.ttip.editsim")); + editButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - int selected = simulationTable.getSelectedRow(); - if (selected < 0) - return; // TODO: MEDIUM: "None selected" dialog + int[] selection = simulationTable.getSelectedRows(); + if (selection.length == 0) + return; // TODO: LOW: "None selected" dialog - selected = simulationTable.convertRowIndexToModel(selected); - simulationTable.clearSelection(); - simulationTable.addRowSelectionInterval(selected, selected); - - openDialog(document.getSimulations().get(selected), SimulationEditDialog.EDIT); + Simulation[] sims = new Simulation[selection.length]; + for (int i = 0; i < selection.length; i++) { + selection[i] = simulationTable.convertRowIndexToModel(selection[i]); + sims[i] = document.getSimulation(selection[i]); + } + openDialog(sims); } }); - this.add(button, "gapright para"); + this.add(editButton, "gapright para"); //// Run simulations - button = new JButton(trans.get("simpanel.but.runsimulations")); + runButton = new JButton(trans.get("simpanel.but.runsimulations")); //// Re-run the selected simulations - button.setToolTipText(trans.get("simpanel.but.ttip.runsimu")); - button.addActionListener(new ActionListener() { + runButton.setToolTipText(trans.get("simpanel.but.ttip.runsimu")); + runButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { int[] selection = simulationTable.getSelectedRows(); @@ -146,13 +154,13 @@ public class SimulationPanel extends JPanel { fireMaintainSelection(); } }); - this.add(button, "gapright para"); + this.add(runButton, "gapright para"); //// Delete simulations button - button = new JButton(trans.get("simpanel.but.deletesimulations")); + deleteButton = new JButton(trans.get("simpanel.but.deletesimulations")); //// Delete the selected simulations - button.setToolTipText(trans.get("simpanel.but.ttip.deletesim")); - button.addActionListener(new ActionListener() { + deleteButton.setToolTipText(trans.get("simpanel.but.ttip.deletesim")); + deleteButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { int[] selection = simulationTable.getSelectedRows(); @@ -201,12 +209,12 @@ public class SimulationPanel extends JPanel { simulationTableModel.fireTableDataChanged(); } }); - this.add(button, "gapright para"); + this.add(deleteButton, "gapright para"); //// Plot / export button - button = new JButton(trans.get("simpanel.but.plotexport")); + plotButton = new JButton(trans.get("simpanel.but.plotexport")); // button = new JButton("Plot flight"); - button.addActionListener(new ActionListener() { + plotButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { int selected = simulationTable.getSelectedRow(); @@ -217,10 +225,21 @@ public class SimulationPanel extends JPanel { simulationTable.clearSelection(); simulationTable.addRowSelectionInterval(selected, selected); - openDialog(document.getSimulations().get(selected), SimulationEditDialog.PLOT); + + Simulation sim = document.getSimulations().get(selected); + + if (sim.getSimulatedData() == null || sim.getSimulatedData().getBranchCount() == 0) { + new SimulationRunDialog(SwingUtilities.getWindowAncestor( + SimulationPanel.this), document, sim).setVisible(true); + } + + new SimulationPlotExportDialog(SwingUtilities.getWindowAncestor(SimulationPanel.this), document, sim) + .setVisible(true); + fireMaintainSelection(); + } }); - this.add(button, "wrap para"); + this.add(plotButton, "wrap para"); @@ -474,13 +493,20 @@ public class SimulationPanel extends JPanel { int selected = simulationTable.getSelectedRow(); if (selected < 0) return; - selected = simulationTable.convertRowIndexToModel(selected); - simulationTable.clearSelection(); - simulationTable.addRowSelectionInterval(selected, selected); - openDialog(document.getSimulations().get(selected), - SimulationEditDialog.DEFAULT); + int column = simulationTable.columnAtPoint(e.getPoint()); + if (column == 0) { + SimulationWarningDialog.showWarningDialog(SimulationPanel.this, document.getSimulations().get(selected)); + } else { + simulationTable.clearSelection(); + simulationTable.addRowSelectionInterval(selected, selected); + + // FIXME - do we want to check to open plot dialog? + openDialog(document.getSimulations().get(selected)); + } + } else { + updateButtonStates(); } } }); @@ -509,17 +535,35 @@ public class SimulationPanel extends JPanel { JScrollPane scrollpane = new JScrollPane(simulationTable); this.add(scrollpane, "spanx, grow, wrap rel"); - + updateButtonStates(); } + private void updateButtonStates() { + int[] selection = simulationTable.getSelectedRows(); + if (selection.length == 0) { + editButton.setEnabled(false); + runButton.setEnabled(false); + deleteButton.setEnabled(false); + plotButton.setEnabled(false); + } else { + if (selection.length > 1) { + plotButton.setEnabled(false); + } else { + plotButton.setEnabled(true); + } + editButton.setEnabled(true); + runButton.setEnabled(true); + deleteButton.setEnabled(true); + } + + } public ListSelectionModel getSimulationListSelectionModel() { return simulationTable.getSelectionModel(); } - private void openDialog(final Simulation sim, int position) { - new SimulationEditDialog(SwingUtilities.getWindowAncestor(this), document, sim, position) - .setVisible(true); + private void openDialog(final Simulation... sims) { + new SimulationEditDialog(SwingUtilities.getWindowAncestor(this), document, sims).setVisible(true); fireMaintainSelection(); } diff --git a/core/src/net/sf/openrocket/gui/plot/SimulationPlot.java b/core/src/net/sf/openrocket/gui/plot/SimulationPlot.java index a254275c1..05d2de63e 100644 --- a/core/src/net/sf/openrocket/gui/plot/SimulationPlot.java +++ b/core/src/net/sf/openrocket/gui/plot/SimulationPlot.java @@ -20,6 +20,7 @@ import java.util.HashSet; import java.util.List; import net.sf.openrocket.document.Simulation; +import net.sf.openrocket.gui.simulation.SimulationPlotPanel; import net.sf.openrocket.simulation.FlightDataBranch; import net.sf.openrocket.simulation.FlightDataType; import net.sf.openrocket.simulation.FlightEvent; diff --git a/core/src/net/sf/openrocket/gui/plot/SimulationPlotDialog.java b/core/src/net/sf/openrocket/gui/plot/SimulationPlotDialog.java index 1bb158549..95d18726b 100644 --- a/core/src/net/sf/openrocket/gui/plot/SimulationPlotDialog.java +++ b/core/src/net/sf/openrocket/gui/plot/SimulationPlotDialog.java @@ -7,8 +7,6 @@ import java.awt.event.InputEvent; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.ArrayList; -import java.util.Collections; -import java.util.List; import javax.swing.JButton; import javax.swing.JCheckBox; @@ -40,7 +38,7 @@ public class SimulationPlotDialog extends JDialog { private SimulationPlotDialog(Window parent, Simulation simulation, PlotConfiguration config) { //// Flight data plot super(parent, simulation.getName()); - this.setModalityType(ModalityType.DOCUMENT_MODAL); + this.setModalityType(ModalityType.MODELESS); final boolean initialShowPoints = Application.getPreferences().getBoolean(Preferences.PLOT_SHOW_POINTS, false); @@ -113,8 +111,8 @@ public class SimulationPlotDialog extends JDialog { //// Add series selection box ArrayList stages = new ArrayList(); stages.add("All"); - stages.addAll( Util.generateSeriesLabels(simulation)); - + stages.addAll(Util.generateSeriesLabels(simulation)); + final JComboBox stageSelection = new JComboBox(stages.toArray(new String[0])); stageSelection.addItemListener(new ItemListener() { @@ -159,8 +157,8 @@ public class SimulationPlotDialog extends JDialog { * @param simulation the simulation to plot. * @param config the configuration of the plot. */ - public static void showPlot(Window parent, Simulation simulation, PlotConfiguration config) { - new SimulationPlotDialog(parent, simulation, config).setVisible(true); + public static SimulationPlotDialog getPlot(Window parent, Simulation simulation, PlotConfiguration config) { + return new SimulationPlotDialog(parent, simulation, config); } } diff --git a/core/src/net/sf/openrocket/gui/print/PrintSimulationWorker.java b/core/src/net/sf/openrocket/gui/print/PrintSimulationWorker.java index 53a710c80..be4fbe6c9 100644 --- a/core/src/net/sf/openrocket/gui/print/PrintSimulationWorker.java +++ b/core/src/net/sf/openrocket/gui/print/PrintSimulationWorker.java @@ -4,7 +4,7 @@ package net.sf.openrocket.gui.print; import net.sf.openrocket.document.Simulation; -import net.sf.openrocket.gui.main.SimulationWorker; +import net.sf.openrocket.gui.simulation.SimulationWorker; import net.sf.openrocket.simulation.FlightData; /** diff --git a/core/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java b/core/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java index 70e9928e8..5ae1d1581 100644 --- a/core/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java +++ b/core/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java @@ -54,8 +54,8 @@ import net.sf.openrocket.gui.figureelements.CGCaret; import net.sf.openrocket.gui.figureelements.CPCaret; import net.sf.openrocket.gui.figureelements.Caret; import net.sf.openrocket.gui.figureelements.RocketInfo; -import net.sf.openrocket.gui.main.SimulationWorker; import net.sf.openrocket.gui.main.componenttree.ComponentTreeModel; +import net.sf.openrocket.gui.simulation.SimulationWorker; import net.sf.openrocket.gui.util.SwingPreferences; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.masscalc.BasicMassCalculator; diff --git a/core/src/net/sf/openrocket/gui/main/SimulationEditDialog.java b/core/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java similarity index 73% rename from core/src/net/sf/openrocket/gui/main/SimulationEditDialog.java rename to core/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java index 62175e4de..ab05b176a 100644 --- a/core/src/net/sf/openrocket/gui/main/SimulationEditDialog.java +++ b/core/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java @@ -1,13 +1,11 @@ -package net.sf.openrocket.gui.main; +package net.sf.openrocket.gui.simulation; -import java.awt.Color; import java.awt.Component; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Arrays; -import java.util.List; import javax.swing.AbstractListModel; import javax.swing.BorderFactory; @@ -40,139 +38,126 @@ import net.sf.openrocket.gui.adaptors.EnumModel; import net.sf.openrocket.gui.adaptors.FlightConfigurationModel; import net.sf.openrocket.gui.components.BasicSlider; import net.sf.openrocket.gui.components.DescriptionArea; -import net.sf.openrocket.gui.components.SimulationExportPanel; import net.sf.openrocket.gui.components.UnitSelector; import net.sf.openrocket.gui.dialogs.flightconfiguration.FlightConfigurationDialog; -import net.sf.openrocket.gui.plot.Axis; -import net.sf.openrocket.gui.plot.PlotConfiguration; -import net.sf.openrocket.gui.plot.SimulationPlotPanel; -import net.sf.openrocket.gui.scalefigure.RocketPanel; import net.sf.openrocket.gui.util.GUIUtil; import net.sf.openrocket.gui.util.Icons; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.models.atmosphere.ExtendedISAModel; import net.sf.openrocket.rocketcomponent.Configuration; -import net.sf.openrocket.simulation.FlightData; -import net.sf.openrocket.simulation.FlightDataBranch; -import net.sf.openrocket.simulation.FlightDataType; +import net.sf.openrocket.simulation.DefaultSimulationOptionFactory; import net.sf.openrocket.simulation.RK4SimulationStepper; import net.sf.openrocket.simulation.SimulationOptions; import net.sf.openrocket.simulation.listeners.SimulationListener; import net.sf.openrocket.simulation.listeners.example.CSVSaveListener; import net.sf.openrocket.startup.Application; -import net.sf.openrocket.unit.Unit; import net.sf.openrocket.unit.UnitGroup; import net.sf.openrocket.util.Chars; import net.sf.openrocket.util.GeodeticComputationStrategy; -import org.jfree.chart.ChartFactory; -import org.jfree.chart.ChartPanel; -import org.jfree.chart.JFreeChart; -import org.jfree.chart.axis.NumberAxis; -import org.jfree.chart.plot.PlotOrientation; -import org.jfree.chart.plot.ValueMarker; -import org.jfree.chart.plot.XYPlot; -import org.jfree.chart.renderer.xy.StandardXYItemRenderer; -import org.jfree.data.xy.XYSeries; -import org.jfree.data.xy.XYSeriesCollection; - public class SimulationEditDialog extends JDialog { - public static final int DEFAULT = -1; - public static final int EDIT = 1; - public static final int PLOT = 2; - - private final Window parentWindow; - private final Simulation simulation; + private final Simulation[] simulation; private final OpenRocketDocument document; private final SimulationOptions conditions; private final Configuration configuration; private static final Translator trans = Application.getTranslator(); - public SimulationEditDialog(Window parent, OpenRocketDocument document, Simulation s) { - this(parent, document, s, 0); - } - - public SimulationEditDialog(Window parent, OpenRocketDocument document, Simulation s, int tab) { + public SimulationEditDialog(Window parent, OpenRocketDocument document, Simulation... sims) { //// Edit simulation super(parent, trans.get("simedtdlg.title.Editsim"), JDialog.ModalityType.DOCUMENT_MODAL); this.document = document; this.parentWindow = parent; - this.simulation = s; - this.conditions = simulation.getOptions(); - configuration = simulation.getConfiguration(); + this.simulation = sims; + this.conditions = simulation[0].getOptions(); + configuration = simulation[0].getConfiguration(); - JPanel mainPanel = new JPanel(new MigLayout("fill", "[grow, fill]")); + JPanel mainPanel = new JPanel(new MigLayout("")); - //// Simulation name: - mainPanel.add(new JLabel(trans.get("simedtdlg.lbl.Simname") + " "), "span, split 2, shrink"); - final JTextField field = new JTextField(simulation.getName()); - field.getDocument().addDocumentListener(new DocumentListener() { - @Override - public void changedUpdate(DocumentEvent e) { - setText(); - } - - @Override - public void insertUpdate(DocumentEvent e) { - setText(); - } - - @Override - public void removeUpdate(DocumentEvent e) { - setText(); - } - - private void setText() { - String name = field.getText(); - if (name == null || name.equals("")) - return; - //System.out.println("Setting name:" + name); - simulation.setName(name); + if (sims.length == 1) { + //// Simulation name: + mainPanel.add(new JLabel(trans.get("simedtdlg.lbl.Simname") + " "), "shrink"); + final JTextField field = new JTextField(simulation[0].getName()); + field.getDocument().addDocumentListener(new DocumentListener() { + @Override + public void changedUpdate(DocumentEvent e) { + setText(); + } - } - }); - mainPanel.add(field, "shrinky, growx, wrap"); - + @Override + public void insertUpdate(DocumentEvent e) { + setText(); + } + + @Override + public void removeUpdate(DocumentEvent e) { + setText(); + } + + private void setText() { + String name = field.getText(); + if (name == null || name.equals("")) + return; + //System.out.println("Setting name:" + name); + simulation[0].setName(name); + + } + }); + mainPanel.add(field, "shrinky, growx, wrap"); + + //// Flight selector + //// Flight configuration: + JLabel label = new JLabel(trans.get("simedtdlg.lbl.Flightcfg")); + //// Select the motor configuration to use. + label.setToolTipText(trans.get("simedtdlg.lbl.ttip.Flightcfg")); + mainPanel.add(label, "shrink"); + + JComboBox combo = new JComboBox(new FlightConfigurationModel(configuration)); + //// Select the motor configuration to use. + combo.setToolTipText(trans.get("simedtdlg.combo.ttip.Flightcfg")); + combo.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + conditions.setMotorConfigurationID(configuration.getFlightConfigurationID()); + } + }); + mainPanel.add(combo, "split 2, shrink"); + + //// Edit button + JButton button = new JButton(trans.get("simedtdlg.but.FlightcfgEdit")); + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + JDialog configDialog = new FlightConfigurationDialog(SimulationEditDialog.this.document.getRocket(), SwingUtilities.windowForComponent(SimulationEditDialog.this)); + configDialog.setVisible(true); + } + }); + mainPanel.add(button, "shrink, wrap"); + } JTabbedPane tabbedPane = new JTabbedPane(); //// Launch conditions tabbedPane.addTab(trans.get("simedtdlg.tab.Launchcond"), flightConditionsTab()); //// Simulation options tabbedPane.addTab(trans.get("simedtdlg.tab.Simopt"), simulationOptionsTab()); - //// Plot data - tabbedPane.addTab(trans.get("simedtdlg.tab.Plotdata"), plotTab()); - //// Export data - tabbedPane.addTab(trans.get("simedtdlg.tab.Exportdata"), exportTab()); - // Select the initial tab - if (tab == EDIT) { - tabbedPane.setSelectedIndex(0); - } else if (tab == PLOT) { - tabbedPane.setSelectedIndex(2); - } else { - FlightData data = s.getSimulatedData(); - if (data == null || data.getBranchCount() == 0) - tabbedPane.setSelectedIndex(0); - else - tabbedPane.setSelectedIndex(2); - } + tabbedPane.setSelectedIndex(0); mainPanel.add(tabbedPane, "spanx, grow, wrap"); - + // Buttons mainPanel.add(new JPanel(), "spanx, split, growx"); - JButton button; //// Run simulation button - button = new JButton(trans.get("simedtdlg.but.runsimulation")); + JButton button = new JButton(trans.get("simedtdlg.but.runsimulation")); button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { + copyChangesToAllSims(); SimulationEditDialog.this.dispose(); SimulationRunDialog.runSimulations(parentWindow, SimulationEditDialog.this.document, simulation); } @@ -184,12 +169,13 @@ public class SimulationEditDialog extends JDialog { close.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { + copyChangesToAllSims(); SimulationEditDialog.this.dispose(); } }); mainPanel.add(close, ""); - + this.add(mainPanel); this.validate(); this.pack(); @@ -198,10 +184,19 @@ public class SimulationEditDialog extends JDialog { GUIUtil.setDisposableDialogOptions(this, button); } + private void copyChangesToAllSims() { + if (simulation.length > 1) { + for (int i = 1; i < simulation.length; i++) { + simulation[i].getOptions().copyConditionsFrom(simulation[0].getOptions()); + simulation[i].getSimulationListeners().clear(); + simulation[i].getSimulationListeners().addAll(simulation[0].getSimulationListeners()); + } + } + } + + + - - - private JPanel flightConditionsTab() { JPanel panel = new JPanel(new MigLayout("fill")); JPanel sub; @@ -211,35 +206,6 @@ public class SimulationEditDialog extends JDialog { DoubleModel m; JSpinner spin; - //// Flight selector - //// Flight configuration: - JLabel label = new JLabel(trans.get("simedtdlg.lbl.Flightcfg")); - //// Select the motor configuration to use. - label.setToolTipText(trans.get("simedtdlg.lbl.ttip.Flightcfg")); - panel.add(label, "shrinkx, spanx, split 2"); - - JComboBox combo = new JComboBox(new FlightConfigurationModel(configuration)); - //// Select the motor configuration to use. - combo.setToolTipText(trans.get("simedtdlg.combo.ttip.Flightcfg")); - combo.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - conditions.setMotorConfigurationID(configuration.getFlightConfigurationID()); - } - }); - panel.add(combo, ""); - - //// Edit button - JButton button = new JButton(trans.get("simedtdlg.but.FlightcfgEdit")); - button.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - JDialog configDialog = new FlightConfigurationDialog(document.getRocket(),SwingUtilities.windowForComponent(SimulationEditDialog.this)); - configDialog.show(); - } - }); - panel.add(button, "wrap"); - //// Wind settings: Average wind speed, turbulence intensity, std. deviation sub = new JPanel(new MigLayout("fill, gap rel unrel", "[grow][65lp!][30lp!][75lp!]", "")); @@ -247,10 +213,10 @@ public class SimulationEditDialog extends JDialog { sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.lbl.Wind"))); panel.add(sub, "growx, split 2, aligny 0, flowy, gapright para"); - + // Wind average //// Average windspeed: - label = new JLabel(trans.get("simedtdlg.lbl.Averwindspeed")); + JLabel label = new JLabel(trans.get("simedtdlg.lbl.Averwindspeed")); //// The average windspeed relative to the ground. tip = trans.get("simedtdlg.lbl.ttip.Averwindspeed"); label.setToolTipText(tip); @@ -270,8 +236,8 @@ public class SimulationEditDialog extends JDialog { slider.setToolTipText(tip); sub.add(slider, "w 75lp, wrap"); - - + + // Wind std. deviation //// Standard deviation: label = new JLabel(trans.get("simedtdlg.lbl.Stddeviation")); @@ -297,7 +263,7 @@ public class SimulationEditDialog extends JDialog { slider.setToolTipText(tip); sub.add(slider, "w 75lp, wrap"); - + // Wind turbulence intensity //// Turbulence intensity: label = new JLabel(trans.get("simedtdlg.lbl.Turbulenceintensity")); @@ -335,10 +301,10 @@ public class SimulationEditDialog extends JDialog { } }); - - - - + + + + //// Temperature and pressure sub = new JPanel(new MigLayout("fill, gap rel unrel", "[grow][65lp!][30lp!][75lp!]", "")); @@ -346,7 +312,7 @@ public class SimulationEditDialog extends JDialog { sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.border.Atmoscond"))); panel.add(sub, "growx, aligny 0, gapright para"); - + BooleanModel isa = new BooleanModel(conditions, "ISAAtmosphere"); JCheckBox check = new JCheckBox(isa); //// Use International Standard Atmosphere @@ -387,8 +353,8 @@ public class SimulationEditDialog extends JDialog { isa.addEnableComponent(slider, false); sub.add(slider, "w 75lp, wrap"); - - + + // Pressure: label = new JLabel(trans.get("simedtdlg.lbl.Pressure")); //// The atmospheric pressure at the launch site. @@ -414,10 +380,10 @@ public class SimulationEditDialog extends JDialog { isa.addEnableComponent(slider, false); sub.add(slider, "w 75lp, wrap"); - - - - + + + + //// Launch site conditions sub = new JPanel(new MigLayout("fill, gap rel unrel", "[grow][65lp!][30lp!][75lp!]", "")); @@ -425,7 +391,7 @@ public class SimulationEditDialog extends JDialog { sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.lbl.Launchsite"))); panel.add(sub, "growx, split 2, aligny 0, flowy"); - + // Latitude: label = new JLabel(trans.get("simedtdlg.lbl.Latitude")); //// The launch site latitude affects the gravitational pull of Earth.
@@ -448,7 +414,7 @@ public class SimulationEditDialog extends JDialog { slider.setToolTipText(tip); sub.add(slider, "w 75lp, wrap"); - + // Longitude: label = new JLabel(trans.get("simedtdlg.lbl.Longitude")); tip = trans.get("simedtdlg.lbl.ttip.Longitude"); @@ -469,7 +435,7 @@ public class SimulationEditDialog extends JDialog { slider.setToolTipText(tip); sub.add(slider, "w 75lp, wrap"); - + // Altitude: label = new JLabel(trans.get("simedtdlg.lbl.Altitude")); //// The launch altitude above mean sea level.
@@ -492,10 +458,10 @@ public class SimulationEditDialog extends JDialog { slider.setToolTipText(tip); sub.add(slider, "w 75lp, wrap"); - - - - + + + + //// Launch rod sub = new JPanel(new MigLayout("fill, gap rel unrel", "[grow][65lp!][30lp!][75lp!]", "")); @@ -503,7 +469,7 @@ public class SimulationEditDialog extends JDialog { sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.border.Launchrod"))); panel.add(sub, "growx, aligny 0, wrap"); - + // Length: label = new JLabel(trans.get("simedtdlg.lbl.Length")); //// The length of the launch rod. @@ -525,8 +491,8 @@ public class SimulationEditDialog extends JDialog { slider.setToolTipText(tip); sub.add(slider, "w 75lp, wrap"); - - + + // Angle: label = new JLabel(trans.get("simedtdlg.lbl.Angle")); //// The angle of the launch rod from vertical. @@ -550,8 +516,8 @@ public class SimulationEditDialog extends JDialog { slider.setToolTipText(tip); sub.add(slider, "w 75lp, wrap"); - - + + // Direction: label = new JLabel(trans.get("simedtdlg.lbl.Direction")); //// Direction of the launch rod relative to the wind.
@@ -580,6 +546,35 @@ public class SimulationEditDialog extends JDialog { slider.setToolTipText(tip); sub.add(slider, "w 75lp, wrap"); + JButton restoreDefaults = new JButton(trans.get("simedtdlg.but.resettodefault")); + restoreDefaults.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + + DefaultSimulationOptionFactory f = Application.getInjector().getInstance(DefaultSimulationOptionFactory.class); + SimulationOptions defaults = f.getDefault(); + conditions.copyConditionsFrom(defaults); + + } + + }); + panel.add(restoreDefaults, "span, split 3, skip, gapbottom para, gapright para, right"); + + JButton saveDefaults = new JButton(trans.get("simedtdlg.but.savedefault")); + saveDefaults.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + + DefaultSimulationOptionFactory f = Application.getInjector().getInstance(DefaultSimulationOptionFactory.class); + f.saveDefault(conditions); + + } + + }); + + panel.add(saveDefaults, "gapbottom para, gapright para, right"); return panel; } @@ -608,7 +603,7 @@ public class SimulationEditDialog extends JDialog { } - + private JPanel simulationOptionsTab() { JPanel panel = new JPanel(new MigLayout("fill")); JPanel sub, subsub; @@ -619,7 +614,7 @@ public class SimulationEditDialog extends JDialog { UnitSelector unit; BasicSlider slider; - + //// Simulation options sub = new JPanel(new MigLayout("fill, gap rel unrel", "[grow][65lp!][30lp!][75lp!]", "")); @@ -627,11 +622,11 @@ public class SimulationEditDialog extends JDialog { sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.border.Simopt"))); panel.add(sub, "growx, growy, aligny 0"); - + // Separate panel for computation methods, as they use a different layout subsub = new JPanel(new MigLayout("insets 0, fill")); - + //// Calculation method: tip = trans.get("simedtdlg.lbl.ttip.Calcmethod"); label = new JLabel(trans.get("simedtdlg.lbl.Calcmethod")); @@ -643,7 +638,7 @@ public class SimulationEditDialog extends JDialog { label.setToolTipText(tip); subsub.add(label, "growx, wrap para"); - + // Simulation method tip = trans.get("simedtdlg.lbl.ttip.Simmethod1") + trans.get("simedtdlg.lbl.ttip.Simmethod2"); @@ -655,7 +650,7 @@ public class SimulationEditDialog extends JDialog { label.setToolTipText(tip); subsub.add(label, "growx, wrap para"); - + //// Geodetic calculation method: label = new JLabel(trans.get("simedtdlg.lbl.GeodeticMethod")); label.setToolTipText(trans.get("simedtdlg.lbl.ttip.GeodeticMethodTip")); @@ -676,7 +671,7 @@ public class SimulationEditDialog extends JDialog { sub.add(subsub, "spanx, wrap para"); - + //// Time step: label = new JLabel(trans.get("simedtdlg.lbl.Timestep")); tip = trans.get("simedtdlg.lbl.ttip.Timestep1") + @@ -703,9 +698,9 @@ public class SimulationEditDialog extends JDialog { sub.add(slider, "w 75lp, wrap"); //sub.add(slider,"wrap"); - - - + + + //// Reset to default button JButton button = new JButton(trans.get("simedtdlg.but.resettodefault")); //// Reset the time step to its default value ( @@ -722,16 +717,16 @@ public class SimulationEditDialog extends JDialog { sub.add(button, "align left"); - - - + + + //// Simulation listeners sub = new JPanel(new MigLayout("fill, gap 0 0")); //// Simulator listeners sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.border.Simlist"))); panel.add(sub, "growx, growy"); - + DescriptionArea desc = new DescriptionArea(5); //// Simulation listeners is an advanced feature that allows user-written code to listen to and interact with the simulation. //// For details on writing simulation listeners, see the OpenRocket technical documentation. @@ -771,7 +766,7 @@ public class SimulationEditDialog extends JDialog { return; Application.getPreferences().putString("previousListenerName", input); - simulation.getSimulationListeners().add(input); + simulation[0].getSimulationListeners().add(input); listenerModel.fireContentsChanged(); } }); @@ -785,14 +780,14 @@ public class SimulationEditDialog extends JDialog { int[] selected = list.getSelectedIndices(); Arrays.sort(selected); for (int i = selected.length - 1; i >= 0; i--) { - simulation.getSimulationListeners().remove(selected[i]); + simulation[0].getSimulationListeners().remove(selected[i]); } listenerModel.fireContentsChanged(); } }); sub.add(button, "sizegroup buttons, alignx 50%"); - + return panel; } @@ -802,12 +797,12 @@ public class SimulationEditDialog extends JDialog { public String getElementAt(int index) { if (index < 0 || index >= getSize()) return null; - return simulation.getSimulationListeners().get(index); + return simulation[0].getSimulationListeners().get(index); } @Override public int getSize() { - return simulation.getSimulationListeners().size(); + return simulation[0].getSimulationListeners().size(); } public void fireContentsChanged() { @@ -816,40 +811,9 @@ public class SimulationEditDialog extends JDialog { } - - - /** - * A panel for plotting the previously calculated data. - */ - private JPanel plotTab() { - - // Check that data exists - if (simulation.getSimulatedData() == null || - simulation.getSimulatedData().getBranchCount() == 0) { - return noDataPanel(); - } - - return new SimulationPlotPanel(simulation); - } - - /** - * A panel for exporting the data. - */ - private JPanel exportTab() { - FlightData data = simulation.getSimulatedData(); - - // Check that data exists - if (data == null || data.getBranchCount() == 0 || - data.getBranch(0).getTypes().length == 0) { - return noDataPanel(); - } - - return new SimulationExportPanel(simulation); - } - /** * Return a panel stating that there is no data available, and that the user * should run the simulation first. @@ -868,165 +832,7 @@ public class SimulationEditDialog extends JDialog { } - @SuppressWarnings("unused") - private void performPlot(PlotConfiguration config) { - - // Fill the auto-selections - FlightDataBranch branch = simulation.getSimulatedData().getBranch(0); - PlotConfiguration filled = config.fillAutoAxes(branch); - List axes = filled.getAllAxes(); - - - // Create the data series for both axes - XYSeriesCollection[] data = new XYSeriesCollection[2]; - data[0] = new XYSeriesCollection(); - data[1] = new XYSeriesCollection(); - - - // Get the domain axis type - final FlightDataType domainType = filled.getDomainAxisType(); - final Unit domainUnit = filled.getDomainAxisUnit(); - if (domainType == null) { - throw new IllegalArgumentException("Domain axis type not specified."); - } - List x = branch.get(domainType); - - - // Create the XYSeries objects from the flight data and store into the collections - int length = filled.getTypeCount(); - String[] axisLabel = new String[2]; - for (int i = 0; i < length; i++) { - // Get info - FlightDataType type = filled.getType(i); - Unit unit = filled.getUnit(i); - int axis = filled.getAxis(i); - String name = getLabel(type, unit); - - // Store data in provided units - List y = branch.get(type); - XYSeries series = new XYSeries(name, false, true); - for (int j = 0; j < x.size(); j++) { - series.add(domainUnit.toUnit(x.get(j)), unit.toUnit(y.get(j))); - } - data[axis].addSeries(series); - - // Update axis label - if (axisLabel[axis] == null) - axisLabel[axis] = type.getName(); - else - axisLabel[axis] += "; " + type.getName(); - } - - - // Create the chart using the factory to get all default settings - JFreeChart chart = ChartFactory.createXYLineChart( - //// Simulated flight - trans.get("simedtdlg.chart.Simflight"), - null, - null, - null, - PlotOrientation.VERTICAL, - true, - true, - false - ); - - - // Add the data and formatting to the plot - XYPlot plot = chart.getXYPlot(); - int axisno = 0; - for (int i = 0; i < 2; i++) { - // Check whether axis has any data - if (data[i].getSeriesCount() > 0) { - // Create and set axis - double min = axes.get(i).getMinValue(); - double max = axes.get(i).getMaxValue(); - NumberAxis axis = new PresetNumberAxis(min, max); - axis.setLabel(axisLabel[i]); - // axis.setRange(axes.get(i).getMinValue(), axes.get(i).getMaxValue()); - plot.setRangeAxis(axisno, axis); - - // Add data and map to the axis - plot.setDataset(axisno, data[i]); - plot.setRenderer(axisno, new StandardXYItemRenderer()); - plot.mapDatasetToRangeAxis(axisno, axisno); - axisno++; - } - } - - plot.getDomainAxis().setLabel(getLabel(domainType, domainUnit)); - plot.addDomainMarker(new ValueMarker(0)); - plot.addRangeMarker(new ValueMarker(0)); - - - // Create the dialog - //// Simulation results - final JDialog dialog = new JDialog(this, trans.get("simedtdlg.dlg.Simres")); - dialog.setModalityType(ModalityType.DOCUMENT_MODAL); - - JPanel panel = new JPanel(new MigLayout("fill")); - dialog.add(panel); - - ChartPanel chartPanel = new ChartPanel(chart, - false, // properties - true, // save - false, // print - true, // zoom - true); // tooltips - chartPanel.setMouseWheelEnabled(true); - chartPanel.setEnforceFileExtensions(true); - chartPanel.setInitialDelay(500); - - chartPanel.setBorder(BorderFactory.createLineBorder(Color.GRAY, 1)); - - panel.add(chartPanel, "grow, wrap 20lp"); - - //// Close button - JButton button = new JButton(trans.get("dlg.but.close")); - button.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - dialog.setVisible(false); - } - }); - panel.add(button, "right"); - - dialog.setLocationByPlatform(true); - dialog.pack(); - - GUIUtil.setDisposableDialogOptions(dialog, button); - - dialog.setVisible(true); - } - - private class PresetNumberAxis extends NumberAxis { - private final double min; - private final double max; - - public PresetNumberAxis(double min, double max) { - this.min = min; - this.max = max; - autoAdjustRange(); - } - - @Override - protected void autoAdjustRange() { - this.setRange(min, max); - } - } - - - private String getLabel(FlightDataType type, Unit unit) { - String name = type.getName(); - if (unit != null && !UnitGroup.UNITS_NONE.contains(unit) && - !UnitGroup.UNITS_COEFFICIENT.contains(unit) && unit.getUnit().length() > 0) - name += " (" + unit.getUnit() + ")"; - return name; - } - - - private class ListenerCellRenderer extends JLabel implements ListCellRenderer { @Override diff --git a/core/src/net/sf/openrocket/gui/simulation/SimulationExportPanel.java b/core/src/net/sf/openrocket/gui/simulation/SimulationExportPanel.java new file mode 100644 index 000000000..08a7b8678 --- /dev/null +++ b/core/src/net/sf/openrocket/gui/simulation/SimulationExportPanel.java @@ -0,0 +1,436 @@ +package net.sf.openrocket.gui.simulation; + +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.util.Arrays; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JFileChooser; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.SwingUtilities; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; +import javax.swing.table.TableColumnModel; + +import net.miginfocom.swing.MigLayout; +import net.sf.openrocket.document.Simulation; +import net.sf.openrocket.gui.components.CsvOptionPanel; +import net.sf.openrocket.gui.components.UnitCellEditor; +import net.sf.openrocket.gui.util.FileHelper; +import net.sf.openrocket.gui.util.GUIUtil; +import net.sf.openrocket.gui.util.SaveCSVWorker; +import net.sf.openrocket.gui.util.SwingPreferences; +import net.sf.openrocket.l10n.Translator; +import net.sf.openrocket.simulation.FlightData; +import net.sf.openrocket.simulation.FlightDataBranch; +import net.sf.openrocket.simulation.FlightDataType; +import net.sf.openrocket.startup.Application; +import net.sf.openrocket.unit.Unit; +import net.sf.openrocket.unit.UnitGroup; + +public class SimulationExportPanel extends JPanel { + + private static final String SPACE = "SPACE"; + private static final String TAB = "TAB"; + private static final Translator trans = Application.getTranslator(); + + private static final int OPTION_SIMULATION_COMMENTS = 0; + private static final int OPTION_FIELD_DESCRIPTIONS = 1; + private static final int OPTION_FLIGHT_EVENTS = 2; + + private final JTable table; + private final SelectionTableModel tableModel; + private final JLabel selectedCountLabel; + + private final Simulation simulation; + private final FlightDataBranch branch; + + private final boolean[] selected; + private final FlightDataType[] types; + private final Unit[] units; + + private final CsvOptionPanel csvOptions; + + + public SimulationExportPanel(Simulation sim) { + super(new MigLayout("fill, flowy")); + + JPanel panel; + JButton button; + + + this.simulation = sim; + + // TODO: MEDIUM: Only exports primary branch + + final FlightData data = simulation.getSimulatedData(); + + // Check that data exists + if (data == null || data.getBranchCount() == 0 || + data.getBranch(0).getTypes().length == 0) { + throw new IllegalArgumentException("No data for panel"); + } + + + // Create the data model + branch = data.getBranch(0); + + types = branch.getTypes(); + Arrays.sort(types); + + selected = new boolean[types.length]; + units = new Unit[types.length]; + for (int i = 0; i < types.length; i++) { + selected[i] = ((SwingPreferences) Application.getPreferences()).isExportSelected(types[i]); + units[i] = types[i].getUnitGroup().getDefaultUnit(); + } + + + //// Create the panel + + + // Set up the variable selection table + tableModel = new SelectionTableModel(); + table = new JTable(tableModel); + table.setDefaultRenderer(Object.class, + new SelectionBackgroundCellRenderer(table.getDefaultRenderer(Object.class))); + table.setDefaultRenderer(Boolean.class, + new SelectionBackgroundCellRenderer(table.getDefaultRenderer(Boolean.class))); + table.setRowSelectionAllowed(false); + table.setColumnSelectionAllowed(false); + + table.setDefaultEditor(Unit.class, new UnitCellEditor() { + @Override + protected UnitGroup getUnitGroup(Unit value, int row, int column) { + return types[row].getUnitGroup(); + } + }); + + // Set column widths + TableColumnModel columnModel = table.getColumnModel(); + TableColumn col = columnModel.getColumn(0); + int w = table.getRowHeight(); + col.setMinWidth(w); + col.setPreferredWidth(w); + col.setMaxWidth(w); + + col = columnModel.getColumn(1); + col.setPreferredWidth(200); + + col = columnModel.getColumn(2); + col.setPreferredWidth(100); + + table.addMouseListener(new GUIUtil.BooleanTableClickListener(table)); + + // Add table + panel = new JPanel(new MigLayout("fill")); + panel.setBorder(BorderFactory.createTitledBorder(trans.get("SimExpPan.border.Vartoexport"))); + + panel.add(new JScrollPane(table), "wmin 300lp, width 300lp, height 1, grow 100, wrap"); + + // Select all/none buttons + button = new JButton(trans.get("SimExpPan.but.Selectall")); + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + tableModel.selectAll(); + } + }); + panel.add(button, "split 2, growx 1, sizegroup selectbutton"); + + button = new JButton(trans.get("SimExpPan.but.Selectnone")); + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + tableModel.selectNone(); + } + }); + panel.add(button, "growx 1, sizegroup selectbutton, wrap"); + + + selectedCountLabel = new JLabel(); + updateSelectedCount(); + panel.add(selectedCountLabel); + + this.add(panel, "grow 100, wrap"); + + + // These need to be in the order of the OPTIONS_XXX indices + csvOptions = new CsvOptionPanel(SimulationExportPanel.class, + trans.get("SimExpPan.checkbox.Includesimudesc"), + trans.get("SimExpPan.checkbox.ttip.Includesimudesc"), + trans.get("SimExpPan.checkbox.Includefielddesc"), + trans.get("SimExpPan.checkbox.ttip.Includefielddesc"), + trans.get("SimExpPan.checkbox.Incflightevents"), + trans.get("SimExpPan.checkbox.ttip.Incflightevents")); + + this.add(csvOptions, "spany, split, growx 1"); + + + // Space-filling panel + panel = new JPanel(); + this.add(panel, "width 1, height 1, grow 1"); + + /* + // Export button + button = new JButton(trans.get("SimExpPan.but.Exporttofile")); + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + doExport(); + } + }); + this.add(button, "gapbottom para, gapright para, right"); + */ + } + + + public boolean doExport() { + JFileChooser chooser = new JFileChooser(); + chooser.setFileFilter(FileHelper.CSV_FILE_FILTER); + chooser.setCurrentDirectory(((SwingPreferences) Application.getPreferences()).getDefaultDirectory()); + + if (chooser.showSaveDialog(this) != JFileChooser.APPROVE_OPTION) + return false; + + File file = chooser.getSelectedFile(); + if (file == null) + return false; + + file = FileHelper.ensureExtension(file, "csv"); + if (!FileHelper.confirmWrite(file, this)) { + return false; + } + + + String commentChar = csvOptions.getCommentCharacter(); + String fieldSep = csvOptions.getFieldSeparator(); + boolean simulationComment = csvOptions.getSelectionOption(OPTION_SIMULATION_COMMENTS); + boolean fieldComment = csvOptions.getSelectionOption(OPTION_FIELD_DESCRIPTIONS); + boolean eventComment = csvOptions.getSelectionOption(OPTION_FLIGHT_EVENTS); + csvOptions.storePreferences(); + + // Store preferences and export + int n = 0; + ((SwingPreferences) Application.getPreferences()).setDefaultDirectory(chooser.getCurrentDirectory()); + for (int i = 0; i < selected.length; i++) { + ((SwingPreferences) Application.getPreferences()).setExportSelected(types[i], selected[i]); + if (selected[i]) + n++; + } + + + FlightDataType[] fieldTypes = new FlightDataType[n]; + Unit[] fieldUnits = new Unit[n]; + int pos = 0; + for (int i = 0; i < selected.length; i++) { + if (selected[i]) { + fieldTypes[pos] = types[i]; + fieldUnits[pos] = units[i]; + pos++; + } + } + + if (fieldSep.equals(SPACE)) { + fieldSep = " "; + } else if (fieldSep.equals(TAB)) { + fieldSep = "\t"; + } + + + SaveCSVWorker.export(file, simulation, branch, fieldTypes, fieldUnits, fieldSep, + commentChar, simulationComment, fieldComment, eventComment, + SwingUtilities.getWindowAncestor(this)); + + return true; + } + + + private void updateSelectedCount() { + int total = selected.length; + int n = 0; + String str; + + for (int i = 0; i < selected.length; i++) { + if (selected[i]) + n++; + } + + if (n == 1) { + //// Exporting 1 variable out of + str = trans.get("SimExpPan.ExportingVar.desc1") + " " + total + "."; + } else { + //// Exporting + //// variables out of + str = trans.get("SimExpPan.ExportingVar.desc2") + " " + n + " " + + trans.get("SimExpPan.ExportingVar.desc3") + " " + total + "."; + } + + selectedCountLabel.setText(str); + } + + + + /** + * A table cell renderer that uses another renderer and sets the background and + * foreground of the returned component based on the selection of the variable. + */ + private class SelectionBackgroundCellRenderer implements TableCellRenderer { + + private final TableCellRenderer renderer; + + public SelectionBackgroundCellRenderer(TableCellRenderer renderer) { + this.renderer = renderer; + } + + @Override + public Component getTableCellRendererComponent(JTable myTable, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + + Component component = renderer.getTableCellRendererComponent(myTable, + value, isSelected, hasFocus, row, column); + + if (selected[row]) { + component.setBackground(myTable.getSelectionBackground()); + component.setForeground(myTable.getSelectionForeground()); + } else { + component.setBackground(myTable.getBackground()); + component.setForeground(myTable.getForeground()); + } + + return component; + } + + } + + + /** + * The table model for the variable selection. + */ + private class SelectionTableModel extends AbstractTableModel { + private static final int SELECTED = 0; + private static final int NAME = 1; + private static final int UNIT = 2; + + @Override + public int getColumnCount() { + return 3; + } + + @Override + public int getRowCount() { + return types.length; + } + + @Override + public String getColumnName(int column) { + switch (column) { + case SELECTED: + return ""; + case NAME: + //// Variable + return trans.get("SimExpPan.Col.Variable"); + case UNIT: + //// Unit + return trans.get("SimExpPan.Col.Unit"); + default: + throw new IndexOutOfBoundsException("column=" + column); + } + + } + + @Override + public Class getColumnClass(int column) { + switch (column) { + case SELECTED: + return Boolean.class; + case NAME: + return FlightDataType.class; + case UNIT: + return Unit.class; + default: + throw new IndexOutOfBoundsException("column=" + column); + } + } + + @Override + public Object getValueAt(int row, int column) { + + switch (column) { + case SELECTED: + return selected[row]; + + case NAME: + return types[row]; + + case UNIT: + return units[row]; + + default: + throw new IndexOutOfBoundsException("column=" + column); + } + + } + + @Override + public void setValueAt(Object value, int row, int column) { + + switch (column) { + case SELECTED: + selected[row] = (Boolean) value; + this.fireTableRowsUpdated(row, row); + updateSelectedCount(); + break; + + case NAME: + break; + + case UNIT: + units[row] = (Unit) value; + break; + + default: + throw new IndexOutOfBoundsException("column=" + column); + } + + } + + @Override + public boolean isCellEditable(int row, int column) { + switch (column) { + case SELECTED: + return true; + + case NAME: + return false; + + case UNIT: + return types[row].getUnitGroup().getUnitCount() > 1; + + default: + throw new IndexOutOfBoundsException("column=" + column); + } + } + + public void selectAll() { + Arrays.fill(selected, true); + updateSelectedCount(); + this.fireTableDataChanged(); + } + + public void selectNone() { + Arrays.fill(selected, false); + updateSelectedCount(); + this.fireTableDataChanged(); + } + + } + +} diff --git a/core/src/net/sf/openrocket/gui/simulation/SimulationPlotExportDialog.java b/core/src/net/sf/openrocket/gui/simulation/SimulationPlotExportDialog.java new file mode 100644 index 000000000..e145dc2b7 --- /dev/null +++ b/core/src/net/sf/openrocket/gui/simulation/SimulationPlotExportDialog.java @@ -0,0 +1,137 @@ +package net.sf.openrocket.gui.simulation; + +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.JTextField; + +import net.miginfocom.swing.MigLayout; +import net.sf.openrocket.document.OpenRocketDocument; +import net.sf.openrocket.document.Simulation; +import net.sf.openrocket.gui.util.GUIUtil; +import net.sf.openrocket.l10n.Translator; +import net.sf.openrocket.rocketcomponent.Configuration; +import net.sf.openrocket.simulation.FlightData; +import net.sf.openrocket.simulation.SimulationOptions; +import net.sf.openrocket.startup.Application; + +public class SimulationPlotExportDialog extends JDialog { + + private final Window parentWindow; + private final Simulation simulation; + private final OpenRocketDocument document; + private final SimulationOptions conditions; + private final Configuration configuration; + private static final Translator trans = Application.getTranslator(); + + public SimulationPlotExportDialog(Window parent, OpenRocketDocument document, Simulation s) { + //// Plot/Export simulation + super(parent, trans.get("simedtdlg.title.Editsim"), JDialog.ModalityType.DOCUMENT_MODAL); + this.document = document; + this.parentWindow = parent; + this.simulation = s; + this.conditions = simulation.getOptions(); + configuration = simulation.getConfiguration(); + + JPanel mainPanel = new JPanel(new MigLayout("fill", "[grow]")); + + //// Simulation name: + mainPanel.add(new JLabel(trans.get("simedtdlg.lbl.Simname") + " "), "span, split 2, shrink"); + final JTextField field = new JTextField(simulation.getName()); + field.setEditable(false); + mainPanel.add(field, "shrinky, growx, wrap"); + + final JTabbedPane tabbedPane = new JTabbedPane(); + + //// Plot data + final SimulationPlotPanel plotTab = plotTab(); + tabbedPane.addTab(trans.get("simedtdlg.tab.Plotdata"), plotTab); + //// Export data + final SimulationExportPanel exportTab = exportTab(); + tabbedPane.addTab(trans.get("simedtdlg.tab.Exportdata"), exportTab); + + mainPanel.add(tabbedPane, "grow, wrap"); + + JButton ok = new JButton(trans.get("dlg.but.ok")); + ok.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + + if (tabbedPane.getSelectedIndex() == 0) { + JDialog plot = plotTab.doPlot(); + if (plot != null) { + SimulationPlotExportDialog.this.dispose(); + plot.setVisible(true); + } + } else { + if (exportTab.doExport()) { + SimulationPlotExportDialog.this.dispose(); + } + } + } + }); + mainPanel.add(ok, "tag ok, split 2"); + + //// Close button + JButton close = new JButton(trans.get("dlg.but.close")); + close.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + SimulationPlotExportDialog.this.dispose(); + } + }); + mainPanel.add(close, "tag cancel"); + + + this.add(mainPanel); + this.validate(); + this.pack(); + this.setLocationByPlatform(true); + + GUIUtil.setDisposableDialogOptions(this, close); + + } + + + /** + * A panel for plotting the previously calculated data. + */ + private SimulationPlotPanel plotTab() { + + // Check that data exists + // FIXME - + /* + if (simulation.getSimulatedData() == null || + simulation.getSimulatedData().getBranchCount() == 0) { + return noDataPanel(); + } + */ + return new SimulationPlotPanel(simulation); + } + + /** + * A panel for exporting the data. + */ + private SimulationExportPanel exportTab() { + FlightData data = simulation.getSimulatedData(); + + // Check that data exists + // FIXME - + /* + if (data == null || data.getBranchCount() == 0 || + data.getBranch(0).getTypes().length == 0) { + return noDataPanel(); + } + */ + return new SimulationExportPanel(simulation); + } + + + +} diff --git a/core/src/net/sf/openrocket/gui/plot/SimulationPlotPanel.java b/core/src/net/sf/openrocket/gui/simulation/SimulationPlotPanel.java similarity index 95% rename from core/src/net/sf/openrocket/gui/plot/SimulationPlotPanel.java rename to core/src/net/sf/openrocket/gui/simulation/SimulationPlotPanel.java index 5a8787b28..dfac15d55 100644 --- a/core/src/net/sf/openrocket/gui/plot/SimulationPlotPanel.java +++ b/core/src/net/sf/openrocket/gui/simulation/SimulationPlotPanel.java @@ -1,5 +1,6 @@ -package net.sf.openrocket.gui.plot; +package net.sf.openrocket.gui.simulation; +import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; @@ -10,6 +11,7 @@ import java.util.EnumSet; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JComboBox; +import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; @@ -24,6 +26,8 @@ import net.miginfocom.swing.MigLayout; import net.sf.openrocket.document.Simulation; import net.sf.openrocket.gui.components.DescriptionArea; import net.sf.openrocket.gui.components.UnitSelector; +import net.sf.openrocket.gui.plot.PlotConfiguration; +import net.sf.openrocket.gui.plot.SimulationPlotDialog; import net.sf.openrocket.gui.util.GUIUtil; import net.sf.openrocket.gui.util.Icons; import net.sf.openrocket.l10n.Translator; @@ -213,7 +217,7 @@ public class SimulationPlotPanel extends JPanel { col0.setPreferredWidth(w); col0.setMaxWidth(w); table.addMouseListener(new GUIUtil.BooleanTableClickListener(table)); - this.add(new JScrollPane(table), "height 10px, width 200lp, grow 1, wrap rel"); + this.add(new JScrollPane(table), "height 200px, width 200lp, grow 1, wrap rel"); //// All + None buttons @@ -294,6 +298,7 @@ public class SimulationPlotPanel extends JPanel { this.add(new JPanel(), "growx"); + /* //// Plot flight button = new JButton(trans.get("simplotpanel.but.Plotflight")); button.addActionListener(new ActionListener() { @@ -312,10 +317,22 @@ public class SimulationPlotPanel extends JPanel { } }); this.add(button, "right"); - + */ updatePlots(); } + public JDialog doPlot() { + if (configuration.getTypeCount() == 0) { + JOptionPane.showMessageDialog(SimulationPlotPanel.this, + trans.get("error.noPlotSelected"), + trans.get("error.noPlotSelected.title"), + JOptionPane.ERROR_MESSAGE); + return null; + } + defaultConfiguration = configuration.clone(); + return SimulationPlotDialog.getPlot((Window) SwingUtilities.getRoot(SimulationPlotPanel.this), + simulation, configuration); + } private void setConfiguration(PlotConfiguration conf) { diff --git a/core/src/net/sf/openrocket/gui/main/SimulationRunDialog.java b/core/src/net/sf/openrocket/gui/simulation/SimulationRunDialog.java similarity index 99% rename from core/src/net/sf/openrocket/gui/main/SimulationRunDialog.java rename to core/src/net/sf/openrocket/gui/simulation/SimulationRunDialog.java index 25bb169c1..ca8b49b0f 100644 --- a/core/src/net/sf/openrocket/gui/main/SimulationRunDialog.java +++ b/core/src/net/sf/openrocket/gui/simulation/SimulationRunDialog.java @@ -1,4 +1,4 @@ -package net.sf.openrocket.gui.main; +package net.sf.openrocket.gui.simulation; import java.awt.Dialog; diff --git a/core/src/net/sf/openrocket/gui/simulation/SimulationWarningDialog.java b/core/src/net/sf/openrocket/gui/simulation/SimulationWarningDialog.java new file mode 100644 index 000000000..45a9bfa80 --- /dev/null +++ b/core/src/net/sf/openrocket/gui/simulation/SimulationWarningDialog.java @@ -0,0 +1,32 @@ +package net.sf.openrocket.gui.simulation; + +import java.awt.Component; +import java.util.ArrayList; + +import javax.swing.JOptionPane; + +import net.sf.openrocket.aerodynamics.Warning; +import net.sf.openrocket.document.Simulation; +import net.sf.openrocket.gui.dialogs.DetailDialog; +import net.sf.openrocket.l10n.Translator; +import net.sf.openrocket.startup.Application; + +public class SimulationWarningDialog { + + private static final Translator trans = Application.getTranslator(); + + public static void showWarningDialog(Component parent, Simulation simulation) { + + if (simulation.getSimulatedWarnings().size() > 0) { + ArrayList messages = new ArrayList(); + messages.add(trans.get("SimuRunDlg.msg.errorOccurred")); + for (Warning m : simulation.getSimulatedWarnings()) { + messages.add(m.toString()); + } + DetailDialog.showDetailedMessageDialog(parent, + messages.toArray(), + null, simulation.getName(), JOptionPane.ERROR_MESSAGE); + } + + } +} diff --git a/core/src/net/sf/openrocket/gui/main/SimulationWorker.java b/core/src/net/sf/openrocket/gui/simulation/SimulationWorker.java similarity index 97% rename from core/src/net/sf/openrocket/gui/main/SimulationWorker.java rename to core/src/net/sf/openrocket/gui/simulation/SimulationWorker.java index f348fbcdb..659b6b429 100644 --- a/core/src/net/sf/openrocket/gui/main/SimulationWorker.java +++ b/core/src/net/sf/openrocket/gui/simulation/SimulationWorker.java @@ -1,4 +1,4 @@ -package net.sf.openrocket.gui.main; +package net.sf.openrocket.gui.simulation; import java.util.Arrays; @@ -53,6 +53,7 @@ public abstract class SimulationWorker extends SwingWorker { /** * The rocket begins to tumble. */ - TUMBLE(trans.get("FlightEvent.Type.TUMBLE")); + TUMBLE(trans.get("FlightEvent.Type.TUMBLE")), + + /** + * Simulation aborted + */ + EXCEPTION(trans.get("FlightEvent.Type.EXCEPTION")); private final String name; diff --git a/core/src/net/sf/openrocket/simulation/SimulationOptions.java b/core/src/net/sf/openrocket/simulation/SimulationOptions.java index d47389b0d..dbbfbd19c 100644 --- a/core/src/net/sf/openrocket/simulation/SimulationOptions.java +++ b/core/src/net/sf/openrocket/simulation/SimulationOptions.java @@ -452,6 +452,25 @@ public class SimulationOptions implements ChangeSource, Cloneable { fireChangeEvent(); } + public void copyConditionsFrom(SimulationOptions src) { + + this.launchAltitude = src.launchAltitude; + this.launchLatitude = src.launchLatitude; + this.launchLongitude = src.launchLongitude; + this.launchPressure = src.launchPressure; + this.launchRodAngle = src.launchRodAngle; + this.launchRodDirection = src.launchRodDirection; + this.launchRodLength = src.launchRodLength; + this.launchTemperature = src.launchTemperature; + this.maximumAngle = src.maximumAngle; + this.timeStep = src.timeStep; + this.windAverage = src.windAverage; + this.windTurbulence = src.windTurbulence; + this.calculateExtras = src.calculateExtras; + this.randomSeed = src.randomSeed; + + fireChangeEvent(); + } /** diff --git a/core/src/net/sf/openrocket/simulation/SimulationStepper.java b/core/src/net/sf/openrocket/simulation/SimulationStepper.java index 90855c3cb..f218f387e 100644 --- a/core/src/net/sf/openrocket/simulation/SimulationStepper.java +++ b/core/src/net/sf/openrocket/simulation/SimulationStepper.java @@ -11,7 +11,7 @@ public interface SimulationStepper { * @param status the current simulation status. * @return a SimulationStatus suitable for simulating with this simulation stepper. */ - public SimulationStatus initialize(SimulationStatus status) throws SimulationException; + public SimulationStatus initialize(SimulationStatus status); /** * Perform one simulation time step. From f19044f08d3073996bd46d874602f90decd9e35b Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Thu, 23 May 2013 12:08:03 -0500 Subject: [PATCH 02/14] Make exceptions show up in plots. Use the exception text in the warnings. --- .../sf/openrocket/aerodynamics/Warning.java | 119 +++++++++--------- .../gui/plot/PlotConfiguration.java | 8 ++ .../gui/plot/SimulationPlotDialog.java | 2 +- .../gui/simulation/SimulationRunDialog.java | 1 + .../BasicEventSimulationEngine.java | 2 +- 5 files changed, 69 insertions(+), 63 deletions(-) diff --git a/core/src/net/sf/openrocket/aerodynamics/Warning.java b/core/src/net/sf/openrocket/aerodynamics/Warning.java index b06876c22..72df1ec49 100644 --- a/core/src/net/sf/openrocket/aerodynamics/Warning.java +++ b/core/src/net/sf/openrocket/aerodynamics/Warning.java @@ -8,7 +8,7 @@ import net.sf.openrocket.unit.UnitGroup; public abstract class Warning { private static final Translator trans = Application.getTranslator(); - + /** * Return a Warning with the specific text. */ @@ -36,8 +36,8 @@ public abstract class Warning { */ @Override public boolean equals(Object o) { - return o != null && (o.getClass() == this.getClass()); - } + return o != null && (o.getClass() == this.getClass()); + } /** * A hashCode method compatible with the equals method. @@ -79,21 +79,21 @@ public abstract class Warning { return (trans.get("Warning.LargeAOA.str2") + UnitGroup.UNITS_ANGLE.getDefaultUnit().toString(aoa) + ")."); } - + @Override public boolean replaceBy(Warning other) { if (!(other instanceof LargeAOA)) return false; - LargeAOA o = (LargeAOA)other; - if (Double.isNaN(this.aoa)) // If this has value NaN then replace + LargeAOA o = (LargeAOA) other; + if (Double.isNaN(this.aoa)) // If this has value NaN then replace return true; return (o.aoa > this.aoa); } } public static class MissingMotor extends Warning { - + private Motor.Type type = null; private String manufacturer = null; private String designation = null; @@ -101,7 +101,7 @@ public abstract class Warning { private double diameter = Double.NaN; private double length = Double.NaN; private double delay = Double.NaN; - + @Override public String toString() { String str = "No motor with designation '" + designation + "'"; @@ -110,82 +110,82 @@ public abstract class Warning { str += " found."; return str; } - + public Motor.Type getType() { return type; } - - + + public void setType(Motor.Type type) { this.type = type; } - - + + public String getManufacturer() { return manufacturer; } - - + + public void setManufacturer(String manufacturer) { this.manufacturer = manufacturer; } - - + + public String getDesignation() { return designation; } - - + + public void setDesignation(String designation) { this.designation = designation; } - - + + public String getDigest() { return digest; } - - + + public void setDigest(String digest) { this.digest = digest; } - - + + public double getDiameter() { return diameter; } - - + + public void setDiameter(double diameter) { this.diameter = diameter; } - - + + public double getLength() { return length; } - - + + public void setLength(double length) { this.length = length; } - - + + public double getDelay() { return delay; } - - + + public void setDelay(double delay) { this.delay = delay; } - - + + @Override public boolean replaceBy(Warning other) { return false; } - + @Override public int hashCode() { final int prime = 31; @@ -206,7 +206,7 @@ public abstract class Warning { result = prime * result + ((type == null) ? 0 : type.hashCode()); return result; } - + @Override public boolean equals(Object obj) { if (this == obj) @@ -272,7 +272,7 @@ public abstract class Warning { if (!(other instanceof Other)) return false; - Other o = (Other)other; + Other o = (Other) other; return (o.description.equals(this.description)); } @@ -280,7 +280,7 @@ public abstract class Warning { public int hashCode() { return description.hashCode(); } - + @Override public boolean replaceBy(Warning other) { return false; @@ -289,43 +289,40 @@ public abstract class Warning { /** A Warning that the body diameter is discontinuous. */ -////Discontinuity in rocket body diameter. - public static final Warning DISCONTINUITY = - new Other(trans.get("Warning.DISCONTINUITY")); + ////Discontinuity in rocket body diameter. + public static final Warning DISCONTINUITY = + new Other(trans.get("Warning.DISCONTINUITY")); /** A Warning that the fins are thick compared to the rocket body. */ -////Thick fins may not be modeled accurately. + ////Thick fins may not be modeled accurately. public static final Warning THICK_FIN = - new Other(trans.get("Warning.THICK_FIN")); + new Other(trans.get("Warning.THICK_FIN")); /** A Warning that the fins have jagged edges. */ -////Jagged-edged fin predictions may be inaccurate. + ////Jagged-edged fin predictions may be inaccurate. public static final Warning JAGGED_EDGED_FIN = - new Other(trans.get("Warning.JAGGED_EDGED_FIN")); + new Other(trans.get("Warning.JAGGED_EDGED_FIN")); /** A Warning that simulation listeners have affected the simulation */ -////Listeners modified the flight simulation + ////Listeners modified the flight simulation public static final Warning LISTENERS_AFFECTED = - new Other(trans.get("Warning.LISTENERS_AFFECTED")); + new Other(trans.get("Warning.LISTENERS_AFFECTED")); -////Recovery device opened while motor still burning. + ////Recovery device opened while motor still burning. public static final Warning RECOVERY_DEPLOYMENT_WHILE_BURNING = - new Other(trans.get("Warning.RECOVERY_DEPLOYMENT_WHILE_BURNING")); + new Other(trans.get("Warning.RECOVERY_DEPLOYMENT_WHILE_BURNING")); //// Invalid parameter encountered, ignoring. public static final Warning FILE_INVALID_PARAMETER = - new Other(trans.get("Warning.FILE_INVALID_PARAMETER")); - + new Other(trans.get("Warning.FILE_INVALID_PARAMETER")); + public static final Warning PARALLEL_FINS = - new Other(trans.get("Warning.PARALLEL_FINS")); + new Other(trans.get("Warning.PARALLEL_FINS")); public static final Warning SUPERSONIC = - new Other(trans.get("Warning.SUPERSONIC")); - + new Other(trans.get("Warning.SUPERSONIC")); + public static final Warning RECOVERY_LAUNCH_ROD = - new Other(trans.get("Warning.RECOVERY_LAUNCH_ROD")); - - public static final Warning SIMULATION_EXCEPTION = - new Other("Exception during simulation"); + new Other(trans.get("Warning.RECOVERY_LAUNCH_ROD")); } diff --git a/core/src/net/sf/openrocket/gui/plot/PlotConfiguration.java b/core/src/net/sf/openrocket/gui/plot/PlotConfiguration.java index db604a1f2..8f1f455de 100644 --- a/core/src/net/sf/openrocket/gui/plot/PlotConfiguration.java +++ b/core/src/net/sf/openrocket/gui/plot/PlotConfiguration.java @@ -37,6 +37,7 @@ public class PlotConfiguration implements Cloneable { config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true); config.setEvent(FlightEvent.Type.GROUND_HIT, true); config.setEvent(FlightEvent.Type.TUMBLE, true); + config.setEvent(FlightEvent.Type.EXCEPTION, true); configs.add(config); //// Total motion vs. time @@ -51,6 +52,7 @@ public class PlotConfiguration implements Cloneable { config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true); config.setEvent(FlightEvent.Type.GROUND_HIT, true); config.setEvent(FlightEvent.Type.TUMBLE, true); + config.setEvent(FlightEvent.Type.EXCEPTION, true); configs.add(config); //// Flight side profile @@ -63,6 +65,7 @@ public class PlotConfiguration implements Cloneable { config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true); config.setEvent(FlightEvent.Type.GROUND_HIT, true); config.setEvent(FlightEvent.Type.TUMBLE, true); + config.setEvent(FlightEvent.Type.EXCEPTION, true); configs.add(config); //// Stability vs. time @@ -77,6 +80,7 @@ public class PlotConfiguration implements Cloneable { config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true); config.setEvent(FlightEvent.Type.GROUND_HIT, true); config.setEvent(FlightEvent.Type.TUMBLE, true); + config.setEvent(FlightEvent.Type.EXCEPTION, true); configs.add(config); //// Drag coefficients vs. Mach number @@ -86,6 +90,7 @@ public class PlotConfiguration implements Cloneable { config.addPlotDataType(FlightDataType.TYPE_FRICTION_DRAG_COEFF, 0); config.addPlotDataType(FlightDataType.TYPE_BASE_DRAG_COEFF, 0); config.addPlotDataType(FlightDataType.TYPE_PRESSURE_DRAG_COEFF, 0); + config.setEvent(FlightEvent.Type.EXCEPTION, true); configs.add(config); //// Roll characteristics @@ -102,6 +107,7 @@ public class PlotConfiguration implements Cloneable { config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true); config.setEvent(FlightEvent.Type.GROUND_HIT, true); config.setEvent(FlightEvent.Type.TUMBLE, true); + config.setEvent(FlightEvent.Type.EXCEPTION, true); configs.add(config); //// Angle of attack and orientation vs. time @@ -116,6 +122,7 @@ public class PlotConfiguration implements Cloneable { config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true); config.setEvent(FlightEvent.Type.GROUND_HIT, true); config.setEvent(FlightEvent.Type.TUMBLE, true); + config.setEvent(FlightEvent.Type.EXCEPTION, true); configs.add(config); //// Simulation time step and computation time @@ -129,6 +136,7 @@ public class PlotConfiguration implements Cloneable { config.setEvent(FlightEvent.Type.STAGE_SEPARATION, true); config.setEvent(FlightEvent.Type.GROUND_HIT, true); config.setEvent(FlightEvent.Type.TUMBLE, true); + config.setEvent(FlightEvent.Type.EXCEPTION, true); configs.add(config); DEFAULT_CONFIGURATIONS = configs.toArray(new PlotConfiguration[0]); diff --git a/core/src/net/sf/openrocket/gui/plot/SimulationPlotDialog.java b/core/src/net/sf/openrocket/gui/plot/SimulationPlotDialog.java index 95d18726b..d57563a1c 100644 --- a/core/src/net/sf/openrocket/gui/plot/SimulationPlotDialog.java +++ b/core/src/net/sf/openrocket/gui/plot/SimulationPlotDialog.java @@ -38,7 +38,7 @@ public class SimulationPlotDialog extends JDialog { private SimulationPlotDialog(Window parent, Simulation simulation, PlotConfiguration config) { //// Flight data plot super(parent, simulation.getName()); - this.setModalityType(ModalityType.MODELESS); + this.setModalityType(ModalityType.DOCUMENT_MODAL); final boolean initialShowPoints = Application.getPreferences().getBoolean(Preferences.PLOT_SHOW_POINTS, false); diff --git a/core/src/net/sf/openrocket/gui/simulation/SimulationRunDialog.java b/core/src/net/sf/openrocket/gui/simulation/SimulationRunDialog.java index ca8b49b0f..033dbb1e1 100644 --- a/core/src/net/sf/openrocket/gui/simulation/SimulationRunDialog.java +++ b/core/src/net/sf/openrocket/gui/simulation/SimulationRunDialog.java @@ -395,6 +395,7 @@ public class SimulationRunDialog extends JDialog { log.debug("Simulation done"); setSimulationProgress(1.0); updateProgress(); + SimulationWarningDialog.showWarningDialog(SimulationRunDialog.this, simulation); } diff --git a/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java b/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java index 6bfc7eaf5..1e7a395e3 100644 --- a/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java +++ b/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java @@ -224,7 +224,7 @@ public class BasicEventSimulationEngine implements SimulationEngine { SimulationListenerHelper.fireEndSimulation(status, e); // Add FlightEvent for Abort. status.getFlightData().addEvent(new FlightEvent(FlightEvent.Type.EXCEPTION, status.getSimulationTime(), status.getConfiguration().getRocket(), e.getLocalizedMessage())); - status.getWarnings().add(Warning.SIMULATION_EXCEPTION); + status.getWarnings().add(e.getLocalizedMessage()); } return status.getFlightData(); From 9107566b3828fb91fd7294043b43f91d42ef9a95 Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Thu, 23 May 2013 16:18:38 -0500 Subject: [PATCH 03/14] Fix bug where plotted series were not labelled correctly in the legend. --- core/src/net/sf/openrocket/gui/plot/SimulationPlot.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/net/sf/openrocket/gui/plot/SimulationPlot.java b/core/src/net/sf/openrocket/gui/plot/SimulationPlot.java index 05d2de63e..043617a51 100644 --- a/core/src/net/sf/openrocket/gui/plot/SimulationPlot.java +++ b/core/src/net/sf/openrocket/gui/plot/SimulationPlot.java @@ -153,7 +153,6 @@ public class SimulationPlot { Unit unit = filled.getUnit(i); int axis = filled.getAxis(i); String name = getLabel(type, unit); - this.legendItems.lineLabels.add(name); List seriesNames = Util.generateSeriesLabels(simulation); @@ -167,7 +166,7 @@ public class SimulationPlot { List plotx = thisBranch.get(domainType); List ploty = thisBranch.get(type); XYSeries series = new XYSeries(seriesNames.get(branchIndex) + ": " + name, false, true); - series.setDescription(thisBranch.getBranchName() + ": " + name); + series.setDescription(name); int pointCount = plotx.size(); for (int j = 0; j < pointCount; j++) { series.add(domainUnit.toUnit(plotx.get(j)), unit.toUnit(ploty.get(j))); @@ -250,6 +249,8 @@ public class SimulationPlot { } // Now we pull the colors for the legend. for (int j = 0; j < data[i].getSeriesCount(); j += branchCount) { + String name = data[i].getSeries(j).getDescription(); + this.legendItems.lineLabels.add(name); Paint linePaint = r.lookupSeriesPaint(j); this.legendItems.linePaints.add(linePaint); Shape itemShape = r.lookupSeriesShape(j); From 4716030d1b2d07a071e6a7bae2ed73dcb465eef4 Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Thu, 23 May 2013 16:19:56 -0500 Subject: [PATCH 04/14] Explicitly create the plot with a parent window so the configuration window can be dismissed automatically. --- .../SimulationPlotExportDialog.java | 51 +------- .../gui/simulation/SimulationPlotPanel.java | 122 +++++++++--------- 2 files changed, 63 insertions(+), 110 deletions(-) diff --git a/core/src/net/sf/openrocket/gui/simulation/SimulationPlotExportDialog.java b/core/src/net/sf/openrocket/gui/simulation/SimulationPlotExportDialog.java index e145dc2b7..252b6d27b 100644 --- a/core/src/net/sf/openrocket/gui/simulation/SimulationPlotExportDialog.java +++ b/core/src/net/sf/openrocket/gui/simulation/SimulationPlotExportDialog.java @@ -16,28 +16,19 @@ import net.sf.openrocket.document.OpenRocketDocument; import net.sf.openrocket.document.Simulation; import net.sf.openrocket.gui.util.GUIUtil; import net.sf.openrocket.l10n.Translator; -import net.sf.openrocket.rocketcomponent.Configuration; -import net.sf.openrocket.simulation.FlightData; -import net.sf.openrocket.simulation.SimulationOptions; import net.sf.openrocket.startup.Application; public class SimulationPlotExportDialog extends JDialog { private final Window parentWindow; private final Simulation simulation; - private final OpenRocketDocument document; - private final SimulationOptions conditions; - private final Configuration configuration; private static final Translator trans = Application.getTranslator(); public SimulationPlotExportDialog(Window parent, OpenRocketDocument document, Simulation s) { //// Plot/Export simulation super(parent, trans.get("simedtdlg.title.Editsim"), JDialog.ModalityType.DOCUMENT_MODAL); - this.document = document; this.parentWindow = parent; this.simulation = s; - this.conditions = simulation.getOptions(); - configuration = simulation.getConfiguration(); JPanel mainPanel = new JPanel(new MigLayout("fill", "[grow]")); @@ -50,10 +41,10 @@ public class SimulationPlotExportDialog extends JDialog { final JTabbedPane tabbedPane = new JTabbedPane(); //// Plot data - final SimulationPlotPanel plotTab = plotTab(); + final SimulationPlotPanel plotTab = new SimulationPlotPanel(simulation); tabbedPane.addTab(trans.get("simedtdlg.tab.Plotdata"), plotTab); //// Export data - final SimulationExportPanel exportTab = exportTab(); + final SimulationExportPanel exportTab = new SimulationExportPanel(simulation); tabbedPane.addTab(trans.get("simedtdlg.tab.Exportdata"), exportTab); mainPanel.add(tabbedPane, "grow, wrap"); @@ -64,7 +55,7 @@ public class SimulationPlotExportDialog extends JDialog { public void actionPerformed(ActionEvent e) { if (tabbedPane.getSelectedIndex() == 0) { - JDialog plot = plotTab.doPlot(); + JDialog plot = plotTab.doPlot(SimulationPlotExportDialog.this.parentWindow); if (plot != null) { SimulationPlotExportDialog.this.dispose(); plot.setVisible(true); @@ -98,40 +89,4 @@ public class SimulationPlotExportDialog extends JDialog { } - - /** - * A panel for plotting the previously calculated data. - */ - private SimulationPlotPanel plotTab() { - - // Check that data exists - // FIXME - - /* - if (simulation.getSimulatedData() == null || - simulation.getSimulatedData().getBranchCount() == 0) { - return noDataPanel(); - } - */ - return new SimulationPlotPanel(simulation); - } - - /** - * A panel for exporting the data. - */ - private SimulationExportPanel exportTab() { - FlightData data = simulation.getSimulatedData(); - - // Check that data exists - // FIXME - - /* - if (data == null || data.getBranchCount() == 0 || - data.getBranch(0).getTypes().length == 0) { - return noDataPanel(); - } - */ - return new SimulationExportPanel(simulation); - } - - - } diff --git a/core/src/net/sf/openrocket/gui/simulation/SimulationPlotPanel.java b/core/src/net/sf/openrocket/gui/simulation/SimulationPlotPanel.java index dfac15d55..40c3ebba2 100644 --- a/core/src/net/sf/openrocket/gui/simulation/SimulationPlotPanel.java +++ b/core/src/net/sf/openrocket/gui/simulation/SimulationPlotPanel.java @@ -1,6 +1,6 @@ package net.sf.openrocket.gui.simulation; -import java.awt.Window; +import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; @@ -11,13 +11,12 @@ import java.util.EnumSet; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JComboBox; -import javax.swing.JDialog; +import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; -import javax.swing.SwingUtilities; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; @@ -75,18 +74,18 @@ public class SimulationPlotPanel extends JPanel { PRESET_ARRAY[PRESET_ARRAY.length - 1] = CUSTOM_CONFIGURATION; } - - + + /** The current default configuration, set each time a plot is made. */ private static PlotConfiguration defaultConfiguration = PlotConfiguration.DEFAULT_CONFIGURATIONS[0].resetUnits(); - + private final Simulation simulation; private final FlightDataType[] types; private PlotConfiguration configuration; - + private JComboBox configurationSelector; private JComboBox domainTypeSelector; @@ -95,7 +94,7 @@ public class SimulationPlotPanel extends JPanel { private JPanel typeSelectorPanel; private FlightEventTableModel eventTableModel; - + private int modifying = 0; @@ -111,7 +110,7 @@ public class SimulationPlotPanel extends JPanel { types = branch.getTypes(); setConfiguration(defaultConfiguration); - + //// Configuration selector // Setup the combo box @@ -130,7 +129,7 @@ public class SimulationPlotPanel extends JPanel { // the UI when the selected item changes. // TODO - this should probably be implemented as an ActionListener instead // of ItemStateListener. - if ( e.getStateChange() == ItemEvent.DESELECTED) { + if (e.getStateChange() == ItemEvent.DESELECTED) { return; } if (modifying > 0) @@ -148,8 +147,8 @@ public class SimulationPlotPanel extends JPanel { this.add(new JLabel(trans.get("simplotpanel.lbl.Presetplotconf")), "spanx, split"); this.add(configurationSelector, "growx, wrap 20lp"); - - + + //// X axis //// X axis type: @@ -189,8 +188,8 @@ public class SimulationPlotPanel extends JPanel { desc.setViewportBorder(BorderFactory.createEmptyBorder()); this.add(desc, "width 1px, growx 1, wrap unrel"); - - + + //// Y axis selector panel //// Y axis types: this.add(new JLabel(trans.get("simplotpanel.lbl.Yaxistypes"))); @@ -201,7 +200,7 @@ public class SimulationPlotPanel extends JPanel { JScrollPane scroll = new JScrollPane(typeSelectorPanel); this.add(scroll, "spany 2, height 10px, wmin 400lp, grow 100, gapright para"); - + //// Flight events eventTableModel = new FlightEventTableModel(); JTable table = new JTable(eventTableModel); @@ -217,9 +216,9 @@ public class SimulationPlotPanel extends JPanel { col0.setPreferredWidth(w); col0.setMaxWidth(w); table.addMouseListener(new GUIUtil.BooleanTableClickListener(table)); - this.add(new JScrollPane(table), "height 200px, width 200lp, grow 1, wrap rel"); + this.add(new JScrollPane(table), "height 200px, width 200lp, grow 1, wrap rel"); + - //// All + None buttons JButton button = new JButton(trans.get("simplotpanel.but.All")); button.addActionListener(new ActionListener() { @@ -244,8 +243,8 @@ public class SimulationPlotPanel extends JPanel { }); this.add(button, "gapleft para, gapright para, growx, sizegroup buttons, wrap para"); - - + + //// New Y axis plot type button = new JButton(trans.get("simplotpanel.but.NewYaxisplottype")); button.addActionListener(new ActionListener() { @@ -264,41 +263,41 @@ public class SimulationPlotPanel extends JPanel { // Select new type smartly FlightDataType type = null; for (FlightDataType t : - simulation.getSimulatedData().getBranch(0).getTypes()) { - - boolean used = false; - if (configuration.getDomainAxisType().equals(t)) { - used = true; - } else { - for (int i = 0; i < configuration.getTypeCount(); i++) { - if (configuration.getType(i).equals(t)) { - used = true; - break; - } + simulation.getSimulatedData().getBranch(0).getTypes()) { + + boolean used = false; + if (configuration.getDomainAxisType().equals(t)) { + used = true; + } else { + for (int i = 0; i < configuration.getTypeCount(); i++) { + if (configuration.getType(i).equals(t)) { + used = true; + break; } } - - if (!used) { - type = t; - break; - } - } - if (type == null) { - type = simulation.getSimulatedData().getBranch(0).getTypes()[0]; } - // Add new type - configuration.addPlotDataType(type); - setToCustom(); - updatePlots(); + if (!used) { + type = t; + break; + } } + if (type == null) { + type = simulation.getSimulatedData().getBranch(0).getTypes()[0]; + } + + // Add new type + configuration.addPlotDataType(type); + setToCustom(); + updatePlots(); + } }); this.add(button, "spanx, split"); - + this.add(new JPanel(), "growx"); - /* + /* //// Plot flight button = new JButton(trans.get("simplotpanel.but.Plotflight")); button.addActionListener(new ActionListener() { @@ -317,22 +316,21 @@ public class SimulationPlotPanel extends JPanel { } }); this.add(button, "right"); - */ + */ updatePlots(); } - public JDialog doPlot() { - if (configuration.getTypeCount() == 0) { - JOptionPane.showMessageDialog(SimulationPlotPanel.this, - trans.get("error.noPlotSelected"), - trans.get("error.noPlotSelected.title"), - JOptionPane.ERROR_MESSAGE); - return null; - } - defaultConfiguration = configuration.clone(); - return SimulationPlotDialog.getPlot((Window) SwingUtilities.getRoot(SimulationPlotPanel.this), - simulation, configuration); - } + public JDialog doPlot(Window parent) { + if (configuration.getTypeCount() == 0) { + JOptionPane.showMessageDialog(SimulationPlotPanel.this, + trans.get("error.noPlotSelected"), + trans.get("error.noPlotSelected.title"), + JOptionPane.ERROR_MESSAGE); + return null; + } + defaultConfiguration = configuration.clone(); + return SimulationPlotDialog.getPlot(parent, simulation, configuration); + } private void setConfiguration(PlotConfiguration conf) { @@ -383,14 +381,14 @@ public class SimulationPlotPanel extends JPanel { // In order to consistantly update the ui, we need to validate before repaint. typeSelectorPanel.validate(); - typeSelectorPanel.repaint(); + typeSelectorPanel.repaint(); eventTableModel.fireTableDataChanged(); } - - + + /** * A JPanel which configures a single plot of a PlotConfiguration. */ @@ -460,7 +458,7 @@ public class SimulationPlotPanel extends JPanel { }); this.add(axisSelector); - + JButton button = new JButton(Icons.DELETE); //// Remove this plot button.setToolTipText(trans.get("simplotpanel.but.ttip.Removethisplot")); @@ -478,7 +476,7 @@ public class SimulationPlotPanel extends JPanel { } - + private class FlightEventTableModel extends AbstractTableModel { private final FlightEvent.Type[] eventTypes; From ff39e0ea63b00161a26f48d1f85161c0c209269c Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Fri, 24 May 2013 14:38:56 -0500 Subject: [PATCH 05/14] Don't dismiss the plot/export dialog when the plot is displayed. --- .../sf/openrocket/gui/simulation/SimulationPlotExportDialog.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/net/sf/openrocket/gui/simulation/SimulationPlotExportDialog.java b/core/src/net/sf/openrocket/gui/simulation/SimulationPlotExportDialog.java index 252b6d27b..a8b3c499b 100644 --- a/core/src/net/sf/openrocket/gui/simulation/SimulationPlotExportDialog.java +++ b/core/src/net/sf/openrocket/gui/simulation/SimulationPlotExportDialog.java @@ -57,7 +57,6 @@ public class SimulationPlotExportDialog extends JDialog { if (tabbedPane.getSelectedIndex() == 0) { JDialog plot = plotTab.doPlot(SimulationPlotExportDialog.this.parentWindow); if (plot != null) { - SimulationPlotExportDialog.this.dispose(); plot.setVisible(true); } } else { From 9a43a016635cac1eafe838587d6744837ccf09eb Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Fri, 24 May 2013 14:57:32 -0500 Subject: [PATCH 06/14] Don't display warning dialog when simulation ends. --- .../sf/openrocket/gui/simulation/SimulationRunDialog.java | 7 +++---- .../net/sf/openrocket/gui/simulation/SimulationWorker.java | 5 ++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/core/src/net/sf/openrocket/gui/simulation/SimulationRunDialog.java b/core/src/net/sf/openrocket/gui/simulation/SimulationRunDialog.java index 033dbb1e1..c770be0dc 100644 --- a/core/src/net/sf/openrocket/gui/simulation/SimulationRunDialog.java +++ b/core/src/net/sf/openrocket/gui/simulation/SimulationRunDialog.java @@ -23,9 +23,6 @@ import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JProgressBar; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import net.miginfocom.swing.MigLayout; import net.sf.openrocket.document.OpenRocketDocument; import net.sf.openrocket.document.Simulation; @@ -50,6 +47,9 @@ import net.sf.openrocket.unit.Unit; import net.sf.openrocket.unit.UnitGroup; import net.sf.openrocket.util.MathUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class SimulationRunDialog extends JDialog { private static final Logger log = LoggerFactory.getLogger(SimulationRunDialog.class); @@ -395,7 +395,6 @@ public class SimulationRunDialog extends JDialog { log.debug("Simulation done"); setSimulationProgress(1.0); updateProgress(); - SimulationWarningDialog.showWarningDialog(SimulationRunDialog.this, simulation); } diff --git a/core/src/net/sf/openrocket/gui/simulation/SimulationWorker.java b/core/src/net/sf/openrocket/gui/simulation/SimulationWorker.java index 659b6b429..201b4f22e 100644 --- a/core/src/net/sf/openrocket/gui/simulation/SimulationWorker.java +++ b/core/src/net/sf/openrocket/gui/simulation/SimulationWorker.java @@ -53,7 +53,6 @@ public abstract class SimulationWorker extends SwingWorker Date: Mon, 27 May 2013 16:54:09 -0500 Subject: [PATCH 07/14] Added buttons to the edit and plot dialogs to switch to the other one. --- .../sf/openrocket/document/Simulation.java | 16 ++++++++++- .../openrocket/gui/main/SimulationPanel.java | 2 +- .../gui/simulation/SimulationEditDialog.java | 27 +++++++++++++++---- .../SimulationPlotExportDialog.java | 18 +++++++++++-- 4 files changed, 54 insertions(+), 9 deletions(-) diff --git a/core/src/net/sf/openrocket/document/Simulation.java b/core/src/net/sf/openrocket/document/Simulation.java index ad3379b8a..39a97d930 100644 --- a/core/src/net/sf/openrocket/document/Simulation.java +++ b/core/src/net/sf/openrocket/document/Simulation.java @@ -374,7 +374,21 @@ public class Simulation implements ChangeSource, Cloneable { return simulatedData; } - + /** + * Return true if this simulation contains plotable flight data. + * + * @return + */ + public boolean hasSimulationData() { + FlightData data = getSimulatedData(); + if (data == null) { + return false; + } + if (data.getBranchCount() == 0) { + return false; + } + return true; + } /** * Returns a copy of this simulation suitable for cut/copy/paste operations. diff --git a/core/src/net/sf/openrocket/gui/main/SimulationPanel.java b/core/src/net/sf/openrocket/gui/main/SimulationPanel.java index aa27ebc3a..558ca9ef6 100644 --- a/core/src/net/sf/openrocket/gui/main/SimulationPanel.java +++ b/core/src/net/sf/openrocket/gui/main/SimulationPanel.java @@ -228,7 +228,7 @@ public class SimulationPanel extends JPanel { Simulation sim = document.getSimulations().get(selected); - if (sim.getSimulatedData() == null || sim.getSimulatedData().getBranchCount() == 0) { + if (!sim.hasSimulationData()) { new SimulationRunDialog(SwingUtilities.getWindowAncestor( SimulationPanel.this), document, sim).setVisible(true); } diff --git a/core/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java b/core/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java index ab05b176a..47634e048 100644 --- a/core/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java +++ b/core/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java @@ -149,11 +149,28 @@ public class SimulationEditDialog extends JDialog { mainPanel.add(tabbedPane, "spanx, grow, wrap"); - // Buttons - mainPanel.add(new JPanel(), "spanx, split, growx"); + //// Open Plot button + JButton button = new JButton("< Date: Thu, 30 May 2013 15:46:47 -0500 Subject: [PATCH 08/14] Consolidated the SimulationEditDialog and SimulationPlotExportDialog into a single dialog which uses CardLayout to switch between contents. The new SimulationEditDialog is pretty smart about when it can support the plot view and continues to support multi-edit. Double-click in the SimulationPanel is a little smarter - it opens either the dialog in plot mode when appropriate. Fixed but in SimulationPanel where the status icon was not updated after running a simulation when plot button is pressed. --- .../openrocket/gui/main/SimulationPanel.java | 12 +- .../simulation/SimulationConditionsPanel.java | 441 ++++++++ .../gui/simulation/SimulationEditDialog.java | 1008 ++++------------- .../simulation/SimulationOptionsPanel.java | 294 +++++ .../SimulationPlotExportDialog.java | 105 -- 5 files changed, 941 insertions(+), 919 deletions(-) create mode 100644 core/src/net/sf/openrocket/gui/simulation/SimulationConditionsPanel.java create mode 100644 core/src/net/sf/openrocket/gui/simulation/SimulationOptionsPanel.java delete mode 100644 core/src/net/sf/openrocket/gui/simulation/SimulationPlotExportDialog.java diff --git a/core/src/net/sf/openrocket/gui/main/SimulationPanel.java b/core/src/net/sf/openrocket/gui/main/SimulationPanel.java index 558ca9ef6..bdb8c501d 100644 --- a/core/src/net/sf/openrocket/gui/main/SimulationPanel.java +++ b/core/src/net/sf/openrocket/gui/main/SimulationPanel.java @@ -36,7 +36,6 @@ import net.sf.openrocket.gui.adaptors.Column; import net.sf.openrocket.gui.adaptors.ColumnTableModel; import net.sf.openrocket.gui.components.StyledLabel; import net.sf.openrocket.gui.simulation.SimulationEditDialog; -import net.sf.openrocket.gui.simulation.SimulationPlotExportDialog; import net.sf.openrocket.gui.simulation.SimulationRunDialog; import net.sf.openrocket.gui.simulation.SimulationWarningDialog; import net.sf.openrocket.gui.util.Icons; @@ -233,10 +232,10 @@ public class SimulationPanel extends JPanel { SimulationPanel.this), document, sim).setVisible(true); } - new SimulationPlotExportDialog(SwingUtilities.getWindowAncestor(SimulationPanel.this), document, sim) - .setVisible(true); fireMaintainSelection(); + openDialog(sim); + } }); this.add(plotButton, "wrap para"); @@ -502,7 +501,6 @@ public class SimulationPanel extends JPanel { simulationTable.clearSelection(); simulationTable.addRowSelectionInterval(selected, selected); - // FIXME - do we want to check to open plot dialog? openDialog(document.getSimulations().get(selected)); } } else { @@ -563,7 +561,11 @@ public class SimulationPanel extends JPanel { } private void openDialog(final Simulation... sims) { - new SimulationEditDialog(SwingUtilities.getWindowAncestor(this), document, sims).setVisible(true); + SimulationEditDialog d = new SimulationEditDialog(SwingUtilities.getWindowAncestor(this), document, sims); + if (sims.length == 1 && sims[0].hasSimulationData()) { + d.setPlotMode(); + } + d.setVisible(true); fireMaintainSelection(); } diff --git a/core/src/net/sf/openrocket/gui/simulation/SimulationConditionsPanel.java b/core/src/net/sf/openrocket/gui/simulation/SimulationConditionsPanel.java new file mode 100644 index 000000000..2839704b1 --- /dev/null +++ b/core/src/net/sf/openrocket/gui/simulation/SimulationConditionsPanel.java @@ -0,0 +1,441 @@ +package net.sf.openrocket.gui.simulation; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSpinner; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import net.miginfocom.swing.MigLayout; +import net.sf.openrocket.document.Simulation; +import net.sf.openrocket.gui.SpinnerEditor; +import net.sf.openrocket.gui.adaptors.BooleanModel; +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.l10n.Translator; +import net.sf.openrocket.models.atmosphere.ExtendedISAModel; +import net.sf.openrocket.simulation.DefaultSimulationOptionFactory; +import net.sf.openrocket.simulation.SimulationOptions; +import net.sf.openrocket.startup.Application; +import net.sf.openrocket.unit.UnitGroup; +import net.sf.openrocket.util.Chars; + +public class SimulationConditionsPanel extends JPanel { + private static final Translator trans = Application.getTranslator(); + + + SimulationConditionsPanel(final Simulation simulation) { + super(new MigLayout("fill")); + + final SimulationOptions conditions = simulation.getOptions(); + + JPanel sub; + String tip; + UnitSelector unit; + BasicSlider slider; + DoubleModel m; + JSpinner spin; + + //// Wind settings: Average wind speed, turbulence intensity, std. deviation + sub = new JPanel(new MigLayout("fill, gap rel unrel", + "[grow][65lp!][30lp!][75lp!]", "")); + //// Wind + sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.lbl.Wind"))); + this.add(sub, "growx, split 2, aligny 0, flowy, gapright para"); + + + // Wind average + //// Average windspeed: + JLabel label = new JLabel(trans.get("simedtdlg.lbl.Averwindspeed")); + //// The average windspeed relative to the ground. + tip = trans.get("simedtdlg.lbl.ttip.Averwindspeed"); + label.setToolTipText(tip); + sub.add(label); + + m = new DoubleModel(conditions, "WindSpeedAverage", UnitGroup.UNITS_WINDSPEED, 0); + + spin = new JSpinner(m.getSpinnerModel()); + spin.setEditor(new SpinnerEditor(spin)); + spin.setToolTipText(tip); + sub.add(spin, "w 65lp!"); + + unit = new UnitSelector(m); + unit.setToolTipText(tip); + sub.add(unit, "growx"); + slider = new BasicSlider(m.getSliderModel(0, 10.0)); + slider.setToolTipText(tip); + sub.add(slider, "w 75lp, wrap"); + + + + // Wind std. deviation + //// Standard deviation: + label = new JLabel(trans.get("simedtdlg.lbl.Stddeviation")); + //// The standard deviation of the windspeed.
+ //// The windspeed is within twice the standard deviation from the average for 95% of the time. + tip = trans.get("simedtdlg.lbl.ttip.Stddeviation"); + label.setToolTipText(tip); + sub.add(label); + + m = new DoubleModel(conditions, "WindSpeedDeviation", UnitGroup.UNITS_WINDSPEED, 0); + DoubleModel m2 = new DoubleModel(conditions, "WindSpeedAverage", 0.25, + UnitGroup.UNITS_COEFFICIENT, 0); + + spin = new JSpinner(m.getSpinnerModel()); + spin.setEditor(new SpinnerEditor(spin)); + spin.setToolTipText(tip); + sub.add(spin, "w 65lp!"); + + unit = new UnitSelector(m); + unit.setToolTipText(tip); + sub.add(unit, "growx"); + slider = new BasicSlider(m.getSliderModel(new DoubleModel(0), m2)); + slider.setToolTipText(tip); + sub.add(slider, "w 75lp, wrap"); + + + // Wind turbulence intensity + //// Turbulence intensity: + label = new JLabel(trans.get("simedtdlg.lbl.Turbulenceintensity")); + //// The turbulence intensity is the standard deviation divided by the average windspeed.
+ //// Typical values range from + //// to + tip = trans.get("simedtdlg.lbl.ttip.Turbulenceintensity1") + + trans.get("simedtdlg.lbl.ttip.Turbulenceintensity2") + " " + + UnitGroup.UNITS_RELATIVE.getDefaultUnit().toStringUnit(0.05) + + " " + trans.get("simedtdlg.lbl.ttip.Turbulenceintensity3") + " " + + UnitGroup.UNITS_RELATIVE.getDefaultUnit().toStringUnit(0.20) + "."; + label.setToolTipText(tip); + sub.add(label); + + m = new DoubleModel(conditions, "WindTurbulenceIntensity", UnitGroup.UNITS_RELATIVE, 0); + + spin = new JSpinner(m.getSpinnerModel()); + spin.setEditor(new SpinnerEditor(spin)); + spin.setToolTipText(tip); + sub.add(spin, "w 65lp!"); + + unit = new UnitSelector(m); + unit.setToolTipText(tip); + sub.add(unit, "growx"); + + final JLabel intensityLabel = new JLabel( + getIntensityDescription(conditions.getWindTurbulenceIntensity())); + intensityLabel.setToolTipText(tip); + sub.add(intensityLabel, "w 75lp, wrap"); + m.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + intensityLabel.setText( + getIntensityDescription(conditions.getWindTurbulenceIntensity())); + } + }); + + + + + + //// Temperature and pressure + sub = new JPanel(new MigLayout("fill, gap rel unrel", + "[grow][65lp!][30lp!][75lp!]", "")); + //// Atmospheric conditions + sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.border.Atmoscond"))); + this.add(sub, "growx, aligny 0, gapright para"); + + + BooleanModel isa = new BooleanModel(conditions, "ISAAtmosphere"); + JCheckBox check = new JCheckBox(isa); + //// Use International Standard Atmosphere + check.setText(trans.get("simedtdlg.checkbox.InterStdAtmosphere")); + //// Select to use the International Standard Atmosphere model. + ////
This model has a temperature of + //// and a pressure of + //// at sea level. + check.setToolTipText(trans.get("simedtdlg.checkbox.ttip.InterStdAtmosphere1") + " " + + UnitGroup.UNITS_TEMPERATURE.toStringUnit(ExtendedISAModel.STANDARD_TEMPERATURE) + + " " + trans.get("simedtdlg.checkbox.ttip.InterStdAtmosphere2") + " " + + UnitGroup.UNITS_PRESSURE.toStringUnit(ExtendedISAModel.STANDARD_PRESSURE) + + " " + trans.get("simedtdlg.checkbox.ttip.InterStdAtmosphere3")); + sub.add(check, "spanx, wrap unrel"); + + // Temperature: + label = new JLabel(trans.get("simedtdlg.lbl.Temperature")); + //// The temperature at the launch site. + tip = trans.get("simedtdlg.lbl.ttip.Temperature"); + label.setToolTipText(tip); + isa.addEnableComponent(label, false); + sub.add(label); + + m = new DoubleModel(conditions, "LaunchTemperature", UnitGroup.UNITS_TEMPERATURE, 0); + + spin = new JSpinner(m.getSpinnerModel()); + spin.setEditor(new SpinnerEditor(spin)); + spin.setToolTipText(tip); + isa.addEnableComponent(spin, false); + sub.add(spin, "w 65lp!"); + + unit = new UnitSelector(m); + unit.setToolTipText(tip); + isa.addEnableComponent(unit, false); + sub.add(unit, "growx"); + slider = new BasicSlider(m.getSliderModel(253.15, 308.15)); // -20 ... 35 + slider.setToolTipText(tip); + isa.addEnableComponent(slider, false); + sub.add(slider, "w 75lp, wrap"); + + + + // Pressure: + label = new JLabel(trans.get("simedtdlg.lbl.Pressure")); + //// The atmospheric pressure at the launch site. + tip = trans.get("simedtdlg.lbl.ttip.Pressure"); + label.setToolTipText(tip); + isa.addEnableComponent(label, false); + sub.add(label); + + m = new DoubleModel(conditions, "LaunchPressure", UnitGroup.UNITS_PRESSURE, 0); + + spin = new JSpinner(m.getSpinnerModel()); + spin.setEditor(new SpinnerEditor(spin)); + spin.setToolTipText(tip); + isa.addEnableComponent(spin, false); + sub.add(spin, "w 65lp!"); + + unit = new UnitSelector(m); + unit.setToolTipText(tip); + isa.addEnableComponent(unit, false); + sub.add(unit, "growx"); + slider = new BasicSlider(m.getSliderModel(0.950e5, 1.050e5)); + slider.setToolTipText(tip); + isa.addEnableComponent(slider, false); + sub.add(slider, "w 75lp, wrap"); + + + + + + //// Launch site conditions + sub = new JPanel(new MigLayout("fill, gap rel unrel", + "[grow][65lp!][30lp!][75lp!]", "")); + //// Launch site + sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.lbl.Launchsite"))); + this.add(sub, "growx, split 2, aligny 0, flowy"); + + + // Latitude: + label = new JLabel(trans.get("simedtdlg.lbl.Latitude")); + //// The launch site latitude affects the gravitational pull of Earth.
+ //// Positive values are on the Northern hemisphere, negative values on the Southern hemisphere. + tip = trans.get("simedtdlg.lbl.ttip.Latitude"); + label.setToolTipText(tip); + sub.add(label); + + m = new DoubleModel(conditions, "LaunchLatitude", UnitGroup.UNITS_NONE, -90, 90); + + spin = new JSpinner(m.getSpinnerModel()); + spin.setEditor(new SpinnerEditor(spin)); + spin.setToolTipText(tip); + sub.add(spin, "w 65lp!"); + + label = new JLabel(Chars.DEGREE + " N"); + label.setToolTipText(tip); + sub.add(label, "growx"); + slider = new BasicSlider(m.getSliderModel(-90, 90)); + slider.setToolTipText(tip); + sub.add(slider, "w 75lp, wrap"); + + + // Longitude: + label = new JLabel(trans.get("simedtdlg.lbl.Longitude")); + tip = trans.get("simedtdlg.lbl.ttip.Longitude"); + label.setToolTipText(tip); + sub.add(label); + + m = new DoubleModel(conditions, "LaunchLongitude", UnitGroup.UNITS_NONE, -180, 180); + + spin = new JSpinner(m.getSpinnerModel()); + spin.setEditor(new SpinnerEditor(spin)); + spin.setToolTipText(tip); + sub.add(spin, "w 65lp!"); + + label = new JLabel(Chars.DEGREE + " E"); + label.setToolTipText(tip); + sub.add(label, "growx"); + slider = new BasicSlider(m.getSliderModel(-180, 180)); + slider.setToolTipText(tip); + sub.add(slider, "w 75lp, wrap"); + + + // Altitude: + label = new JLabel(trans.get("simedtdlg.lbl.Altitude")); + //// The launch altitude above mean sea level.
+ //// This affects the position of the rocket in the atmospheric model. + tip = trans.get("simedtdlg.lbl.ttip.Altitude"); + label.setToolTipText(tip); + sub.add(label); + + m = new DoubleModel(conditions, "LaunchAltitude", UnitGroup.UNITS_DISTANCE, 0); + + spin = new JSpinner(m.getSpinnerModel()); + spin.setEditor(new SpinnerEditor(spin)); + spin.setToolTipText(tip); + sub.add(spin, "w 65lp!"); + + unit = new UnitSelector(m); + unit.setToolTipText(tip); + sub.add(unit, "growx"); + slider = new BasicSlider(m.getSliderModel(0, 250, 1000)); + slider.setToolTipText(tip); + sub.add(slider, "w 75lp, wrap"); + + + + + + //// Launch rod + sub = new JPanel(new MigLayout("fill, gap rel unrel", + "[grow][65lp!][30lp!][75lp!]", "")); + //// Launch rod + sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.border.Launchrod"))); + this.add(sub, "growx, aligny 0, wrap"); + + + // Length: + label = new JLabel(trans.get("simedtdlg.lbl.Length")); + //// The length of the launch rod. + tip = trans.get("simedtdlg.lbl.ttip.Length"); + label.setToolTipText(tip); + sub.add(label); + + m = new DoubleModel(conditions, "LaunchRodLength", UnitGroup.UNITS_LENGTH, 0); + + spin = new JSpinner(m.getSpinnerModel()); + spin.setEditor(new SpinnerEditor(spin)); + spin.setToolTipText(tip); + sub.add(spin, "w 65lp!"); + + unit = new UnitSelector(m); + unit.setToolTipText(tip); + sub.add(unit, "growx"); + slider = new BasicSlider(m.getSliderModel(0, 1, 5)); + slider.setToolTipText(tip); + sub.add(slider, "w 75lp, wrap"); + + + + // Angle: + label = new JLabel(trans.get("simedtdlg.lbl.Angle")); + //// The angle of the launch rod from vertical. + tip = trans.get("simedtdlg.lbl.ttip.Angle"); + label.setToolTipText(tip); + sub.add(label); + + m = new DoubleModel(conditions, "LaunchRodAngle", UnitGroup.UNITS_ANGLE, + 0, SimulationOptions.MAX_LAUNCH_ROD_ANGLE); + + spin = new JSpinner(m.getSpinnerModel()); + spin.setEditor(new SpinnerEditor(spin)); + spin.setToolTipText(tip); + sub.add(spin, "w 65lp!"); + + unit = new UnitSelector(m); + unit.setToolTipText(tip); + sub.add(unit, "growx"); + slider = new BasicSlider(m.getSliderModel(0, Math.PI / 9, + SimulationOptions.MAX_LAUNCH_ROD_ANGLE)); + slider.setToolTipText(tip); + sub.add(slider, "w 75lp, wrap"); + + + + // Direction: + label = new JLabel(trans.get("simedtdlg.lbl.Direction")); + //// Direction of the launch rod relative to the wind.
+ //// = towards the wind, + //// = downwind. + tip = trans.get("simedtdlg.lbl.ttip.Direction1") + + UnitGroup.UNITS_ANGLE.toStringUnit(0) + + " " + trans.get("simedtdlg.lbl.ttip.Direction2") + " " + + UnitGroup.UNITS_ANGLE.toStringUnit(Math.PI) + + " " + trans.get("simedtdlg.lbl.ttip.Direction3"); + label.setToolTipText(tip); + sub.add(label); + + m = new DoubleModel(conditions, "LaunchRodDirection", UnitGroup.UNITS_ANGLE, + -Math.PI, Math.PI); + + spin = new JSpinner(m.getSpinnerModel()); + spin.setEditor(new SpinnerEditor(spin)); + spin.setToolTipText(tip); + sub.add(spin, "w 65lp!"); + + unit = new UnitSelector(m); + unit.setToolTipText(tip); + sub.add(unit, "growx"); + slider = new BasicSlider(m.getSliderModel(-Math.PI, Math.PI)); + slider.setToolTipText(tip); + sub.add(slider, "w 75lp, wrap"); + + JButton restoreDefaults = new JButton(trans.get("simedtdlg.but.resettodefault")); + restoreDefaults.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + + DefaultSimulationOptionFactory f = Application.getInjector().getInstance(DefaultSimulationOptionFactory.class); + SimulationOptions defaults = f.getDefault(); + conditions.copyConditionsFrom(defaults); + + } + + }); + this.add(restoreDefaults, "span, split 3, skip, gapbottom para, gapright para, right"); + + JButton saveDefaults = new JButton(trans.get("simedtdlg.but.savedefault")); + saveDefaults.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + + DefaultSimulationOptionFactory f = Application.getInjector().getInstance(DefaultSimulationOptionFactory.class); + f.saveDefault(conditions); + + } + + }); + + this.add(saveDefaults, "gapbottom para, gapright para, right"); + + } + + private String getIntensityDescription(double i) { + if (i < 0.001) + //// None + return trans.get("simedtdlg.IntensityDesc.None"); + if (i < 0.05) + //// Very low + return trans.get("simedtdlg.IntensityDesc.Verylow"); + if (i < 0.10) + //// Low + return trans.get("simedtdlg.IntensityDesc.Low"); + if (i < 0.15) + //// Medium + return trans.get("simedtdlg.IntensityDesc.Medium"); + if (i < 0.20) + //// High + return trans.get("simedtdlg.IntensityDesc.High"); + if (i < 0.25) + //// Very high + return trans.get("simedtdlg.IntensityDesc.Veryhigh"); + //// Extreme + return trans.get("simedtdlg.IntensityDesc.Extreme"); + } + +} diff --git a/core/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java b/core/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java index 47634e048..9e16e1a02 100644 --- a/core/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java +++ b/core/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java @@ -1,59 +1,32 @@ package net.sf.openrocket.gui.simulation; -import java.awt.Component; +import java.awt.CardLayout; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.Arrays; -import javax.swing.AbstractListModel; -import javax.swing.BorderFactory; import javax.swing.JButton; -import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JDialog; import javax.swing.JLabel; -import javax.swing.JList; -import javax.swing.JOptionPane; import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JSpinner; import javax.swing.JTabbedPane; import javax.swing.JTextField; -import javax.swing.ListCellRenderer; import javax.swing.SwingUtilities; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import net.miginfocom.swing.MigLayout; import net.sf.openrocket.document.OpenRocketDocument; import net.sf.openrocket.document.Simulation; -import net.sf.openrocket.gui.SpinnerEditor; -import net.sf.openrocket.gui.adaptors.BooleanModel; -import net.sf.openrocket.gui.adaptors.DoubleModel; -import net.sf.openrocket.gui.adaptors.EnumModel; import net.sf.openrocket.gui.adaptors.FlightConfigurationModel; -import net.sf.openrocket.gui.components.BasicSlider; -import net.sf.openrocket.gui.components.DescriptionArea; -import net.sf.openrocket.gui.components.UnitSelector; import net.sf.openrocket.gui.dialogs.flightconfiguration.FlightConfigurationDialog; import net.sf.openrocket.gui.util.GUIUtil; -import net.sf.openrocket.gui.util.Icons; import net.sf.openrocket.l10n.Translator; -import net.sf.openrocket.models.atmosphere.ExtendedISAModel; import net.sf.openrocket.rocketcomponent.Configuration; -import net.sf.openrocket.simulation.DefaultSimulationOptionFactory; -import net.sf.openrocket.simulation.RK4SimulationStepper; import net.sf.openrocket.simulation.SimulationOptions; -import net.sf.openrocket.simulation.listeners.SimulationListener; -import net.sf.openrocket.simulation.listeners.example.CSVSaveListener; import net.sf.openrocket.startup.Application; -import net.sf.openrocket.unit.UnitGroup; -import net.sf.openrocket.util.Chars; -import net.sf.openrocket.util.GeodeticComputationStrategy; public class SimulationEditDialog extends JDialog { @@ -65,6 +38,32 @@ public class SimulationEditDialog extends JDialog { private final Configuration configuration; private static final Translator trans = Application.getTranslator(); + JPanel cards; + private final static String EDITMODE = "EDIT"; + private final static String PLOTMODE = "PLOT"; + + private boolean isSingleEdit() { + return simulation.length == 1; + } + + private boolean allowsPlotMode() { + return simulation.length == 1 && simulation[0].hasSimulationData(); + } + + public void setEditMode() { + CardLayout cl = (CardLayout) (cards.getLayout()); + cl.show(cards, EDITMODE); + cards.validate(); + } + + public void setPlotMode() { + if (!allowsPlotMode()) { + return; + } + CardLayout cl = (CardLayout) (cards.getLayout()); + cl.show(cards, PLOTMODE); + cards.validate(); + } public SimulationEditDialog(Window parent, OpenRocketDocument document, Simulation... sims) { //// Edit simulation @@ -75,130 +74,200 @@ public class SimulationEditDialog extends JDialog { this.conditions = simulation[0].getOptions(); configuration = simulation[0].getConfiguration(); - JPanel mainPanel = new JPanel(new MigLayout("")); - - if (sims.length == 1) { - //// Simulation name: - mainPanel.add(new JLabel(trans.get("simedtdlg.lbl.Simname") + " "), "shrink"); - final JTextField field = new JTextField(simulation[0].getName()); - field.getDocument().addDocumentListener(new DocumentListener() { - @Override - public void changedUpdate(DocumentEvent e) { - setText(); - } - - @Override - public void insertUpdate(DocumentEvent e) { - setText(); - } - - @Override - public void removeUpdate(DocumentEvent e) { - setText(); - } - - private void setText() { - String name = field.getText(); - if (name == null || name.equals("")) - return; - //System.out.println("Setting name:" + name); - simulation[0].setName(name); + this.cards = new JPanel(new CardLayout()); + this.add(cards); + { + JPanel simEditPanel = new JPanel(new MigLayout("fill")); + + if (isSingleEdit()) { + //// Simulation name: + simEditPanel.add(new JLabel(trans.get("simedtdlg.lbl.Simname") + " "), "shrink"); + final JTextField field = new JTextField(simulation[0].getName()); + field.getDocument().addDocumentListener(new DocumentListener() { + @Override + public void changedUpdate(DocumentEvent e) { + setText(); + } - } - }); - mainPanel.add(field, "shrinky, growx, wrap"); + @Override + public void insertUpdate(DocumentEvent e) { + setText(); + } + + @Override + public void removeUpdate(DocumentEvent e) { + setText(); + } + + private void setText() { + String name = field.getText(); + if (name == null || name.equals("")) + return; + //System.out.println("Setting name:" + name); + simulation[0].setName(name); + + } + }); + simEditPanel.add(field, "shrinky, growx, wrap"); + + //// Flight selector + //// Flight configuration: + JLabel label = new JLabel(trans.get("simedtdlg.lbl.Flightcfg")); + //// Select the motor configuration to use. + label.setToolTipText(trans.get("simedtdlg.lbl.ttip.Flightcfg")); + simEditPanel.add(label, "shrink"); + + JComboBox combo = new JComboBox(new FlightConfigurationModel(configuration)); + //// Select the motor configuration to use. + combo.setToolTipText(trans.get("simedtdlg.combo.ttip.Flightcfg")); + combo.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + conditions.setMotorConfigurationID(configuration.getFlightConfigurationID()); + } + }); + simEditPanel.add(combo, "split 2, shrink"); + + //// Edit button + JButton button = new JButton(trans.get("simedtdlg.but.FlightcfgEdit")); + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + JDialog configDialog = new FlightConfigurationDialog(SimulationEditDialog.this.document.getRocket(), SwingUtilities.windowForComponent(SimulationEditDialog.this)); + configDialog.setVisible(true); + } + }); + simEditPanel.add(button, "shrink, wrap"); + } + JTabbedPane tabbedPane = new JTabbedPane(); - //// Flight selector - //// Flight configuration: - JLabel label = new JLabel(trans.get("simedtdlg.lbl.Flightcfg")); - //// Select the motor configuration to use. - label.setToolTipText(trans.get("simedtdlg.lbl.ttip.Flightcfg")); - mainPanel.add(label, "shrink"); + //// Launch conditions + tabbedPane.addTab(trans.get("simedtdlg.tab.Launchcond"), new SimulationConditionsPanel(simulation[0])); + //// Simulation options + tabbedPane.addTab(trans.get("simedtdlg.tab.Simopt"), new SimulationOptionsPanel(simulation[0])); - JComboBox combo = new JComboBox(new FlightConfigurationModel(configuration)); - //// Select the motor configuration to use. - combo.setToolTipText(trans.get("simedtdlg.combo.ttip.Flightcfg")); - combo.addActionListener(new ActionListener() { + tabbedPane.setSelectedIndex(0); + + simEditPanel.add(tabbedPane, "spanx, grow, wrap"); + + + //// Open Plot button + JButton button = new JButton("<The standard deviation of the windspeed.
- //// The windspeed is within twice the standard deviation from the average for 95% of the time. - tip = trans.get("simedtdlg.lbl.ttip.Stddeviation"); - label.setToolTipText(tip); - sub.add(label); - - m = new DoubleModel(conditions, "WindSpeedDeviation", UnitGroup.UNITS_WINDSPEED, 0); - DoubleModel m2 = new DoubleModel(conditions, "WindSpeedAverage", 0.25, - UnitGroup.UNITS_COEFFICIENT, 0); - - spin = new JSpinner(m.getSpinnerModel()); - spin.setEditor(new SpinnerEditor(spin)); - spin.setToolTipText(tip); - sub.add(spin, "w 65lp!"); - - unit = new UnitSelector(m); - unit.setToolTipText(tip); - sub.add(unit, "growx"); - slider = new BasicSlider(m.getSliderModel(new DoubleModel(0), m2)); - slider.setToolTipText(tip); - sub.add(slider, "w 75lp, wrap"); - - - // Wind turbulence intensity - //// Turbulence intensity: - label = new JLabel(trans.get("simedtdlg.lbl.Turbulenceintensity")); - //// The turbulence intensity is the standard deviation divided by the average windspeed.
- //// Typical values range from - //// to - tip = trans.get("simedtdlg.lbl.ttip.Turbulenceintensity1") + - trans.get("simedtdlg.lbl.ttip.Turbulenceintensity2") + " " + - UnitGroup.UNITS_RELATIVE.getDefaultUnit().toStringUnit(0.05) + - " " + trans.get("simedtdlg.lbl.ttip.Turbulenceintensity3") + " " + - UnitGroup.UNITS_RELATIVE.getDefaultUnit().toStringUnit(0.20) + "."; - label.setToolTipText(tip); - sub.add(label); - - m = new DoubleModel(conditions, "WindTurbulenceIntensity", UnitGroup.UNITS_RELATIVE, 0); - - spin = new JSpinner(m.getSpinnerModel()); - spin.setEditor(new SpinnerEditor(spin)); - spin.setToolTipText(tip); - sub.add(spin, "w 65lp!"); - - unit = new UnitSelector(m); - unit.setToolTipText(tip); - sub.add(unit, "growx"); - - final JLabel intensityLabel = new JLabel( - getIntensityDescription(conditions.getWindTurbulenceIntensity())); - intensityLabel.setToolTipText(tip); - sub.add(intensityLabel, "w 75lp, wrap"); - m.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - intensityLabel.setText( - getIntensityDescription(conditions.getWindTurbulenceIntensity())); - } - }); - - - - - - //// Temperature and pressure - sub = new JPanel(new MigLayout("fill, gap rel unrel", - "[grow][65lp!][30lp!][75lp!]", "")); - //// Atmospheric conditions - sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.border.Atmoscond"))); - panel.add(sub, "growx, aligny 0, gapright para"); - - - BooleanModel isa = new BooleanModel(conditions, "ISAAtmosphere"); - JCheckBox check = new JCheckBox(isa); - //// Use International Standard Atmosphere - check.setText(trans.get("simedtdlg.checkbox.InterStdAtmosphere")); - //// Select to use the International Standard Atmosphere model. - ////
This model has a temperature of - //// and a pressure of - //// at sea level. - check.setToolTipText(trans.get("simedtdlg.checkbox.ttip.InterStdAtmosphere1") + " " + - UnitGroup.UNITS_TEMPERATURE.toStringUnit(ExtendedISAModel.STANDARD_TEMPERATURE) + - " " + trans.get("simedtdlg.checkbox.ttip.InterStdAtmosphere2") + " " + - UnitGroup.UNITS_PRESSURE.toStringUnit(ExtendedISAModel.STANDARD_PRESSURE) + - " " + trans.get("simedtdlg.checkbox.ttip.InterStdAtmosphere3")); - sub.add(check, "spanx, wrap unrel"); - - // Temperature: - label = new JLabel(trans.get("simedtdlg.lbl.Temperature")); - //// The temperature at the launch site. - tip = trans.get("simedtdlg.lbl.ttip.Temperature"); - label.setToolTipText(tip); - isa.addEnableComponent(label, false); - sub.add(label); - - m = new DoubleModel(conditions, "LaunchTemperature", UnitGroup.UNITS_TEMPERATURE, 0); - - spin = new JSpinner(m.getSpinnerModel()); - spin.setEditor(new SpinnerEditor(spin)); - spin.setToolTipText(tip); - isa.addEnableComponent(spin, false); - sub.add(spin, "w 65lp!"); - - unit = new UnitSelector(m); - unit.setToolTipText(tip); - isa.addEnableComponent(unit, false); - sub.add(unit, "growx"); - slider = new BasicSlider(m.getSliderModel(253.15, 308.15)); // -20 ... 35 - slider.setToolTipText(tip); - isa.addEnableComponent(slider, false); - sub.add(slider, "w 75lp, wrap"); - - - - // Pressure: - label = new JLabel(trans.get("simedtdlg.lbl.Pressure")); - //// The atmospheric pressure at the launch site. - tip = trans.get("simedtdlg.lbl.ttip.Pressure"); - label.setToolTipText(tip); - isa.addEnableComponent(label, false); - sub.add(label); - - m = new DoubleModel(conditions, "LaunchPressure", UnitGroup.UNITS_PRESSURE, 0); - - spin = new JSpinner(m.getSpinnerModel()); - spin.setEditor(new SpinnerEditor(spin)); - spin.setToolTipText(tip); - isa.addEnableComponent(spin, false); - sub.add(spin, "w 65lp!"); - - unit = new UnitSelector(m); - unit.setToolTipText(tip); - isa.addEnableComponent(unit, false); - sub.add(unit, "growx"); - slider = new BasicSlider(m.getSliderModel(0.950e5, 1.050e5)); - slider.setToolTipText(tip); - isa.addEnableComponent(slider, false); - sub.add(slider, "w 75lp, wrap"); - - - - - - //// Launch site conditions - sub = new JPanel(new MigLayout("fill, gap rel unrel", - "[grow][65lp!][30lp!][75lp!]", "")); - //// Launch site - sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.lbl.Launchsite"))); - panel.add(sub, "growx, split 2, aligny 0, flowy"); - - - // Latitude: - label = new JLabel(trans.get("simedtdlg.lbl.Latitude")); - //// The launch site latitude affects the gravitational pull of Earth.
- //// Positive values are on the Northern hemisphere, negative values on the Southern hemisphere. - tip = trans.get("simedtdlg.lbl.ttip.Latitude"); - label.setToolTipText(tip); - sub.add(label); - - m = new DoubleModel(conditions, "LaunchLatitude", UnitGroup.UNITS_NONE, -90, 90); - - spin = new JSpinner(m.getSpinnerModel()); - spin.setEditor(new SpinnerEditor(spin)); - spin.setToolTipText(tip); - sub.add(spin, "w 65lp!"); - - label = new JLabel(Chars.DEGREE + " N"); - label.setToolTipText(tip); - sub.add(label, "growx"); - slider = new BasicSlider(m.getSliderModel(-90, 90)); - slider.setToolTipText(tip); - sub.add(slider, "w 75lp, wrap"); - - - // Longitude: - label = new JLabel(trans.get("simedtdlg.lbl.Longitude")); - tip = trans.get("simedtdlg.lbl.ttip.Longitude"); - label.setToolTipText(tip); - sub.add(label); - - m = new DoubleModel(conditions, "LaunchLongitude", UnitGroup.UNITS_NONE, -180, 180); - - spin = new JSpinner(m.getSpinnerModel()); - spin.setEditor(new SpinnerEditor(spin)); - spin.setToolTipText(tip); - sub.add(spin, "w 65lp!"); - - label = new JLabel(Chars.DEGREE + " E"); - label.setToolTipText(tip); - sub.add(label, "growx"); - slider = new BasicSlider(m.getSliderModel(-180, 180)); - slider.setToolTipText(tip); - sub.add(slider, "w 75lp, wrap"); - - - // Altitude: - label = new JLabel(trans.get("simedtdlg.lbl.Altitude")); - //// The launch altitude above mean sea level.
- //// This affects the position of the rocket in the atmospheric model. - tip = trans.get("simedtdlg.lbl.ttip.Altitude"); - label.setToolTipText(tip); - sub.add(label); - - m = new DoubleModel(conditions, "LaunchAltitude", UnitGroup.UNITS_DISTANCE, 0); - - spin = new JSpinner(m.getSpinnerModel()); - spin.setEditor(new SpinnerEditor(spin)); - spin.setToolTipText(tip); - sub.add(spin, "w 65lp!"); - - unit = new UnitSelector(m); - unit.setToolTipText(tip); - sub.add(unit, "growx"); - slider = new BasicSlider(m.getSliderModel(0, 250, 1000)); - slider.setToolTipText(tip); - sub.add(slider, "w 75lp, wrap"); - - - - - - //// Launch rod - sub = new JPanel(new MigLayout("fill, gap rel unrel", - "[grow][65lp!][30lp!][75lp!]", "")); - //// Launch rod - sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.border.Launchrod"))); - panel.add(sub, "growx, aligny 0, wrap"); - - - // Length: - label = new JLabel(trans.get("simedtdlg.lbl.Length")); - //// The length of the launch rod. - tip = trans.get("simedtdlg.lbl.ttip.Length"); - label.setToolTipText(tip); - sub.add(label); - - m = new DoubleModel(conditions, "LaunchRodLength", UnitGroup.UNITS_LENGTH, 0); - - spin = new JSpinner(m.getSpinnerModel()); - spin.setEditor(new SpinnerEditor(spin)); - spin.setToolTipText(tip); - sub.add(spin, "w 65lp!"); - - unit = new UnitSelector(m); - unit.setToolTipText(tip); - sub.add(unit, "growx"); - slider = new BasicSlider(m.getSliderModel(0, 1, 5)); - slider.setToolTipText(tip); - sub.add(slider, "w 75lp, wrap"); - - - - // Angle: - label = new JLabel(trans.get("simedtdlg.lbl.Angle")); - //// The angle of the launch rod from vertical. - tip = trans.get("simedtdlg.lbl.ttip.Angle"); - label.setToolTipText(tip); - sub.add(label); - - m = new DoubleModel(conditions, "LaunchRodAngle", UnitGroup.UNITS_ANGLE, - 0, SimulationOptions.MAX_LAUNCH_ROD_ANGLE); - - spin = new JSpinner(m.getSpinnerModel()); - spin.setEditor(new SpinnerEditor(spin)); - spin.setToolTipText(tip); - sub.add(spin, "w 65lp!"); - - unit = new UnitSelector(m); - unit.setToolTipText(tip); - sub.add(unit, "growx"); - slider = new BasicSlider(m.getSliderModel(0, Math.PI / 9, - SimulationOptions.MAX_LAUNCH_ROD_ANGLE)); - slider.setToolTipText(tip); - sub.add(slider, "w 75lp, wrap"); - - - - // Direction: - label = new JLabel(trans.get("simedtdlg.lbl.Direction")); - //// Direction of the launch rod relative to the wind.
- //// = towards the wind, - //// = downwind. - tip = trans.get("simedtdlg.lbl.ttip.Direction1") + - UnitGroup.UNITS_ANGLE.toStringUnit(0) + - " " + trans.get("simedtdlg.lbl.ttip.Direction2") + " " + - UnitGroup.UNITS_ANGLE.toStringUnit(Math.PI) + - " " + trans.get("simedtdlg.lbl.ttip.Direction3"); - label.setToolTipText(tip); - sub.add(label); - - m = new DoubleModel(conditions, "LaunchRodDirection", UnitGroup.UNITS_ANGLE, - -Math.PI, Math.PI); - - spin = new JSpinner(m.getSpinnerModel()); - spin.setEditor(new SpinnerEditor(spin)); - spin.setToolTipText(tip); - sub.add(spin, "w 65lp!"); - - unit = new UnitSelector(m); - unit.setToolTipText(tip); - sub.add(unit, "growx"); - slider = new BasicSlider(m.getSliderModel(-Math.PI, Math.PI)); - slider.setToolTipText(tip); - sub.add(slider, "w 75lp, wrap"); - - JButton restoreDefaults = new JButton(trans.get("simedtdlg.but.resettodefault")); - restoreDefaults.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - - DefaultSimulationOptionFactory f = Application.getInjector().getInstance(DefaultSimulationOptionFactory.class); - SimulationOptions defaults = f.getDefault(); - conditions.copyConditionsFrom(defaults); - - } - - }); - panel.add(restoreDefaults, "span, split 3, skip, gapbottom para, gapright para, right"); - - JButton saveDefaults = new JButton(trans.get("simedtdlg.but.savedefault")); - saveDefaults.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - - DefaultSimulationOptionFactory f = Application.getInjector().getInstance(DefaultSimulationOptionFactory.class); - f.saveDefault(conditions); - - } - - }); - - panel.add(saveDefaults, "gapbottom para, gapright para, right"); - return panel; - } - - - private String getIntensityDescription(double i) { - if (i < 0.001) - //// None - return trans.get("simedtdlg.IntensityDesc.None"); - if (i < 0.05) - //// Very low - return trans.get("simedtdlg.IntensityDesc.Verylow"); - if (i < 0.10) - //// Low - return trans.get("simedtdlg.IntensityDesc.Low"); - if (i < 0.15) - //// Medium - return trans.get("simedtdlg.IntensityDesc.Medium"); - if (i < 0.20) - //// High - return trans.get("simedtdlg.IntensityDesc.High"); - if (i < 0.25) - //// Very high - return trans.get("simedtdlg.IntensityDesc.Veryhigh"); - //// Extreme - return trans.get("simedtdlg.IntensityDesc.Extreme"); - } - - - - private JPanel simulationOptionsTab() { - JPanel panel = new JPanel(new MigLayout("fill")); - JPanel sub, subsub; - String tip; - JLabel label; - DoubleModel m; - JSpinner spin; - UnitSelector unit; - BasicSlider slider; - - - //// Simulation options - sub = new JPanel(new MigLayout("fill, gap rel unrel", - "[grow][65lp!][30lp!][75lp!]", "")); - //// Simulator options - sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.border.Simopt"))); - panel.add(sub, "growx, growy, aligny 0"); - - - // Separate panel for computation methods, as they use a different layout - subsub = new JPanel(new MigLayout("insets 0, fill")); - - - //// Calculation method: - tip = trans.get("simedtdlg.lbl.ttip.Calcmethod"); - label = new JLabel(trans.get("simedtdlg.lbl.Calcmethod")); - label.setToolTipText(tip); - subsub.add(label, "gapright para"); - - //// Extended Barrowman - label = new JLabel(trans.get("simedtdlg.lbl.ExtBarrowman")); - label.setToolTipText(tip); - subsub.add(label, "growx, wrap para"); - - - // Simulation method - tip = trans.get("simedtdlg.lbl.ttip.Simmethod1") + - trans.get("simedtdlg.lbl.ttip.Simmethod2"); - label = new JLabel(trans.get("simedtdlg.lbl.Simmethod")); - label.setToolTipText(tip); - subsub.add(label, "gapright para"); - - label = new JLabel("6-DOF Runge-Kutta 4"); - label.setToolTipText(tip); - subsub.add(label, "growx, wrap para"); - - - //// Geodetic calculation method: - label = new JLabel(trans.get("simedtdlg.lbl.GeodeticMethod")); - label.setToolTipText(trans.get("simedtdlg.lbl.ttip.GeodeticMethodTip")); - subsub.add(label, "gapright para"); - - EnumModel gcsModel = new EnumModel(conditions, "GeodeticComputation"); - final JComboBox gcsCombo = new JComboBox(gcsModel); - ActionListener gcsTTipListener = new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - GeodeticComputationStrategy gcs = (GeodeticComputationStrategy) gcsCombo.getSelectedItem(); - gcsCombo.setToolTipText(gcs.getDescription()); - } - }; - gcsCombo.addActionListener(gcsTTipListener); - gcsTTipListener.actionPerformed(null); - subsub.add(gcsCombo, "growx, wrap para"); - - sub.add(subsub, "spanx, wrap para"); - - - //// Time step: - label = new JLabel(trans.get("simedtdlg.lbl.Timestep")); - tip = trans.get("simedtdlg.lbl.ttip.Timestep1") + - trans.get("simedtdlg.lbl.ttip.Timestep2") + " " + - UnitGroup.UNITS_TIME_STEP.toStringUnit(RK4SimulationStepper.RECOMMENDED_TIME_STEP) + - "."; - label.setToolTipText(tip); - sub.add(label); - - m = new DoubleModel(conditions, "TimeStep", UnitGroup.UNITS_TIME_STEP, 0, 1); - - spin = new JSpinner(m.getSpinnerModel()); - spin.setEditor(new SpinnerEditor(spin)); - spin.setToolTipText(tip); - sub.add(spin, "w 65lp!"); - //sub.add(spin, "nogrid"); - - unit = new UnitSelector(m); - unit.setToolTipText(tip); - sub.add(unit, "w 25"); - //sub.add(unit, "nogrid"); - slider = new BasicSlider(m.getSliderModel(0, 0.2)); - slider.setToolTipText(tip); - sub.add(slider, "w 75lp, wrap"); - //sub.add(slider,"wrap"); - - - - - //// Reset to default button - JButton button = new JButton(trans.get("simedtdlg.but.resettodefault")); - //// Reset the time step to its default value ( - button.setToolTipText(trans.get("simedtdlg.but.ttip.resettodefault") + - UnitGroup.UNITS_SHORT_TIME.toStringUnit(RK4SimulationStepper.RECOMMENDED_TIME_STEP) + - ")."); - button.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - conditions.setTimeStep(RK4SimulationStepper.RECOMMENDED_TIME_STEP); - conditions.setGeodeticComputation(GeodeticComputationStrategy.SPHERICAL); - } - }); - - sub.add(button, "align left"); - - - - - //// Simulation listeners - sub = new JPanel(new MigLayout("fill, gap 0 0")); - //// Simulator listeners - sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.border.Simlist"))); - panel.add(sub, "growx, growy"); - - - DescriptionArea desc = new DescriptionArea(5); - //// Simulation listeners is an advanced feature that allows user-written code to listen to and interact with the simulation. - //// For details on writing simulation listeners, see the OpenRocket technical documentation. - desc.setText(trans.get("simedtdlg.txt.longA1") + - trans.get("simedtdlg.txt.longA2")); - sub.add(desc, "aligny 0, growx, wrap para"); - - //// Current listeners: - label = new JLabel(trans.get("simedtdlg.lbl.Curlist")); - sub.add(label, "spanx, wrap rel"); - - final ListenerListModel listenerModel = new ListenerListModel(); - final JList list = new JList(listenerModel); - list.setCellRenderer(new ListenerCellRenderer()); - JScrollPane scroll = new JScrollPane(list); - // scroll.setPreferredSize(new Dimension(1,1)); - sub.add(scroll, "height 1px, grow, wrap rel"); - - //// Add button - button = new JButton(trans.get("simedtdlg.but.add")); - button.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - String previous = Application.getPreferences().getString("previousListenerName", ""); - String input = (String) JOptionPane.showInputDialog(SimulationEditDialog.this, - new Object[] { - //// Type the full Java class name of the simulation listener, for example: - "Type the full Java class name of the simulation listener, for example:", - "" + CSVSaveListener.class.getName() + "" }, - //// Add simulation listener - trans.get("simedtdlg.lbl.Addsimlist"), - JOptionPane.QUESTION_MESSAGE, - null, null, - previous - ); - if (input == null || input.equals("")) - return; - - Application.getPreferences().putString("previousListenerName", input); - simulation[0].getSimulationListeners().add(input); - listenerModel.fireContentsChanged(); - } - }); - sub.add(button, "split 2, sizegroup buttons, alignx 50%, gapright para"); - - //// Remove button - button = new JButton(trans.get("simedtdlg.but.remove")); - button.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - int[] selected = list.getSelectedIndices(); - Arrays.sort(selected); - for (int i = selected.length - 1; i >= 0; i--) { - simulation[0].getSimulationListeners().remove(selected[i]); - } - listenerModel.fireContentsChanged(); - } - }); - sub.add(button, "sizegroup buttons, alignx 50%"); - - - return panel; - } - - - private class ListenerListModel extends AbstractListModel { - @Override - public String getElementAt(int index) { - if (index < 0 || index >= getSize()) - return null; - return simulation[0].getSimulationListeners().get(index); - } - - @Override - public int getSize() { - return simulation[0].getSimulationListeners().size(); - } - - public void fireContentsChanged() { - super.fireContentsChanged(this, 0, getSize()); - } - } - - - - - - /** - * Return a panel stating that there is no data available, and that the user - * should run the simulation first. - */ - public static JPanel noDataPanel() { - JPanel panel = new JPanel(new MigLayout("fill")); - - // No data available - //// No flight data available. - panel.add(new JLabel(trans.get("simedtdlg.lbl.Noflightdata")), - "alignx 50%, aligny 100%, wrap para"); - //// Please run the simulation first. - panel.add(new JLabel(trans.get("simedtdlg.lbl.runsimfirst")), - "alignx 50%, aligny 0%, wrap"); - return panel; - } - - - - private class ListenerCellRenderer extends JLabel implements ListCellRenderer { - - @Override - public Component getListCellRendererComponent(JList list, Object value, - int index, boolean isSelected, boolean cellHasFocus) { - String s = value.toString(); - setText(s); - - // Attempt instantiating, catch any exceptions - Exception ex = null; - try { - Class c = Class.forName(s); - @SuppressWarnings("unused") - SimulationListener l = (SimulationListener) c.newInstance(); - } catch (Exception e) { - ex = e; - } - - if (ex == null) { - setIcon(Icons.SIMULATION_LISTENER_OK); - //// Listener instantiated successfully. - setToolTipText("Listener instantiated successfully."); - } else { - setIcon(Icons.SIMULATION_LISTENER_ERROR); - //// Unable to instantiate listener due to exception:
- setToolTipText("Unable to instantiate listener due to exception:
" + - ex.toString()); - } - - if (isSelected) { - setBackground(list.getSelectionBackground()); - setForeground(list.getSelectionForeground()); - } else { - setBackground(list.getBackground()); - setForeground(list.getForeground()); - } - setOpaque(true); - return this; - } - } } diff --git a/core/src/net/sf/openrocket/gui/simulation/SimulationOptionsPanel.java b/core/src/net/sf/openrocket/gui/simulation/SimulationOptionsPanel.java new file mode 100644 index 000000000..c7b0fe023 --- /dev/null +++ b/core/src/net/sf/openrocket/gui/simulation/SimulationOptionsPanel.java @@ -0,0 +1,294 @@ +package net.sf.openrocket.gui.simulation; + +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Arrays; + +import javax.swing.AbstractListModel; +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSpinner; +import javax.swing.ListCellRenderer; +import javax.swing.SwingUtilities; + +import net.miginfocom.swing.MigLayout; +import net.sf.openrocket.document.Simulation; +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.DescriptionArea; +import net.sf.openrocket.gui.components.UnitSelector; +import net.sf.openrocket.gui.util.Icons; +import net.sf.openrocket.l10n.Translator; +import net.sf.openrocket.simulation.RK4SimulationStepper; +import net.sf.openrocket.simulation.SimulationOptions; +import net.sf.openrocket.simulation.listeners.SimulationListener; +import net.sf.openrocket.simulation.listeners.example.CSVSaveListener; +import net.sf.openrocket.startup.Application; +import net.sf.openrocket.unit.UnitGroup; +import net.sf.openrocket.util.GeodeticComputationStrategy; + +class SimulationOptionsPanel extends JPanel { + + private static final Translator trans = Application.getTranslator(); + + final Simulation simulation; + + SimulationOptionsPanel(final Simulation simulation) { + super(new MigLayout("fill")); + this.simulation = simulation; + + final SimulationOptions conditions = simulation.getOptions(); + + JPanel sub, subsub; + String tip; + JLabel label; + DoubleModel m; + JSpinner spin; + UnitSelector unit; + BasicSlider slider; + + + //// Simulation options + sub = new JPanel(new MigLayout("fill, gap rel unrel", + "[grow][65lp!][30lp!][75lp!]", "")); + //// Simulator options + sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.border.Simopt"))); + this.add(sub, "growx, growy, aligny 0"); + + + // Separate panel for computation methods, as they use a different layout + subsub = new JPanel(new MigLayout("insets 0, fill")); + + + //// Calculation method: + tip = trans.get("simedtdlg.lbl.ttip.Calcmethod"); + label = new JLabel(trans.get("simedtdlg.lbl.Calcmethod")); + label.setToolTipText(tip); + subsub.add(label, "gapright para"); + + //// Extended Barrowman + label = new JLabel(trans.get("simedtdlg.lbl.ExtBarrowman")); + label.setToolTipText(tip); + subsub.add(label, "growx, wrap para"); + + + // Simulation method + tip = trans.get("simedtdlg.lbl.ttip.Simmethod1") + + trans.get("simedtdlg.lbl.ttip.Simmethod2"); + label = new JLabel(trans.get("simedtdlg.lbl.Simmethod")); + label.setToolTipText(tip); + subsub.add(label, "gapright para"); + + label = new JLabel("6-DOF Runge-Kutta 4"); + label.setToolTipText(tip); + subsub.add(label, "growx, wrap para"); + + + //// Geodetic calculation method: + label = new JLabel(trans.get("simedtdlg.lbl.GeodeticMethod")); + label.setToolTipText(trans.get("simedtdlg.lbl.ttip.GeodeticMethodTip")); + subsub.add(label, "gapright para"); + + EnumModel gcsModel = new EnumModel(conditions, "GeodeticComputation"); + final JComboBox gcsCombo = new JComboBox(gcsModel); + ActionListener gcsTTipListener = new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + GeodeticComputationStrategy gcs = (GeodeticComputationStrategy) gcsCombo.getSelectedItem(); + gcsCombo.setToolTipText(gcs.getDescription()); + } + }; + gcsCombo.addActionListener(gcsTTipListener); + gcsTTipListener.actionPerformed(null); + subsub.add(gcsCombo, "growx, wrap para"); + + sub.add(subsub, "spanx, wrap para"); + + + //// Time step: + label = new JLabel(trans.get("simedtdlg.lbl.Timestep")); + tip = trans.get("simedtdlg.lbl.ttip.Timestep1") + + trans.get("simedtdlg.lbl.ttip.Timestep2") + " " + + UnitGroup.UNITS_TIME_STEP.toStringUnit(RK4SimulationStepper.RECOMMENDED_TIME_STEP) + + "."; + label.setToolTipText(tip); + sub.add(label); + + m = new DoubleModel(conditions, "TimeStep", UnitGroup.UNITS_TIME_STEP, 0, 1); + + spin = new JSpinner(m.getSpinnerModel()); + spin.setEditor(new SpinnerEditor(spin)); + spin.setToolTipText(tip); + sub.add(spin, "w 65lp!"); + //sub.add(spin, "nogrid"); + + unit = new UnitSelector(m); + unit.setToolTipText(tip); + sub.add(unit, "w 25"); + //sub.add(unit, "nogrid"); + slider = new BasicSlider(m.getSliderModel(0, 0.2)); + slider.setToolTipText(tip); + sub.add(slider, "w 75lp, wrap"); + //sub.add(slider,"wrap"); + + + + + //// Reset to default button + JButton button = new JButton(trans.get("simedtdlg.but.resettodefault")); + //// Reset the time step to its default value ( + button.setToolTipText(trans.get("simedtdlg.but.ttip.resettodefault") + + UnitGroup.UNITS_SHORT_TIME.toStringUnit(RK4SimulationStepper.RECOMMENDED_TIME_STEP) + + ")."); + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + conditions.setTimeStep(RK4SimulationStepper.RECOMMENDED_TIME_STEP); + conditions.setGeodeticComputation(GeodeticComputationStrategy.SPHERICAL); + } + }); + + sub.add(button, "align left"); + + + + + //// Simulation listeners + sub = new JPanel(new MigLayout("fill, gap 0 0")); + //// Simulator listeners + sub.setBorder(BorderFactory.createTitledBorder(trans.get("simedtdlg.border.Simlist"))); + this.add(sub, "growx, growy"); + + + DescriptionArea desc = new DescriptionArea(5); + //// Simulation listeners is an advanced feature that allows user-written code to listen to and interact with the simulation. + //// For details on writing simulation listeners, see the OpenRocket technical documentation. + desc.setText(trans.get("simedtdlg.txt.longA1") + + trans.get("simedtdlg.txt.longA2")); + sub.add(desc, "aligny 0, growx, wrap para"); + + //// Current listeners: + label = new JLabel(trans.get("simedtdlg.lbl.Curlist")); + sub.add(label, "spanx, wrap rel"); + + final ListenerListModel listenerModel = new ListenerListModel(); + final JList list = new JList(listenerModel); + list.setCellRenderer(new ListenerCellRenderer()); + JScrollPane scroll = new JScrollPane(list); + // scroll.setPreferredSize(new Dimension(1,1)); + sub.add(scroll, "height 1px, grow, wrap rel"); + + //// Add button + button = new JButton(trans.get("simedtdlg.but.add")); + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + String previous = Application.getPreferences().getString("previousListenerName", ""); + String input = (String) JOptionPane.showInputDialog(SwingUtilities.getRoot(SimulationOptionsPanel.this), + new Object[] { + //// Type the full Java class name of the simulation listener, for example: + "Type the full Java class name of the simulation listener, for example:", + "" + CSVSaveListener.class.getName() + "" }, + //// Add simulation listener + trans.get("simedtdlg.lbl.Addsimlist"), + JOptionPane.QUESTION_MESSAGE, + null, null, + previous + ); + if (input == null || input.equals("")) + return; + + Application.getPreferences().putString("previousListenerName", input); + simulation.getSimulationListeners().add(input); + listenerModel.fireContentsChanged(); + } + }); + sub.add(button, "split 2, sizegroup buttons, alignx 50%, gapright para"); + + //// Remove button + button = new JButton(trans.get("simedtdlg.but.remove")); + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + int[] selected = list.getSelectedIndices(); + Arrays.sort(selected); + for (int i = selected.length - 1; i >= 0; i--) { + simulation.getSimulationListeners().remove(selected[i]); + } + listenerModel.fireContentsChanged(); + } + }); + sub.add(button, "sizegroup buttons, alignx 50%"); + + + } + + private class ListenerCellRenderer extends JLabel implements ListCellRenderer { + + @Override + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, boolean cellHasFocus) { + String s = value.toString(); + setText(s); + + // Attempt instantiating, catch any exceptions + Exception ex = null; + try { + Class c = Class.forName(s); + @SuppressWarnings("unused") + SimulationListener l = (SimulationListener) c.newInstance(); + } catch (Exception e) { + ex = e; + } + + if (ex == null) { + setIcon(Icons.SIMULATION_LISTENER_OK); + //// Listener instantiated successfully. + setToolTipText("Listener instantiated successfully."); + } else { + setIcon(Icons.SIMULATION_LISTENER_ERROR); + //// Unable to instantiate listener due to exception:
+ setToolTipText("Unable to instantiate listener due to exception:
" + + ex.toString()); + } + + if (isSelected) { + setBackground(list.getSelectionBackground()); + setForeground(list.getSelectionForeground()); + } else { + setBackground(list.getBackground()); + setForeground(list.getForeground()); + } + setOpaque(true); + return this; + } + } + + private class ListenerListModel extends AbstractListModel { + @Override + public String getElementAt(int index) { + if (index < 0 || index >= getSize()) + return null; + return simulation.getSimulationListeners().get(index); + } + + @Override + public int getSize() { + return simulation.getSimulationListeners().size(); + } + + public void fireContentsChanged() { + super.fireContentsChanged(this, 0, getSize()); + } + } + +} diff --git a/core/src/net/sf/openrocket/gui/simulation/SimulationPlotExportDialog.java b/core/src/net/sf/openrocket/gui/simulation/SimulationPlotExportDialog.java deleted file mode 100644 index d82ac605b..000000000 --- a/core/src/net/sf/openrocket/gui/simulation/SimulationPlotExportDialog.java +++ /dev/null @@ -1,105 +0,0 @@ -package net.sf.openrocket.gui.simulation; - -import java.awt.Window; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -import javax.swing.JButton; -import javax.swing.JDialog; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JTabbedPane; -import javax.swing.JTextField; - -import net.miginfocom.swing.MigLayout; -import net.sf.openrocket.document.OpenRocketDocument; -import net.sf.openrocket.document.Simulation; -import net.sf.openrocket.gui.util.GUIUtil; -import net.sf.openrocket.l10n.Translator; -import net.sf.openrocket.startup.Application; - -public class SimulationPlotExportDialog extends JDialog { - - private final Window parentWindow; - private final Simulation simulation; - private static final Translator trans = Application.getTranslator(); - - public SimulationPlotExportDialog(Window parent, final OpenRocketDocument document, Simulation s) { - //// Plot/Export simulation - super(parent, trans.get("simedtdlg.title.Editsim"), JDialog.ModalityType.DOCUMENT_MODAL); - this.parentWindow = parent; - this.simulation = s; - - JPanel mainPanel = new JPanel(new MigLayout("fill", "[grow]")); - - //// Simulation name: - mainPanel.add(new JLabel(trans.get("simedtdlg.lbl.Simname") + " "), "span, split 2, shrink"); - final JTextField field = new JTextField(simulation.getName()); - field.setEditable(false); - mainPanel.add(field, "shrinky, growx, wrap"); - - final JTabbedPane tabbedPane = new JTabbedPane(); - - //// Plot data - final SimulationPlotPanel plotTab = new SimulationPlotPanel(simulation); - tabbedPane.addTab(trans.get("simedtdlg.tab.Plotdata"), plotTab); - //// Export data - final SimulationExportPanel exportTab = new SimulationExportPanel(simulation); - tabbedPane.addTab(trans.get("simedtdlg.tab.Exportdata"), exportTab); - - mainPanel.add(tabbedPane, "grow, wrap"); - - JButton button = new JButton("< Date: Fri, 31 May 2013 06:35:07 -0500 Subject: [PATCH 09/14] Create a simulation when a flight configuration is copied or created. --- .../FlightConfigurationDialog.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/FlightConfigurationDialog.java b/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/FlightConfigurationDialog.java index 9a4d98d69..487b0ac66 100644 --- a/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/FlightConfigurationDialog.java +++ b/core/src/net/sf/openrocket/gui/dialogs/flightconfiguration/FlightConfigurationDialog.java @@ -15,6 +15,7 @@ import javax.swing.JTabbedPane; import net.miginfocom.swing.MigLayout; import net.sf.openrocket.document.OpenRocketDocument; +import net.sf.openrocket.document.Simulation; import net.sf.openrocket.gui.adaptors.FlightConfigurationModel; import net.sf.openrocket.gui.main.BasicFrame; import net.sf.openrocket.gui.util.GUIUtil; @@ -170,6 +171,10 @@ public class FlightConfigurationDialog extends JDialog { private void addConfiguration() { String newId = rocket.newFlightConfigurationID(); rocket.getDefaultConfiguration().setFlightConfigurationID(newId); + + // Create a new simulation for this configuration. + createSimulationForNewConfiguration(); + configurationChanged(); } @@ -188,9 +193,22 @@ public class FlightConfigurationDialog extends JDialog { rocket.setFlightConfigurationName(currentId, oldName); rocket.getDefaultConfiguration().setFlightConfigurationID(newConfigId); + // Create a new simulation for this configuration. + createSimulationForNewConfiguration(); + configurationChanged(); } + /** + * prereq - assumes that the new configuration has been set as the default configuration. + */ + private void createSimulationForNewConfiguration() { + Simulation newSim = new Simulation(rocket); + OpenRocketDocument doc = BasicFrame.findDocument(rocket); + newSim.setName(doc.getNextSimulationName()); + doc.addSimulation(newSim); + } + private void renameConfiguration() { new RenameConfigDialog(this, rocket).setVisible(true); } From be62cc243e372c555fec752510a13ae8055b7be2 Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Tue, 4 Jun 2013 10:05:18 -0500 Subject: [PATCH 10/14] When creating a simulation use the DefaultSimulationOptionFactory. --- core/src/net/sf/openrocket/document/Simulation.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/src/net/sf/openrocket/document/Simulation.java b/core/src/net/sf/openrocket/document/Simulation.java index 39a97d930..594734e2b 100644 --- a/core/src/net/sf/openrocket/document/Simulation.java +++ b/core/src/net/sf/openrocket/document/Simulation.java @@ -13,6 +13,7 @@ import net.sf.openrocket.masscalc.MassCalculator; import net.sf.openrocket.rocketcomponent.Configuration; import net.sf.openrocket.rocketcomponent.Rocket; import net.sf.openrocket.simulation.BasicEventSimulationEngine; +import net.sf.openrocket.simulation.DefaultSimulationOptionFactory; import net.sf.openrocket.simulation.FlightData; import net.sf.openrocket.simulation.RK4SimulationStepper; import net.sf.openrocket.simulation.SimulationConditions; @@ -105,8 +106,11 @@ public class Simulation implements ChangeSource, Cloneable { this.status = Status.NOT_SIMULATED; options = new SimulationOptions(rocket); - options.setMotorConfigurationID( - rocket.getDefaultConfiguration().getFlightConfigurationID()); + + DefaultSimulationOptionFactory f = Application.getInjector().getInstance(DefaultSimulationOptionFactory.class); + options.copyConditionsFrom(f.getDefault()); + + options.setMotorConfigurationID(rocket.getDefaultConfiguration().getFlightConfigurationID()); options.addChangeListener(new ConditionListener()); } From 4b9fb6b2fcc03223e2c20218154552160c2d7cc9 Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Tue, 4 Jun 2013 10:06:31 -0500 Subject: [PATCH 11/14] Open the SimulationEditDialog in the correct mode based on button press only try to infer it when double clicking. --- .../openrocket/gui/main/SimulationPanel.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/core/src/net/sf/openrocket/gui/main/SimulationPanel.java b/core/src/net/sf/openrocket/gui/main/SimulationPanel.java index bdb8c501d..cf962e6d0 100644 --- a/core/src/net/sf/openrocket/gui/main/SimulationPanel.java +++ b/core/src/net/sf/openrocket/gui/main/SimulationPanel.java @@ -102,7 +102,7 @@ public class SimulationPanel extends JPanel { simulationTable.clearSelection(); simulationTable.addRowSelectionInterval(n, n); - openDialog(sim); + openDialog(false, sim); } }); this.add(button, "skip 1, gapright para"); @@ -124,7 +124,7 @@ public class SimulationPanel extends JPanel { selection[i] = simulationTable.convertRowIndexToModel(selection[i]); sims[i] = document.getSimulation(selection[i]); } - openDialog(sims); + openDialog(false, sims); } }); this.add(editButton, "gapright para"); @@ -234,7 +234,7 @@ public class SimulationPanel extends JPanel { fireMaintainSelection(); - openDialog(sim); + openDialog(true, sim); } }); @@ -560,15 +560,23 @@ public class SimulationPanel extends JPanel { return simulationTable.getSelectionModel(); } - private void openDialog(final Simulation... sims) { + private void openDialog(boolean plotMode, final Simulation... sims) { SimulationEditDialog d = new SimulationEditDialog(SwingUtilities.getWindowAncestor(this), document, sims); - if (sims.length == 1 && sims[0].hasSimulationData()) { + if (plotMode) { d.setPlotMode(); } d.setVisible(true); fireMaintainSelection(); } + private void openDialog(final Simulation sim) { + boolean plotMode = false; + if (sim.hasSimulationData()) { + plotMode = true; + } + openDialog(plotMode, sim); + } + private void fireMaintainSelection() { int[] selection = simulationTable.getSelectedRows(); simulationTableModel.fireTableDataChanged(); From 4cfc65fbe2e2f21ba09c086f33fe8a747c1e3ada Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Wed, 5 Jun 2013 15:49:09 -0500 Subject: [PATCH 12/14] Make the simulation edit dialog operate a little more friendly. When the Run Simulation button is pressed, the simulations are executed and the edit dialog changes to support plotting (when not in multi-edit mode). The edit dialog will not close in any case. When the user presses close, the dialog is closed. The close button no longer copies the changed simulation conditions to the other selected simulations. --- .../gui/simulation/SimulationEditDialog.java | 307 +++++++++--------- 1 file changed, 159 insertions(+), 148 deletions(-) diff --git a/core/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java b/core/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java index 9e16e1a02..0e57dd01c 100644 --- a/core/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java +++ b/core/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java @@ -42,6 +42,28 @@ public class SimulationEditDialog extends JDialog { private final static String EDITMODE = "EDIT"; private final static String PLOTMODE = "PLOT"; + public SimulationEditDialog(Window parent, final OpenRocketDocument document, Simulation... sims) { + //// Edit simulation + super(parent, trans.get("simedtdlg.title.Editsim"), JDialog.ModalityType.DOCUMENT_MODAL); + this.document = document; + this.parentWindow = parent; + this.simulation = sims; + this.conditions = simulation[0].getOptions(); + configuration = simulation[0].getConfiguration(); + + this.cards = new JPanel(new CardLayout()); + this.add(cards); + buildEditCard(); + buildPlotCard(); + + this.validate(); + this.pack(); + + this.setLocationByPlatform(true); + + GUIUtil.setDisposableDialogOptions(this, null); + } + private boolean isSingleEdit() { return simulation.length == 1; } @@ -65,138 +87,141 @@ public class SimulationEditDialog extends JDialog { cards.validate(); } - public SimulationEditDialog(Window parent, OpenRocketDocument document, Simulation... sims) { - //// Edit simulation - super(parent, trans.get("simedtdlg.title.Editsim"), JDialog.ModalityType.DOCUMENT_MODAL); - this.document = document; - this.parentWindow = parent; - this.simulation = sims; - this.conditions = simulation[0].getOptions(); - configuration = simulation[0].getConfiguration(); - - this.cards = new JPanel(new CardLayout()); - this.add(cards); - { - JPanel simEditPanel = new JPanel(new MigLayout("fill")); - - if (isSingleEdit()) { - //// Simulation name: - simEditPanel.add(new JLabel(trans.get("simedtdlg.lbl.Simname") + " "), "shrink"); - final JTextField field = new JTextField(simulation[0].getName()); - field.getDocument().addDocumentListener(new DocumentListener() { - @Override - public void changedUpdate(DocumentEvent e) { - setText(); - } - - @Override - public void insertUpdate(DocumentEvent e) { - setText(); - } - - @Override - public void removeUpdate(DocumentEvent e) { - setText(); - } - - private void setText() { - String name = field.getText(); - if (name == null || name.equals("")) - return; - //System.out.println("Setting name:" + name); - simulation[0].setName(name); - - } - }); - simEditPanel.add(field, "shrinky, growx, wrap"); - - //// Flight selector - //// Flight configuration: - JLabel label = new JLabel(trans.get("simedtdlg.lbl.Flightcfg")); - //// Select the motor configuration to use. - label.setToolTipText(trans.get("simedtdlg.lbl.ttip.Flightcfg")); - simEditPanel.add(label, "shrink"); - - JComboBox combo = new JComboBox(new FlightConfigurationModel(configuration)); - //// Select the motor configuration to use. - combo.setToolTipText(trans.get("simedtdlg.combo.ttip.Flightcfg")); - combo.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - conditions.setMotorConfigurationID(configuration.getFlightConfigurationID()); - } - }); - simEditPanel.add(combo, "split 2, shrink"); - - //// Edit button - JButton button = new JButton(trans.get("simedtdlg.but.FlightcfgEdit")); - button.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - JDialog configDialog = new FlightConfigurationDialog(SimulationEditDialog.this.document.getRocket(), SwingUtilities.windowForComponent(SimulationEditDialog.this)); - configDialog.setVisible(true); - } - }); - simEditPanel.add(button, "shrink, wrap"); + private void copyChangesToAllSims() { + if (simulation.length > 1) { + for (int i = 1; i < simulation.length; i++) { + simulation[i].getOptions().copyConditionsFrom(simulation[0].getOptions()); + simulation[i].getSimulationListeners().clear(); + simulation[i].getSimulationListeners().addAll(simulation[0].getSimulationListeners()); } - JTabbedPane tabbedPane = new JTabbedPane(); - - //// Launch conditions - tabbedPane.addTab(trans.get("simedtdlg.tab.Launchcond"), new SimulationConditionsPanel(simulation[0])); - //// Simulation options - tabbedPane.addTab(trans.get("simedtdlg.tab.Simopt"), new SimulationOptionsPanel(simulation[0])); - - tabbedPane.setSelectedIndex(0); - - simEditPanel.add(tabbedPane, "spanx, grow, wrap"); - - - //// Open Plot button - JButton button = new JButton("< 1) { - for (int i = 1; i < simulation.length; i++) { - simulation[i].getOptions().copyConditionsFrom(simulation[0].getOptions()); - simulation[i].getSimulationListeners().clear(); - simulation[i].getSimulationListeners().addAll(simulation[0].getSimulationListeners()); - } - } - } - } From 7d30bcb67b50f93f4ba99e7793f1829488da70c3 Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Wed, 5 Jun 2013 21:20:50 -0500 Subject: [PATCH 13/14] I like it better when the close button copies the SimulationOptions. Only SimulationOptions needs to be a little bit smarter about when to fire the change event. --- .../gui/simulation/SimulationEditDialog.java | 1 + .../simulation/SimulationOptions.java | 84 ++++++++++++++----- 2 files changed, 66 insertions(+), 19 deletions(-) diff --git a/core/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java b/core/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java index 0e57dd01c..6cc07b573 100644 --- a/core/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java +++ b/core/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java @@ -213,6 +213,7 @@ public class SimulationEditDialog extends JDialog { close.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { + copyChangesToAllSims(); SimulationEditDialog.this.dispose(); } }); diff --git a/core/src/net/sf/openrocket/simulation/SimulationOptions.java b/core/src/net/sf/openrocket/simulation/SimulationOptions.java index dbbfbd19c..f32c01407 100644 --- a/core/src/net/sf/openrocket/simulation/SimulationOptions.java +++ b/core/src/net/sf/openrocket/simulation/SimulationOptions.java @@ -452,25 +452,71 @@ public class SimulationOptions implements ChangeSource, Cloneable { fireChangeEvent(); } - public void copyConditionsFrom(SimulationOptions src) { - - this.launchAltitude = src.launchAltitude; - this.launchLatitude = src.launchLatitude; - this.launchLongitude = src.launchLongitude; - this.launchPressure = src.launchPressure; - this.launchRodAngle = src.launchRodAngle; - this.launchRodDirection = src.launchRodDirection; - this.launchRodLength = src.launchRodLength; - this.launchTemperature = src.launchTemperature; - this.maximumAngle = src.maximumAngle; - this.timeStep = src.timeStep; - this.windAverage = src.windAverage; - this.windTurbulence = src.windTurbulence; - this.calculateExtras = src.calculateExtras; - this.randomSeed = src.randomSeed; - - fireChangeEvent(); - } + public void copyConditionsFrom(SimulationOptions src) { + // Be a little smart about triggering the change event. + // only do it if one of the "important" (user specified) parameters has really changed. + boolean isChanged = false; + if (this.launchAltitude != src.launchAltitude) { + isChanged = true; + this.launchAltitude = src.launchAltitude; + } + if (this.launchLatitude != src.launchLatitude) { + isChanged = true; + this.launchLatitude = src.launchLatitude; + } + if (this.launchLongitude != src.launchLongitude) { + isChanged = true; + this.launchLongitude = src.launchLongitude; + } + if (this.launchPressure != src.launchPressure) { + isChanged = true; + this.launchPressure = src.launchPressure; + } + if (this.launchRodAngle != src.launchRodAngle) { + isChanged = true; + this.launchRodAngle = src.launchRodAngle; + } + if (this.launchRodDirection != src.launchRodDirection) { + isChanged = true; + this.launchRodDirection = src.launchRodDirection; + } + if (this.launchRodLength != src.launchRodLength) { + isChanged = true; + this.launchRodLength = src.launchRodLength; + } + if (this.launchTemperature != src.launchTemperature) { + isChanged = true; + this.launchTemperature = src.launchTemperature; + } + if (this.maximumAngle != src.maximumAngle) { + isChanged = true; + this.maximumAngle = src.maximumAngle; + } + this.maximumAngle = src.maximumAngle; + if (this.timeStep != src.timeStep) { + isChanged = true; + this.timeStep = src.timeStep; + } + if (this.windAverage != src.windAverage) { + isChanged = true; + this.windAverage = src.windAverage; + } + if (this.windTurbulence != src.windTurbulence) { + isChanged = true; + this.windTurbulence = src.windTurbulence; + } + if (this.calculateExtras != src.calculateExtras) { + isChanged = true; + this.calculateExtras = src.calculateExtras; + } + + if (isChanged) { + // Only copy the randomSeed if something else has changed. + // Honestly, I don't really see a need for that. + this.randomSeed = src.randomSeed; + fireChangeEvent(); + } + } /** From a67bd1add62cf0de5d9683014c633a8af6860c89 Mon Sep 17 00:00:00 2001 From: kruland2607 Date: Tue, 11 Jun 2013 21:28:59 -0500 Subject: [PATCH 14/14] If the simulation runs correctly, then switch to plot view. --- .../sf/openrocket/gui/simulation/SimulationEditDialog.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java b/core/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java index 6cc07b573..cdaf9e0c1 100644 --- a/core/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java +++ b/core/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java @@ -204,6 +204,9 @@ public class SimulationEditDialog extends JDialog { copyChangesToAllSims(); SimulationRunDialog.runSimulations(parentWindow, SimulationEditDialog.this.document, simulation); refreshView(); + if (allowsPlotMode()) { + setPlotMode(); + } } }); simEditPanel.add(button, " align right, tag ok"); @@ -213,7 +216,7 @@ public class SimulationEditDialog extends JDialog { close.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - copyChangesToAllSims(); + copyChangesToAllSims(); SimulationEditDialog.this.dispose(); } });