1 package net.sf.openrocket.gui.components;
3 import java.awt.Component;
4 import java.awt.event.ActionEvent;
5 import java.awt.event.ActionListener;
7 import java.util.Arrays;
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;
26 import net.miginfocom.swing.MigLayout;
27 import net.sf.openrocket.document.Simulation;
28 import net.sf.openrocket.l10n.Translator;
29 import net.sf.openrocket.simulation.FlightData;
30 import net.sf.openrocket.simulation.FlightDataBranch;
31 import net.sf.openrocket.simulation.FlightDataType;
32 import net.sf.openrocket.startup.Application;
33 import net.sf.openrocket.unit.Unit;
34 import net.sf.openrocket.unit.UnitGroup;
35 import net.sf.openrocket.util.GUIUtil;
36 import net.sf.openrocket.util.Prefs;
37 import net.sf.openrocket.util.SaveCSVWorker;
39 public class SimulationExportPanel extends JPanel {
41 private static final String SPACE = "SPACE";
42 private static final String TAB = "TAB";
43 private static final Translator trans = Application.getTranslator();
45 private static final FileFilter CSV_FILE_FILTER = new FileFilter() {
47 public String getDescription() {
48 //// Comma Separated Files (*.csv)
49 return trans.get("SimExpPan.desc");
52 public boolean accept(File f) {
55 String name = f.getName().toLowerCase();
56 return name.endsWith(".csv");
62 private final JTable table;
63 private final SelectionTableModel tableModel;
64 private final JLabel selectedCountLabel;
66 private final Simulation simulation;
67 private final FlightDataBranch branch;
69 private final boolean[] selected;
70 private final FlightDataType[] types;
71 private final Unit[] units;
73 private final JComboBox fieldSeparator;
74 private final JCheckBox simulationComments;
75 private final JCheckBox fieldNameComments;
76 private final JCheckBox eventComments;
77 private final JComboBox commentCharacter;
80 public SimulationExportPanel(Simulation sim) {
81 super(new MigLayout("fill, flowy"));
89 this.simulation = sim;
91 // TODO: MEDIUM: Only exports primary branch
93 final FlightData data = simulation.getSimulatedData();
95 // Check that data exists
96 if (data == null || data.getBranchCount() == 0 ||
97 data.getBranch(0).getTypes().length == 0) {
98 throw new IllegalArgumentException("No data for panel");
102 // Create the data model
103 branch = data.getBranch(0);
105 types = branch.getTypes();
108 selected = new boolean[types.length];
109 units = new Unit[types.length];
110 for (int i = 0; i < types.length; i++) {
111 selected[i] = Prefs.isExportSelected(types[i]);
112 units[i] = types[i].getUnitGroup().getDefaultUnit();
116 //// Create the panel
119 // Set up the variable selection table
120 tableModel = new SelectionTableModel();
121 table = new JTable(tableModel);
122 table.setDefaultRenderer(Object.class,
123 new SelectionBackgroundCellRenderer(table.getDefaultRenderer(Object.class)));
124 table.setDefaultRenderer(Boolean.class,
125 new SelectionBackgroundCellRenderer(table.getDefaultRenderer(Boolean.class)));
126 table.setRowSelectionAllowed(false);
127 table.setColumnSelectionAllowed(false);
129 table.setDefaultEditor(Unit.class, new UnitCellEditor() {
131 protected UnitGroup getUnitGroup(Unit value, int row, int column) {
132 return types[row].getUnitGroup();
137 TableColumnModel columnModel = table.getColumnModel();
138 TableColumn col = columnModel.getColumn(0);
139 int w = table.getRowHeight();
141 col.setPreferredWidth(w);
144 col = columnModel.getColumn(1);
145 col.setPreferredWidth(200);
147 col = columnModel.getColumn(2);
148 col.setPreferredWidth(100);
150 table.addMouseListener(new GUIUtil.BooleanTableClickListener(table));
153 panel = new JPanel(new MigLayout("fill"));
154 panel.setBorder(BorderFactory.createTitledBorder(trans.get("SimExpPan.border.Vartoexport")));
156 panel.add(new JScrollPane(table), "wmin 300lp, width 300lp, height 1, grow 100, wrap");
158 // Select all/none buttons
159 button = new JButton(trans.get("SimExpPan.but.Selectall"));
160 button.addActionListener(new ActionListener() {
162 public void actionPerformed(ActionEvent e) {
163 tableModel.selectAll();
166 panel.add(button, "split 2, growx 1, sizegroup selectbutton");
168 button = new JButton(trans.get("SimExpPan.but.Selectnone"));
169 button.addActionListener(new ActionListener() {
171 public void actionPerformed(ActionEvent e) {
172 tableModel.selectNone();
175 panel.add(button, "growx 1, sizegroup selectbutton, wrap");
178 selectedCountLabel = new JLabel();
179 updateSelectedCount();
180 panel.add(selectedCountLabel);
182 this.add(panel, "grow 100, wrap");
186 // Field separator panel
187 panel = new JPanel(new MigLayout("fill"));
188 panel.setBorder(BorderFactory.createTitledBorder(trans.get("SimExpPan.border.Fieldsep")));
190 label = new JLabel(trans.get("SimExpPan.lbl.Fieldsepstr"));
191 //// <html>The string used to separate the fields in the exported file.<br>
192 //// Use ',' for a Comma Separated Values (CSV) file.
193 tip = trans.get("SimExpPan.lbl.longA1") +
194 trans.get("SimExpPan.lbl.longA2");
195 label.setToolTipText(tip);
198 fieldSeparator = new JComboBox(new String[] { ",", ";", SPACE, TAB });
199 fieldSeparator.setEditable(true);
200 fieldSeparator.setSelectedItem(Prefs.getString(Prefs.EXPORT_FIELD_SEPARATOR,
202 fieldSeparator.setToolTipText(tip);
203 panel.add(fieldSeparator);
205 this.add(panel, "spany, split, growx 1");
210 // Comments separator panel
211 panel = new JPanel(new MigLayout("fill"));
213 panel.setBorder(BorderFactory.createTitledBorder(trans.get("SimExpPan.border.Comments")));
215 //// Include simulation description
216 simulationComments = new JCheckBox(trans.get("SimExpPan.checkbox.Includesimudesc"));
217 //// Include a comment at the beginning of the file describing the simulation.
218 simulationComments.setToolTipText(trans.get("SimExpPan.checkbox.ttip.Includesimudesc"));
219 simulationComments.setSelected(Prefs.getBoolean(Prefs.EXPORT_SIMULATION_COMMENT,
221 panel.add(simulationComments, "wrap");
223 //// Include field descriptions
224 fieldNameComments = new JCheckBox(trans.get("SimExpPan.checkbox.Includefielddesc"));
225 //// Include a comment line with the descriptions of the exported variables.
226 fieldNameComments.setToolTipText(trans.get("SimExpPan.checkbox.ttip.Includefielddesc"));
227 fieldNameComments.setSelected(Prefs.getBoolean(Prefs.EXPORT_FIELD_NAME_COMMENT, true));
228 panel.add(fieldNameComments, "wrap");
231 eventComments = new JCheckBox(trans.get("SimExpPan.checkbox.Incflightevents"));
232 eventComments.setToolTipText(trans.get("SimExpPan.checkbox.ttip.Incflightevents"));
233 eventComments.setSelected(Prefs.getBoolean(Prefs.EXPORT_EVENT_COMMENTS, true));
234 panel.add(eventComments, "wrap");
237 label = new JLabel(trans.get("SimExpPan.lbl.Commentchar"));
238 tip = trans.get("SimExpPan.lbl.ttip.Commentchar");
239 label.setToolTipText(tip);
240 panel.add(label, "split 2");
242 commentCharacter = new JComboBox(new String[] { "#", "%", ";" });
243 commentCharacter.setEditable(true);
244 commentCharacter.setSelectedItem(Prefs.getString(Prefs.EXPORT_COMMENT_CHARACTER, "#"));
245 commentCharacter.setToolTipText(tip);
246 panel.add(commentCharacter);
248 this.add(panel, "growx 1");
251 // Space-filling panel
252 panel = new JPanel();
253 this.add(panel, "width 1, height 1, grow 1");
257 button = new JButton(trans.get("SimExpPan.but.Exporttofile"));
258 button.addActionListener(new ActionListener() {
260 public void actionPerformed(ActionEvent e) {
264 this.add(button, "gapbottom para, gapright para, right");
269 private void doExport() {
270 JFileChooser chooser = new JFileChooser();
271 chooser.setFileFilter(CSV_FILE_FILTER);
272 chooser.setCurrentDirectory(Prefs.getDefaultDirectory());
274 if (chooser.showSaveDialog(this) != JFileChooser.APPROVE_OPTION)
277 File file = chooser.getSelectedFile();
281 if (file.getName().indexOf('.') < 0) {
282 String name = file.getAbsolutePath();
283 name = name + ".csv";
284 file = new File(name);
288 int ret = JOptionPane.showConfirmDialog(this,
290 trans.get("SimExpPan.Fileexists.desc1") + file.getName() +
291 //// \" exists. Overwrite?
292 trans.get("SimExpPan.Fileexists.desc2"),
294 trans.get("SimExpPan.Fileexists.title"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
295 if (ret != JOptionPane.YES_OPTION)
299 String commentChar = commentCharacter.getSelectedItem().toString();
300 String fieldSep = fieldSeparator.getSelectedItem().toString();
301 boolean simulationComment = simulationComments.isSelected();
302 boolean fieldComment = fieldNameComments.isSelected();
303 boolean eventComment = eventComments.isSelected();
305 // Store preferences and export
307 Prefs.setDefaultDirectory(chooser.getCurrentDirectory());
308 for (int i=0; i < selected.length; i++) {
309 Prefs.setExportSelected(types[i], selected[i]);
313 Prefs.putString(Prefs.EXPORT_FIELD_SEPARATOR, fieldSep);
314 Prefs.putString(Prefs.EXPORT_COMMENT_CHARACTER, commentChar);
315 Prefs.putBoolean(Prefs.EXPORT_EVENT_COMMENTS, eventComment);
316 Prefs.putBoolean(Prefs.EXPORT_FIELD_NAME_COMMENT, fieldComment);
317 Prefs.putBoolean(Prefs.EXPORT_SIMULATION_COMMENT, simulationComment);
320 FlightDataType[] fieldTypes = new FlightDataType[n];
321 Unit[] fieldUnits = new Unit[n];
323 for (int i=0; i < selected.length; i++) {
325 fieldTypes[pos] = types[i];
326 fieldUnits[pos] = units[i];
331 if (fieldSep.equals(SPACE)) {
333 } else if (fieldSep.equals(TAB)) {
338 SaveCSVWorker.export(file, simulation, branch, fieldTypes, fieldUnits, fieldSep,
339 commentChar, simulationComment, fieldComment, eventComment,
340 SwingUtilities.getWindowAncestor(this));
344 private void updateSelectedCount() {
345 int total = selected.length;
349 for (int i=0; i < selected.length; i++) {
355 //// Exporting 1 variable out of
356 str = trans.get("SimExpPan.ExportingVar.desc1") + " " + total + ".";
359 //// variables out of
360 str = trans.get("SimExpPan.ExportingVar.desc2") + " "+n+" " +
361 trans.get("SimExpPan.ExportingVar.desc3") + " " + total + ".";
364 selectedCountLabel.setText(str);
370 * A table cell renderer that uses another renderer and sets the background and
371 * foreground of the returned component based on the selection of the variable.
373 private class SelectionBackgroundCellRenderer implements TableCellRenderer {
375 private final TableCellRenderer renderer;
377 public SelectionBackgroundCellRenderer(TableCellRenderer renderer) {
378 this.renderer = renderer;
382 public Component getTableCellRendererComponent(JTable table, Object value,
383 boolean isSelected, boolean hasFocus, int row, int column) {
385 Component component = renderer.getTableCellRendererComponent(table,
386 value, isSelected, hasFocus, row, column);
389 component.setBackground(table.getSelectionBackground());
390 component.setForeground(table.getSelectionForeground());
392 component.setBackground(table.getBackground());
393 component.setForeground(table.getForeground());
403 * The table model for the variable selection.
405 private class SelectionTableModel extends AbstractTableModel {
406 private static final int SELECTED = 0;
407 private static final int NAME = 1;
408 private static final int UNIT = 2;
411 public int getColumnCount() {
416 public int getRowCount() {
421 public String getColumnName(int column) {
427 return trans.get("SimExpPan.Col.Variable");
430 return trans.get("SimExpPan.Col.Unit");
432 throw new IndexOutOfBoundsException("column=" + column);
438 public Class<?> getColumnClass(int column) {
441 return Boolean.class;
443 return FlightDataType.class;
447 throw new IndexOutOfBoundsException("column=" + column);
452 public Object getValueAt(int row, int column) {
456 return selected[row];
465 throw new IndexOutOfBoundsException("column="+column);
471 public void setValueAt(Object value, int row, int column) {
475 selected[row] = (Boolean)value;
476 this.fireTableRowsUpdated(row, row);
477 updateSelectedCount();
484 units[row] = (Unit)value;
488 throw new IndexOutOfBoundsException("column="+column);
494 public boolean isCellEditable(int row, int column) {
503 return types[row].getUnitGroup().getUnitCount() > 1;
506 throw new IndexOutOfBoundsException("column="+column);
510 public void selectAll() {
511 Arrays.fill(selected, true);
512 updateSelectedCount();
513 this.fireTableDataChanged();
516 public void selectNone() {
517 Arrays.fill(selected, false);
518 updateSelectedCount();
519 this.fireTableDataChanged();