1 package net.sf.openrocket.gui.configdialog;
4 import java.awt.Window;
5 import java.lang.reflect.Constructor;
6 import java.lang.reflect.InvocationTargetException;
8 import javax.swing.JDialog;
10 import net.sf.openrocket.document.OpenRocketDocument;
11 import net.sf.openrocket.l10n.Translator;
12 import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
13 import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
14 import net.sf.openrocket.rocketcomponent.RocketComponent;
15 import net.sf.openrocket.startup.Application;
16 import net.sf.openrocket.util.BugException;
17 import net.sf.openrocket.util.GUIUtil;
18 import net.sf.openrocket.util.Reflection;
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;
42 private static final Translator trans = Application.getTranslator();
44 private ComponentConfigDialog(Window parent, OpenRocketDocument document,
45 RocketComponent component) {
49 setComponent(document, component);
51 GUIUtil.setDisposableDialogOptions(this, null);
52 GUIUtil.rememberWindowPosition(this);
57 * Set the component being configured. The listening connections of the old configurator
58 * will be removed and the new ones created.
60 * @param component Component to configure.
62 private void setComponent(OpenRocketDocument document, RocketComponent component) {
63 if (this.document != null) {
64 this.document.getRocket().removeComponentChangeListener(this);
67 if (configurator != null) {
68 // Remove listeners by setting all applicable models to null
69 GUIUtil.setNullModels(configurator); // null-safe
72 this.document = document;
73 this.component = component;
74 this.document.getRocket().addComponentChangeListener(this);
76 configurator = getDialogContents();
77 this.setContentPane(configurator);
78 configurator.updateFields();
81 setTitle(trans.get("ComponentCfgDlg.configuration1") + " " + component.getComponentName() + " " + trans.get("ComponentCfgDlg.configuration"));
83 // Dimension pref = getPreferredSize();
84 // Dimension real = getSize();
85 // if (pref.width > real.width || pref.height > real.height)
90 * Return the configurator panel of the current component.
92 private RocketComponentConfig getDialogContents() {
93 Constructor<? extends RocketComponentConfig> c =
94 findDialogContentsConstructor(component);
97 return c.newInstance(component);
98 } catch (InstantiationException e) {
99 throw new BugException("BUG in constructor reflection", e);
100 } catch (IllegalAccessException e) {
101 throw new BugException("BUG in constructor reflection", e);
102 } catch (InvocationTargetException e) {
103 throw Reflection.handleWrappedException(e);
107 // Should never be reached, since RocketComponentConfig should catch all
108 // components without their own configurator.
109 throw new BugException("Unable to find any configurator for " + component);
113 private void closeDialog() {
114 this.setVisible(false);
116 this.configurator.invalidateModels();
121 public void componentChanged(ComponentChangeEvent e) {
122 if (e.isTreeChange() || e.isUndoChange()) {
124 // Hide dialog in case of tree or undo change
125 dialog.closeDialog();
129 * TODO: HIGH: The line below has caused a NullPointerException (without null check)
130 * How is this possible? The null check was added to avoid this, but the
131 * root cause should be analyzed.
132 * [Openrocket-bugs] 2009-12-12 19:23:22 Automatic bug report for OpenRocket 0.9.5
134 if (configurator != null)
135 configurator.updateFields();
141 * Finds the Constructor of the given component's config dialog panel in
142 * CONFIGDIALOGPACKAGE.
144 @SuppressWarnings("unchecked")
145 private static Constructor<? extends RocketComponentConfig> findDialogContentsConstructor(RocketComponent component) {
146 Class<?> currentclass;
147 String currentclassname;
148 String configclassname;
150 Class<?> configclass;
151 Constructor<? extends RocketComponentConfig> c;
153 currentclass = component.getClass();
154 while ((currentclass != null) && (currentclass != Object.class)) {
155 currentclassname = currentclass.getCanonicalName();
156 int index = currentclassname.lastIndexOf('.');
158 currentclassname = currentclassname.substring(index + 1);
159 configclassname = CONFIGDIALOGPACKAGE + "." + currentclassname +
163 configclass = Class.forName(configclassname);
164 c = (Constructor<? extends RocketComponentConfig>)
165 configclass.getConstructor(RocketComponent.class);
167 } catch (Exception ignore) {
170 currentclass = currentclass.getSuperclass();
178 ////////// Static dialog /////////
181 * A singleton configuration dialog. Will create and show a new dialog if one has not
182 * previously been used, or update the dialog and show it if a previous one exists.
184 * @param document the document to configure.
185 * @param component the component to configure.
187 public static void showDialog(Window parent, OpenRocketDocument document,
188 RocketComponent component) {
192 dialog = new ComponentConfigDialog(parent, document, component);
193 dialog.setVisible(true);
196 document.addUndoPosition(trans.get("ComponentCfgDlg.Modify") + " " + component.getComponentName());
201 static void showDialog(RocketComponent component) {
202 showDialog(dialog.parent, dialog.document, component);
206 * Hides the configuration dialog. May be used even if not currently visible.
208 public static void hideDialog() {
209 if (dialog != null) {
210 dialog.closeDialog();
216 * Add an undo position for the current document. This is intended for use only
217 * by the currently open dialog.
219 * @param description Description of the undoable action
221 /*package*/static void addUndoPosition(String description) {
222 if (dialog == null) {
223 throw new IllegalStateException("Dialog not open, report bug!");
225 dialog.document.addUndoPosition(description);
229 static String getUndoDescription() {
230 if (dialog == null) {
231 throw new IllegalStateException("Dialog not open, report bug!");
233 return dialog.document.getUndoDescription();
237 * Returns whether the singleton configuration dialog is currently visible or not.
239 public static boolean isDialogVisible() {
240 return (dialog != null) && (dialog.isVisible());