]> git.gag.com Git - debian/openrocket/commitdiff
Refactored preset GUI for unit of measure spinners; added launch lug, parachute,...
authorrodinia814 <rodinia814@180e2498-e6e9-4542-8430-84ac67f01cd8>
Thu, 10 May 2012 23:51:26 +0000 (23:51 +0000)
committerrodinia814 <rodinia814@180e2498-e6e9-4542-8430-84ac67f01cd8>
Thu, 10 May 2012 23:51:26 +0000 (23:51 +0000)
git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@664 180e2498-e6e9-4542-8430-84ac67f01cd8

core/src/net/sf/openrocket/gui/preset/ComponentPresetPanel.java
core/src/net/sf/openrocket/gui/preset/MaterialModel.java
core/src/net/sf/openrocket/gui/preset/PresetEditorDialog.java

index 1a34b3d4d0500b9961f7eef1777067a472796252..d1745145e48da8fdcfa2268d58c2eba359499124 100644 (file)
@@ -1,6 +1,5 @@
 package net.sf.openrocket.gui.preset;
 
-
 import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.gui.util.FileHelper;
 import net.sf.openrocket.gui.util.SwingPreferences;
@@ -11,7 +10,14 @@ import net.sf.openrocket.preset.ComponentPreset;
 import net.sf.openrocket.preset.xml.OpenRocketComponentSaver;
 import net.sf.openrocket.startup.Application;
 
-import javax.swing.*;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.SwingConstants;
 import javax.swing.table.DefaultTableModel;
 import javax.xml.bind.JAXBException;
 import java.awt.event.ActionEvent;
@@ -25,28 +31,40 @@ import java.util.List;
 
 /**
  * A UI for editing component presets.  Currently this is a standalone application - run the main within this class.
- * TODO: Full I18n
- * TODO: Delete component
- * TODO: Open .orc for editing
- * TODO: Import .csv
- * TODO: Export .csv
- * TODO: proper mass unit conversion
+ * TODO: Full I18n TODO: Delete component TODO: Open .orc for editing TODO: Import .csv TODO: Export .csv TODO: Menu
  */
 public class ComponentPresetPanel extends JPanel implements PresetResultListener {
 
+    /**
+     * The logger.
+     */
     private static final LogHelper log = Application.getLogger();
 
+    /**
+     * The I18N translator.
+     */
     private static ResourceBundleTranslator trans = null;
 
+    /**
+     * The table of presets.
+     */
+    private JTable table;
+
+    /**
+     * The table's data model.
+     */
+    private DataTableModel model;
+
+    /**
+     * Flag that indicates if an existing Preset is currently being edited.
+     */
+    private boolean editingSelected = false;
+
     static {
         trans = new ResourceBundleTranslator("l10n.messages");
         net.sf.openrocket.startup.Application.setBaseTranslator(trans);
     }
 
-    private JTable table;
-    private DataTableModel model;
-    private boolean editingSelected = false;
-
     /**
      * Create the panel.
      */
@@ -113,15 +131,23 @@ public class ComponentPresetPanel extends JPanel implements PresetResultListener
 
     }
 
+    /**
+     * Callback method from the PresetEditorDialog to notify this class when a preset has been saved.  The 'save' is
+     * really just a call back here so the preset can be added to the master table.  It's not to be confused with the
+     * save to disk.
+     *
+     * @param preset the new or modified preset
+     */
     @Override
     public void notifyResult(final ComponentPreset preset) {
         if (preset != null) {
             DataTableModel model = (DataTableModel) table.getModel();
+            //Is this a new preset?
             if (!editingSelected) {
-                model.addRow(new String[]{preset.getManufacturer().getDisplayName(), preset.getType().name(), preset.getPartNo(), preset.get(ComponentPreset.DESCRIPTION)},
-                        preset);
+                model.addRow(new String[]{preset.getManufacturer().getDisplayName(), preset.getType().name(), preset.getPartNo(), preset.get(ComponentPreset.DESCRIPTION)}, preset);
             }
             else {
+                //This is a modified preset; update all of the columns and the stored associated instance.
                 int row = table.getSelectedRow();
                 model.setValueAt(preset.getManufacturer().getDisplayName(), row, 0);
                 model.setValueAt(preset.getType().name(), row, 1);
@@ -150,6 +176,9 @@ public class ComponentPresetPanel extends JPanel implements PresetResultListener
         }
     }
 
+    /**
+     * A table model that adds associated objects to each row, allowing for easy retrieval.
+     */
     class DataTableModel extends DefaultTableModel {
 
         private List<Object> associated = new ArrayList<Object>();
@@ -216,8 +245,8 @@ public class ComponentPresetPanel extends JPanel implements PresetResultListener
         List<Material> materials = new ArrayList<Material>();
         List<ComponentPreset> presets = new ArrayList<ComponentPreset>();
 
-        for (int x = 0; x< model.getRowCount(); x++) {
-            ComponentPreset preset = (ComponentPreset)model.getAssociatedObject(x);
+        for (int x = 0; x < model.getRowCount(); x++) {
+            ComponentPreset preset = (ComponentPreset) model.getAssociatedObject(x);
             if (!materials.contains(preset.get(ComponentPreset.MATERIAL))) {
                 materials.add(preset.get(ComponentPreset.MATERIAL));
             }
index a80e6847e0e975777c54765ed42e754786ca4d84..a58370ac9a3d18bfa4ad6c588f4a0b88a86df07c 100644 (file)
@@ -8,8 +8,9 @@ import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.material.Material;
 import net.sf.openrocket.startup.Application;
 
-import javax.swing.*;
-import java.awt.*;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.SwingUtilities;
+import java.awt.Component;
 
 /**
  * A material model specifically for presets.
@@ -22,9 +23,13 @@ public class MaterialModel extends DefaultComboBoxModel implements DatabaseListe
 
     private static final Translator trans = Application.getTranslator();
 
+    private Material.Type type;
+
     private Component parent;
+
     public MaterialModel(Component theParent, Material.Type type) {
         parent = theParent;
+        this.type = type;
 
         switch (type) {
             case LINE:
@@ -59,9 +64,7 @@ public class MaterialModel extends DefaultComboBoxModel implements DatabaseListe
             SwingUtilities.invokeLater(new Runnable() {
                 @Override
                 public void run() {
-                    CustomMaterialDialog dialog = new CustomMaterialDialog(
-                            SwingUtilities.getWindowAncestor(parent),
-                            (Material) getSelectedItem(), true,
+                    CustomMaterialDialog dialog = new CustomMaterialDialog(SwingUtilities.getWindowAncestor(parent), (Material) getSelectedItem(), true,
                             //// Define custom material
                             trans.get("MaterialModel.title.Defcustmat"));
 
@@ -117,4 +120,7 @@ public class MaterialModel extends DefaultComboBoxModel implements DatabaseListe
         this.fireContentsChanged(this, 0, database.size());
     }
 
+    public Material.Type getType() {
+        return type;
+    }
 }
index 82f496947613cba8ada2a875af3603f4ef25d241..80188505acd9ca7093913bf35df3f372110c752f 100644 (file)
@@ -1,7 +1,9 @@
 package net.sf.openrocket.gui.preset;
 
 import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.gui.print.PrintUnit;
+import net.sf.openrocket.gui.SpinnerEditor;
+import net.sf.openrocket.gui.adaptors.DoubleModel;
+import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.material.Material;
@@ -12,13 +14,32 @@ import net.sf.openrocket.preset.InvalidComponentPresetException;
 import net.sf.openrocket.preset.TypedPropertyMap;
 import net.sf.openrocket.rocketcomponent.Transition;
 import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.unit.UnitGroup;
 
 import javax.imageio.ImageIO;
-import javax.swing.*;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.ImageIcon;
+import javax.swing.InputVerifier;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JSpinner;
+import javax.swing.JTextField;
 import javax.swing.border.EmptyBorder;
 import javax.swing.filechooser.FileFilter;
 import javax.swing.text.JTextComponent;
-import java.awt.*;
+import java.awt.BorderLayout;
+import java.awt.CardLayout;
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Rectangle;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.ItemEvent;
@@ -32,6 +53,7 @@ import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -42,43 +64,40 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
 
     private static LogHelper log = Application.getLogger();
 
-    private static final String NON_NEGATIVE_DECIMAL_FIELD = "(\\d){1,10}\\.(\\d){1,10}";
+    private static final String NON_NEGATIVE_INTEGER_FIELD = "(\\d){0,10}";
 
     /**
      * Input of non-negative decimals.
      */
-    final PresetInputVerifier NON_NEGATIVE_DECIMAL =
-            new PresetInputVerifier(Pattern.compile(NON_NEGATIVE_DECIMAL_FIELD));
+    final PresetInputVerifier NON_NEGATIVE_INTEGER = new PresetInputVerifier(Pattern.compile(NON_NEGATIVE_INTEGER_FIELD));
 
     private final JPanel contentPanel = new JPanel();
     private DeselectableComboBox typeCombo;
     private JTextField mfgTextField;
     private JComboBox materialChooser;
-    private JComboBox massUnitCombo;
-    private JComboBox lenUnitCombo;
 
     private JTextField ncPartNoTextField;
     private JTextField ncDescTextField;
-    private JTextField ncLengthTextField;
+    private DoubleModel ncLength;
     private JCheckBox ncFilledCB;
     private JComboBox ncShapeCB;
-    private JTextField ncAftDiaTextField;
-    private JTextField ncAftShoulderDiaTextField;
-    private JTextField ncAftShoulderLenTextField;
-    private JTextField ncMassTextField;
+    private DoubleModel ncAftDia;
+    private DoubleModel ncAftShoulderDia;
+    private DoubleModel ncAftShoulderLen;
+    private DoubleModel ncMass;
     private ImageIcon ncImage;
     private JButton ncImageBtn;
 
     private JTextField trPartNoTextField;
     private JTextField trDescTextField;
-    private JTextField trLengthTextField;
-    private JTextField trAftDiaTextField;
-    private JTextField trAftShoulderDiaTextField;
-    private JTextField trAftShoulderLenTextField;
-    private JTextField trForeDiaTextField;
-    private JTextField trForeShoulderDiaTextField;
-    private JTextField trForeShoulderLenTextField;
-    private JTextField trMassTextField;
+    private DoubleModel trLength;
+    private DoubleModel trAftDia;
+    private DoubleModel trAftShoulderDia;
+    private DoubleModel trAftShoulderLen;
+    private DoubleModel trForeDia;
+    private DoubleModel trForeShoulderDia;
+    private DoubleModel trForeShoulderLen;
+    private DoubleModel trMass;
     private ImageIcon trImage;
     private JCheckBox trFilledCB;
     private JComboBox trShapeCB;
@@ -86,48 +105,77 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
 
     private JTextField btPartNoTextField;
     private JTextField btDescTextField;
-    private JTextField btMassTextField;
-    private JTextField btInnerDiaTextField;
-    private JTextField btOuterDiaTextField;
-    private JTextField btLengthTextField;
+    private DoubleModel btMass;
+    private DoubleModel btInnerDia;
+    private DoubleModel btOuterDia;
+    private DoubleModel btLength;
     private ImageIcon btImage;
     private JButton btImageBtn;
 
     private JTextField tcPartNoTextField;
     private JTextField tcDescTextField;
-    private JTextField tcMassTextField;
-    private JTextField tcInnerDiaTextField;
-    private JTextField tcOuterDiaTextField;
-    private JTextField tcLengthTextField;
+    private DoubleModel tcMass;
+    private DoubleModel tcInnerDia;
+    private DoubleModel tcOuterDia;
+    private DoubleModel tcLength;
     private ImageIcon tcImage;
     private JButton tcImageBtn;
 
     private JTextField bhPartNoTextField;
     private JTextField bhDescTextField;
-    private JTextField bhOuterDiaTextField;
-    private JTextField bhLengthTextField;
-    private JTextField bhMassTextField;
+    private DoubleModel bhOuterDia;
+    private DoubleModel bhLength;
+    private DoubleModel bhMass;
     private ImageIcon bhImage;
     private JButton bhImageBtn;
 
     private JTextField crPartNoTextField;
     private JTextField crDescTextField;
-    private JTextField crOuterDiaTextField;
-    private JTextField crInnerDiaTextField;
-    private JTextField crThicknessTextField;
-    private JTextField crMassTextField;
+    private DoubleModel crOuterDia;
+    private DoubleModel crInnerDia;
+    private DoubleModel crThickness;
+    private DoubleModel crMass;
     private ImageIcon crImage;
     private JButton crImageBtn;
 
     private JTextField ebPartNoTextField;
     private JTextField ebDescTextField;
-    private JTextField ebOuterDiaTextField;
-    private JTextField ebInnerDiaTextField;
-    private JTextField ebThicknessTextField;
-    private JTextField ebMassTextField;
+    private DoubleModel ebOuterDia;
+    private DoubleModel ebInnerDia;
+    private DoubleModel ebThickness;
+    private DoubleModel ebMass;
     private ImageIcon ebImage;
     private JButton ebImageBtn;
 
+    private JTextField llPartNoTextField;
+    private JTextField llDescTextField;
+    private DoubleModel llOuterDia;
+    private DoubleModel llInnerDia;
+    private DoubleModel llLength;
+    private DoubleModel llMass;
+    private ImageIcon llImage;
+    private JButton llImageBtn;
+
+    private JTextField stPartNoTextField;
+    private JTextField stDescTextField;
+    private DoubleModel stThickness;
+    private DoubleModel stWidth;
+    private DoubleModel stLength;
+    private DoubleModel stMass;
+    private ImageIcon stImage;
+    private JButton stImageBtn;
+
+    private JTextField pcPartNoTextField;
+    private JTextField pcDescTextField;
+    private JTextField pcSides;
+    private JTextField pcLineCount;
+    private DoubleModel pcDiameter;
+    private DoubleModel pcLineLength;
+    private JComboBox pcLineMaterialChooser;
+    private DoubleModel pcMass;
+    private ImageIcon pcImage;
+    private JButton pcImageBtn;
+
     private final JFileChooser imageChooser = createImageChooser();
 
     private JPanel componentOverlayPanel;
@@ -135,7 +183,6 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
     private PresetResultListener resultListener;
 
     private static Map<String, String> componentMap = new HashMap<String, String>();
-    private static Map<String, PrintUnit> lengthMap = new HashMap<String, PrintUnit>();
 
     private static final String NOSE_CONE_KEY = "NoseCone.NoseCone";
     private static final String BODY_TUBE_KEY = "BodyTube.BodyTube";
@@ -144,6 +191,9 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
     private static final String CR_KEY = "ComponentIcons.Centeringring";
     private static final String BULKHEAD_KEY = "Bulkhead.Bulkhead";
     private static final String EB_KEY = "ComponentIcons.Engineblock";
+    private static final String LAUNCH_LUG_KEY = "ComponentIcons.Launchlug";
+    private static final String STREAMER_KEY = "ComponentIcons.Streamer";
+    private static final String PARACHUTE_KEY = "ComponentIcons.Parachute";
 
 
     static {
@@ -154,12 +204,9 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
         componentMap.put(trans.get(CR_KEY), "CENTERINGRING");
         componentMap.put(trans.get(BULKHEAD_KEY), "BULKHEAD");
         componentMap.put(trans.get(EB_KEY), "ENGINEBLOCK");
-
-        lengthMap.put("m", PrintUnit.METERS);
-        lengthMap.put("cm", PrintUnit.CENTIMETERS);
-        lengthMap.put("mm", PrintUnit.MILLIMETERS);
-        lengthMap.put("in", PrintUnit.INCHES);
-        lengthMap.put("ft", PrintUnit.FOOT);
+        componentMap.put(trans.get(LAUNCH_LUG_KEY), "LAUNCHLUG");
+        componentMap.put(trans.get(PARACHUTE_KEY), "PARACHUTE");
+        componentMap.put(trans.get(STREAMER_KEY), "STREAMER");
     }
 
     /**
@@ -180,7 +227,7 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
     public PresetEditorDialog(PresetResultListener theCallback, ComponentPreset toEdit) {
         resultListener = theCallback;
         getContentPane().setMinimumSize(new Dimension(200, 200));
-        setBounds(100, 100, 720, 610);
+        setBounds(100, 100, 825, 610);
         getContentPane().setLayout(new BorderLayout());
         contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
         getContentPane().add(contentPanel, BorderLayout.CENTER);
@@ -192,13 +239,6 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
         contentPanel.add(mfgTextField, "cell 3 0,growx");
         mfgTextField.setColumns(10);
 
-        JLabel lenUnitLabel = new JLabel("Length Unit:");
-        contentPanel.add(lenUnitLabel, "cell 4 0,alignx left,aligny center");
-
-        lenUnitCombo = new JComboBox();
-        lenUnitCombo.setModel(new DefaultComboBoxModel(new String[]{"m", "cm", "mm", "in", "ft"}));
-        contentPanel.add(lenUnitCombo, "cell 5 0,growx");
-
         JLabel typeLabel = new JLabel("Type:");
         contentPanel.add(typeLabel, "cell 2 1,alignx left,aligny center");
 
@@ -212,23 +252,17 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
         setItems(typeCombo, toEdit);
         contentPanel.add(typeCombo, "cell 3 1,growx");
 
-        JLabel massUnitLabel = new JLabel("Mass Unit:");
-        contentPanel.add(massUnitLabel, "cell 4 1,alignx left,aligny center");
-
-        massUnitCombo = new JComboBox();
-        massUnitCombo.setModel(new DefaultComboBoxModel(new String[]{"kg", "g", "oz", "lb"}));
-        contentPanel.add(massUnitCombo, "cell 5 1,growx");
-
         JLabel bhMaterialLabel = new JLabel("Material:");
         contentPanel.add(bhMaterialLabel, "cell 2 2, alignx left");
 
         materialChooser = new JComboBox(new MaterialModel(this, Material.Type.BULK));
+
         contentPanel.add(materialChooser, "cell 3 2,growx");
 
         {
             JPanel ncPanel = new JPanel();
             componentOverlayPanel.add(ncPanel, "NOSECONE");
-            ncPanel.setLayout(new MigLayout("", "[61px][159.00,grow][35.00][109.00,grow][189.00,grow][grow]", "[16px][][][][][]"));
+            ncPanel.setLayout(new MigLayout("", "[61px][159.00,grow][45.00][109.00,grow][189.00,grow][grow]", "[16px][][][][][]"));
             JLabel ncPartNoLabel = new JLabel("Part No:");
             ncPanel.add(ncPartNoLabel, "cell 0 0,alignx left,aligny center");
 
@@ -246,57 +280,60 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
             ncFilledCB = new JCheckBox("Filled");
             ncPanel.add(ncFilledCB, "cell 1 1");
 
-            JLabel ncMaterialLabel = new JLabel("Material:");
+            JLabel ncMaterialLabel = new JLabel(trans.get("RocketCompCfg.lbl.Componentmaterial"));
             ncPanel.add(ncMaterialLabel, "cell 0 1,alignx left");
 
-            JLabel ncMassLabel = new JLabel("Mass:");
+            JLabel ncMassLabel = new JLabel(trans.get("RocketCompCfg.lbl.Componentmass"));
             ncPanel.add(ncMassLabel, "cell 3 1,alignx left");
 
-            ncMassTextField = new JTextField();
-            ncMassTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            ncPanel.add(ncMassTextField, "cell 4 1,growx");
-            ncMassTextField.setColumns(10);
+            ncMass = new DoubleModel(0, UnitGroup.UNITS_MASS, 0);
+            JSpinner spin = new JSpinner(ncMass.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            ncPanel.add(spin, "cell 4 1, growx");
+            ncPanel.add(new UnitSelector(ncMass), "growx");
 
-            JLabel ncShapeLabel = new JLabel("Shape:");
+            JLabel ncShapeLabel = new JLabel(trans.get("NoseConeCfg.lbl.Noseconeshape"));
             ncPanel.add(ncShapeLabel, "cell 0 2,alignx left");
 
             ncShapeCB = new JComboBox();
-            ncShapeCB.setModel(new DefaultComboBoxModel(new String[]{Transition.Shape.OGIVE.getName(),
-                    Transition.Shape.CONICAL.getName(), Transition.Shape.PARABOLIC.getName(),
-                    Transition.Shape.ELLIPSOID.getName(), Transition.Shape.HAACK.getName()}));
+            ncShapeCB.setModel(new DefaultComboBoxModel(new String[]{Transition.Shape.OGIVE.getName(), Transition.Shape.CONICAL.getName(), Transition.Shape.PARABOLIC.getName(), Transition.Shape.ELLIPSOID.getName(), Transition.Shape.HAACK.getName()}));
             ncPanel.add(ncShapeCB, "cell 1 2,growx");
 
-            JLabel ncLengthLabel = new JLabel("Length:");
+            JLabel ncLengthLabel = new JLabel(trans.get("NoseConeCfg.lbl.Noseconelength"));
             ncPanel.add(ncLengthLabel, "cell 3 2,alignx left");
 
-            ncLengthTextField = new JTextField();
-            ncLengthTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            ncPanel.add(ncLengthTextField, "cell 4 2,growx");
-            ncLengthTextField.setColumns(10);
+            ncLength = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0, 2);
+            spin = new JSpinner(ncLength.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            ncPanel.add(spin, "cell 4 2, growx");
+            ncPanel.add(new UnitSelector(ncLength), "growx");
 
             JLabel ncAftDiaLabel = new JLabel("Aft Dia.:");
-            ncPanel.add(ncAftDiaLabel, "cell 0 3,alignx left, aligny top");
+            ncPanel.add(ncAftDiaLabel, "cell 0 3,alignx left");
 
-            ncAftDiaTextField = new JTextField();
-            ncAftDiaTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            ncPanel.add(ncAftDiaTextField, "cell 1 3,growx, aligny top");
-            ncAftDiaTextField.setColumns(10);
+            ncAftDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0, 2);
+            spin = new JSpinner(ncAftDia.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            ncPanel.add(spin, "cell 1 3, growx");
+            ncPanel.add(new UnitSelector(ncAftDia), "growx");
 
             JLabel ncAftShoulderLenLabel = new JLabel("Aft Shoulder Len:");
-            ncPanel.add(ncAftShoulderLenLabel, "cell 0 4,alignx left, aligny top");
+            ncPanel.add(ncAftShoulderLenLabel, "cell 0 4,alignx left");
 
-            ncAftShoulderLenTextField = new JTextField();
-            ncAftShoulderLenTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            ncPanel.add(ncAftShoulderLenTextField, "cell 1 4,growx,aligny top");
-            ncAftShoulderLenTextField.setColumns(10);
+            ncAftShoulderLen = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0, 2);
+            spin = new JSpinner(ncAftShoulderLen.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            ncPanel.add(spin, "cell 1 4, growx");
+            ncPanel.add(new UnitSelector(ncAftShoulderLen), "growx");
 
             JLabel ncAftShoulderDiaLabel = new JLabel("Aft Shoulder Dia.:");
-            ncPanel.add(ncAftShoulderDiaLabel, "cell 0 5,alignx left, aligny top");
+            ncPanel.add(ncAftShoulderDiaLabel, "cell 0 5,alignx left, aligny top, pad 7 0 0 0");
 
-            ncAftShoulderDiaTextField = new JTextField();
-            ncAftShoulderDiaTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            ncPanel.add(ncAftShoulderDiaTextField, "cell 1 5,growx, aligny top");
-            ncAftShoulderDiaTextField.setColumns(10);
+            ncAftShoulderDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0, 2);
+            spin = new JSpinner(ncAftShoulderDia.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            ncPanel.add(spin, "cell 1 5, growx, aligny top");
+            ncPanel.add(new UnitSelector(ncAftShoulderDia), "growx, aligny top, pad 7 0 0 0");
 
             JPanel panel = new JPanel();
             panel.setMinimumSize(new Dimension(200, 200));
@@ -325,7 +362,7 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
         {
             JPanel trPanel = new JPanel();
             componentOverlayPanel.add(trPanel, "TRANSITION");
-            trPanel.setLayout(new MigLayout("", "[][grow][][grow]", "[][][28.00][31.00][][]"));
+            trPanel.setLayout(new MigLayout("", "[61px][159.00,grow][45.00][109.00,grow][189.00,grow][grow]", "[16px][][][][][]"));
 
             JLabel trPartNoLabel = new JLabel("Part No:");
             trPanel.add(trPartNoLabel, "cell 0 0,alignx left");
@@ -335,91 +372,97 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
             trPartNoTextField.setColumns(10);
 
             JLabel trDescLabel = new JLabel("Description:");
-            trPanel.add(trDescLabel, "cell 2 0,alignx left");
+            trPanel.add(trDescLabel, "cell 3 0,alignx left");
 
             trDescTextField = new JTextField();
-            trPanel.add(trDescTextField, "cell 3 0,growx");
+            trPanel.add(trDescTextField, "cell 4 0,growx");
             trDescTextField.setColumns(10);
 
             trFilledCB = new JCheckBox("Filled");
             trPanel.add(trFilledCB, "cell 1 1");
 
             JLabel trMassLabel = new JLabel("Mass:");
-            trPanel.add(trMassLabel, "cell 2 1,alignx left");
+            trPanel.add(trMassLabel, "cell 3 1,alignx left");
 
-            trMassTextField = new JTextField();
-            trMassTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            trPanel.add(trMassTextField, "cell 3 1,growx");
-            trMassTextField.setColumns(10);
+            trMass = new DoubleModel(0, UnitGroup.UNITS_MASS, 0);
+            JSpinner spin = new JSpinner(trMass.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            trPanel.add(spin, "cell 4 1, growx");
+            trPanel.add(new UnitSelector(trMass), "growx");
 
             JLabel trShapeLabel = new JLabel("Shape:");
             trPanel.add(trShapeLabel, "cell 0 2,alignx left");
 
             trShapeCB = new JComboBox();
-            trShapeCB.setModel(new DefaultComboBoxModel(new String[]{Transition.Shape.OGIVE.getName(),
-                    Transition.Shape.CONICAL.getName(), Transition.Shape.PARABOLIC.getName(),
-                    Transition.Shape.ELLIPSOID.getName(), Transition.Shape.HAACK.getName()}));
+            trShapeCB.setModel(new DefaultComboBoxModel(new String[]{Transition.Shape.OGIVE.getName(), Transition.Shape.CONICAL.getName(), Transition.Shape.PARABOLIC.getName(), Transition.Shape.ELLIPSOID.getName(), Transition.Shape.HAACK.getName()}));
             trPanel.add(trShapeCB, "cell 1 2,growx");
 
             JLabel trLengthLabel = new JLabel("Length:");
-            trPanel.add(trLengthLabel, "cell 2 2,alignx left");
+            trPanel.add(trLengthLabel, "cell 3 2,alignx left");
 
-            trLengthTextField = new JTextField();
-            trLengthTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            trPanel.add(trLengthTextField, "cell 3 2,growx");
-            trLengthTextField.setColumns(10);
+            trLength = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0, 2);
+            spin = new JSpinner(trLength.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            trPanel.add(spin, "cell 4 2, growx");
+            trPanel.add(new UnitSelector(trLength), "growx");
 
             JLabel trAftDiaLabel = new JLabel("Aft Dia.:");
             trPanel.add(trAftDiaLabel, "cell 0 3,alignx left");
 
-            trAftDiaTextField = new JTextField();
-            trAftDiaTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            trPanel.add(trAftDiaTextField, "cell 1 3,growx");
-            trAftDiaTextField.setColumns(10);
+            trAftDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0, 2);
+            spin = new JSpinner(trAftDia.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            trPanel.add(spin, "cell 1 3, growx");
+            trPanel.add(new UnitSelector(trAftDia));
 
             JLabel trForeDiaLabel = new JLabel("Fore Dia.:");
-            trPanel.add(trForeDiaLabel, "cell 2 3,alignx left");
+            trPanel.add(trForeDiaLabel, "cell 3 3,alignx left");
 
-            trForeDiaTextField = new JTextField();
-            trForeDiaTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            trPanel.add(trForeDiaTextField, "cell 3 3,growx");
-            trForeDiaTextField.setColumns(10);
+            trForeDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0, 2);
+            spin = new JSpinner(trForeDia.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            trPanel.add(spin, "cell 4 3, growx");
+            trPanel.add(new UnitSelector(trForeDia), "growx");
 
             JLabel trAftShouldDiaLabel = new JLabel("Aft Shoulder Dia.:");
             trPanel.add(trAftShouldDiaLabel, "cell 0 4,alignx left");
 
-            trAftShoulderDiaTextField = new JTextField();
-            trAftShoulderDiaTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            trPanel.add(trAftShoulderDiaTextField, "cell 1 4,growx");
-            trAftShoulderDiaTextField.setColumns(10);
+            trAftShoulderDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0, 2);
+            spin = new JSpinner(trAftShoulderDia.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            trPanel.add(spin, "cell 1 4, growx");
+            trPanel.add(new UnitSelector(trAftShoulderDia), "growx");
 
             JLabel trForeShouldDiaLabel = new JLabel("Fore Shoulder Dia.:");
-            trPanel.add(trForeShouldDiaLabel, "cell 2 4,alignx left");
+            trPanel.add(trForeShouldDiaLabel, "cell 3 4,alignx left");
 
-            trForeShoulderDiaTextField = new JTextField();
-            trForeShoulderDiaTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            trPanel.add(trForeShoulderDiaTextField, "cell 3 4,growx");
-            trForeShoulderDiaTextField.setColumns(10);
+            trForeShoulderDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0, 2);
+            spin = new JSpinner(trForeShoulderDia.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            trPanel.add(spin, "cell 4 4, growx");
+            trPanel.add(new UnitSelector(trForeShoulderDia), "growx");
 
             JLabel trAftShoulderLenLabel = new JLabel("Aft Shoulder Len.:");
             trPanel.add(trAftShoulderLenLabel, "cell 0 5,alignx left");
 
-            trAftShoulderLenTextField = new JTextField();
-            trAftShoulderLenTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            trPanel.add(trAftShoulderLenTextField, "cell 1 5,growx");
-            trAftShoulderLenTextField.setColumns(10);
+            trAftShoulderLen = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0, 2);
+            spin = new JSpinner(trAftShoulderLen.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            trPanel.add(spin, "cell 1 5, growx");
+            trPanel.add(new UnitSelector(trAftShoulderLen), "growx");
 
             JLabel lblForeShoulderLen = new JLabel("Fore Shoulder Len.:");
-            trPanel.add(lblForeShoulderLen, "cell 2 5,alignx left");
+            trPanel.add(lblForeShoulderLen, "cell 3 5,alignx left");
 
-            trForeShoulderLenTextField = new JTextField();
-            trForeShoulderLenTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            trPanel.add(trForeShoulderLenTextField, "cell 3 5,growx");
-            trForeShoulderLenTextField.setColumns(10);
+            trForeShoulderLen = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0, 2);
+            spin = new JSpinner(trForeShoulderLen.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            trPanel.add(spin, "cell 4 5, growx");
+            trPanel.add(new UnitSelector(trForeShoulderLen), "growx");
 
             JPanel panel = new JPanel();
             panel.setMinimumSize(new Dimension(200, 200));
-            trPanel.add(panel, "cell 3 6");
+            trPanel.add(panel, "cell 4 6");
             panel.setLayout(null);
             trImageBtn = new JButton("No Image");
             trImageBtn.setMaximumSize(new Dimension(75, 75));
@@ -453,47 +496,51 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
             btPartNoTextField.setColumns(10);
 
             JLabel btDescLabel = new JLabel("Description:");
-            btPanel.add(btDescLabel, "cell 2 0,alignx left");
+            btPanel.add(btDescLabel, "cell 3 0,alignx left");
 
             btDescTextField = new JTextField();
-            btPanel.add(btDescTextField, "cell 3 0,growx");
+            btPanel.add(btDescTextField, "cell 4 0,growx");
             btDescTextField.setColumns(10);
 
+            JLabel btLengthLabel = new JLabel("Length:");
+            btPanel.add(btLengthLabel, "cell 0 1,alignx left");
+
+            btLength = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+            JSpinner spin = new JSpinner(btLength.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            btPanel.add(spin, "cell 1 1, growx");
+            btPanel.add(new UnitSelector(btLength), "growx");
+
             JLabel btMassLabel = new JLabel("Mass:");
-            btPanel.add(btMassLabel, "cell 2 1,alignx left");
+            btPanel.add(btMassLabel, "cell 3 1,alignx left");
 
-            btMassTextField = new JTextField();
-            btMassTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            btPanel.add(btMassTextField, "cell 3 1,growx");
-            btMassTextField.setColumns(10);
+            btMass = new DoubleModel(0, UnitGroup.UNITS_MASS, 0);
+            spin = new JSpinner(btMass.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            btPanel.add(spin, "cell 4 1, growx");
+            btPanel.add(new UnitSelector(btMass), "growx");
 
             JLabel btInnerDiaLabel = new JLabel("Inner Dia.:");
             btPanel.add(btInnerDiaLabel, "cell 0 2,alignx left");
 
-            btInnerDiaTextField = new JTextField();
-            btInnerDiaTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            btPanel.add(btInnerDiaTextField, "cell 1 2,growx");
-            btInnerDiaTextField.setColumns(10);
+            btInnerDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+            spin = new JSpinner(btInnerDia.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            btPanel.add(spin, "cell 1 2, growx");
+            btPanel.add(new UnitSelector(btInnerDia), "growx");
 
             JLabel btOuterDiaLabel = new JLabel("Outer Dia.:");
-            btPanel.add(btOuterDiaLabel, "cell 2 2,alignx left");
-
-            btOuterDiaTextField = new JTextField();
-            btOuterDiaTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            btPanel.add(btOuterDiaTextField, "cell 3 2,growx");
-            btOuterDiaTextField.setColumns(10);
-
-            JLabel btLengthLabel = new JLabel("Length:");
-            btPanel.add(btLengthLabel, "cell 0 1,alignx left");
+            btPanel.add(btOuterDiaLabel, "cell 3 2,alignx left");
 
-            btLengthTextField = new JTextField();
-            btLengthTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            btPanel.add(btLengthTextField, "cell 1 1,growx");
-            btLengthTextField.setColumns(10);
+            btOuterDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+            spin = new JSpinner(btOuterDia.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            btPanel.add(spin, "cell 4 2, growx");
+            btPanel.add(new UnitSelector(btOuterDia), "growx");
 
             JPanel panel = new JPanel();
             panel.setMinimumSize(new Dimension(200, 200));
-            btPanel.add(panel, "cell 3 3");
+            btPanel.add(panel, "cell 4 3");
             panel.setLayout(null);
             btImageBtn = new JButton("No Image");
             btImageBtn.setMaximumSize(new Dimension(75, 75));
@@ -527,47 +574,51 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
             tcPartNoTextField.setColumns(10);
 
             JLabel tcDescLabel = new JLabel("Description:");
-            tcPanel.add(tcDescLabel, "cell 2 0,alignx left");
+            tcPanel.add(tcDescLabel, "cell 3 0,alignx left");
 
             tcDescTextField = new JTextField();
-            tcPanel.add(tcDescTextField, "cell 3 0,growx");
+            tcPanel.add(tcDescTextField, "cell 4 0,growx");
             tcDescTextField.setColumns(10);
 
+            JLabel tcLengthLabel = new JLabel("Length:");
+            tcPanel.add(tcLengthLabel, "cell 0 1,alignx left");
+
+            tcLength = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+            JSpinner spin = new JSpinner(tcLength.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            tcPanel.add(spin, "cell 1 1, growx");
+            tcPanel.add(new UnitSelector(tcLength), "growx");
+
             JLabel tcMassLabel = new JLabel("Mass:");
-            tcPanel.add(tcMassLabel, "cell 2 1,alignx left");
+            tcPanel.add(tcMassLabel, "cell 3 1,alignx left");
 
-            tcMassTextField = new JTextField();
-            tcMassTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            tcPanel.add(tcMassTextField, "cell 3 1,growx");
-            tcMassTextField.setColumns(10);
+            tcMass = new DoubleModel(0, UnitGroup.UNITS_MASS, 0);
+            spin = new JSpinner(tcMass.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            tcPanel.add(spin, "cell 4 1, growx");
+            tcPanel.add(new UnitSelector(tcMass), "growx");
 
             JLabel tcInnerDiaLabel = new JLabel("Inner Dia.:");
-            tcPanel.add(tcInnerDiaLabel, "cell 0 2,alignx left, aligny top");
+            tcPanel.add(tcInnerDiaLabel, "cell 0 2,alignx left");
 
-            tcInnerDiaTextField = new JTextField();
-            tcInnerDiaTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            tcPanel.add(tcInnerDiaTextField, "cell 1 2,growx, aligny top");
-            tcInnerDiaTextField.setColumns(10);
+            tcInnerDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+            spin = new JSpinner(tcInnerDia.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            tcPanel.add(spin, "cell 1 2, growx");
+            tcPanel.add(new UnitSelector(tcInnerDia), "growx");
 
             JLabel tcOuterDiaLabel = new JLabel("Outer Dia.:");
-            tcPanel.add(tcOuterDiaLabel, "cell 2 2,alignx left, aligny top");
-
-            tcOuterDiaTextField = new JTextField();
-            tcOuterDiaTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            tcPanel.add(tcOuterDiaTextField, "cell 3 2,growx, aligny top");
-            tcOuterDiaTextField.setColumns(10);
+            tcPanel.add(tcOuterDiaLabel, "cell 3 2,alignx left");
 
-            JLabel tcLengthLabel = new JLabel("Length:");
-            tcPanel.add(tcLengthLabel, "cell 0 1,alignx left");
-
-            tcLengthTextField = new JTextField();
-            tcLengthTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            tcPanel.add(tcLengthTextField, "cell 1 1,growx");
-            tcLengthTextField.setColumns(10);
+            tcOuterDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+            spin = new JSpinner(tcOuterDia.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            tcPanel.add(spin, "cell 4 2, growx");
+            tcPanel.add(new UnitSelector(tcOuterDia), "growx");
 
             JPanel panel = new JPanel();
             panel.setMinimumSize(new Dimension(200, 200));
-            tcPanel.add(panel, "cell 3 3");
+            tcPanel.add(panel, "cell 4 3");
             panel.setLayout(null);
             tcImageBtn = new JButton("No Image");
             tcImageBtn.setMaximumSize(new Dimension(75, 75));
@@ -603,36 +654,42 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
             bhPartNoTextField.setColumns(10);
 
             JLabel bhDescLabel = new JLabel("Description:");
-            bhPanel.add(bhDescLabel, "cell 2 0,alignx left");
+            bhPanel.add(bhDescLabel, "cell 3 0,alignx left");
 
             bhDescTextField = new JTextField();
-            bhPanel.add(bhDescTextField, "cell 3 0,growx");
+            bhPanel.add(bhDescTextField, "cell 4 0,growx");
             bhDescTextField.setColumns(10);
 
-            JLabel bhOuterDiaLabel = new JLabel("Outer Dia.:");
-            bhPanel.add(bhOuterDiaLabel, "cell 0 2,alignx left, aligny top");
+            JLabel bhLengthLabel = new JLabel("Thickness:");
+            bhPanel.add(bhLengthLabel, "cell 0 1,alignx left");
 
-            bhOuterDiaTextField = new JTextField();
-            bhPanel.add(bhOuterDiaTextField, "cell 1 2,growx, aligny top");
-            bhOuterDiaTextField.setColumns(10);
+            bhLength = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+            JSpinner spin = new JSpinner(bhLength.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            bhPanel.add(spin, "cell 1 1, growx");
+            bhPanel.add(new UnitSelector(bhLength), "growx");
 
             JLabel bhMassLabel = new JLabel("Mass:");
-            bhPanel.add(bhMassLabel, "cell 2 1,alignx left");
+            bhPanel.add(bhMassLabel, "cell 3 1,alignx left");
 
-            bhMassTextField = new JTextField();
-            bhPanel.add(bhMassTextField, "cell 3 1,growx");
-            bhMassTextField.setColumns(10);
+            bhMass = new DoubleModel(0, UnitGroup.UNITS_MASS, 0);
+            spin = new JSpinner(bhMass.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            bhPanel.add(spin, "cell 4 1, growx");
+            bhPanel.add(new UnitSelector(bhMass), "growx");
 
-            JLabel bhLengthLabel = new JLabel("Thickness:");
-            bhPanel.add(bhLengthLabel, "cell 0 1,alignx left");
+            JLabel bhOuterDiaLabel = new JLabel("Outer Dia.:");
+            bhPanel.add(bhOuterDiaLabel, "cell 0 2,alignx left, aligny top, pad 7 0 0 0");
 
-            bhLengthTextField = new JTextField();
-            bhPanel.add(bhLengthTextField, "cell 1 1,growx");
-            bhLengthTextField.setColumns(10);
+            bhOuterDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+            spin = new JSpinner(bhOuterDia.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            bhPanel.add(spin, "cell 1 2, growx, aligny top");
+            bhPanel.add(new UnitSelector(bhOuterDia), "growx, aligny top, pad 7 0 0 0");
 
             JPanel panel = new JPanel();
             panel.setMinimumSize(new Dimension(200, 200));
-            bhPanel.add(panel, "cell 3 2");
+            bhPanel.add(panel, "cell 4 2");
             panel.setLayout(null);
             bhImageBtn = new JButton("No Image");
             bhImageBtn.setMaximumSize(new Dimension(75, 75));
@@ -667,47 +724,51 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
             crPartNoTextField.setColumns(10);
 
             JLabel crDescLabel = new JLabel("Description:");
-            crPanel.add(crDescLabel, "cell 2 0,alignx left");
+            crPanel.add(crDescLabel, "cell 3 0,alignx left");
 
             crDescTextField = new JTextField();
-            crPanel.add(crDescTextField, "cell 3 0, growx");
+            crPanel.add(crDescTextField, "cell 4 0, growx");
             crDescTextField.setColumns(10);
 
+            JLabel crThicknessLabel = new JLabel("Thickness:");
+            crPanel.add(crThicknessLabel, "cell 0 1,alignx left");
+
+            crThickness = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+            JSpinner spin = new JSpinner(crThickness.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            crPanel.add(spin, "cell 1 1, growx");
+            crPanel.add(new UnitSelector(crThickness), "growx");
+
             JLabel crMassLabel = new JLabel("Mass:");
-            crPanel.add(crMassLabel, "cell 2 1,alignx left");
+            crPanel.add(crMassLabel, "cell 3 1,alignx left");
 
-            crMassTextField = new JTextField();
-            crMassTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            crPanel.add(crMassTextField, "cell 3 1, growx");
-            crMassTextField.setColumns(10);
+            crMass = new DoubleModel(0, UnitGroup.UNITS_MASS, 0);
+            spin = new JSpinner(crMass.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            crPanel.add(spin, "cell 4 1, growx");
+            crPanel.add(new UnitSelector(crMass), "growx");
 
             JLabel crOuterDiaLabel = new JLabel("Outer Dia.:");
             crPanel.add(crOuterDiaLabel, "cell 0 2,alignx left");
 
-            crOuterDiaTextField = new JTextField();
-            crOuterDiaTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            crPanel.add(crOuterDiaTextField, "cell 1 2, growx");
-            crOuterDiaTextField.setColumns(10);
+            crOuterDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+            spin = new JSpinner(crOuterDia.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            crPanel.add(spin, "cell 1 2, growx");
+            crPanel.add(new UnitSelector(crOuterDia), "growx");
 
             JLabel crInnerDiaLabel = new JLabel("Inner Dia.:");
-            crPanel.add(crInnerDiaLabel, "cell 2 2,alignx left");
-
-            crInnerDiaTextField = new JTextField();
-            crInnerDiaTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            crPanel.add(crInnerDiaTextField, "cell 3 2, growx");
-            crInnerDiaTextField.setColumns(10);
+            crPanel.add(crInnerDiaLabel, "cell 3 2,alignx left");
 
-            JLabel crThicknessLabel = new JLabel("Thickness:");
-            crPanel.add(crThicknessLabel, "cell 0 1,alignx left");
-
-            crThicknessTextField = new JTextField();
-            crThicknessTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            crPanel.add(crThicknessTextField, "cell 1 1, growx");
-            crThicknessTextField.setColumns(10);
+            crInnerDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+            spin = new JSpinner(crInnerDia.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            crPanel.add(spin, "cell 4 2, growx");
+            crPanel.add(new UnitSelector(crInnerDia), "growx");
 
             JPanel panel = new JPanel();
             panel.setMinimumSize(new Dimension(200, 200));
-            crPanel.add(panel, "cell 3 3");
+            crPanel.add(panel, "cell 4 3");
             panel.setLayout(null);
             crImageBtn = new JButton("No Image");
             crImageBtn.setMaximumSize(new Dimension(75, 75));
@@ -741,47 +802,51 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
             ebPartNoTextField.setColumns(10);
 
             JLabel ebDescLabel = new JLabel("Description:");
-            ebPanel.add(ebDescLabel, "cell 2 0,alignx left");
+            ebPanel.add(ebDescLabel, "cell 3 0,alignx left");
 
             ebDescTextField = new JTextField();
-            ebPanel.add(ebDescTextField, "cell 3 0,growx");
+            ebPanel.add(ebDescTextField, "cell 4 0,growx");
             ebDescTextField.setColumns(10);
 
+            JLabel ebThicknessLabel = new JLabel("Thickness:");
+            ebPanel.add(ebThicknessLabel, "cell 0 1,alignx left");
+
+            ebThickness = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+            JSpinner spin = new JSpinner(ebThickness.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            ebPanel.add(spin, "cell 1 1, growx");
+            ebPanel.add(new UnitSelector(ebThickness), "growx");
+
             JLabel ebMassLabel = new JLabel("Mass:");
-            ebPanel.add(ebMassLabel, "cell 2 1,alignx left");
+            ebPanel.add(ebMassLabel, "cell 3 1,alignx left");
 
-            ebMassTextField = new JTextField();
-            ebMassTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            ebPanel.add(ebMassTextField, "cell 3 1,growx");
-            ebMassTextField.setColumns(10);
+            ebMass = new DoubleModel(0, UnitGroup.UNITS_MASS, 0);
+            spin = new JSpinner(ebMass.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            ebPanel.add(spin, "cell 4 1, growx");
+            ebPanel.add(new UnitSelector(ebMass), "growx");
 
             JLabel ebOuterDiaLabel = new JLabel("Outer Dia.:");
             ebPanel.add(ebOuterDiaLabel, "cell 0 2,alignx left");
 
-            ebOuterDiaTextField = new JTextField();
-            ebOuterDiaTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            ebPanel.add(ebOuterDiaTextField, "cell 1 2,growx");
-            ebOuterDiaTextField.setColumns(10);
+            ebOuterDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+            spin = new JSpinner(ebOuterDia.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            ebPanel.add(spin, "cell 1 2, growx");
+            ebPanel.add(new UnitSelector(ebOuterDia), "growx");
 
             JLabel ebInnerDiaLabel = new JLabel("Inner Dia.:");
-            ebPanel.add(ebInnerDiaLabel, "cell 2 2,alignx left");
+            ebPanel.add(ebInnerDiaLabel, "cell 3 2,alignx left");
 
-            ebInnerDiaTextField = new JTextField();
-            ebInnerDiaTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            ebPanel.add(ebInnerDiaTextField, "cell 3 2,growx");
-            ebInnerDiaTextField.setColumns(10);
-
-            JLabel ebThicknessLabel = new JLabel("Thickness:");
-            ebPanel.add(ebThicknessLabel, "cell 0 1,alignx left");
-
-            ebThicknessTextField = new JTextField();
-            ebThicknessTextField.setInputVerifier(NON_NEGATIVE_DECIMAL);
-            ebPanel.add(ebThicknessTextField, "cell 1 1,growx");
-            ebThicknessTextField.setColumns(10);
+            ebInnerDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+            spin = new JSpinner(ebInnerDia.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            ebPanel.add(spin, "cell 4 2, growx");
+            ebPanel.add(new UnitSelector(ebInnerDia), "growx");
 
             JPanel panel = new JPanel();
             panel.setMinimumSize(new Dimension(200, 200));
-            ebPanel.add(panel, "cell 3 3");
+            ebPanel.add(panel, "cell 4 3");
             panel.setLayout(null);
             ebImageBtn = new JButton("No Image");
             ebImageBtn.setMaximumSize(new Dimension(75, 75));
@@ -803,6 +868,255 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
             });
         }
 
+        {
+            JPanel llPanel = new JPanel();
+            componentOverlayPanel.add(llPanel, "LAUNCHLUG");
+            llPanel.setLayout(new MigLayout("", "[][grow][][grow]", "[][][][]"));
+            JLabel llPartNoLabel = new JLabel("Part No:");
+            llPanel.add(llPartNoLabel, "cell 0 0,alignx left");
+
+            llPartNoTextField = new JTextField();
+            llPanel.add(llPartNoTextField, "cell 1 0,growx");
+            llPartNoTextField.setColumns(10);
+
+            JLabel llDescLabel = new JLabel("Description:");
+            llPanel.add(llDescLabel, "cell 3 0,alignx left");
+
+            llDescTextField = new JTextField();
+            llPanel.add(llDescTextField, "cell 4 0,growx");
+            llDescTextField.setColumns(10);
+
+            JLabel llLengthLabel = new JLabel("Length:");
+            llPanel.add(llLengthLabel, "cell 0 1,alignx left");
+
+            llLength = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+            JSpinner spin = new JSpinner(llLength.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            llPanel.add(spin, "cell 1 1, growx");
+            llPanel.add(new UnitSelector(llLength), "growx");
+
+            JLabel llMassLabel = new JLabel("Mass:");
+            llPanel.add(llMassLabel, "cell 3 1,alignx left");
+
+            llMass = new DoubleModel(0, UnitGroup.UNITS_MASS, 0);
+            spin = new JSpinner(llMass.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            llPanel.add(spin, "cell 4 1, growx");
+            llPanel.add(new UnitSelector(llMass), "growx");
+
+            JLabel llOuterDiaLabel = new JLabel("Outer Dia.:");
+            llPanel.add(llOuterDiaLabel, "cell 0 2,alignx left");
+
+            llOuterDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+            spin = new JSpinner(llOuterDia.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            llPanel.add(spin, "cell 1 2, growx");
+            llPanel.add(new UnitSelector(llOuterDia), "growx");
+
+            JLabel llInnerDiaLabel = new JLabel("Inner Dia.:");
+            llPanel.add(llInnerDiaLabel, "cell 3 2,alignx left");
+
+            llInnerDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+            spin = new JSpinner(llInnerDia.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            llPanel.add(spin, "cell 4 2, growx");
+            llPanel.add(new UnitSelector(llInnerDia), "growx");
+
+            JPanel panel = new JPanel();
+            panel.setMinimumSize(new Dimension(200, 200));
+            llPanel.add(panel, "cell 4 3");
+            panel.setLayout(null);
+            llImageBtn = new JButton("No Image");
+            llImageBtn.setMaximumSize(new Dimension(75, 75));
+            llImageBtn.setMinimumSize(new Dimension(75, 75));
+            panel.add(llImageBtn);
+            llImageBtn.setBounds(new Rectangle(6, 6, 132, 145));
+
+            llImageBtn.addActionListener(new ActionListener() {
+                @Override
+                public void actionPerformed(final ActionEvent e) {
+                    int returnVal = imageChooser.showOpenDialog(PresetEditorDialog.this);
+
+                    if (returnVal == JFileChooser.APPROVE_OPTION) {
+                        File file = imageChooser.getSelectedFile();
+                        llImage = scaleImage(new ImageIcon(file.getAbsolutePath()).getImage(), 155);
+                        llImageBtn.setIcon(llImage);
+                    }
+                }
+            });
+        }
+
+        {
+            JPanel stPanel = new JPanel();
+            componentOverlayPanel.add(stPanel, "STREAMER");
+            stPanel.setLayout(new MigLayout("", "[][grow][][grow]", "[][][][]"));
+            JLabel stPartNoLabel = new JLabel("Part No:");
+            stPanel.add(stPartNoLabel, "cell 0 0,alignx left");
+
+            stPartNoTextField = new JTextField();
+            stPanel.add(stPartNoTextField, "cell 1 0,growx");
+            stPartNoTextField.setColumns(10);
+
+            JLabel stDescLabel = new JLabel("Description:");
+            stPanel.add(stDescLabel, "cell 3 0,alignx left");
+
+            stDescTextField = new JTextField();
+            stPanel.add(stDescTextField, "cell 4 0,growx");
+            stDescTextField.setColumns(10);
+
+            JLabel stLengthLabel = new JLabel("Length:");
+            stPanel.add(stLengthLabel, "cell 0 1,alignx left");
+
+            stLength = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+            JSpinner spin = new JSpinner(stLength.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            stPanel.add(spin, "cell 1 1, growx");
+            stPanel.add(new UnitSelector(stLength), "growx");
+
+            JLabel stMassLabel = new JLabel("Mass:");
+            stPanel.add(stMassLabel, "cell 3 1,alignx left");
+
+            stMass = new DoubleModel(0, UnitGroup.UNITS_MASS, 0);
+            spin = new JSpinner(stMass.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            stPanel.add(spin, "cell 4 1, growx");
+            stPanel.add(new UnitSelector(stMass), "growx");
+
+            JLabel stThicknessLabel = new JLabel("Thickness:");
+            stPanel.add(stThicknessLabel, "cell 0 2,alignx left");
+
+            stThickness = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+            spin = new JSpinner(stThickness.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            stPanel.add(spin, "cell 1 2, growx");
+            stPanel.add(new UnitSelector(stThickness), "growx");
+
+            JLabel stWidthLabel = new JLabel("Width:");
+            stPanel.add(stWidthLabel, "cell 3 2,alignx left");
+
+            stWidth = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+            spin = new JSpinner(stWidth.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            stPanel.add(spin, "cell 4 2, growx");
+            stPanel.add(new UnitSelector(stWidth), "growx");
+
+            JPanel panel = new JPanel();
+            panel.setMinimumSize(new Dimension(200, 200));
+            stPanel.add(panel, "cell 4 3");
+            panel.setLayout(null);
+            stImageBtn = new JButton("No Image");
+            stImageBtn.setMaximumSize(new Dimension(75, 75));
+            stImageBtn.setMinimumSize(new Dimension(75, 75));
+            panel.add(stImageBtn);
+            stImageBtn.setBounds(new Rectangle(6, 6, 132, 145));
+
+            stImageBtn.addActionListener(new ActionListener() {
+                @Override
+                public void actionPerformed(final ActionEvent e) {
+                    int returnVal = imageChooser.showOpenDialog(PresetEditorDialog.this);
+
+                    if (returnVal == JFileChooser.APPROVE_OPTION) {
+                        File file = imageChooser.getSelectedFile();
+                        stImage = scaleImage(new ImageIcon(file.getAbsolutePath()).getImage(), 155);
+                        stImageBtn.setIcon(stImage);
+                    }
+                }
+            });
+        }
+
+        {
+            JPanel pcPanel = new JPanel();
+            componentOverlayPanel.add(pcPanel, "PARACHUTE");
+            pcPanel.setLayout(new MigLayout("", "[][157.00,grow 79][65.00][grow][][]", "[][][][][][]"));
+            //pcPanel.setLayout(new MigLayout("", "[][grow][][grow]", "[][][][]"));
+            JLabel pcPartNoLabel = new JLabel("Part No:");
+            pcPanel.add(pcPartNoLabel, "cell 0 0,alignx left");
+
+            pcPartNoTextField = new JTextField();
+            pcPanel.add(pcPartNoTextField, "cell 1 0,growx");
+            pcPartNoTextField.setColumns(10);
+
+            JLabel pcDescLabel = new JLabel("Description:");
+            pcPanel.add(pcDescLabel, "cell 3 0,alignx left");
+
+            pcDescTextField = new JTextField();
+            pcPanel.add(pcDescTextField, "cell 4 0,growx");
+            pcDescTextField.setColumns(10);
+
+            JLabel pcSidesLabel = new JLabel("Sides:");
+            pcPanel.add(pcSidesLabel, "cell 0 1,alignx left");
+
+            pcSides = new JTextField();
+            pcPanel.add(pcSides, "cell 1 1, growx");
+            pcSides.setInputVerifier(NON_NEGATIVE_INTEGER);
+            pcSides.setColumns(10);
+
+            JLabel pcMassLabel = new JLabel("Mass:");
+            pcPanel.add(pcMassLabel, "cell 3 1,alignx left");
+
+            pcMass = new DoubleModel(0, UnitGroup.UNITS_MASS, 0);
+            JSpinner spin = new JSpinner(pcMass.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            pcPanel.add(spin, "cell 4 1, growx");
+            pcPanel.add(new UnitSelector(pcMass), "growx");
+
+            JLabel pcDiameterLabel = new JLabel("Diameter:");
+            pcPanel.add(pcDiameterLabel, "cell 0 2,alignx left");
+
+            pcDiameter = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+            spin = new JSpinner(pcDiameter.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            pcPanel.add(spin, "cell 1 2, growx");
+            pcPanel.add(new UnitSelector(pcDiameter));
+
+            JLabel pcLineLengthLabel = new JLabel("Line Length:");
+            pcPanel.add(pcLineLengthLabel, "cell 3 2,alignx left");
+
+            pcLineLength = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+            spin = new JSpinner(pcLineLength.getSpinnerModel());
+            spin.setEditor(new SpinnerEditor(spin));
+            pcPanel.add(spin, "cell 4 2, growx");
+            pcPanel.add(new UnitSelector(pcLineLength), "growx");
+
+            JLabel pcLineCountLabel = new JLabel("Line Count:");
+            pcPanel.add(pcLineCountLabel, "cell 3 3,alignx left");
+
+            pcLineCount = new JTextField();
+            pcLineCount.setInputVerifier(NON_NEGATIVE_INTEGER);
+            pcPanel.add(pcLineCount, "cell 4 3, growx");
+            pcLineCount.setColumns(10);
+
+            JLabel pcLineMaterialLabel = new JLabel("Line Material:");
+            pcPanel.add(pcLineMaterialLabel, "cell 3 4,alignx left, aligny top, pad 7 0 0 0 ");
+
+            pcLineMaterialChooser = new JComboBox();
+            pcLineMaterialChooser.setModel(new MaterialModel(PresetEditorDialog.this, Material.Type.LINE));
+            pcPanel.add(pcLineMaterialChooser, "cell 4 4, span 3 1, growx, aligny top");
+
+            JPanel panel = new JPanel();
+            panel.setMinimumSize(new Dimension(200, 200));
+            pcPanel.add(panel, "cell 1 3, span 1 3");
+            panel.setLayout(null);
+            pcImageBtn = new JButton("No Image");
+            pcImageBtn.setMaximumSize(new Dimension(75, 75));
+            pcImageBtn.setMinimumSize(new Dimension(75, 75));
+            panel.add(pcImageBtn);
+            pcImageBtn.setBounds(new Rectangle(6, 6, 132, 145));
+
+            pcImageBtn.addActionListener(new ActionListener() {
+                @Override
+                public void actionPerformed(final ActionEvent e) {
+                    int returnVal = imageChooser.showOpenDialog(PresetEditorDialog.this);
+
+                    if (returnVal == JFileChooser.APPROVE_OPTION) {
+                        File file = imageChooser.getSelectedFile();
+                        pcImage = scaleImage(new ImageIcon(file.getAbsolutePath()).getImage(), 155);
+                        pcImageBtn.setIcon(pcImage);
+                    }
+                }
+            });
+        }
+
         JPanel buttonPane = new JPanel();
         getContentPane().add(buttonPane, BorderLayout.SOUTH);
         buttonPane.setLayout(new MigLayout("", "[130px][176.00px][131.00px]", "[29px]"));
@@ -818,8 +1132,9 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
         JButton okButton = new JButton("Save and Close");
         okButton.addActionListener(new ActionListener() {
             public void actionPerformed(ActionEvent event) {
-                saveResult();
-                dispose();
+                if (saveResult()) {
+                    dispose();
+                }
             }
         });
         okButton.setActionCommand("OK");
@@ -844,23 +1159,26 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
      * When an existing preset is edited, we want to disable the other types of presets.  If the user wants a different
      * type of component, then they should delete this one and add a new one.
      *
-     * @param cb
-     * @param preset
+     * @param cb     the combo box component
+     * @param preset the preset being edited
      */
     private void setItems(DeselectableComboBox cb, ComponentPreset preset) {
-        cb.addItem(trans.get(NOSE_CONE_KEY), preset == null ? false : !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.NOSE_CONE));
-        cb.addItem(trans.get(BODY_TUBE_KEY), preset == null ? false : !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.BODY_TUBE));
-        cb.addItem(trans.get(TUBE_COUPLER_KEY), preset == null ? false : !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.TUBE_COUPLER));
-        cb.addItem(trans.get(TRANSITION_KEY), preset == null ? false : !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.TRANSITION));
-        cb.addItem(trans.get(CR_KEY), preset == null ? false : !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.CENTERING_RING));
-        cb.addItem(trans.get(BULKHEAD_KEY), preset == null ? false : !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.BULK_HEAD));
-        cb.addItem(trans.get(EB_KEY), preset == null ? false : !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.ENGINE_BLOCK));
+        cb.addItem(trans.get(NOSE_CONE_KEY), preset != null && !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.NOSE_CONE));
+        cb.addItem(trans.get(BODY_TUBE_KEY), preset != null && !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.BODY_TUBE));
+        cb.addItem(trans.get(BULKHEAD_KEY), preset != null && !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.BULK_HEAD));
+        cb.addItem(trans.get(CR_KEY), preset != null && !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.CENTERING_RING));
+        cb.addItem(trans.get(EB_KEY), preset != null && !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.ENGINE_BLOCK));
+        cb.addItem(trans.get(TRANSITION_KEY), preset != null && !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.TRANSITION));
+        cb.addItem(trans.get(TUBE_COUPLER_KEY), preset != null && !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.TUBE_COUPLER));
+        cb.addItem(trans.get(LAUNCH_LUG_KEY), preset != null && !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.LAUNCH_LUG));
+        cb.addItem(trans.get(PARACHUTE_KEY), preset != null && !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.PARACHUTE));
+        cb.addItem(trans.get(STREAMER_KEY), preset != null && !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.STREAMER));
     }
 
     /**
      * Create an image chooser.  Currently png and jpg are supported.
      *
-     * @return
+     * @return a file chooser that looks for image files
      */
     private JFileChooser createImageChooser() {
         final JFileChooser chooser = new JFileChooser();
@@ -882,10 +1200,16 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
         return chooser;
     }
 
+    /**
+     * To support editing of an existing preset, the swing components need to be prepopulated with the field data.
+     *
+     * @param preset the preset to edit
+     */
     private void fillEditor(ComponentPreset preset) {
         ComponentPreset.Type t = preset.getType();
 
         mfgTextField.setText(preset.get(ComponentPreset.MANUFACTURER).getDisplayName());
+        materialChooser.setModel(new MaterialModel(PresetEditorDialog.this, Material.Type.BULK));
         materialChooser.getModel().setSelectedItem(preset.get(ComponentPreset.MATERIAL));
         switch (t) {
             case BODY_TUBE:
@@ -893,16 +1217,20 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
                 btDescTextField.setText(preset.get(ComponentPreset.DESCRIPTION));
 
                 if (preset.has(ComponentPreset.INNER_DIAMETER)) {
-                    btInnerDiaTextField.setText(preset.get(ComponentPreset.INNER_DIAMETER).toString());
+                    btInnerDia.setValue(preset.get(ComponentPreset.INNER_DIAMETER));
+                    btInnerDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.LENGTH)) {
-                    btLengthTextField.setText(preset.get(ComponentPreset.LENGTH).toString());
+                    btLength.setValue(preset.get(ComponentPreset.LENGTH));
+                    btLength.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.MASS)) {
-                    btMassTextField.setText(preset.get(ComponentPreset.MASS).toString());
+                    btMass.setValue(preset.get(ComponentPreset.MASS));
+                    btMass.setCurrentUnit(UnitGroup.UNITS_MASS.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.OUTER_DIAMETER)) {
-                    btOuterDiaTextField.setText(preset.get(ComponentPreset.OUTER_DIAMETER).toString());
+                    btOuterDia.setValue(preset.get(ComponentPreset.OUTER_DIAMETER));
+                    btOuterDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.IMAGE)) {
                     btImage = new ImageIcon(byteArrayToImage(preset.get(ComponentPreset.IMAGE)));
@@ -914,13 +1242,16 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
                 typeCombo.setSelectedItem(trans.get(BULKHEAD_KEY));
                 bhDescTextField.setText(preset.get(ComponentPreset.DESCRIPTION));
                 if (preset.has(ComponentPreset.LENGTH)) {
-                    bhLengthTextField.setText(preset.get(ComponentPreset.LENGTH).toString());
+                    bhLength.setValue(preset.get(ComponentPreset.LENGTH));
+                    bhLength.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.MASS)) {
-                    bhMassTextField.setText(preset.get(ComponentPreset.MASS).toString());
+                    bhMass.setValue(preset.get(ComponentPreset.MASS));
+                    bhMass.setCurrentUnit(UnitGroup.UNITS_MASS.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.OUTER_DIAMETER)) {
-                    bhOuterDiaTextField.setText(preset.get(ComponentPreset.OUTER_DIAMETER).toString());
+                    bhOuterDia.setValue(preset.get(ComponentPreset.OUTER_DIAMETER));
+                    bhOuterDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.IMAGE)) {
                     bhImage = new ImageIcon(byteArrayToImage(preset.get(ComponentPreset.IMAGE)));
@@ -932,16 +1263,20 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
                 typeCombo.setSelectedItem(trans.get(CR_KEY));
                 crDescTextField.setText(preset.get(ComponentPreset.DESCRIPTION));
                 if (preset.has(ComponentPreset.INNER_DIAMETER)) {
-                    crInnerDiaTextField.setText(preset.get(ComponentPreset.INNER_DIAMETER).toString());
+                    crInnerDia.setValue(preset.get(ComponentPreset.INNER_DIAMETER));
+                    crInnerDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.LENGTH)) {
-                    crThicknessTextField.setText(preset.get(ComponentPreset.LENGTH).toString());
+                    crThickness.setValue(preset.get(ComponentPreset.LENGTH));
+                    crThickness.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.MASS)) {
-                    crMassTextField.setText(preset.get(ComponentPreset.MASS).toString());
+                    crMass.setValue(preset.get(ComponentPreset.MASS));
+                    crMass.setCurrentUnit(UnitGroup.UNITS_MASS.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.OUTER_DIAMETER)) {
-                    crOuterDiaTextField.setText(preset.get(ComponentPreset.OUTER_DIAMETER).toString());
+                    crOuterDia.setValue(preset.get(ComponentPreset.OUTER_DIAMETER));
+                    crOuterDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.IMAGE)) {
                     crImage = new ImageIcon(byteArrayToImage(preset.get(ComponentPreset.IMAGE)));
@@ -953,16 +1288,20 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
                 typeCombo.setSelectedItem(trans.get(EB_KEY));
                 ebDescTextField.setText(preset.get(ComponentPreset.DESCRIPTION));
                 if (preset.has(ComponentPreset.INNER_DIAMETER)) {
-                    ebInnerDiaTextField.setText(preset.get(ComponentPreset.INNER_DIAMETER).toString());
+                    ebInnerDia.setValue(preset.get(ComponentPreset.INNER_DIAMETER));
+                    ebInnerDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.LENGTH)) {
-                    ebThicknessTextField.setText(preset.get(ComponentPreset.LENGTH).toString());
+                    ebThickness.setValue(preset.get(ComponentPreset.LENGTH));
+                    ebThickness.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.MASS)) {
-                    ebMassTextField.setText(preset.get(ComponentPreset.MASS).toString());
+                    ebMass.setValue(preset.get(ComponentPreset.MASS));
+                    ebMass.setCurrentUnit(UnitGroup.UNITS_MASS.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.OUTER_DIAMETER)) {
-                    ebOuterDiaTextField.setText(preset.get(ComponentPreset.OUTER_DIAMETER).toString());
+                    ebOuterDia.setValue(preset.get(ComponentPreset.OUTER_DIAMETER));
+                    ebOuterDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.IMAGE)) {
                     ebImage = new ImageIcon(byteArrayToImage(preset.get(ComponentPreset.IMAGE)));
@@ -974,16 +1313,20 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
                 typeCombo.setSelectedItem(trans.get(NOSE_CONE_KEY));
                 ncDescTextField.setText(preset.get(ComponentPreset.DESCRIPTION));
                 if (preset.has(ComponentPreset.AFT_OUTER_DIAMETER)) {
-                    ncAftDiaTextField.setText(preset.get(ComponentPreset.AFT_OUTER_DIAMETER).toString());
+                    ncAftDia.setValue(preset.get(ComponentPreset.AFT_OUTER_DIAMETER));
+                    ncAftDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.AFT_SHOULDER_DIAMETER)) {
-                    ncAftShoulderDiaTextField.setText(preset.get(ComponentPreset.AFT_SHOULDER_DIAMETER).toString());
+                    ncAftShoulderDia.setValue(preset.get(ComponentPreset.AFT_SHOULDER_DIAMETER));
+                    ncAftShoulderDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.AFT_SHOULDER_LENGTH)) {
-                    ncAftShoulderLenTextField.setText(preset.get(ComponentPreset.AFT_SHOULDER_LENGTH).toString());
+                    ncAftShoulderLen.setValue(preset.get(ComponentPreset.AFT_SHOULDER_LENGTH));
+                    ncAftShoulderLen.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.MASS)) {
-                    ncMassTextField.setText(preset.get(ComponentPreset.MASS).toString());
+                    ncMass.setValue(preset.get(ComponentPreset.MASS));
+                    ncMass.setCurrentUnit(UnitGroup.UNITS_MASS.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.SHAPE)) {
                     ncShapeCB.setSelectedItem(preset.get(ComponentPreset.SHAPE).toString());
@@ -992,7 +1335,8 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
                     ncFilledCB.setSelected((preset.get(ComponentPreset.FILLED)));
                 }
                 if (preset.has(ComponentPreset.LENGTH)) {
-                    ncLengthTextField.setText(preset.get(ComponentPreset.LENGTH).toString());
+                    ncLength.setValue(preset.get(ComponentPreset.LENGTH));
+                    ncLength.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.IMAGE)) {
                     ncImage = new ImageIcon(byteArrayToImage(preset.get(ComponentPreset.IMAGE)));
@@ -1004,25 +1348,32 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
                 typeCombo.setSelectedItem(trans.get(TRANSITION_KEY));
                 trDescTextField.setText(preset.get(ComponentPreset.DESCRIPTION));
                 if (preset.has(ComponentPreset.AFT_OUTER_DIAMETER)) {
-                    trAftDiaTextField.setText(preset.get(ComponentPreset.AFT_OUTER_DIAMETER).toString());
+                    trAftDia.setValue(preset.get(ComponentPreset.AFT_OUTER_DIAMETER));
+                    trAftDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.AFT_SHOULDER_DIAMETER)) {
-                    trAftShoulderDiaTextField.setText(preset.get(ComponentPreset.AFT_SHOULDER_DIAMETER).toString());
+                    trAftShoulderDia.setValue(preset.get(ComponentPreset.AFT_SHOULDER_DIAMETER));
+                    trAftShoulderDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.AFT_SHOULDER_LENGTH)) {
-                    trAftShoulderLenTextField.setText(preset.get(ComponentPreset.AFT_SHOULDER_LENGTH).toString());
+                    trAftShoulderLen.setValue(preset.get(ComponentPreset.AFT_SHOULDER_LENGTH));
+                    trAftShoulderLen.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.FORE_OUTER_DIAMETER)) {
-                    trForeDiaTextField.setText(preset.get(ComponentPreset.FORE_OUTER_DIAMETER).toString());
+                    trForeDia.setValue(preset.get(ComponentPreset.FORE_OUTER_DIAMETER));
+                    trForeDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.FORE_SHOULDER_DIAMETER)) {
-                    trForeShoulderDiaTextField.setText(preset.get(ComponentPreset.FORE_SHOULDER_DIAMETER).toString());
+                    trForeShoulderDia.setValue(preset.get(ComponentPreset.FORE_SHOULDER_DIAMETER));
+                    trForeShoulderDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.FORE_SHOULDER_LENGTH)) {
-                    trForeShoulderLenTextField.setText(preset.get(ComponentPreset.FORE_SHOULDER_LENGTH).toString());
+                    trForeShoulderLen.setValue(preset.get(ComponentPreset.FORE_SHOULDER_LENGTH));
+                    trForeShoulderLen.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.MASS)) {
-                    trMassTextField.setText(preset.get(ComponentPreset.MASS).toString());
+                    trMass.setValue(preset.get(ComponentPreset.MASS));
+                    trMass.setCurrentUnit(UnitGroup.UNITS_MASS.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.SHAPE)) {
                     trShapeCB.setSelectedItem(preset.get(ComponentPreset.SHAPE).toString());
@@ -1031,7 +1382,8 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
                     trFilledCB.setSelected((preset.get(ComponentPreset.FILLED)));
                 }
                 if (preset.has(ComponentPreset.LENGTH)) {
-                    trLengthTextField.setText(preset.get(ComponentPreset.LENGTH).toString());
+                    trLength.setValue(preset.get(ComponentPreset.LENGTH));
+                    trLength.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.IMAGE)) {
                     trImage = new ImageIcon(byteArrayToImage(preset.get(ComponentPreset.IMAGE)));
@@ -1043,16 +1395,20 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
                 typeCombo.setSelectedItem(trans.get(TUBE_COUPLER_KEY));
                 tcDescTextField.setText(preset.get(ComponentPreset.DESCRIPTION));
                 if (preset.has(ComponentPreset.INNER_DIAMETER)) {
-                    tcInnerDiaTextField.setText(preset.get(ComponentPreset.INNER_DIAMETER).toString());
+                    tcInnerDia.setValue(preset.get(ComponentPreset.INNER_DIAMETER));
+                    tcInnerDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.LENGTH)) {
-                    tcLengthTextField.setText(preset.get(ComponentPreset.LENGTH).toString());
+                    tcLength.setValue(preset.get(ComponentPreset.LENGTH));
+                    tcLength.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.MASS)) {
-                    tcMassTextField.setText(preset.get(ComponentPreset.MASS).toString());
+                    tcMass.setValue(preset.get(ComponentPreset.MASS));
+                    tcMass.setCurrentUnit(UnitGroup.UNITS_MASS.getDefaultUnit());
                 }
                 if (preset.has(ComponentPreset.OUTER_DIAMETER)) {
-                    tcOuterDiaTextField.setText(preset.get(ComponentPreset.OUTER_DIAMETER).toString());
+                    tcOuterDia.setValue(preset.get(ComponentPreset.OUTER_DIAMETER));
+                    tcOuterDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
                 }
                 tcPartNoTextField.setText(preset.get(ComponentPreset.PARTNO));
                 if (preset.has(ComponentPreset.IMAGE)) {
@@ -1060,11 +1416,96 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
                     tcImageBtn.setIcon(tcImage);
                 }
                 break;
+            case LAUNCH_LUG:
+                typeCombo.setSelectedItem(trans.get(LAUNCH_LUG_KEY));
+                llDescTextField.setText(preset.get(ComponentPreset.DESCRIPTION));
+                if (preset.has(ComponentPreset.INNER_DIAMETER)) {
+                    llInnerDia.setValue(preset.get(ComponentPreset.INNER_DIAMETER));
+                    llInnerDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                }
+                if (preset.has(ComponentPreset.LENGTH)) {
+                    llLength.setValue(preset.get(ComponentPreset.LENGTH));
+                    llLength.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                }
+                if (preset.has(ComponentPreset.MASS)) {
+                    llMass.setValue(preset.get(ComponentPreset.MASS));
+                    llMass.setCurrentUnit(UnitGroup.UNITS_MASS.getDefaultUnit());
+                }
+                if (preset.has(ComponentPreset.OUTER_DIAMETER)) {
+                    llOuterDia.setValue(preset.get(ComponentPreset.OUTER_DIAMETER));
+                    llOuterDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                }
+                llPartNoTextField.setText(preset.get(ComponentPreset.PARTNO));
+                if (preset.has(ComponentPreset.IMAGE)) {
+                    llImage = new ImageIcon(byteArrayToImage(preset.get(ComponentPreset.IMAGE)));
+                    llImageBtn.setIcon(llImage);
+                }
+                break;
+            case PARACHUTE:
+                materialChooser.setModel(new MaterialModel(PresetEditorDialog.this, Material.Type.SURFACE));
+                materialChooser.getModel().setSelectedItem(preset.get(ComponentPreset.MATERIAL));
+                typeCombo.setSelectedItem(trans.get(PARACHUTE_KEY));
+                pcDescTextField.setText(preset.get(ComponentPreset.DESCRIPTION));
+                if (preset.has(ComponentPreset.LINE_COUNT)) {
+                    pcLineCount.setText(preset.get(ComponentPreset.LINE_COUNT).toString());
+                }
+                if (preset.has(ComponentPreset.SIDES)) {
+                    pcSides.setText(preset.get(ComponentPreset.SIDES).toString());
+                }
+                if (preset.has(ComponentPreset.MASS)) {
+                    pcMass.setValue(preset.get(ComponentPreset.MASS));
+                    pcMass.setCurrentUnit(UnitGroup.UNITS_MASS.getDefaultUnit());
+                }
+                if (preset.has(ComponentPreset.DIAMETER)) {
+                    pcDiameter.setValue(preset.get(ComponentPreset.DIAMETER));
+                    pcDiameter.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                }
+                if (preset.has(ComponentPreset.LINE_LENGTH)) {
+                    pcLineLength.setValue(preset.get(ComponentPreset.LINE_LENGTH));
+                    pcLineLength.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                }
+                pcPartNoTextField.setText(preset.get(ComponentPreset.PARTNO));
+                if (preset.has(ComponentPreset.IMAGE)) {
+                    pcImage = new ImageIcon(byteArrayToImage(preset.get(ComponentPreset.IMAGE)));
+                    pcImageBtn.setIcon(pcImage);
+                }
+                pcLineMaterialChooser.getModel().setSelectedItem(preset.get(ComponentPreset.LINE_MATERIAL));
+                break;
+            case STREAMER:
+                materialChooser.setModel(new MaterialModel(PresetEditorDialog.this, Material.Type.SURFACE));
+                materialChooser.getModel().setSelectedItem(preset.get(ComponentPreset.MATERIAL));
+                typeCombo.setSelectedItem(trans.get(STREAMER_KEY));
+                stDescTextField.setText(preset.get(ComponentPreset.DESCRIPTION));
+                if (preset.has(ComponentPreset.LENGTH)) {
+                    stLength.setValue(preset.get(ComponentPreset.LENGTH));
+                    stLength.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                }
+                if (preset.has(ComponentPreset.THICKNESS)) {
+                    stThickness.setValue(preset.get(ComponentPreset.LENGTH));
+                    stThickness.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                }
+                if (preset.has(ComponentPreset.MASS)) {
+                    stMass.setValue(preset.get(ComponentPreset.MASS));
+                    stMass.setCurrentUnit(UnitGroup.UNITS_MASS.getDefaultUnit());
+                }
+                if (preset.has(ComponentPreset.WIDTH)) {
+                    stWidth.setValue(preset.get(ComponentPreset.WIDTH));
+                    stWidth.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                }
+                if (preset.has(ComponentPreset.IMAGE)) {
+                    stImage = new ImageIcon(byteArrayToImage(preset.get(ComponentPreset.IMAGE)));
+                    stImageBtn.setIcon(stImage);
+                }
+                stPartNoTextField.setText(preset.get(ComponentPreset.PARTNO));
+                break;
             default:
         }
     }
 
-    private void saveResult() {
+    /**
+     * Extract the preset data from the UI fields, create a ComponentPreset instance, and notify the listener.
+     */
+    private boolean saveResult() {
         String type = (String) typeCombo.getSelectedItem();
 
         ComponentPreset result = null;
@@ -1111,30 +1552,44 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
                 clearBulkhead();
             }
         }
-        resultListener.notifyResult(result);
+        else if (type.equals(trans.get(LAUNCH_LUG_KEY))) {
+            result = extractLaunchLug();
+            if (result != null) {
+                clearLaunchLug();
+            }
+        }
+        else if (type.equals(trans.get(PARACHUTE_KEY))) {
+            result = extractParachute();
+            if (result != null) {
+                clearParachute();
+            }
+        }
+        else if (type.equals(trans.get(STREAMER_KEY))) {
+            result = extractStreamer();
+            if (result != null) {
+                clearStreamer();
+            }
+        }
+        if (result != null) {
+            resultListener.notifyResult(result);
+            return true;
+        }
+        else {
+            return false;
+        }
     }
 
     private ComponentPreset extractNoseCone() {
         TypedPropertyMap props = new TypedPropertyMap();
         try {
-            PrintUnit lpu = lengthMap.get(lenUnitCombo.getSelectedItem());
-
             props.put(ComponentPreset.TYPE, ComponentPreset.Type.NOSE_CONE);
-            if (!ncAftDiaTextField.getText().equals("")) {
-                props.put(ComponentPreset.AFT_OUTER_DIAMETER, lpu.toMeters(Double.parseDouble(ncAftDiaTextField.getText())));
-            }
-            if (!ncAftShoulderDiaTextField.getText().equals("")) {
-                props.put(ComponentPreset.AFT_SHOULDER_DIAMETER, lpu.toMeters(Double.parseDouble(ncAftShoulderDiaTextField.getText())));
-            }
-            if (!ncAftShoulderLenTextField.getText().equals("")) {
-                props.put(ComponentPreset.AFT_SHOULDER_LENGTH, lpu.toMeters(Double.parseDouble(ncAftShoulderLenTextField.getText())));
-            }
+            props.put(ComponentPreset.AFT_OUTER_DIAMETER, ncAftDia.getValue());
+            props.put(ComponentPreset.AFT_SHOULDER_DIAMETER, ncAftShoulderDia.getValue());
+            props.put(ComponentPreset.AFT_SHOULDER_LENGTH, ncAftShoulderLen.getValue());
             props.put(ComponentPreset.DESCRIPTION, ncDescTextField.getText());
             props.put(ComponentPreset.PARTNO, ncPartNoTextField.getText());
             props.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer(mfgTextField.getText()));
-            if (!ncLengthTextField.getText().equals("")) {
-                props.put(ComponentPreset.LENGTH, lpu.toMeters(Double.parseDouble(ncLengthTextField.getText())));
-            }
+            props.put(ComponentPreset.LENGTH, ncLength.getValue());
             props.put(ComponentPreset.SHAPE, Transition.Shape.toShape((String) ncShapeCB.getSelectedItem()));
             final Material material = (Material) materialChooser.getSelectedItem();
             if (material != null) {
@@ -1144,9 +1599,7 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
                 JOptionPane.showMessageDialog(null, "A material must be selected.", "Error", JOptionPane.ERROR_MESSAGE);
                 return null;
             }
-            if (!ncMassTextField.getText().equals("")) {
-                props.put(ComponentPreset.MASS, lpu.toMeters(Double.parseDouble(ncMassTextField.getText())));
-            }
+            props.put(ComponentPreset.MASS, ncMass.getValue());
             props.put(ComponentPreset.FILLED, ncFilledCB.isSelected());
             if (ncImage != null) {
                 props.put(ComponentPreset.IMAGE, imageToByteArray(ncImage.getImage()));
@@ -1158,19 +1611,19 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
             JOptionPane.showMessageDialog(null, "Could not convert nose cone attribute.", "Error", JOptionPane.ERROR_MESSAGE);
         }
         catch (InvalidComponentPresetException e) {
-            JOptionPane.showMessageDialog(null, "Mandatory nose cone attribute not set.", "Error", JOptionPane.ERROR_MESSAGE);
+            JOptionPane.showMessageDialog(null, craftErrorMessage(e, "Mandatory nose cone attribute not set."), "Error", JOptionPane.ERROR_MESSAGE);
         }
         return null;
     }
 
     private void clearNoseCone() {
-        ncAftDiaTextField.setText("");
-        ncAftShoulderDiaTextField.setText("");
-        ncAftShoulderLenTextField.setText("");
+        ncAftDia.setValue(0);
+        ncAftShoulderDia.setValue(0);
+        ncAftShoulderLen.setValue(0);
         ncDescTextField.setText("");
         ncPartNoTextField.setText("");
-        ncLengthTextField.setText("");
-        ncMassTextField.setText("");
+        ncLength.setValue(0);
+        ncMass.setValue(0);
         ncFilledCB.setSelected(false);
         ncImage = null;
         ncImageBtn.setIcon(null);
@@ -1179,33 +1632,18 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
     private ComponentPreset extractTransition() {
         TypedPropertyMap props = new TypedPropertyMap();
         try {
-            PrintUnit lpu = lengthMap.get(lenUnitCombo.getSelectedItem());
             props.put(ComponentPreset.TYPE, ComponentPreset.Type.TRANSITION);
-            if (!trAftDiaTextField.getText().equals("")) {
-                props.put(ComponentPreset.AFT_OUTER_DIAMETER, lpu.toMeters(Double.parseDouble(trAftDiaTextField.getText())));
-            }
-            if (!trAftShoulderDiaTextField.getText().equals("")) {
-                props.put(ComponentPreset.AFT_SHOULDER_DIAMETER, lpu.toMeters(Double.parseDouble(trAftShoulderDiaTextField.getText())));
-            }
-            if (!trAftShoulderLenTextField.getText().equals("")) {
-                props.put(ComponentPreset.AFT_SHOULDER_LENGTH, lpu.toMeters(Double.parseDouble(trAftShoulderLenTextField.getText())));
-            }
-            if (!trForeDiaTextField.getText().equals("")) {
-                props.put(ComponentPreset.FORE_OUTER_DIAMETER, lpu.toMeters(Double.parseDouble(trForeDiaTextField.getText())));
-            }
-            if (!trForeShoulderDiaTextField.getText().equals("")) {
-                props.put(ComponentPreset.FORE_SHOULDER_DIAMETER, lpu.toMeters(Double.parseDouble(trForeShoulderDiaTextField.getText())));
-            }
-            if (!trForeShoulderLenTextField.getText().equals("")) {
-                props.put(ComponentPreset.FORE_SHOULDER_LENGTH, lpu.toMeters(Double.parseDouble(trForeShoulderLenTextField.getText())));
-            }
+            props.put(ComponentPreset.AFT_OUTER_DIAMETER, trAftDia.getValue());
+            props.put(ComponentPreset.AFT_SHOULDER_DIAMETER, trAftShoulderDia.getValue());
+            props.put(ComponentPreset.AFT_SHOULDER_LENGTH, trAftShoulderLen.getValue());
+            props.put(ComponentPreset.FORE_OUTER_DIAMETER, trForeDia.getValue());
+            props.put(ComponentPreset.FORE_SHOULDER_DIAMETER, trForeShoulderDia.getValue());
+            props.put(ComponentPreset.FORE_SHOULDER_LENGTH, trForeShoulderLen.getValue());
             props.put(ComponentPreset.DESCRIPTION, trDescTextField.getText());
             props.put(ComponentPreset.PARTNO, trPartNoTextField.getText());
             props.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer(mfgTextField.getText()));
 
-            if (!trLengthTextField.getText().equals("")) {
-                props.put(ComponentPreset.LENGTH, lpu.toMeters(Double.parseDouble(trLengthTextField.getText())));
-            }
+            props.put(ComponentPreset.LENGTH, trLength.getValue());
             props.put(ComponentPreset.SHAPE, Transition.Shape.toShape((String) trShapeCB.getSelectedItem()));
             final Material material = (Material) materialChooser.getSelectedItem();
             if (material != null) {
@@ -1215,9 +1653,7 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
                 JOptionPane.showMessageDialog(null, "A material must be selected.", "Error", JOptionPane.ERROR_MESSAGE);
                 return null;
             }
-            if (!trMassTextField.getText().equals("")) {
-                props.put(ComponentPreset.MASS, lpu.toMeters(Double.parseDouble(trMassTextField.getText())));
-            }
+            props.put(ComponentPreset.MASS, trMass.getValue());
             props.put(ComponentPreset.FILLED, trFilledCB.isSelected());
             if (trImage != null) {
                 props.put(ComponentPreset.IMAGE, imageToByteArray(trImage.getImage()));
@@ -1229,22 +1665,22 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
             JOptionPane.showMessageDialog(null, "Could not convert transition attribute.", "Error", JOptionPane.ERROR_MESSAGE);
         }
         catch (InvalidComponentPresetException e) {
-            JOptionPane.showMessageDialog(null, "Mandatory transition attribute not set.", "Error", JOptionPane.ERROR_MESSAGE);
+            JOptionPane.showMessageDialog(null, craftErrorMessage(e, "Mandatory transition attribute not set."), "Error", JOptionPane.ERROR_MESSAGE);
         }
         return null;
     }
 
     private void clearTransition() {
-        trAftDiaTextField.setText("");
-        trAftShoulderDiaTextField.setText("");
-        trAftShoulderLenTextField.setText("");
-        trForeDiaTextField.setText("");
-        trForeShoulderDiaTextField.setText("");
-        trForeShoulderLenTextField.setText("");
+        trAftDia.setValue(0);
+        trAftShoulderDia.setValue(0);
+        trAftShoulderLen.setValue(0);
+        trForeDia.setValue(0);
+        trForeShoulderDia.setValue(0);
+        trForeShoulderLen.setValue(0);
         trDescTextField.setText("");
         trPartNoTextField.setText("");
-        trLengthTextField.setText("");
-        trMassTextField.setText("");
+        trLength.setValue(0);
+        trMass.setValue(0);
         trFilledCB.setSelected(false);
         trImage = null;
         trImageBtn.setIcon(null);
@@ -1253,20 +1689,13 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
     private ComponentPreset extractBodyTube() {
         TypedPropertyMap props = new TypedPropertyMap();
         try {
-            PrintUnit lpu = lengthMap.get(lenUnitCombo.getSelectedItem());
             props.put(ComponentPreset.TYPE, ComponentPreset.Type.BODY_TUBE);
-            if (!btOuterDiaTextField.getText().equals("")) {
-                props.put(ComponentPreset.OUTER_DIAMETER, lpu.toMeters(Double.parseDouble(btOuterDiaTextField.getText())));
-            }
-            if (!btInnerDiaTextField.getText().equals("")) {
-                props.put(ComponentPreset.INNER_DIAMETER, lpu.toMeters(Double.parseDouble(btInnerDiaTextField.getText())));
-            }
+            props.put(ComponentPreset.OUTER_DIAMETER, btOuterDia.getValue());
+            props.put(ComponentPreset.INNER_DIAMETER, btInnerDia.getValue());
             props.put(ComponentPreset.DESCRIPTION, btDescTextField.getText());
             props.put(ComponentPreset.PARTNO, btPartNoTextField.getText());
             props.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer(mfgTextField.getText()));
-            if (!btLengthTextField.getText().equals("")) {
-                props.put(ComponentPreset.LENGTH, lpu.toMeters(Double.parseDouble(btLengthTextField.getText())));
-            }
+            props.put(ComponentPreset.LENGTH, btLength.getValue());
             final Material material = (Material) materialChooser.getSelectedItem();
             if (material != null) {
                 props.put(ComponentPreset.MATERIAL, material);
@@ -1275,31 +1704,28 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
                 JOptionPane.showMessageDialog(null, "A material must be selected.", "Error", JOptionPane.ERROR_MESSAGE);
                 return null;
             }
-            if (!btMassTextField.getText().equals("")) {
-                props.put(ComponentPreset.MASS, lpu.toMeters(Double.parseDouble(btMassTextField.getText())));
-            }
+            props.put(ComponentPreset.MASS, btMass.getValue());
             if (btImage != null) {
                 props.put(ComponentPreset.IMAGE, imageToByteArray(btImage.getImage()));
             }
             return ComponentPresetFactory.create(props);
         }
         catch (NumberFormatException nfe) {
-            nfe.printStackTrace();
             JOptionPane.showMessageDialog(null, "Could not convert body tube attribute.", "Error", JOptionPane.ERROR_MESSAGE);
         }
         catch (InvalidComponentPresetException e) {
-            JOptionPane.showMessageDialog(null, "Mandatory body tube attribute not set.", "Error", JOptionPane.ERROR_MESSAGE);
+            JOptionPane.showMessageDialog(null, craftErrorMessage(e, "Mandatory body tube attribute not set."), "Error", JOptionPane.ERROR_MESSAGE);
         }
         return null;
     }
 
     private void clearBodyTube() {
-        btOuterDiaTextField.setText("");
-        btInnerDiaTextField.setText("");
+        btOuterDia.setValue(0);
+        btInnerDia.setValue(0);
         btDescTextField.setText("");
         btPartNoTextField.setText("");
-        btLengthTextField.setText("");
-        btMassTextField.setText("");
+        btLength.setValue(0);
+        btMass.setValue(0);
         btImage = null;
         btImageBtn.setIcon(null);
     }
@@ -1307,20 +1733,13 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
     public ComponentPreset extractTubeCoupler() {
         TypedPropertyMap props = new TypedPropertyMap();
         try {
-            PrintUnit lpu = lengthMap.get(lenUnitCombo.getSelectedItem());
             props.put(ComponentPreset.TYPE, ComponentPreset.Type.TUBE_COUPLER);
-            if (!tcOuterDiaTextField.getText().equals("")) {
-                props.put(ComponentPreset.OUTER_DIAMETER, lpu.toMeters(Double.parseDouble(tcOuterDiaTextField.getText())));
-            }
-            if (!tcInnerDiaTextField.getText().equals("")) {
-                props.put(ComponentPreset.INNER_DIAMETER, lpu.toMeters(Double.parseDouble(tcInnerDiaTextField.getText())));
-            }
+            props.put(ComponentPreset.OUTER_DIAMETER, tcOuterDia.getValue());
+            props.put(ComponentPreset.INNER_DIAMETER, tcInnerDia.getValue());
             props.put(ComponentPreset.DESCRIPTION, tcDescTextField.getText());
             props.put(ComponentPreset.PARTNO, tcPartNoTextField.getText());
             props.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer(mfgTextField.getText()));
-            if (!tcLengthTextField.getText().equals("")) {
-                props.put(ComponentPreset.LENGTH, lpu.toMeters(Double.parseDouble(tcLengthTextField.getText())));
-            }
+            props.put(ComponentPreset.LENGTH, tcLength.getValue());
             final Material material = (Material) materialChooser.getSelectedItem();
             if (material != null) {
                 props.put(ComponentPreset.MATERIAL, material);
@@ -1329,9 +1748,7 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
                 JOptionPane.showMessageDialog(null, "A material must be selected.", "Error", JOptionPane.ERROR_MESSAGE);
                 return null;
             }
-            if (!tcMassTextField.getText().equals("")) {
-                props.put(ComponentPreset.MASS, lpu.toMeters(Double.parseDouble(tcMassTextField.getText())));
-            }
+            props.put(ComponentPreset.MASS, tcMass.getValue());
             if (tcImage != null) {
                 props.put(ComponentPreset.IMAGE, imageToByteArray(tcImage.getImage()));
             }
@@ -1342,18 +1759,18 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
             JOptionPane.showMessageDialog(null, "Could not convert tube coupler attribute.", "Error", JOptionPane.ERROR_MESSAGE);
         }
         catch (InvalidComponentPresetException e) {
-            JOptionPane.showMessageDialog(null, "Mandatory tube coupler attribute not set.", "Error", JOptionPane.ERROR_MESSAGE);
+            JOptionPane.showMessageDialog(null, craftErrorMessage(e, "Mandatory tube coupler attribute not set."), "Error", JOptionPane.ERROR_MESSAGE);
         }
         return null;
     }
 
     private void clearTubeCoupler() {
-        tcOuterDiaTextField.setText("");
-        tcInnerDiaTextField.setText("");
+        tcOuterDia.setValue(0);
+        tcInnerDia.setValue(0);
         tcDescTextField.setText("");
         tcPartNoTextField.setText("");
-        tcLengthTextField.setText("");
-        tcMassTextField.setText("");
+        tcLength.setValue(0);
+        tcMass.setValue(0);
         tcImage = null;
         tcImageBtn.setIcon(null);
     }
@@ -1361,17 +1778,12 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
     private ComponentPreset extractBulkhead() {
         TypedPropertyMap props = new TypedPropertyMap();
         try {
-            PrintUnit lpu = lengthMap.get(lenUnitCombo.getSelectedItem());
             props.put(ComponentPreset.TYPE, ComponentPreset.Type.BULK_HEAD);
-            if (!bhOuterDiaTextField.getText().equals("")) {
-                props.put(ComponentPreset.OUTER_DIAMETER, lpu.toMeters(Double.parseDouble(bhOuterDiaTextField.getText())));
-            }
+            props.put(ComponentPreset.OUTER_DIAMETER, bhOuterDia.getValue());
             props.put(ComponentPreset.DESCRIPTION, bhDescTextField.getText());
             props.put(ComponentPreset.PARTNO, bhPartNoTextField.getText());
             props.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer(mfgTextField.getText()));
-            if (!bhLengthTextField.getText().equals("")) {
-                props.put(ComponentPreset.LENGTH, lpu.toMeters(Double.parseDouble(bhLengthTextField.getText())));
-            }
+            props.put(ComponentPreset.LENGTH, bhLength.getValue());
             final Material material = (Material) materialChooser.getSelectedItem();
             if (material != null) {
                 props.put(ComponentPreset.MATERIAL, material);
@@ -1380,9 +1792,7 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
                 JOptionPane.showMessageDialog(null, "A material must be selected.", "Error", JOptionPane.ERROR_MESSAGE);
                 return null;
             }
-            if (!bhMassTextField.getText().equals("")) {
-                props.put(ComponentPreset.MASS, lpu.toMeters(Double.parseDouble(bhMassTextField.getText())));
-            }
+            props.put(ComponentPreset.MASS, bhMass.getValue());
             if (bhImage != null) {
                 props.put(ComponentPreset.IMAGE, imageToByteArray(bhImage.getImage()));
             }
@@ -1392,17 +1802,17 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
             JOptionPane.showMessageDialog(null, "Could not convert bulkhead attribute.", "Error", JOptionPane.ERROR_MESSAGE);
         }
         catch (InvalidComponentPresetException e) {
-            JOptionPane.showMessageDialog(null, "Mandatory bulkhead attribute not set.", "Error", JOptionPane.ERROR_MESSAGE);
+            JOptionPane.showMessageDialog(null, craftErrorMessage(e, "Mandatory bulkhead attribute not set."), "Error", JOptionPane.ERROR_MESSAGE);
         }
         return null;
     }
 
     private void clearBulkhead() {
-        bhOuterDiaTextField.setText("");
+        bhOuterDia.setValue(0);
         bhDescTextField.setText("");
         bhPartNoTextField.setText("");
-        bhLengthTextField.setText("");
-        bhMassTextField.setText("");
+        bhLength.setValue(0);
+        bhMass.setValue(0);
         bhImage = null;
         bhImageBtn.setIcon(null);
     }
@@ -1410,20 +1820,13 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
     private ComponentPreset extractCenteringRing() {
         TypedPropertyMap props = new TypedPropertyMap();
         try {
-            PrintUnit lpu = lengthMap.get(lenUnitCombo.getSelectedItem());
             props.put(ComponentPreset.TYPE, ComponentPreset.Type.CENTERING_RING);
-            if (!crOuterDiaTextField.getText().equals("")) {
-                props.put(ComponentPreset.OUTER_DIAMETER, lpu.toMeters(Double.parseDouble(crOuterDiaTextField.getText())));
-            }
-            if (!crInnerDiaTextField.getText().equals("")) {
-                props.put(ComponentPreset.INNER_DIAMETER, lpu.toMeters(Double.parseDouble(crInnerDiaTextField.getText())));
-            }
+            props.put(ComponentPreset.OUTER_DIAMETER, crOuterDia.getValue());
+            props.put(ComponentPreset.INNER_DIAMETER, crInnerDia.getValue());
             props.put(ComponentPreset.DESCRIPTION, crDescTextField.getText());
             props.put(ComponentPreset.PARTNO, crPartNoTextField.getText());
             props.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer(mfgTextField.getText()));
-            if (!crThicknessTextField.getText().equals("")) {
-                props.put(ComponentPreset.LENGTH, lpu.toMeters(Double.parseDouble(crThicknessTextField.getText())));
-            }
+            props.put(ComponentPreset.LENGTH, crThickness.getValue());
             final Material material = (Material) materialChooser.getSelectedItem();
             if (material != null) {
                 props.put(ComponentPreset.MATERIAL, material);
@@ -1432,9 +1835,7 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
                 JOptionPane.showMessageDialog(null, "A material must be selected.", "Error", JOptionPane.ERROR_MESSAGE);
                 return null;
             }
-            if (!crMassTextField.getText().equals("")) {
-                props.put(ComponentPreset.MASS, lpu.toMeters(Double.parseDouble(crMassTextField.getText())));
-            }
+            props.put(ComponentPreset.MASS, crMass.getValue());
             if (crImage != null) {
                 props.put(ComponentPreset.IMAGE, imageToByteArray(crImage.getImage()));
             }
@@ -1444,18 +1845,18 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
             JOptionPane.showMessageDialog(null, "Could not convert centering ring attribute.", "Error", JOptionPane.ERROR_MESSAGE);
         }
         catch (InvalidComponentPresetException e) {
-            JOptionPane.showMessageDialog(null, "Mandatory centering ring attribute not set.", "Error", JOptionPane.ERROR_MESSAGE);
+            JOptionPane.showMessageDialog(null, craftErrorMessage(e, "Mandatory centering ring attribute not set."), "Error", JOptionPane.ERROR_MESSAGE);
         }
         return null;
     }
 
     private void clearCenteringRing() {
-        crOuterDiaTextField.setText("");
-        crInnerDiaTextField.setText("");
+        crOuterDia.setValue(0);
+        crInnerDia.setValue(0);
         crDescTextField.setText("");
         crPartNoTextField.setText("");
-        crThicknessTextField.setText("");
-        crMassTextField.setText("");
+        crThickness.setValue(0);
+        crMass.setValue(0);
         crImage = null;
         crImageBtn.setIcon(null);
     }
@@ -1463,20 +1864,13 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
     public ComponentPreset extractEngineBlock() {
         TypedPropertyMap props = new TypedPropertyMap();
         try {
-            PrintUnit lpu = lengthMap.get(lenUnitCombo.getSelectedItem());
             props.put(ComponentPreset.TYPE, ComponentPreset.Type.ENGINE_BLOCK);
-            if (!ebOuterDiaTextField.getText().equals("")) {
-                props.put(ComponentPreset.OUTER_DIAMETER, lpu.toMeters(Double.parseDouble(ebOuterDiaTextField.getText())));
-            }
-            if (!ebInnerDiaTextField.getText().equals("")) {
-                props.put(ComponentPreset.INNER_DIAMETER, lpu.toMeters(Double.parseDouble(ebInnerDiaTextField.getText())));
-            }
+            props.put(ComponentPreset.OUTER_DIAMETER, ebOuterDia.getValue());
+            props.put(ComponentPreset.INNER_DIAMETER, ebInnerDia.getValue());
             props.put(ComponentPreset.DESCRIPTION, ebDescTextField.getText());
             props.put(ComponentPreset.PARTNO, ebPartNoTextField.getText());
             props.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer(mfgTextField.getText()));
-            if (!ebThicknessTextField.getText().equals("")) {
-                props.put(ComponentPreset.LENGTH, lpu.toMeters(Double.parseDouble(ebThicknessTextField.getText())));
-            }
+            props.put(ComponentPreset.LENGTH, ebThickness.getValue());
             final Material material = (Material) materialChooser.getSelectedItem();
             if (material != null) {
                 props.put(ComponentPreset.MATERIAL, material);
@@ -1485,9 +1879,7 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
                 JOptionPane.showMessageDialog(null, "A material must be selected.", "Error", JOptionPane.ERROR_MESSAGE);
                 return null;
             }
-            if (!ebMassTextField.getText().equals("")) {
-                props.put(ComponentPreset.MASS, lpu.toMeters(Double.parseDouble(ebMassTextField.getText())));
-            }
+            props.put(ComponentPreset.MASS, ebMass.getValue());
             if (ebImage != null) {
                 props.put(ComponentPreset.IMAGE, imageToByteArray(ebImage.getImage()));
             }
@@ -1497,26 +1889,192 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
             JOptionPane.showMessageDialog(null, "Could not convert engine block attribute.", "Error", JOptionPane.ERROR_MESSAGE);
         }
         catch (InvalidComponentPresetException e) {
-            JOptionPane.showMessageDialog(null, "Mandatory engine block attribute not set.", "Error", JOptionPane.ERROR_MESSAGE);
+            JOptionPane.showMessageDialog(null, craftErrorMessage(e, "Mandatory engine block attribute not set."), "Error", JOptionPane.ERROR_MESSAGE);
         }
         return null;
     }
 
     private void clearEngineBlock() {
-        ebOuterDiaTextField.setText("");
-        ebInnerDiaTextField.setText("");
+        ebOuterDia.setValue(0);
+        ebInnerDia.setValue(0);
         ebDescTextField.setText("");
         ebPartNoTextField.setText("");
-        ebThicknessTextField.setText("");
-        ebMassTextField.setText("");
+        ebThickness.setValue(0);
+        ebMass.setValue(0);
         ebImage = null;
         ebImageBtn.setIcon(null);
     }
 
+    public ComponentPreset extractLaunchLug() {
+        TypedPropertyMap props = new TypedPropertyMap();
+        try {
+            props.put(ComponentPreset.TYPE, ComponentPreset.Type.LAUNCH_LUG);
+            props.put(ComponentPreset.OUTER_DIAMETER, llOuterDia.getValue());
+            props.put(ComponentPreset.INNER_DIAMETER, llInnerDia.getValue());
+            props.put(ComponentPreset.DESCRIPTION, llDescTextField.getText());
+            props.put(ComponentPreset.PARTNO, llPartNoTextField.getText());
+            props.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer(mfgTextField.getText()));
+            props.put(ComponentPreset.LENGTH, llLength.getValue());
+            final Material material = (Material) materialChooser.getSelectedItem();
+            if (material != null) {
+                props.put(ComponentPreset.MATERIAL, material);
+            }
+            else {
+                JOptionPane.showMessageDialog(null, "A material must be selected.", "Error", JOptionPane.ERROR_MESSAGE);
+                return null;
+            }
+            props.put(ComponentPreset.MASS, llMass.getValue());
+            if (llImage != null) {
+                props.put(ComponentPreset.IMAGE, imageToByteArray(llImage.getImage()));
+            }
+            return ComponentPresetFactory.create(props);
+        }
+        catch (NumberFormatException nfe) {
+            JOptionPane.showMessageDialog(null, "Could not convert launch lug attribute.", "Error", JOptionPane.ERROR_MESSAGE);
+        }
+        catch (InvalidComponentPresetException e) {
+            JOptionPane.showMessageDialog(null, craftErrorMessage(e, "Mandatory launch lug attribute not set."), "Error", JOptionPane.ERROR_MESSAGE);
+        }
+        return null;
+    }
+
+    private void clearLaunchLug() {
+        llOuterDia.setValue(0);
+        llInnerDia.setValue(0);
+        llDescTextField.setText("");
+        llPartNoTextField.setText("");
+        llLength.setValue(0);
+        llMass.setValue(0);
+        llImage = null;
+        llImageBtn.setIcon(null);
+    }
+
+    public ComponentPreset extractParachute() {
+        TypedPropertyMap props = new TypedPropertyMap();
+        try {
+            props.put(ComponentPreset.TYPE, ComponentPreset.Type.PARACHUTE);
+            props.put(ComponentPreset.DIAMETER, pcDiameter.getValue());
+            props.put(ComponentPreset.DESCRIPTION, pcDescTextField.getText());
+            props.put(ComponentPreset.PARTNO, pcPartNoTextField.getText());
+            props.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer(mfgTextField.getText()));
+            if (!pcLineCount.getText().equals("")) {
+                props.put(ComponentPreset.LINE_COUNT, Integer.parseInt(pcLineCount.getText()));
+            }
+            if (!pcSides.getText().equals("")) {
+                props.put(ComponentPreset.SIDES, Integer.parseInt(pcSides.getText()));
+            }
+            props.put(ComponentPreset.LINE_LENGTH, pcLineLength.getValue());
+            Material material = (Material) materialChooser.getSelectedItem();
+            if (material != null) {
+                props.put(ComponentPreset.MATERIAL, material);
+            }
+            else {
+                JOptionPane.showMessageDialog(null, "A material must be selected.", "Error", JOptionPane.ERROR_MESSAGE);
+                return null;
+            }
+            material = (Material) pcLineMaterialChooser.getSelectedItem();
+            if (material != null) {
+                props.put(ComponentPreset.LINE_MATERIAL, material);
+            }
+            props.put(ComponentPreset.MASS, pcMass.getValue());
+            if (pcImage != null) {
+                props.put(ComponentPreset.IMAGE, imageToByteArray(pcImage.getImage()));
+            }
+            return ComponentPresetFactory.create(props);
+        }
+        catch (NumberFormatException nfe) {
+            JOptionPane.showMessageDialog(null, "Could not convert parachute attribute.", "Error", JOptionPane.ERROR_MESSAGE);
+        }
+        catch (InvalidComponentPresetException e) {
+            JOptionPane.showMessageDialog(null, craftErrorMessage(e, "Mandatory parachute attribute not set."), "Error", JOptionPane.ERROR_MESSAGE);
+        }
+        return null;
+    }
+
+    private void clearParachute() {
+        ebOuterDia.setValue(0);
+        ebInnerDia.setValue(0);
+        ebDescTextField.setText("");
+        ebPartNoTextField.setText("");
+        ebThickness.setValue(0);
+        ebMass.setValue(0);
+        ebImage = null;
+        ebImageBtn.setIcon(null);
+    }
+
+    public ComponentPreset extractStreamer() {
+        TypedPropertyMap props = new TypedPropertyMap();
+        try {
+            props.put(ComponentPreset.TYPE, ComponentPreset.Type.STREAMER);
+            props.put(ComponentPreset.DESCRIPTION, stDescTextField.getText());
+            props.put(ComponentPreset.PARTNO, stPartNoTextField.getText());
+            props.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer(mfgTextField.getText()));
+            props.put(ComponentPreset.THICKNESS, stThickness.getValue());
+            props.put(ComponentPreset.LENGTH, stLength.getValue());
+            props.put(ComponentPreset.WIDTH, stWidth.getValue());
+            final Material material = (Material) materialChooser.getSelectedItem();
+            if (material != null) {
+                props.put(ComponentPreset.MATERIAL, material);
+            }
+            else {
+                JOptionPane.showMessageDialog(null, "A material must be selected.", "Error", JOptionPane.ERROR_MESSAGE);
+                return null;
+            }
+            props.put(ComponentPreset.MASS, stMass.getValue());
+            if (stImage != null) {
+                props.put(ComponentPreset.IMAGE, imageToByteArray(stImage.getImage()));
+            }
+            return ComponentPresetFactory.create(props);
+        }
+        catch (NumberFormatException nfe) {
+            JOptionPane.showMessageDialog(null, "Could not convert engine block attribute.", "Error", JOptionPane.ERROR_MESSAGE);
+        }
+        catch (InvalidComponentPresetException e) {
+            JOptionPane.showMessageDialog(null, craftErrorMessage(e, "Mandatory engine block attribute not set."), "Error", JOptionPane.ERROR_MESSAGE);
+        }
+        return null;
+    }
+
+    private void clearStreamer() {
+        stWidth.setValue(0);
+        stLength.setValue(0);
+        stDescTextField.setText("");
+        stPartNoTextField.setText("");
+        stThickness.setValue(0);
+        stMass.setValue(0);
+        stImage = null;
+        stImageBtn.setIcon(null);
+    }
+
     public void itemStateChanged(ItemEvent evt) {
         CardLayout cl = (CardLayout) (componentOverlayPanel.getLayout());
-        cl.show(componentOverlayPanel, componentMap.get((String) evt.getItem()));
+        final String item = (String) evt.getItem();
+        if (materialChooser != null && evt.getStateChange() == ItemEvent.SELECTED) {
+            if (item.equals(trans.get(PARACHUTE_KEY)) || item.equals(trans.get(STREAMER_KEY))) {
+                if (!((MaterialModel) materialChooser.getModel()).getType().equals(Material.Type.SURFACE)) {
+                    materialChooser.setModel(new MaterialModel(PresetEditorDialog.this, Material.Type.SURFACE));
+                }
+            }
+            else {
+                if (!((MaterialModel) materialChooser.getModel()).getType().equals(Material.Type.BULK)) {
+                    materialChooser.setModel(new MaterialModel(PresetEditorDialog.this, Material.Type.BULK));
+                }
+            }
+        }
+        cl.show(componentOverlayPanel, componentMap.get(item));
+    }
+
+    //Todo: I18N
+    private String craftErrorMessage(InvalidComponentPresetException e, String baseMsg) {
+        StringBuilder stringBuilder = new StringBuilder();
+        List<String> invalids = e.getErrors();
+        stringBuilder.append(baseMsg).append("\n");
+        for (int i = 0; i < invalids.size(); i++) {
+            String s = invalids.get(i);
+            stringBuilder.append(s).append("\n");
+        }
 
+        return stringBuilder.toString();
     }
 
     /**
@@ -1543,10 +2101,7 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
     }
 
     private BufferedImage imageToBufferedImage(final Image originalImage) {
-        BufferedImage bi = new BufferedImage(
-                originalImage.getWidth(null),
-                originalImage.getHeight(null),
-                BufferedImage.TYPE_INT_RGB);
+        BufferedImage bi = new BufferedImage(originalImage.getWidth(null), originalImage.getHeight(null), BufferedImage.TYPE_INT_RGB);
 
         Graphics2D g2 = bi.createGraphics();
         g2.drawImage(originalImage, 0, 0, null);
@@ -1615,28 +2170,6 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
         public boolean verify(JComponent aComponent) {
             JTextComponent textComponent = (JTextComponent) aComponent;
             String text = textComponent.getText();
-            boolean munged = false;
-            //Make sure there's a leading number
-            if (text.startsWith(".")) {
-                text = "0" + text;
-                munged = true;
-            }
-            //Make sure there's a trailing number
-            if (text.endsWith(".")) {
-                text = text + "0";
-                munged = true;
-            }
-            //Make sure if it's a decimal format
-            else if (text.length() > 0 && !text.contains(".")) {
-                text = text + ".0";
-                munged = true;
-            }
-
-            if (munged) {
-                textComponent.setInputVerifier(null);
-                textComponent.setText(text);
-                textComponent.setInputVerifier(this);
-            }
             matcher.reset(text);
             return matcher.matches();
         }