X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fnet%2Fsf%2Fopenrocket%2Futil%2FGUIUtil.java;fp=src%2Fnet%2Fsf%2Fopenrocket%2Futil%2FGUIUtil.java;h=2f50a9cf92d11c75d2c197d3d02c6764a8b48663;hb=b3c3c1071dfdca4c6b3eb9935dc461201abdaf60;hp=27cf121c7a5ffad1ae201742e15c87cb7df226a4;hpb=fa61335265b0af5f9bc8800df953d41cde2d75f6;p=debian%2Fopenrocket diff --git a/src/net/sf/openrocket/util/GUIUtil.java b/src/net/sf/openrocket/util/GUIUtil.java index 27cf121c..2f50a9cf 100644 --- a/src/net/sf/openrocket/util/GUIUtil.java +++ b/src/net/sf/openrocket/util/GUIUtil.java @@ -1,36 +1,62 @@ package net.sf.openrocket.util; import java.awt.Component; +import java.awt.Container; import java.awt.Image; import java.awt.KeyboardFocusManager; import java.awt.Point; import java.awt.Window; import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ComponentListener; +import java.awt.event.FocusListener; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; +import java.beans.PropertyChangeListener; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; +import java.util.Enumeration; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.Vector; import javax.imageio.ImageIO; import javax.swing.AbstractAction; +import javax.swing.AbstractButton; import javax.swing.Action; +import javax.swing.DefaultBoundedRangeModel; +import javax.swing.DefaultComboBoxModel; +import javax.swing.DefaultListSelectionModel; import javax.swing.JButton; +import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JRootPane; +import javax.swing.JSlider; +import javax.swing.JSpinner; import javax.swing.JTable; +import javax.swing.JTree; import javax.swing.KeyStroke; import javax.swing.RootPaneContainer; +import javax.swing.SpinnerNumberModel; import javax.swing.SwingUtilities; +import javax.swing.event.ChangeListener; import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableColumnModel; +import javax.swing.table.DefaultTableModel; import javax.swing.table.TableModel; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.DefaultTreeSelectionModel; +import javax.swing.tree.TreeNode; + +import net.sf.openrocket.gui.Resettable; public class GUIUtil { @@ -45,7 +71,6 @@ public class GUIUtil { loadImage("pix/icon/icon-032.png"); loadImage("pix/icon/icon-016.png"); } - private static void loadImage(String file) { InputStream is; @@ -62,6 +87,26 @@ public class GUIUtil { } + + /** + * Set suitable options for a single-use disposable dialog. This includes + * setting ESC to close the dialog and adding the appropriate window icons. + * If defaultButton is provided, it is set to the default button action. + *

+ * The default button must be already attached to the dialog. + * + * @param dialog the dialog. + * @param defaultButton the default button of the dialog, or null. + */ + public static void setDisposableDialogOptions(JDialog dialog, JButton defaultButton) { + installEscapeCloseOperation(dialog); + setWindowIcons(dialog); + addModelNullingListener(dialog); + if (defaultButton != null) { + setDefaultButton(defaultButton); + } + } + /** @@ -115,10 +160,165 @@ public class GUIUtil { } + + /** + * Set the OpenRocket icons to the window icons. + * + * @param window the window to set. + */ public static void setWindowIcons(Window window) { window.setIconImages(images); } + /** + * Add a listener to the provided window that will call {@link #setNullModels(Component)} + * on the window once it is disposed. This method may only be used on single-use + * windows and dialogs, that will never be shown again once closed! + * + * @param window the window to add the listener to. + */ + public static void addModelNullingListener(final Window window) { + window.addWindowListener(new WindowAdapter() { + @Override + public void windowClosed(WindowEvent e) { + setNullModels(window); + } + }); + } + + + /** + * Traverses recursively the component tree, and sets all applicable component + * models to null, so as to remove the listener connections. After calling this + * method the component hierarchy should no longed be used. + *

+ * All components that use custom models should be added to this method, as + * there exists no standard way of removing the model from a component. + * + * @param c the component (null is ok) + */ + public static void setNullModels(Component c) { + if (c==null) + return; + + // Remove various listeners + for (ComponentListener l: c.getComponentListeners()) { + c.removeComponentListener(l); + } + for (FocusListener l: c.getFocusListeners()) { + c.removeFocusListener(l); + } + for (MouseListener l: c.getMouseListeners()) { + c.removeMouseListener(l); + } + for (PropertyChangeListener l: c.getPropertyChangeListeners()) { + c.removePropertyChangeListener(l); + } + for (PropertyChangeListener l: c.getPropertyChangeListeners("model")) { + c.removePropertyChangeListener("model", l); + } + for (PropertyChangeListener l: c.getPropertyChangeListeners("action")) { + c.removePropertyChangeListener("action", l); + } + + // Remove models for known components + // Why the FSCK must this be so hard?!?!? + + if (c instanceof JSpinner) { + + JSpinner spinner = (JSpinner)c; + for (ChangeListener l: spinner.getChangeListeners()) { + spinner.removeChangeListener(l); + } + spinner.setModel(new SpinnerNumberModel()); + + } else if (c instanceof JSlider) { + + JSlider slider = (JSlider)c; + for (ChangeListener l: slider.getChangeListeners()) { + slider.removeChangeListener(l); + } + slider.setModel(new DefaultBoundedRangeModel()); + + } else if (c instanceof JComboBox) { + + JComboBox combo = (JComboBox)c; + for (ActionListener l: combo.getActionListeners()) { + combo.removeActionListener(l); + } + combo.setModel(new DefaultComboBoxModel()); + + } else if (c instanceof AbstractButton) { + + AbstractButton button = (AbstractButton)c; + for (ActionListener l: button.getActionListeners()) { + button.removeActionListener(l); + } + button.setAction(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { } + }); + + } else if (c instanceof JTable) { + + JTable table = (JTable)c; + table.setModel(new DefaultTableModel()); + table.setColumnModel(new DefaultTableColumnModel()); + table.setSelectionModel(new DefaultListSelectionModel()); + + } else if (c instanceof JTree) { + + JTree tree = (JTree)c; + tree.setModel(new DefaultTreeModel(new TreeNode() { + @SuppressWarnings("unchecked") + @Override + public Enumeration children() { + return new Vector().elements(); + } + @Override + public boolean getAllowsChildren() { + return false; + } + @Override + public TreeNode getChildAt(int childIndex) { + return null; + } + @Override + public int getChildCount() { + return 0; + } + @Override + public int getIndex(TreeNode node) { + return 0; + } + @Override + public TreeNode getParent() { + return null; + } + @Override + public boolean isLeaf() { + return true; + } + })); + tree.setSelectionModel(new DefaultTreeSelectionModel()); + + } else if (c instanceof Resettable) { + + ((Resettable)c).resetModel(); + + } + + // Recurse the component + if (c instanceof Container) { + Component[] cs = ((Container)c).getComponents(); + for (Component sub: cs) + setNullModels(sub); + } + + } + + + /** * A mouse listener that toggles the state of a boolean value in a table model @@ -184,5 +384,5 @@ public class GUIUtil { } } - + }