View Javadoc

1   /*
2    *  XNap Commons
3    *
4    *  Copyright (C) 2005  Steffen Pingel
5    *
6    *  This library is free software; you can redistribute it and/or
7    *  modify it under the terms of the GNU Lesser General Public
8    *  License as published by the Free Software Foundation; either
9    *  version 2.1 of the License, or (at your option) any later version.
10   *
11   *  This library is distributed in the hope that it will be useful,
12   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   *  Lesser General Public License for more details.
15   *
16   *  You should have received a copy of the GNU Lesser General Public
17   *  License along with this library; if not, write to the Free Software
18   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19   */
20  package org.xnap.commons.gui.shortcut;
21  
22  import java.awt.BorderLayout;
23  import java.awt.Event;
24  import java.awt.FlowLayout;
25  import java.awt.event.ActionEvent;
26  import java.awt.event.ActionListener;
27  import java.awt.event.FocusAdapter;
28  import java.awt.event.FocusEvent;
29  import java.awt.event.ItemEvent;
30  import java.awt.event.ItemListener;
31  import java.awt.event.KeyAdapter;
32  import java.awt.event.KeyEvent;
33  import javax.swing.AbstractAction;
34  import javax.swing.Action;
35  import javax.swing.JCheckBox;
36  import javax.swing.JPanel;
37  import javax.swing.JToggleButton;
38  import javax.swing.KeyStroke;
39  import javax.swing.event.ChangeEvent;
40  import javax.swing.event.ChangeListener;
41  import org.xnap.commons.gui.Builder;
42  import org.xnap.commons.i18n.I18n;
43  import org.xnap.commons.i18n.I18nFactory;
44  
45  /***
46   * A panel to enter a keystroke.
47   * 
48   * @author Steffen Pingel
49   */
50  public class KeyStrokePanel extends JPanel implements ActionListener {
51      
52  	private static I18n i18n = I18nFactory.getI18n(KeyStrokePanel.class);
53  	
54  	public static String toString(KeyStroke stroke)
55  	{
56  		StringBuilder sb = new StringBuilder();
57  
58  		int m = stroke.getModifiers();
59  		if ((m & Event.CTRL_MASK) != 0) {
60  			sb.append(KeyEvent.getKeyModifiersText(Event.CTRL_MASK));
61  			sb.append("+");
62  		}
63  		if ((m & Event.ALT_MASK) != 0) {
64  			sb.append(KeyEvent.getKeyModifiersText(Event.ALT_MASK));
65  			sb.append("+");
66  		}
67  		if ((m & Event.META_MASK) != 0) {
68  			sb.append(KeyEvent.getKeyModifiersText(Event.META_MASK));
69  			sb.append("+");
70  		}
71  		if ((m & Event.SHIFT_MASK) != 0) {
72  			sb.append(KeyEvent.getKeyModifiersText(Event.SHIFT_MASK));
73  			sb.append("+");
74  		}
75  		sb.append(KeyEvent.getKeyText(stroke.getKeyCode()));
76  		return sb.toString();
77  	}
78  	
79      private JCheckBox altCheckBox;
80  	protected transient ChangeEvent changeEvent;
81  	private JToggleButton charButton;
82  	private JCheckBox ctrlCheckBox;
83  	private KeyStroke defaultKeyStroke;
84  	private int keyCode;
85  	private CharButtonListener keyListener = new CharButtonListener();
86      private JCheckBox metaCheckBox;
87      private JCheckBox shiftCheckBox;
88  	private DefaultAction defaultAction;
89  	private NoneAction noneAction;
90  
91  	public KeyStrokePanel()
92      {
93  		defaultAction = new DefaultAction();
94  		noneAction = new NoneAction();
95  		
96  		setLayout(new BorderLayout());
97  
98  		// check boxes
99  		JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
100 		add(topPanel, BorderLayout.NORTH);
101 		
102 		ctrlCheckBox 
103 			= new JCheckBox(KeyEvent.getKeyModifiersText(Event.CTRL_MASK));
104 		ctrlCheckBox.addActionListener(this);
105 		topPanel.add(ctrlCheckBox);
106 
107 		altCheckBox 
108 			= new JCheckBox(KeyEvent.getKeyModifiersText(Event.ALT_MASK));
109 		altCheckBox.addActionListener(this);
110 		topPanel.add(altCheckBox);
111 
112 		metaCheckBox
113 			= new JCheckBox(KeyEvent.getKeyModifiersText(Event.META_MASK));
114 		metaCheckBox.addActionListener(this);
115 		topPanel.add(metaCheckBox);
116 		
117 		shiftCheckBox
118 			= new JCheckBox(KeyEvent.getKeyModifiersText(Event.SHIFT_MASK));
119 		shiftCheckBox.addActionListener(this);
120 		topPanel.add(shiftCheckBox);
121 
122 		charButton = new JToggleButton(" ");
123 		charButton.addItemListener(new ItemListener() {
124 			public void itemStateChanged(ItemEvent event)
125 			{
126 				if (event.getStateChange() == ItemEvent.SELECTED) {
127 					// record the key that is pressed next
128 					charButton.addKeyListener(keyListener);
129 				}
130 				else {
131 					charButton.removeKeyListener(keyListener);
132 					fireChangeEvent();
133 				}
134 			}
135 		});
136 		charButton.addFocusListener(new UntoggleListener());
137 		topPanel.add(charButton);
138 		
139 		// buttons
140 		JPanel bottomPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
141 		add(bottomPanel, BorderLayout.SOUTH);
142 		
143 		bottomPanel.add(Builder.createButton(defaultAction));
144 		bottomPanel.add(Builder.createButton(noneAction));
145     }
146 
147     /***
148 	 *  @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
149 	 */
150 	public void actionPerformed(ActionEvent e)
151 	{
152 		fireChangeEvent();
153 	}
154     
155     public void addChangeListener(ChangeListener l) 
156     {
157         listenerList.add(ChangeListener.class, l);
158     }
159 
160     protected void fireChangeEvent() {
161         Object[] listeners = listenerList.getListenerList();
162 
163         for (int i = listeners.length - 2; i >= 0; i -= 2) {
164             if (listeners[i] == ChangeListener.class) {
165 				// Lazily create the event:
166                 if (changeEvent == null) {
167                     changeEvent = new ChangeEvent(this);
168                 }
169                 ((ChangeListener)listeners[i + 1]).stateChanged(changeEvent);
170             }          
171         }
172     }   
173 
174     public KeyStroke getKeyStroke()
175 	{
176     	if (keyCode == KeyEvent.VK_UNDEFINED) {
177 			return null;
178     	}
179     	else {
180     		int m = 0;
181     		m |= (ctrlCheckBox.isSelected()) ? Event.CTRL_MASK : 0;
182     		m |= (altCheckBox.isSelected()) ? Event.ALT_MASK : 0;
183     		m |= (metaCheckBox.isSelected()) ? Event.META_MASK : 0;
184     		m |= (shiftCheckBox.isSelected()) ? Event.SHIFT_MASK : 0;
185     		return KeyStroke.getKeyStroke(keyCode, m);
186     	}
187     }
188     
189     public void removeChangeListener(ChangeListener l) 
190     {
191         listenerList.remove(ChangeListener.class, l);
192     }
193 
194     @Override
195     public void setEnabled(boolean enabled)
196     {
197     	super.setEnabled(enabled);
198 
199 		ctrlCheckBox.setEnabled(enabled);
200 		altCheckBox.setEnabled(enabled);
201 		metaCheckBox.setEnabled(enabled);
202 		shiftCheckBox.setEnabled(enabled);
203 		charButton.setEnabled(enabled);
204 		
205 		defaultAction.setEnabled(enabled);
206 		noneAction.setEnabled(enabled);
207     }
208     
209 	public void setDefaultKeyStroke(KeyStroke defaultKeyStroke)
210 	{
211 		this.defaultKeyStroke = defaultKeyStroke;
212 	}
213 
214 	public void setKeyStroke(KeyStroke keyStroke)
215 	{
216 		if (keyStroke != null) {
217 			int m = keyStroke.getModifiers();
218 			ctrlCheckBox.setSelected((m & Event.CTRL_MASK) != 0);
219 			altCheckBox.setSelected((m & Event.ALT_MASK) != 0);
220 			metaCheckBox.setSelected((m & Event.META_MASK) != 0);
221 			shiftCheckBox.setSelected((m & Event.SHIFT_MASK) != 0);
222 			keyCode = keyStroke.getKeyCode();
223 			charButton.setText(KeyEvent.getKeyText(keyCode));
224 		}
225 		else {
226 			ctrlCheckBox.setSelected(false);
227 			altCheckBox.setSelected(false);
228 			metaCheckBox.setSelected(false);
229 			shiftCheckBox.setSelected(false);
230 			charButton.setText(" ");
231 			keyCode = KeyEvent.VK_UNDEFINED;
232 		}
233 	}
234 
235 	private class CharButtonListener extends KeyAdapter {
236 
237 		public void keyPressed(KeyEvent e) 
238 		{
239 			keyCode = e.getKeyCode();
240 			
241 			charButton.setSelected(false);
242 			charButton.setText(KeyEvent.getKeyText(keyCode));
243 			//  charButton.setText(KeyStroke.getKeyStrokeForEvent(e).toString());
244 		}
245 
246 	}
247 
248     /***
249      * Reperforms a search.
250      */
251     private class DefaultAction extends AbstractAction {
252 
253         public DefaultAction() 
254 		{
255             putValue(Action.NAME, i18n.tr("Default"));
256             putValue(Action.SHORT_DESCRIPTION, i18n.tr("Reset to default"));
257         }
258 
259         public void actionPerformed(ActionEvent event) 
260 		{
261 			setKeyStroke(defaultKeyStroke);
262 			fireChangeEvent();
263         }
264     }
265 
266     /***
267      * Reperforms a search.
268      */
269     private class NoneAction extends AbstractAction {
270 
271         public NoneAction() 
272 		{
273             putValue(Action.NAME, i18n.tr("None"));
274             putValue(Action.SHORT_DESCRIPTION,
275 					 i18n.tr("Assigns no keystroke"));
276         }
277 
278         public void actionPerformed(ActionEvent event) 
279 		{
280         	setKeyStroke(null);
281 			fireChangeEvent();
282 		}
283         
284     }
285 
286 	private class UntoggleListener extends FocusAdapter {
287 
288 		public void focusLost(FocusEvent e)
289 		{
290 			charButton.setSelected(false);
291 		}
292 
293 	}
294 
295 }