diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index 2d2cc8b79..650df356d 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -452,9 +452,10 @@ simedtdlg.but.delete = Delete simedtdlg.title.Editsim = Edit simulation simedtdlg.title.MultiSimEdit = Multi-simulation edit simedtdlg.title.MultiSimEdit.ttip = You are editing the following simulations:
-simedtdlg.lbl.Simname = Simulation name: +simedtdlg.lbl.Simname = Name: simedtdlg.tab.Launchcond = Launch conditions simedtdlg.tab.Simopt = Simulation options +simedtdlg.tab.Settings = Settings simedtdlg.tab.Plotdata = Plot data simedtdlg.tab.CustomExpressions = Custom expressions simedtdlg.tab.Exportdata = Export data @@ -534,6 +535,10 @@ simedtdlg.IntensityDesc.High = High simedtdlg.IntensityDesc.Veryhigh = Very high simedtdlg.IntensityDesc.Extreme = Extreme +! SimulationConfigDialog +SimulationConfigDialog.tab.plotDis.ttip = Plotting not supported for multi-simulation editing +SimulationConfigDialog.tab.expDis.ttip = Exporting not supported for multi-simulation editing + SimulationExtension.airstart.name.alt = Air-start ({alt}) SimulationExtension.airstart.name.altvel = Air-start ({alt}, {vel}) SimulationExtension.javacode.name = Java code diff --git a/core/resources/l10n/messages_uk_UA.properties b/core/resources/l10n/messages_uk_UA.properties index 72c45b44e..a99a4ccb3 100644 --- a/core/resources/l10n/messages_uk_UA.properties +++ b/core/resources/l10n/messages_uk_UA.properties @@ -321,7 +321,7 @@ simedtdlg.but.savedefault = Save as default simedtdlg.but.add = Add simedtdlg.but.delete = Delete simedtdlg.title.Editsim = Edit simulation -simedtdlg.lbl.Simname = Simulation name: +simedtdlg.lbl.Simname = Name: simedtdlg.tab.Launchcond = Launch conditions simedtdlg.tab.Simopt = Simulation options simedtdlg.tab.Plotdata = Plot data diff --git a/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java b/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java index 5f762ee11..7a2ee0cfb 100644 --- a/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java +++ b/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java @@ -45,6 +45,7 @@ import javax.swing.table.DefaultTableCellRenderer; import net.sf.openrocket.arch.SystemInfo; import net.sf.openrocket.gui.components.CsvOptionPanel; +import net.sf.openrocket.gui.simulation.SimulationConfigDialog; import net.sf.openrocket.gui.util.ColorConversion; import net.sf.openrocket.gui.util.FileHelper; import net.sf.openrocket.gui.util.GUIUtil; @@ -57,7 +58,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.miginfocom.swing.MigLayout; -import net.sf.openrocket.logging.Warning; import net.sf.openrocket.logging.WarningSet; import net.sf.openrocket.document.OpenRocketDocument; import net.sf.openrocket.document.Simulation; @@ -72,7 +72,6 @@ import net.sf.openrocket.gui.adaptors.ColumnTableModel; import net.sf.openrocket.gui.adaptors.ColumnTableRowSorter; import net.sf.openrocket.gui.adaptors.ValueColumn; import net.sf.openrocket.gui.components.StyledLabel; -import net.sf.openrocket.gui.simulation.SimulationEditDialog; import net.sf.openrocket.gui.simulation.SimulationRunDialog; import net.sf.openrocket.gui.simulation.SimulationWarningDialog; import net.sf.openrocket.gui.util.Icons; @@ -888,9 +887,11 @@ public class SimulationPanel extends JPanel { } private void openDialog(boolean plotMode, boolean isNewSimulation, final Simulation... sims) { - SimulationEditDialog d = new SimulationEditDialog(SwingUtilities.getWindowAncestor(this), document, isNewSimulation, sims); + SimulationConfigDialog d = new SimulationConfigDialog(SwingUtilities.getWindowAncestor(this), document, isNewSimulation, sims); if (plotMode) { - d.setPlotMode(); + d.switchToPlotTab(); + } else { + d.switchToSettingsTab(); } d.setVisible(true); fireMaintainSelection(); diff --git a/swing/src/net/sf/openrocket/gui/simulation/SimulationConfigDialog.java b/swing/src/net/sf/openrocket/gui/simulation/SimulationConfigDialog.java new file mode 100644 index 000000000..a1037cfe1 --- /dev/null +++ b/swing/src/net/sf/openrocket/gui/simulation/SimulationConfigDialog.java @@ -0,0 +1,456 @@ +package net.sf.openrocket.gui.simulation; + +import net.miginfocom.swing.MigLayout; +import net.sf.openrocket.document.OpenRocketDocument; +import net.sf.openrocket.document.Simulation; +import net.sf.openrocket.document.events.DocumentChangeEvent; +import net.sf.openrocket.gui.components.ConfigurationComboBox; +import net.sf.openrocket.gui.components.StyledLabel; +import net.sf.openrocket.gui.util.GUIUtil; +import net.sf.openrocket.gui.util.UITheme; +import net.sf.openrocket.gui.widgets.SelectColorButton; +import net.sf.openrocket.l10n.Translator; +import net.sf.openrocket.rocketcomponent.FlightConfiguration; +import net.sf.openrocket.rocketcomponent.FlightConfigurationId; +import net.sf.openrocket.rocketcomponent.Rocket; +import net.sf.openrocket.simulation.extension.SimulationExtension; +import net.sf.openrocket.startup.Application; +import net.sf.openrocket.startup.Preferences; +import net.sf.openrocket.util.StateChangeListener; + +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.JTextField; +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 java.awt.Color; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import java.util.ArrayList; +import java.util.EventObject; +import java.util.List; + +public class SimulationConfigDialog extends JDialog { + private static final long serialVersionUID = -1068127685642912715L; + + private final Window parentWindow; + private final Simulation[] simulationList; + private final OpenRocketDocument document; + private final JTabbedPane tabbedPane; + private JButton okButton; + private JButton cancelButton; + private static final Translator trans = Application.getTranslator(); + private static final Preferences preferences = Application.getPreferences(); + + + private final WindowListener applyChangesToSimsListener; + private final Simulation initialSim; // A copy of the first selected simulation before it was modified + private final boolean initialIsSaved; // Whether the document was saved before the dialog was opened + private boolean isModified = false; // Whether the simulation has been modified + private final boolean isNewSimulation; // Whether you are editing a new simulation, or an existing one + + private static final int SETTINGS_IDX = 0; + private static final int PLOT_IDX = 1; + private static final int EXPORT_IDX = 2; + + private final SimulationPlotPanel plotTab; + private final SimulationExportPanel exportTab; + + private static Color multiCompEditColor; + + static { + initColors(); + } + + public SimulationConfigDialog(Window parent, final OpenRocketDocument document, boolean isNewSimulation, Simulation... sims) { + super(parent, sims.length == 1 ? trans.get("simedtdlg.title.Editsim") : trans.get("simedtdlg.title.MultiSimEdit"), + JDialog.ModalityType.DOCUMENT_MODAL); + this.document = document; + this.parentWindow = parent; + this.simulationList = sims; + this.initialSim = simulationList[0].clone(); + this.initialIsSaved = document.isSaved(); + this.isNewSimulation = isNewSimulation; + + simulationList[0].addChangeListener(new StateChangeListener() { + @Override + public void stateChanged(EventObject e) { + isModified = true; + setTitle("* " + getTitle()); // Add component changed indicator to the title + simulationList[0].removeChangeListener(this); + } + }); + + final JPanel contentPanel = new JPanel(new MigLayout("fill")); + + // ======== Top panel ======== + addTopPanel(document, contentPanel); + + + // ======== Tabbed pane ======== + this.tabbedPane = new JTabbedPane(); + + //// Simulation Settings + final SimulationSettingsPanel settingsTab = new SimulationSettingsPanel(document, simulationList[0]); + tabbedPane.addTab(trans.get("simedtdlg.tab.Settings"), settingsTab); + + //// Plot data + this.plotTab = new SimulationPlotPanel(simulationList[0]); + tabbedPane.addTab(trans.get("simedtdlg.tab.Plotdata"), plotTab); + if (isMultiCompEdit()) { + tabbedPane.setEnabledAt(PLOT_IDX, false); + tabbedPane.setToolTipTextAt(PLOT_IDX, trans.get("SimulationConfigDialog.tab.plotDis.ttip")); + } + + //// Export data + this.exportTab = new SimulationExportPanel(simulationList[0]); + tabbedPane.addTab(trans.get("simedtdlg.tab.Exportdata"), exportTab); + if (isMultiCompEdit()) { + tabbedPane.setEnabledAt(EXPORT_IDX, false); + tabbedPane.setToolTipTextAt(EXPORT_IDX, trans.get("SimulationConfigDialog.tab.expDis.ttip")); + } + + contentPanel.add(tabbedPane, "grow, wrap"); + + + // ======== Bottom panel ======== + addBottomPanel(contentPanel); + + + tabbedPane.addChangeListener(new ChangeListener() { + + @Override + public void stateChanged(ChangeEvent e) { + if (okButton == null) { + return; + } + int selectedIndex = tabbedPane.getSelectedIndex(); + switch (selectedIndex) { + case SETTINGS_IDX: + okButton.setText(trans.get("dlg.but.ok")); + cancelButton.setText(trans.get("dlg.but.cancel")); + SimulationConfigDialog.this.revalidate(); + break; + case PLOT_IDX: + okButton.setText(trans.get("SimulationEditDialog.btn.plot")); + cancelButton.setText(trans.get("dlg.but.close")); + SimulationConfigDialog.this.revalidate(); + break; + case EXPORT_IDX: + okButton.setText(trans.get("SimulationEditDialog.btn.export")); + cancelButton.setText(trans.get("dlg.but.close")); + SimulationConfigDialog.this.revalidate(); + break; + } + } + + }); + + this.add(contentPanel); + this.validate(); + this.pack(); + + this.setLocationByPlatform(true); + + this.applyChangesToSimsListener = new WindowAdapter() { + @Override + public void windowClosed(WindowEvent e) { + copyChangesToAllSims(); + } + }; + this.addWindowListener(applyChangesToSimsListener); + + GUIUtil.setDisposableDialogOptions(this, null); + } + + private static void initColors() { + updateColors(); + UITheme.Theme.addUIThemeChangeListener(SimulationConfigDialog::updateColors); + } + + private static void updateColors() { + multiCompEditColor = GUIUtil.getUITheme().getMultiCompEditColor(); + } + + public void switchToSettingsTab() { + tabbedPane.setSelectedIndex(SETTINGS_IDX); + } + + public void switchToPlotTab() { + tabbedPane.setSelectedIndex(PLOT_IDX); + } + + public void switchToExportTab() { + tabbedPane.setSelectedIndex(EXPORT_IDX); + } + + private void addTopPanel(OpenRocketDocument document, JPanel contentPanel) { + JPanel topPanel = new JPanel(new MigLayout("fill, ins 0")); + + //// Name: + topPanel.add(new JLabel(trans.get("simedtdlg.lbl.Simname") + " "), "growx 0, gapright para"); + final JTextField field = new JTextField(simulationList[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; + simulationList[0].setName(name); + + } + }); + topPanel.add(field, "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")); + topPanel.add(label, "growx 0, gapright para"); + + final Rocket rkt = document.getRocket(); + final FlightConfiguration config = rkt.getFlightConfiguration(simulationList[0].getFlightConfigurationId()); + final ConfigurationComboBox configComboBox = new ConfigurationComboBox(rkt, false); + configComboBox.setSelectedItem(config); + + //// Select the motor configuration to use. + configComboBox.setToolTipText(trans.get("simedtdlg.combo.ttip.Flightcfg")); + configComboBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + FlightConfiguration config = (FlightConfiguration)configComboBox.getSelectedItem(); + FlightConfigurationId id = config.getId(); + + simulationList[0].setFlightConfigurationId( id ); + } + }); + topPanel.add(configComboBox, "span"); + + topPanel.add(new JPanel(), "growx, wrap"); + + contentPanel.add(topPanel, "growx, wrap"); + } + + private void addBottomPanel(JPanel contentPanel) { + final JPanel bottomPanel = new JPanel(new MigLayout("fill, ins 0")); + + //// Multi-simulation edit + if (isMultiCompEdit()) { + StyledLabel multiSimEditLabel = new StyledLabel("", -1, StyledLabel.Style.BOLD); + multiSimEditLabel.setFontColor(multiCompEditColor); + multiSimEditLabel.setText(trans.get("simedtdlg.title.MultiSimEdit")); + StringBuilder components = new StringBuilder(trans.get("simedtdlg.title.MultiSimEdit.ttip")); + for (int i = 0; i < simulationList.length; i++) { + if (i < simulationList.length - 1) { + components.append(simulationList[i].getName()).append(", "); + } else { + components.append(simulationList[i].getName()); + } + } + multiSimEditLabel.setToolTipText(components.toString()); + bottomPanel.add(multiSimEditLabel, "align left"); + } + + //// Run simulation button + // TODO: disable when sim is up to date? + /*JButton button = new SelectColorButton(trans.get("SimulationEditDialog.btn.simulateAndPlot")); + if (!isSingleEdit()) { + button.setText(trans.get("SimulationEditDialog.btn.simulate")); + } + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + copyChangesToAllSims(); + SimulationRunDialog dialog = SimulationRunDialog.runSimulations(parentWindow, SimulationEditDialog.this.document, simulationList); + if (allowsPlotMode() && dialog.isAllSimulationsSuccessful()) { + refreshView(); + setPlotMode(); + } + } + }); + simEditPanel.add(button, "align right, gapright 10lp, tag ok");*/ + + //// Cancel button + this.cancelButton = new SelectColorButton(trans.get("dlg.but.cancel")); + this.cancelButton.setToolTipText(trans.get("SimulationEditDialog.btn.Cancel.ttip")); + this.cancelButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (tabbedPane.getSelectedIndex() == SETTINGS_IDX) { + cancelSimEdit(); + } else { + // Normal close action + closeDialog(); + } + + // TODO: include plot/export undo? + } + }); + bottomPanel.add(this.cancelButton, "split 2, tag ok"); + + //// Ok button + this.okButton = new SelectColorButton(trans.get("dlg.but.ok")); + this.okButton.setToolTipText(trans.get("SimulationEditDialog.btn.OK.ttip")); + this.okButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + copyChangesToAllSims(); + + // Run outdated simulations + Simulation[] outdatedSims = getOutdatedSimulations(); + if (outdatedSims.length > 0) { + new SimulationRunDialog(SimulationConfigDialog.this.parentWindow, document, outdatedSims).setVisible(true); + } + + int tabIdx = tabbedPane.getSelectedIndex(); + if (tabIdx == PLOT_IDX) { + JDialog plot = plotTab.doPlot(SimulationConfigDialog.this.parentWindow); + if (plot != null) { + plot.setVisible(true); + } + closeDialog(); + return; + } else if (tabIdx == EXPORT_IDX) { + if (exportTab.doExport()) { + closeDialog(); + } + return; + } + + closeDialog(); + } + }); + bottomPanel.add(this.okButton, "tag ok"); + + contentPanel.add(bottomPanel, "growx, wrap"); + } + + private void copyChangesToAllSims() { + if (isMultiCompEdit()) { + for (int i = 1; i < simulationList.length; i++) { + simulationList[i].getOptions().copyConditionsFrom(simulationList[0].getOptions()); + simulationList[i].getSimulationExtensions().clear(); + for (SimulationExtension c : simulationList[0].getSimulationExtensions()) { + simulationList[i].getSimulationExtensions().add(c.clone()); + } + } + } + } + + private Simulation[] getOutdatedSimulations() { + List outdated = new ArrayList<>(); + for (Simulation sim : simulationList) { + if (!Simulation.isStatusUpToDate(sim.getStatus())) { + outdated.add(sim); + } + } + return outdated.toArray(new Simulation[0]); + } + + private boolean isMultiCompEdit() { + return simulationList.length > 1; + } + + private void closeDialog() { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + SimulationConfigDialog.this.removeWindowListener(applyChangesToSimsListener); + SimulationConfigDialog.this.dispose(); + } + }); + } + + private JPanel createCancelOperationContent() { + JPanel panel = new JPanel(new MigLayout()); + String msg = isNewSimulation ? trans.get("SimulationEditDialog.CancelOperation.msg.undoAdd") : + trans.get("SimulationEditDialog.CancelOperation.msg.discardChanges"); + JLabel msgLabel = new JLabel(msg); + JCheckBox dontAskAgain = new JCheckBox(trans.get("SimulationEditDialog.CancelOperation.checkbox.dontAskAgain")); + dontAskAgain.setSelected(false); + dontAskAgain.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + if (e.getStateChange() == ItemEvent.SELECTED) { + preferences.setShowDiscardSimulationConfirmation(false); + } + // Unselected state should be not be possible and thus not be handled + } + }); + + panel.add(msgLabel, "left, wrap"); + panel.add(dontAskAgain, "left, gaptop para"); + + return panel; + } + + private void cancelSimEdit() { + // Don't do anything on cancel if you are editing an existing simulation, and it is not modified + if (!isNewSimulation && !isModified) { + closeDialog(); + return; + } + + // Apply the cancel operation if set to auto discard in preferences + if (!preferences.isShowDiscardSimulationConfirmation()) { + discardChanges(); + return; + } + + // Yes/No dialog: Are you sure you want to discard your changes? + JPanel msg = createCancelOperationContent(); + int resultYesNo = JOptionPane.showConfirmDialog(SimulationConfigDialog.this, msg, + trans.get("SimulationEditDialog.CancelOperation.title"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); + if (resultYesNo == JOptionPane.YES_OPTION) { + discardChanges(); + } + } + + private void discardChanges() { + if (isNewSimulation) { + document.removeSimulation(simulationList[0]); + } else { + undoSimulationChanges(); + } + document.setSaved(this.initialIsSaved); // Restore the saved state of the document + document.fireDocumentChangeEvent(new DocumentChangeEvent(this)); + + closeDialog(); + } + + private void undoSimulationChanges() { + if (simulationList == null || simulationList.length == 0) { + return; + } + simulationList[0].loadFrom(initialSim); + } +} diff --git a/swing/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java b/swing/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java deleted file mode 100644 index 51fd38235..000000000 --- a/swing/src/net/sf/openrocket/gui/simulation/SimulationEditDialog.java +++ /dev/null @@ -1,476 +0,0 @@ -package net.sf.openrocket.gui.simulation; - - -import java.awt.CardLayout; -import java.awt.Color; -import java.awt.Window; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.awt.event.WindowListener; -import java.util.EventObject; - -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JDialog; -import javax.swing.JLabel; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JTabbedPane; -import javax.swing.JTextField; -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.document.events.DocumentChangeEvent; -import net.sf.openrocket.gui.components.ConfigurationComboBox; -import net.sf.openrocket.gui.components.StyledLabel; -import net.sf.openrocket.gui.util.GUIUtil; -import net.sf.openrocket.gui.util.UITheme; -import net.sf.openrocket.gui.widgets.SelectColorButton; -import net.sf.openrocket.l10n.Translator; -import net.sf.openrocket.rocketcomponent.FlightConfiguration; -import net.sf.openrocket.rocketcomponent.FlightConfigurationId; -import net.sf.openrocket.rocketcomponent.Rocket; -import net.sf.openrocket.simulation.extension.SimulationExtension; -import net.sf.openrocket.startup.Application; -import net.sf.openrocket.startup.Preferences; -import net.sf.openrocket.util.StateChangeListener; - - -public class SimulationEditDialog extends JDialog { - private static final long serialVersionUID = -4468157685542912715L; - private final Window parentWindow; - private final Simulation[] simulationList; - private final OpenRocketDocument document; - private static final Translator trans = Application.getTranslator(); - private static final Preferences preferences = Application.getPreferences(); - - JPanel cards; - private final static String EDITMODE = "EDIT"; - private final static String PLOTMODE = "PLOT"; - - private final WindowListener applyChangesToSimsListener; - private final Simulation initialSim; // A copy of the first selected simulation before it was modified - private final boolean initialIsSaved; // Whether the document was saved before the dialog was opened - private boolean isModified = false; // Whether the simulation has been modified - private final boolean isNewSimulation; // Whether you are editing a new simulation, or an existing one - - private static Color multiCompEditColor; - - static { - initColors(); - } - - public SimulationEditDialog(Window parent, final OpenRocketDocument document, boolean isNewSimulation, Simulation... sims) { - //// Edit simulation - super(parent, sims.length == 1 ? trans.get("simedtdlg.title.Editsim") : trans.get("simedtdlg.title.MultiSimEdit"), - JDialog.ModalityType.DOCUMENT_MODAL); - this.document = document; - this.parentWindow = parent; - this.simulationList = sims; - this.initialSim = simulationList[0].clone(); - this.initialIsSaved = document.isSaved(); - this.isNewSimulation = isNewSimulation; - - simulationList[0].addChangeListener(new StateChangeListener() { - @Override - public void stateChanged(EventObject e) { - isModified = true; - setTitle("* " + getTitle()); // Add component changed indicator to the title - simulationList[0].removeChangeListener(this); - } - }); - - this.cards = new JPanel(new CardLayout()); - this.add(cards); - buildEditCard(); - buildPlotCard(); - - this.validate(); - this.pack(); - - this.setLocationByPlatform(true); - - this.applyChangesToSimsListener = new WindowAdapter() { - @Override - public void windowClosed(WindowEvent e) { - copyChangesToAllSims(); - } - }; - this.addWindowListener(applyChangesToSimsListener); - - GUIUtil.setDisposableDialogOptions(this, null); - } - - private static void initColors() { - updateColors(); - UITheme.Theme.addUIThemeChangeListener(SimulationEditDialog::updateColors); - } - - private static void updateColors() { - multiCompEditColor = GUIUtil.getUITheme().getMultiCompEditColor(); - } - - private boolean isSingleEdit() { - return simulationList.length == 1; - } - - private boolean allowsPlotMode() { - return simulationList.length == 1 && simulationList[0].hasSimulationData(); - } - - public void setEditMode() { - String baseTitle = simulationList.length == 1 ? - trans.get("simedtdlg.title.Editsim") : trans.get("simedtdlg.title.MultiSimEdit"); - setTitle((isModified ? "* " : "") + baseTitle); - CardLayout cl = (CardLayout) (cards.getLayout()); - cl.show(cards, EDITMODE); - cards.validate(); - this.addWindowListener(applyChangesToSimsListener); - } - - public void setPlotMode() { - if (!allowsPlotMode()) { - return; - } - this.removeWindowListener(applyChangesToSimsListener); - setTitle((isModified ? "* " : "") + trans.get("simplotpanel.title.Plotsim")); - CardLayout cl = (CardLayout) (cards.getLayout()); - cl.show(cards, PLOTMODE); - cards.validate(); - } - - private void copyChangesToAllSims() { - if (simulationList.length > 1) { - for (int i = 1; i < simulationList.length; i++) { - simulationList[i].getOptions().copyConditionsFrom(simulationList[0].getOptions()); - simulationList[i].getSimulationExtensions().clear(); - for (SimulationExtension c : simulationList[0].getSimulationExtensions()) { - simulationList[i].getSimulationExtensions().add(c.clone()); - } - } - } - } - - private void refreshView() { - cards.removeAll(); - buildEditCard(); - buildPlotCard(); - this.validate(); - } - - private void buildEditCard() { - JPanel simEditPanel = new JPanel(new MigLayout("fill, hidemode 1")); - - if (isSingleEdit()) { - JPanel panel = new JPanel(new MigLayout("fill, ins 0")); - - //// Simulation name: - panel.add(new JLabel(trans.get("simedtdlg.lbl.Simname") + " "), "growx 0, gapright para"); - final JTextField field = new JTextField(simulationList[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; - simulationList[0].setName(name); - - } - }); - panel.add(field, "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")); - panel.add(label, "growx 0, gapright para"); - - final Rocket rkt = document.getRocket(); - final FlightConfiguration config = rkt.getFlightConfiguration(simulationList[0].getFlightConfigurationId()); - final ConfigurationComboBox configComboBox = new ConfigurationComboBox(rkt, false); - configComboBox.setSelectedItem(config); - - //// Select the motor configuration to use. - configComboBox.setToolTipText(trans.get("simedtdlg.combo.ttip.Flightcfg")); - configComboBox.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - FlightConfiguration config = (FlightConfiguration)configComboBox.getSelectedItem(); - FlightConfigurationId id = config.getId(); - - simulationList[0].setFlightConfigurationId( id ); - } - }); - panel.add(configComboBox, "span"); - - panel.add(new JPanel(), "growx, wrap"); - - simEditPanel.add(panel, "growx, wrap"); - } - JTabbedPane tabbedPane = new JTabbedPane(); - - //// Launch conditions - tabbedPane.addTab(trans.get("simedtdlg.tab.Launchcond"), new SimulationConditionsPanel(simulationList[0])); - //// Simulation options - tabbedPane.addTab(trans.get("simedtdlg.tab.Simopt"), new SimulationOptionsPanel(document, simulationList[0])); - - tabbedPane.setSelectedIndex(0); - - simEditPanel.add(tabbedPane, "spanx, grow, wrap"); - - - //// Open Plot button - JButton button = new SelectColorButton(trans.get("SimulationEditDialog.btn.plot") + " >>"); - button.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - SimulationEditDialog.this.setPlotMode(); - } - - }); - simEditPanel.add(button, "spanx, split 5, align left"); - if (allowsPlotMode()) { - button.setVisible(true); - } else { - button.setVisible(false); - } - - //// Multi-simulation edit - if (simulationList.length > 1) { - StyledLabel multiSimEditLabel = new StyledLabel("", -1, StyledLabel.Style.BOLD); - multiSimEditLabel.setFontColor(multiCompEditColor); - multiSimEditLabel.setText(trans.get("simedtdlg.title.MultiSimEdit")); - StringBuilder components = new StringBuilder(trans.get("simedtdlg.title.MultiSimEdit.ttip")); - for (int i = 0; i < simulationList.length; i++) { - if (i < simulationList.length - 1) { - components.append(simulationList[i].getName()).append(", "); - } else { - components.append(simulationList[i].getName()); - } - } - multiSimEditLabel.setToolTipText(components.toString()); - simEditPanel.add(multiSimEditLabel, "align left"); - } - - //// Run simulation button - button = new SelectColorButton(trans.get("SimulationEditDialog.btn.simulateAndPlot")); - if (!isSingleEdit()) { - button.setText(trans.get("SimulationEditDialog.btn.simulate")); - } - button.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - copyChangesToAllSims(); - SimulationRunDialog dialog = SimulationRunDialog.runSimulations(parentWindow, SimulationEditDialog.this.document, simulationList); - if (allowsPlotMode() && dialog.isAllSimulationsSuccessful()) { - refreshView(); - setPlotMode(); - } - } - }); - simEditPanel.add(button, "align right, gapright 10lp, tag ok"); - - //// Cancel button - JButton cancelButton = new SelectColorButton(trans.get("dlg.but.cancel")); - cancelButton.setToolTipText(trans.get("SimulationEditDialog.btn.Cancel.ttip")); - cancelButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - // Don't do anything on cancel if you are editing an existing simulation, and it is not modified - if (!isNewSimulation && !isModified) { - SimulationEditDialog.this.removeWindowListener(applyChangesToSimsListener); - SimulationEditDialog.this.dispose(); - return; - } - - // Apply the cancel operation if set to auto discard in preferences - if (!preferences.isShowDiscardSimulationConfirmation()) { - discardChanges(); - return; - } - - // Yes/No dialog: Are you sure you want to discard your changes? - JPanel msg = createCancelOperationContent(); - int resultYesNo = JOptionPane.showConfirmDialog(SimulationEditDialog.this, msg, - trans.get("SimulationEditDialog.CancelOperation.title"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); - if (resultYesNo == JOptionPane.YES_OPTION) { - discardChanges(); - } - } - }); - simEditPanel.add(cancelButton, "tag ok"); - - //// Ok button - JButton okButton = new SelectColorButton(trans.get("dlg.but.ok")); - okButton.setToolTipText(trans.get("SimulationEditDialog.btn.OK.ttip")); - okButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - copyChangesToAllSims(); - SimulationEditDialog.this.dispose(); - } - }); - simEditPanel.add(okButton, "tag ok"); - - cards.add(simEditPanel, EDITMODE); - } - - private void buildPlotCard() { - if (allowsPlotMode()) { - JPanel plotExportPanel = new JPanel(new MigLayout("fill")); - - //// Simulation name: - plotExportPanel.add(new JLabel(trans.get("simedtdlg.lbl.Simname") + " "), "span, split 2, shrink"); - final JTextField field = new JTextField(simulationList[0].getName()); - field.setEditable(false); - plotExportPanel.add(field, "shrinky, growx, wrap"); - - final JTabbedPane tabbedPane = new JTabbedPane(); - - //// Plot data - final SimulationPlotPanel plotTab = new SimulationPlotPanel(simulationList[0]); - tabbedPane.addTab(trans.get("simedtdlg.tab.Plotdata"), plotTab); - //// Export data - final SimulationExportPanel exportTab = new SimulationExportPanel(simulationList[0]); - tabbedPane.addTab(trans.get("simedtdlg.tab.Exportdata"), exportTab); - - plotExportPanel.add(tabbedPane, "grow, wrap"); - - JButton button = new SelectColorButton("<< " + trans.get("SimulationEditDialog.btn.edit")); - button.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - SimulationEditDialog.this.setEditMode(); - } - - }); - - plotExportPanel.add(button, "spanx, split 3, align left"); - - final JButton ok = new SelectColorButton(trans.get("SimulationEditDialog.btn.plot")); - - tabbedPane.addChangeListener(new ChangeListener() { - - @Override - public void stateChanged(ChangeEvent e) { - int selectedIndex = tabbedPane.getSelectedIndex(); - switch (selectedIndex) { - case 0: - ok.setText(trans.get("SimulationEditDialog.btn.plot")); - plotExportPanel.revalidate(); - break; - case 1: - ok.setText(trans.get("SimulationEditDialog.btn.export")); - plotExportPanel.revalidate(); - break; - } - } - - }); - - ok.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - // If the simulation is out of date, run the simulation. - if (!Simulation.isStatusUpToDate(simulationList[0].getStatus())) { - new SimulationRunDialog(SimulationEditDialog.this.parentWindow, document, simulationList[0]).setVisible(true); - } - - if (tabbedPane.getSelectedIndex() == 0) { - JDialog plot = plotTab.doPlot(SimulationEditDialog.this.parentWindow); - if (plot != null) { - plot.setVisible(true); - } - } else { - if (exportTab.doExport()) { - SimulationEditDialog.this.dispose(); - } - } - } - }); - plotExportPanel.add(ok, "tag ok, split 2"); - - //// Close button - JButton close = new SelectColorButton(trans.get("dlg.but.close")); - close.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - SimulationEditDialog.this.dispose(); - } - }); - plotExportPanel.add(close, "tag cancel"); - //plotExportPanel.validate(); - cards.add(plotExportPanel, PLOTMODE); - - } - } - - private JPanel createCancelOperationContent() { - JPanel panel = new JPanel(new MigLayout()); - String msg = isNewSimulation ? trans.get("SimulationEditDialog.CancelOperation.msg.undoAdd") : - trans.get("SimulationEditDialog.CancelOperation.msg.discardChanges"); - JLabel msgLabel = new JLabel(msg); - JCheckBox dontAskAgain = new JCheckBox(trans.get("SimulationEditDialog.CancelOperation.checkbox.dontAskAgain")); - dontAskAgain.setSelected(false); - dontAskAgain.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - if (e.getStateChange() == ItemEvent.SELECTED) { - preferences.setShowDiscardSimulationConfirmation(false); - } - // Unselected state should be not be possible and thus not be handled - } - }); - - panel.add(msgLabel, "left, wrap"); - panel.add(dontAskAgain, "left, gaptop para"); - - return panel; - } - - private void discardChanges() { - if (isNewSimulation) { - document.removeSimulation(simulationList[0]); - } else { - undoSimulationChanges(); - } - document.setSaved(this.initialIsSaved); // Restore the saved state of the document - document.fireDocumentChangeEvent(new DocumentChangeEvent(this)); - - SimulationEditDialog.this.removeWindowListener(applyChangesToSimsListener); - SimulationEditDialog.this.dispose(); - } - - private void undoSimulationChanges() { - if (simulationList == null || simulationList.length == 0) { - return; - } - simulationList[0].loadFrom(initialSim); - } -} diff --git a/swing/src/net/sf/openrocket/gui/simulation/SimulationPlotPanel.java b/swing/src/net/sf/openrocket/gui/simulation/SimulationPlotPanel.java index baba99187..5e4db1160 100644 --- a/swing/src/net/sf/openrocket/gui/simulation/SimulationPlotPanel.java +++ b/swing/src/net/sf/openrocket/gui/simulation/SimulationPlotPanel.java @@ -5,6 +5,7 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; +import java.io.Serial; import java.util.Arrays; import java.util.EnumSet; @@ -51,6 +52,7 @@ import net.sf.openrocket.gui.widgets.SelectColorButton; * @author Sampo Niskanen */ public class SimulationPlotPanel extends JPanel { + @Serial private static final long serialVersionUID = -2227129713185477998L; private static final Translator trans = Application.getTranslator(); diff --git a/swing/src/net/sf/openrocket/gui/simulation/SimulationSettingsPanel.java b/swing/src/net/sf/openrocket/gui/simulation/SimulationSettingsPanel.java new file mode 100644 index 000000000..466d4a3e6 --- /dev/null +++ b/swing/src/net/sf/openrocket/gui/simulation/SimulationSettingsPanel.java @@ -0,0 +1,36 @@ +package net.sf.openrocket.gui.simulation; + +import net.miginfocom.swing.MigLayout; +import net.sf.openrocket.document.OpenRocketDocument; +import net.sf.openrocket.document.Simulation; +import net.sf.openrocket.l10n.Translator; +import net.sf.openrocket.startup.Application; + +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import java.io.Serial; + +public class SimulationSettingsPanel extends JPanel { + @Serial + private static final long serialVersionUID = -2114129713185477998L; + + private static final Translator trans = Application.getTranslator(); + + public SimulationSettingsPanel(final OpenRocketDocument document, final Simulation simulation) { + super(new MigLayout("fill")); + + JTabbedPane tabbedPane = new JTabbedPane(); + + //// Launch conditions + tabbedPane.addTab(trans.get("simedtdlg.tab.Launchcond"), new SimulationConditionsPanel(simulation)); + + //// Simulation options + tabbedPane.addTab(trans.get("simedtdlg.tab.Simopt"), new SimulationOptionsPanel(document, simulation)); + + tabbedPane.setSelectedIndex(0); + + this.add(tabbedPane, "spanx, grow, wrap"); + } + + +}