import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
-import javax.swing.JTable;
import javax.swing.JTextField;
-import javax.swing.ListSelectionModel;
import javax.swing.RowFilter;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
+import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
-import javax.swing.table.TableRowSorter;
import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.gui.adaptors.Column;
-import net.sf.openrocket.gui.adaptors.ColumnTableModel;
import net.sf.openrocket.gui.util.GUIUtil;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.TypedKey;
-import net.sf.openrocket.rocketcomponent.InternalComponent;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.rocketcomponent.SymmetricComponent;
import net.sf.openrocket.startup.Application;
-import net.sf.openrocket.unit.Value;
+/**
+ * Dialog shown for selecting a preset component.
+ */
public class ComponentPresetChooserDialog extends JDialog {
private static final Translator trans = Application.getTranslator();
private final RocketComponent component;
- private final JTable componentSelectionTable;
- private final TableRowSorter<TableModel> sorter;
- private final JTextField filterText;
- private final JCheckBox foreDiameterFilterCheckBox;
- private final JCheckBox aftDiameterFilterCheckBox;
+ private ComponentPresetTable componentSelectionTable;
+ private JTextField filterText;
+ private JCheckBox foreDiameterFilterCheckBox;
+ private JCheckBox aftDiameterFilterCheckBox;
+
+ private ComponentPresetRowFilter foreDiameterFilter;
+ private ComponentPresetRowFilter aftDiameterFilter;
+
/*
* outerDiamtereColumnIndex is the index of the column associated with the OUTER_DIAMETER
*/
int aftDiameterColumnIndex = -1;
int foreDiameterColumnIndex = -1;
-
- private final List<ComponentPreset> presets;
+
+ private List<ComponentPreset> presets;
+ private ComponentPreset.Type presetType;
private boolean okClicked = false;
public ComponentPresetChooserDialog(Window owner, RocketComponent component) {
super(owner, trans.get("title"), Dialog.ModalityType.APPLICATION_MODAL);
this.component = component;
+ this.presetType = component.getPresetType();
+ this.presets = Application.getComponentPresetDao().listForType(component.getPresetType());
- final TypedKey<?>[] columnKeys = component.getPresetType().getDisplayedColumns();
-
- presets = Application.getComponentPresetDao().listForType(component.getPresetType());
-
- /*
- * Set up the Column Table model
- */
- final Column[] columns = new Column[columnKeys.length+1];
+ List<TypedKey<?>> displayedColumnKeys = Arrays.asList(component.getPresetType().getDisplayedColumns());
- columns[0] = new Column(trans.get("table.column.Favorite") ) {
- @Override
- public Object getValueAt(int row) {
- return Boolean.valueOf(ComponentPresetChooserDialog.this.presets.get(row).isFavorite());
- }
-
- @Override
- public void setValueAt(int row, Object value) {
- Application.getComponentPresetDao().setFavorite(ComponentPresetChooserDialog.this.presets.get(row), (Boolean) value);
- }
-
- @Override
- public Class<?> getColumnClass() {
- return Boolean.class;
- }
-
- };
-
- for (int i = 0; i < columnKeys.length; i++) {
- final TypedKey<?> key = columnKeys[i];
- if ( key == ComponentPreset.OUTER_DIAMETER ) {
- // magic +1 is because we have inserted the column for favorites above.
- aftDiameterColumnIndex = i+1;
- }
- if ( key == ComponentPreset.FORE_OUTER_DIAMETER ) {
- // magic +1 is because we have inserted the column for favorites above.
- foreDiameterColumnIndex = i+1;
- }
- columns[i+1] = new Column(trans.get("table.column." + key.getName())) {
- @Override
- public Object getValueAt(int row) {
- ComponentPreset preset = ComponentPresetChooserDialog.this.presets.get(row);
- if ( ! preset.has(key) ) {
- return null;
- }
- Object value = preset.get(key);
- if (key.getType() == Double.class && key.getUnitGroup() != null) {
- return new Value( (Double) value, key.getUnitGroup() );
- } else {
- return value;
- }
+ {
+ final List<TypedKey<?>> columnKeys = ComponentPreset.ORDERED_KEY_LIST;
+ int i = 0; // We start at 0 but use preincrement because the first column is favorite.
+ for (final TypedKey<?> key : columnKeys) {
+ // Note the increment early in the loop. This really means that initial loop i=1
+ // we do it here so the continue below doesn't mess up the counting.
+ i++;
+ // Don't allow the matching filters if the column is not part of the default set for
+ // this kind of preset.
+ if (!displayedColumnKeys.contains(key)) {
+ continue;
+ }
+ if (key == ComponentPreset.OUTER_DIAMETER || key == ComponentPreset.AFT_OUTER_DIAMETER) {
+ aftDiameterColumnIndex = i;
+ }
+ if (key == ComponentPreset.OUTER_DIAMETER || key == ComponentPreset.FORE_OUTER_DIAMETER) {
+ foreDiameterColumnIndex = i;
}
- };
+ }
}
- /*
- * perhaps there is a better way for this.
- *
- * This check basically says that if a component does not have a fore diameter, use the
- * outer_diameter when filtering. The problem this introduced is when this dialog is
- * created for nose cones (which are aft of a body tube), you will be given the option
- * to filter based on matching fore diameter.
- */
- if ( foreDiameterColumnIndex < 0 ) {
- foreDiameterColumnIndex = aftDiameterColumnIndex;
- }
- ColumnTableModel tableModel = new ColumnTableModel(columns) {
- @Override
- public int getRowCount() {
- return ComponentPresetChooserDialog.this.presets.size();
- }
-
- @Override
- public boolean isCellEditable(int rowIndex, int columnIndex) {
- return columnIndex == 0;
- }
-
- };
+ JPanel panel = new JPanel(new MigLayout("fill, ins para"));
-
/*
* Add filter by text.
*/
- JPanel panel = new JPanel(new MigLayout("fill"));
+ JPanel sub = new JPanel(new MigLayout("fill, ins 0"));
JLabel filterLabel = new JLabel(trans.get("ComponentPresetChooserDialog.filter.label"));
- panel.add(filterLabel);
- filterText = new JTextField(15);
- panel.add(filterText,"growx, growy 0, wrap");
+ sub.add(filterLabel, "gapright para");
+
+ filterText = new JTextField();
+ sub.add(filterText, "growx");
filterText.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void changedUpdate(DocumentEvent e) {
updateFilters();
}
+
@Override
public void insertUpdate(DocumentEvent e) {
updateFilters();
}
+
@Override
public void removeUpdate(DocumentEvent e) {
updateFilters();
}
});
- /*
- * Add filter by fore diameter
- */
- foreDiameterFilterCheckBox = new JCheckBox();
- foreDiameterFilterCheckBox.setText(trans.get("ComponentPresetChooserDialog.checkbox.filterForeDiameter"));
- panel.add(foreDiameterFilterCheckBox, "skip, span 2");
- foreDiameterFilterCheckBox.addItemListener( new ItemListener () {
- @Override
- public void itemStateChanged(ItemEvent e) {
- updateFilters();
- }
- });
-
- /* hide the fore diameter filter if it is not applicable */
- if ( foreDiameterColumnIndex < 0 || component.getPreviousComponent() == null ) {
- foreDiameterFilterCheckBox.setVisible(false);
- }
+ panel.add(sub, "growx, ay 0, gapright para");
- /*
- * Add filter by aft diameter
- */
- aftDiameterFilterCheckBox = new JCheckBox();
- aftDiameterFilterCheckBox.setText(trans.get("ComponentPresetChooserDialog.checkbox.filterAftDiameter"));
- panel.add(aftDiameterFilterCheckBox, "skip, span 2, wrap");
- aftDiameterFilterCheckBox.addItemListener( new ItemListener () {
- @Override
- public void itemStateChanged(ItemEvent e) {
- updateFilters();
- }
- });
-
- /* hide the aft diameter filter if it is not applicable */
- if ( aftDiameterColumnIndex < 0 || component.getNextComponent() == null ) {
- aftDiameterFilterCheckBox.setVisible(false);
- }
- componentSelectionTable = new JTable( tableModel );
+ panel.add(getFilterCheckboxes(), "wrap para");
+
+ componentSelectionTable = new ComponentPresetTable(presetType, presets, displayedColumnKeys);
+ // GUIUtil.setAutomaticColumnTableWidths(componentSelectionTable, 20);
+ int w = componentSelectionTable.getRowHeight() + 4;
+ TableColumn tc = componentSelectionTable.getColumnModel().getColumn(0);
+ tc.setPreferredWidth(w);
+ tc.setMaxWidth(w);
+ tc.setMinWidth(w);
- componentSelectionTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-
- sorter = new TableRowSorter<TableModel>(tableModel);
- componentSelectionTable.setRowSorter(sorter);
-
JScrollPane scrollpane = new JScrollPane();
scrollpane.setViewportView(componentSelectionTable);
- panel.add(scrollpane, "grow, width :500:, height :300:, spanx, wrap para");
-
+ panel.add(scrollpane, "grow, width 700lp, height 300lp, spanx, wrap para");
+
// OK / Cancel buttons
JButton okButton = new JButton(trans.get("dlg.but.ok"));
this.add(panel);
- this.setModal(true);
- this.pack();
- this.setLocationByPlatform(true);
+ GUIUtil.rememberWindowSize(this);
GUIUtil.setDisposableDialogOptions(this, okButton);
+ }
+
+
+ private JPanel getFilterCheckboxes() {
+ SymmetricComponent sc;
- //JComponent focus = selectionPanel.getDefaultFocus();
- //if (focus != null) {
- // focus.grabFocus();
- //}
+ JPanel panel = new JPanel(new MigLayout("fill, ins 0"));
- // Set the closeable dialog after all initialization
- //selectionPanel.setCloseableDialog(this);
+ /*
+ * Add show all compatible check box.
+ */
+ final List<ComponentPreset.Type> compatibleTypes = component.getPresetType().getCompatibleTypes();
+ final ComponentPreset.Type nativeType = component.getPresetType();
+ if (compatibleTypes != null && compatibleTypes.size() > 0) {
+ JCheckBox showAll = new JCheckBox();
+ showAll.setText(trans.get("ComponentPresetChooserDialog.checkbox.showAllCompatible"));
+ panel.add(showAll, "wrap");
+ showAll.addItemListener(new ItemListener() {
+ @Override
+ public void itemStateChanged(ItemEvent e) {
+ if (((JCheckBox) e.getItem()).isSelected()) {
+ presets = Application.getComponentPresetDao().listForTypes(compatibleTypes);
+ } else {
+ presets = Application.getComponentPresetDao().listForType(nativeType);
+ }
+ componentSelectionTable.updateData(presets);
+ }
+ });
+ }
+
+ /*
+ * Add filter by fore diameter
+ */
+ foreDiameterFilterCheckBox = new JCheckBox(trans.get("ComponentPresetChooserDialog.checkbox.filterForeDiameter"));
+ sc = getPreviousSymmetricComponent();
+ if (sc != null && foreDiameterColumnIndex >= 0) {
+ foreDiameterFilter = new ComponentPresetRowFilter(sc.getAftRadius() * 2.0, foreDiameterColumnIndex);
+ panel.add(foreDiameterFilterCheckBox, "wrap");
+ foreDiameterFilterCheckBox.addItemListener(new ItemListener() {
+ @Override
+ public void itemStateChanged(ItemEvent e) {
+ updateFilters();
+ }
+ });
+ }
+
+ /*
+ * Add filter by aft diameter
+ */
+ aftDiameterFilterCheckBox = new JCheckBox(trans.get("ComponentPresetChooserDialog.checkbox.filterAftDiameter"));
+ sc = getNextSymmetricComponent();
+ if (sc != null && aftDiameterColumnIndex >= 0) {
+ aftDiameterFilter = new ComponentPresetRowFilter(sc.getForeRadius() * 2.0, aftDiameterColumnIndex);
+ panel.add(aftDiameterFilterCheckBox, "wrap");
+ aftDiameterFilterCheckBox.addItemListener(new ItemListener() {
+ @Override
+ public void itemStateChanged(ItemEvent e) {
+ updateFilters();
+ }
+ });
+ }
+
+ return panel;
}
/**
if (!okClicked)
return null;
int row = componentSelectionTable.getSelectedRow();
+ if ( row < 0 ) {
+ // Nothing selected.
+ return null;
+ }
row = componentSelectionTable.convertRowIndexToModel(row);
return presets.get(row);
}
}
private void updateFilters() {
- List<RowFilter<TableModel,Object>> filters = new ArrayList<RowFilter<TableModel,Object>> (2);
+ List<RowFilter<TableModel, Object>> filters = new ArrayList<RowFilter<TableModel, Object>>(2);
String filterTextRegex = filterText.getText();
- if ( filterTextRegex != null ) {
+ if (filterTextRegex != null) {
try {
// The "(?iu)" magic turns on case insensitivity with unicode chars
- RowFilter<TableModel,Object> regexFilter = RowFilter.regexFilter("(?iu)"+filterTextRegex);
+ RowFilter<TableModel, Object> regexFilter = RowFilter.regexFilter("(?iu)" + filterTextRegex);
filters.add(regexFilter);
- } catch ( java.util.regex.PatternSyntaxException e ) {
+ } catch (java.util.regex.PatternSyntaxException e) {
}
}
- if ( aftDiameterFilterCheckBox.isSelected() ) {
- // FIXME - please verify this logic looks correct.
- // Grab the next component.
- // If this.component is an InternalComponent, then we want to filter the outer diameter field
- // against the next component's inner diameter.
- RocketComponent nextComponent = component.getNextComponent();
- if ( nextComponent != null && nextComponent instanceof SymmetricComponent ) {
- SymmetricComponent parent = (SymmetricComponent) nextComponent;
- double nextDiameter;
- if ( this.component instanceof InternalComponent ) {
- nextDiameter = parent.getInnerRadius(0) * 2.0;
- } else {
- nextDiameter = parent.getForeRadius() * 2.0;
- }
- RowFilter<TableModel,Object> outerDiameterFilter = new ComponentPresetRowFilter( nextDiameter, aftDiameterColumnIndex);
- filters.add(outerDiameterFilter);
+ if (aftDiameterFilterCheckBox.isSelected()) {
+ filters.add(aftDiameterFilter);
+ }
+ if (foreDiameterFilterCheckBox.isSelected()) {
+ filters.add(foreDiameterFilter);
+ }
+
+ componentSelectionTable.setRowFilter(RowFilter.andFilter(filters));
+ }
+
+
+ private SymmetricComponent getPreviousSymmetricComponent() {
+ RocketComponent c = component;
+ while (c != null) {
+ c = c.getPreviousComponent();
+ if (c instanceof SymmetricComponent) {
+ return (SymmetricComponent) c;
}
}
- if ( foreDiameterFilterCheckBox.isSelected() ) {
- // FIXME - please verify this logic looks correct.
- // Grab the previous component.
- // If this.component is an InternalComponent, then we want to filter the outer diameter field
- // against the previous component's inner diameter.
- RocketComponent previousComponent = component.getPreviousComponent();
- if ( previousComponent != null && previousComponent instanceof SymmetricComponent ) {
- SymmetricComponent parent = (SymmetricComponent) previousComponent;
- double previousDaimeter;
- if ( this.component instanceof InternalComponent ) {
- previousDaimeter = parent.getInnerRadius(parent.getLength()) * 2.0;
- } else {
- previousDaimeter = parent.getAftRadius() * 2.0;
- }
- RowFilter<TableModel,Object> outerDiameterFilter = new ComponentPresetRowFilter( previousDaimeter, foreDiameterColumnIndex);
- filters.add(outerDiameterFilter);
+ return null;
+ }
+
+
+ private SymmetricComponent getNextSymmetricComponent() {
+ RocketComponent c = component;
+ while (c != null) {
+ c = c.getNextComponent();
+ if (c instanceof SymmetricComponent) {
+ return (SymmetricComponent) c;
}
}
-
- sorter.setRowFilter( RowFilter.andFilter(filters) );
+ return null;
}
}