Initial commit
[debian/openrocket] / src / net / sf / openrocket / gui / adaptors / MaterialModel.java
diff --git a/src/net/sf/openrocket/gui/adaptors/MaterialModel.java b/src/net/sf/openrocket/gui/adaptors/MaterialModel.java
new file mode 100644 (file)
index 0000000..1af6f2a
--- /dev/null
@@ -0,0 +1,206 @@
+package net.sf.openrocket.gui.adaptors;
+
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.AbstractListModel;
+import javax.swing.ComboBoxModel;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JSpinner;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.database.Database;
+import net.sf.openrocket.database.Databases;
+import net.sf.openrocket.gui.UnitSelector;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.unit.UnitGroup;
+import net.sf.openrocket.util.Reflection;
+
+public class MaterialModel extends AbstractListModel implements
+               ComboBoxModel, ChangeListener {
+       
+       private static final String CUSTOM = "Custom";
+
+       
+       private final RocketComponent component;
+       private final Material.Type type;
+       private final Database<Material> database;
+       
+       private final Reflection.Method getMethod;
+       private final Reflection.Method setMethod;
+       
+       
+       public MaterialModel(RocketComponent component, Material.Type type) {
+               this(component, type, "Material");
+       }       
+
+       public MaterialModel(RocketComponent component, Material.Type type, String name) {
+               this.component = component;
+               this.type = type;
+               
+               switch (type) {
+               case LINE:
+                       this.database = Databases.LINE_MATERIAL;
+                       break;
+                       
+               case BULK:
+                       this.database = Databases.BULK_MATERIAL;
+                       break;
+                       
+               case SURFACE:
+                       this.database = Databases.SURFACE_MATERIAL;
+                       break;
+                       
+               default:
+                       throw new IllegalArgumentException("Unknown material type:"+type);
+               }
+               
+               try {
+                       getMethod = new Reflection.Method(component.getClass().getMethod("get"+name));
+                       setMethod = new Reflection.Method(component.getClass().getMethod("set"+name,
+                                       Material.class));
+               } catch (NoSuchMethodException e) {
+                       throw new IllegalArgumentException("get/is methods for material " +
+                                       "not present in class "+component.getClass().getCanonicalName());
+               }
+               
+               component.addChangeListener(this);
+               database.addChangeListener(this);
+       }
+       
+       @Override
+       public Object getSelectedItem() {
+               return getMethod.invoke(component);
+       }
+
+       @Override
+       public void setSelectedItem(Object item) {
+               if (item == CUSTOM) {
+                       
+                       // Open custom material dialog in the future, after combo box has closed
+                       SwingUtilities.invokeLater(new Runnable() {
+                               @Override
+                               public void run() {
+                                       AddMaterialDialog dialog = new AddMaterialDialog();
+                                       dialog.setVisible(true);
+                                       
+                                       if (!dialog.okClicked)
+                                               return;
+                                       
+                                       Material material = Material.newMaterial(type, 
+                                                       dialog.nameField.getText().trim(),
+                                                       dialog.density.getValue());
+                                       setMethod.invoke(component, material);
+                                       
+                                       // TODO: HIGH: Allow saving added material to database
+//                                     if (dialog.addBox.isSelected()) {
+//                                             database.add(material);
+//                                     }
+                               }
+                       });
+                       
+               } else if (item instanceof Material) {
+                       
+                       setMethod.invoke(component, item);
+                       
+               } else {
+                       assert(false): "Should not occur";
+               }
+       }
+
+       @Override
+       public Object getElementAt(int index) {
+               if (index == database.size()) {
+                       return CUSTOM;
+               } else if (index >= database.size()+1) {
+                       return null;
+               }
+               return database.get(index);
+       }
+
+       @Override
+       public int getSize() {
+               return database.size() + 1;
+       }
+
+
+       @Override
+       public void stateChanged(ChangeEvent e) {
+               if (e instanceof ComponentChangeEvent) {
+                       if (((ComponentChangeEvent)e).isMassChange()) {
+                               this.fireContentsChanged(this, 0, 0);
+                       }
+               } else {
+                       this.fireContentsChanged(this, 0, database.size());
+               }
+       }
+       
+       
+       
+       
+       private class AddMaterialDialog extends JDialog {
+               
+               private boolean okClicked = false;
+               private JTextField nameField;
+               private DoubleModel density;
+//             private JCheckBox addBox;
+               
+               public AddMaterialDialog() {
+                       super((JFrame)null, "Custom material", true);
+                       
+                       Material material = (Material) getSelectedItem();
+                       
+                       JPanel panel = new JPanel(new MigLayout("gap rel unrel","[][65lp::][30lp::]"));
+                       
+                       panel.add(new JLabel("Material name:"));
+                       nameField = new JTextField(15);
+                       nameField.setText(material.getName());
+                       panel.add(nameField,"span 2, growx, wrap");
+                       
+                       panel.add(new JLabel("Material density:"));
+                       density = new DoubleModel(material.getDensity(),UnitGroup.UNITS_DENSITY_BULK,0);
+                       JSpinner spinner = new JSpinner(density.getSpinnerModel());
+                       panel.add(spinner, "growx");
+                       panel.add(new UnitSelector(density),"wrap");
+                       
+//                     addBox = new JCheckBox("Add material to database");
+//                     panel.add(addBox,"span, wrap");
+                       
+                       JButton button = new JButton("OK");
+                       button.addActionListener(new ActionListener() {
+                               @Override
+                               public void actionPerformed(ActionEvent e) {
+                                       okClicked = true;
+                                       AddMaterialDialog.this.setVisible(false);
+                               }
+                       });
+                       panel.add(button,"span, split, tag ok");
+                       
+                       button = new JButton("Cancel");
+                       button.addActionListener(new ActionListener() {
+                               @Override
+                               public void actionPerformed(ActionEvent e) {
+                                       AddMaterialDialog.this.setVisible(false);
+                               }
+                       });
+                       panel.add(button,"tag cancel");
+                       
+                       this.setContentPane(panel);
+                       this.pack();
+                       this.setAlwaysOnTop(true);
+                       this.setLocationRelativeTo(null);
+               }
+               
+       }
+}