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,
289 "File \"" + file.getName() + "\" exists. Overwrite?",
290 "File exists", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
291 if (ret != JOptionPane.YES_OPTION)
295 String commentChar = commentCharacter.getSelectedItem().toString();
296 String fieldSep = fieldSeparator.getSelectedItem().toString();
297 boolean simulationComment = simulationComments.isSelected();
298 boolean fieldComment = fieldNameComments.isSelected();
299 boolean eventComment = eventComments.isSelected();
301 // Store preferences and export
303 Prefs.setDefaultDirectory(chooser.getCurrentDirectory());
304 for (int i=0; i < selected.length; i++) {
305 Prefs.setExportSelected(types[i], selected[i]);
309 Prefs.putString(Prefs.EXPORT_FIELD_SEPARATOR, fieldSep);
310 Prefs.putString(Prefs.EXPORT_COMMENT_CHARACTER, commentChar);
311 Prefs.putBoolean(Prefs.EXPORT_EVENT_COMMENTS, eventComment);
312 Prefs.putBoolean(Prefs.EXPORT_FIELD_NAME_COMMENT, fieldComment);
313 Prefs.putBoolean(Prefs.EXPORT_SIMULATION_COMMENT, simulationComment);
316 FlightDataType[] fieldTypes = new FlightDataType[n];
317 Unit[] fieldUnits = new Unit[n];
319 for (int i=0; i < selected.length; i++) {
321 fieldTypes[pos] = types[i];
322 fieldUnits[pos] = units[i];
327 if (fieldSep.equals(SPACE)) {
329 } else if (fieldSep.equals(TAB)) {
334 SaveCSVWorker.export(file, simulation, branch, fieldTypes, fieldUnits, fieldSep,
335 commentChar, simulationComment, fieldComment, eventComment,
336 SwingUtilities.getWindowAncestor(this));
340 private void updateSelectedCount() {
341 int total = selected.length;
345 for (int i=0; i < selected.length; i++) {
351 str = "Exporting 1 variable out of " + total + ".";
353 str = "Exporting "+n+" variables out of " + total + ".";
356 selectedCountLabel.setText(str);
362 * A table cell renderer that uses another renderer and sets the background and
363 * foreground of the returned component based on the selection of the variable.
365 private class SelectionBackgroundCellRenderer implements TableCellRenderer {
367 private final TableCellRenderer renderer;
369 public SelectionBackgroundCellRenderer(TableCellRenderer renderer) {
370 this.renderer = renderer;
374 public Component getTableCellRendererComponent(JTable table, Object value,
375 boolean isSelected, boolean hasFocus, int row, int column) {
377 Component component = renderer.getTableCellRendererComponent(table,
378 value, isSelected, hasFocus, row, column);
381 component.setBackground(table.getSelectionBackground());
382 component.setForeground(table.getSelectionForeground());
384 component.setBackground(table.getBackground());
385 component.setForeground(table.getForeground());
395 * The table model for the variable selection.
397 private class SelectionTableModel extends AbstractTableModel {
398 private static final int SELECTED = 0;
399 private static final int NAME = 1;
400 private static final int UNIT = 2;
403 public int getColumnCount() {
408 public int getRowCount() {
413 public String getColumnName(int column) {
422 throw new IndexOutOfBoundsException("column=" + column);
428 public Class<?> getColumnClass(int column) {
431 return Boolean.class;
433 return FlightDataType.class;
437 throw new IndexOutOfBoundsException("column=" + column);
442 public Object getValueAt(int row, int column) {
446 return selected[row];
455 throw new IndexOutOfBoundsException("column="+column);
461 public void setValueAt(Object value, int row, int column) {
465 selected[row] = (Boolean)value;
466 this.fireTableRowsUpdated(row, row);
467 updateSelectedCount();
474 units[row] = (Unit)value;
478 throw new IndexOutOfBoundsException("column="+column);
484 public boolean isCellEditable(int row, int column) {
493 return types[row].getUnitGroup().getUnitCount() > 1;
496 throw new IndexOutOfBoundsException("column="+column);
500 public void selectAll() {
501 Arrays.fill(selected, true);
502 updateSelectedCount();
503 this.fireTableDataChanged();
506 public void selectNone() {
507 Arrays.fill(selected, false);
508 updateSelectedCount();
509 this.fireTableDataChanged();