1 package net.sf.openrocket.gui.dialogs.preset;
4 import java.awt.Dialog;
5 import java.awt.Window;
6 import java.awt.event.ActionEvent;
7 import java.awt.event.ActionListener;
8 import java.awt.event.ItemEvent;
9 import java.awt.event.ItemListener;
10 import java.util.ArrayList;
11 import java.util.Arrays;
12 import java.util.List;
14 import javax.swing.JButton;
15 import javax.swing.JCheckBox;
16 import javax.swing.JDialog;
17 import javax.swing.JLabel;
18 import javax.swing.JPanel;
19 import javax.swing.JScrollPane;
20 import javax.swing.JTextField;
21 import javax.swing.RowFilter;
22 import javax.swing.event.DocumentEvent;
23 import javax.swing.event.DocumentListener;
24 import javax.swing.table.TableColumn;
25 import javax.swing.table.TableModel;
27 import net.miginfocom.swing.MigLayout;
28 import net.sf.openrocket.gui.util.GUIUtil;
29 import net.sf.openrocket.l10n.Translator;
30 import net.sf.openrocket.preset.ComponentPreset;
31 import net.sf.openrocket.preset.TypedKey;
32 import net.sf.openrocket.rocketcomponent.RocketComponent;
33 import net.sf.openrocket.rocketcomponent.SymmetricComponent;
34 import net.sf.openrocket.startup.Application;
37 * Dialog shown for selecting a preset component.
39 public class ComponentPresetChooserDialog extends JDialog {
41 private static final Translator trans = Application.getTranslator();
43 private final RocketComponent component;
45 private ComponentPresetTable componentSelectionTable;
46 private JTextField filterText;
47 private JCheckBox foreDiameterFilterCheckBox;
48 private JCheckBox aftDiameterFilterCheckBox;
50 private ComponentPresetRowFilter foreDiameterFilter;
51 private ComponentPresetRowFilter aftDiameterFilter;
55 * outerDiamtereColumnIndex is the index of the column associated with the OUTER_DIAMETER
56 * field. This index is needed by the matchOuterDiameterCheckBox to implement filtering.
58 int aftDiameterColumnIndex = -1;
59 int foreDiameterColumnIndex = -1;
61 private List<ComponentPreset> presets;
62 private ComponentPreset.Type presetType;
64 private boolean okClicked = false;
67 public ComponentPresetChooserDialog(Window owner, RocketComponent component) {
68 super(owner, trans.get("title"), Dialog.ModalityType.APPLICATION_MODAL);
69 this.component = component;
70 this.presetType = component.getPresetType();
71 this.presets = Application.getComponentPresetDao().listForType(component.getPresetType());
73 List<TypedKey<?>> displayedColumnKeys = Arrays.asList(component.getPresetType().getDisplayedColumns());
76 final List<TypedKey<?>> columnKeys = ComponentPreset.ORDERED_KEY_LIST;
77 int i = 0; // We start at 0 but use preincrement because the first column is favorite.
78 for (final TypedKey<?> key : columnKeys) {
79 // Note the increment early in the loop. This really means that initial loop i=1
80 // we do it here so the continue below doesn't mess up the counting.
82 // Don't allow the matching filters if the column is not part of the default set for
83 // this kind of preset.
84 if (!displayedColumnKeys.contains(key)) {
87 if (key == ComponentPreset.OUTER_DIAMETER || key == ComponentPreset.AFT_OUTER_DIAMETER) {
88 aftDiameterColumnIndex = i;
90 if (key == ComponentPreset.OUTER_DIAMETER || key == ComponentPreset.FORE_OUTER_DIAMETER) {
91 foreDiameterColumnIndex = i;
97 JPanel panel = new JPanel(new MigLayout("fill, ins para"));
100 * Add filter by text.
102 JPanel sub = new JPanel(new MigLayout("fill, ins 0"));
103 JLabel filterLabel = new JLabel(trans.get("ComponentPresetChooserDialog.filter.label"));
104 sub.add(filterLabel, "gapright para");
106 filterText = new JTextField();
107 sub.add(filterText, "growx");
108 filterText.getDocument().addDocumentListener(new DocumentListener() {
110 public void changedUpdate(DocumentEvent e) {
115 public void insertUpdate(DocumentEvent e) {
120 public void removeUpdate(DocumentEvent e) {
125 panel.add(sub, "growx, ay 0, gapright para");
128 panel.add(getFilterCheckboxes(), "wrap para");
130 componentSelectionTable = new ComponentPresetTable(presetType, presets, displayedColumnKeys);
131 // GUIUtil.setAutomaticColumnTableWidths(componentSelectionTable, 20);
132 int w = componentSelectionTable.getRowHeight() + 4;
133 TableColumn tc = componentSelectionTable.getColumnModel().getColumn(0);
134 tc.setPreferredWidth(w);
138 JScrollPane scrollpane = new JScrollPane();
139 scrollpane.setViewportView(componentSelectionTable);
140 panel.add(scrollpane, "grow, width 700lp, height 300lp, spanx, wrap para");
143 // OK / Cancel buttons
144 JButton okButton = new JButton(trans.get("dlg.but.ok"));
145 okButton.addActionListener(new ActionListener() {
147 public void actionPerformed(ActionEvent e) {
151 panel.add(okButton, "tag ok, spanx, split");
154 JButton cancelButton = new JButton(trans.get("dlg.but.cancel"));
155 cancelButton.addActionListener(new ActionListener() {
157 public void actionPerformed(ActionEvent e) {
161 panel.add(cancelButton, "tag cancel");
165 GUIUtil.rememberWindowSize(this);
166 GUIUtil.setDisposableDialogOptions(this, okButton);
170 private JPanel getFilterCheckboxes() {
171 SymmetricComponent sc;
173 JPanel panel = new JPanel(new MigLayout("fill, ins 0"));
176 * Add show all compatible check box.
178 final List<ComponentPreset.Type> compatibleTypes = component.getPresetType().getCompatibleTypes();
179 final ComponentPreset.Type nativeType = component.getPresetType();
180 if (compatibleTypes != null && compatibleTypes.size() > 0) {
181 JCheckBox showAll = new JCheckBox();
182 showAll.setText(trans.get("ComponentPresetChooserDialog.checkbox.showAllCompatible"));
183 panel.add(showAll, "wrap");
184 showAll.addItemListener(new ItemListener() {
186 public void itemStateChanged(ItemEvent e) {
187 if (((JCheckBox) e.getItem()).isSelected()) {
188 presets = Application.getComponentPresetDao().listForTypes(compatibleTypes);
190 presets = Application.getComponentPresetDao().listForType(nativeType);
192 componentSelectionTable.updateData(presets);
198 * Add filter by fore diameter
200 foreDiameterFilterCheckBox = new JCheckBox(trans.get("ComponentPresetChooserDialog.checkbox.filterForeDiameter"));
201 sc = getPreviousSymmetricComponent();
202 if (sc != null && foreDiameterColumnIndex >= 0) {
203 foreDiameterFilter = new ComponentPresetRowFilter(sc.getAftRadius() * 2.0, foreDiameterColumnIndex);
204 panel.add(foreDiameterFilterCheckBox, "wrap");
205 foreDiameterFilterCheckBox.addItemListener(new ItemListener() {
207 public void itemStateChanged(ItemEvent e) {
214 * Add filter by aft diameter
216 aftDiameterFilterCheckBox = new JCheckBox(trans.get("ComponentPresetChooserDialog.checkbox.filterAftDiameter"));
217 sc = getNextSymmetricComponent();
218 if (sc != null && aftDiameterColumnIndex >= 0) {
219 aftDiameterFilter = new ComponentPresetRowFilter(sc.getForeRadius() * 2.0, aftDiameterColumnIndex);
220 panel.add(aftDiameterFilterCheckBox, "wrap");
221 aftDiameterFilterCheckBox.addItemListener(new ItemListener() {
223 public void itemStateChanged(ItemEvent e) {
233 * Return the motor selected by this chooser dialog, or <code>null</code> if the selection has been aborted.
235 * @return the selected motor, or <code>null</code> if no motor has been selected or the selection was canceled.
237 public ComponentPreset getSelectedComponentPreset() {
240 int row = componentSelectionTable.getSelectedRow();
241 row = componentSelectionTable.convertRowIndexToModel(row);
242 return presets.get(row);
245 public void close(boolean ok) {
247 this.setVisible(false);
250 private void updateFilters() {
251 List<RowFilter<TableModel, Object>> filters = new ArrayList<RowFilter<TableModel, Object>>(2);
252 String filterTextRegex = filterText.getText();
253 if (filterTextRegex != null) {
255 // The "(?iu)" magic turns on case insensitivity with unicode chars
256 RowFilter<TableModel, Object> regexFilter = RowFilter.regexFilter("(?iu)" + filterTextRegex);
257 filters.add(regexFilter);
258 } catch (java.util.regex.PatternSyntaxException e) {
261 if (aftDiameterFilterCheckBox.isSelected()) {
262 filters.add(aftDiameterFilter);
264 if (foreDiameterFilterCheckBox.isSelected()) {
265 filters.add(foreDiameterFilter);
268 componentSelectionTable.setRowFilter(RowFilter.andFilter(filters));
272 private SymmetricComponent getPreviousSymmetricComponent() {
273 RocketComponent c = component;
275 c = c.getPreviousComponent();
276 if (c instanceof SymmetricComponent) {
277 return (SymmetricComponent) c;
284 private SymmetricComponent getNextSymmetricComponent() {
285 RocketComponent c = component;
287 c = c.getNextComponent();
288 if (c instanceof SymmetricComponent) {
289 return (SymmetricComponent) c;