added svn:ignores
[debian/openrocket] / src / net / sf / openrocket / gui / components / SimulationExportPanel.java
1 package net.sf.openrocket.gui.components;
2
3 import java.awt.Component;
4 import java.awt.event.ActionEvent;
5 import java.awt.event.ActionListener;
6 import java.io.File;
7 import java.util.Arrays;
8
9 import javax.swing.BorderFactory;
10 import javax.swing.JButton;
11 import javax.swing.JCheckBox;
12 import javax.swing.JComboBox;
13 import javax.swing.JFileChooser;
14 import javax.swing.JLabel;
15 import javax.swing.JOptionPane;
16 import javax.swing.JPanel;
17 import javax.swing.JScrollPane;
18 import javax.swing.JTable;
19 import javax.swing.SwingUtilities;
20 import javax.swing.filechooser.FileFilter;
21 import javax.swing.table.AbstractTableModel;
22 import javax.swing.table.TableCellRenderer;
23 import javax.swing.table.TableColumn;
24 import javax.swing.table.TableColumnModel;
25
26 import net.miginfocom.swing.MigLayout;
27 import net.sf.openrocket.document.Simulation;
28 import net.sf.openrocket.simulation.FlightData;
29 import net.sf.openrocket.simulation.FlightDataBranch;
30 import net.sf.openrocket.simulation.FlightDataType;
31 import net.sf.openrocket.unit.Unit;
32 import net.sf.openrocket.unit.UnitGroup;
33 import net.sf.openrocket.util.GUIUtil;
34 import net.sf.openrocket.util.Prefs;
35 import net.sf.openrocket.util.SaveCSVWorker;
36
37 public class SimulationExportPanel extends JPanel {
38
39         private static final String SPACE = "SPACE";
40         private static final String TAB = "TAB";
41         
42         private static final FileFilter CSV_FILE_FILTER = new FileFilter() {
43                 @Override
44                 public String getDescription() {
45                         return "Comma Separated Files (*.csv)";
46                 }
47                 @Override
48                 public boolean accept(File f) {
49                         if (f.isDirectory())
50                                 return true;
51                         String name = f.getName().toLowerCase();
52                         return name.endsWith(".csv");
53                 }
54     };
55
56         
57         
58         private final JTable table;
59         private final SelectionTableModel tableModel;
60         private final JLabel selectedCountLabel;
61         
62         private final Simulation simulation;
63         private final FlightDataBranch branch;
64         
65         private final boolean[] selected;
66         private final FlightDataType[] types;
67         private final Unit[] units;
68         
69         private final JComboBox fieldSeparator;
70         private final JCheckBox simulationComments;
71         private final JCheckBox fieldNameComments;
72         private final JCheckBox eventComments;
73         private final JComboBox commentCharacter;
74         
75         
76         public SimulationExportPanel(Simulation sim) {
77                 super(new MigLayout("fill, flowy"));
78
79                 JLabel label;
80                 JPanel panel;
81                 JButton button;
82                 String tip;
83                 
84                 
85                 this.simulation = sim;
86                 
87                 // TODO: MEDIUM: Only exports primary branch
88                 
89                 final FlightData data = simulation.getSimulatedData();
90
91                 // Check that data exists
92                 if (data == null  || data.getBranchCount() == 0 ||
93                                 data.getBranch(0).getTypes().length == 0) {
94                         throw new IllegalArgumentException("No data for panel");
95                 }
96                 
97                 
98                 // Create the data model
99                 branch = data.getBranch(0);
100
101                 types = branch.getTypes();
102                 Arrays.sort(types);
103                 
104                 selected = new boolean[types.length];
105                 units = new Unit[types.length];
106                 for (int i = 0; i < types.length; i++) {
107                         selected[i] = Prefs.isExportSelected(types[i]);
108                         units[i] = types[i].getUnitGroup().getDefaultUnit();
109                 }
110                 
111                 
112                 //// Create the panel
113                 
114                 
115                 // Set up the variable selection table
116                 tableModel = new SelectionTableModel();
117                 table = new JTable(tableModel);
118                 table.setDefaultRenderer(Object.class, 
119                                 new SelectionBackgroundCellRenderer(table.getDefaultRenderer(Object.class)));
120                 table.setDefaultRenderer(Boolean.class, 
121                                 new SelectionBackgroundCellRenderer(table.getDefaultRenderer(Boolean.class)));
122                 table.setRowSelectionAllowed(false);
123                 table.setColumnSelectionAllowed(false);
124                 
125                 table.setDefaultEditor(Unit.class, new UnitCellEditor() {
126                         @Override
127                         protected UnitGroup getUnitGroup(Unit value, int row, int column) {
128                                 return types[row].getUnitGroup();
129                         }
130                 });
131                 
132                 // Set column widths
133                 TableColumnModel columnModel = table.getColumnModel();
134                 TableColumn col = columnModel.getColumn(0);
135                 int w = table.getRowHeight();
136                 col.setMinWidth(w);
137                 col.setPreferredWidth(w);
138                 col.setMaxWidth(w);
139                 
140                 col = columnModel.getColumn(1);
141                 col.setPreferredWidth(200);
142                 
143                 col = columnModel.getColumn(2);
144                 col.setPreferredWidth(100);
145
146                 table.addMouseListener(new GUIUtil.BooleanTableClickListener(table));
147                 
148                 // Add table
149                 panel = new JPanel(new MigLayout("fill"));
150                 panel.setBorder(BorderFactory.createTitledBorder("Variables to export"));
151                 
152                 panel.add(new JScrollPane(table), "wmin 300lp, width 300lp, height 1, grow 100, wrap");
153                 
154                 // Select all/none buttons
155                 button = new JButton("Select all");
156                 button.addActionListener(new ActionListener() {
157                         @Override
158                         public void actionPerformed(ActionEvent e) {
159                                 tableModel.selectAll();
160                         }
161                 });
162                 panel.add(button, "split 2, growx 1, sizegroup selectbutton");
163                 
164                 button = new JButton("Select none");
165                 button.addActionListener(new ActionListener() {
166                         @Override
167                         public void actionPerformed(ActionEvent e) {
168                                 tableModel.selectNone();
169                         }
170                 });
171                 panel.add(button, "growx 1, sizegroup selectbutton, wrap");
172                 
173                 
174                 selectedCountLabel = new JLabel();
175                 updateSelectedCount();
176                 panel.add(selectedCountLabel);
177                 
178                 this.add(panel, "grow 100, wrap");
179                 
180                 
181                 
182                 // Field separator panel
183                 panel = new JPanel(new MigLayout("fill"));
184                 panel.setBorder(BorderFactory.createTitledBorder("Field separator"));
185                 
186                 label = new JLabel("Field separator string:");
187                 tip = "<html>The string used to separate the fields in the exported file.<br>" +
188                                 "Use ',' for a Comma Separated Values (CSV) file.";
189                 label.setToolTipText(tip);
190                 panel.add(label);
191                 
192                 fieldSeparator = new JComboBox(new String[] { ",", ";", SPACE, TAB });
193                 fieldSeparator.setEditable(true);
194                 fieldSeparator.setSelectedItem(Prefs.getString(Prefs.EXPORT_FIELD_SEPARATOR, 
195                                 ","));
196                 fieldSeparator.setToolTipText(tip);
197                 panel.add(fieldSeparator);
198                 
199                 this.add(panel, "spany, split, growx 1");
200                 
201                 
202                 
203                 
204                 // Comments separator panel
205                 panel = new JPanel(new MigLayout("fill"));
206                 panel.setBorder(BorderFactory.createTitledBorder("Comments"));
207                 
208                 simulationComments = new JCheckBox("Include simulation description");
209                 simulationComments.setToolTipText("Include a comment at the beginning of the file " +
210                                 "describing the simulation.");
211                 simulationComments.setSelected(Prefs.getBoolean(Prefs.EXPORT_SIMULATION_COMMENT, 
212                                 true));
213                 panel.add(simulationComments, "wrap");
214                 
215                 
216                 fieldNameComments = new JCheckBox("Include field descriptions");
217                 fieldNameComments.setToolTipText("Include a comment line with the descriptions of " +
218                                 "the exported variables.");
219                 fieldNameComments.setSelected(Prefs.getBoolean(Prefs.EXPORT_FIELD_NAME_COMMENT, true));
220                 panel.add(fieldNameComments, "wrap");
221                 
222                 
223                 eventComments = new JCheckBox("Include flight events");
224                 eventComments.setToolTipText("Include a comment line for every flight event.");
225                 eventComments.setSelected(Prefs.getBoolean(Prefs.EXPORT_EVENT_COMMENTS, true));
226                 panel.add(eventComments, "wrap");
227                 
228                 
229                 label = new JLabel("Comment character:");
230                 tip = "The character(s) that mark a comment line.";
231                 label.setToolTipText(tip);
232                 panel.add(label, "split 2");
233                 
234                 commentCharacter = new JComboBox(new String[] { "#", "%", ";" });
235                 commentCharacter.setEditable(true);
236                 commentCharacter.setSelectedItem(Prefs.getString(Prefs.EXPORT_COMMENT_CHARACTER, "#"));
237                 commentCharacter.setToolTipText(tip);
238                 panel.add(commentCharacter);
239                 
240                 this.add(panel, "growx 1");
241
242                 
243                 // Space-filling panel
244                 panel = new JPanel();
245                 this.add(panel, "width 1, height 1, grow 1");
246                 
247                 
248                 // Export button
249                 button = new JButton("Export to file...");
250                 button.addActionListener(new ActionListener() {
251                         @Override
252                         public void actionPerformed(ActionEvent e) {
253                                 doExport();
254                         }
255                 });
256                 this.add(button, "gapbottom para, gapright para, right");
257                 
258         }
259         
260         
261         private void doExport() {
262                 JFileChooser chooser = new JFileChooser();
263                 chooser.setFileFilter(CSV_FILE_FILTER);
264                 chooser.setCurrentDirectory(Prefs.getDefaultDirectory());
265                 
266                 if (chooser.showSaveDialog(this) != JFileChooser.APPROVE_OPTION)
267                         return;
268                 
269                 File file = chooser.getSelectedFile();
270                 if (file == null)
271                         return;
272                 
273                 if (file.getName().indexOf('.') < 0) {
274                         String name = file.getAbsolutePath();
275                         name = name + ".csv";
276                         file = new File(name);
277                 }
278
279                 if (file.exists()) {
280                         int ret = JOptionPane.showConfirmDialog(this, 
281                                         "File \"" + file.getName() + "\" exists.  Overwrite?", 
282                                         "File exists", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
283                         if (ret != JOptionPane.YES_OPTION)
284                                 return;
285                 }
286
287                 String commentChar = commentCharacter.getSelectedItem().toString();
288                 String fieldSep = fieldSeparator.getSelectedItem().toString();
289                 boolean simulationComment = simulationComments.isSelected();
290                 boolean fieldComment = fieldNameComments.isSelected();
291                 boolean eventComment = eventComments.isSelected();
292                 
293                 // Store preferences and export
294                 int n = 0;
295                 Prefs.setDefaultDirectory(chooser.getCurrentDirectory());
296                 for (int i=0; i < selected.length; i++) {
297                         Prefs.setExportSelected(types[i], selected[i]);
298                         if (selected[i])
299                                 n++;
300                 }
301                 Prefs.putString(Prefs.EXPORT_FIELD_SEPARATOR, fieldSep);
302                 Prefs.putString(Prefs.EXPORT_COMMENT_CHARACTER, commentChar);
303                 Prefs.putBoolean(Prefs.EXPORT_EVENT_COMMENTS, eventComment);
304                 Prefs.putBoolean(Prefs.EXPORT_FIELD_NAME_COMMENT, fieldComment);
305                 Prefs.putBoolean(Prefs.EXPORT_SIMULATION_COMMENT, simulationComment);
306                 
307                 
308                 FlightDataType[] fieldTypes = new FlightDataType[n];
309                 Unit[] fieldUnits = new Unit[n];
310                 int pos = 0;
311                 for (int i=0; i < selected.length; i++) {
312                         if (selected[i]) {
313                                 fieldTypes[pos] = types[i];
314                                 fieldUnits[pos] = units[i];
315                                 pos++;
316                         }
317                 }
318                 
319                 if (fieldSep.equals(SPACE)) {
320                         fieldSep = " ";
321                 } else if (fieldSep.equals(TAB)) {
322                         fieldSep = "\t";
323                 }
324                 
325                 
326                 SaveCSVWorker.export(file, simulation, branch, fieldTypes, fieldUnits, fieldSep, 
327                                 commentChar, simulationComment, fieldComment, eventComment, 
328                                 SwingUtilities.getWindowAncestor(this));
329         }
330         
331         
332         private void updateSelectedCount() {
333                 int total = selected.length;
334                 int n = 0;
335                 String str;
336                 
337                 for (int i=0; i < selected.length; i++) {
338                         if (selected[i])
339                                 n++;
340                 }
341                 
342                 if (n == 1) {
343                         str = "Exporting 1 variable out of " + total + ".";
344                 } else {
345                         str = "Exporting "+n+" variables out of " + total + ".";
346                 }
347
348                 selectedCountLabel.setText(str);
349         }
350         
351         
352         
353         /**
354          * A table cell renderer that uses another renderer and sets the background and
355          * foreground of the returned component based on the selection of the variable.
356          */
357         private class SelectionBackgroundCellRenderer implements TableCellRenderer {
358
359                 private final TableCellRenderer renderer;
360                 
361                 public SelectionBackgroundCellRenderer(TableCellRenderer renderer) {
362                         this.renderer = renderer;
363                 }
364                 
365                 @Override
366                 public Component getTableCellRendererComponent(JTable table, Object value,
367                                 boolean isSelected, boolean hasFocus, int row, int column) {
368                         
369                         Component component = renderer.getTableCellRendererComponent(table, 
370                                         value, isSelected, hasFocus, row, column);
371                         
372                         if (selected[row]) {
373                                 component.setBackground(table.getSelectionBackground());
374                                 component.setForeground(table.getSelectionForeground());
375                         } else {
376                                 component.setBackground(table.getBackground());
377                                 component.setForeground(table.getForeground());
378                         }
379                         
380                         return component;
381                 }
382                 
383         }
384         
385         
386         /**
387          * The table model for the variable selection.
388          */
389         private class SelectionTableModel extends AbstractTableModel {
390                 private static final int SELECTED = 0;
391                 private static final int NAME = 1;
392                 private static final int UNIT = 2;
393
394                 @Override
395                 public int getColumnCount() {
396                         return 3;
397                 }
398
399                 @Override
400                 public int getRowCount() {
401                         return types.length;
402                 }
403                 
404                 @Override
405                 public String getColumnName(int column) {
406                         switch (column) {
407                         case SELECTED:
408                                 return "";
409                         case NAME:
410                                 return "Variable";
411                         case UNIT:
412                                 return "Unit";
413                         default:
414                                 throw new IndexOutOfBoundsException("column=" + column);
415                         }
416                         
417                 }
418                 
419                 @Override
420                 public Class<?> getColumnClass(int column) {
421                         switch (column) {
422                         case SELECTED:
423                                 return Boolean.class;
424                         case NAME:
425                                 return FlightDataType.class;
426                         case UNIT:
427                                 return Unit.class;
428                         default:
429                                 throw new IndexOutOfBoundsException("column=" + column);
430                         }
431                 }
432
433                 @Override
434                 public Object getValueAt(int row, int column) {
435
436                         switch (column) {
437                         case SELECTED:
438                                 return selected[row];
439                                 
440                         case NAME:
441                                 return types[row];
442                                 
443                         case UNIT:
444                                 return units[row];
445                                 
446                         default:
447                                 throw new IndexOutOfBoundsException("column="+column);
448                         }
449                         
450                 }
451
452                 @Override
453                 public void setValueAt(Object value, int row, int column) {
454                         
455                         switch (column) {
456                         case SELECTED:
457                                 selected[row] = (Boolean)value;
458                                 this.fireTableRowsUpdated(row, row);
459                                 updateSelectedCount();
460                                 break;
461                                 
462                         case NAME:
463                                 break;
464                                 
465                         case UNIT:
466                                 units[row] = (Unit)value;
467                                 break;
468                                 
469                         default:
470                                 throw new IndexOutOfBoundsException("column="+column);
471                         }
472                         
473                 }
474
475                 @Override
476                 public boolean isCellEditable(int row, int column) {
477                         switch (column) {
478                         case SELECTED:
479                                 return true;
480                                 
481                         case NAME:
482                                 return false;
483                                 
484                         case UNIT:
485                                 return types[row].getUnitGroup().getUnitCount() > 1;
486                                 
487                         default:
488                                 throw new IndexOutOfBoundsException("column="+column);
489                         }
490                 }
491                 
492                 public void selectAll() {
493                         Arrays.fill(selected, true);
494                         updateSelectedCount();
495                         this.fireTableDataChanged();
496                 }
497                 
498                 public void selectNone() {
499                         Arrays.fill(selected, false);
500                         updateSelectedCount();
501                         this.fireTableDataChanged();
502                 }
503                 
504         }
505         
506 }