be8df36eb4a762492949e8a71127c2dc1ca2f404
[debian/openrocket] / src / net / sf / openrocket / gui / adaptors / MaterialModel.java
1 package net.sf.openrocket.gui.adaptors;
2
3
4 import java.awt.Component;
5
6 import javax.swing.AbstractListModel;
7 import javax.swing.ComboBoxModel;
8 import javax.swing.SwingUtilities;
9
10 import net.sf.openrocket.database.Database;
11 import net.sf.openrocket.database.DatabaseListener;
12 import net.sf.openrocket.database.Databases;
13 import net.sf.openrocket.gui.dialogs.CustomMaterialDialog;
14 import net.sf.openrocket.material.Material;
15 import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
16 import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
17 import net.sf.openrocket.rocketcomponent.RocketComponent;
18 import net.sf.openrocket.util.Reflection;
19
20 public class MaterialModel extends AbstractListModel implements
21                 ComboBoxModel, ComponentChangeListener, DatabaseListener<Material> {
22         
23         private static final String CUSTOM = "Custom";
24
25         
26         private final Component parentComponent;
27         
28         private final RocketComponent component;
29         private final Material.Type type;
30         private final Database<Material> database;
31         
32         private final Reflection.Method getMethod;
33         private final Reflection.Method setMethod;
34         
35         
36         public MaterialModel(Component parent, RocketComponent component, Material.Type type) {
37                 this(parent, component, type, "Material");
38         }       
39
40         public MaterialModel(Component parent, RocketComponent component, Material.Type type, 
41                         String name) {
42                 this.parentComponent = parent;
43                 this.component = component;
44                 this.type = type;
45                 
46                 switch (type) {
47                 case LINE:
48                         this.database = Databases.LINE_MATERIAL;
49                         break;
50                         
51                 case BULK:
52                         this.database = Databases.BULK_MATERIAL;
53                         break;
54                         
55                 case SURFACE:
56                         this.database = Databases.SURFACE_MATERIAL;
57                         break;
58                         
59                 default:
60                         throw new IllegalArgumentException("Unknown material type:"+type);
61                 }
62                 
63                 try {
64                         getMethod = new Reflection.Method(component.getClass().getMethod("get"+name));
65                         setMethod = new Reflection.Method(component.getClass().getMethod("set"+name,
66                                         Material.class));
67                 } catch (NoSuchMethodException e) {
68                         throw new IllegalArgumentException("get/is methods for material " +
69                                         "not present in class "+component.getClass().getCanonicalName());
70                 }
71                 
72                 component.addComponentChangeListener(this);
73                 database.addDatabaseListener(this);
74         }
75         
76         @Override
77         public Object getSelectedItem() {
78                 return getMethod.invoke(component);
79         }
80
81         @Override
82         public void setSelectedItem(Object item) {
83                 if (item == CUSTOM) {
84                         
85                         // Open custom material dialog in the future, after combo box has closed
86                         SwingUtilities.invokeLater(new Runnable() {
87                                 @Override
88                                 public void run() {
89                                         CustomMaterialDialog dialog = new CustomMaterialDialog(
90                                                         SwingUtilities.getWindowAncestor(parentComponent), 
91                                                         (Material) getSelectedItem(), true,
92                                                         "Define custom material");
93
94                                         dialog.setVisible(true);
95                                         
96                                         if (!dialog.getOkClicked())
97                                                 return;
98                                         
99                                         Material material = dialog.getMaterial();
100                                         setMethod.invoke(component, material);
101                                         
102                                         if (dialog.isAddSelected()) {
103                                                 database.add(material);
104                                         }
105                                 }
106                         });
107                         
108                 } else if (item instanceof Material) {
109                         
110                         setMethod.invoke(component, item);
111                         
112                 } else {
113                         throw new IllegalArgumentException("Illegal item class " + item.getClass() + 
114                                         " item=" + item);
115                 }
116         }
117
118         @Override
119         public Object getElementAt(int index) {
120                 if (index == database.size()) {
121                         return CUSTOM;
122                 } else if (index >= database.size()+1) {
123                         return null;
124                 }
125                 return database.get(index);
126         }
127
128         @Override
129         public int getSize() {
130                 return database.size() + 1;
131         }
132
133
134
135         ////////  Change listeners
136
137         @Override
138         public void componentChanged(ComponentChangeEvent e) {
139                 if (((ComponentChangeEvent)e).isMassChange()) {
140                         this.fireContentsChanged(this, 0, 0);
141                 }
142         }
143
144         @Override
145         public void elementAdded(Material element, Database<Material> source) {
146                 this.fireContentsChanged(this, 0, database.size());
147         }
148
149         @Override
150         public void elementRemoved(Material element, Database<Material> source) {
151                 this.fireContentsChanged(this, 0, database.size());
152         }
153         
154 }