X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FJvOptionPane.java;h=0e0b13d847464fc8a9467f7867dc6ab9b32bff53;hb=0de37d1a047209510bab82225109ae2a47931f79;hp=c5427cb1c224075b4dd8d90ed067e6ec074321fb;hpb=b364e1e6d199002069dab615d1007799b5bb71e1;p=jalview.git diff --git a/src/jalview/gui/JvOptionPane.java b/src/jalview/gui/JvOptionPane.java index c5427cb..0e0b13d 100644 --- a/src/jalview/gui/JvOptionPane.java +++ b/src/jalview/gui/JvOptionPane.java @@ -18,15 +18,22 @@ * along with Jalview. If not, see . * The Jalview Authors are detailed in the 'AUTHORS' file. */ - package jalview.gui; +import java.awt.AWTEvent; +import java.awt.ActiveEvent; import java.awt.Component; +import java.awt.Container; import java.awt.Dialog.ModalityType; +import java.awt.EventQueue; import java.awt.HeadlessException; +import java.awt.MenuComponent; +import java.awt.Toolkit; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseMotionAdapter; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; @@ -42,10 +49,15 @@ import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JInternalFrame; +import javax.swing.JLayeredPane; import javax.swing.JOptionPane; import javax.swing.JPanel; +import javax.swing.SwingUtilities; import javax.swing.UIManager; +import javax.swing.event.InternalFrameEvent; +import javax.swing.event.InternalFrameListener; +import jalview.util.ChannelProperties; import jalview.util.Platform; import jalview.util.dialogrunner.DialogRunnerI; @@ -54,23 +66,24 @@ public class JvOptionPane extends JOptionPane { private static final long serialVersionUID = -3019167117756785229L; - private static Object mockResponse = JOptionPane.CANCEL_OPTION; + private static Object mockResponse = JvOptionPane.CANCEL_OPTION; private static boolean interactiveMode = true; private Component parentComponent; - private Map callbacks = new HashMap<>(); + private Map> callbacks = new HashMap<>(); /* - * JalviewJS reports user choice in the dialog as the selected - * option (text); this list allows conversion to index (int) + * JalviewJS reports user choice in the dialog as the selected option (text); + * this list allows conversion to index (int) */ List ourOptions; public JvOptionPane(final Component parent) { this.parentComponent = Platform.isJS() ? this : parent; + this.setIcon(null); } public static int showConfirmDialog(Component parentComponent, @@ -102,17 +115,17 @@ public class JvOptionPane extends JOptionPane } switch (optionType) { - case JOptionPane.YES_NO_CANCEL_OPTION: + case JvOptionPane.YES_NO_CANCEL_OPTION: // FeatureRenderer amendFeatures ?? TODO ?? // Chimera close // PromptUserConfig // $FALL-THROUGH$ default: - case JOptionPane.YES_NO_OPTION: + case JvOptionPane.YES_NO_OPTION: // PromptUserConfig usage stats // for now treated as "OK CANCEL" // $FALL-THROUGH$ - case JOptionPane.OK_CANCEL_OPTION: + case JvOptionPane.OK_CANCEL_OPTION: // will fall back to simple HTML return JOptionPane.showConfirmDialog(parentComponent, message, title, optionType); @@ -200,13 +213,13 @@ public class JvOptionPane extends JOptionPane } switch (optionType) { - case JOptionPane.YES_NO_CANCEL_OPTION: + case JvOptionPane.YES_NO_CANCEL_OPTION: // ColourMenuHelper.addMenuItmers.offerRemoval TODO - case JOptionPane.YES_NO_OPTION: + case JvOptionPane.YES_NO_OPTION: // UserDefinedColoursSave -- relevant? TODO // $FALL-THROUGH$ default: - case JOptionPane.OK_CANCEL_OPTION: + case JvOptionPane.OK_CANCEL_OPTION: // EditNameDialog --- uses panel for messsage TODO @@ -235,13 +248,13 @@ public class JvOptionPane extends JOptionPane } switch (optionType) { - case JOptionPane.YES_NO_CANCEL_OPTION: - case JOptionPane.YES_NO_OPTION: + case JvOptionPane.YES_NO_CANCEL_OPTION: + case JvOptionPane.YES_NO_OPTION: // UserQuestionanaireCheck // VamsasApplication // $FALL-THROUGH$ default: - case JOptionPane.OK_CANCEL_OPTION: + case JvOptionPane.OK_CANCEL_OPTION: // will fall back to simple HTML return JOptionPane.showConfirmDialog(parentComponent, message, title, optionType, messageType); @@ -269,11 +282,11 @@ public class JvOptionPane extends JOptionPane } switch (optionType) { - case JOptionPane.YES_NO_CANCEL_OPTION: - case JOptionPane.YES_NO_OPTION: + case JvOptionPane.YES_NO_CANCEL_OPTION: + case JvOptionPane.YES_NO_OPTION: //$FALL-THROUGH$ default: - case JOptionPane.OK_CANCEL_OPTION: + case JvOptionPane.OK_CANCEL_OPTION: // Preferences editLink/newLink return JOptionPane.showConfirmDialog(parentComponent, message, title, optionType, messageType, icon); @@ -710,7 +723,7 @@ public class JvOptionPane extends JOptionPane public static void resetMock() { - setMockResponse(JOptionPane.CANCEL_OPTION); + setMockResponse(JvOptionPane.CANCEL_OPTION); setInteractiveMode(true); } @@ -733,10 +746,10 @@ public class JvOptionPane extends JOptionPane { switch (messageType) { - case JOptionPane.WARNING_MESSAGE: + case JvOptionPane.WARNING_MESSAGE: prefix = "WARNING! "; break; - case JOptionPane.ERROR_MESSAGE: + case JvOptionPane.ERROR_MESSAGE: prefix = "ERROR! "; break; default: @@ -777,13 +790,22 @@ public class JvOptionPane extends JOptionPane initialValue, true); } - public void showDialog(String message, String title, int optionType, + public void showDialog(Object message, String title, int optionType, int messageType, Icon icon, Object[] options, Object initialValue, boolean modal) { + showDialog(message, title, optionType, messageType, icon, options, + initialValue, modal, null); + } + + public void showDialog(Object message, String title, int optionType, + int messageType, Icon icon, Object[] options, Object initialValue, + boolean modal, JButton[] buttons) + { if (!isInteractiveMode()) { handleResponse(getMockResponse()); + return; } // two uses: // @@ -804,13 +826,102 @@ public class JvOptionPane extends JOptionPane if (modal) { + boolean useButtons = false; + Object initialValueButton = null; + NOTNULL: if (buttons != null) + { + if (buttons.length != options.length) + { + jalview.bin.Console.error( + "Supplied buttons array not the same length as supplied options array."); + break NOTNULL; + } + int[] buttonActions = { JOptionPane.YES_OPTION, + JOptionPane.NO_OPTION, JOptionPane.CANCEL_OPTION }; + for (int i = 0; i < options.length; i++) + { + Object o = options[i]; + jalview.bin.Console.debug( + "Setting button " + i + " to '" + o.toString() + "'"); + JButton jb = buttons[i]; + + if (o.equals(initialValue)) + initialValueButton = jb; + + int buttonAction = buttonActions[i]; + Callable action = callbacks.get(buttonAction); + jb.setText((String) o); + jb.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + + Object obj = e.getSource(); + if (obj == null || !(obj instanceof Component)) + { + jalview.bin.Console.debug( + "Could not find Component source of event object " + + obj); + return; + } + Object joptionpaneObject = SwingUtilities.getAncestorOfClass( + JOptionPane.class, (Component) obj); + if (joptionpaneObject == null + || !(joptionpaneObject instanceof JOptionPane)) + { + jalview.bin.Console.debug( + "Could not find JOptionPane ancestor of event object " + + obj); + return; + } + JOptionPane joptionpane = (JOptionPane) joptionpaneObject; + joptionpane.setValue(buttonAction); + if (action != null) + Executors.newSingleThreadExecutor().submit(action); + joptionpane.transferFocusBackward(); + joptionpane.setVisible(false); + // put focus and raise parent window if possible, unless cancel or + // no button pressed + boolean raiseParent = (parentComponent != null); + if (buttonAction == JOptionPane.CANCEL_OPTION) + raiseParent = false; + if (optionType == JOptionPane.YES_NO_OPTION + && buttonAction == JOptionPane.NO_OPTION) + raiseParent = false; + if (raiseParent) + { + parentComponent.requestFocus(); + if (parentComponent instanceof JInternalFrame) + { + JInternalFrame jif = (JInternalFrame) parentComponent; + jif.show(); + jif.moveToFront(); + jif.grabFocus(); + } + else if (parentComponent instanceof Window) + { + Window w = (Window) parentComponent; + w.toFront(); + w.requestFocus(); + } + } + joptionpane.setVisible(false); + } + }); + + } + useButtons = true; + } // use a JOptionPane as usual int response = JOptionPane.showOptionDialog(parentComponent, message, - title, optionType, messageType, icon, options, initialValue); + title, optionType, messageType, icon, + useButtons ? buttons : options, + useButtons ? initialValueButton : initialValue); /* - * In Java, the response is returned to this thread and handled here; - * (for Javascript, see propertyChange) + * In Java, the response is returned to this thread and handled here; (for + * Javascript, see propertyChange) */ if (!Platform.isJS()) /** @@ -825,16 +936,106 @@ public class JvOptionPane extends JOptionPane else { /* - * This is java similar to the swingjs handling, with the callbacks - * attached to the button press of the dialog. This means we can use - * a non-modal JDialog for the confirmation without blocking the GUI. + * This is java similar to the swingjs handling, with the callbacks attached to + * the button press of the dialog. This means we can use a non-modal JDialog for + * the confirmation without blocking the GUI. */ + JOptionPane joptionpane = new JOptionPane(); + // Make button options + int[] buttonActions = { JvOptionPane.YES_OPTION, + JvOptionPane.NO_OPTION, JvOptionPane.CANCEL_OPTION }; + + // we need the strings to make the buttons with actionEventListener + if (options == null) + { + ArrayList options_default = new ArrayList<>(); + options_default + .add(UIManager.getString("OptionPane.yesButtonText")); + if (optionType == JvOptionPane.YES_NO_OPTION + || optionType == JvOptionPane.YES_NO_CANCEL_OPTION) + { + options_default + .add(UIManager.getString("OptionPane.noButtonText")); + } + if (optionType == JvOptionPane.YES_NO_CANCEL_OPTION) + { + options_default + .add(UIManager.getString("OptionPane.cancelButtonText")); + } + options = options_default.toArray(); + } - JDialog dialog = this.createDialog(parentComponent, message, title, - optionType, messageType, icon, options, initialValue, modal); - jalview.bin.Console.debug("About to setVisible(true)"); + ArrayList options_btns = new ArrayList<>(); + Object initialValue_btn = null; + if (!Platform.isJS()) // JalviewJS already uses callback, don't need to + // add them here + { + for (int i = 0; i < options.length && i < 3; i++) + { + Object o = options[i]; + int buttonAction = buttonActions[i]; + Callable action = callbacks.get(buttonAction); + JButton jb = new JButton(); + jb.setText((String) o); + jb.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + joptionpane.setValue(buttonAction); + if (action != null) + Executors.newSingleThreadExecutor().submit(action); + // joptionpane.transferFocusBackward(); + joptionpane.transferFocusBackward(); + joptionpane.setVisible(false); + // put focus and raise parent window if possible, unless cancel + // button pressed + boolean raiseParent = (parentComponent != null); + if (buttonAction == JvOptionPane.CANCEL_OPTION) + raiseParent = false; + if (optionType == JvOptionPane.YES_NO_OPTION + && buttonAction == JvOptionPane.NO_OPTION) + raiseParent = false; + if (raiseParent) + { + parentComponent.requestFocus(); + if (parentComponent instanceof JInternalFrame) + { + JInternalFrame jif = (JInternalFrame) parentComponent; + jif.show(); + jif.moveToFront(); + jif.grabFocus(); + } + else if (parentComponent instanceof Window) + { + Window w = (Window) parentComponent; + w.toFront(); + w.requestFocus(); + } + } + joptionpane.setVisible(false); + } + }); + options_btns.add(jb); + if (o.equals(initialValue)) + initialValue_btn = jb; + } + } + joptionpane.setMessage(message); + joptionpane.setMessageType(messageType); + joptionpane.setOptionType(optionType); + joptionpane.setIcon(icon); + joptionpane.setOptions( + Platform.isJS() ? options : options_btns.toArray()); + joptionpane.setInitialValue( + Platform.isJS() ? initialValue : initialValue_btn); + + JDialog dialog = joptionpane.createDialog(parentComponent, title); + dialog.setIconImages(ChannelProperties.getIconList()); + dialog.setModalityType(modal ? ModalityType.APPLICATION_MODAL + : ModalityType.MODELESS); + dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); dialog.setVisible(true); - jalview.bin.Console.debug("Just setVisible(true)"); } } @@ -847,20 +1048,77 @@ public class JvOptionPane extends JOptionPane handleResponse(getMockResponse()); } + // need to set these separately so we can set the title bar icon later + this.setOptionType(yesNoCancelOption); + this.setMessageType(questionMessage); + this.setIcon(icon); + this.setInitialValue(initresponse); + this.setOptions(options); + this.setMessage(mainPanel); + ourOptions = Arrays.asList(options); int response; if (parentComponent != this) { - response = JOptionPane.showInternalOptionDialog(parentComponent, - mainPanel, title, yesNoCancelOption, questionMessage, icon, - options, initresponse); + JInternalFrame jif = this.createInternalFrame(parentComponent, title); + jif.setFrameIcon(null); + jif.addInternalFrameListener(new InternalFrameListener() + { + @Override + public void internalFrameActivated(InternalFrameEvent arg0) + { + } + + @Override + public void internalFrameClosed(InternalFrameEvent arg0) + { + JvOptionPane.this.internalDialogHandleResponse(); + } + + @Override + public void internalFrameClosing(InternalFrameEvent arg0) + { + } + + @Override + public void internalFrameDeactivated(InternalFrameEvent arg0) + { + } + + @Override + public void internalFrameDeiconified(InternalFrameEvent arg0) + { + } + + @Override + public void internalFrameIconified(InternalFrameEvent arg0) + { + } + + @Override + public void internalFrameOpened(InternalFrameEvent arg0) + { + } + }); + jif.setVisible(true); + startModal(jif); + return; } else { - response = JOptionPane.showOptionDialog(parentComponent, mainPanel, - title, yesNoCancelOption, questionMessage, icon, options, - initresponse); + JDialog dialog = this.createDialog(parentComponent, title); + dialog.setIconImages(ChannelProperties.getIconList()); + dialog.setVisible(true); // blocking + this.internalDialogHandleResponse(); + return; } + } + + private void internalDialogHandleResponse() + { + String responseString = (String) this.getValue(); + int response = ourOptions.indexOf(responseString); + if (!Platform.isJS()) /** * Java only @@ -873,23 +1131,15 @@ public class JvOptionPane extends JOptionPane } /* + * @Override public JvOptionPane setResponseHandler(Object response, Runnable + * action) { callbacks.put(response, new Callable() { + * + * @Override public Void call() { action.run(); return null; } }); return this; + * } + */ @Override - public JvOptionPane setResponseHandler(Object response, Runnable action) - { - callbacks.put(response, new Callable() - { - @Override - public Void call() - { - action.run(); - return null; - } - }); - return this; - } - */ - @Override - public JvOptionPane setResponseHandler(Object response, Callable action) + public JvOptionPane setResponseHandler(Object response, + Callable action) { callbacks.put(response, action); return this; @@ -902,6 +1152,10 @@ public class JvOptionPane extends JOptionPane public static int showDialogOnTop(String label, String actionString, int JOPTIONPANE_OPTION, int JOPTIONPANE_MESSAGETYPE) { + if (!isInteractiveMode()) + { + return (int) getMockResponse(); + } // Ensure Jalview window is brought to front (primarily for Quit // confirmation window to be visible) @@ -912,15 +1166,14 @@ public class JvOptionPane extends JOptionPane // A better hack which works is to create a new JFrame parent with // setAlwaysOnTop(true) JFrame dialogParent = new JFrame(); + dialogParent.setIconImages(ChannelProperties.getIconList()); dialogParent.setAlwaysOnTop(true); int answer = JOptionPane.showConfirmDialog(dialogParent, label, actionString, JOPTIONPANE_OPTION, JOPTIONPANE_MESSAGETYPE); dialogParent.setAlwaysOnTop(false); - jalview.bin.Console.debug("*********** BEFORE dialogParent.dispose()"); dialogParent.dispose(); - jalview.bin.Console.debug("*********** BEFORE dialogParent.dispose()"); return answer; } @@ -929,6 +1182,32 @@ public class JvOptionPane extends JOptionPane int JOPTIONPANE_OPTION, int JOPTIONPANE_MESSAGETYPE, Icon icon, Object[] options, Object initialValue, boolean modal) { + JFrame frame = new JFrame(); + frame.setIconImages(ChannelProperties.getIconList()); + showDialogOnTopAsync(frame, label, actionString, JOPTIONPANE_OPTION, + JOPTIONPANE_MESSAGETYPE, icon, options, initialValue, modal); + } + + public void showDialogOnTopAsync(JFrame dialogParent, Object label, + String actionString, int JOPTIONPANE_OPTION, + int JOPTIONPANE_MESSAGETYPE, Icon icon, Object[] options, + Object initialValue, boolean modal) + { + showDialogOnTopAsync(dialogParent, label, actionString, + JOPTIONPANE_OPTION, JOPTIONPANE_MESSAGETYPE, icon, options, + initialValue, modal, null); + } + + public void showDialogOnTopAsync(JFrame dialogParent, Object label, + String actionString, int JOPTIONPANE_OPTION, + int JOPTIONPANE_MESSAGETYPE, Icon icon, Object[] options, + Object initialValue, boolean modal, JButton[] buttons) + { + if (!isInteractiveMode()) + { + handleResponse(getMockResponse()); + return; + } // Ensure Jalview window is brought to front (primarily for Quit // confirmation window to be visible) @@ -938,12 +1217,12 @@ public class JvOptionPane extends JOptionPane // A better hack which works is to create a new JFrame parent with // setAlwaysOnTop(true) - JFrame dialogParent = new JFrame(); dialogParent.setAlwaysOnTop(true); parentComponent = dialogParent; showDialog(label, actionString, JOPTIONPANE_OPTION, - JOPTIONPANE_MESSAGETYPE, icon, options, initialValue, modal); + JOPTIONPANE_MESSAGETYPE, icon, options, initialValue, modal, + buttons); dialogParent.setAlwaysOnTop(false); dialogParent.dispose(); @@ -976,8 +1255,8 @@ public class JvOptionPane extends JOptionPane public void handleResponse(Object response) { /* - * this test is for NaN in Chrome - */ + * this test is for NaN in Chrome + */ if (response != null && !response.equals(response)) { return; @@ -1000,10 +1279,26 @@ public class JvOptionPane extends JOptionPane /** * Create a non-modal confirm dialog */ - public JDialog createDialog(Component parentComponent, String message, + public JDialog createDialog(Component parentComponent, Object message, String title, int optionType, int messageType, Icon icon, Object[] options, Object initialValue, boolean modal) { + return createDialog(parentComponent, message, title, optionType, + messageType, icon, options, initialValue, modal, null); + } + + public JDialog createDialog(Component parentComponent, Object message, + String title, int optionType, int messageType, Icon icon, + Object[] options, Object initialValue, boolean modal, + JButton[] buttons) + { + if (!isInteractiveMode()) + { + handleResponse(getMockResponse()); + return null; + } + JButton[] optionsButtons = null; + Object initialValueButton = null; JOptionPane joptionpane = new JOptionPane(); // Make button options int[] buttonActions = { JOptionPane.YES_OPTION, JOptionPane.NO_OPTION, @@ -1026,26 +1321,39 @@ public class JvOptionPane extends JOptionPane } options = options_default.toArray(); } - ArrayList options_btns = new ArrayList<>(); - Object initialValue_btn = null; if (!Platform.isJS()) // JalviewJS already uses callback, don't need to // add them here { - if (((optionType == JOptionPane.YES_NO_OPTION - || optionType == JOptionPane.OK_CANCEL_OPTION) - && options.length < 2) + if (((optionType == JOptionPane.YES_OPTION + || optionType == JOptionPane.NO_OPTION + || optionType == JOptionPane.CANCEL_OPTION + || optionType == JOptionPane.OK_OPTION + || optionType == JOptionPane.DEFAULT_OPTION) + && options.length < 1) + || ((optionType == JOptionPane.YES_NO_OPTION + || optionType == JOptionPane.OK_CANCEL_OPTION) + && options.length < 2) || (optionType == JOptionPane.YES_NO_CANCEL_OPTION && options.length < 3)) { jalview.bin.Console .debug("JvOptionPane: not enough options for dialog type"); } + optionsButtons = new JButton[options.length]; for (int i = 0; i < options.length && i < 3; i++) { Object o = options[i]; int buttonAction = buttonActions[i]; - Callable action = callbacks.get(buttonAction); - JButton jb = new JButton(); + Callable action = callbacks.get(buttonAction); + JButton jb; + if (buttons != null && buttons.length > i && buttons[i] != null) + { + jb = buttons[i]; + } + else + { + jb = new JButton(); + } jb.setText((String) o); jb.addActionListener(new ActionListener() { @@ -1086,21 +1394,21 @@ public class JvOptionPane extends JOptionPane joptionpane.setVisible(false); } }); - options_btns.add(jb); + optionsButtons[i] = jb; if (o.equals(initialValue)) - initialValue_btn = jb; + initialValueButton = jb; } } joptionpane.setMessage(message); joptionpane.setMessageType(messageType); joptionpane.setOptionType(optionType); joptionpane.setIcon(icon); - joptionpane - .setOptions(Platform.isJS() ? options : options_btns.toArray()); + joptionpane.setOptions(Platform.isJS() ? options : optionsButtons); joptionpane.setInitialValue( - Platform.isJS() ? initialValue : initialValue_btn); + Platform.isJS() ? initialValue : initialValueButton); JDialog dialog = joptionpane.createDialog(parentComponent, title); + dialog.setIconImages(ChannelProperties.getIconList()); dialog.setModalityType( modal ? ModalityType.APPLICATION_MODAL : ModalityType.MODELESS); dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); @@ -1117,4 +1425,78 @@ public class JvOptionPane extends JOptionPane return false; } + + /** + * This helper method makes the JInternalFrame wait until it is notified by an + * InternalFrameClosing event. This method also adds the given JOptionPane to + * the JInternalFrame and sizes it according to the JInternalFrame's preferred + * size. + * + * @param f + * The JInternalFrame to make modal. + */ + private static void startModal(JInternalFrame f) + { + // We need to add an additional glasspane-like component directly + // below the frame, which intercepts all mouse events that are not + // directed at the frame itself. + JPanel modalInterceptor = new JPanel(); + modalInterceptor.setOpaque(false); + JLayeredPane lp = JLayeredPane.getLayeredPaneAbove(f); + lp.setLayer(modalInterceptor, JLayeredPane.MODAL_LAYER.intValue()); + modalInterceptor.setBounds(0, 0, lp.getWidth(), lp.getHeight()); + modalInterceptor.addMouseListener(new MouseAdapter() + { + }); + modalInterceptor.addMouseMotionListener(new MouseMotionAdapter() + { + }); + lp.add(modalInterceptor); + f.toFront(); + + // We need to explicitly dispatch events when we are blocking the event + // dispatch thread. + EventQueue queue = Toolkit.getDefaultToolkit().getSystemEventQueue(); + try + { + while (!f.isClosed()) + { + if (EventQueue.isDispatchThread()) + { + // The getNextEventMethod() issues wait() when no + // event is available, so we don't need do explicitly wait(). + AWTEvent ev = queue.getNextEvent(); + // This mimics EventQueue.dispatchEvent(). We can't use + // EventQueue.dispatchEvent() directly, because it is + // protected, unfortunately. + if (ev instanceof ActiveEvent) + ((ActiveEvent) ev).dispatch(); + else if (ev.getSource() instanceof Component) + ((Component) ev.getSource()).dispatchEvent(ev); + else if (ev.getSource() instanceof MenuComponent) + ((MenuComponent) ev.getSource()).dispatchEvent(ev); + // Other events are ignored as per spec in + // EventQueue.dispatchEvent + } + else + { + // Give other threads a chance to become active. + Thread.yield(); + } + } + } catch (InterruptedException ex) + { + // If we get interrupted, then leave the modal state. + } finally + { + // Clean up the modal interceptor. + lp.remove(modalInterceptor); + + // Remove the internal frame from its parent, so it is no longer + // lurking around and clogging memory. + Container parent = f.getParent(); + if (parent != null) + parent.remove(f); + } + } }