1 package net.sf.openrocket.gui.configdialog;
5 import java.awt.Window;
6 import java.awt.event.ComponentAdapter;
7 import java.awt.event.ComponentEvent;
8 import java.lang.reflect.Constructor;
9 import java.lang.reflect.InvocationTargetException;
11 import javax.swing.JDialog;
13 import net.sf.openrocket.document.OpenRocketDocument;
14 import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
15 import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
16 import net.sf.openrocket.rocketcomponent.RocketComponent;
17 import net.sf.openrocket.util.BugException;
18 import net.sf.openrocket.util.GUIUtil;
19 import net.sf.openrocket.util.Prefs;
20 import net.sf.openrocket.util.Reflection;
23 * A dialog that contains the configuration elements of one component.
24 * The contents of the dialog are instantiated from CONFIGDIALOGPACKAGE according
25 * to the current component.
27 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
30 public class ComponentConfigDialog extends JDialog implements ComponentChangeListener {
31 private static final long serialVersionUID = 1L;
32 private static final String CONFIGDIALOGPACKAGE = "net.sf.openrocket.gui.configdialog";
33 private static final String CONFIGDIALOGPOSTFIX = "Config";
36 private static ComponentConfigDialog dialog = null;
39 private OpenRocketDocument document = null;
40 private RocketComponent component = null;
41 private RocketComponentConfig configurator = null;
43 private final Window parent;
45 private ComponentConfigDialog(Window parent, OpenRocketDocument document,
46 RocketComponent component) {
50 setComponent(document, component);
52 // Set window position according to preferences, and set prefs when moving
53 Point position = Prefs.getWindowPosition(this.getClass());
55 this.setLocationByPlatform(true);
57 this.setLocation(position);
59 this.addComponentListener(new ComponentAdapter() {
61 public void componentMoved(ComponentEvent e) {
62 Prefs.setWindowPosition(ComponentConfigDialog.this.getClass(),
63 ComponentConfigDialog.this.getLocation());
67 GUIUtil.setDisposableDialogOptions(this, null);
72 * Set the component being configured. The listening connections of the old configurator
73 * will be removed and the new ones created.
75 * @param component Component to configure.
77 private void setComponent(OpenRocketDocument document, RocketComponent component) {
78 if (this.document != null) {
79 this.document.getRocket().removeComponentChangeListener(this);
82 if (configurator != null) {
83 // Remove listeners by setting all applicable models to null
84 GUIUtil.setNullModels(configurator); // null-safe
87 this.document = document;
88 this.component = component;
89 this.document.getRocket().addComponentChangeListener(this);
91 configurator = getDialogContents();
92 this.setContentPane(configurator);
93 configurator.updateFields();
95 setTitle(component.getComponentName()+" configuration");
97 // Dimension pref = getPreferredSize();
98 // Dimension real = getSize();
99 // if (pref.width > real.width || pref.height > real.height)
104 * Return the configurator panel of the current component.
106 private RocketComponentConfig getDialogContents() {
107 Constructor<? extends RocketComponentConfig> c =
108 findDialogContentsConstructor(component);
111 return (RocketComponentConfig) c.newInstance(component);
112 } catch (InstantiationException e) {
113 throw new BugException("BUG in constructor reflection",e);
114 } catch (IllegalAccessException e) {
115 throw new BugException("BUG in constructor reflection",e);
116 } catch (InvocationTargetException e) {
117 throw Reflection.handleWrappedException(e);
121 // Should never be reached, since RocketComponentConfig should catch all
122 // components without their own configurator.
123 throw new BugException("Unable to find any configurator for "+component);
127 * Finds the Constructor of the given component's config dialog panel in
128 * CONFIGDIALOGPACKAGE.
130 @SuppressWarnings("unchecked")
131 private static Constructor<? extends RocketComponentConfig>
132 findDialogContentsConstructor(RocketComponent component) {
133 Class<?> currentclass;
134 String currentclassname;
135 String configclassname;
137 Class<?> configclass;
138 Constructor<? extends RocketComponentConfig> c;
140 currentclass = component.getClass();
141 while ((currentclass != null) && (currentclass != Object.class)) {
142 currentclassname = currentclass.getCanonicalName();
143 int index = currentclassname.lastIndexOf('.');
145 currentclassname = currentclassname.substring(index + 1);
146 configclassname = CONFIGDIALOGPACKAGE + "." + currentclassname +
150 configclass = Class.forName(configclassname);
151 c = (Constructor<? extends RocketComponentConfig>)
152 configclass.getConstructor(RocketComponent.class);
154 } catch (Exception ignore) { }
156 currentclass = currentclass.getSuperclass();
164 ////////// Static dialog /////////
167 * A singleton configuration dialog. Will create and show a new dialog if one has not
168 * previously been used, or update the dialog and show it if a previous one exists.
170 * @param document the document to configure.
171 * @param component the component to configure.
173 public static void showDialog(Window parent, OpenRocketDocument document,
174 RocketComponent component) {
178 dialog = new ComponentConfigDialog(parent, document, component);
179 dialog.setVisible(true);
181 document.addUndoPosition("Modify "+component.getComponentName());
186 static void showDialog(RocketComponent component) {
187 showDialog(dialog.parent, dialog.document, component);
191 * Hides the configuration dialog. May be used even if not currently visible.
193 public static void hideDialog() {
195 dialog.setVisible(false);
200 * Add an undo position for the current document. This is intended for use only
201 * by the currently open dialog.
203 * @param description Description of the undoable action
205 /*package*/ static void addUndoPosition(String description) {
206 if (dialog == null) {
207 throw new IllegalStateException("Dialog not open, report bug!");
209 dialog.document.addUndoPosition(description);
213 static String getUndoDescription() {
214 if (dialog == null) {
215 throw new IllegalStateException("Dialog not open, report bug!");
217 return dialog.document.getUndoDescription();
221 * Returns whether the singleton configuration dialog is currently visible or not.
223 public static boolean isDialogVisible() {
224 return (dialog!=null) && (dialog.isVisible());
228 public void componentChanged(ComponentChangeEvent e) {
229 if (e.isTreeChange() || e.isUndoChange()) {
231 // Hide dialog in case of tree or undo change
232 dialog.setVisible(false);
236 * TODO: HIGH: The line below has caused a NullPointerException (without null check)
237 * How is this possible? The null check was added to avoid this, but the
238 * root cause should be analyzed.
239 * [Openrocket-bugs] 2009-12-12 19:23:22 Automatic bug report for OpenRocket 0.9.5
241 if (configurator != null)
242 configurator.updateFields();