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.TableModel;
26 import net.miginfocom.swing.MigLayout;
27 import net.sf.openrocket.gui.util.GUIUtil;
28 import net.sf.openrocket.l10n.Translator;
29 import net.sf.openrocket.preset.ComponentPreset;
30 import net.sf.openrocket.preset.TypedKey;
31 import net.sf.openrocket.rocketcomponent.ExternalComponent;
32 import net.sf.openrocket.rocketcomponent.InternalComponent;
33 import net.sf.openrocket.rocketcomponent.RocketComponent;
34 import net.sf.openrocket.rocketcomponent.SymmetricComponent;
35 import net.sf.openrocket.startup.Application;
37 public class ComponentPresetChooserDialog extends JDialog {
39 private static final Translator trans = Application.getTranslator();
41 private final RocketComponent component;
43 private ComponentPresetTable componentSelectionTable;
44 private final JTextField filterText;
45 private final JCheckBox foreDiameterFilterCheckBox;
46 private final JCheckBox aftDiameterFilterCheckBox;
49 * outerDiamtereColumnIndex is the index of the column associated with the OUTER_DIAMETER
50 * field. This index is needed by the matchOuterDiameterCheckBox to implement filtering.
52 int aftDiameterColumnIndex = -1;
53 int foreDiameterColumnIndex = -1;
55 private List<ComponentPreset> presets;
57 private boolean okClicked = false;
60 public ComponentPresetChooserDialog(Window owner, RocketComponent component) {
61 super(owner, trans.get("title"), Dialog.ModalityType.APPLICATION_MODAL);
62 this.component = component;
63 this.presets = Application.getComponentPresetDao().listForType(component.getPresetType());
65 List<TypedKey<?>> displayedColumnKeys = Arrays.<TypedKey<?>>asList(component.getPresetType().getDisplayedColumns());
67 final List<TypedKey<?>> columnKeys = ComponentPreset.orderedKeyList;
68 int i=0; // We start at 0 but use preincrement because the first column is favorite.
69 for (final TypedKey<?> key : columnKeys) {
70 // Note the increment early in the loop. This really means that initial loop i=1
71 // we do it here so the continue below doesn't mess up the counting.
73 // Don't allow the matching filters if the column is not part of the default set for
74 // this kind of preset.
75 if ( ! displayedColumnKeys.contains(key) ) {
78 if ( key == ComponentPreset.OUTER_DIAMETER || key == ComponentPreset.AFT_OUTER_DIAMETER ) {
79 aftDiameterColumnIndex = i;
81 if ( key == ComponentPreset.OUTER_DIAMETER || key == ComponentPreset.FORE_OUTER_DIAMETER ) {
82 foreDiameterColumnIndex = i;
90 JPanel panel = new JPanel(new MigLayout("fill"));
91 JLabel filterLabel = new JLabel(trans.get("ComponentPresetChooserDialog.filter.label"));
92 panel.add(filterLabel);
93 filterText = new JTextField(15);
94 panel.add(filterText,"growx, growy 0, wrap");
95 filterText.getDocument().addDocumentListener(new DocumentListener() {
97 public void changedUpdate(DocumentEvent e) {
101 public void insertUpdate(DocumentEvent e) {
105 public void removeUpdate(DocumentEvent e) {
111 * Add show all compatible check box.
113 final List<ComponentPreset.Type> compatibleTypes = component.getPresetType().getCompatibleTypes();
114 final ComponentPreset.Type nativeType = component.getPresetType();
115 if ( compatibleTypes != null && compatibleTypes.size() > 0 ) {
116 JCheckBox showAll = new JCheckBox();
117 showAll.setText(trans.get("ComponentPresetChooserDialog.checkbox.showAllCompatible"));
118 panel.add(showAll, "skip, span 2");
119 showAll.addItemListener( new ItemListener () {
121 public void itemStateChanged(ItemEvent e) {
122 if ( ((JCheckBox)e.getItem()).isSelected() ) {
123 presets = Application.getComponentPresetDao().listForTypes(compatibleTypes);
125 presets = Application.getComponentPresetDao().listForType(nativeType);
127 componentSelectionTable.updateData( presets );
135 * Add filter by fore diameter
137 foreDiameterFilterCheckBox = new JCheckBox();
138 foreDiameterFilterCheckBox.setText(trans.get("ComponentPresetChooserDialog.checkbox.filterForeDiameter"));
139 panel.add(foreDiameterFilterCheckBox, "skip, span 2");
140 foreDiameterFilterCheckBox.addItemListener( new ItemListener () {
142 public void itemStateChanged(ItemEvent e) {
147 RocketComponent previousComponent = component.getPreviousComponent();
148 /* hide the fore diameter filter if it is not applicable */
149 if ( foreDiameterColumnIndex < 0 ) {
150 foreDiameterFilterCheckBox.setVisible(false);
152 if ( previousComponent == null ) {
153 foreDiameterFilterCheckBox.setVisible(false);
155 if ( !(previousComponent instanceof ExternalComponent) && !(previousComponent instanceof InternalComponent) )
156 foreDiameterFilterCheckBox.setVisible(false);
160 * Add filter by aft diameter
162 aftDiameterFilterCheckBox = new JCheckBox();
163 aftDiameterFilterCheckBox.setText(trans.get("ComponentPresetChooserDialog.checkbox.filterAftDiameter"));
164 panel.add(aftDiameterFilterCheckBox, "skip, span 2, wrap");
165 aftDiameterFilterCheckBox.addItemListener( new ItemListener () {
167 public void itemStateChanged(ItemEvent e) {
172 RocketComponent nextComponent = component.getNextComponent();
173 /* hide the aft diameter filter if it is not applicable */
174 if ( aftDiameterColumnIndex < 0 ) {
175 aftDiameterFilterCheckBox.setVisible(false);
177 if ( nextComponent == null ) {
178 aftDiameterFilterCheckBox.setVisible(false);
179 } else if ( !(nextComponent instanceof ExternalComponent) && !(nextComponent instanceof InternalComponent)) {
180 aftDiameterFilterCheckBox.setVisible(false);
183 componentSelectionTable = new ComponentPresetTable( presets, displayedColumnKeys );
185 JScrollPane scrollpane = new JScrollPane();
186 scrollpane.setViewportView(componentSelectionTable);
187 panel.add(scrollpane, "grow, width :500:, height :300:, spanx, wrap para");
190 // OK / Cancel buttons
191 JButton okButton = new JButton(trans.get("dlg.but.ok"));
192 okButton.addActionListener(new ActionListener() {
194 public void actionPerformed(ActionEvent e) {
198 panel.add(okButton, "tag ok, spanx, split");
201 JButton cancelButton = new JButton(trans.get("dlg.but.cancel"));
202 cancelButton.addActionListener(new ActionListener() {
204 public void actionPerformed(ActionEvent e) {
208 panel.add(cancelButton, "tag cancel");
214 this.setLocationByPlatform(true);
215 GUIUtil.setDisposableDialogOptions(this, okButton);
220 * Return the motor selected by this chooser dialog, or <code>null</code> if the selection has been aborted.
222 * @return the selected motor, or <code>null</code> if no motor has been selected or the selection was canceled.
224 public ComponentPreset getSelectedComponentPreset() {
227 int row = componentSelectionTable.getSelectedRow();
228 row = componentSelectionTable.convertRowIndexToModel(row);
229 return presets.get(row);
232 public void close(boolean ok) {
234 this.setVisible(false);
237 private void updateFilters() {
238 List<RowFilter<TableModel,Object>> filters = new ArrayList<RowFilter<TableModel,Object>> (2);
239 String filterTextRegex = filterText.getText();
240 if ( filterTextRegex != null ) {
242 // The "(?iu)" magic turns on case insensitivity with unicode chars
243 RowFilter<TableModel,Object> regexFilter = RowFilter.regexFilter("(?iu)"+filterTextRegex);
244 filters.add(regexFilter);
245 } catch ( java.util.regex.PatternSyntaxException e ) {
248 if ( aftDiameterFilterCheckBox.isSelected() ) {
249 // FIXME - please verify this logic looks correct.
250 // Grab the next component.
251 // If this.component is an InternalComponent, then we want to filter the outer diameter field
252 // against the next component's inner diameter.
253 RocketComponent nextComponent = component.getNextComponent();
254 if ( nextComponent != null && nextComponent instanceof SymmetricComponent ) {
255 SymmetricComponent parent = (SymmetricComponent) nextComponent;
257 if ( this.component instanceof InternalComponent ) {
258 nextDiameter = parent.getInnerRadius(0) * 2.0;
260 nextDiameter = parent.getForeRadius() * 2.0;
262 RowFilter<TableModel,Object> outerDiameterFilter = new ComponentPresetRowFilter( nextDiameter, aftDiameterColumnIndex);
263 filters.add(outerDiameterFilter);
266 if ( foreDiameterFilterCheckBox.isSelected() ) {
267 // FIXME - please verify this logic looks correct.
268 // Grab the previous component.
269 // If this.component is an InternalComponent, then we want to filter the outer diameter field
270 // against the previous component's inner diameter.
271 RocketComponent previousComponent = component.getPreviousComponent();
272 if ( previousComponent != null && previousComponent instanceof SymmetricComponent ) {
273 SymmetricComponent parent = (SymmetricComponent) previousComponent;
274 double previousDaimeter;
275 if ( this.component instanceof InternalComponent ) {
276 previousDaimeter = parent.getInnerRadius(parent.getLength()) * 2.0;
278 previousDaimeter = parent.getAftRadius() * 2.0;
280 RowFilter<TableModel,Object> outerDiameterFilter = new ComponentPresetRowFilter( previousDaimeter, foreDiameterColumnIndex);
281 filters.add(outerDiameterFilter);
285 componentSelectionTable.setRowFilter( RowFilter.andFilter(filters) );