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.GUIUtil;
18 import net.sf.openrocket.util.Prefs;
21 * A dialog that contains the configuration elements of one component.
22 * The contents of the dialog are instantiated from CONFIGDIALOGPACKAGE according
23 * to the current component.
25 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
28 public class ComponentConfigDialog extends JDialog implements ComponentChangeListener {
29 private static final long serialVersionUID = 1L;
30 private static final String CONFIGDIALOGPACKAGE = "net.sf.openrocket.gui.configdialog";
31 private static final String CONFIGDIALOGPOSTFIX = "Config";
34 private static ComponentConfigDialog dialog = null;
37 private OpenRocketDocument document = null;
38 private RocketComponent component = null;
39 private RocketComponentConfig configurator = null;
41 private final Window parent;
43 private ComponentConfigDialog(Window parent, OpenRocketDocument document,
44 RocketComponent component) {
48 setComponent(document, component);
50 // Set window position according to preferences, and set prefs when moving
51 Point position = Prefs.getWindowPosition(this.getClass());
53 this.setLocationByPlatform(true);
55 this.setLocation(position);
57 this.addComponentListener(new ComponentAdapter() {
59 public void componentMoved(ComponentEvent e) {
60 Prefs.setWindowPosition(ComponentConfigDialog.this.getClass(),
61 ComponentConfigDialog.this.getLocation());
65 GUIUtil.setDisposableDialogOptions(this, null);
70 * Set the component being configured. The listening connections of the old configurator
71 * will be removed and the new ones created.
73 * @param component Component to configure.
75 private void setComponent(OpenRocketDocument document, RocketComponent component) {
76 if (this.document != null) {
77 this.document.getRocket().removeComponentChangeListener(this);
80 if (configurator != null) {
81 // Remove listeners by setting all applicable models to null
82 GUIUtil.setNullModels(configurator); // null-safe
85 this.document = document;
86 this.component = component;
87 this.document.getRocket().addComponentChangeListener(this);
89 configurator = getDialogContents();
90 this.setContentPane(configurator);
91 configurator.updateFields();
93 setTitle(component.getComponentName()+" configuration");
95 // Dimension pref = getPreferredSize();
96 // Dimension real = getSize();
97 // if (pref.width > real.width || pref.height > real.height)
102 * Return the configurator panel of the current component.
104 private RocketComponentConfig getDialogContents() {
105 Constructor<? extends RocketComponentConfig> c =
106 findDialogContentsConstructor(component);
109 return (RocketComponentConfig) c.newInstance(component);
110 } catch (InstantiationException e) {
111 throw new RuntimeException("BUG in constructor reflection",e);
112 } catch (IllegalAccessException e) {
113 throw new RuntimeException("BUG in constructor reflection",e);
114 } catch (InvocationTargetException e) {
115 throw new RuntimeException("BUG in constructor reflection",e);
119 // Should never be reached, since RocketComponentConfig should catch all
120 // components without their own configurator.
121 throw new RuntimeException("Unable to find any configurator for "+component);
125 * Finds the Constructor of the given component's config dialog panel in
126 * CONFIGDIALOGPACKAGE.
128 @SuppressWarnings("unchecked")
129 private static Constructor<? extends RocketComponentConfig>
130 findDialogContentsConstructor(RocketComponent component) {
131 Class<?> currentclass;
132 String currentclassname;
133 String configclassname;
135 Class<?> configclass;
136 Constructor<? extends RocketComponentConfig> c;
138 currentclass = component.getClass();
139 while ((currentclass != null) && (currentclass != Object.class)) {
140 currentclassname = currentclass.getCanonicalName();
141 int index = currentclassname.lastIndexOf('.');
143 currentclassname = currentclassname.substring(index + 1);
144 configclassname = CONFIGDIALOGPACKAGE + "." + currentclassname +
148 configclass = Class.forName(configclassname);
149 c = (Constructor<? extends RocketComponentConfig>)
150 configclass.getConstructor(RocketComponent.class);
152 } catch (Exception ignore) { }
154 currentclass = currentclass.getSuperclass();
162 ////////// Static dialog /////////
165 * A singleton configuration dialog. Will create and show a new dialog if one has not
166 * previously been used, or update the dialog and show it if a previous one exists.
168 * @param document the document to configure.
169 * @param component the component to configure.
171 public static void showDialog(Window parent, OpenRocketDocument document,
172 RocketComponent component) {
176 dialog = new ComponentConfigDialog(parent, document, component);
177 dialog.setVisible(true);
179 document.addUndoPosition("Modify "+component.getComponentName());
184 static void showDialog(RocketComponent component) {
185 showDialog(dialog.parent, dialog.document, component);
189 * Hides the configuration dialog. May be used even if not currently visible.
191 public static void hideDialog() {
193 dialog.setVisible(false);
198 * Add an undo position for the current document. This is intended for use only
199 * by the currently open dialog.
201 * @param description Description of the undoable action
203 /*package*/ static void addUndoPosition(String description) {
204 if (dialog == null) {
205 throw new IllegalStateException("Dialog not open, report bug!");
207 dialog.document.addUndoPosition(description);
211 static String getUndoDescription() {
212 if (dialog == null) {
213 throw new IllegalStateException("Dialog not open, report bug!");
215 return dialog.document.getUndoDescription();
219 * Returns whether the singleton configuration dialog is currently visible or not.
221 public static boolean isDialogVisible() {
222 return (dialog!=null) && (dialog.isVisible());
226 public void componentChanged(ComponentChangeEvent e) {
227 if (e.isTreeChange() || e.isUndoChange()) {
229 // Hide dialog in case of tree or undo change
230 dialog.setVisible(false);
233 configurator.updateFields();