2e7023affb56ccf6825ef849ffe37a4ee14cdbf0
[sw/motorsim] / gpl / com / billkuker / rocketry / motorsim / visual / openRocket / RocketSimTable.java
1 package com.billkuker.rocketry.motorsim.visual.openRocket;\r
2 \r
3 import java.awt.BorderLayout;\r
4 import java.awt.Color;\r
5 import java.awt.Component;\r
6 import java.awt.event.MouseAdapter;\r
7 import java.awt.event.MouseEvent;\r
8 import java.io.File;\r
9 import java.util.HashSet;\r
10 import java.util.Iterator;\r
11 import java.util.List;\r
12 import java.util.Set;\r
13 import java.util.Vector;\r
14 \r
15 import javax.measure.unit.SI;\r
16 import javax.swing.JPanel;\r
17 import javax.swing.JScrollPane;\r
18 import javax.swing.JTable;\r
19 import javax.swing.SwingUtilities;\r
20 import javax.swing.table.AbstractTableModel;\r
21 import javax.swing.table.DefaultTableCellRenderer;\r
22 \r
23 import net.sf.openrocket.aerodynamics.Warning;\r
24 import net.sf.openrocket.document.OpenRocketDocument;\r
25 import net.sf.openrocket.document.Simulation;\r
26 import net.sf.openrocket.file.RocketLoadException;\r
27 import net.sf.openrocket.file.openrocket.OpenRocketLoader;\r
28 import net.sf.openrocket.gui.plot.PlotConfiguration;\r
29 import net.sf.openrocket.gui.plot.SimulationPlotDialog;\r
30 import net.sf.openrocket.gui.util.SwingPreferences;\r
31 import net.sf.openrocket.l10n.ResourceBundleTranslator;\r
32 import net.sf.openrocket.rocketcomponent.MotorMount;\r
33 import net.sf.openrocket.rocketcomponent.RocketComponent;\r
34 import net.sf.openrocket.simulation.exception.SimulationException;\r
35 import net.sf.openrocket.startup.Application;\r
36 import net.sf.openrocket.unit.UnitGroup;\r
37 \r
38 import org.jscience.physics.amount.Amount;\r
39 \r
40 import com.billkuker.rocketry.motorsim.Burn;\r
41 import com.billkuker.rocketry.motorsim.Colors;\r
42 import com.billkuker.rocketry.motorsim.Motor;\r
43 import com.billkuker.rocketry.motorsim.RocketScience;\r
44 import com.billkuker.rocketry.motorsim.RocketScience.UnitPreference;\r
45 import com.billkuker.rocketry.motorsim.visual.workbench.BurnWatcher;\r
46 \r
47 public class RocketSimTable extends JPanel implements BurnWatcher,\r
48                 RocketScience.UnitPreferenceListener {\r
49         static final long serialVersionUID = 1L;\r
50 \r
51         static {\r
52                 Application.setBaseTranslator(new ResourceBundleTranslator(\r
53                                 "l10n.messages"));\r
54                 Application.setMotorSetDatabase(new OneMotorDatabase());\r
55                 Application.setPreferences(new SwingPreferences());\r
56 \r
57         }\r
58 \r
59         class Entry {\r
60                 Entry(Motor m, Simulation s, Burn b) {\r
61                         this.m = m;\r
62                         this.s = s;\r
63                         this.b = b;\r
64                 }\r
65 \r
66                 boolean ready = false;\r
67                 Simulation s;\r
68                 Motor m;\r
69                 Burn b;\r
70         }\r
71 \r
72         class TM extends AbstractTableModel {\r
73                 private static final long serialVersionUID = 1L;\r
74 \r
75                 @Override\r
76                 public String getColumnName(int col) {\r
77                         switch (col) {\r
78                         case 0:\r
79                                 return "Motor";\r
80                         case 1:\r
81                                 return "Apogee";\r
82                         case 2:\r
83                                 return "Vmax";\r
84                         case 3:\r
85                                 return "Vdeploy";\r
86                         case 4:\r
87                                 return "Vground";\r
88                         case 5:\r
89                                 return "Tapogee";\r
90                         case 6:\r
91                                 return "Tflight";\r
92                         }\r
93                         return "??";\r
94                 }\r
95 \r
96                 @Override\r
97                 public int getColumnCount() {\r
98                         return 7;\r
99                 }\r
100 \r
101                 @Override\r
102                 public int getRowCount() {\r
103                         return entries.size();\r
104                 }\r
105 \r
106                 @Override\r
107                 public Object getValueAt(int row, int col) {\r
108                         Entry e = entries.get(row);\r
109                         if (e == null)\r
110                                 return "???";\r
111                         if (e.ready == false)\r
112                                 return "...";\r
113                         switch (col) {\r
114                         case 0:\r
115                                 return e.m.getName();\r
116                         case 1:\r
117                                 return RocketScience.ammountToRoundedString(Amount.valueOf(e.s\r
118                                                 .getSimulatedData().getMaxAltitude(), SI.METER));\r
119                         case 2:\r
120                                 return RocketScience.ammountToRoundedString(Amount.valueOf(e.s\r
121                                                 .getSimulatedData().getMaxVelocity(),\r
122                                                 SI.METERS_PER_SECOND));\r
123                         case 3:\r
124                                 return RocketScience.ammountToRoundedString(Amount.valueOf(e.s\r
125                                                 .getSimulatedData().getDeploymentVelocity(),\r
126                                                 SI.METERS_PER_SECOND));\r
127                         case 4:\r
128                                 return RocketScience.ammountToRoundedString(Amount.valueOf(e.s\r
129                                                 .getSimulatedData().getGroundHitVelocity(),\r
130                                                 SI.METERS_PER_SECOND));\r
131                         case 5:\r
132                                 return RocketScience.ammountToRoundedString(Amount.valueOf(e.s\r
133                                                 .getSimulatedData().getTimeToApogee(), SI.SECOND));\r
134                         case 6:\r
135                                 return RocketScience.ammountToRoundedString(Amount.valueOf(e.s\r
136                                                 .getSimulatedData().getFlightTime(), SI.SECOND));\r
137                         }\r
138                         return "??";\r
139                 }\r
140 \r
141         }\r
142 \r
143         private TM tm = new TM();\r
144         private JTable table = new JTable(tm);\r
145         private OpenRocketDocument doc;\r
146         List<Entry> entries = new Vector<Entry>();\r
147         Set<Burn> burns = new HashSet<Burn>();\r
148 \r
149         public RocketSimTable() {\r
150                 setLayout(new BorderLayout());\r
151                 JScrollPane scroll = new JScrollPane();\r
152                 scroll.setViewportView(table);\r
153                 add(scroll, BorderLayout.CENTER);\r
154 \r
155                 table.setDefaultRenderer(Object.class, new DefaultTableCellRenderer() {\r
156                         private static final long serialVersionUID = 1L;\r
157 \r
158                         public Component getTableCellRendererComponent(JTable table,\r
159                                         Object value, boolean isSelected, boolean hasFocus,\r
160                                         int row, int column) {\r
161                                 Component c = super.getTableCellRendererComponent(table, value,\r
162                                                 isSelected, hasFocus, row, column);\r
163                                 Entry e = entries.get(row);\r
164                                 if (e.ready && e.s.getSimulatedWarnings().size() > 0) {\r
165                                         c.setBackground(Colors.RED);\r
166                                         c.setForeground(Color.WHITE);\r
167                                         StringBuilder sb = new StringBuilder();\r
168                                         sb.append("<html>");\r
169                                         for (Warning w : e.s.getSimulatedWarnings()) {\r
170                                                 sb.append(w.toString());\r
171                                                 sb.append("<br>");\r
172                                         }\r
173                                         sb.append("<html>");\r
174                                         setToolTipText(sb.toString());\r
175                                 } else {\r
176                                         c.setBackground(table.getBackground());\r
177                                         c.setForeground(table.getForeground());\r
178                                 }\r
179                                 return c;\r
180                         }\r
181                 });\r
182 \r
183                 RocketScience.addUnitPreferenceListener(this);\r
184                 table.addMouseListener(new MouseAdapter() {\r
185                         public void mouseClicked(MouseEvent e) {\r
186                                 if (e.getClickCount() == 2) {\r
187                                         Entry entry = entries.get(table.getSelectedRow());\r
188                                         SimulationPlotDialog.showPlot(SwingUtilities\r
189                                                         .getWindowAncestor(RocketSimTable.this), entry.s,\r
190                                                         PlotConfiguration.DEFAULT_CONFIGURATIONS[0]\r
191                                                                         .resetUnits());\r
192                                 }\r
193                         }\r
194                 });\r
195                 preferredUnitsChanged();\r
196         }\r
197 \r
198         public void openRocket(File f) throws RocketLoadException {\r
199                 this.doc = new OpenRocketLoader().load(f);\r
200                 // JPanel rocketInfo = new JPanel();\r
201                 // JLabel name = new JLabel("File: " + f.getAbsolutePath());\r
202                 // rocketInfo.add(name);\r
203                 // add(rocketInfo, BorderLayout.NORTH);\r
204 \r
205                 RocketPanel p = new RocketPanel(this.doc);\r
206                 add(p, BorderLayout.NORTH);\r
207 \r
208                 entries = new Vector<Entry>();\r
209                 for (Burn b : burns) {\r
210                         entries.add(toEntry(b));\r
211                 }\r
212                 tm.fireTableDataChanged();\r
213                 revalidate();\r
214         }\r
215 \r
216         private Entry toEntry(final Burn b) {\r
217                 final Entry e = new Entry(b.getMotor(), doc.getSimulation(0).copy(), b);\r
218                 tm.fireTableDataChanged();\r
219                 new Thread() {\r
220                         @Override\r
221                         public void run() {\r
222                                 try {\r
223                                         synchronized (OneMotorDatabase.lock) {\r
224 \r
225                                                 OneMotorDatabase.setBurn(b);\r
226 \r
227                                                 e.s.getConfiguration().getMotorConfigurationID();\r
228                                                 Iterator<RocketComponent> iterator = doc.getRocket()\r
229                                                                 .iterator();\r
230                                                 while (iterator.hasNext()) {\r
231                                                         RocketComponent c = iterator.next();\r
232                                                         if (c instanceof MotorMount) {\r
233                                                                 ((MotorMount) c).setMotorDelay(e.s\r
234                                                                                 .getConfiguration()\r
235                                                                                 .getMotorConfigurationID(), b\r
236                                                                                 .getMotor().getEjectionDelay()\r
237                                                                                 .doubleValue(SI.SECOND));\r
238                                                         }\r
239                                                 }\r
240 \r
241                                                 e.s.simulate();\r
242                                                 e.ready = true;\r
243                                                 tm.fireTableDataChanged();\r
244                                         }\r
245                                 } catch (SimulationException e1) {\r
246                                         e1.printStackTrace();\r
247                                 }\r
248 \r
249                         }\r
250                 }.start();\r
251 \r
252                 return e;\r
253         }\r
254 \r
255         @Override\r
256         public void replace(Burn oldBurn, Burn newBurn) {\r
257                 burns.add(newBurn);\r
258                 burns.remove(oldBurn);\r
259 \r
260                 if (doc == null) {\r
261                         return; // TODO, deal with changing rockets\r
262                 }\r
263 \r
264                 if (oldBurn != null) {\r
265                         for (int i = 0; i < entries.size(); i++) {\r
266                                 if (entries.get(i).b == oldBurn) {\r
267                                         if (newBurn != null) {\r
268                                                 entries.set(i, toEntry(newBurn));\r
269                                         } else {\r
270                                                 entries.remove(i);\r
271                                         }\r
272                                         break;\r
273                                 }\r
274                         }\r
275                 } else {\r
276                         entries.add(toEntry(newBurn));\r
277                 }\r
278                 tm.fireTableDataChanged();\r
279         }\r
280 \r
281         @Override\r
282         public void preferredUnitsChanged() {\r
283                 tm.fireTableDataChanged();\r
284                 if (UnitPreference.getUnitPreference() == UnitPreference.NONSI) {\r
285                         System.err.println("NONSI");\r
286                         UnitGroup.setDefaultImperialUnits();\r
287                 } else {\r
288                         System.err.println("SI");\r
289                         UnitGroup.setDefaultMetricUnits();\r
290                 }\r
291         }\r
292 }\r