Refactor SimulationPlotPanel to more generic PlotPanel

This commit is contained in:
SiboVG 2024-08-14 23:59:04 +02:00
parent 1465ed4f98
commit 809a50dd7c
4 changed files with 422 additions and 321 deletions

View File

@ -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<T extends DataType & Groupable<G>, B extends DataBranch<T>, 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<T, B> customConfiguration;
/** The array of presets for the combo box. */
private final PlotConfiguration<T, B>[] presetArray;
private PlotConfiguration<T, B> defaultConfiguration;
private final T[] types;
protected PlotConfiguration<T, B> configuration;
private JComboBox<PlotConfiguration<T, B>> configurationSelector;
protected GroupableAndSearchableComboBox<G, T> domainTypeSelector;
private UnitSelector domainUnitSelector;
private JPanel typeSelectorPanel;
protected int modifying = 0;
public PlotPanel(T[] types, PlotConfiguration<T, B> customConfiguration, PlotConfiguration<T, B>[] presets,
PlotConfiguration<T, B> 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<T, B> 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<T, B> conf = (PlotConfiguration<T, B>) 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<T, B> getConfiguration() {
return configuration;
}
protected void setConfiguration(PlotConfiguration<T, B> 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<T, B> 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<G, T> 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();
}
}

View File

@ -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<G extends Group, T extends Groupable<G> & UnitValu
return index;
}
public FlightDataType getSelectedType() {
return (FlightDataType) typeSelector.getSelectedItem();
public T getSelectedType() {
return (T) typeSelector.getSelectedItem();
}
public Unit getSelectedUnit() {

View File

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

View File

@ -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 <sampo.niskanen@iki.fi>
*/
public class SimulationPlotPanel extends JPanel {
public class SimulationPlotPanel extends PlotPanel<FlightDataType, FlightDataBranch, FlightDataTypeGroup> {
@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<SimulationPlotConfiguration> configurationSelector;
private GroupableAndSearchableComboBox<FlightDataTypeGroup, FlightDataType> 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<FlightDataType, FlightDataBranch> 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<FlightDataTypeGroup, FlightDataType> 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);
}
}