diff --git a/swing/src/main/java/info/openrocket/swing/gui/plot/PlotPanel.java b/swing/src/main/java/info/openrocket/swing/gui/plot/PlotPanel.java new file mode 100644 index 000000000..b2ecee292 --- /dev/null +++ b/swing/src/main/java/info/openrocket/swing/gui/plot/PlotPanel.java @@ -0,0 +1,311 @@ +package info.openrocket.swing.gui.plot; + +import info.openrocket.core.l10n.Translator; +import info.openrocket.core.simulation.DataBranch; +import info.openrocket.core.simulation.DataType; +import info.openrocket.core.startup.Application; +import info.openrocket.core.unit.Unit; +import info.openrocket.core.util.Group; +import info.openrocket.core.util.Groupable; +import info.openrocket.core.util.Utils; +import info.openrocket.swing.gui.components.UnitSelector; +import info.openrocket.swing.gui.widgets.GroupableAndSearchableComboBox; +import net.miginfocom.swing.MigLayout; + +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSeparator; +import java.awt.Component; +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.util.Arrays; + +public class PlotPanel, B extends DataBranch, G extends Group> extends JPanel { + private static final Translator trans = Application.getTranslator(); + + //// Custom + protected static final String CUSTOM = trans.get("simplotpanel.CUSTOM"); + /** The "Custom" configuration - not to be used for anything other than the title. */ + private final PlotConfiguration customConfiguration; + + /** The array of presets for the combo box. */ + private final PlotConfiguration[] presetArray; + + private PlotConfiguration defaultConfiguration; + + private final T[] types; + protected PlotConfiguration configuration; + + private JComboBox> configurationSelector; + + protected GroupableAndSearchableComboBox domainTypeSelector; + private UnitSelector domainUnitSelector; + + private JPanel typeSelectorPanel; + + protected int modifying = 0; + + public PlotPanel(T[] types, PlotConfiguration customConfiguration, PlotConfiguration[] presets, + PlotConfiguration defaultConfiguration, + Component[] extraWidgetsX, Component[] extraWidgetsY) { + super(new MigLayout("fill")); + + this.customConfiguration = customConfiguration; + this.presetArray = presets; + this.defaultConfiguration = defaultConfiguration; + this.types = types; + + setConfiguration(defaultConfiguration); + + //// Configuration selector + + // Setup the combo box + configurationSelector = new JComboBox<>(presetArray); + for (PlotConfiguration config : presetArray) { + if (config.getName().equals(configuration.getName())) { + configurationSelector.setSelectedItem(config); + } + } + + configurationSelector.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + // We are only concerned with ItemEvent.SELECTED to update + // the UI when the selected item changes. + // TODO - this should probably be implemented as an ActionListener instead + // of ItemStateListener. + if (e.getStateChange() == ItemEvent.DESELECTED) { + return; + } + if (modifying > 0) + return; + PlotConfiguration conf = (PlotConfiguration) configurationSelector.getSelectedItem(); + if (conf == null || conf == customConfiguration) + return; + modifying++; + setConfiguration(conf.clone().resetUnits()); + updatePlots(); + modifying--; + } + }); + //// Preset plot configurations: + this.add(new JLabel(trans.get("simplotpanel.lbl.Presetplotconf")), "spanx, split"); + this.add(configurationSelector, "growx, wrap 20lp"); + + + this.add(new JSeparator(JSeparator.HORIZONTAL), "spanx, growx, wrap"); + + + //// X axis + + //// X axis type: + this.add(new JLabel(trans.get("simplotpanel.lbl.Xaxistype")), "spanx, split"); + domainTypeSelector = new GroupableAndSearchableComboBox<>(Arrays.asList(types), trans.get("FlightDataComboBox.placeholder")); + domainTypeSelector.setSelectedItem(configuration.getDomainAxisType()); + domainTypeSelector.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + if (modifying > 0) + return; + T type = (T) domainTypeSelector.getSelectedItem(); + if (type == null) { + return; + } + configuration.setDomainAxisType(type); + domainUnitSelector.setUnitGroup(type.getUnitGroup()); + domainUnitSelector.setSelectedUnit(configuration.getDomainAxisUnit()); + setToCustom(); + } + }); + this.add(domainTypeSelector, "gapright para"); + + //// Unit: + this.add(new JLabel(trans.get("simplotpanel.lbl.Unit"))); + domainUnitSelector = new UnitSelector(configuration.getDomainAxisType().getUnitGroup()); + domainUnitSelector.setSelectedUnit(configuration.getDomainAxisUnit()); + domainUnitSelector.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + if (modifying > 0) + return; + configuration.setDomainAxisUnit(domainUnitSelector.getSelectedUnit()); + } + }); + this.add(domainUnitSelector, "width 40lp, gapright para"); + + // Extra X widgets + if (extraWidgetsX != null) { + for (int i = 0; i < extraWidgetsX.length; i++) { + if (i == extraWidgetsX.length - 1) { + this.add(extraWidgetsX[i], "growx, wrap"); + } else { + this.add(extraWidgetsX[i], "growx, wrap unrel"); + } + } + } else { + this.add(new JLabel(), "wrap unrel"); + } + + + //// Y axis selector panel + //// Y axis types: + this.add(new JLabel(trans.get("simplotpanel.lbl.Yaxistypes"))); + //// Flight events: + this.add(new JLabel(trans.get("simplotpanel.lbl.Flightevents")), "wrap rel"); + + typeSelectorPanel = new JPanel(new MigLayout("gapy rel")); + JScrollPane scroll = new JScrollPane(typeSelectorPanel); + int spanY = extraWidgetsY == null ? 1 : extraWidgetsY.length + 1; + this.add(scroll, "spany " + spanY + ", pushy, wmin 400lp, grow 100, gapright para"); + + // Extra Y widgets + if (extraWidgetsY != null) { + for (Component widgetsY : extraWidgetsY) { + this.add(widgetsY, "growx, wrap"); + } + this.add(new JPanel(), "pushy, wrap"); // Fill up the rest of the vertical space + } + + + //// New Y axis plot type + JButton newYAxisBtn = new JButton(trans.get("simplotpanel.but.NewYaxisplottype")); + newYAxisBtn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (configuration.getTypeCount() >= 15) { + JOptionPane.showMessageDialog(PlotPanel.this, + //// A maximum of 15 plots is allowed. + //// Cannot add plot + trans.get("simplotpanel.OptionPane.lbl1"), + trans.get("simplotpanel.OptionPane.lbl2"), + JOptionPane.ERROR_MESSAGE); + return; + } + + // Select new type smartly + T type = null; + for (T t : types) { + + 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 = types[0]; + } + + // Add new type + configuration.addPlotDataType(type); + setToCustom(); + updatePlots(); + } + }); + this.add(newYAxisBtn, "spanx, pushx, left"); + } + + protected PlotConfiguration getConfiguration() { + return configuration; + } + + protected void setConfiguration(PlotConfiguration conf) { + boolean modified = false; + + configuration = conf.clone(); + if (!Utils.contains(types, configuration.getDomainAxisType())) { + configuration.setDomainAxisType(types[0]); + modified = true; + } + + for (int i = 0; i < configuration.getTypeCount(); i++) { + if (!Utils.contains(types, configuration.getType(i))) { + configuration.removePlotDataType(i); + i--; + modified = true; + } + } + + if (modified) { + configuration.setName(CUSTOM); + } + } + + protected void setDefaultConfiguration(PlotConfiguration newConfiguration) { + defaultConfiguration = newConfiguration; + } + + + protected void setToCustom() { + modifying++; + configuration.setName(CUSTOM); + configurationSelector.setSelectedItem(customConfiguration); + modifying--; + } + + public JDialog doPlot(Window parent) { + throw new RuntimeException("Not implemented"); + } + + + protected void updatePlots() { + domainTypeSelector.setSelectedItem(configuration.getDomainAxisType()); + domainUnitSelector.setUnitGroup(configuration.getDomainAxisType().getUnitGroup()); + domainUnitSelector.setSelectedUnit(configuration.getDomainAxisUnit()); + + typeSelectorPanel.removeAll(); + for (int i = 0; i < configuration.getTypeCount(); i++) { + T type = configuration.getType(i); + Unit unit = configuration.getUnit(i); + int axis = configuration.getAxis(i); + + PlotTypeSelector selector = new PlotTypeSelector<>(i, type, unit, axis, Arrays.asList(types)); + int finalI = i; + selector.addTypeSelectionListener(e -> { + if (modifying > 0) return; + T selectedType = selector.getSelectedType(); + configuration.setPlotDataType(finalI, selectedType); + selector.setUnitGroup(selectedType.getUnitGroup()); + configuration.setPlotDataUnit(finalI, selector.getSelectedUnit()); + setToCustom(); + }); + selector.addUnitSelectionListener(e -> { + if (modifying > 0) return; + configuration.setPlotDataUnit(finalI, selector.getSelectedUnit()); + }); + selector.addAxisSelectionListener(e -> { + if (modifying > 0) return; + configuration.setPlotDataAxis(finalI, selector.getSelectedAxis()); + }); + selector.addRemoveButtonListener(e -> { + configuration.removePlotDataType(finalI); + setToCustom(); + updatePlots(); + }); + typeSelectorPanel.add(selector, "wrap"); + } + + // In order to consistently update the UI, we need to validate before repaint. + typeSelectorPanel.validate(); + typeSelectorPanel.repaint(); + } +} diff --git a/swing/src/main/java/info/openrocket/swing/gui/plot/PlotTypeSelector.java b/swing/src/main/java/info/openrocket/swing/gui/plot/PlotTypeSelector.java index 22e08a012..56ea3cbf4 100644 --- a/swing/src/main/java/info/openrocket/swing/gui/plot/PlotTypeSelector.java +++ b/swing/src/main/java/info/openrocket/swing/gui/plot/PlotTypeSelector.java @@ -1,7 +1,6 @@ package info.openrocket.swing.gui.plot; import info.openrocket.core.l10n.Translator; -import info.openrocket.core.simulation.FlightDataType; import info.openrocket.core.startup.Application; import info.openrocket.core.unit.Unit; import info.openrocket.core.unit.UnitGroup; @@ -67,8 +66,8 @@ public class PlotTypeSelector & UnitValu return index; } - public FlightDataType getSelectedType() { - return (FlightDataType) typeSelector.getSelectedItem(); + public T getSelectedType() { + return (T) typeSelector.getSelectedItem(); } public Unit getSelectedUnit() { diff --git a/swing/src/main/java/info/openrocket/swing/gui/simulation/SimulationConfigDialog.java b/swing/src/main/java/info/openrocket/swing/gui/simulation/SimulationConfigDialog.java index 61391be72..7027b024a 100644 --- a/swing/src/main/java/info/openrocket/swing/gui/simulation/SimulationConfigDialog.java +++ b/swing/src/main/java/info/openrocket/swing/gui/simulation/SimulationConfigDialog.java @@ -119,7 +119,7 @@ public class SimulationConfigDialog extends JDialog { //// Plot data boolean hasData = simulationList[0].hasSimulationData(); if (hasData) { - this.plotTab = new SimulationPlotPanel(simulationList[0]); + this.plotTab = SimulationPlotPanel.create(simulationList[0]); } else { this.plotTab = null; } diff --git a/swing/src/main/java/info/openrocket/swing/gui/simulation/SimulationPlotPanel.java b/swing/src/main/java/info/openrocket/swing/gui/simulation/SimulationPlotPanel.java index 0a3533215..feabfa66d 100644 --- a/swing/src/main/java/info/openrocket/swing/gui/simulation/SimulationPlotPanel.java +++ b/swing/src/main/java/info/openrocket/swing/gui/simulation/SimulationPlotPanel.java @@ -1,5 +1,6 @@ package info.openrocket.swing.gui.simulation; +import java.awt.Component; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -12,7 +13,6 @@ import java.util.EnumSet; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.JButton; -import javax.swing.JComboBox; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JOptionPane; @@ -32,16 +32,13 @@ import info.openrocket.core.simulation.FlightDataTypeGroup; import info.openrocket.core.simulation.FlightEvent; import info.openrocket.core.startup.Application; import info.openrocket.core.preferences.ApplicationPreferences; -import info.openrocket.core.unit.Unit; -import info.openrocket.core.util.Utils; +import info.openrocket.swing.gui.plot.PlotConfiguration; +import info.openrocket.swing.gui.plot.PlotPanel; import info.openrocket.swing.gui.plot.SimulationPlotConfiguration; -import info.openrocket.swing.gui.widgets.GroupableAndSearchableComboBox; -import info.openrocket.swing.gui.widgets.PlotTypeSelector; +import info.openrocket.swing.gui.plot.SimulationPlotDialog; import net.miginfocom.swing.MigLayout; import info.openrocket.swing.gui.components.DescriptionArea; -import info.openrocket.swing.gui.components.UnitSelector; -import info.openrocket.swing.gui.plot.SimulationPlotDialog; import info.openrocket.swing.gui.util.GUIUtil; import info.openrocket.swing.gui.util.SwingPreferences; import info.openrocket.swing.gui.theme.UITheme; @@ -51,124 +48,57 @@ import info.openrocket.swing.gui.theme.UITheme; * * @author Sampo Niskanen */ -public class SimulationPlotPanel extends JPanel { +public class SimulationPlotPanel extends PlotPanel { @Serial private static final long serialVersionUID = -2227129713185477998L; private static final Translator trans = Application.getTranslator(); private static final SwingPreferences preferences = (SwingPreferences) Application.getPreferences(); - - //// Custom - private static final String CUSTOM = trans.get("simplotpanel.CUSTOM"); /** The "Custom" configuration - not to be used for anything other than the title. */ private static final SimulationPlotConfiguration CUSTOM_CONFIGURATION; - static { - CUSTOM_CONFIGURATION = new SimulationPlotConfiguration(CUSTOM); - } /** The array of presets for the combo box. */ private static final SimulationPlotConfiguration[] PRESET_ARRAY; + + + /** The current default configuration, set each time a plot is made. */ + private static SimulationPlotConfiguration DEFAULT_CONFIGURATION = + SimulationPlotConfiguration.DEFAULT_CONFIGURATIONS[0].resetUnits(); + + + private final Simulation simulation; + private FlightEventTableModel eventTableModel; + private static java.awt.Color darkErrorColor; + static { + initColors(); + + CUSTOM_CONFIGURATION = new SimulationPlotConfiguration(CUSTOM); + PRESET_ARRAY = Arrays.copyOf(SimulationPlotConfiguration.DEFAULT_CONFIGURATIONS, SimulationPlotConfiguration.DEFAULT_CONFIGURATIONS.length + 1); PRESET_ARRAY[PRESET_ARRAY.length - 1] = CUSTOM_CONFIGURATION; } - - - /** The current default configuration, set each time a plot is made. */ - private static SimulationPlotConfiguration defaultConfiguration = - SimulationPlotConfiguration.DEFAULT_CONFIGURATIONS[0].resetUnits(); - - - private final Simulation simulation; - private final FlightDataType[] types; - private SimulationPlotConfiguration configuration; - - - private JComboBox configurationSelector; - - private GroupableAndSearchableComboBox domainTypeSelector; - private UnitSelector domainUnitSelector; - - private JPanel typeSelectorPanel; - private FlightEventTableModel eventTableModel; - - - private int modifying = 0; - - private DescriptionArea simPlotPanelDesc; - - private static java.awt.Color darkErrorColor; - - static { - initColors(); - } - - public SimulationPlotPanel(final Simulation simulation) { - super(new MigLayout("fill")); + private SimulationPlotPanel(final Simulation simulation, FlightDataType[] types, + final DescriptionArea simPlotPanelDesc, + Component[] extraWidgetsX, JPanel selectorPanel, Component[] extraWidgetsY) { + super(types, CUSTOM_CONFIGURATION, PRESET_ARRAY, DEFAULT_CONFIGURATION, extraWidgetsX, extraWidgetsY); this.simulation = simulation; - if (simulation.getSimulatedData() == null || - simulation.getSimulatedData().getBranchCount() == 0) { - throw new IllegalArgumentException("Simulation contains no data."); - } - FlightDataBranch branch = simulation.getSimulatedData().getBranch(0); - types = branch.getTypes(); - - setConfiguration(defaultConfiguration); - - //// Configuration selector - - // Setup the combo box - configurationSelector = new JComboBox<>(PRESET_ARRAY); - for (SimulationPlotConfiguration config : PRESET_ARRAY) { - if (config.getName().equals(configuration.getName())) { - configurationSelector.setSelectedItem(config); - } - } - - configurationSelector.addItemListener(new ItemListener() { - - @Override - public void itemStateChanged(ItemEvent e) { - // We are only concerned with ItemEvent.SELECTED to update - // the UI when the selected item changes. - // TODO - this should probably be implemented as an ActionListener instead - // of ItemStateListener. - if (e.getStateChange() == ItemEvent.DESELECTED) { - return; - } - if (modifying > 0) - return; - SimulationPlotConfiguration conf = (SimulationPlotConfiguration) configurationSelector.getSelectedItem(); - if (conf == CUSTOM_CONFIGURATION) - return; - modifying++; - setConfiguration(conf.clone().resetUnits()); - updatePlots(); - modifying--; - } - }); - //// Preset plot configurations: - this.add(new JLabel(trans.get("simplotpanel.lbl.Presetplotconf")), "spanx, split"); - this.add(configurationSelector, "growx, wrap 20lp"); - - - - //// X axis - - //// X axis type: - this.add(new JLabel(trans.get("simplotpanel.lbl.Xaxistype")), "spanx, split"); - domainTypeSelector = new GroupableAndSearchableComboBox<>(Arrays.asList(types), trans.get("FlightDataComboBox.placeholder")); - domainTypeSelector.setSelectedItem(configuration.getDomainAxisType()); + + + //// X axis listeners domainTypeSelector.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { if (modifying > 0) return; FlightDataType type = (FlightDataType) domainTypeSelector.getSelectedItem(); + if (type == null) { + return; + } if (type == FlightDataType.TYPE_TIME) { simPlotPanelDesc.setVisible(false); simPlotPanelDesc.setText(""); @@ -177,49 +107,58 @@ public class SimulationPlotPanel extends JPanel { simPlotPanelDesc.setVisible(true); simPlotPanelDesc.setText(trans.get("simplotpanel.Desc")); } - configuration.setDomainAxisType(type); - domainUnitSelector.setUnitGroup(type.getUnitGroup()); - domainUnitSelector.setSelectedUnit(configuration.getDomainAxisUnit()); - setToCustom(); } }); - this.add(domainTypeSelector, "gapright para"); - - //// Unit: - this.add(new JLabel(trans.get("simplotpanel.lbl.Unit"))); - domainUnitSelector = new UnitSelector(configuration.getDomainAxisType().getUnitGroup()); - domainUnitSelector.setSelectedUnit(configuration.getDomainAxisUnit()); - domainUnitSelector.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - if (modifying > 0) - return; - configuration.setDomainAxisUnit(domainUnitSelector.getSelectedUnit()); - } - }); - this.add(domainUnitSelector, "width 40lp, gapright para"); + + //// Y axis + addFlightEventsSelectorWidgets(selectorPanel); + + this.add(new JPanel(), "growx"); + + updatePlots(); + } + + public static SimulationPlotPanel create(Simulation simulation) { + // Check the simulation data + if (simulation.getSimulatedData() == null || + simulation.getSimulatedData().getBranchCount() == 0) { + throw new IllegalArgumentException("Simulation contains no data."); + } + FlightDataBranch branch = simulation.getSimulatedData().getBranch(0); + FlightDataType[] types = branch.getTypes(); + + // Create extra widgets for the X axis //// The data will be plotted in time order even if the X axis type is not time. - simPlotPanelDesc = new DescriptionArea("", 2, -2.0f, false); + DescriptionArea simPlotPanelDesc = new DescriptionArea("", 2, -2.0f, false); simPlotPanelDesc.setVisible(false); simPlotPanelDesc.setForeground(darkErrorColor); simPlotPanelDesc.setViewportBorder(BorderFactory.createEmptyBorder()); - this.add(simPlotPanelDesc, "width 1px, growx 1, wrap unrel"); - - - - - //// Y axis selector panel - //// Y axis types: - this.add(new JLabel(trans.get("simplotpanel.lbl.Yaxistypes"))); - //// Flight events: - this.add(new JLabel(trans.get("simplotpanel.lbl.Flightevents")), "wrap rel"); - - typeSelectorPanel = new JPanel(new MigLayout("gapy rel")); - JScrollPane scroll = new JScrollPane(typeSelectorPanel); - this.add(scroll, "spany 3, height 10px, wmin 400lp, grow 100, gapright para"); - - + Component[] extraWidgetsX = new Component[] {simPlotPanelDesc}; + + // Create extra widgets for the Y axis + JPanel selectorPanel = new JPanel(new MigLayout("ins 0")); + Component[] extraWidgetsY = new Component[] {selectorPanel}; + + return new SimulationPlotPanel(simulation, types, simPlotPanelDesc, extraWidgetsX, selectorPanel, extraWidgetsY); + } + + private static void initColors() { + updateColors(); + UITheme.Theme.addUIThemeChangeListener(SimulationPlotPanel::updateColors); + } + + private static void updateColors() { + darkErrorColor = GUIUtil.getUITheme().getDarkErrorColor(); + } + + @Override + protected void setDefaultConfiguration(PlotConfiguration newConfiguration) { + super.setDefaultConfiguration(newConfiguration); + DEFAULT_CONFIGURATION = (SimulationPlotConfiguration) newConfiguration; + } + + private void addFlightEventsSelectorWidgets(JPanel selectorPanel) { //// Flight events eventTableModel = new FlightEventTableModel(); JTable table = new JTable(eventTableModel); @@ -227,7 +166,7 @@ public class SimulationPlotPanel extends JPanel { table.setShowVerticalLines(false); table.setRowSelectionAllowed(false); table.setColumnSelectionAllowed(false); - + TableColumnModel columnModel = table.getColumnModel(); TableColumn col0 = columnModel.getColumn(0); int w = table.getRowHeight() + 2; @@ -235,33 +174,41 @@ 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"); - - + selectorPanel.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() { @Override public void actionPerformed(ActionEvent e) { - for (FlightEvent.Type t : FlightEvent.Type.values()) - configuration.setEvent(t, true); + for (FlightEvent.Type t : FlightEvent.Type.values()) { + SimulationPlotConfiguration configuration = (SimulationPlotConfiguration) getConfiguration(); + if (configuration != null) { + configuration.setEvent(t, true); + } + } eventTableModel.fireTableDataChanged(); } }); - this.add(button, "split 2, gapleft para, gapright para, growx, sizegroup buttons"); - + selectorPanel.add(button, "split 2, gapleft para, gapright para, growx, sizegroup buttons"); + //// None button = new JButton(trans.get("simplotpanel.but.None")); button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - for (FlightEvent.Type t : FlightEvent.Type.values()) - configuration.setEvent(t, false); + for (FlightEvent.Type t : FlightEvent.Type.values()) { + SimulationPlotConfiguration configuration = (SimulationPlotConfiguration) getConfiguration(); + if (configuration != null) { + configuration.setEvent(t, false); + } + } eventTableModel.fireTableDataChanged(); } }); - this.add(button, "gapleft para, gapright para, growx, sizegroup buttons, wrap"); - + selectorPanel.add(button, "gapleft para, gapright para, growx, sizegroup buttons, wrap"); + //// Style event marker JLabel styleEventMarker = new JLabel(trans.get("simplotpanel.MarkerStyle.lbl.MarkerStyle")); @@ -295,93 +242,9 @@ public class SimulationPlotPanel extends JPanel { }); updateStyleEventWidgets(styleEventMarker, radioVerticalMarker, radioIcon); - this.add(styleEventMarker, "split 3, growx"); - this.add(radioVerticalMarker); - this.add(radioIcon, "wrap para"); - - - //// New Y axis plot type - button = new JButton(trans.get("simplotpanel.but.NewYaxisplottype")); - button.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - if (configuration.getTypeCount() >= 15) { - JOptionPane.showMessageDialog(SimulationPlotPanel.this, - //// A maximum of 15 plots is allowed. - //// Cannot add plot - trans.get("simplotpanel.OptionPane.lbl1"), - trans.get("simplotpanel.OptionPane.lbl2"), - JOptionPane.ERROR_MESSAGE); - return; - } - - // 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; - } - } - } - - 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() { - @Override - public void actionPerformed(ActionEvent e) { - if (configuration.getTypeCount() == 0) { - JOptionPane.showMessageDialog(SimulationPlotPanel.this, - trans.get("error.noPlotSelected"), - trans.get("error.noPlotSelected.title"), - JOptionPane.ERROR_MESSAGE); - return; - } - defaultConfiguration = configuration.clone(); - SimulationPlotDialog.showPlot(SwingUtilities.getWindowAncestor(SimulationPlotPanel.this), - simulation, configuration); - } - }); - this.add(button, "right"); - */ - updatePlots(); - } - - private static void initColors() { - updateColors(); - UITheme.Theme.addUIThemeChangeListener(SimulationPlotPanel::updateColors); - } - - private static void updateColors() { - darkErrorColor = GUIUtil.getUITheme().getDarkErrorColor(); + selectorPanel.add(styleEventMarker, "split 3, growx"); + selectorPanel.add(radioVerticalMarker); + selectorPanel.add(radioIcon, "wrap"); } private void updateStyleEventWidgets(JLabel styleEventMarker, JRadioButton radioVerticalMarker, JRadioButton radioIcon) { @@ -396,7 +259,8 @@ public class SimulationPlotPanel extends JPanel { radioVerticalMarker.setToolTipText(isTime ? null : trans.get("simplotpanel.MarkerStyle.OnlyInTime")); radioIcon.setToolTipText(isTime ? null : trans.get("simplotpanel.MarkerStyle.OnlyInTime")); } - + + @Override public JDialog doPlot(Window parent) { if (configuration.getTypeCount() == 0) { JOptionPane.showMessageDialog(SimulationPlotPanel.this, @@ -405,89 +269,16 @@ public class SimulationPlotPanel extends JPanel { JOptionPane.ERROR_MESSAGE); return null; } - defaultConfiguration = configuration.clone(); - return SimulationPlotDialog.getPlot(parent, simulation, configuration); + setDefaultConfiguration(configuration.clone()); + return SimulationPlotDialog.getPlot(parent, simulation, (SimulationPlotConfiguration) configuration); } - - private void setConfiguration(SimulationPlotConfiguration conf) { - - boolean modified = false; - - configuration = conf.clone(); - if (!Utils.contains(types, configuration.getDomainAxisType())) { - configuration.setDomainAxisType(types[0]); - modified = true; - } - - for (int i = 0; i < configuration.getTypeCount(); i++) { - if (!Utils.contains(types, configuration.getType(i))) { - configuration.removePlotDataType(i); - i--; - modified = true; - } - } - - if (modified) { - configuration.setName(CUSTOM); - } - - } - - - private void setToCustom() { - modifying++; - configuration.setName(CUSTOM); - configurationSelector.setSelectedItem(CUSTOM_CONFIGURATION); - modifying--; - } - - - private void updatePlots() { - domainTypeSelector.setSelectedItem(configuration.getDomainAxisType()); - domainUnitSelector.setUnitGroup(configuration.getDomainAxisType().getUnitGroup()); - domainUnitSelector.setSelectedUnit(configuration.getDomainAxisUnit()); - - typeSelectorPanel.removeAll(); - for (int i = 0; i < configuration.getTypeCount(); i++) { - FlightDataType type = configuration.getType(i); - Unit unit = configuration.getUnit(i); - int axis = configuration.getAxis(i); - PlotTypeSelector selector = new PlotTypeSelector<>(i, type, unit, axis, Arrays.asList(types)); - int finalI = i; - selector.addTypeSelectionListener(e -> { - if (modifying > 0) return; - FlightDataType selectedType = selector.getSelectedType(); - configuration.setPlotDataType(finalI, selectedType); - selector.setUnitGroup(selectedType.getUnitGroup()); - configuration.setPlotDataUnit(finalI, selector.getSelectedUnit()); - setToCustom(); - }); - selector.addUnitSelectionListener(e -> { - if (modifying > 0) return; - configuration.setPlotDataUnit(finalI, selector.getSelectedUnit()); - }); - selector.addAxisSelectionListener(e -> { - if (modifying > 0) return; - configuration.setPlotDataAxis(finalI, selector.getSelectedAxis()); - }); - selector.addRemoveButtonListener(e -> { - configuration.removePlotDataType(finalI); - setToCustom(); - updatePlots(); - }); - typeSelectorPanel.add(selector, "wrap"); - } - - // In order to consistantly update the ui, we need to validate before repaint. - typeSelectorPanel.validate(); - typeSelectorPanel.repaint(); - + @Override + protected void updatePlots() { + super.updatePlots(); eventTableModel.fireTableDataChanged(); } - - private class FlightEventTableModel extends AbstractTableModel { private static final long serialVersionUID = -1108240805614567627L; private final FlightEvent.Type[] eventTypes; @@ -534,7 +325,7 @@ public class SimulationPlotPanel extends JPanel { @Override public Object getValueAt(int row, int column) { return switch (column) { - case 0 -> Boolean.valueOf(configuration.isEventActive(eventTypes[row])); + case 0 -> ((SimulationPlotConfiguration) configuration).isEventActive(eventTypes[row]); case 1 -> eventTypes[row].toString(); default -> throw new IndexOutOfBoundsException("column=" + column); }; @@ -550,8 +341,8 @@ public class SimulationPlotPanel extends JPanel { if (column != 0 || !(value instanceof Boolean)) { throw new IllegalArgumentException("column=" + column + ", value=" + value); } - - configuration.setEvent(eventTypes[row], (Boolean) value); + + ((SimulationPlotConfiguration) configuration).setEvent(eventTypes[row], (Boolean) value); this.fireTableCellUpdated(row, column); } }