2015-05-05 Yvan Roux <yvan.roux@linaro.org>
[official-gcc.git] / libjava / classpath / javax / swing / KeyboardManager.java
blob5c1c09eab39ba8477585341244182abf1ee369ac
1 /* KeyboardManager.java --
2 Copyright (C) 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package javax.swing;
41 import java.applet.Applet;
42 import java.awt.Component;
43 import java.awt.Container;
44 import java.awt.Window;
45 import java.awt.event.KeyEvent;
46 import java.util.Enumeration;
47 import java.util.Hashtable;
48 import java.util.Vector;
49 import java.util.WeakHashMap;
51 /**
52 * This class maintains a mapping from top-level containers to a
53 * Hashtable. The Hashtable maps KeyStrokes to Components to be used when
54 * Components register keyboard actions with the condition
55 * JComponent.WHEN_IN_FOCUSED_WINDOW.
57 * @author Anthony Balkissoon abalkiss at redhat dot com
60 class KeyboardManager
62 /** Shared instance of KeyboardManager **/
63 static KeyboardManager manager = new KeyboardManager();
65 /**
66 * A mapping between top level containers and Hashtables that
67 * map KeyStrokes to Components.
69 WeakHashMap topLevelLookup = new WeakHashMap();
71 /**
72 * A mapping between top level containers and Vectors of JMenuBars
73 * used to allow all the JMenuBars within a top level container
74 * a chance to consume key events.
76 Hashtable menuBarLookup = new Hashtable();
77 /**
78 * Returns the shared instance of KeyboardManager.
79 * @return the shared instance of KeybaordManager.
81 public static KeyboardManager getManager()
83 return manager;
85 /**
86 * Returns the top-level ancestor for the given JComponent.
87 * @param c the JComponent whose top-level ancestor we want
88 * @return the top-level ancestor for the given JComponent.
90 static Container findTopLevel (Component c)
92 Container topLevel = (c instanceof Container) ? (Container) c
93 : c.getParent();
94 while (topLevel != null &&
95 !(topLevel instanceof Window) &&
96 !(topLevel instanceof Applet) &&
97 !(topLevel instanceof JInternalFrame))
98 topLevel = topLevel.getParent();
99 return topLevel;
103 * Returns the Hashtable that maps KeyStrokes to Components, for
104 * the specified top-level container c. If no Hashtable exists
105 * we create and register it here and return the newly created
106 * Hashtable.
108 * @param c the top-level container whose Hashtable we want
109 * @return the Hashtable mapping KeyStrokes to Components for the
110 * specified top-level container
112 Hashtable getHashtableForTopLevel (Container c)
114 Hashtable keyToComponent = (Hashtable)topLevelLookup.get(c);
115 if (keyToComponent == null)
117 keyToComponent = new Hashtable();
118 topLevelLookup.put(c, keyToComponent);
120 return keyToComponent;
124 * Registers a KeyStroke with a Component. This does not register
125 * the KeyStroke to a specific Action. When searching for a
126 * WHEN_IN_FOCUSED_WINDOW binding we will first go up to the focused
127 * top-level Container, then get the Hashtable that maps KeyStrokes
128 * to components for that particular top-level Container, then
129 * call processKeyBindings on that component with the condition
130 * JComponent.WHEN_IN_FOCUSED_WINDOW.
131 * @param comp the JComponent associated with the KeyStroke
132 * @param key the KeyStroke
134 public void registerBinding(JComponent comp, KeyStroke key)
136 // This method associates a KeyStroke with a particular JComponent
137 // When the KeyStroke occurs, if this component's top-level ancestor
138 // has focus (one of its children is the focused Component) then
139 // comp.processKeyBindings will be called with condition
140 // JComponent.WHEN_IN_FOCUSED_WINDOW.
142 // Look for the JComponent's top-level parent and return if it is null
143 Container topLevel = findTopLevel(comp);
144 if (topLevel == null)
145 return;
147 // Now get the Hashtable for this top-level container
148 Hashtable keyToComponent = getHashtableForTopLevel(topLevel);
150 // And add the new binding to this Hashtable
151 // FIXME: should allow more than one JComponent to be associated
152 // with a KeyStroke, in case one of them is disabled
153 keyToComponent.put(key, comp);
156 public void clearBindingsForComp(JComponent comp)
158 // This method clears all the WHEN_IN_FOCUSED_WINDOW bindings associated
159 // with <code>comp</code>. This is used for a terribly ineffcient
160 // strategy in which JComponent.updateComponentInputMap simply clears
161 // all bindings associated with its component and then reloads all the
162 // bindings from the updated ComponentInputMap. This is only a preliminary
163 // strategy and should be improved upon once the WHEN_IN_FOCUSED_WINDOW
164 // bindings work.
166 // Find the top-level ancestor
168 Container topLevel = findTopLevel(comp);
169 if (topLevel == null)
170 return;
171 // And now get its Hashtable
172 Hashtable keyToComponent = getHashtableForTopLevel(topLevel);
174 Enumeration keys = keyToComponent.keys();
175 Object temp;
177 // Iterate through the keys and remove any key whose value is comp
178 while (keys.hasMoreElements())
180 temp = keys.nextElement();
181 if (comp == (JComponent)keyToComponent.get(temp))
182 keyToComponent.remove(temp);
187 * This method registers all the bindings in the given ComponentInputMap.
188 * Rather than call registerBinding on all the keys, we do the work here
189 * so that we don't duplicate finding the top-level container and
190 * getting its Hashtable.
192 * @param map the ComponentInputMap whose bindings we want to register
194 public void registerEntireMap (ComponentInputMap map)
196 if (map == null)
197 return;
198 JComponent comp = map.getComponent();
199 KeyStroke[] keys = map.allKeys();
200 if (keys == null)
201 return;
202 // Find the top-level container associated with this ComponentInputMap
203 Container topLevel = findTopLevel(comp);
204 if (topLevel == null)
205 return;
207 // Register the KeyStrokes in the top-level container's Hashtable
208 Hashtable keyToComponent = getHashtableForTopLevel(topLevel);
209 for (int i = 0; i < keys.length; i++)
210 keyToComponent.put(keys[i], comp);
213 public boolean processKeyStroke (Component comp, KeyStroke key, KeyEvent e)
215 boolean pressed = e.getID() == KeyEvent.KEY_PRESSED;
217 // Look for the top-level ancestor
218 Container topLevel = findTopLevel(comp);
219 if (topLevel == null)
220 return false;
221 // Now get the Hashtable for that top-level container
222 Hashtable keyToComponent = getHashtableForTopLevel(topLevel);
223 Enumeration keys = keyToComponent.keys();
224 JComponent target = (JComponent)keyToComponent.get(key);
225 if (target != null && target.processKeyBinding
226 (key, e, JComponent.WHEN_IN_FOCUSED_WINDOW, pressed))
227 return true;
229 // Have to give all the JMenuBars a chance to consume the event
230 Vector menuBars = getVectorForTopLevel(topLevel);
231 for (int i = 0; i < menuBars.size(); i++)
232 if (((JMenuBar)menuBars.elementAt(i)).processKeyBinding(key, e, JComponent.WHEN_IN_FOCUSED_WINDOW, pressed))
233 return true;
234 return false;
238 * Returns the Vector of JMenuBars associated with the top-level
239 * @param c the top-level container whose JMenuBar Vector we want
240 * @return the Vector of JMenuBars for this top level container
242 Vector getVectorForTopLevel(Container c)
244 Vector result = (Vector) menuBarLookup.get(c);
245 if (result == null)
247 result = new Vector();
248 menuBarLookup.put (c, result);
250 return result;
254 * In processKeyStroke, KeyManager must give all JMenuBars in the
255 * focused top-level container a chance to process the event. So,
256 * JMenuBars must be registered in KeyManager and associated with a
257 * top-level container. That's what this method is for.
258 * @param menuBar the JMenuBar to register
260 public void registerJMenuBar (JMenuBar menuBar)
262 Container topLevel = findTopLevel(menuBar);
263 Vector menuBars = getVectorForTopLevel(topLevel);
264 if (!menuBars.contains(menuBar))
265 menuBars.add(menuBar);
269 * Unregisters a JMenuBar from its top-level container. This is
270 * called before the JMenuBar is actually removed from the container
271 * so findTopLevel will still find us the correct top-level container.
272 * @param menuBar the JMenuBar to unregister.
274 public void unregisterJMenuBar (JMenuBar menuBar)
276 Container topLevel = findTopLevel(menuBar);
277 Vector menuBars = getVectorForTopLevel(topLevel);
278 if (menuBars.contains(menuBar))
279 menuBars.remove(menuBar);