Bug fixes and startup checks
[debian/openrocket] / src / net / sf / openrocket / gui / plot / PlotPanel.java
1 package net.sf.openrocket.gui.plot;
2
3 import java.awt.event.ActionEvent;
4 import java.awt.event.ActionListener;
5 import java.awt.event.ItemEvent;
6 import java.awt.event.ItemListener;
7 import java.util.Arrays;
8
9 import javax.swing.JButton;
10 import javax.swing.JComboBox;
11 import javax.swing.JLabel;
12 import javax.swing.JOptionPane;
13 import javax.swing.JPanel;
14 import javax.swing.JScrollPane;
15 import javax.swing.SwingUtilities;
16
17 import net.miginfocom.swing.MigLayout;
18 import net.sf.openrocket.document.Simulation;
19 import net.sf.openrocket.gui.components.ResizeLabel;
20 import net.sf.openrocket.gui.components.UnitSelector;
21 import net.sf.openrocket.simulation.FlightDataBranch;
22 import net.sf.openrocket.simulation.FlightDataBranch.Type;
23 import net.sf.openrocket.unit.Unit;
24
25 public class PlotPanel extends JPanel {
26         
27         // TODO: LOW: Should these be somewhere else?
28         public static final int AUTO = -1;
29         public static final int LEFT = 0;
30         public static final int RIGHT = 1;
31         
32         public static final String AUTO_NAME = "Auto";
33         public static final String LEFT_NAME = "Left";
34         public static final String RIGHT_NAME = "Right";
35         
36         private static final String CUSTOM = "Custom";
37         
38         /** The "Custom" configuration - not to be used for anything other than the title. */
39         private static final PlotConfiguration CUSTOM_CONFIGURATION;
40         static {
41                 CUSTOM_CONFIGURATION = new PlotConfiguration(CUSTOM);
42         }
43         
44         /** The array of presets for the combo box. */
45         private static final PlotConfiguration[] PRESET_ARRAY;
46         static {
47                 PRESET_ARRAY = Arrays.copyOf(PlotConfiguration.DEFAULT_CONFIGURATIONS, 
48                                 PlotConfiguration.DEFAULT_CONFIGURATIONS.length + 1);
49                 PRESET_ARRAY[PRESET_ARRAY.length-1] = CUSTOM_CONFIGURATION;
50         }
51         
52         
53         
54         /** The current default configuration, set each time a plot is made. */
55         private static PlotConfiguration defaultConfiguration =
56                 PlotConfiguration.DEFAULT_CONFIGURATIONS[0].resetUnits();
57         
58         
59         private final Simulation simulation;
60         private final FlightDataBranch.Type[] types;
61         private PlotConfiguration configuration;
62         
63
64         private JComboBox configurationSelector;
65         
66         private JComboBox domainTypeSelector;
67         private UnitSelector domainUnitSelector;
68         
69         private JPanel typeSelectorPanel;
70         
71         
72         private int modifying = 0;
73         
74
75         public PlotPanel(final Simulation simulation) {
76                 super(new MigLayout("fill"));
77                 
78                 this.simulation = simulation;
79                 if (simulation.getSimulatedData() == null  ||
80                                 simulation.getSimulatedData().getBranchCount()==0) {
81                         throw new IllegalArgumentException("Simulation contains no data.");
82                 }
83                 FlightDataBranch branch = simulation.getSimulatedData().getBranch(0);
84                 types = branch.getTypes();
85                 
86                 // TODO: LOW: Revert to custom if data type is not available.
87                 configuration = defaultConfiguration.clone();
88                 
89                 
90                 
91                 
92                 // Setup the combo box
93                 configurationSelector = new JComboBox(PRESET_ARRAY);
94                 for (PlotConfiguration config: PRESET_ARRAY) {
95                         if (config.getName().equals(configuration.getName())) {
96                                 configurationSelector.setSelectedItem(config);
97                         }
98                 }
99                 configurationSelector.addItemListener(new ItemListener() {
100                         @Override
101                         public void itemStateChanged(ItemEvent e) {
102                                 if (modifying > 0)
103                                         return;
104                                 PlotConfiguration conf = (PlotConfiguration)configurationSelector.getSelectedItem();
105                                 if (conf == CUSTOM_CONFIGURATION)
106                                         return;
107                                 modifying++;
108                                 configuration = conf.clone().resetUnits();
109                                 updatePlots();
110                                 modifying--;
111                         }
112                 });
113                 this.add(new JLabel("Preset plot configurations: "), "spanx, split");
114                 this.add(configurationSelector,"growx, wrap 30lp");
115
116                 
117                 
118                 this.add(new JLabel("X axis type:"), "spanx, split");
119                 domainTypeSelector = new JComboBox(types);
120                 domainTypeSelector.setSelectedItem(configuration.getDomainAxisType());
121                 domainTypeSelector.addItemListener(new ItemListener() {
122                         @Override
123                         public void itemStateChanged(ItemEvent e) {
124                                 if (modifying > 0)
125                                         return;
126                                 FlightDataBranch.Type type = (Type) domainTypeSelector.getSelectedItem();
127                                 configuration.setDomainAxisType(type);
128                                 domainUnitSelector.setUnitGroup(type.getUnitGroup());
129                                 domainUnitSelector.setSelectedUnit(configuration.getDomainAxisUnit());
130                                 setToCustom();
131                         }
132                 });
133                 this.add(domainTypeSelector, "gapright para");
134
135                 
136                 this.add(new JLabel("Unit:"));
137                 domainUnitSelector = new UnitSelector(configuration.getDomainAxisType().getUnitGroup());
138                 domainUnitSelector.setSelectedUnit(configuration.getDomainAxisUnit());
139                 domainUnitSelector.addItemListener(new ItemListener() {
140                         @Override
141                         public void itemStateChanged(ItemEvent e) {
142                                 if (modifying > 0)
143                                         return;
144                                 configuration.setDomainAxisUnit(domainUnitSelector.getSelectedUnit());
145                         }
146                 });
147                 this.add(domainUnitSelector, "width 40lp, gapright para");
148                 
149                 
150                 ResizeLabel desc = new ResizeLabel("<html><p>The data will be plotted in time order " +
151                                 "even if the X axis type is not time.", -2);
152                 this.add(desc, "width :0px:, growx, wrap para");
153                 
154                 
155                 
156                 this.add(new JLabel("Y axis types:"), "spanx, wrap rel");
157                 
158                 typeSelectorPanel = new JPanel(new MigLayout("gapy rel"));
159                 JScrollPane scroll = new JScrollPane(typeSelectorPanel);
160                 this.add(scroll, "spanx, height :0:, grow, wrap para");
161                 
162                 
163                 JButton button = new JButton("New Y axis plot type");
164                 button.addActionListener(new ActionListener() {
165                         @Override
166                         public void actionPerformed(ActionEvent e) {
167                                 if (configuration.getTypeCount() >= 15) {
168                                         JOptionPane.showMessageDialog(PlotPanel.this, 
169                                                         "A maximum of 15 plots is allowed.", "Cannot add plot", 
170                                                         JOptionPane.ERROR_MESSAGE);
171                                         return;
172                                 }
173
174                                 // Select new type smartly
175                                 FlightDataBranch.Type type = null;
176                                 for (FlightDataBranch.Type t: 
177                                         simulation.getSimulatedData().getBranch(0).getTypes()) {
178                                         
179                                         boolean used = false;
180                                         if (configuration.getDomainAxisType().equals(t)) {
181                                                 used = true;
182                                         } else {
183                                                 for (int i=0; i < configuration.getTypeCount(); i++) {
184                                                         if (configuration.getType(i).equals(t)) {
185                                                                 used = true;
186                                                                 break;
187                                                         }
188                                                 }
189                                         }
190                                         
191                                         if (!used) {
192                                                 type = t;
193                                                 break;
194                                         }
195                                 }
196                                 if (type == null) {
197                                         type = simulation.getSimulatedData().getBranch(0).getTypes()[0];
198                                 }
199                                 
200                                 // Add new type
201                                 configuration.addPlotDataType(type);
202                                 setToCustom();
203                                 updatePlots();
204                         }
205                 });
206                 this.add(button, "spanx, split");
207                 
208                 this.add(new JPanel(), "growx");
209                 
210                 button = new JButton("Plot flight");
211                 button.addActionListener(new ActionListener() {
212                         @Override
213                         public void actionPerformed(ActionEvent e) {
214                                 defaultConfiguration = configuration.clone();
215                                 PlotDialog.showPlot(SwingUtilities.getWindowAncestor(PlotPanel.this), 
216                                                 simulation, configuration);
217                         }
218                 });
219                 this.add(button, "right");
220
221                 
222                 updatePlots();
223         }
224         
225         
226         private void setToCustom() {
227                 configuration.setName(CUSTOM);
228                 configurationSelector.setSelectedItem(CUSTOM_CONFIGURATION);
229         }
230         
231         
232         private void updatePlots() {
233                 domainTypeSelector.setSelectedItem(configuration.getDomainAxisType());
234                 domainUnitSelector.setUnitGroup(configuration.getDomainAxisType().getUnitGroup());
235                 domainUnitSelector.setSelectedUnit(configuration.getDomainAxisUnit());
236                 
237                 typeSelectorPanel.removeAll();
238                 for (int i=0; i < configuration.getTypeCount(); i++) {
239                         FlightDataBranch.Type type = configuration.getType(i);
240                         Unit unit = configuration.getUnit(i);
241                         int axis = configuration.getAxis(i);
242                         
243                         typeSelectorPanel.add(new PlotTypeSelector(i, type, unit, axis), "wrap");
244                 }
245                 
246                 typeSelectorPanel.repaint();
247         }
248         
249         
250         
251         
252         /**
253          * A JPanel which configures a single plot of a PlotConfiguration.
254          */
255         private class PlotTypeSelector extends JPanel {
256                 private final String[] POSITIONS = { AUTO_NAME, LEFT_NAME, RIGHT_NAME };
257                 
258                 private final int index;
259                 private JComboBox typeSelector;
260                 private UnitSelector unitSelector;
261                 private JComboBox axisSelector;
262                 
263                 
264                 public PlotTypeSelector(int index, FlightDataBranch.Type type) {
265                         this (index, type, null, -1);
266                 }
267                 
268                 public PlotTypeSelector(int plotIndex, FlightDataBranch.Type type, Unit unit, int position) {
269                         super(new MigLayout(""));
270                         
271                         this.index = plotIndex;
272                         
273                         typeSelector = new JComboBox(types);
274                         typeSelector.setSelectedItem(type);
275                         typeSelector.addItemListener(new ItemListener() {
276                                 @Override
277                                 public void itemStateChanged(ItemEvent e) {
278                                         if (modifying > 0)
279                                                 return;
280                                         FlightDataBranch.Type type = (Type) typeSelector.getSelectedItem();
281                                         configuration.setPlotDataType(index, type);
282                                         unitSelector.setUnitGroup(type.getUnitGroup());
283                                         unitSelector.setSelectedUnit(configuration.getUnit(index));
284                                         setToCustom();
285                                 }
286                         });
287                         this.add(typeSelector, "gapright para");
288                         
289                         this.add(new JLabel("Unit:"));
290                         unitSelector = new UnitSelector(type.getUnitGroup());
291                         if (unit != null)
292                                 unitSelector.setSelectedUnit(unit);
293                         unitSelector.addItemListener(new ItemListener() {
294                                 @Override
295                                 public void itemStateChanged(ItemEvent e) {
296                                         if (modifying > 0)
297                                                 return;
298                                         Unit unit = (Unit) unitSelector.getSelectedUnit();
299                                         configuration.setPlotDataUnit(index, unit);
300                                 }
301                         });
302                         this.add(unitSelector, "width 40lp, gapright para");
303                         
304                         this.add(new JLabel("Axis:"));
305                         axisSelector = new JComboBox(POSITIONS);
306                         if (position == LEFT)
307                                 axisSelector.setSelectedIndex(1);
308                         else if (position == RIGHT)
309                                 axisSelector.setSelectedIndex(2);
310                         else
311                                 axisSelector.setSelectedIndex(0);
312                         axisSelector.addItemListener(new ItemListener() {
313                                 @Override
314                                 public void itemStateChanged(ItemEvent e) {
315                                         if (modifying > 0)
316                                                 return;
317                                         int axis = axisSelector.getSelectedIndex() - 1;
318                                         configuration.setPlotDataAxis(index, axis);
319                                 }
320                         });
321                         this.add(axisSelector, "gapright para");
322                         
323                         
324                         JButton button = new JButton("Remove");
325                         button.addActionListener(new ActionListener() {
326                                 @Override
327                                 public void actionPerformed(ActionEvent e) {
328                                         configuration.removePlotDataType(index);
329                                         setToCustom();
330                                         updatePlots();
331                                 }
332                         });
333                         this.add(button);
334                 }
335         }
336 }