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.JFileChooser;
12 import javax.swing.JLabel;
13 import javax.swing.JPanel;
14 import javax.swing.JScrollPane;
15 import javax.swing.JTable;
16 import javax.swing.SwingUtilities;
17 import javax.swing.table.AbstractTableModel;
18 import javax.swing.table.TableCellRenderer;
19 import javax.swing.table.TableColumn;
20 import javax.swing.table.TableColumnModel;
22 import net.miginfocom.swing.MigLayout;
23 import net.sf.openrocket.document.Simulation;
24 import net.sf.openrocket.gui.util.FileHelper;
25 import net.sf.openrocket.gui.util.GUIUtil;
26 import net.sf.openrocket.gui.util.SwingPreferences;
27 import net.sf.openrocket.gui.util.SaveCSVWorker;
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;
36 public class SimulationExportPanel extends JPanel {
38 private static final String SPACE = "SPACE";
39 private static final String TAB = "TAB";
40 private static final Translator trans = Application.getTranslator();
42 private static final int OPTION_SIMULATION_COMMENTS = 0;
43 private static final int OPTION_FIELD_DESCRIPTIONS = 1;
44 private static final int OPTION_FLIGHT_EVENTS = 2;
46 private final JTable table;
47 private final SelectionTableModel tableModel;
48 private final JLabel selectedCountLabel;
50 private final Simulation simulation;
51 private final FlightDataBranch branch;
53 private final boolean[] selected;
54 private final FlightDataType[] types;
55 private final Unit[] units;
57 private final CsvOptionPanel csvOptions;
60 public SimulationExportPanel(Simulation sim) {
61 super(new MigLayout("fill, flowy"));
67 this.simulation = sim;
69 // TODO: MEDIUM: Only exports primary branch
71 final FlightData data = simulation.getSimulatedData();
73 // Check that data exists
74 if (data == null || data.getBranchCount() == 0 ||
75 data.getBranch(0).getTypes().length == 0) {
76 throw new IllegalArgumentException("No data for panel");
80 // Create the data model
81 branch = data.getBranch(0);
83 types = branch.getTypes();
86 selected = new boolean[types.length];
87 units = new Unit[types.length];
88 for (int i = 0; i < types.length; i++) {
89 selected[i] = ((SwingPreferences) Application.getPreferences()).isExportSelected(types[i]);
90 units[i] = types[i].getUnitGroup().getDefaultUnit();
97 // Set up the variable selection table
98 tableModel = new SelectionTableModel();
99 table = new JTable(tableModel);
100 table.setDefaultRenderer(Object.class,
101 new SelectionBackgroundCellRenderer(table.getDefaultRenderer(Object.class)));
102 table.setDefaultRenderer(Boolean.class,
103 new SelectionBackgroundCellRenderer(table.getDefaultRenderer(Boolean.class)));
104 table.setRowSelectionAllowed(false);
105 table.setColumnSelectionAllowed(false);
107 table.setDefaultEditor(Unit.class, new UnitCellEditor() {
109 protected UnitGroup getUnitGroup(Unit value, int row, int column) {
110 return types[row].getUnitGroup();
115 TableColumnModel columnModel = table.getColumnModel();
116 TableColumn col = columnModel.getColumn(0);
117 int w = table.getRowHeight();
119 col.setPreferredWidth(w);
122 col = columnModel.getColumn(1);
123 col.setPreferredWidth(200);
125 col = columnModel.getColumn(2);
126 col.setPreferredWidth(100);
128 table.addMouseListener(new GUIUtil.BooleanTableClickListener(table));
131 panel = new JPanel(new MigLayout("fill"));
132 panel.setBorder(BorderFactory.createTitledBorder(trans.get("SimExpPan.border.Vartoexport")));
134 panel.add(new JScrollPane(table), "wmin 300lp, width 300lp, height 1, grow 100, wrap");
136 // Select all/none buttons
137 button = new JButton(trans.get("SimExpPan.but.Selectall"));
138 button.addActionListener(new ActionListener() {
140 public void actionPerformed(ActionEvent e) {
141 tableModel.selectAll();
144 panel.add(button, "split 2, growx 1, sizegroup selectbutton");
146 button = new JButton(trans.get("SimExpPan.but.Selectnone"));
147 button.addActionListener(new ActionListener() {
149 public void actionPerformed(ActionEvent e) {
150 tableModel.selectNone();
153 panel.add(button, "growx 1, sizegroup selectbutton, wrap");
156 selectedCountLabel = new JLabel();
157 updateSelectedCount();
158 panel.add(selectedCountLabel);
160 this.add(panel, "grow 100, wrap");
163 // These need to be in the order of the OPTIONS_XXX indices
164 csvOptions = new CsvOptionPanel(SimulationExportPanel.class,
165 trans.get("SimExpPan.checkbox.Includesimudesc"),
166 trans.get("SimExpPan.checkbox.ttip.Includesimudesc"),
167 trans.get("SimExpPan.checkbox.Includefielddesc"),
168 trans.get("SimExpPan.checkbox.ttip.Includefielddesc"),
169 trans.get("SimExpPan.checkbox.Incflightevents"),
170 trans.get("SimExpPan.checkbox.ttip.Incflightevents"));
172 this.add(csvOptions, "spany, split, growx 1");
175 // Space-filling panel
176 panel = new JPanel();
177 this.add(panel, "width 1, height 1, grow 1");
181 button = new JButton(trans.get("SimExpPan.but.Exporttofile"));
182 button.addActionListener(new ActionListener() {
184 public void actionPerformed(ActionEvent e) {
188 this.add(button, "gapbottom para, gapright para, right");
193 private void doExport() {
194 JFileChooser chooser = new JFileChooser();
195 chooser.setFileFilter(FileHelper.CSV_FILE_FILTER);
196 chooser.setCurrentDirectory(((SwingPreferences) Application.getPreferences()).getDefaultDirectory());
198 if (chooser.showSaveDialog(this) != JFileChooser.APPROVE_OPTION)
201 File file = chooser.getSelectedFile();
205 file = FileHelper.ensureExtension(file, "csv");
206 if (!FileHelper.confirmWrite(file, this)) {
211 String commentChar = csvOptions.getCommentCharacter();
212 String fieldSep = csvOptions.getFieldSeparator();
213 boolean simulationComment = csvOptions.getSelectionOption(OPTION_SIMULATION_COMMENTS);
214 boolean fieldComment = csvOptions.getSelectionOption(OPTION_FIELD_DESCRIPTIONS);
215 boolean eventComment = csvOptions.getSelectionOption(OPTION_FLIGHT_EVENTS);
216 csvOptions.storePreferences();
218 // Store preferences and export
220 ((SwingPreferences) Application.getPreferences()).setDefaultDirectory(chooser.getCurrentDirectory());
221 for (int i = 0; i < selected.length; i++) {
222 ((SwingPreferences) Application.getPreferences()).setExportSelected(types[i], selected[i]);
228 FlightDataType[] fieldTypes = new FlightDataType[n];
229 Unit[] fieldUnits = new Unit[n];
231 for (int i = 0; i < selected.length; i++) {
233 fieldTypes[pos] = types[i];
234 fieldUnits[pos] = units[i];
239 if (fieldSep.equals(SPACE)) {
241 } else if (fieldSep.equals(TAB)) {
246 SaveCSVWorker.export(file, simulation, branch, fieldTypes, fieldUnits, fieldSep,
247 commentChar, simulationComment, fieldComment, eventComment,
248 SwingUtilities.getWindowAncestor(this));
252 private void updateSelectedCount() {
253 int total = selected.length;
257 for (int i = 0; i < selected.length; i++) {
263 //// Exporting 1 variable out of
264 str = trans.get("SimExpPan.ExportingVar.desc1") + " " + total + ".";
267 //// variables out of
268 str = trans.get("SimExpPan.ExportingVar.desc2") + " " + n + " " +
269 trans.get("SimExpPan.ExportingVar.desc3") + " " + total + ".";
272 selectedCountLabel.setText(str);
278 * A table cell renderer that uses another renderer and sets the background and
279 * foreground of the returned component based on the selection of the variable.
281 private class SelectionBackgroundCellRenderer implements TableCellRenderer {
283 private final TableCellRenderer renderer;
285 public SelectionBackgroundCellRenderer(TableCellRenderer renderer) {
286 this.renderer = renderer;
290 public Component getTableCellRendererComponent(JTable table, Object value,
291 boolean isSelected, boolean hasFocus, int row, int column) {
293 Component component = renderer.getTableCellRendererComponent(table,
294 value, isSelected, hasFocus, row, column);
297 component.setBackground(table.getSelectionBackground());
298 component.setForeground(table.getSelectionForeground());
300 component.setBackground(table.getBackground());
301 component.setForeground(table.getForeground());
311 * The table model for the variable selection.
313 private class SelectionTableModel extends AbstractTableModel {
314 private static final int SELECTED = 0;
315 private static final int NAME = 1;
316 private static final int UNIT = 2;
319 public int getColumnCount() {
324 public int getRowCount() {
329 public String getColumnName(int column) {
335 return trans.get("SimExpPan.Col.Variable");
338 return trans.get("SimExpPan.Col.Unit");
340 throw new IndexOutOfBoundsException("column=" + column);
346 public Class<?> getColumnClass(int column) {
349 return Boolean.class;
351 return FlightDataType.class;
355 throw new IndexOutOfBoundsException("column=" + column);
360 public Object getValueAt(int row, int column) {
364 return selected[row];
373 throw new IndexOutOfBoundsException("column=" + column);
379 public void setValueAt(Object value, int row, int column) {
383 selected[row] = (Boolean) value;
384 this.fireTableRowsUpdated(row, row);
385 updateSelectedCount();
392 units[row] = (Unit) value;
396 throw new IndexOutOfBoundsException("column=" + column);
402 public boolean isCellEditable(int row, int column) {
411 return types[row].getUnitGroup().getUnitCount() > 1;
414 throw new IndexOutOfBoundsException("column=" + column);
418 public void selectAll() {
419 Arrays.fill(selected, true);
420 updateSelectedCount();
421 this.fireTableDataChanged();
424 public void selectNone() {
425 Arrays.fill(selected, false);
426 updateSelectedCount();
427 this.fireTableDataChanged();