Fix up the logic for showing and using the aft/fore match diameter switches.
[debian/openrocket] / core / src / net / sf / openrocket / gui / dialogs / preset / ComponentPresetChooserDialog.java
1 package net.sf.openrocket.gui.dialogs.preset;
2
3
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;
13
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;
25
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;
36
37 public class ComponentPresetChooserDialog extends JDialog {
38
39         private static final Translator trans = Application.getTranslator();
40
41         private final RocketComponent component;
42
43         private ComponentPresetTable componentSelectionTable;
44         private final JTextField filterText;
45         private final JCheckBox foreDiameterFilterCheckBox;
46         private final JCheckBox aftDiameterFilterCheckBox;
47
48         /*
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.
51          */
52         int aftDiameterColumnIndex = -1;
53         int foreDiameterColumnIndex = -1;
54
55         private List<ComponentPreset> presets;
56
57         private boolean okClicked = false;
58
59
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());
64                 
65                 List<TypedKey<?>> displayedColumnKeys = Arrays.<TypedKey<?>>asList(component.getPresetType().getDisplayedColumns());
66                 {
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.
72                                 i++;
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) ) { 
76                                         continue;
77                                 }
78                                 if ( key == ComponentPreset.OUTER_DIAMETER || key == ComponentPreset.AFT_OUTER_DIAMETER ) {
79                                         aftDiameterColumnIndex = i;
80                                 }
81                                 if ( key == ComponentPreset.OUTER_DIAMETER || key == ComponentPreset.FORE_OUTER_DIAMETER ) {
82                                         foreDiameterColumnIndex = i;
83                                 }
84                         }
85                 }
86                 
87                 /*
88                  * Add filter by text.
89                  */
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() {
96                         @Override
97                         public void changedUpdate(DocumentEvent e) {
98                                 updateFilters();
99                         }
100                         @Override
101                         public void insertUpdate(DocumentEvent e) {
102                                 updateFilters();
103                         }
104                         @Override
105                         public void removeUpdate(DocumentEvent e) {
106                                 updateFilters();
107                         }
108                 });
109
110                 /*
111                  * Add show all compatible check box.
112                  */
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 () {
120                                 @Override
121                                 public void itemStateChanged(ItemEvent e) {
122                                         if ( ((JCheckBox)e.getItem()).isSelected()  ) {
123                                                 presets = Application.getComponentPresetDao().listForTypes(compatibleTypes);
124                                         } else {
125                                                 presets = Application.getComponentPresetDao().listForType(nativeType);
126                                         }
127                                         componentSelectionTable.updateData( presets );
128                                 }
129                         });
130
131
132                 }
133
134                 /*
135                  * Add filter by fore diameter
136                  */
137                 foreDiameterFilterCheckBox = new JCheckBox();
138                 foreDiameterFilterCheckBox.setText(trans.get("ComponentPresetChooserDialog.checkbox.filterForeDiameter"));
139                 panel.add(foreDiameterFilterCheckBox, "skip, span 2");
140                 foreDiameterFilterCheckBox.addItemListener( new ItemListener () {
141                         @Override
142                         public void itemStateChanged(ItemEvent e) {
143                                 updateFilters();
144                         }
145                 });
146
147                 RocketComponent previousComponent = component.getPreviousComponent(); 
148                 /* hide the fore diameter filter if it is not applicable */
149                 if ( foreDiameterColumnIndex < 0 ) {
150                         foreDiameterFilterCheckBox.setVisible(false);
151                 }
152                 if ( previousComponent == null ) {
153                         foreDiameterFilterCheckBox.setVisible(false);
154                 } else {
155                         if ( !(previousComponent instanceof ExternalComponent) && !(previousComponent instanceof InternalComponent) )
156                                 foreDiameterFilterCheckBox.setVisible(false);
157                 }
158
159                 /*
160                  * Add filter by aft diameter
161                  */
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 () {
166                         @Override
167                         public void itemStateChanged(ItemEvent e) {
168                                 updateFilters();
169                         }
170                 });
171
172                 RocketComponent nextComponent = component.getNextComponent();
173                 /* hide the aft diameter filter if it is not applicable */
174                 if ( aftDiameterColumnIndex < 0 ) {
175                         aftDiameterFilterCheckBox.setVisible(false);
176                 }
177                 if ( nextComponent == null ) {
178                         aftDiameterFilterCheckBox.setVisible(false);
179                 } else if ( !(nextComponent instanceof ExternalComponent) && !(nextComponent instanceof InternalComponent)) {
180                         aftDiameterFilterCheckBox.setVisible(false);
181                 }
182
183                 componentSelectionTable = new ComponentPresetTable( presets, displayedColumnKeys );
184
185                 JScrollPane scrollpane = new JScrollPane();
186                 scrollpane.setViewportView(componentSelectionTable);
187                 panel.add(scrollpane, "grow, width :500:, height :300:, spanx, wrap para");
188
189
190                 // OK / Cancel buttons
191                 JButton okButton = new JButton(trans.get("dlg.but.ok"));
192                 okButton.addActionListener(new ActionListener() {
193                         @Override
194                         public void actionPerformed(ActionEvent e) {
195                                 close(true);
196                         }
197                 });
198                 panel.add(okButton, "tag ok, spanx, split");
199
200                 //// Cancel button
201                 JButton cancelButton = new JButton(trans.get("dlg.but.cancel"));
202                 cancelButton.addActionListener(new ActionListener() {
203                         @Override
204                         public void actionPerformed(ActionEvent e) {
205                                 close(false);
206                         }
207                 });
208                 panel.add(cancelButton, "tag cancel");
209
210                 this.add(panel);
211
212                 this.setModal(true);
213                 this.pack();
214                 this.setLocationByPlatform(true);
215                 GUIUtil.setDisposableDialogOptions(this, okButton);
216
217         }
218
219         /**
220          * Return the motor selected by this chooser dialog, or <code>null</code> if the selection has been aborted.
221          * 
222          * @return      the selected motor, or <code>null</code> if no motor has been selected or the selection was canceled.
223          */
224         public ComponentPreset getSelectedComponentPreset() {
225                 if (!okClicked)
226                         return null;
227                 int row = componentSelectionTable.getSelectedRow();
228                 row = componentSelectionTable.convertRowIndexToModel(row);
229                 return presets.get(row);
230         }
231
232         public void close(boolean ok) {
233                 okClicked = ok;
234                 this.setVisible(false);
235         }
236
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 ) {
241                         try {
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 ) {
246                         }
247                 }
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;
256                                 double nextDiameter;
257                                 if ( this.component instanceof InternalComponent ) {
258                                         nextDiameter = parent.getInnerRadius(0) * 2.0;
259                                 } else {
260                                         nextDiameter = parent.getForeRadius() * 2.0;
261                                 }
262                                 RowFilter<TableModel,Object> outerDiameterFilter = new ComponentPresetRowFilter( nextDiameter, aftDiameterColumnIndex);
263                                 filters.add(outerDiameterFilter);
264                         }
265                 }
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;
277                                 } else {
278                                         previousDaimeter = parent.getAftRadius() * 2.0;
279                                 }
280                                 RowFilter<TableModel,Object> outerDiameterFilter = new ComponentPresetRowFilter( previousDaimeter, foreDiameterColumnIndex);
281                                 filters.add(outerDiameterFilter);
282                         }
283                 }
284
285                 componentSelectionTable.setRowFilter( RowFilter.andFilter(filters) );
286         }
287 }