Updates and fixed to preset handling

This commit is contained in:
Sampo Niskanen 2012-04-01 19:16:25 +00:00
parent 6f465cd0a2
commit 70e7936454
12 changed files with 227 additions and 259 deletions

View File

@ -1,4 +1,4 @@
Manufacturer,PartNo,id(cm),od(cm),maxlength(cm)
Manufacturer,PartNo,InnerDiameter,OuterDiameter,Length
Semroc,BT-3,0.8865,0.9525,45.72
Semroc,BT-3H,0.8865,0.9525,7.62
Semroc,BT-3XW,0.8865,0.9525,3.81

1 Manufacturer PartNo id(cm) InnerDiameter od(cm) OuterDiameter maxlength(cm) Length
2 Semroc BT-3 0.8865 0.9525 45.72
3 Semroc BT-3H 0.8865 0.9525 7.62
4 Semroc BT-3XW 0.8865 0.9525 3.81

View File

@ -1587,3 +1587,7 @@ CustomFinImport.error.title = Error loading fin profile
CustomFinImport.error.badimage = Could not deduce fin shape from image.
CustomFinImport.description = The image will be converted internally to black and white image (black for the fin), so make sure you use a solid dark color for the fin, and white or a light color for the background. The fin must be touching the bottom of the image, which is the base of the fin.
PresetModel.lbl.select = Select preset:
PresetModel.lbl.database = From database...

View File

@ -8,26 +8,25 @@ import java.util.List;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.TypedKey;
import net.sf.openrocket.rocketcomponent.BodyTube;
import au.com.bytecode.opencsv.CSVReader;
public class PresetCSVReader {
private InputStream is;
private ColumnDefinition[] columns;
public PresetCSVReader( InputStream is ) {
public PresetCSVReader(InputStream is) {
this.is = is;
}
public List<ComponentPreset> parse() throws IOException {
List<ComponentPreset> templates = new ArrayList<ComponentPreset>();
InputStreamReader r = new InputStreamReader(is);
// Create the CSV reader. Use comma separator and double-quote escaping.
CSVReader reader = new CSVReader(r,',','"');
CSVReader reader = new CSVReader(r, ',', '"');
String[] headers = reader.readNext();
if (headers == null || headers.length == 0) {
@ -35,28 +34,28 @@ public class PresetCSVReader {
}
columns = new ColumnDefinition[headers.length];
for( int i = 0; i< headers.length; i++ ) {
for (int i = 0; i < headers.length; i++) {
String h = headers[i];
if( "Manufacturer".equals(h) ) {
if ("Manufacturer".equals(h)) {
columns[i] = new ColumnDefinition.Manufactuer();
} else if ( "PartNumber".equals(h) ) {
} else if ("PartNo".equals(h)) {
columns[i] = new ColumnDefinition.PartNumber();
} else if ( "Type".equals(h) ) {
} else if ("Type".equals(h)) {
columns[i] = new ColumnDefinition.Type();
} else {
TypedKey key = ComponentPreset.keyMap.get(h);
if ( key == null ) {
if (key == null) {
throw new RuntimeException("Invalid parameter key " + h + " in file");
}
columns[i] = new ColumnDefinition.Parameter( key );
columns[i] = new ColumnDefinition.Parameter(key);
}
}
String[] line;
while( (line = reader.readNext()) != null ) {
while ((line = reader.readNext()) != null) {
ComponentPreset preset = new ComponentPreset();
for( int i = 0; i< headers.length; i++ ) {
if ( i > line.length ) {
for (int i = 0; i < headers.length; i++) {
if (i > line.length) {
break;
}
String value = line[i];
@ -64,7 +63,7 @@ public class PresetCSVReader {
}
templates.add(preset);
}
return templates;
}

View File

@ -1,97 +0,0 @@
package net.sf.openrocket.gui.adaptors;
import java.util.List;
import javax.swing.AbstractListModel;
import javax.swing.ComboBoxModel;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.startup.Application;
public class BodyTubePresetModel extends AbstractListModel implements ComboBoxModel {
private final RocketComponent component;
private List<ComponentPreset> presets;
public BodyTubePresetModel(RocketComponent component) {
presets = Application.getDaos().getBodyTubePresetDao().listAll();
this.component = component;
}
public static class BodyTubePresetAdapter {
// If the ComponentPreset bt is null, then no preset is selected.
private ComponentPreset bt;
private BodyTubePresetAdapter( ComponentPreset bt ) {
this.bt = bt;
}
@Override
public String toString() {
if ( bt != null ) {
return bt.getManufacturer() + " " + bt.getPartNo();
} else {
return "";
}
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((bt == null) ? 0 : bt.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
// I don't know why the default equals generated by Eclipse does not work.
// instead of relying on bt.equals(other.bt), we have to compare the hashcodes of those objects.
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
BodyTubePresetAdapter other = (BodyTubePresetAdapter) obj;
if (bt == null) {
if (other.bt != null)
return false;
} else if (other.bt == null)
return false;
return bt.hashCode() == other.bt.hashCode();
}
}
@Override
public int getSize() {
return presets.size();
}
@Override
public Object getElementAt(int index) {
if ( index < 0 ) {
return null;
}
return new BodyTubePresetAdapter(presets.get(index));
}
@Override
public void setSelectedItem(Object anItem) {
BodyTubePresetAdapter selected = (BodyTubePresetAdapter) anItem;
if ( selected == null ) {
component.loadPreset(null);
} else {
component.loadPreset(selected.bt);
}
}
@Override
public Object getSelectedItem() {
ComponentPreset preset = (ComponentPreset) component.getPresetComponent();
if ( preset == null ) {
return null;
} else {
return new BodyTubePresetAdapter(preset);
}
}
}

View File

@ -0,0 +1,93 @@
package net.sf.openrocket.gui.adaptors;
import java.util.List;
import javax.swing.AbstractListModel;
import javax.swing.ComboBoxModel;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.logging.LogHelper;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.startup.Application;
public class PresetModel extends AbstractListModel implements ComboBoxModel, ComponentChangeListener {
private static final LogHelper log = Application.getLogger();
private static final Translator trans = Application.getTranslator();
private static final String SELECT_PRESET = trans.get("lbl.select");
private static final String SELECT_DATABASE = trans.get("lbl.database");
private final RocketComponent component;
private ComponentPreset previousPreset;
private final List<ComponentPreset> presets;
public PresetModel(RocketComponent component) {
// FIXME: Make generic for any component type
// FIXME: This should load only the user's favorites, NOT all presets
presets = Application.getDaos().getBodyTubePresetDao().listAll();
this.component = component;
previousPreset = component.getPresetComponent();
component.addComponentChangeListener(this);
}
@Override
public int getSize() {
return presets.size() + 2;
}
@Override
public Object getElementAt(int index) {
if (index == 0) {
return SELECT_PRESET;
}
if (index == getSize() - 1) {
return SELECT_DATABASE;
}
return presets.get(index - 1);
}
@Override
public void setSelectedItem(Object item) {
log.user("User selected preset item '" + item + "' for component " + component);
System.err.println("**** Setting item: " + item);
if (item == null) {
// FIXME: What to do?
} else if (item.equals(SELECT_PRESET)) {
component.clearPreset();
} else if (item.equals(SELECT_DATABASE)) {
// FIXME: Open database dialog
} else {
// FIXME: Add undo point here
component.loadPreset((ComponentPreset) item);
}
}
@Override
public Object getSelectedItem() {
ComponentPreset preset = component.getPresetComponent();
if (preset == null) {
return SELECT_PRESET;
} else {
return preset;
}
}
@Override
public void componentChanged(ComponentChangeEvent e) {
if (previousPreset != component.getPresetComponent()) {
previousPreset = component.getPresetComponent();
System.err.println("Firing event");
fireContentsChanged(this, 0, getSize());
}
}
// FIXME: Make model invalidatable
}

View File

@ -1,138 +1,120 @@
package net.sf.openrocket.gui.configdialog;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SwingUtilities;
import net.miginfocom.swing.MigLayout;
import net.sf.openrocket.document.OpenRocketDocument;
import net.sf.openrocket.gui.SpinnerEditor;
import net.sf.openrocket.gui.adaptors.BodyTubePresetModel;
import net.sf.openrocket.gui.adaptors.BooleanModel;
import net.sf.openrocket.gui.adaptors.DoubleModel;
import net.sf.openrocket.gui.adaptors.PresetModel;
import net.sf.openrocket.gui.components.BasicSlider;
import net.sf.openrocket.gui.components.UnitSelector;
import net.sf.openrocket.gui.dialogs.preset.ComponentPresetChooserDialog;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.rocketcomponent.BodyTube;
import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.unit.UnitGroup;
public class BodyTubeConfig extends RocketComponentConfig {
private ComponentChangeListener listener;
private MotorConfig motorConfigPane = null;
private DoubleModel maxLength;
private JComboBox presetComboBox;
private static final Translator trans = Application.getTranslator();
public BodyTubeConfig(OpenRocketDocument d, RocketComponent c) {
super(d, c);
JPanel panel = new JPanel(new MigLayout("gap rel unrel", "[][65lp::][30lp::][]", ""));
//// Body tube template
panel.add( new JLabel(trans.get("BodyTubecfg.lbl.Bodytubepreset")) );
presetComboBox = new JComboBox(new BodyTubePresetModel(component));
panel.add(presetComboBox);
{
JButton opendialog = new JButton("o");
opendialog.addActionListener(
new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ComponentPresetChooserDialog dialog = new ComponentPresetChooserDialog(SwingUtilities.getWindowAncestor(BodyTubeConfig.this));
dialog.setVisible(true);
ComponentPreset preset = dialog.getSelectedComponentPreset();
}
});
panel.add( opendialog, "wrap" );
}
// FIXME: Move to proper location
panel.add(new JLabel());
presetComboBox = new JComboBox(new PresetModel(component));
presetComboBox.setEditable(false);
panel.add(presetComboBox, "wrap para");
//// Body tube length
panel.add(new JLabel(trans.get("BodyTubecfg.lbl.Bodytubelength")));
maxLength = new DoubleModel(2.0);
DoubleModel length = new DoubleModel(component, "Length", UnitGroup.UNITS_LENGTH, 0);
JSpinner spin = new JSpinner(length.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
panel.add(spin, "growx");
panel.add(new UnitSelector(length), "growx");
panel.add(new BasicSlider(length.getSliderModel(0, 0.5, maxLength)), "w 100lp, wrap");
//// Body tube diameter
panel.add(new JLabel(trans.get("BodyTubecfg.lbl.Outerdiameter")));
DoubleModel od = new DoubleModel(component, "OuterRadius", 2, UnitGroup.UNITS_LENGTH, 0);
// Diameter = 2*Radius
spin = new JSpinner(od.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
panel.add(spin, "growx");
panel.add(new UnitSelector(od), "growx");
panel.add(new BasicSlider(od.getSliderModel(0, 0.04, 0.2)), "w 100lp, wrap 0px");
JCheckBox check = new JCheckBox(od.getAutomaticAction());
//// Automatic
check.setText(trans.get("BodyTubecfg.checkbox.Automatic"));
panel.add(check, "skip, span 2, wrap");
//// Inner diameter
panel.add(new JLabel(trans.get("BodyTubecfg.lbl.Innerdiameter")));
// Diameter = 2*Radius
DoubleModel m = new DoubleModel(component, "InnerRadius", 2, UnitGroup.UNITS_LENGTH, 0);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
panel.add(spin, "growx");
panel.add(new UnitSelector(m), "growx");
panel.add(new BasicSlider(m.getSliderModel(new DoubleModel(0), od)), "w 100lp, wrap");
//// Wall thickness
panel.add(new JLabel(trans.get("BodyTubecfg.lbl.Wallthickness")));
m = new DoubleModel(component, "Thickness", UnitGroup.UNITS_LENGTH, 0);
spin = new JSpinner(m.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
panel.add(spin, "growx");
panel.add(new UnitSelector(m), "growx");
panel.add(new BasicSlider(m.getSliderModel(0, 0.01)), "w 100lp, wrap 0px");
//// Filled
check = new JCheckBox(new BooleanModel(component, "Filled"));
check.setText(trans.get("BodyTubecfg.checkbox.Filled"));
panel.add(check, "skip, span 2, wrap");
//// Material
panel.add(materialPanel(new JPanel(new MigLayout()), Material.Type.BULK),
"cell 4 0, gapleft paragraph, aligny 0%, spany");
//// General and General properties
tabbedPane.insertTab(trans.get("BodyTubecfg.tab.General"), null, panel,
trans.get("BodyTubecfg.tab.Generalproperties"), 0);
@ -141,47 +123,17 @@ public class BodyTubeConfig extends RocketComponentConfig {
tabbedPane.insertTab(trans.get("BodyTubecfg.tab.Motor"), null, motorConfigPane,
trans.get("BodyTubecfg.tab.Motormountconf"), 1);
tabbedPane.setSelectedIndex(0);
// need to work in the max length for body tubes based on presets...
adjustPresetState();
listener = new ComponentChangeListener() {
@Override
public void componentChanged(ComponentChangeEvent e) {
adjustPresetState();
}
};
component.addChangeListener(listener);
}
@Override
public void updateFields() {
super.updateFields();
if (motorConfigPane != null)
motorConfigPane.updateFields();
}
@Override
public void invalidateModels() {
super.invalidateModels();
component.removeChangeListener(listener);
}
private void adjustPresetState() {
BodyTube bt = (BodyTube) component;
if ( bt.getPresetComponent() != null ) {
ComponentPreset btPreset = bt.getPresetComponent();
maxLength.setValue( btPreset.get(ComponentPreset.LENGTH) );
} else {
// here we should be able to force the preset combo box to display empty.
// We set the selected index to -1 (undefined), then force a repaint.
presetComboBox.setSelectedIndex(-1);
presetComboBox.repaint();
maxLength.setValue(2.0);
}
}
}

View File

@ -5,6 +5,7 @@ import java.util.Map;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.rocketcomponent.ExternalComponent.Finish;
import net.sf.openrocket.util.BugException;
/**
@ -15,26 +16,29 @@ import net.sf.openrocket.rocketcomponent.ExternalComponent.Finish;
*
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/
public class ComponentPreset extends TypedPropertyMap {
public class ComponentPreset {
private final Map<TypedKey<?>, Object> properties = new HashMap<TypedKey<?>, Object>();
// TODO - Implement clone.
// Implement "freezing" so the object cannot be modified.
public enum Type {
BodyTube,
NoseCone
BODY_TUBE,
NOSE_CONE
}
public final static TypedKey<Double> LENGTH = new TypedKey<Double>("Length", Double.class);
public final static TypedKey<Double> INNER_DIAMETER = new TypedKey<Double>("InnerDiameter", Double.class);
public final static TypedKey<Double> OUTER_DIAMETER = new TypedKey<Double>("OuterDiameter", Double.class);
public final static TypedKey<Material> MATERIAL = new TypedKey<Material>("Material", Material.class);
public final static TypedKey<Finish> FINISH = new TypedKey<Finish>("Finish",Finish.class);
public final static TypedKey<Finish> FINISH = new TypedKey<Finish>("Finish", Finish.class);
public final static TypedKey<Double> THICKNESS = new TypedKey<Double>("Thickness", Double.class);
public final static TypedKey<Boolean> FILLED = new TypedKey<Boolean>("Filled",Boolean.class);
public final static TypedKey<Boolean> FILLED = new TypedKey<Boolean>("Filled", Boolean.class);
public final static TypedKey<Double> MASS = new TypedKey<Double>("Mass", Double.class);
public final static Map<String,TypedKey<?>> keyMap = new HashMap<String,TypedKey<?>>();
public final static Map<String, TypedKey<?>> keyMap = new HashMap<String, TypedKey<?>>();
static {
keyMap.put(LENGTH.getName(), LENGTH);
keyMap.put(INNER_DIAMETER.getName(), INNER_DIAMETER);
@ -50,42 +54,65 @@ public class ComponentPreset extends TypedPropertyMap {
private String partNo;
private String partDescription;
private Type type;
public ComponentPreset() {
}
public String getManufacturer() {
return manufacturer;
}
public void setManufacturer(String manufacturer) {
this.manufacturer = manufacturer;
}
public String getPartNo() {
return partNo;
}
public void setPartNo(String partNo) {
this.partNo = partNo;
}
public String getPartDescription() {
return partDescription;
}
public void setPartDescription(String partDescription) {
this.partDescription = partDescription;
}
public Type getType() {
return type;
}
public void setType(Type type) {
this.type = type;
}
public boolean has(Object key) {
return properties.containsKey(key);
}
@SuppressWarnings("unchecked")
public <T> T get(TypedKey<T> key) {
Object value = properties.get(key);
if (value == null) {
throw new BugException("Preset of type " + type + " did not contain key " + key + " mfg=" + manufacturer + " partNo=" + partNo);
}
return (T) value;
}
@SuppressWarnings("unchecked")
public <T> T put(TypedKey<T> key, T value) {
return (T) properties.put(key, value);
}
@Override
public String toString() {
return partNo;
}
}

View File

@ -7,74 +7,64 @@ import java.util.Map.Entry;
import java.util.Set;
public class TypedPropertyMap {
private final Map<TypedKey<?>, Object> delegate;
public TypedPropertyMap() {
delegate = new LinkedHashMap<TypedKey<?>,Object>();
delegate = new LinkedHashMap<TypedKey<?>, Object>();
}
public int size() {
return delegate.size();
}
public boolean isEmpty() {
return delegate.isEmpty();
}
public boolean containsKey(Object key) {
return delegate.containsKey(key);
}
public boolean containsValue(Object value) {
return delegate.containsValue(value);
}
@SuppressWarnings("unchecked")
public <T> T get(TypedKey<T> key) {
return (T) delegate.get(key);
}
@SuppressWarnings("unchecked")
public <T> T put(TypedKey<T> key, T value) {
return (T) delegate.put(key, value);
}
public Object remove(Object key) {
return delegate.remove(key);
}
public void putAll(TypedPropertyMap other) {
if ( other == null ) {
if (other == null) {
return;
}
delegate.putAll(other.delegate);
}
public void clear() {
delegate.clear();
}
public Set<TypedKey<?>> keySet() {
return delegate.keySet();
}
public Collection<Object> values() {
return delegate.values();
}
public Set<Entry<TypedKey<?>, Object>> entrySet() {
return delegate.entrySet();
}
@Override
public boolean equals(Object o) {
return delegate.equals(o);
}
@Override
public int hashCode() {
return delegate.hashCode();
}
}

View File

@ -52,7 +52,7 @@ public abstract class BodyComponent extends ExternalComponent {
@Override
protected void loadFromPreset(ComponentPreset preset) {
if ( preset.containsKey(ComponentPreset.LENGTH) ) {
if ( preset.has(ComponentPreset.LENGTH) ) {
this.setLength(preset.get(ComponentPreset.LENGTH));
}

View File

@ -137,10 +137,10 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial
@Override
protected void loadFromPreset(ComponentPreset preset) {
this.autoRadius = false;
if ( preset.containsKey(ComponentPreset.OUTER_DIAMETER) ) {
if ( preset.has(ComponentPreset.OUTER_DIAMETER) ) {
double outerDiameter = preset.get(ComponentPreset.OUTER_DIAMETER);
this.outerRadius = outerDiameter/2.0;
if ( preset.containsKey(ComponentPreset.INNER_DIAMETER) ) {
if ( preset.has(ComponentPreset.INNER_DIAMETER) ) {
double innerDiameter = preset.get(ComponentPreset.INNER_DIAMETER);
this.thickness = (outerDiameter-innerDiameter) / 2.0;
}

View File

@ -134,7 +134,7 @@ public abstract class ExternalComponent extends RocketComponent {
// Surface finish is left unchanged
if ( preset.containsKey(ComponentPreset.MATERIAL ) ) {
if ( preset.has(ComponentPreset.MATERIAL ) ) {
Material mat = preset.get(ComponentPreset.MATERIAL);
if ( mat != null ) {
setMaterial(mat);

View File

@ -148,10 +148,10 @@ public abstract class SymmetricComponent extends BodyComponent implements Radial
@Override
protected void loadFromPreset(ComponentPreset preset) {
if ( preset.containsKey(ComponentPreset.THICKNESS) ) {
if ( preset.has(ComponentPreset.THICKNESS) ) {
this.setThickness(preset.get(ComponentPreset.THICKNESS));
}
if ( preset.containsKey(ComponentPreset.FILLED)) {
if ( preset.has(ComponentPreset.FILLED)) {
this.setFilled(preset.get(ComponentPreset.FILLED));
}