History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/swing/KeyboardManager.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/swing/KeyboardManager.java+391−0
@@ -0,0 +1,391 @@
1+/*
2+ * Copyright (c) 1998, 2009, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+package javax.swing;
26+
27+
28+import java.util.*;
29+import java.awt.*;
30+import java.awt.event.*;
31+import java.applet.*;
32+import java.beans.*;
33+import javax.swing.event.*;
34+import sun.awt.EmbeddedFrame;
35+
36+/**
37+ * The KeyboardManager class is used to help dispatch keyboard actions for the
38+ * WHEN_IN_FOCUSED_WINDOW style actions. Actions with other conditions are handled
39+ * directly in JComponent.
40+ *
41+ * Here's a description of the symantics of how keyboard dispatching should work
42+ * atleast as I understand it.
43+ *
44+ * KeyEvents are dispatched to the focused component. The focus manager gets first
45+ * crack at processing this event. If the focus manager doesn't want it, then
46+ * the JComponent calls super.processKeyEvent() this allows listeners a chance
47+ * to process the event.
48+ *
49+ * If none of the listeners "consumes" the event then the keybindings get a shot.
50+ * This is where things start to get interesting. First, KeyStokes defined with the
51+ * WHEN_FOCUSED condition get a chance. If none of these want the event, then the component
52+ * walks though it's parents looked for actions of type WHEN_ANCESTOR_OF_FOCUSED_COMPONENT.
53+ *
54+ * If no one has taken it yet, then it winds up here. We then look for components registered
55+ * for WHEN_IN_FOCUSED_WINDOW events and fire to them. Note that if none of those are found
56+ * then we pass the event to the menubars and let them have a crack at it. They're handled differently.
57+ *
58+ * Lastly, we check if we're looking at an internal frame. If we are and no one wanted the event
59+ * then we move up to the InternalFrame's creator and see if anyone wants the event (and so on and so on).
60+ *
61+ *
62+ * @see InputMap
63+ */
64+class KeyboardManager {
65+
66+ static KeyboardManager currentManager = new KeyboardManager();
67+
68+ /**
69+ * maps top-level containers to a sub-hashtable full of keystrokes
70+ */
71+ Hashtable<Container, Hashtable> containerMap = new Hashtable<Container, Hashtable>();
72+
73+ /**
74+ * Maps component/keystroke pairs to a topLevel container
75+ * This is mainly used for fast unregister operations
76+ */
77+ Hashtable<ComponentKeyStrokePair, Container> componentKeyStrokeMap = new Hashtable<ComponentKeyStrokePair, Container>();
78+
79+ public static KeyboardManager getCurrentManager() {
80+ return currentManager;
81+ }
82+
83+ public static void setCurrentManager(KeyboardManager km) {
84+ currentManager = km;
85+ }
86+
87+ /**
88+ * register keystrokes here which are for the WHEN_IN_FOCUSED_WINDOW
89+ * case.
90+ * Other types of keystrokes will be handled by walking the hierarchy
91+ * That simplifies some potentially hairy stuff.
92+ */
93+ public void registerKeyStroke(KeyStroke k, JComponent c) {
94+ Container topContainer = getTopAncestor(c);
95+ if (topContainer == null) {
96+ return;
97+ }
98+ Hashtable keyMap = containerMap.get(topContainer);
99+
100+ if (keyMap == null) { // lazy evaluate one
101+ keyMap = registerNewTopContainer(topContainer);
102+ }
103+
104+ Object tmp = keyMap.get(k);
105+ if (tmp == null) {
106+ keyMap.put(k,c);
107+ } else if (tmp instanceof Vector) { // if there's a Vector there then add to it.
108+ Vector v = (Vector)tmp;
109+ if (!v.contains(c)) { // only add if this keystroke isn't registered for this component
110+ v.addElement(c);
111+ }
112+ } else if (tmp instanceof JComponent) {
113+ // if a JComponent is there then remove it and replace it with a vector
114+ // Then add the old compoennt and the new compoent to the vector
115+ // then insert the vector in the table
116+ if (tmp != c) { // this means this is already registered for this component, no need to dup
117+ Vector<JComponent> v = new Vector<JComponent>();
118+ v.addElement((JComponent) tmp);
119+ v.addElement(c);
120+ keyMap.put(k, v);
121+ }
122+ } else {
123+ System.out.println("Unexpected condition in registerKeyStroke");
124+ Thread.dumpStack();
125+ }
126+
127+ componentKeyStrokeMap.put(new ComponentKeyStrokePair(c,k), topContainer);
128+
129+ // Check for EmbeddedFrame case, they know how to process accelerators even
130+ // when focus is not in Java
131+ if (topContainer instanceof EmbeddedFrame) {
132+ ((EmbeddedFrame)topContainer).registerAccelerator(k);
133+ }
134+ }
135+
136+ /**
137+ * Find the top focusable Window, Applet, or InternalFrame
138+ */
139+ private static Container getTopAncestor(JComponent c) {
140+ for(Container p = c.getParent(); p != null; p = p.getParent()) {
141+ if (p instanceof Window && ((Window)p).isFocusableWindow() ||
142+ p instanceof Applet || p instanceof JInternalFrame) {
143+
144+ return p;
145+ }
146+ }
147+ return null;
148+ }
149+
150+ public void unregisterKeyStroke(KeyStroke ks, JComponent c) {
151+
152+ // component may have already been removed from the hierarchy, we
153+ // need to look up the container using the componentKeyStrokeMap.
154+
155+ ComponentKeyStrokePair ckp = new ComponentKeyStrokePair(c,ks);
156+
157+ Container topContainer = componentKeyStrokeMap.get(ckp);
158+
159+ if (topContainer == null) { // never heard of this pairing, so bail
160+ return;
161+ }
162+
163+ Hashtable keyMap = containerMap.get(topContainer);
164+ if (keyMap == null) { // this should never happen, but I'm being safe
165+ Thread.dumpStack();
166+ return;
167+ }
168+
169+ Object tmp = keyMap.get(ks);
170+ if (tmp == null) { // this should never happen, but I'm being safe
171+ Thread.dumpStack();
172+ return;
173+ }
174+
175+ if (tmp instanceof JComponent && tmp == c) {
176+ keyMap.remove(ks); // remove the KeyStroke from the Map
177+ //System.out.println("removed a stroke" + ks);
178+ } else if (tmp instanceof Vector ) { // this means there is more than one component reg for this key
179+ Vector v = (Vector)tmp;
180+ v.removeElement(c);
181+ if ( v.isEmpty() ) {
182+ keyMap.remove(ks); // remove the KeyStroke from the Map
183+ //System.out.println("removed a ks vector");
184+ }
185+ }
186+
187+ if ( keyMap.isEmpty() ) { // if no more bindings in this table
188+ containerMap.remove(topContainer); // remove table to enable GC
189+ //System.out.println("removed a container");
190+ }
191+
192+ componentKeyStrokeMap.remove(ckp);
193+
194+ // Check for EmbeddedFrame case, they know how to process accelerators even
195+ // when focus is not in Java
196+ if (topContainer instanceof EmbeddedFrame) {
197+ ((EmbeddedFrame)topContainer).unregisterAccelerator(ks);
198+ }
199+ }
200+
201+ /**
202+ * This method is called when the focused component (and none of
203+ * its ancestors) want the key event. This will look up the keystroke
204+ * to see if any chidren (or subchildren) of the specified container
205+ * want a crack at the event.
206+ * If one of them wants it, then it will "DO-THE-RIGHT-THING"
207+ */
208+ public boolean fireKeyboardAction(KeyEvent e, boolean pressed, Container topAncestor) {
209+
210+ if (e.isConsumed()) {
211+ System.out.println("Aquired pre-used event!");
212+ Thread.dumpStack();
213+ }
214+
215+ // There may be two keystrokes associated with a low-level key event;
216+ // in this case a keystroke made of an extended key code has a priority.
217+ KeyStroke ks;
218+ KeyStroke ksE = null;
219+
220+
221+ if(e.getID() == KeyEvent.KEY_TYPED) {
222+ ks=KeyStroke.getKeyStroke(e.getKeyChar());
223+ } else {
224+ if(e.getKeyCode() != e.getExtendedKeyCode()) {
225+ ksE=KeyStroke.getKeyStroke(e.getExtendedKeyCode(), e.getModifiers(), !pressed);
226+ }
227+ ks=KeyStroke.getKeyStroke(e.getKeyCode(), e.getModifiers(), !pressed);
228+ }
229+
230+ Hashtable keyMap = containerMap.get(topAncestor);
231+ if (keyMap != null) { // this container isn't registered, so bail
232+
233+ Object tmp = null;
234+ // extended code has priority
235+ if( ksE != null ) {
236+ tmp = keyMap.get(ksE);
237+ if( tmp != null ) {
238+ ks = ksE;
239+ }
240+ }
241+ if( tmp == null ) {
242+ tmp = keyMap.get(ks);
243+ }
244+
245+ if (tmp == null) {
246+ // don't do anything
247+ } else if ( tmp instanceof JComponent) {
248+ JComponent c = (JComponent)tmp;
249+ if ( c.isShowing() && c.isEnabled() ) { // only give it out if enabled and visible
250+ fireBinding(c, ks, e, pressed);
251+ }
252+ } else if ( tmp instanceof Vector) { //more than one comp registered for this
253+ Vector v = (Vector)tmp;
254+ // There is no well defined order for WHEN_IN_FOCUSED_WINDOW
255+ // bindings, but we give precedence to those bindings just
256+ // added. This is done so that JMenus WHEN_IN_FOCUSED_WINDOW
257+ // bindings are accessed before those of the JRootPane (they
258+ // both have a WHEN_IN_FOCUSED_WINDOW binding for enter).
259+ for (int counter = v.size() - 1; counter >= 0; counter--) {
260+ JComponent c = (JComponent)v.elementAt(counter);
261+ //System.out.println("Trying collision: " + c + " vector = "+ v.size());
262+ if ( c.isShowing() && c.isEnabled() ) { // don't want to give these out
263+ fireBinding(c, ks, e, pressed);
264+ if (e.isConsumed())
265+ return true;
266+ }
267+ }
268+ } else {
269+ System.out.println( "Unexpected condition in fireKeyboardAction " + tmp);
270+ // This means that tmp wasn't null, a JComponent, or a Vector. What is it?
271+ Thread.dumpStack();
272+ }
273+ }
274+
275+ if (e.isConsumed()) {
276+ return true;
277+ }
278+ // if no one else handled it, then give the menus a crack
279+ // The're handled differently. The key is to let any JMenuBars
280+ // process the event
281+ if ( keyMap != null) {
282+ Vector v = (Vector)keyMap.get(JMenuBar.class);
283+ if (v != null) {
284+ Enumeration iter = v.elements();
285+ while (iter.hasMoreElements()) {
286+ JMenuBar mb = (JMenuBar)iter.nextElement();
287+ if ( mb.isShowing() && mb.isEnabled() ) { // don't want to give these out
288+ if( !(ks.equals(ksE)) ) {
289+ fireBinding(mb, ksE, e, pressed);
290+ }
291+ if(ks.equals(ksE) || !e.isConsumed()) {
292+ fireBinding(mb, ks, e, pressed);
293+ }
294+ if (e.isConsumed()) {
295+ return true;
296+ }
297+ }
298+ }
299+ }
300+ }
301+
302+ return e.isConsumed();
303+ }
304+
305+ void fireBinding(JComponent c, KeyStroke ks, KeyEvent e, boolean pressed) {
306+ if (c.processKeyBinding(ks, e, JComponent.WHEN_IN_FOCUSED_WINDOW,
307+ pressed)) {
308+ e.consume();
309+ }
310+ }
311+
312+ public void registerMenuBar(JMenuBar mb) {
313+ Container top = getTopAncestor(mb);
314+ if (top == null) {
315+ return;
316+ }
317+ Hashtable keyMap = containerMap.get(top);
318+
319+ if (keyMap == null) { // lazy evaluate one
320+ keyMap = registerNewTopContainer(top);
321+ }
322+ // use the menubar class as the key
323+ Vector menuBars = (Vector)keyMap.get(JMenuBar.class);
324+
325+ if (menuBars == null) { // if we don't have a list of menubars,
326+ // then make one.
327+ menuBars = new Vector();
328+ keyMap.put(JMenuBar.class, menuBars);
329+ }
330+
331+ if (!menuBars.contains(mb)) {
332+ menuBars.addElement(mb);
333+ }
334+ }
335+
336+
337+ public void unregisterMenuBar(JMenuBar mb) {
338+ Container topContainer = getTopAncestor(mb);
339+ if (topContainer == null) {
340+ return;
341+ }
342+ Hashtable keyMap = containerMap.get(topContainer);
343+ if (keyMap!=null) {
344+ Vector v = (Vector)keyMap.get(JMenuBar.class);
345+ if (v != null) {
346+ v.removeElement(mb);
347+ if (v.isEmpty()) {
348+ keyMap.remove(JMenuBar.class);
349+ if (keyMap.isEmpty()) {
350+ // remove table to enable GC
351+ containerMap.remove(topContainer);
352+ }
353+ }
354+ }
355+ }
356+ }
357+ protected Hashtable registerNewTopContainer(Container topContainer) {
358+ Hashtable keyMap = new Hashtable();
359+ containerMap.put(topContainer, keyMap);
360+ return keyMap;
361+ }
362+
363+ /**
364+ * This class is used to create keys for a hashtable
365+ * which looks up topContainers based on component, keystroke pairs
366+ * This is used to make unregistering KeyStrokes fast
367+ */
368+ class ComponentKeyStrokePair {
369+ Object component;
370+ Object keyStroke;
371+
372+ public ComponentKeyStrokePair(Object comp, Object key) {
373+ component = comp;
374+ keyStroke = key;
375+ }
376+
377+ public boolean equals(Object o) {
378+ if ( !(o instanceof ComponentKeyStrokePair)) {
379+ return false;
380+ }
381+ ComponentKeyStrokePair ckp = (ComponentKeyStrokePair)o;
382+ return ((component.equals(ckp.component)) && (keyStroke.equals(ckp.keyStroke)));
383+ }
384+
385+ public int hashCode() {
386+ return component.hashCode() * keyStroke.hashCode();
387+ }
388+
389+ }
390+
391+} // end KeyboardManager