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.JTable;
21 import javax.swing.JTextField;
22 import javax.swing.ListSelectionModel;
23 import javax.swing.RowFilter;
24 import javax.swing.event.DocumentEvent;
25 import javax.swing.event.DocumentListener;
26 import javax.swing.table.TableModel;
27 import javax.swing.table.TableRowSorter;
29 import net.miginfocom.swing.MigLayout;
30 import net.sf.openrocket.gui.adaptors.Column;
31 import net.sf.openrocket.gui.adaptors.ColumnTableModel;
32 import net.sf.openrocket.gui.util.GUIUtil;
33 import net.sf.openrocket.l10n.Translator;
34 import net.sf.openrocket.preset.ComponentPreset;
35 import net.sf.openrocket.preset.TypedKey;
36 import net.sf.openrocket.rocketcomponent.InternalComponent;
37 import net.sf.openrocket.rocketcomponent.RocketComponent;
38 import net.sf.openrocket.rocketcomponent.SymmetricComponent;
39 import net.sf.openrocket.startup.Application;
40 import net.sf.openrocket.unit.Value;
42 public class ComponentPresetChooserDialog extends JDialog {
44 private static final Translator trans = Application.getTranslator();
46 private final RocketComponent component;
48 private ComponentPresetTable componentSelectionTable;
49 // private final JTable componentSelectionTable;
50 private final JTextField filterText;
51 private final JCheckBox foreDiameterFilterCheckBox;
52 private final JCheckBox aftDiameterFilterCheckBox;
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 final List<ComponentPreset> presets;
63 private boolean okClicked = false;
66 public ComponentPresetChooserDialog(Window owner, RocketComponent component) {
67 super(owner, trans.get("title"), Dialog.ModalityType.APPLICATION_MODAL);
68 this.component = component;
70 final TypedKey<?>[] columnKeys = component.getPresetType().getDisplayedColumns();
72 presets = Application.getComponentPresetDao().listForType(component.getPresetType());
74 for (int i = 0; i < columnKeys.length; i++) {
75 final TypedKey<?> key = columnKeys[i];
76 if ( key == ComponentPreset.OUTER_DIAMETER ) {
77 // magic +1 is because we have inserted the column for favorites above.
78 aftDiameterColumnIndex = i+1;
80 if ( key == ComponentPreset.FORE_OUTER_DIAMETER ) {
81 // magic +1 is because we have inserted the column for favorites above.
82 foreDiameterColumnIndex = i+1;
87 * perhaps there is a better way for this.
89 * This check basically says that if a component does not have a fore diameter, use the
90 * outer_diameter when filtering. The problem this introduced is when this dialog is
91 * created for nose cones (which are aft of a body tube), you will be given the option
92 * to filter based on matching fore diameter.
94 if ( foreDiameterColumnIndex < 0 ) {
95 foreDiameterColumnIndex = aftDiameterColumnIndex;
101 JPanel panel = new JPanel(new MigLayout("fill"));
102 JLabel filterLabel = new JLabel(trans.get("ComponentPresetChooserDialog.filter.label"));
103 panel.add(filterLabel);
104 filterText = new JTextField(15);
105 panel.add(filterText,"growx, growy 0, wrap");
106 filterText.getDocument().addDocumentListener(new DocumentListener() {
108 public void changedUpdate(DocumentEvent e) {
112 public void insertUpdate(DocumentEvent e) {
116 public void removeUpdate(DocumentEvent e) {
122 * Add filter by fore diameter
124 foreDiameterFilterCheckBox = new JCheckBox();
125 foreDiameterFilterCheckBox.setText(trans.get("ComponentPresetChooserDialog.checkbox.filterForeDiameter"));
126 panel.add(foreDiameterFilterCheckBox, "skip, span 2");
127 foreDiameterFilterCheckBox.addItemListener( new ItemListener () {
129 public void itemStateChanged(ItemEvent e) {
134 /* hide the fore diameter filter if it is not applicable */
135 if ( foreDiameterColumnIndex < 0 || component.getPreviousComponent() == null ) {
136 foreDiameterFilterCheckBox.setVisible(false);
140 * Add filter by aft diameter
142 aftDiameterFilterCheckBox = new JCheckBox();
143 aftDiameterFilterCheckBox.setText(trans.get("ComponentPresetChooserDialog.checkbox.filterAftDiameter"));
144 panel.add(aftDiameterFilterCheckBox, "skip, span 2, wrap");
145 aftDiameterFilterCheckBox.addItemListener( new ItemListener () {
147 public void itemStateChanged(ItemEvent e) {
152 /* hide the aft diameter filter if it is not applicable */
153 if ( aftDiameterColumnIndex < 0 || component.getNextComponent() == null ) {
154 aftDiameterFilterCheckBox.setVisible(false);
157 componentSelectionTable = new ComponentPresetTable( presets, Arrays.<TypedKey<?>>asList(columnKeys) );
160 JScrollPane scrollpane = new JScrollPane();
161 scrollpane.setViewportView(componentSelectionTable);
162 panel.add(scrollpane, "grow, width :500:, height :300:, spanx, wrap para");
165 // OK / Cancel buttons
166 JButton okButton = new JButton(trans.get("dlg.but.ok"));
167 okButton.addActionListener(new ActionListener() {
169 public void actionPerformed(ActionEvent e) {
173 panel.add(okButton, "tag ok, spanx, split");
176 JButton cancelButton = new JButton(trans.get("dlg.but.cancel"));
177 cancelButton.addActionListener(new ActionListener() {
179 public void actionPerformed(ActionEvent e) {
183 panel.add(cancelButton, "tag cancel");
189 this.setLocationByPlatform(true);
190 GUIUtil.setDisposableDialogOptions(this, okButton);
192 //JComponent focus = selectionPanel.getDefaultFocus();
193 //if (focus != null) {
194 // focus.grabFocus();
197 // Set the closeable dialog after all initialization
198 //selectionPanel.setCloseableDialog(this);
202 * Return the motor selected by this chooser dialog, or <code>null</code> if the selection has been aborted.
204 * @return the selected motor, or <code>null</code> if no motor has been selected or the selection was canceled.
206 public ComponentPreset getSelectedComponentPreset() {
209 int row = componentSelectionTable.getSelectedRow();
210 row = componentSelectionTable.convertRowIndexToModel(row);
211 return presets.get(row);
214 public void close(boolean ok) {
216 this.setVisible(false);
219 private void updateFilters() {
220 List<RowFilter<TableModel,Object>> filters = new ArrayList<RowFilter<TableModel,Object>> (2);
221 String filterTextRegex = filterText.getText();
222 if ( filterTextRegex != null ) {
224 // The "(?iu)" magic turns on case insensitivity with unicode chars
225 RowFilter<TableModel,Object> regexFilter = RowFilter.regexFilter("(?iu)"+filterTextRegex);
226 filters.add(regexFilter);
227 } catch ( java.util.regex.PatternSyntaxException e ) {
230 if ( aftDiameterFilterCheckBox.isSelected() ) {
231 // FIXME - please verify this logic looks correct.
232 // Grab the next component.
233 // If this.component is an InternalComponent, then we want to filter the outer diameter field
234 // against the next component's inner diameter.
235 RocketComponent nextComponent = component.getNextComponent();
236 if ( nextComponent != null && nextComponent instanceof SymmetricComponent ) {
237 SymmetricComponent parent = (SymmetricComponent) nextComponent;
239 if ( this.component instanceof InternalComponent ) {
240 nextDiameter = parent.getInnerRadius(0) * 2.0;
242 nextDiameter = parent.getForeRadius() * 2.0;
244 RowFilter<TableModel,Object> outerDiameterFilter = new ComponentPresetRowFilter( nextDiameter, aftDiameterColumnIndex);
245 filters.add(outerDiameterFilter);
248 if ( foreDiameterFilterCheckBox.isSelected() ) {
249 // FIXME - please verify this logic looks correct.
250 // Grab the previous component.
251 // If this.component is an InternalComponent, then we want to filter the outer diameter field
252 // against the previous component's inner diameter.
253 RocketComponent previousComponent = component.getPreviousComponent();
254 if ( previousComponent != null && previousComponent instanceof SymmetricComponent ) {
255 SymmetricComponent parent = (SymmetricComponent) previousComponent;
256 double previousDaimeter;
257 if ( this.component instanceof InternalComponent ) {
258 previousDaimeter = parent.getInnerRadius(parent.getLength()) * 2.0;
260 previousDaimeter = parent.getAftRadius() * 2.0;
262 RowFilter<TableModel,Object> outerDiameterFilter = new ComponentPresetRowFilter( previousDaimeter, foreDiameterColumnIndex);
263 filters.add(outerDiameterFilter);
267 componentSelectionTable.setRowFilter( RowFilter.andFilter(filters) );