updates for 0.9.3
[debian/openrocket] / src / net / sf / openrocket / gui / adaptors / MaterialModel.java
1 package net.sf.openrocket.gui.adaptors;
2
3
4 import java.awt.Dialog;
5 import java.awt.Window;
6 import java.awt.event.ActionEvent;
7 import java.awt.event.ActionListener;
8
9 import javax.swing.AbstractListModel;
10 import javax.swing.ComboBoxModel;
11 import javax.swing.JButton;
12 import javax.swing.JDialog;
13 import javax.swing.JLabel;
14 import javax.swing.JPanel;
15 import javax.swing.JSpinner;
16 import javax.swing.JTextField;
17 import javax.swing.SwingUtilities;
18 import javax.swing.event.ChangeEvent;
19 import javax.swing.event.ChangeListener;
20
21 import net.miginfocom.swing.MigLayout;
22 import net.sf.openrocket.database.Database;
23 import net.sf.openrocket.database.Databases;
24 import net.sf.openrocket.gui.components.UnitSelector;
25 import net.sf.openrocket.material.Material;
26 import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
27 import net.sf.openrocket.rocketcomponent.RocketComponent;
28 import net.sf.openrocket.unit.UnitGroup;
29 import net.sf.openrocket.util.Reflection;
30
31 public class MaterialModel extends AbstractListModel implements
32                 ComboBoxModel, ChangeListener {
33         
34         private static final String CUSTOM = "Custom";
35
36         
37         private final RocketComponent component;
38         private final Material.Type type;
39         private final Database<Material> database;
40         
41         private final Reflection.Method getMethod;
42         private final Reflection.Method setMethod;
43         
44         
45         public MaterialModel(RocketComponent component, Material.Type type) {
46                 this(component, type, "Material");
47         }       
48
49         public MaterialModel(RocketComponent component, Material.Type type, String name) {
50                 this.component = component;
51                 this.type = type;
52                 
53                 switch (type) {
54                 case LINE:
55                         this.database = Databases.LINE_MATERIAL;
56                         break;
57                         
58                 case BULK:
59                         this.database = Databases.BULK_MATERIAL;
60                         break;
61                         
62                 case SURFACE:
63                         this.database = Databases.SURFACE_MATERIAL;
64                         break;
65                         
66                 default:
67                         throw new IllegalArgumentException("Unknown material type:"+type);
68                 }
69                 
70                 try {
71                         getMethod = new Reflection.Method(component.getClass().getMethod("get"+name));
72                         setMethod = new Reflection.Method(component.getClass().getMethod("set"+name,
73                                         Material.class));
74                 } catch (NoSuchMethodException e) {
75                         throw new IllegalArgumentException("get/is methods for material " +
76                                         "not present in class "+component.getClass().getCanonicalName());
77                 }
78                 
79                 component.addChangeListener(this);
80                 database.addChangeListener(this);
81         }
82         
83         @Override
84         public Object getSelectedItem() {
85                 return getMethod.invoke(component);
86         }
87
88         @Override
89         public void setSelectedItem(Object item) {
90                 if (item == CUSTOM) {
91                         
92                         // Open custom material dialog in the future, after combo box has closed
93                         SwingUtilities.invokeLater(new Runnable() {
94                                 @Override
95                                 public void run() {
96                                         AddMaterialDialog dialog = new AddMaterialDialog();
97                                         dialog.setVisible(true);
98                                         
99                                         if (!dialog.okClicked)
100                                                 return;
101                                         
102                                         Material material = Material.newMaterial(type, 
103                                                         dialog.nameField.getText().trim(),
104                                                         dialog.density.getValue());
105                                         setMethod.invoke(component, material);
106                                         
107                                         // TODO: HIGH: Allow saving added material to database
108 //                                      if (dialog.addBox.isSelected()) {
109 //                                              database.add(material);
110 //                                      }
111                                 }
112                         });
113                         
114                 } else if (item instanceof Material) {
115                         
116                         setMethod.invoke(component, item);
117                         
118                 } else {
119                         assert(false): "Should not occur";
120                 }
121         }
122
123         @Override
124         public Object getElementAt(int index) {
125                 if (index == database.size()) {
126                         return CUSTOM;
127                 } else if (index >= database.size()+1) {
128                         return null;
129                 }
130                 return database.get(index);
131         }
132
133         @Override
134         public int getSize() {
135                 return database.size() + 1;
136         }
137
138
139         @Override
140         public void stateChanged(ChangeEvent e) {
141                 if (e instanceof ComponentChangeEvent) {
142                         if (((ComponentChangeEvent)e).isMassChange()) {
143                                 this.fireContentsChanged(this, 0, 0);
144                         }
145                 } else {
146                         this.fireContentsChanged(this, 0, database.size());
147                 }
148         }
149         
150         
151         
152         
153         private class AddMaterialDialog extends JDialog {
154                 
155                 private boolean okClicked = false;
156                 private JTextField nameField;
157                 private DoubleModel density;
158 //              private JCheckBox addBox;
159                 
160                 public AddMaterialDialog() {
161                         super((Window)null, "Custom material", Dialog.ModalityType.APPLICATION_MODAL);
162                         
163                         Material material = (Material) getSelectedItem();
164                         
165                         JPanel panel = new JPanel(new MigLayout("gap rel unrel","[][65lp::][30lp::]"));
166                         
167                         panel.add(new JLabel("Material name:"));
168                         nameField = new JTextField(15);
169                         nameField.setText(material.getName());
170                         panel.add(nameField,"span 2, growx, wrap");
171                         
172                         panel.add(new JLabel("Material density:"));
173                         density = new DoubleModel(material.getDensity(),UnitGroup.UNITS_DENSITY_BULK,0);
174                         JSpinner spinner = new JSpinner(density.getSpinnerModel());
175                         panel.add(spinner, "growx");
176                         panel.add(new UnitSelector(density),"wrap");
177                         
178 //                      addBox = new JCheckBox("Add material to database");
179 //                      panel.add(addBox,"span, wrap");
180                         
181                         JButton button = new JButton("OK");
182                         button.addActionListener(new ActionListener() {
183                                 @Override
184                                 public void actionPerformed(ActionEvent e) {
185                                         okClicked = true;
186                                         AddMaterialDialog.this.setVisible(false);
187                                 }
188                         });
189                         panel.add(button,"span, split, tag ok");
190                         
191                         button = new JButton("Cancel");
192                         button.addActionListener(new ActionListener() {
193                                 @Override
194                                 public void actionPerformed(ActionEvent e) {
195                                         AddMaterialDialog.this.setVisible(false);
196                                 }
197                         });
198                         panel.add(button,"tag cancel");
199                         
200                         this.setContentPane(panel);
201                         this.pack();
202                         this.setAlwaysOnTop(true);
203                         this.setLocationRelativeTo(null);
204                 }
205         }
206 }