1 package net.sf.openrocket.gui.preset;
3 import net.miginfocom.swing.MigLayout;
4 import net.sf.openrocket.gui.util.FileHelper;
5 import net.sf.openrocket.gui.util.Icons;
6 import net.sf.openrocket.gui.util.SwingPreferences;
7 import net.sf.openrocket.l10n.ResourceBundleTranslator;
8 import net.sf.openrocket.logging.LogHelper;
9 import net.sf.openrocket.material.Material;
10 import net.sf.openrocket.preset.ComponentPreset;
11 import net.sf.openrocket.preset.xml.OpenRocketComponentSaver;
12 import net.sf.openrocket.startup.Application;
14 import javax.swing.AbstractAction;
15 import javax.swing.Action;
16 import javax.swing.JButton;
17 import javax.swing.JDialog;
18 import javax.swing.JFileChooser;
19 import javax.swing.JFrame;
20 import javax.swing.JLabel;
21 import javax.swing.JOptionPane;
22 import javax.swing.JPanel;
23 import javax.swing.JScrollPane;
24 import javax.swing.JTable;
25 import javax.swing.SwingConstants;
26 import javax.swing.table.DefaultTableModel;
27 import javax.xml.bind.JAXBException;
28 import java.awt.event.ActionEvent;
29 import java.awt.event.ActionListener;
30 import java.awt.event.MouseAdapter;
31 import java.awt.event.MouseEvent;
33 import java.io.IOException;
34 import java.util.ArrayList;
35 import java.util.List;
38 * A UI for editing component presets. Currently this is a standalone application - run the main within this class.
40 * TODO: Open .orc for editing
45 public class ComponentPresetPanel extends JPanel implements PresetResultListener {
50 private static final LogHelper log = Application.getLogger();
53 * The I18N translator.
55 private static ResourceBundleTranslator trans = null;
58 * The table of presets.
63 * The table's data model.
65 private DataTableModel model;
68 * Flag that indicates if an existing Preset is currently being edited.
70 private boolean editingSelected = false;
73 trans = new ResourceBundleTranslator("l10n.messages");
74 net.sf.openrocket.startup.Application.setBaseTranslator(trans);
80 public ComponentPresetPanel() {
81 setLayout(new MigLayout("", "[82.00px][168.00px][84px][117.00px][][222px]", "[346.00px][29px]"));
83 model = new DataTableModel(new String[]{"Manufacturer", "Type", "Part No", "Description", ""});
85 table = new JTable(model);
86 table.getTableHeader().setFont(new JLabel().getFont());
87 //The action never gets called because the table MouseAdapter intercepts it first. Still need an empty
89 Action action = new AbstractAction() {
91 public void actionPerformed(final ActionEvent e) {
94 //Create a editor/renderer for the delete operation. Instantiation self-registers into the table.
95 new ButtonColumn(table, action, 4);
96 table.getColumnModel().getColumn(4).setMaxWidth(Icons.EDIT_DELETE.getIconWidth());
97 table.getColumnModel().getColumn(4).setMinWidth(Icons.EDIT_DELETE.getIconWidth());
99 JScrollPane scrollPane = new JScrollPane(table);
100 table.setFillsViewportHeight(true);
101 table.setAutoCreateRowSorter(true);
102 add(scrollPane, "cell 0 0 6 1,grow");
104 table.addMouseListener(new MouseAdapter() {
105 public void mouseClicked(MouseEvent e) {
106 JTable target = (JTable) e.getSource();
107 if (target.getSelectedColumn() == 4) {
108 if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(ComponentPresetPanel.this,
109 "Do you want to delete this preset?",
110 "Confirm Delete", JOptionPane.YES_OPTION,
111 JOptionPane.QUESTION_MESSAGE)) {
112 model.removeRow(target.getSelectedRow());
116 if (e.getClickCount() == 2) {
117 int row = target.getSelectedRow();
118 editingSelected = true;
119 new PresetEditorDialog(ComponentPresetPanel.this, (ComponentPreset) model.getAssociatedObject(row)).setVisible(true);
124 JButton addBtn = new JButton("Add");
125 addBtn.addMouseListener(new MouseAdapter() {
127 public void mouseClicked(MouseEvent arg0) {
128 editingSelected = false;
129 new PresetEditorDialog(ComponentPresetPanel.this).setVisible(true);
132 add(addBtn, "cell 0 1,alignx left,aligny top");
134 JButton saveBtn = new JButton("Save...");
135 saveBtn.setHorizontalAlignment(SwingConstants.RIGHT);
136 add(saveBtn, "flowx,cell 5 1,alignx right,aligny center");
137 saveBtn.addActionListener(new ActionListener() {
139 public void actionPerformed(final ActionEvent e) {
143 catch (Exception e1) {
144 JOptionPane.showMessageDialog(ComponentPresetPanel.this, e1.getLocalizedMessage(),
145 "Error saving ORC file.", JOptionPane.ERROR_MESSAGE);
150 JButton cancelBtn = new JButton("Cancel");
151 cancelBtn.setHorizontalAlignment(SwingConstants.RIGHT);
152 add(cancelBtn, "cell 5 1,alignx right,aligny top");
153 cancelBtn.addActionListener(new ActionListener() {
155 public void actionPerformed(final ActionEvent e) {
163 * Callback method from the PresetEditorDialog to notify this class when a preset has been saved. The 'save' is
164 * really just a call back here so the preset can be added to the master table. It's not to be confused with the
167 * @param preset the new or modified preset
170 public void notifyResult(final ComponentPreset preset) {
171 if (preset != null) {
172 DataTableModel model = (DataTableModel) table.getModel();
173 //Is this a new preset?
174 if (!editingSelected) {
175 model.addRow(new Object[]{preset.getManufacturer().getDisplayName(), preset.getType().name(),
176 preset.getPartNo(), preset.get(ComponentPreset.DESCRIPTION), Icons.EDIT_DELETE}, preset);
179 //This is a modified preset; update all of the columns and the stored associated instance.
180 int row = table.getSelectedRow();
181 model.setValueAt(preset.getManufacturer().getDisplayName(), row, 0);
182 model.setValueAt(preset.getType().name(), row, 1);
183 model.setValueAt(preset.getPartNo(), row, 2);
184 model.setValueAt(preset.get(ComponentPreset.DESCRIPTION), row, 3);
185 model.associated.set(row, preset);
188 editingSelected = false;
192 * Launch the test main.
194 public static void main(String[] args) {
196 Application.setPreferences(new SwingPreferences());
197 JFrame dialog = new JFrame();
198 dialog.getContentPane().add(new ComponentPresetPanel());
199 dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
201 dialog.setVisible(true);
203 catch (Exception e) {
209 * A table model that adds associated objects to each row, allowing for easy retrieval.
211 class DataTableModel extends DefaultTableModel {
213 private List<Object> associated = new ArrayList<Object>();
216 * Constructs a <code>DefaultTableModel</code> with as many columns as there are elements in
217 * <code>columnNames</code> and <code>rowCount</code> of <code>null</code> object values. Each column's name
218 * will be taken from the <code>columnNames</code> array.
220 * @param columnNames <code>array</code> containing the names of the new columns; if this is <code>null</code>
221 * then the model has no columns
223 * @see #setDataVector
226 DataTableModel(final Object[] columnNames) {
227 super(columnNames, 0);
230 public void addRow(Object[] data, Object associatedData) {
232 associated.add(getRowCount() - 1, associatedData);
235 public void removeRow(int row) {
236 super.removeRow(row);
237 associated.remove(row);
240 public Object getAssociatedObject(int row) {
241 return associated.get(row);
244 public boolean isCellEditable(int rowIndex, int mColIndex) {
249 private boolean saveAsORC() throws JAXBException, IOException {
252 final JFileChooser chooser = new JFileChooser();
253 chooser.addChoosableFileFilter(FileHelper.OPEN_ROCKET_COMPONENT_FILTER);
255 chooser.setFileFilter(FileHelper.OPEN_ROCKET_COMPONENT_FILTER);
256 chooser.setCurrentDirectory(((SwingPreferences) Application.getPreferences()).getDefaultDirectory());
258 int option = chooser.showSaveDialog(ComponentPresetPanel.this);
259 if (option != JFileChooser.APPROVE_OPTION) {
260 log.user("User decided not to save, option=" + option);
264 file = chooser.getSelectedFile();
266 log.user("User did not select a file");
270 ((SwingPreferences) Application.getPreferences()).setDefaultDirectory(chooser.getCurrentDirectory());
272 file = FileHelper.forceExtension(file, "orc");
274 List<Material> materials = new ArrayList<Material>();
275 List<ComponentPreset> presets = new ArrayList<ComponentPreset>();
277 for (int x = 0; x < model.getRowCount(); x++) {
278 ComponentPreset preset = (ComponentPreset) model.getAssociatedObject(x);
279 if (!materials.contains(preset.get(ComponentPreset.MATERIAL))) {
280 materials.add(preset.get(ComponentPreset.MATERIAL));
285 return FileHelper.confirmWrite(file, this) && new OpenRocketComponentSaver().save(file, materials, presets);