From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- .../classpath/java/awt/KeyboardFocusManager.java | 1479 ++++++++++++++++++++ 1 file changed, 1479 insertions(+) create mode 100644 libjava/classpath/java/awt/KeyboardFocusManager.java (limited to 'libjava/classpath/java/awt/KeyboardFocusManager.java') diff --git a/libjava/classpath/java/awt/KeyboardFocusManager.java b/libjava/classpath/java/awt/KeyboardFocusManager.java new file mode 100644 index 000000000..691351175 --- /dev/null +++ b/libjava/classpath/java/awt/KeyboardFocusManager.java @@ -0,0 +1,1479 @@ +/* KeyboardFocusManager.java -- manage component focusing via the keyboard + Copyright (C) 2002, 2004, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import java.applet.Applet; +import java.awt.FocusTraversalPolicy; +import java.awt.event.FocusEvent; +import java.awt.event.KeyEvent; +import java.awt.event.WindowEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.beans.PropertyVetoException; +import java.beans.VetoableChangeListener; +import java.beans.VetoableChangeSupport; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * The KeyboardFocusManager handles the focusing of + * windows for receiving keyboard events. The manager handles + * the dispatch of all FocusEvents and + * KeyEvents, along with WindowEvents + * relating to the focused window. Users can use the manager + * to ascertain the current focus owner and fire events. + *
+ *
+ * The focus owner is the Component that receives + * key events. The focus owner is either the currently focused + * window or a component within this window. + *
+ *
+ * The underlying native windowing system may denote the active + * window or its children with special decorations (e.g. a highlighted + * title bar). The active window is always either a Frame + * or Dialog, and is either the currently focused + * window or its owner. + *
+ *
+ * Applets may be partitioned into different applet contexts, according + * to their code base. In this case, each context has its own + * KeyboardFocusManager, as opposed to the global + * manager maintained by applets which share the same context. + * Each context is insulated from the others, and they don't interact. + * The resulting behaviour, as with context division, depends on the browser + * supporting the applets. Regardless, there can only ever be + * one focused window, one active window and one focus owner + * per ClassLoader. + *
+ *
+ * To support this separation of focus managers, the manager instances + * and the internal state information is grouped by the + * ThreadGroup to which it pertains. With respect to + * applets, each code base has its own ThreadGroup, so the + * isolation of each context is enforced within the manager. + *
+ *
+ * By default, the manager defines TAB and Ctrl+TAB as the + * forward focus traversal keys and Shift+TAB and Ctrl+Shift+TAB + * as the backward focus traversal keys. No up or down cycle + * traversal keys are defined by default. Traversal takes effect + * on the firing of a relevant KEY_PRESSED event. + * However, all other key events related to the use of the + * defined focus traversal key sequence are consumed and not + * dispatched. + *
+ *
+ * These default traversal keys come into effect on all windows + * for which no alternative set of keys is defined. This also + * applies recursively to any child components of such a window, + * which define no traversal keys of their own. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @author Thomas Fitzsimmons (fitzsim@redhat.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.4 + */ +public abstract class KeyboardFocusManager + implements KeyEventDispatcher, KeyEventPostProcessor +{ + /** Identifies {@link AWTKeyStroke}s that move the focus forward in + the focus cycle. */ + public static final int FORWARD_TRAVERSAL_KEYS = 0; + + /** Identifies {@link AWTKeyStroke}s that move the focus backward in + the focus cycle. */ + public static final int BACKWARD_TRAVERSAL_KEYS = 1; + + /** Identifies {@link AWTKeyStroke}s that move the focus up to the + parent focus cycle root. */ + public static final int UP_CYCLE_TRAVERSAL_KEYS = 2; + + /** Identifies {@link AWTKeyStroke}s that move the focus down to the + child focus cycle root. */ + public static final int DOWN_CYCLE_TRAVERSAL_KEYS = 3; + + /** The set of {@link AWTKeyStroke}s that cause focus to be moved to + the next focusable Component in the focus cycle. */ + private static final Set DEFAULT_FORWARD_KEYS; + + /** The set of {@link AWTKeyStroke}s that cause focus to be moved to + the previous focusable Component in the focus cycle. */ + private static final Set DEFAULT_BACKWARD_KEYS; + + /** Populate the DEFAULT_FORWARD_KEYS and DEFAULT_BACKWARD_KEYS + {@link java.util.Set}s. */ + static + { + Set s = new HashSet(); + s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, 0)); + s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, + KeyEvent.CTRL_DOWN_MASK)); + DEFAULT_FORWARD_KEYS = Collections.unmodifiableSet(s); + s = new HashSet(); + s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, + KeyEvent.SHIFT_DOWN_MASK)); + s.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, + KeyEvent.SHIFT_DOWN_MASK + | KeyEvent.CTRL_DOWN_MASK)); + DEFAULT_BACKWARD_KEYS = Collections.unmodifiableSet(s); + } + + /** The global object {@link java.util.Map}s. */ + + /** For security reasons, {@link java.applet.Applet}s in different + codebases must be insulated from one another. Since {@link + KeyboardFocusManager}s have the ability to return {@link + Component}s from a given {@link java.applet.Applet}, each + codebase must have an independent {@link KeyboardFocusManager}. + Since each codebase has its own {@link ThreadGroup} in which its + {@link Applet}s run, it makes sense to partition {@link + KeyboardFocusManager}s according to {@link + java.lang.ThreadGroup}. Thus, currentKeyboardFocusManagers is a + {@link java.util.Map} keyed on {@link java.lang.ThreadGroup}. */ + private static Map currentKeyboardFocusManagers = new HashMap (); + + /** {@link java.applet.Applet}s in one codebase must not be allowed + to access {@link Component}s in {@link java.applet.Applet}s in + other codebases. To enforce this restriction, we key the + following {@link java.util.Map}s on {@link java.lang.ThreadGroup}s (which + are per-codebase). For example, if {@link + java.lang.ThreadGroup} A calls {@link #setGlobalFocusOwner}, + passing {@link Component} C, currentFocusOwners[A] is assigned + C, and all other currentFocusOwners values are nullified. Then + if {@link java.lang.ThreadGroup} A subsequently calls {@link + #getGlobalFocusOwner}, it will return currentFocusOwners[A], + that is, {@link Component} C. If another {@link + java.lang.ThreadGroup} K calls {@link #getGlobalFocusOwner}, it + will return currentFocusOwners[K], that is, null. + + Since this is a static field, we ensure that there is only one + focused {@link Component} per class loader. */ + private static Map currentFocusOwners = new HashMap (); + + /** A {@link java.util.Map} keyed on {@link java.lang.ThreadGroup}s + that stores the {@link Component} that owns the permanent + keyboard focus. @see currentFocusOwners */ + private static Map currentPermanentFocusOwners = new HashMap (); + + /** A {@link java.util.Map} keyed on {@link java.lang.ThreadGroup}s + that stores the focused {@link Window}. @see + currentFocusOwners */ + private static Map currentFocusedWindows = new HashMap (); + + /** A {@link java.util.Map} keyed on {@link java.lang.ThreadGroup}s + that stores the active {@link Window}. @see + currentFocusOwners */ + private static Map currentActiveWindows = new HashMap (); + + /** A {@link java.util.Map} keyed on {@link java.lang.ThreadGroup}s + that stores the focus cycle root {@link Container}. @see + currentFocusOwners */ + private static Map currentFocusCycleRoots = new HashMap (); + + /** The default {@link FocusTraversalPolicy} that focus-managing + {@link Container}s will use to define their initial focus + traversal policy. */ + private FocusTraversalPolicy defaultPolicy; + + /** An array that stores the {@link #FORWARD_TRAVERSAL_KEYS}, {@link + #BACKWARD_TRAVERSAL_KEYS}, {@link #UP_CYCLE_TRAVERSAL_KEYS} and + {@link #DOWN_CYCLE_TRAVERSAL_KEYS} {@link AWTKeyStroke}s {@link + java.util.Set}s. */ + private Set[] defaultFocusKeys = new Set[] + { + DEFAULT_FORWARD_KEYS, DEFAULT_BACKWARD_KEYS, + Collections.EMPTY_SET, Collections.EMPTY_SET + }; + + /** + * A utility class to support the handling of events relating to property changes. + */ + private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport (this); + + /** + * A utility class to support the handling of events relating to vetoable changes. + */ + private final VetoableChangeSupport vetoableChangeSupport = new VetoableChangeSupport (this); + + /** A list of {@link KeyEventDispatcher}s that process {@link + KeyEvent}s before they are processed the default keyboard focus + manager. */ + private final ArrayList keyEventDispatchers = new ArrayList(); + + /** A list of {@link KeyEventPostProcessor}s that process unconsumed + {@link KeyEvent}s. */ + private final ArrayList keyEventPostProcessors = new ArrayList(); + + /** + * Construct a KeyboardFocusManager. + */ + public KeyboardFocusManager () + { + } + + /** + * Retrieve the keyboard focus manager associated with the {@link + * java.lang.ThreadGroup} to which the calling thread belongs. + * + * @return the keyboard focus manager associated with the current + * thread group + */ + public static KeyboardFocusManager getCurrentKeyboardFocusManager () + { + ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup (); + + if (currentKeyboardFocusManagers.get (currentGroup) == null) + setCurrentKeyboardFocusManager (null); + + return (KeyboardFocusManager) currentKeyboardFocusManagers.get (currentGroup); + } + + /** + * Set the keyboard focus manager associated with the {@link + * java.lang.ThreadGroup} to which the calling thread belongs. + * + * @param m the keyboard focus manager for the current thread group + */ + public static void setCurrentKeyboardFocusManager (KeyboardFocusManager m) + { + SecurityManager sm = System.getSecurityManager (); + if (sm != null) + sm.checkPermission (new AWTPermission ("replaceKeyboardFocusManager")); + + ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup (); + KeyboardFocusManager manager; + + if (m == null) + manager = new DefaultKeyboardFocusManager(); + else + manager = m; + + currentKeyboardFocusManagers.put (currentGroup, manager); + } + + /** + * Retrieve the {@link Component} that has the keyboard focus, or + * null if the focus owner was not set by a thread in the current + * {@link java.lang.ThreadGroup}. + * + * @return the keyboard focus owner or null + */ + public Component getFocusOwner () + { + return (Component) getObject (currentFocusOwners); + } + + /** + * Retrieve the {@link Component} that has the keyboard focus, + * regardless of whether or not it was set by a thread in the + * current {@link java.lang.ThreadGroup}. If there is no temporary + * focus owner in effect then this method will return the same value + * as {@link #getGlobalPermanentFocusOwner}. + * + * @return the keyboard focus owner + * @throws SecurityException if this is not the keyboard focus + * manager associated with the current {@link java.lang.ThreadGroup} + */ + protected Component getGlobalFocusOwner () + { + return (Component) getGlobalObject(currentFocusOwners, true); + } + + /** + * Set the {@link Component} that will be returned by {@link + * #getFocusOwner} (when it is called from the current {@link + * java.lang.ThreadGroup}) and {@link #getGlobalFocusOwner}. This + * method does not actually transfer the keyboard focus. + * + * @param owner the Component to return from getFocusOwner and + * getGlobalFocusOwner + * + * @see Component#requestFocus() + * @see Component#requestFocusInWindow() + */ + protected void setGlobalFocusOwner (Component owner) + { + if (owner == null || owner.focusable) + setGlobalObject (currentFocusOwners, owner, "focusOwner"); + } + + /** + * Clear the global focus owner and deliver a FOCUS_LOST event to + * the previously-focused {@link Component}. Until another {@link + * Component} becomes the keyboard focus owner, key events will be + * discarded by top-level windows. + */ + public void clearGlobalFocusOwner () + { + synchronized (currentFocusOwners) + { + Component focusOwner = getGlobalFocusOwner (); + Component permanentFocusOwner = getGlobalPermanentFocusOwner (); + + setGlobalFocusOwner (null); + setGlobalPermanentFocusOwner (null); + + // Inform the old focus owner that it has lost permanent + // focus. + if (focusOwner != null) + { + // We can't cache the event queue, because of + // bootstrapping issues. We need to set the default + // KeyboardFocusManager in EventQueue before the event + // queue is started. + EventQueue q = Toolkit.getDefaultToolkit ().getSystemEventQueue (); + if (focusOwner != permanentFocusOwner) + q.postEvent (new FocusEvent (focusOwner, FocusEvent.FOCUS_LOST, true)); + else + q.postEvent (new FocusEvent (focusOwner, FocusEvent.FOCUS_LOST, false)); + } + + if (focusOwner != permanentFocusOwner) + { + EventQueue q = Toolkit.getDefaultToolkit ().getSystemEventQueue (); + q.postEvent (new FocusEvent (permanentFocusOwner, FocusEvent.FOCUS_LOST, false)); + } + } + } + + /** + * Retrieve the {@link Component} that has the permanent keyboard + * focus, or null if the focus owner was not set by a thread in the + * current {@link java.lang.ThreadGroup}. + * + * @return the keyboard focus owner or null + */ + public Component getPermanentFocusOwner () + { + return (Component) getObject (currentPermanentFocusOwners); + } + + /** + * Retrieve the {@link Component} that has the permanent keyboard + * focus, regardless of whether or not it was set by a thread in the + * current {@link java.lang.ThreadGroup}. + * + * @return the keyboard focus owner + * @throws SecurityException if this is not the keyboard focus + * manager associated with the current {@link java.lang.ThreadGroup} + */ + protected Component getGlobalPermanentFocusOwner () + { + return (Component) getGlobalObject (currentPermanentFocusOwners, true); + } + + /** + * Set the {@link Component} that will be returned by {@link + * #getPermanentFocusOwner} (when it is called from the current + * {@link java.lang.ThreadGroup}) and {@link + * #getGlobalPermanentFocusOwner}. This method does not actually + * transfer the keyboard focus. + * + * @param focusOwner the Component to return from + * getPermanentFocusOwner and getGlobalPermanentFocusOwner + * + * @see Component#requestFocus() + * @see Component#requestFocusInWindow() + */ + protected void setGlobalPermanentFocusOwner (Component focusOwner) + { + if (focusOwner == null || focusOwner.focusable) + setGlobalObject (currentPermanentFocusOwners, focusOwner, + "permanentFocusOwner"); + } + + /** + * Retrieve the {@link Window} that is or contains the keyboard + * focus owner, or null if the focused window was not set by a + * thread in the current {@link java.lang.ThreadGroup}. + * + * @return the focused window or null + */ + public Window getFocusedWindow () + { + return (Window) getObject (currentFocusedWindows); + } + + /** + * Retrieve the {@link Window} that is or contains the focus owner, + * regardless of whether or not the {@link Window} was set focused + * by a thread in the current {@link java.lang.ThreadGroup}. + * + * @return the focused window + * @throws SecurityException if this is not the keyboard focus + * manager associated with the current {@link java.lang.ThreadGroup} + */ + protected Window getGlobalFocusedWindow () + { + return (Window) getGlobalObject (currentFocusedWindows, true); + } + + /** + * Set the {@link Window} that will be returned by {@link + * #getFocusedWindow} (when it is called from the current {@link + * java.lang.ThreadGroup}) and {@link #getGlobalFocusedWindow}. + * This method does not actually cause window to become + * the focused {@link Window}. + * + * @param window the Window to return from getFocusedWindow and + * getGlobalFocusedWindow + */ + protected void setGlobalFocusedWindow (Window window) + { + if (window == null || window.focusable) + setGlobalObject (currentFocusedWindows, window, "focusedWindow"); + } + + /** + * Retrieve the active {@link Window}, or null if the active window + * was not set by a thread in the current {@link + * java.lang.ThreadGroup}. + * + * @return the active window or null + */ + public Window getActiveWindow() + { + return (Window) getObject (currentActiveWindows); + } + + /** + * Retrieve the active {@link Window}, regardless of whether or not + * the {@link Window} was made active by a thread in the current + * {@link java.lang.ThreadGroup}. + * + * @return the active window + * @throws SecurityException if this is not the keyboard focus + * manager associated with the current {@link java.lang.ThreadGroup} + */ + protected Window getGlobalActiveWindow() + { + return (Window) getGlobalObject (currentActiveWindows, true); + } + + /** + * Set the {@link Window} that will be returned by {@link + * #getActiveWindow} (when it is called from the current {@link + * java.lang.ThreadGroup}) and {@link #getGlobalActiveWindow}. This + * method does not actually cause window to be made + * active. + * + * @param window the Window to return from getActiveWindow and + * getGlobalActiveWindow + */ + protected void setGlobalActiveWindow(Window window) + { + setGlobalObject (currentActiveWindows, window, "activeWindow"); + } + + /** + * Retrieve the default {@link FocusTraversalPolicy}. + * Focus-managing {@link Container}s use the returned object to + * define their initial focus traversal policy. + * + * @return a non-null default FocusTraversalPolicy object + */ + public FocusTraversalPolicy getDefaultFocusTraversalPolicy () + { + if (defaultPolicy == null) + defaultPolicy = new DefaultFocusTraversalPolicy (); + return defaultPolicy; + } + + /** + * Set the {@link FocusTraversalPolicy} returned by {@link + * #getDefaultFocusTraversalPolicy}. Focus-managing {@link + * Container}s created after this call will use policy as their + * initial focus traversal policy. Existing {@link Container}s' + * focus traversal policies will not be affected by calls to this + * method. + * + * @param policy the FocusTraversalPolicy that will be returned by + * subsequent calls to getDefaultFocusTraversalPolicy + * @throws IllegalArgumentException if policy is null + */ + public void setDefaultFocusTraversalPolicy (FocusTraversalPolicy policy) + { + if (policy == null) + throw new IllegalArgumentException (); + firePropertyChange ("defaultFocusTraversalPolicy", defaultPolicy, policy); + defaultPolicy = policy; + } + + /** + * Set the default {@link java.util.Set} of focus traversal keys for + * one of the focus traversal directions. + * + * @param id focus traversal direction identifier + * @param keystrokes set of AWTKeyStrokes + * + * @see #FORWARD_TRAVERSAL_KEYS + * @see #BACKWARD_TRAVERSAL_KEYS + * @see #UP_CYCLE_TRAVERSAL_KEYS + * @see #DOWN_CYCLE_TRAVERSAL_KEYS + */ + public void setDefaultFocusTraversalKeys (int id, + Set + keystrokes) + { + if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS && + id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS) + throw new IllegalArgumentException (); + + if (keystrokes == null) + throw new IllegalArgumentException (); + + Set sa; + Set sb; + Set sc; + String type; + switch (id) + { + case FORWARD_TRAVERSAL_KEYS: + sa = defaultFocusKeys[BACKWARD_TRAVERSAL_KEYS]; + sb = defaultFocusKeys[UP_CYCLE_TRAVERSAL_KEYS]; + sc = defaultFocusKeys[DOWN_CYCLE_TRAVERSAL_KEYS]; + type = "forwardDefaultFocusTraversalKeys"; + break; + case BACKWARD_TRAVERSAL_KEYS: + sa = defaultFocusKeys[FORWARD_TRAVERSAL_KEYS]; + sb = defaultFocusKeys[UP_CYCLE_TRAVERSAL_KEYS]; + sc = defaultFocusKeys[DOWN_CYCLE_TRAVERSAL_KEYS]; + type = "backwardDefaultFocusTraversalKeys"; + break; + case UP_CYCLE_TRAVERSAL_KEYS: + sa = defaultFocusKeys[FORWARD_TRAVERSAL_KEYS]; + sb = defaultFocusKeys[BACKWARD_TRAVERSAL_KEYS]; + sc = defaultFocusKeys[DOWN_CYCLE_TRAVERSAL_KEYS]; + type = "upCycleDefaultFocusTraversalKeys"; + break; + case DOWN_CYCLE_TRAVERSAL_KEYS: + sa = defaultFocusKeys[FORWARD_TRAVERSAL_KEYS]; + sb = defaultFocusKeys[BACKWARD_TRAVERSAL_KEYS]; + sc = defaultFocusKeys[UP_CYCLE_TRAVERSAL_KEYS]; + type = "downCycleDefaultFocusTraversalKeys"; + break; + default: + throw new IllegalArgumentException (); + } + int i = keystrokes.size (); + Iterator iter = keystrokes.iterator (); + while (--i >= 0) + { + Object o = iter.next (); + if (!(o instanceof AWTKeyStroke) + || sa.contains (o) || sb.contains (o) || sc.contains (o) + || ((AWTKeyStroke) o).keyCode == KeyEvent.VK_UNDEFINED) + throw new IllegalArgumentException (); + } + keystrokes = Collections.unmodifiableSet (new HashSet (keystrokes)); + firePropertyChange (type, defaultFocusKeys[id], keystrokes); + defaultFocusKeys[id] = keystrokes; + } + + /** + * Retrieve the default {@link java.util.Set} of focus traversal + * keys for one of the focus traversal directions. + * + * @param id focus traversal direction identifier + * + * @return the default set of AWTKeyStrokes + * + * @see #FORWARD_TRAVERSAL_KEYS + * @see #BACKWARD_TRAVERSAL_KEYS + * @see #UP_CYCLE_TRAVERSAL_KEYS + * @see #DOWN_CYCLE_TRAVERSAL_KEYS + */ + public Set getDefaultFocusTraversalKeys (int id) + { + if (id < FORWARD_TRAVERSAL_KEYS || id > DOWN_CYCLE_TRAVERSAL_KEYS) + throw new IllegalArgumentException (); + return defaultFocusKeys[id]; + } + + /** + * Retrieve the current focus cycle root, or null if the focus owner + * was not set by a thread in the current {@link + * java.lang.ThreadGroup}. + * + * @return the current focus cycle root or null + */ + public Container getCurrentFocusCycleRoot () + { + return (Container) getObject (currentFocusCycleRoots); + } + + /** + * Retrieve the current focus cycle root, regardless of whether or + * not it was made set by a thread in the current {@link + * java.lang.ThreadGroup}. + * + * @return the current focus cycle root + * @throws SecurityException if this is not the keyboard focus + * manager associated with the current {@link java.lang.ThreadGroup} + */ + protected Container getGlobalCurrentFocusCycleRoot () + { + return (Container) getGlobalObject (currentFocusCycleRoots, true); + } + + /** + * Set the {@link Container} that will be returned by {@link + * #getCurrentFocusCycleRoot} (when it is called from the current + * {@link java.lang.ThreadGroup}) and {@link + * #getGlobalCurrentFocusCycleRoot}. This method does not actually + * make cycleRoot the current focus cycle root. + * + * @param cycleRoot the focus cycle root to return from + * getCurrentFocusCycleRoot and getGlobalCurrentFocusCycleRoot + */ + public void setGlobalCurrentFocusCycleRoot (Container cycleRoot) + { + setGlobalObject (currentFocusCycleRoots, cycleRoot, "currentFocusCycleRoot"); + } + + /** + * Registers the supplied property change listener for receiving + * events caused by the following property changes: + * + * + * + * If the supplied listener is null, nothing occurs. + * + * @param l the new listener to register. + * @see KeyboardFocusManager#addPropertyChangeListener(String, java.beans.PropertyChangeListener) + */ + public void addPropertyChangeListener(PropertyChangeListener l) + { + if (l != null) + propertyChangeSupport.addPropertyChangeListener(l); + } + + /** + * Removes the supplied property change listener from the list + * of registered listeners. If the supplied listener is null, + * nothing occurs. + * + * @param l the listener to remove. + */ + public void removePropertyChangeListener(PropertyChangeListener l) + { + if (l != null) + propertyChangeSupport.removePropertyChangeListener(l); + } + + /** + * Returns the currently registered property change listeners + * in array form. The returned array is empty if no listeners are + * currently registered. + * + * @return an array of registered property change listeners. + */ + public PropertyChangeListener[] getPropertyChangeListeners() + { + return propertyChangeSupport.getPropertyChangeListeners(); + } + + /** + * Registers a property change listener for receiving events relating + * to a change to a specified property. The supplied property name can be + * either user-defined or one from the following list of properties + * relevant to this class: + * + * + * + * Nothing occurs if a null listener is supplied. null is regarded as a valid property name. + * + * @param name the name of the property to handle change events for. + * @param l the listener to register for changes to the specified property. + * @see KeyboardFocusManager#addPropertyChangeListener(java.beans.PropertyChangeListener) + */ + public void addPropertyChangeListener(String name, PropertyChangeListener l) + { + if (l != null) + propertyChangeSupport.addPropertyChangeListener(name, l); + } + + /** + * Removes the supplied property change listener registered for the + * specified property from the list of registered listeners. If the + * supplied listener is null, nothing occurs. + * + * @param name the name of the property the listener is + * monitoring changes to. + * @param l the listener to remove. + */ + public void removePropertyChangeListener(String name, + PropertyChangeListener l) + { + if (l != null) + propertyChangeSupport.removePropertyChangeListener(name, l); + } + + /** + * Returns the currently registered property change listeners + * in array form, which listen for changes to the supplied property. + * The returned array is empty, if no listeners are currently registered + * for events pertaining to the supplied property. + * + * @param name The property the returned listeners monitor for changes. + * @return an array of registered property change listeners which + * listen for changes to the supplied property. + */ + public PropertyChangeListener[] getPropertyChangeListeners(String name) + { + return propertyChangeSupport.getPropertyChangeListeners(name); + } + + /** + * Fires a property change event as a response to a change to + * to the specified property. The event is only fired if a + * change has actually occurred (i.e. o and n are different). + * + * @param name The name of the property to which a change occurred. + * @param o The old value of the property. + * @param n The new value of the property. + */ + protected void firePropertyChange(String name, Object o, Object n) + { + propertyChangeSupport.firePropertyChange(name, o, n); + } + + /** + * Registers a vetoable property change listener for receiving events + * relating to the following properties: + * + * + * + * Nothing occurs if a null listener is supplied. + * + * @param l the listener to register. + * @see KeyboardFocusManager#addVetoableChangeListener(String, java.beans.VetoableChangeListener) + */ + public void addVetoableChangeListener(VetoableChangeListener l) + { + if (l != null) + vetoableChangeSupport.addVetoableChangeListener(l); + } + + /** + * Removes the supplied vetoable property change listener from + * the list of registered listeners. If the supplied listener + * is null, nothing occurs. + * + * @param l the listener to remove. + */ + public void removeVetoableChangeListener(VetoableChangeListener l) + { + if (l != null) + vetoableChangeSupport.removeVetoableChangeListener(l); + } + + /** + * Returns the currently registered vetoable property change listeners + * in array form. The returned array is empty if no listeners are + * currently registered. + * + * @return an array of registered vetoable property change listeners. + * @since 1.4 + */ + public VetoableChangeListener[] getVetoableChangeListeners() + { + return vetoableChangeSupport.getVetoableChangeListeners(); + } + + /** + * Registers a vetoable property change listener for receiving events relating + * to a vetoable change to a specified property. The supplied property name can be + * either user-defined or one from the following list of properties + * relevant to this class: + * + * + * + * Nothing occurs if a null listener is supplied. null is regarded as a valid property name. + * + * @param name the name of the property to handle change events for. + * @param l the listener to register for changes to the specified property. + * @see KeyboardFocusManager#addVetoableChangeListener(java.beans.VetoableChangeListener) + */ + public void addVetoableChangeListener(String name, VetoableChangeListener l) + { + if (l != null) + vetoableChangeSupport.addVetoableChangeListener(name, l); + } + + /** + * Removes the supplied vetoable property change listener registered + * for the specified property from the list of registered listeners. + * If the supplied listener is null, nothing occurs. + * + * @param name the name of the vetoable property the listener is + * monitoring changes to. + * @param l the listener to remove. + */ + public void removeVetoableChangeListener(String name, + VetoableChangeListener l) + { + if (l != null) + vetoableChangeSupport.removeVetoableChangeListener(name, l); + } + + /** + * Returns the currently registered vetoable property change listeners + * in array form, which listen for changes to the supplied property. + * The returned array is empty, if no listeners are currently registered + * for events pertaining to the supplied property. + * + * @param name The property the returned listeners monitor for changes. + * @return an array of registered property change listeners which + * listen for changes to the supplied property. + * @since 1.4 + */ + public VetoableChangeListener[] getVetoableChangeListeners(String name) + { + return vetoableChangeSupport.getVetoableChangeListeners(name); + } + + /** + * Fires a property change event as a response to a vetoable change to + * to the specified property. The event is only fired if a + * change has actually occurred (i.e. o and n are different). + * In the event that the property change is vetoed, the following + * occurs: + * + *
    + *
  1. + * This method throws a PropertyVetoException to + * the proposed change. + *
  2. + *
  3. + * A new event is fired to reverse the previous change. + *
  4. + *
  5. + * This method again throws a PropertyVetoException + * in response to the reversion. + *
  6. + *
+ * + * @param name The name of the property to which a change occurred. + * @param o The old value of the property. + * @param n The new value of the property. + * @throws PropertyVetoException if one of the listeners vetos + * the change by throwing this exception. + */ + protected void fireVetoableChange(String name, Object o, Object n) + throws PropertyVetoException + { + vetoableChangeSupport.fireVetoableChange(name, o, n); + } + + /** + * Adds a key event dispatcher to the list of registered dispatchers. + * When a key event is fired, each dispatcher's dispatchKeyEvent + * method is called in the order that they were added, prior to the manager + * dispatching the event itself. Notifications halt when one of the + * dispatchers returns true. + *
+ *
+ * The same dispatcher can exist multiple times within the list + * of registered dispatchers, and there is no limit on the length + * of this list. A null dispatcher is simply ignored. + * + * @param dispatcher The dispatcher to register. + */ + public void addKeyEventDispatcher(KeyEventDispatcher dispatcher) + { + if (dispatcher != null) + keyEventDispatchers.add(dispatcher); + } + + /** + * Removes the specified key event dispatcher from the list of + * registered dispatchers. The manager always dispatches events, + * regardless of its existence within the list. The manager + * can be added and removed from the list, as with any other + * dispatcher, but this does not affect its ability to dispatch + * key events. Non-existent and null dispatchers are simply ignored + * by this method. + * + * @param dispatcher The dispatcher to remove. + */ + public void removeKeyEventDispatcher(KeyEventDispatcher dispatcher) + { + keyEventDispatchers.remove(dispatcher); + } + + /** + * Returns the currently registered key event dispatchers in List + * form. At present, this only includes dispatchers explicitly registered + * via the addKeyEventDispatcher() method, but this behaviour + * is subject to change and should not be depended on. The manager itself + * may be a member of the list, but only if explicitly registered. If no + * dispatchers have been registered, the list will be empty. + * + * @return A list of explicitly registered key event dispatchers. + * @see KeyboardFocusManager#addKeyEventDispatcher(java.awt.KeyEventDispatcher) + */ + protected List getKeyEventDispatchers () + { + return (List) keyEventDispatchers.clone (); + } + + /** + * Adds a key event post processor to the list of registered post processors. + * Post processors work in the same way as key event dispatchers, except + * that they are invoked after the manager has dispatched the key event, + * and not prior to this. Each post processor's postProcessKeyEvent + * method is called to see if any post processing needs to be performed. THe + * processors are called in the order in which they were added to the list, + * and notifications continue until one returns true. As with key event + * dispatchers, the manager is implicitly called following this process, + * regardless of whether or not it is present within the list. + *
+ *
+ * The same post processor can exist multiple times within the list + * of registered post processors, and there is no limit on the length + * of this list. A null post processor is simply ignored. + * + * @param postProcessor the post processor to register. + * @see KeyboardFocusManager#addKeyEventDispatcher(java.awt.KeyEventDispatcher) + */ + public void addKeyEventPostProcessor (KeyEventPostProcessor postProcessor) + { + if (postProcessor != null) + keyEventPostProcessors.add (postProcessor); + } + + /** + * Removes the specified key event post processor from the list of + * registered post processors. The manager always post processes events, + * regardless of its existence within the list. The manager + * can be added and removed from the list, as with any other + * post processor, but this does not affect its ability to post process + * key events. Non-existent and null post processors are simply ignored + * by this method. + * + * @param postProcessor the post processor to remove. + */ + public void removeKeyEventPostProcessor (KeyEventPostProcessor postProcessor) + { + keyEventPostProcessors.remove (postProcessor); + } + + /** + * Returns the currently registered key event post processors in List + * form. At present, this only includes post processors explicitly registered + * via the addKeyEventPostProcessor() method, but this behaviour + * is subject to change and should not be depended on. The manager itself + * may be a member of the list, but only if explicitly registered. If no + * post processors have been registered, the list will be empty. + * + * @return A list of explicitly registered key event post processors. + * @see KeyboardFocusManager#addKeyEventPostProcessor(java.awt.KeyEventPostProcessor) + */ + protected List getKeyEventPostProcessors () + { + return (List) keyEventPostProcessors.clone (); + } + + /** + * The AWT event dispatcher uses this method to request that the manager + * handle a particular event. If the manager fails or refuses to + * dispatch the supplied event (this method returns false), the + * AWT event dispatcher will try to dispatch the event itself. + *
+ *
+ * The manager is expected to handle all FocusEvents + * and KeyEvents, and WindowEvents + * relating to the focus. Dispatch is done with regard to the + * the focus owner and the currently focused and active windows. + * In handling the event, the source of the event may be overridden. + *
+ *
+ * The actual dispatching is performed by calling + * redispatchEvent(). This avoids the infinite recursion + * of dispatch requests which may occur if this method is called on + * the target component. + * + * @param e the event to dispatch. + * @return true if the event was dispatched. + * @see KeyboardFocusManager#redispatchEvent(java.awt.Component, java.awt.AWTEvent) + * @see KeyEvent + * @see FocusEvent + * @see WindowEvent + */ + public abstract boolean dispatchEvent (AWTEvent e); + + /** + * Handles redispatching of an event so that recursion of + * dispatch requests does not occur. Event dispatch methods + * within this manager (dispatchEvent()) and + * the key event dispatchers should use this method to handle + * dispatching rather than the dispatch method of the target + * component. + *
+ *
+ * + * This method is not intended for general consumption, and is + * only for the use of the aforementioned classes. + * + * + * @param target the target component to which the event is + * dispatched. + * @param e the event to dispatch. + */ + public final void redispatchEvent (Component target, AWTEvent e) + { + e.isFocusManagerEvent = true; + target.dispatchEvent (e); + e.isFocusManagerEvent = false; + } + + /** + * Attempts to dispatch key events for which no key event dispatcher + * has so far succeeded. This method is usually called by + * dispatchEvent() following the sending of the key + * event to any registered key event dispatchers. If the key + * event reaches this stage, none of the dispatchers returned + * true. This is, of course, always the case if there are no + * registered dispatchers. + *
+ *
+ * If this method also fails to handle the key event, then + * false is returned to the caller. In the case of + * dispatchEvent(), the calling method may try + * to handle the event itself or simply forward on the + * false result to its caller. When the event is dispatched + * by this method, a true result is propogated through the + * calling methods. + * + * @param e the key event to dispatch. + * @return true if the event was dispatched successfully. + */ + public abstract boolean dispatchKeyEvent (KeyEvent e); + + /** + * Handles the post processing of key events. By default, + * this method will map unhandled key events to appropriate + * MenuShortcuts. The event is consumed + * in the process and the shortcut is activated. This + * method is usually called by dispatchKeyEvent. + * + * @param e the key event to post process. + * @return true by default, as the event was handled. + */ + public abstract boolean postProcessKeyEvent (KeyEvent e); + + /** + * Handles focus traversal operations for key events which + * represent focus traversal keys in relation to the supplied + * component. The supplied component is assumed to have the + * focus, whether it does so or not, and the operation is + * carried out as appropriate, with this in mind. + * + * @param focused the component on which to perform focus traversal, + * on the assumption that this component has the focus. + * @param e the possible focus traversal key event. + */ + public abstract void processKeyEvent (Component focused, KeyEvent e); + + /** + * Delays all key events following the specified timestamp until the + * supplied component has focus. The AWT calls this method when it is + * determined that a focus change may occur within the native windowing + * system. Any key events which occur following the time specified by + * after are delayed until a FOCUS_GAINED event is received + * for the untilFocused component. The manager is responsible for ensuring + * this takes place. + * + * @param after the timestamp beyond which all key events are delayed until + * the supplied component gains focus. + * @param untilFocused the component to wait on gaining focus. + */ + protected abstract void enqueueKeyEvents (long after, Component untilFocused); + + /** + * Removes the key event block specified by the supplied timestamp and component. + * All delayed key events are released for normal dispatching following its + * removal and subsequent key events that would have been blocked are now + * immediately dispatched. If the specified timestamp is below 0, then + * the request with the oldest timestamp is removed. + * + * @param after the timestamp of the key event block to be removed, or a + * value smaller than 0 if the oldest is to be removed. + * @param untilFocused the component of the key event block to be removed. + */ + protected abstract void dequeueKeyEvents (long after, Component untilFocused); + + /** + * Discards all key event blocks relating to focus requirements for + * the supplied component, regardless of timestamp. + * + * @param comp the component of the key event block(s) to be removed. + */ + protected abstract void discardKeyEvents (Component comp); + + /** + * Moves the current focus to the next component following + * comp, based on the current focus traversal policy. By + * default, only visible, displayable, accepted components + * can receive focus. Canvases, Panels, + * Labels, ScrollPanes, Scrollbars, + * Windows and lightweight components are judged + * to be unacceptable by default. See the + * DefaultFocusTraversalPolicy for more details. + * + * @param comp the component prior to the one which will + * become the focus, following execution of this method. + * @see DefaultFocusTraversalPolicy + */ + public abstract void focusNextComponent(Component comp); + + /** + * Moves the current focus to the previous component, prior to + * comp, based on the current focus traversal policy. By + * default, only visible, displayable, accepted components + * can receive focus. Canvases, Panels, + * Labels, ScrollPanes, Scrollbars, + * Windows and lightweight components are judged + * to be unacceptable by default. See the + * DefaultFocusTraversalPolicy for more details. + * + * @param comp the component following the one which will + * become the focus, following execution of this method. + * @see DefaultFocusTraversalPolicy + */ + public abstract void focusPreviousComponent(Component comp); + + /** + * Moves the current focus upwards by one focus cycle. + * Both the current focus owner and current focus cycle root + * become the focus cycle root of the supplied component. + * However, in the case of a Window, the default + * focus component becomes the focus owner and the focus cycle + * root is not changed. + * + * @param comp the component used as part of the focus traversal. + */ + public abstract void upFocusCycle(Component comp); + + /** + * Moves the current focus downwards by one focus cycle. + * If the supplied container is a focus cycle root, then this + * becomes the current focus cycle root and the focus goes + * to the default component of the specified container. + * Nothing happens for non-focus cycle root containers. + * + * @param cont the container used as part of the focus traversal. + */ + public abstract void downFocusCycle(Container cont); + + /** + * Moves the current focus to the next component, based on the + * current focus traversal policy. By default, only visible, + * displayable, accepted component can receive focus. + * Canvases, Panels, + * Labels, ScrollPanes, Scrollbars, + * Windows and lightweight components are judged + * to be unacceptable by default. See the + * DefaultFocusTraversalPolicy for more details. + * + * @see DefaultFocusTraversalPolicy + */ + public final void focusNextComponent() + { + focusNextComponent (null); + } + + /** + * Moves the current focus to the previous component, based on the + * current focus traversal policy. By default, only visible, + * displayable, accepted component can receive focus. + * Canvases, Panels, + * Labels, ScrollPanes, Scrollbars, + * Windows and lightweight components are judged + * to be unacceptable by default. See the + * DefaultFocusTraversalPolicy for more details. + * + * @see DefaultFocusTraversalPolicy + */ + public final void focusPreviousComponent() + { + focusPreviousComponent (null); + } + + /** + * Moves the current focus upwards by one focus cycle, + * so that the new focus owner is the focus cycle root + * of the current owner. The current focus cycle root then + * becomes the focus cycle root of the new focus owner. + * However, in the case of the focus cycle root of the + * current focus owner being a Window, the default + * component of this window becomes the focus owner and the + * focus cycle root is not changed. + */ + public final void upFocusCycle() + { + upFocusCycle (null); + } + + /** + * Moves the current focus downwards by one focus cycle, + * iff the current focus cycle root is a Container. + * Usually, the new focus owner is set to the default component + * of the container and the current focus cycle root is set + * to the current focus owner. Nothing occurs if the current + * focus cycle root is not a container. + */ + public final void downFocusCycle() + { + Component focusOwner = getGlobalFocusOwner (); + if (focusOwner instanceof Container + && ((Container) focusOwner).isFocusCycleRoot ()) + downFocusCycle ((Container) focusOwner); + } + + /** + * Retrieve an object from one of the global object {@link + * java.util.Map}s, if the object was set by the a thread in the + * current {@link java.lang.ThreadGroup}. Otherwise, return null. + * + * @param globalMap one of the global object Maps + * + * @return a global object set by the current ThreadGroup, or null + * + * @see #getFocusOwner() + * @see #getPermanentFocusOwner() + * @see #getFocusedWindow() + * @see #getActiveWindow() + * @see #getCurrentFocusCycleRoot() + */ + private Object getObject (Map globalMap) + { + ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup (); + return globalMap.get (currentGroup); + } + + /** + * Retrieve an object from one of the global object {@link + * java.util.Map}s, regardless of whether or not the object was set + * by a thread in the current {@link java.lang.ThreadGroup}. + * + * @param globalMap one of the global object Maps + * + * @return a global object set by the current ThreadGroup, or null + * + * @throws SecurityException if this is not the keyboard focus + * manager associated with the current {@link java.lang.ThreadGroup} + * + * @see #getGlobalFocusOwner() + * @see #getGlobalPermanentFocusOwner() + * @see #getGlobalFocusedWindow() + * @see #getGlobalActiveWindow() + * @see #getGlobalCurrentFocusCycleRoot() + */ + private Object getGlobalObject (Map globalMap, boolean checkThread) + { + if (checkThread) + { + ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup (); + KeyboardFocusManager managerForCallingThread = + (KeyboardFocusManager) currentKeyboardFocusManagers.get(currentGroup); + + if (this != managerForCallingThread) + throw new SecurityException ("Attempted to retrieve an object from a " + + "keyboard focus manager that isn't " + + "associated with the current thread group."); + } + synchronized (globalMap) + { + Collection globalObjects = globalMap.values (); + Iterator i = globalObjects.iterator (); + Component globalObject; + + while (i.hasNext ()) + { + globalObject = (Component) i.next (); + if (globalObject != null) + return globalObject; + } + } + + // No Object was found. + return null; + } + + /** + * Set an object in one of the global object {@link java.util.Map}s, + * that will be returned by subsequent calls to getGlobalObject on + * the same {@link java.util.Map}. + * + * @param globalMap one of the global object Maps + * @param newObject the object to set + * @param property the property that will change + * + * @see #setGlobalFocusOwner(Component) + * @see #setGlobalPermanentFocusOwner(Component) + * @see #setGlobalFocusedWindow(Window) + * @see #setGlobalActiveWindow(Window) + * @see #setGlobalCurrentFocusCycleRoot(Container) + */ + private void setGlobalObject (Map globalMap, + Object newObject, + String property) + { + synchronized (globalMap) + { + // Save old object. + Object oldObject = getGlobalObject(globalMap, false); + + // Nullify old object. + Collection threadGroups = globalMap.keySet (); + Iterator i = threadGroups.iterator (); + while (i.hasNext ()) + { + ThreadGroup oldThreadGroup = (ThreadGroup) i.next (); + if (globalMap.get (oldThreadGroup) != null) + { + globalMap.put (oldThreadGroup, null); + // There should only be one object set at a time, so + // we can short circuit. + break; + } + } + + ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup (); + firePropertyChange (property, oldObject, newObject); + try + { + fireVetoableChange (property, oldObject, newObject); + // Set new object. + globalMap.put (currentGroup, newObject); + } + catch (PropertyVetoException e) + { + } + } + } + + + /** + * Maps focus requests from heavyweight to lightweight components. + */ + private static HashMap focusRequests = new HashMap(); + + /** + * Retargets focus events that come from the peer (which only know about + * heavyweight components) to go to the correct lightweight component + * if appropriate. + * + * @param ev the event to check + * + * @return the retargetted event + */ + static AWTEvent retargetFocusEvent(AWTEvent ev) + { + if (ev instanceof FocusEvent) + { + FocusEvent fe = (FocusEvent) ev; + Component target = fe.getComponent(); + if (focusRequests.containsKey(target)) + { + Component lightweight = (Component) focusRequests.get(target); + ev = new FocusEvent(lightweight, fe.id, fe.isTemporary()); + focusRequests.remove(target); + } + } + return ev; + } + + /** + * Adds a lightweight focus request for a heavyweight component. + * + * @param heavyweight the heavyweight from which we will receive a focus + * event soon + * @param lightweight the lightweight that ultimately receives the request + */ + static void addLightweightFocusRequest(Component heavyweight, + Component lightweight) + { + focusRequests.put(heavyweight, lightweight); + } +} -- cgit v1.2.3