001/**
002 * Please feel free to use any fragment of the code in this file that you need in your own
003 * work. As far as I am concerned, it's in the public domain. No permission is necessary
004 * or required. Credit is always appreciated if you use a large chunk or base a
005 * significant product on one of my examples, but that's not required either.
006 *
007 * This code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
008 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
009 * PURPOSE.
010 *
011 * --- Joseph A. Huwaldt
012 */
013package jahuwaldt.swing;
014
015import java.awt.*;
016import java.awt.event.*;
017import javax.swing.*;
018
019/**
020 * A dialog that responds to the user pressing the escape or enter keys for default
021 * buttons (cancel and OK).
022 *
023 * <p> Modified by: Joseph A. Huwaldt </p>
024 *
025 * @author Unknown, Date: August 31, 2000
026 * @version October 26, 2016
027 */
028@SuppressWarnings("serial")
029public class EscapeJDialog extends JDialog implements ContainerListener, KeyListener {
030
031    @SuppressWarnings("LeakingThisInConstructor")
032    public EscapeJDialog(Component parentComponent, String title) {
033        super(AppUtilities.getFrameForComponent(parentComponent), title);
034        addKeyAndContainerListenerRecursively(this);
035    }
036
037    @SuppressWarnings("LeakingThisInConstructor")
038    public EscapeJDialog(Component parentComponent, String title, boolean model) {
039        super(AppUtilities.getFrameForComponent(parentComponent), title, model);
040        addKeyAndContainerListenerRecursively(this);
041    }
042
043    /**
044     * The following function is recursive and is intended for internal use only.
045     *
046     * The function takes a Component as an argument and adds this JFrame as a KeyListener
047     * to it.
048     *
049     * Besides it checks if the component is actually a Container and if it is, there are
050     * 2 additional things to be done to this Container: 1 - add this JFrame as a
051     * ContainerListener to the Container 2 - call this function recursively for every
052     * child of the Container.
053     */
054    private void addKeyAndContainerListenerRecursively(Component c) {
055        //  To be on the safe side, try to remove KeyListener first just in case
056        //  it has been added before.  If not, it won't do any harm.
057        c.removeKeyListener(this);
058
059        //  Add KeyListener to the Component passed as an argument
060        c.addKeyListener(this);
061
062        if (c instanceof Container) {
063
064            //  Component c is a Container. The following cast is safe.
065            Container cont = (Container)c;
066
067            //  To be on the safe side, try to remove ContainerListener
068            //  first just in case it has been added before.
069            //  If not, it won't do any harm.
070            cont.removeContainerListener(this);
071            //  Add ContainerListener to the Container.
072            cont.addContainerListener(this);
073
074            //  Get the Container's array of children Components.
075            Component[] children = cont.getComponents();
076
077            //  For every child repeat the above operation.
078            for (Component children1 : children)
079                addKeyAndContainerListenerRecursively(children1);
080        }
081    }
082
083    /**
084     * The following function is the same as the function above with the exception that it
085     * does exactly the opposite - removes this Dialog from the listener lists of
086     * Components.
087     */
088    private void removeKeyAndContainerListenerRecursively(Component c) {
089        c.removeKeyListener(this);
090
091        if (c instanceof Container) {
092            Container cont = (Container)c;
093
094            cont.removeContainerListener(this);
095
096            Component[] children = cont.getComponents();
097
098            for (Component children1 : children)
099                removeKeyAndContainerListenerRecursively(children1);
100        }
101    }
102
103    /*
104     * ContainerListener interface
105     */
106    /**
107     * This function is called whenever a Component or a Container is added to another
108     * Container belonging to this JFrame.
109     *
110     * @param e The event that caused this method to be called.
111     */
112    @Override
113    public void componentAdded(ContainerEvent e) {
114        addKeyAndContainerListenerRecursively(e.getChild());
115    }
116
117    /**
118     * This function is called whenever a Component or a Container is removed from another
119     * Container belonging to this JFrame.
120     *
121     * @param e The even that caused this method to be called.
122     */
123    @Override
124    public void componentRemoved(ContainerEvent e) {
125        removeKeyAndContainerListenerRecursively(e.getChild());
126    }
127
128    /*
129     * KeyListener interface
130     */
131    /**
132     * This function is called whenever a Component belonging to this JFrame (or the
133     * JFrame itself) gets the KEY_PRESSED event.
134     *
135     * @param e The event that caused this method to be called.
136     */
137    @Override
138    public void keyPressed(KeyEvent e) {
139        int code = e.getKeyCode();
140        if (code == KeyEvent.VK_ESCAPE) {
141            //  Key pressed is the ESCAPE key. Redefine performEscapeAction()
142            //  in subclasses to respond to depressing the ENTER key.
143            performEscapeAction(e);
144
145        } else if (code == KeyEvent.VK_ENTER) {
146            //  Key pressed is the ENTER key. Redefine performEnterAction()
147            //  in subclasses to respond to depressing the ENTER key.
148            performEnterAction(e);
149        }
150
151        //  Insert code to process other keys here
152    }
153
154    //  We need the following 2 functions to complete imlementation of KeyListener
155    @Override
156    public void keyReleased(KeyEvent e) {
157    }
158
159    @Override
160    public void keyTyped(KeyEvent e) {
161    }
162
163    /**
164     * *********************************************************
165     */
166    /**
167     * Response to ENTER key pressed goes here. The default implementation selects the
168     * default button for the root pane of this frame. Redefine this function in
169     * subclasses to respond to ENTER key differently.
170     *
171     * @param e The even that caused this method to be called.
172     */
173    protected void performEnterAction(KeyEvent e) {
174        JButton btn = this.getRootPane().getDefaultButton();
175        if (btn != null)
176            btn.doClick();
177    }
178
179    /**
180     * Response to ESCAPE key pressed goes here. The default implementation closes the
181     * window/frame by dispatching a "WINDOW_CLOSING" event. Redefine this function in
182     * subclasses to respond to ESCAPE key differently.
183     *
184     * @param e The event that caused this method to be called.
185     */
186    protected void performEscapeAction(KeyEvent e) {
187        //setVisible(false);    //  Doesn't call event handlers.
188
189        //  Use this instead.
190        this.dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
191    }
192
193}