When the OK button in the component preset dialog is pressed without selecting an...
[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.TableColumn;
25 import javax.swing.table.TableModel;
26
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;
35
36 /**
37  * Dialog shown for selecting a preset component.
38  */
39 public class ComponentPresetChooserDialog extends JDialog {
40         
41         private static final Translator trans = Application.getTranslator();
42         
43         private final RocketComponent component;
44         
45         private ComponentPresetTable componentSelectionTable;
46         private JTextField filterText;
47         private JCheckBox foreDiameterFilterCheckBox;
48         private JCheckBox aftDiameterFilterCheckBox;
49         
50         private ComponentPresetRowFilter foreDiameterFilter;
51         private ComponentPresetRowFilter aftDiameterFilter;
52         
53         
54         /*
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.
57          */
58         int aftDiameterColumnIndex = -1;
59         int foreDiameterColumnIndex = -1;
60         
61         private List<ComponentPreset> presets;
62         private ComponentPreset.Type presetType;
63         
64         private boolean okClicked = false;
65         
66         
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());
72                 
73                 List<TypedKey<?>> displayedColumnKeys = Arrays.asList(component.getPresetType().getDisplayedColumns());
74                 
75                 {
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.
81                                 i++;
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)) {
85                                         continue;
86                                 }
87                                 if (key == ComponentPreset.OUTER_DIAMETER || key == ComponentPreset.AFT_OUTER_DIAMETER) {
88                                         aftDiameterColumnIndex = i;
89                                 }
90                                 if (key == ComponentPreset.OUTER_DIAMETER || key == ComponentPreset.FORE_OUTER_DIAMETER) {
91                                         foreDiameterColumnIndex = i;
92                                 }
93                         }
94                 }
95                 
96                 
97                 JPanel panel = new JPanel(new MigLayout("fill, ins para"));
98                 
99                 /*
100                  * Add filter by text.
101                  */
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");
105                 
106                 filterText = new JTextField();
107                 sub.add(filterText, "growx");
108                 filterText.getDocument().addDocumentListener(new DocumentListener() {
109                         @Override
110                         public void changedUpdate(DocumentEvent e) {
111                                 updateFilters();
112                         }
113                         
114                         @Override
115                         public void insertUpdate(DocumentEvent e) {
116                                 updateFilters();
117                         }
118                         
119                         @Override
120                         public void removeUpdate(DocumentEvent e) {
121                                 updateFilters();
122                         }
123                 });
124                 
125                 panel.add(sub, "growx, ay 0, gapright para");
126                 
127                 
128                 panel.add(getFilterCheckboxes(), "wrap para");
129                 
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);
135                 tc.setMaxWidth(w);
136                 tc.setMinWidth(w);
137                 
138                 JScrollPane scrollpane = new JScrollPane();
139                 scrollpane.setViewportView(componentSelectionTable);
140                 panel.add(scrollpane, "grow, width 700lp, height 300lp, spanx, wrap para");
141                 
142                 
143                 // OK / Cancel buttons
144                 JButton okButton = new JButton(trans.get("dlg.but.ok"));
145                 okButton.addActionListener(new ActionListener() {
146                         @Override
147                         public void actionPerformed(ActionEvent e) {
148                                 close(true);
149                         }
150                 });
151                 panel.add(okButton, "tag ok, spanx, split");
152                 
153                 //// Cancel button
154                 JButton cancelButton = new JButton(trans.get("dlg.but.cancel"));
155                 cancelButton.addActionListener(new ActionListener() {
156                         @Override
157                         public void actionPerformed(ActionEvent e) {
158                                 close(false);
159                         }
160                 });
161                 panel.add(cancelButton, "tag cancel");
162                 
163                 this.add(panel);
164                 
165                 GUIUtil.rememberWindowSize(this);
166                 GUIUtil.setDisposableDialogOptions(this, okButton);
167         }
168         
169         
170         private JPanel getFilterCheckboxes() {
171                 SymmetricComponent sc;
172                 
173                 JPanel panel = new JPanel(new MigLayout("fill, ins 0"));
174                 
175                 /*
176                  * Add show all compatible check box.
177                  */
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() {
185                                 @Override
186                                 public void itemStateChanged(ItemEvent e) {
187                                         if (((JCheckBox) e.getItem()).isSelected()) {
188                                                 presets = Application.getComponentPresetDao().listForTypes(compatibleTypes);
189                                         } else {
190                                                 presets = Application.getComponentPresetDao().listForType(nativeType);
191                                         }
192                                         componentSelectionTable.updateData(presets);
193                                 }
194                         });
195                 }
196                 
197                 /*
198                  * Add filter by fore diameter
199                  */
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() {
206                                 @Override
207                                 public void itemStateChanged(ItemEvent e) {
208                                         updateFilters();
209                                 }
210                         });
211                 }
212                 
213                 /*
214                  * Add filter by aft diameter
215                  */
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() {
222                                 @Override
223                                 public void itemStateChanged(ItemEvent e) {
224                                         updateFilters();
225                                 }
226                         });
227                 }
228                 
229                 return panel;
230         }
231         
232         /**
233          * Return the motor selected by this chooser dialog, or <code>null</code> if the selection has been aborted.
234          * 
235          * @return      the selected motor, or <code>null</code> if no motor has been selected or the selection was canceled.
236          */
237         public ComponentPreset getSelectedComponentPreset() {
238                 if (!okClicked)
239                         return null;
240                 int row = componentSelectionTable.getSelectedRow();
241                 if ( row < 0 ) {
242                         // Nothing selected.
243                         return null;
244                 }
245                 row = componentSelectionTable.convertRowIndexToModel(row);
246                 return presets.get(row);
247         }
248         
249         public void close(boolean ok) {
250                 okClicked = ok;
251                 this.setVisible(false);
252         }
253         
254         private void updateFilters() {
255                 List<RowFilter<TableModel, Object>> filters = new ArrayList<RowFilter<TableModel, Object>>(2);
256                 String filterTextRegex = filterText.getText();
257                 if (filterTextRegex != null) {
258                         try {
259                                 // The "(?iu)" magic turns on case insensitivity with unicode chars
260                                 RowFilter<TableModel, Object> regexFilter = RowFilter.regexFilter("(?iu)" + filterTextRegex);
261                                 filters.add(regexFilter);
262                         } catch (java.util.regex.PatternSyntaxException e) {
263                         }
264                 }
265                 if (aftDiameterFilterCheckBox.isSelected()) {
266                         filters.add(aftDiameterFilter);
267                 }
268                 if (foreDiameterFilterCheckBox.isSelected()) {
269                         filters.add(foreDiameterFilter);
270                 }
271                 
272                 componentSelectionTable.setRowFilter(RowFilter.andFilter(filters));
273         }
274         
275         
276         private SymmetricComponent getPreviousSymmetricComponent() {
277                 RocketComponent c = component;
278                 while (c != null) {
279                         c = c.getPreviousComponent();
280                         if (c instanceof SymmetricComponent) {
281                                 return (SymmetricComponent) c;
282                         }
283                 }
284                 return null;
285         }
286         
287         
288         private SymmetricComponent getNextSymmetricComponent() {
289                 RocketComponent c = component;
290                 while (c != null) {
291                         c = c.getNextComponent();
292                         if (c instanceof SymmetricComponent) {
293                                 return (SymmetricComponent) c;
294                         }
295                 }
296                 return null;
297         }
298 }