3838import java .beans .PropertyChangeListener ;
3939import java .beans .PropertyChangeSupport ;
4040import java .io .File ;
41+ import java .io .FileNotFoundException ;
42+ import java .io .FileOutputStream ;
43+ import java .io .IOException ;
4144import java .lang .reflect .Field ;
45+ import java .nio .charset .StandardCharsets ;
4246import java .util .Collections ;
4347import java .util .List ;
48+ import java .util .zip .ZipEntry ;
49+ import java .util .zip .ZipOutputStream ;
4450import javax .swing .*;
4551import javax .swing .table .DefaultTableModel ;
4652
@@ -200,51 +206,24 @@ private JPanel addBottomPanel() {
200206 }
201207
202208 private @ NotNull JPanel addSimulationListPanel () {
203- JPanel simulationListPanel = new JPanel (new MigLayout ("fill" ));
209+ JPanel simulationListPanel = new JPanel (new MigLayout ("fill, wrap 1 " ));
204210 simulationListPanel .setBorder (BorderFactory .createTitledBorder ("Simulations" ));
205211
206212 // Create table model and table
207213 String [] columnNames =
208214 {"Simulation Name" , "Wind Speed(mph)" , "Wind Direction(°)" , "Temperature(°C)" , "Pressure(mbar)" ,
209215 "Apogee(ft)" , "Max Velocity(m/s)" , "Min Stability" };
210- DefaultTableModel tableModel = new DefaultTableModel (columnNames , 0 ) {
211- @ Override
212- public boolean isCellEditable (int row , int column ) {
213- return false ; // Disable editing for all cells
214- }
215- };
216+ SimulationTableModel tableModel = new SimulationTableModel ();
216217 JTable simulationTable = new JTable (tableModel );
217218
218219 simulationListPanel .add (new JScrollPane (simulationTable ), "grow, push" );
219220
220221 PropertyChangeListener tableChangeHandler = evt -> {
222+ tableModel .clearSimulations ();
221223 if (simulationEngine == null ) {
222- tableModel .setRowCount (0 );
223224 return ;
224225 }
225-
226- tableModel .setRowCount (0 ); // Clear existing rows
227- for (SimulationData data : simulationEngine .getData ()) {
228- String name = data .getName ();
229-
230- double temp = data .getTemperatureInCelsius ();
231- double pressure = data .getPressureInMBar ();
232-
233- double windSpeed = data .getMaxWindSpeedInMPH ();
234- double windDirection = data .getMaxWindDirectionInDegrees ();
235-
236- double apogee = 0 ;
237- double maxVelocity = 0 ;
238- double minStability = 0 ;
239- if (data .hasData ()) {
240- apogee = data .getApogeeInFeet ();
241- maxVelocity = data .getMaxVelocity ();
242- minStability = data .getMinStability ().get (0 );
243- }
244-
245- tableModel .addRow (new Object []{name , windSpeed , windDirection , temp , pressure ,
246- apogee , maxVelocity , minStability });
247- }
226+ tableModel .addSimulations (simulationEngine .getData ());
248227 };
249228
250229 simulationTable .addMouseListener (new MouseAdapter () {
@@ -270,10 +249,63 @@ public void mouseClicked(java.awt.event.MouseEvent e) {
270249 }
271250 });
272251
273- // Add listener to update table when simulations are configured
252+ // Add listener to add rows when simulations are configured
274253 pcs .addPropertyChangeListener (SIMULATIONS_CONFIGURED_EVENT , tableChangeHandler );
275254
276- pcs .addPropertyChangeListener (SIMULATIONS_PROCESSED_EVENT , tableChangeHandler );
255+ JButton exportButton = new JButton ("Export Wind Levels" , Icons .EXPORT );
256+ exportButton .addActionListener (e -> {
257+ int [] selectedIdx = simulationTable .getSelectedRows ();
258+ if (selectedIdx .length == 0 ) {
259+ log .warn ("No simulations selected for export" );
260+ JOptionPane .showMessageDialog (SimulationOptionsFrame .this ,
261+ "Select a simulation to export wind levels." ,
262+ "Export Failed" ,
263+ JOptionPane .ERROR_MESSAGE );
264+ return ;
265+ }
266+
267+ // select directory to save to
268+ JFileChooser chooser = new JFileChooser ();
269+ chooser .setFileSelectionMode (JFileChooser .DIRECTORIES_ONLY );
270+ chooser .setMultiSelectionEnabled (false );
271+ chooser .setCurrentDirectory (((SwingPreferences ) Application .getPreferences ()).getDefaultDirectory ());
272+ int option = chooser .showOpenDialog (this );
273+ if (option != JFileChooser .APPROVE_OPTION ) {
274+ log .info (Markers .USER_MARKER , "Decided not to export wind levels, option={}" , option );
275+ return ;
276+ }
277+
278+ File file = new File (chooser .getSelectedFile ().getAbsolutePath () + "/wind_level_export.zip" );
279+ if (file .exists ()) {
280+ int response = JOptionPane .showConfirmDialog (SimulationOptionsFrame .this ,
281+ "File " + file .getName () + " already exists. Overwrite?" ,
282+ "Confirm Overwrite" ,
283+ JOptionPane .YES_NO_OPTION ,
284+ JOptionPane .WARNING_MESSAGE );
285+ if (response != JOptionPane .YES_OPTION ) {
286+ log .info ("Decided not to overwrite existing export file {}" , file .getAbsolutePath ());
287+ return ;
288+ }
289+ file .delete ();
290+ }
291+ log .info ("Export to file {}" , file );
292+ try (ZipOutputStream out = new ZipOutputStream (new FileOutputStream (file ))) {
293+ for (int idx : selectedIdx ) {
294+ SimulationData data = tableModel .getDataAt (idx );
295+
296+ log .debug ("Exporting simulation data for {}" , data .getName ());
297+
298+ ZipEntry entry = new ZipEntry (data .getName () + ".csv" );
299+ out .putNextEntry (entry );
300+ out .write (data .exportWindLevels ().getBytes (StandardCharsets .UTF_8 ));
301+ out .closeEntry ();
302+ }
303+ } catch (IOException ex ) {
304+ log .error (ex .toString ());
305+ }
306+ });
307+
308+ simulationListPanel .add (exportButton , "left" );
277309
278310 return simulationListPanel ;
279311 }
0 commit comments