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