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