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}