/* * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.awt; import java.awt.event.FocusEvent; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.WindowEvent; import java.awt.peer.KeyboardFocusManagerPeer; import java.awt.peer.LightweightPeer; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.beans.PropertyVetoException; import java.beans.VetoableChangeListener; import java.beans.VetoableChangeSupport; import java.lang.ref.WeakReference; import java.lang.reflect.Field; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.Set; import java.util.StringTokenizer; import java.util.WeakHashMap; import sun.util.logging.PlatformLogger; import sun.awt.AppContext; import sun.awt.HeadlessToolkit; import sun.awt.SunToolkit; import sun.awt.CausedFocusEvent; import sun.awt.KeyboardFocusManagerPeerProvider; import sun.awt.AWTAccessor; /** * The KeyboardFocusManager is responsible for managing the active and focused * Windows, and the current focus owner. The focus owner is defined as the * Component in an application that will typically receive all KeyEvents * generated by the user. The focused Window is the Window that is, or * contains, the focus owner. Only a Frame or a Dialog can be the active * Window. The native windowing system may denote the active Window or its * children with special decorations, such as a highlighted title bar. The * active Window is always either the focused Window, or the first Frame or * Dialog that is an owner of the focused Window. *
* The KeyboardFocusManager is both a centralized location for client code to * query for the focus owner and initiate focus changes, and an event * dispatcher for all FocusEvents, WindowEvents related to focus, and * KeyEvents. *
* Some browsers partition applets in different code bases into separate * contexts, and establish walls between these contexts. In such a scenario, * there will be one KeyboardFocusManager per context. Other browsers place all * applets into the same context, implying that there will be only a single, * global KeyboardFocusManager for all applets. This behavior is * implementation-dependent. Consult your browser's documentation for more * information. No matter how many contexts there may be, however, there can * never be more than one focus owner, focused Window, or active Window, per * ClassLoader. *
* Please see * * How to Use the Focus Subsystem, * a section in The Java Tutorial, and the * Focus Specification * for more information. * * @author David Mendenhall * * @see Window * @see Frame * @see Dialog * @see java.awt.event.FocusEvent * @see java.awt.event.WindowEvent * @see java.awt.event.KeyEvent * @since 1.4 */ public abstract class KeyboardFocusManager implements KeyEventDispatcher, KeyEventPostProcessor { // Shared focus engine logger private static final PlatformLogger focusLog = PlatformLogger.getLogger("java.awt.focus.KeyboardFocusManager"); static { /* ensure that the necessary native libraries are loaded */ Toolkit.loadLibraries(); if (!GraphicsEnvironment.isHeadless()) { initIDs(); } AWTAccessor.setKeyboardFocusManagerAccessor( new AWTAccessor.KeyboardFocusManagerAccessor() { public int shouldNativelyFocusHeavyweight(Component heavyweight, Component descendant, boolean temporary, boolean focusedWindowChangeAllowed, long time, CausedFocusEvent.Cause cause) { return KeyboardFocusManager.shouldNativelyFocusHeavyweight( heavyweight, descendant, temporary, focusedWindowChangeAllowed, time, cause); } public boolean processSynchronousLightweightTransfer(Component heavyweight, Component descendant, boolean temporary, boolean focusedWindowChangeAllowed, long time) { return KeyboardFocusManager.processSynchronousLightweightTransfer( heavyweight, descendant, temporary, focusedWindowChangeAllowed, time); } public void removeLastFocusRequest(Component heavyweight) { KeyboardFocusManager.removeLastFocusRequest(heavyweight); } public void setMostRecentFocusOwner(Window window, Component component) { KeyboardFocusManager.setMostRecentFocusOwner(window, component); } public KeyboardFocusManager getCurrentKeyboardFocusManager(AppContext ctx) { return KeyboardFocusManager.getCurrentKeyboardFocusManager(ctx); } } ); } transient KeyboardFocusManagerPeer peer; /** * Initialize JNI field and method IDs */ private static native void initIDs(); private static final PlatformLogger log = PlatformLogger.getLogger("java.awt.KeyboardFocusManager"); /** * The identifier for the Forward focus traversal keys. * * @see #setDefaultFocusTraversalKeys * @see #getDefaultFocusTraversalKeys * @see Component#setFocusTraversalKeys * @see Component#getFocusTraversalKeys */ public static final int FORWARD_TRAVERSAL_KEYS = 0; /** * The identifier for the Backward focus traversal keys. * * @see #setDefaultFocusTraversalKeys * @see #getDefaultFocusTraversalKeys * @see Component#setFocusTraversalKeys * @see Component#getFocusTraversalKeys */ public static final int BACKWARD_TRAVERSAL_KEYS = 1; /** * The identifier for the Up Cycle focus traversal keys. * * @see #setDefaultFocusTraversalKeys * @see #getDefaultFocusTraversalKeys * @see Component#setFocusTraversalKeys * @see Component#getFocusTraversalKeys */ public static final int UP_CYCLE_TRAVERSAL_KEYS = 2; /** * The identifier for the Down Cycle focus traversal keys. * * @see #setDefaultFocusTraversalKeys * @see #getDefaultFocusTraversalKeys * @see Component#setFocusTraversalKeys * @see Component#getFocusTraversalKeys */ public static final int DOWN_CYCLE_TRAVERSAL_KEYS = 3; static final int TRAVERSAL_KEY_LENGTH = DOWN_CYCLE_TRAVERSAL_KEYS + 1; /** * Returns the current KeyboardFocusManager instance for the calling * thread's context. * * @return this thread's context's KeyboardFocusManager * @see #setCurrentKeyboardFocusManager */ public static KeyboardFocusManager getCurrentKeyboardFocusManager() { return getCurrentKeyboardFocusManager(AppContext.getAppContext()); } synchronized static KeyboardFocusManager getCurrentKeyboardFocusManager(AppContext appcontext) { KeyboardFocusManager manager = (KeyboardFocusManager) appcontext.get(KeyboardFocusManager.class); if (manager == null) { manager = new DefaultKeyboardFocusManager(); appcontext.put(KeyboardFocusManager.class, manager); } return manager; } /** * Sets the current KeyboardFocusManager instance for the calling thread's * context. If null is specified, then the current KeyboardFocusManager * is replaced with a new instance of DefaultKeyboardFocusManager. *
* If a SecurityManager is installed, the calling thread must be granted
* the AWTPermission "replaceKeyboardFocusManager" in order to replace the
* the current KeyboardFocusManager. If this permission is not granted,
* this method will throw a SecurityException, and the current
* KeyboardFocusManager will be unchanged.
*
* @param newManager the new KeyboardFocusManager for this thread's context
* @see #getCurrentKeyboardFocusManager
* @see DefaultKeyboardFocusManager
* @throws SecurityException if the calling thread does not have permission
* to replace the current KeyboardFocusManager
*/
public static void setCurrentKeyboardFocusManager(
KeyboardFocusManager newManager) throws SecurityException
{
checkReplaceKFMPermission();
KeyboardFocusManager oldManager = null;
synchronized (KeyboardFocusManager.class) {
AppContext appcontext = AppContext.getAppContext();
if (newManager != null) {
oldManager = getCurrentKeyboardFocusManager(appcontext);
appcontext.put(KeyboardFocusManager.class, newManager);
} else {
oldManager = getCurrentKeyboardFocusManager(appcontext);
appcontext.remove(KeyboardFocusManager.class);
}
}
if (oldManager != null) {
oldManager.firePropertyChange("managingFocus",
Boolean.TRUE,
Boolean.FALSE);
}
if (newManager != null) {
newManager.firePropertyChange("managingFocus",
Boolean.FALSE,
Boolean.TRUE);
}
}
/**
* The Component in an application that will typically receive all
* KeyEvents generated by the user.
*/
private static Component focusOwner;
/**
* The Component in an application that will regain focus when an
* outstanding temporary focus transfer has completed, or the focus owner,
* if no outstanding temporary transfer exists.
*/
private static Component permanentFocusOwner;
/**
* The Window which is, or contains, the focus owner.
*/
private static Window focusedWindow;
/**
* Only a Frame or a Dialog can be the active Window. The native windowing
* system may denote the active Window with a special decoration, such as a
* highlighted title bar. The active Window is always either the focused
* Window, or the first Frame or Dialog which is an owner of the focused
* Window.
*/
private static Window activeWindow;
/**
* The default FocusTraversalPolicy for all Windows that have no policy of
* their own set. If those Windows have focus-cycle-root children that have
* no keyboard-traversal policy of their own, then those children will also
* inherit this policy (as will, recursively, their focus-cycle-root
* children).
*/
private FocusTraversalPolicy defaultPolicy =
new DefaultFocusTraversalPolicy();
/**
* The bound property names of each focus traversal key.
*/
private static final String[] defaultFocusTraversalKeyPropertyNames = {
"forwardDefaultFocusTraversalKeys",
"backwardDefaultFocusTraversalKeys",
"upCycleDefaultFocusTraversalKeys",
"downCycleDefaultFocusTraversalKeys"
};
/**
* The default strokes for initializing the default focus traversal keys.
*/
private static final AWTKeyStroke[][] defaultFocusTraversalKeyStrokes = {
{
AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, 0, false),
AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, InputEvent.CTRL_DOWN_MASK | InputEvent.CTRL_MASK, false),
},
{
AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_DOWN_MASK | InputEvent.SHIFT_MASK, false),
AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB,
InputEvent.SHIFT_DOWN_MASK | InputEvent.SHIFT_MASK | InputEvent.CTRL_DOWN_MASK | InputEvent.CTRL_MASK,
false),
},
{},
{},
};
/**
* The default focus traversal keys. Each array of traversal keys will be
* in effect on all Windows that have no such array of their own explicitly
* set. Each array will also be inherited, recursively, by any child
* Component of those Windows that has no such array of its own explicitly
* set.
*/
private Set[] defaultFocusTraversalKeys = new Set[4];
/**
* The current focus cycle root. If the focus owner is itself a focus cycle
* root, then it may be ambiguous as to which Components represent the next
* and previous Components to focus during normal focus traversal. In that
* case, the current focus cycle root is used to differentiate among the
* possibilities.
*/
private static Container currentFocusCycleRoot;
/**
* A description of any VetoableChangeListeners which have been registered.
*/
private VetoableChangeSupport vetoableSupport;
/**
* A description of any PropertyChangeListeners which have been registered.
*/
private PropertyChangeSupport changeSupport;
/**
* This KeyboardFocusManager's KeyEventDispatcher chain. The List does not
* include this KeyboardFocusManager unless it was explicitly re-registered
* via a call to addKeyEventDispatcher
. If no other
* KeyEventDispatchers are registered, this field may be null or refer to
* a List of length 0.
*/
private java.util.LinkedList keyEventDispatchers;
/**
* This KeyboardFocusManager's KeyEventPostProcessor chain. The List does
* not include this KeyboardFocusManager unless it was explicitly
* re-registered via a call to addKeyEventPostProcessor
.
* If no other KeyEventPostProcessors are registered, this field may be
* null or refer to a List of length 0.
*/
private java.util.LinkedList keyEventPostProcessors;
/**
* Maps Windows to those Windows' most recent focus owners.
*/
private static java.util.Map mostRecentFocusOwners = new WeakHashMap();
/**
* We cache the permission used to verify that the calling thread is
* permitted to access the global focus state.
*/
private static AWTPermission replaceKeyboardFocusManagerPermission;
/*
* SequencedEvent which is currently dispatched in AppContext.
*/
transient SequencedEvent currentSequencedEvent = null;
final void setCurrentSequencedEvent(SequencedEvent current) {
synchronized (SequencedEvent.class) {
assert(current == null || currentSequencedEvent == null);
currentSequencedEvent = current;
}
}
final SequencedEvent getCurrentSequencedEvent() {
synchronized (SequencedEvent.class) {
return currentSequencedEvent;
}
}
static Set initFocusTraversalKeysSet(String value, Set targetSet) {
StringTokenizer tokens = new StringTokenizer(value, ",");
while (tokens.hasMoreTokens()) {
targetSet.add(AWTKeyStroke.getAWTKeyStroke(tokens.nextToken()));
}
return (targetSet.isEmpty())
? Collections.EMPTY_SET
: Collections.unmodifiableSet(targetSet);
}
/**
* Initializes a KeyboardFocusManager.
*/
public KeyboardFocusManager() {
for (int i = 0; i < TRAVERSAL_KEY_LENGTH; i++) {
Set work_set = new HashSet();
for (int j = 0; j < defaultFocusTraversalKeyStrokes[i].length; j++) {
work_set.add(defaultFocusTraversalKeyStrokes[i][j]);
}
defaultFocusTraversalKeys[i] = (work_set.isEmpty())
? Collections.EMPTY_SET
: Collections.unmodifiableSet(work_set);
}
initPeer();
}
private void initPeer() {
Toolkit tk = Toolkit.getDefaultToolkit();
KeyboardFocusManagerPeerProvider peerProvider = (KeyboardFocusManagerPeerProvider)tk;
peer = peerProvider.createKeyboardFocusManagerPeer(this);
}
/**
* Returns the focus owner, if the focus owner is in the same context as
* the calling thread. The focus owner is defined as the Component in an
* application that will typically receive all KeyEvents generated by the
* user. KeyEvents which map to the focus owner's focus traversal keys will
* not be delivered if focus traversal keys are enabled for the focus
* owner. In addition, KeyEventDispatchers may retarget or consume
* KeyEvents before they reach the focus owner.
*
* @return the focus owner, or null if the focus owner is not a member of
* the calling thread's context
* @see #getGlobalFocusOwner
* @see #setGlobalFocusOwner
*/
public Component getFocusOwner() {
synchronized (KeyboardFocusManager.class) {
if (focusOwner == null) {
return null;
}
return (focusOwner.appContext == AppContext.getAppContext())
? focusOwner
: null;
}
}
/**
* Returns the focus owner, even if the calling thread is in a different
* context than the focus owner. The focus owner is defined as the
* Component in an application that will typically receive all KeyEvents
* generated by the user. KeyEvents which map to the focus owner's focus
* traversal keys will not be delivered if focus traversal keys are enabled
* for the focus owner. In addition, KeyEventDispatchers may retarget or
* consume KeyEvents before they reach the focus owner.
*
* This method will throw a SecurityException if this KeyboardFocusManager * is not the current KeyboardFocusManager for the calling thread's * context. * * @return the focus owner * @see #getFocusOwner * @see #setGlobalFocusOwner * @throws SecurityException if this KeyboardFocusManager is not the * current KeyboardFocusManager for the calling thread's context * and if the calling thread does not have "replaceKeyboardFocusManager" * permission */ protected Component getGlobalFocusOwner() throws SecurityException { synchronized (KeyboardFocusManager.class) { checkKFMSecurity(); return focusOwner; } } /** * Sets the focus owner. The operation will be cancelled if the Component * is not focusable. The focus owner is defined as the Component in an * application that will typically receive all KeyEvents generated by the * user. KeyEvents which map to the focus owner's focus traversal keys will * not be delivered if focus traversal keys are enabled for the focus * owner. In addition, KeyEventDispatchers may retarget or consume * KeyEvents before they reach the focus owner. *
* This method does not actually set the focus to the specified Component.
* It merely stores the value to be subsequently returned by
* getFocusOwner()
. Use Component.requestFocus()
* or Component.requestFocusInWindow()
to change the focus
* owner, subject to platform limitations.
*
* @param focusOwner the focus owner
* @see #getFocusOwner
* @see #getGlobalFocusOwner
* @see Component#requestFocus()
* @see Component#requestFocusInWindow()
* @see Component#isFocusable
* @throws SecurityException if this KeyboardFocusManager is not the
* current KeyboardFocusManager for the calling thread's context
* and if the calling thread does not have "replaceKeyboardFocusManager"
* permission
* @beaninfo
* bound: true
*/
protected void setGlobalFocusOwner(Component focusOwner)
throws SecurityException
{
Component oldFocusOwner = null;
boolean shouldFire = false;
if (focusOwner == null || focusOwner.isFocusable()) {
synchronized (KeyboardFocusManager.class) {
checkKFMSecurity();
oldFocusOwner = getFocusOwner();
try {
fireVetoableChange("focusOwner", oldFocusOwner,
focusOwner);
} catch (PropertyVetoException e) {
// rejected
return;
}
KeyboardFocusManager.focusOwner = focusOwner;
if (focusOwner != null &&
(getCurrentFocusCycleRoot() == null ||
!focusOwner.isFocusCycleRoot(getCurrentFocusCycleRoot())))
{
Container rootAncestor =
focusOwner.getFocusCycleRootAncestor();
if (rootAncestor == null && (focusOwner instanceof Window))
{
rootAncestor = (Container)focusOwner;
}
if (rootAncestor != null) {
setGlobalCurrentFocusCycleRootPriv(rootAncestor);
}
}
shouldFire = true;
}
}
if (shouldFire) {
firePropertyChange("focusOwner", oldFocusOwner, focusOwner);
}
}
/**
* Clears the focus owner at both the Java and native levels if the
* focus owner exists and resides in the same context as the calling thread,
* otherwise the method returns silently.
*
* The focus owner component will receive a permanent FOCUS_LOST event.
* After this operation completes, the native windowing system will discard
* all user-generated KeyEvents until the user selects a new Component to
* receive focus, or a Component is given focus explicitly via a call to
* {@code requestFocus()}. This operation does not change the focused or
* active Windows.
*
* @see Component#requestFocus()
* @see java.awt.event.FocusEvent#FOCUS_LOST
*/
public void clearFocusOwner() {
if (getFocusOwner() != null) {
clearGlobalFocusOwner();
}
}
/**
* Clears the global focus owner at both the Java and native levels. If
* there exists a focus owner, that Component will receive a permanent
* FOCUS_LOST event. After this operation completes, the native windowing
* system will discard all user-generated KeyEvents until the user selects
* a new Component to receive focus, or a Component is given focus
* explicitly via a call to requestFocus()
. This operation
* does not change the focused or active Windows.
*
* If a SecurityManager is installed, the calling thread must be granted * the "replaceKeyboardFocusManager" AWTPermission. If this permission is * not granted, this method will throw a SecurityException, and the current * focus owner will not be cleared. *
* This method is intended to be used only by KeyboardFocusManager set as
* current KeyboardFocusManager for the calling thread's context. It is not
* for general client use.
*
* @see KeyboardFocusManager#clearFocusOwner
* @see Component#requestFocus()
* @see java.awt.event.FocusEvent#FOCUS_LOST
* @throws SecurityException if the calling thread does not have
* "replaceKeyboardFocusManager" permission
*/
public void clearGlobalFocusOwner()
throws SecurityException
{
checkReplaceKFMPermission();
if (!GraphicsEnvironment.isHeadless()) {
// Toolkit must be fully initialized, otherwise
// _clearGlobalFocusOwner will crash or throw an exception
Toolkit.getDefaultToolkit();
_clearGlobalFocusOwner();
}
}
private void _clearGlobalFocusOwner() {
Window activeWindow = markClearGlobalFocusOwner();
peer.clearGlobalFocusOwner(activeWindow);
}
void clearGlobalFocusOwnerPriv() {
AccessController.doPrivileged(new PrivilegedAction
* This method does not actually set the focus to the specified Component.
* It merely stores the value to be subsequently returned by
*
* This method does not actually change the focused Window as far as the
* native windowing system is concerned. It merely stores the value to be
* subsequently returned by
* This method does not actually change the active Window as far as the
* native windowing system is concerned. It merely stores the value to be
* subsequently returned by
* The default values for the default focus traversal keys are
* implementation-dependent. Sun recommends that all implementations for a
* particular native platform use the same default values. The
* recommendations for Windows and Unix are listed below. These
* recommendations are used in the Sun AWT implementations.
*
*
* Using the {@code AWTKeyStroke} API, client code can
* specify on which of two
* specific {@code KeyEvent}s, {@code KEY_PRESSED} or
* {@code KEY_RELEASED}, the focus traversal operation will
* occur. Regardless of which {@code KeyEvent} is specified,
* however, all {@code KeyEvent}s related to the focus
* traversal key, including the associated {@code KEY_TYPED}
* event, will be consumed, and will not be dispatched
* to any {@code Component}. It is a runtime error to
* specify a {@code KEY_TYPED} event as
* mapping to a focus traversal operation, or to map the same event to
* multiple default focus traversal operations.
*
* This method may throw a {@code ClassCastException} if any {@code Object}
* in {@code keystrokes} is not an {@code AWTKeyStroke}.
*
* @param id one of
* {@code KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS},
* {@code KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS},
* {@code KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS}, or
* {@code KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS}
* @param keystrokes the Set of {@code AWTKeyStroke}s for the
* specified operation
* @see #getDefaultFocusTraversalKeys
* @see Component#setFocusTraversalKeys
* @see Component#getFocusTraversalKeys
* @throws IllegalArgumentException if id is not one of
* {@code KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS},
* {@code KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS},
* {@code KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS}, or
* {@code KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS},
* or if keystrokes is {@code null},
* or if keystrokes contains {@code null},
* or if any keystroke
* represents a {@code KEY_TYPED} event,
* or if any keystroke already maps
* to another default focus traversal operation
* @beaninfo
* bound: true
*/
public void
setDefaultFocusTraversalKeys(int id,
Set extends AWTKeyStroke> keystrokes)
{
if (id < 0 || id >= TRAVERSAL_KEY_LENGTH) {
throw new IllegalArgumentException("invalid focus traversal key identifier");
}
if (keystrokes == null) {
throw new IllegalArgumentException("cannot set null Set of default focus traversal keys");
}
Set oldKeys;
synchronized (this) {
for (AWTKeyStroke keystroke : keystrokes) {
if (keystroke == null) {
throw new IllegalArgumentException("cannot set null focus traversal key");
}
if (keystroke.getKeyChar() != KeyEvent.CHAR_UNDEFINED) {
throw new IllegalArgumentException("focus traversal keys cannot map to KEY_TYPED events");
}
// Check to see if key already maps to another traversal
// operation
for (int i = 0; i < TRAVERSAL_KEY_LENGTH; i++) {
if (i == id) {
continue;
}
if (defaultFocusTraversalKeys[i].contains(keystroke)) {
throw new IllegalArgumentException("focus traversal keys must be unique for a Component");
}
}
}
oldKeys = defaultFocusTraversalKeys[id];
defaultFocusTraversalKeys[id] =
Collections.unmodifiableSet(new HashSet(keystrokes));
}
firePropertyChange(defaultFocusTraversalKeyPropertyNames[id],
oldKeys, keystrokes);
}
/**
* Returns a Set of default focus traversal keys for a given traversal
* operation. This traversal key Set will be in effect on all Windows that
* have no such Set of their own explicitly defined. This Set will also be
* inherited, recursively, by any child Component of those Windows that has
* no such Set of its own explicitly defined. (See
*
* This method is intended to be used only by KeyboardFocusManagers and
* focus implementations. It is not for general client use.
*
* @return the current focus cycle root, or null if the current focus cycle
* root is not a member of the calling thread's context
* @see #getGlobalCurrentFocusCycleRoot
* @see #setGlobalCurrentFocusCycleRoot
*/
public Container getCurrentFocusCycleRoot() {
synchronized (KeyboardFocusManager.class) {
if (currentFocusCycleRoot == null) {
return null;
}
return (currentFocusCycleRoot.appContext ==
AppContext.getAppContext())
? currentFocusCycleRoot
: null;
}
}
/**
* Returns the current focus cycle root, even if the calling thread is in a
* different context than the current focus cycle root. If the focus owner
* is itself a focus cycle root, then it may be ambiguous as to which
* Components represent the next and previous Components to focus during
* normal focus traversal. In that case, the current focus cycle root is
* used to differentiate among the possibilities.
*
* @return the current focus cycle root, or null if the current focus cycle
* root is not a member of the calling thread's context
* @see #getCurrentFocusCycleRoot
* @see #setGlobalCurrentFocusCycleRoot
* @throws SecurityException if this KeyboardFocusManager is not the
* current KeyboardFocusManager for the calling thread's context
* and if the calling thread does not have "replaceKeyboardFocusManager"
* permission
*/
protected Container getGlobalCurrentFocusCycleRoot()
throws SecurityException
{
synchronized (KeyboardFocusManager.class) {
checkKFMSecurity();
return currentFocusCycleRoot;
}
}
/**
* Sets the current focus cycle root. If the focus owner is itself a focus
* cycle root, then it may be ambiguous as to which Components represent
* the next and previous Components to focus during normal focus traversal.
* In that case, the current focus cycle root is used to differentiate
* among the possibilities.
*
* If a SecurityManager is installed, the calling thread must be granted
* the "replaceKeyboardFocusManager" AWTPermission. If this permission is
* not granted, this method will throw a SecurityException, and the current
* focus cycle root will not be changed.
*
* This method is intended to be used only by KeyboardFocusManagers and
* focus implementations. It is not for general client use.
*
* @param newFocusCycleRoot the new focus cycle root
* @see #getCurrentFocusCycleRoot
* @see #getGlobalCurrentFocusCycleRoot
* @throws SecurityException if the calling thread does not have
* "replaceKeyboardFocusManager" permission
* @beaninfo
* bound: true
*/
public void setGlobalCurrentFocusCycleRoot(Container newFocusCycleRoot)
throws SecurityException
{
checkReplaceKFMPermission();
Container oldFocusCycleRoot;
synchronized (KeyboardFocusManager.class) {
oldFocusCycleRoot = getCurrentFocusCycleRoot();
currentFocusCycleRoot = newFocusCycleRoot;
}
firePropertyChange("currentFocusCycleRoot", oldFocusCycleRoot,
newFocusCycleRoot);
}
void setGlobalCurrentFocusCycleRootPriv(final Container newFocusCycleRoot) {
AccessController.doPrivileged(new PrivilegedAction
* If listener is null, no exception is thrown and no action is performed.
*
* @param listener the PropertyChangeListener to be removed
* @see #addPropertyChangeListener
* @see #getPropertyChangeListeners
* @see #removePropertyChangeListener(java.lang.String,java.beans.PropertyChangeListener)
*/
public void removePropertyChangeListener(PropertyChangeListener listener) {
if (listener != null) {
synchronized (this) {
if (changeSupport != null) {
changeSupport.removePropertyChangeListener(listener);
}
}
}
}
/**
* Returns an array of all the property change listeners
* registered on this keyboard focus manager.
*
* @return all of this keyboard focus manager's
*
* If listener is null, no exception is thrown and no action is performed.
*
* @param propertyName a valid property name
* @param listener the PropertyChangeListener to be removed
* @see #addPropertyChangeListener(java.lang.String,java.beans.PropertyChangeListener)
* @see #getPropertyChangeListeners(java.lang.String)
* @see #removePropertyChangeListener(java.beans.PropertyChangeListener)
*/
public void removePropertyChangeListener(String propertyName,
PropertyChangeListener listener) {
if (listener != null) {
synchronized (this) {
if (changeSupport != null) {
changeSupport.removePropertyChangeListener(propertyName,
listener);
}
}
}
}
/**
* Returns an array of all the
* If listener is null, no exception is thrown and no action is performed.
*
* @param listener the VetoableChangeListener to be removed
* @see #addVetoableChangeListener
* @see #getVetoableChangeListeners
* @see #removeVetoableChangeListener(java.lang.String,java.beans.VetoableChangeListener)
*/
public void removeVetoableChangeListener(VetoableChangeListener listener) {
if (listener != null) {
synchronized (this) {
if (vetoableSupport != null) {
vetoableSupport.removeVetoableChangeListener(listener);
}
}
}
}
/**
* Returns an array of all the vetoable change listeners
* registered on this keyboard focus manager.
*
* @return all of this keyboard focus manager's
*
* If listener is null, no exception is thrown and no action is performed.
*
* @param propertyName a valid property name
* @param listener the VetoableChangeListener to be removed
* @see #addVetoableChangeListener
* @see #getVetoableChangeListeners
* @see #removeVetoableChangeListener(java.beans.VetoableChangeListener)
*/
public void removeVetoableChangeListener(String propertyName,
VetoableChangeListener listener) {
if (listener != null) {
synchronized (this) {
if (vetoableSupport != null) {
vetoableSupport.removeVetoableChangeListener(propertyName,
listener);
}
}
}
}
/**
* Returns an array of all the
* If a null dispatcher is specified, no action is taken and no exception
* is thrown.
*
* In a multithreaded application, {@link KeyEventDispatcher} behaves
* the same as other AWT listeners. See
* AWT Threading Issues for more details.
*
* @param dispatcher the KeyEventDispatcher to add to the dispatcher chain
* @see #removeKeyEventDispatcher
*/
public void addKeyEventDispatcher(KeyEventDispatcher dispatcher) {
if (dispatcher != null) {
synchronized (this) {
if (keyEventDispatchers == null) {
keyEventDispatchers = new java.util.LinkedList();
}
keyEventDispatchers.add(dispatcher);
}
}
}
/**
* Removes a KeyEventDispatcher which was previously added to this
* KeyboardFocusManager's dispatcher chain. This KeyboardFocusManager
* cannot itself be removed, unless it was explicitly re-registered via a
* call to
* If a null dispatcher is specified, if the specified dispatcher is not
* in the dispatcher chain, or if this KeyboardFocusManager is specified
* without having been explicitly re-registered, no action is taken and no
* exception is thrown.
*
* In a multithreaded application, {@link KeyEventDispatcher} behaves
* the same as other AWT listeners. See
* AWT Threading Issues for more details.
*
* @param dispatcher the KeyEventDispatcher to remove from the dispatcher
* chain
* @see #addKeyEventDispatcher
*/
public void removeKeyEventDispatcher(KeyEventDispatcher dispatcher) {
if (dispatcher != null) {
synchronized (this) {
if (keyEventDispatchers != null) {
keyEventDispatchers.remove(dispatcher);
}
}
}
}
/**
* Returns this KeyboardFocusManager's KeyEventDispatcher chain as a List.
* The List will not include this KeyboardFocusManager unless it was
* explicitly re-registered via a call to
*
* If a null post-processor is specified, no action is taken and no
* exception is thrown.
*
* In a multithreaded application, {@link KeyEventPostProcessor} behaves
* the same as other AWT listeners. See
* AWT Threading Issues for more details.
*
* @param processor the KeyEventPostProcessor to add to the post-processor
* chain
* @see #removeKeyEventPostProcessor
*/
public void addKeyEventPostProcessor(KeyEventPostProcessor processor) {
if (processor != null) {
synchronized (this) {
if (keyEventPostProcessors == null) {
keyEventPostProcessors = new java.util.LinkedList();
}
keyEventPostProcessors.add(processor);
}
}
}
/**
* Removes a previously added KeyEventPostProcessor from this
* KeyboardFocusManager's post-processor chain. This KeyboardFocusManager
* cannot itself be entirely removed from the chain. Only additional
* references added via
* If a null post-processor is specified, if the specified post-processor
* is not in the post-processor chain, or if this KeyboardFocusManager is
* specified without having been explicitly added, no action is taken and
* no exception is thrown.
*
* In a multithreaded application, {@link KeyEventPostProcessor} behaves
* the same as other AWT listeners. See
* AWT Threading Issues for more details.
*
* @param processor the KeyEventPostProcessor to remove from the post-
* processor chain
* @see #addKeyEventPostProcessor
*/
public void removeKeyEventPostProcessor(KeyEventPostProcessor processor) {
if (processor != null) {
synchronized (this) {
if (keyEventPostProcessors != null) {
keyEventPostProcessors.remove(processor);
}
}
}
}
/**
* Returns this KeyboardFocusManager's KeyEventPostProcessor chain as a
* List. The List will not include this KeyboardFocusManager unless it was
* explicitly added via a call to
* This method is intended to be used only by KeyboardFocusManagers and
* KeyEventDispatchers. It is not for general client use.
*
* @param target the Component to which the event should be dispatched
* @param e the event to dispatch
* @see #dispatchEvent
* @see KeyEventDispatcher
*/
public final void redispatchEvent(Component target, AWTEvent e) {
e.focusManagerIsDispatching = true;
target.dispatchEvent(e);
e.focusManagerIsDispatching = false;
}
/**
* Typically this method will be called by getPermanentFocusOwner()
. Use
* Component.requestFocus()
or
* Component.requestFocusInWindow()
to change the focus owner,
* subject to platform limitations.
*
* @param permanentFocusOwner the permanent focus owner
* @see #getPermanentFocusOwner
* @see #getGlobalPermanentFocusOwner
* @see Component#requestFocus()
* @see Component#requestFocusInWindow()
* @see Component#isFocusable
* @throws SecurityException if this KeyboardFocusManager is not the
* current KeyboardFocusManager for the calling thread's context
* and if the calling thread does not have "replaceKeyboardFocusManager"
* permission
* @beaninfo
* bound: true
*/
protected void setGlobalPermanentFocusOwner(Component permanentFocusOwner)
throws SecurityException
{
Component oldPermanentFocusOwner = null;
boolean shouldFire = false;
if (permanentFocusOwner == null || permanentFocusOwner.isFocusable()) {
synchronized (KeyboardFocusManager.class) {
checkKFMSecurity();
oldPermanentFocusOwner = getPermanentFocusOwner();
try {
fireVetoableChange("permanentFocusOwner",
oldPermanentFocusOwner,
permanentFocusOwner);
} catch (PropertyVetoException e) {
// rejected
return;
}
KeyboardFocusManager.permanentFocusOwner = permanentFocusOwner;
KeyboardFocusManager.
setMostRecentFocusOwner(permanentFocusOwner);
shouldFire = true;
}
}
if (shouldFire) {
firePropertyChange("permanentFocusOwner", oldPermanentFocusOwner,
permanentFocusOwner);
}
}
/**
* Returns the focused Window, if the focused Window is in the same context
* as the calling thread. The focused Window is the Window that is or
* contains the focus owner.
*
* @return the focused Window, or null if the focused Window is not a
* member of the calling thread's context
* @see #getGlobalFocusedWindow
* @see #setGlobalFocusedWindow
*/
public Window getFocusedWindow() {
synchronized (KeyboardFocusManager.class) {
if (focusedWindow == null) {
return null;
}
return (focusedWindow.appContext == AppContext.getAppContext())
? focusedWindow
: null;
}
}
/**
* Returns the focused Window, even if the calling thread is in a different
* context than the focused Window. The focused Window is the Window that
* is or contains the focus owner.
*
* @return the focused Window
* @see #getFocusedWindow
* @see #setGlobalFocusedWindow
* @throws SecurityException if this KeyboardFocusManager is not the
* current KeyboardFocusManager for the calling thread's context
* and if the calling thread does not have "replaceKeyboardFocusManager"
* permission
*/
protected Window getGlobalFocusedWindow() throws SecurityException {
synchronized (KeyboardFocusManager.class) {
checkKFMSecurity();
return focusedWindow;
}
}
/**
* Sets the focused Window. The focused Window is the Window that is or
* contains the focus owner. The operation will be cancelled if the
* specified Window to focus is not a focusable Window.
* getFocusedWindow()
. Use
* Component.requestFocus()
or
* Component.requestFocusInWindow()
to change the focused
* Window, subject to platform limitations.
*
* @param focusedWindow the focused Window
* @see #getFocusedWindow
* @see #getGlobalFocusedWindow
* @see Component#requestFocus()
* @see Component#requestFocusInWindow()
* @see Window#isFocusableWindow
* @throws SecurityException if this KeyboardFocusManager is not the
* current KeyboardFocusManager for the calling thread's context
* and if the calling thread does not have "replaceKeyboardFocusManager"
* permission
* @beaninfo
* bound: true
*/
protected void setGlobalFocusedWindow(Window focusedWindow)
throws SecurityException
{
Window oldFocusedWindow = null;
boolean shouldFire = false;
if (focusedWindow == null || focusedWindow.isFocusableWindow()) {
synchronized (KeyboardFocusManager.class) {
checkKFMSecurity();
oldFocusedWindow = getFocusedWindow();
try {
fireVetoableChange("focusedWindow", oldFocusedWindow,
focusedWindow);
} catch (PropertyVetoException e) {
// rejected
return;
}
KeyboardFocusManager.focusedWindow = focusedWindow;
shouldFire = true;
}
}
if (shouldFire) {
firePropertyChange("focusedWindow", oldFocusedWindow,
focusedWindow);
}
}
/**
* Returns the active Window, if the active Window is in the same context
* as the calling thread. Only a Frame or a Dialog can be the active
* Window. The native windowing system may denote the active Window or its
* children with special decorations, such as a highlighted title bar.
* The active Window is always either the focused Window, or the first
* Frame or Dialog that is an owner of the focused Window.
*
* @return the active Window, or null if the active Window is not a member
* of the calling thread's context
* @see #getGlobalActiveWindow
* @see #setGlobalActiveWindow
*/
public Window getActiveWindow() {
synchronized (KeyboardFocusManager.class) {
if (activeWindow == null) {
return null;
}
return (activeWindow.appContext == AppContext.getAppContext())
? activeWindow
: null;
}
}
/**
* Returns the active Window, even if the calling thread is in a different
* context than the active Window. Only a Frame or a Dialog can be the
* active Window. The native windowing system may denote the active Window
* or its children with special decorations, such as a highlighted title
* bar. The active Window is always either the focused Window, or the first
* Frame or Dialog that is an owner of the focused Window.
*
* @return the active Window
* @see #getActiveWindow
* @see #setGlobalActiveWindow
* @throws SecurityException if this KeyboardFocusManager is not the
* current KeyboardFocusManager for the calling thread's context
* and if the calling thread does not have "replaceKeyboardFocusManager"
* permission
*/
protected Window getGlobalActiveWindow() throws SecurityException {
synchronized (KeyboardFocusManager.class) {
checkKFMSecurity();
return activeWindow;
}
}
/**
* Sets the active Window. Only a Frame or a Dialog can be the active
* Window. The native windowing system may denote the active Window or its
* children with special decorations, such as a highlighted title bar. The
* active Window is always either the focused Window, or the first Frame or
* Dialog that is an owner of the focused Window.
* getActiveWindow()
. Use
* Component.requestFocus()
or
* Component.requestFocusInWindow()
to change the active
* Window, subject to platform limitations.
*
* @param activeWindow the active Window
* @see #getActiveWindow
* @see #getGlobalActiveWindow
* @see Component#requestFocus()
* @see Component#requestFocusInWindow()
* @throws SecurityException if this KeyboardFocusManager is not the
* current KeyboardFocusManager for the calling thread's context
* and if the calling thread does not have "replaceKeyboardFocusManager"
* permission
* @beaninfo
* bound: true
*/
protected void setGlobalActiveWindow(Window activeWindow)
throws SecurityException
{
Window oldActiveWindow;
synchronized (KeyboardFocusManager.class) {
checkKFMSecurity();
oldActiveWindow = getActiveWindow();
if (focusLog.isLoggable(PlatformLogger.FINER)) {
focusLog.finer("Setting global active window to " + activeWindow + ", old active " + oldActiveWindow);
}
try {
fireVetoableChange("activeWindow", oldActiveWindow,
activeWindow);
} catch (PropertyVetoException e) {
// rejected
return;
}
KeyboardFocusManager.activeWindow = activeWindow;
}
firePropertyChange("activeWindow", oldActiveWindow, activeWindow);
}
/**
* Returns the default FocusTraversalPolicy. Top-level components
* use this value on their creation to initialize their own focus traversal
* policy by explicit call to Container.setFocusTraversalPolicy.
*
* @return the default FocusTraversalPolicy. null will never be returned.
* @see #setDefaultFocusTraversalPolicy
* @see Container#setFocusTraversalPolicy
* @see Container#getFocusTraversalPolicy
*/
public synchronized FocusTraversalPolicy getDefaultFocusTraversalPolicy() {
return defaultPolicy;
}
/**
* Sets the default FocusTraversalPolicy. Top-level components
* use this value on their creation to initialize their own focus traversal
* policy by explicit call to Container.setFocusTraversalPolicy.
* Note: this call doesn't affect already created components as they have
* their policy initialized. Only new components will use this policy as
* their default policy.
*
* @param defaultPolicy the new, default FocusTraversalPolicy
* @see #getDefaultFocusTraversalPolicy
* @see Container#setFocusTraversalPolicy
* @see Container#getFocusTraversalPolicy
* @throws IllegalArgumentException if defaultPolicy is null
* @beaninfo
* bound: true
*/
public void setDefaultFocusTraversalPolicy(FocusTraversalPolicy
defaultPolicy) {
if (defaultPolicy == null) {
throw new IllegalArgumentException("default focus traversal policy cannot be null");
}
FocusTraversalPolicy oldPolicy;
synchronized (this) {
oldPolicy = this.defaultPolicy;
this.defaultPolicy = defaultPolicy;
}
firePropertyChange("defaultFocusTraversalPolicy", oldPolicy,
defaultPolicy);
}
/**
* Sets the default focus traversal keys for a given traversal operation.
* This traversal key {@code Set} will be in effect on all
* {@code Window}s that have no such {@code Set} of
* their own explicitly defined. This {@code Set} will also be
* inherited, recursively, by any child {@code Component} of
* those {@code Windows} that has
* no such {@code Set} of its own explicitly defined.
*
*
*
* To disable a traversal key, use an empty {@code Set};
* {@code Collections.EMPTY_SET} is recommended.
*
*
* Identifier
* Meaning
* Default
*
*
* {@code KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS}
* Normal forward keyboard traversal
* {@code TAB} on {@code KEY_PRESSED},
* {@code CTRL-TAB} on {@code KEY_PRESSED}
*
*
* {@code KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS}
* Normal reverse keyboard traversal
* {@code SHIFT-TAB} on {@code KEY_PRESSED},
* {@code CTRL-SHIFT-TAB} on {@code KEY_PRESSED}
*
*
* {@code KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS}
* Go up one focus traversal cycle
* none
*
*
* {@code KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS}
* Go down one focus traversal cycle
* none
* setDefaultFocusTraversalKeys
for a full description of each
* operation.)
*
* @param id one of KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
* KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
* KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or
* KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS
* @return the Set
of AWTKeyStroke
s
* for the specified operation; the Set
* will be unmodifiable, and may be empty; null
* will never be returned
* @see #setDefaultFocusTraversalKeys
* @see Component#setFocusTraversalKeys
* @see Component#getFocusTraversalKeys
* @throws IllegalArgumentException if id is not one of
* KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
* KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
* KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or
* KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS
*/
public Set
*
* If listener is null, no exception is thrown and no action is performed.
*
* @param listener the PropertyChangeListener to be added
* @see #removePropertyChangeListener
* @see #getPropertyChangeListeners
* @see #addPropertyChangeListener(java.lang.String,java.beans.PropertyChangeListener)
*/
public void addPropertyChangeListener(PropertyChangeListener listener) {
if (listener != null) {
synchronized (this) {
if (changeSupport == null) {
changeSupport = new PropertyChangeSupport(this);
}
changeSupport.addPropertyChangeListener(listener);
}
}
}
/**
* Removes a PropertyChangeListener from the listener list. This method
* should be used to remove the PropertyChangeListeners that were
* registered for all bound properties of this class.
* PropertyChangeListener
s
* or an empty array if no property change
* listeners are currently registered
*
* @see #addPropertyChangeListener
* @see #removePropertyChangeListener
* @see #getPropertyChangeListeners(java.lang.String)
* @since 1.4
*/
public synchronized PropertyChangeListener[] getPropertyChangeListeners() {
if (changeSupport == null) {
changeSupport = new PropertyChangeSupport(this);
}
return changeSupport.getPropertyChangeListeners();
}
/**
* Adds a PropertyChangeListener to the listener list for a specific
* property. The specified property may be user-defined, or one of the
* following:
*
*
* If listener is null, no exception is thrown and no action is performed.
*
* @param propertyName one of the property names listed above
* @param listener the PropertyChangeListener to be added
* @see #addPropertyChangeListener(java.beans.PropertyChangeListener)
* @see #removePropertyChangeListener(java.lang.String,java.beans.PropertyChangeListener)
* @see #getPropertyChangeListeners(java.lang.String)
*/
public void addPropertyChangeListener(String propertyName,
PropertyChangeListener listener) {
if (listener != null) {
synchronized (this) {
if (changeSupport == null) {
changeSupport = new PropertyChangeSupport(this);
}
changeSupport.addPropertyChangeListener(propertyName,
listener);
}
}
}
/**
* Removes a PropertyChangeListener from the listener list for a specific
* property. This method should be used to remove PropertyChangeListeners
* that were registered for a specific bound property.
* PropertyChangeListener
s
* associated with the named property.
*
* @return all of the PropertyChangeListener
s associated with
* the named property or an empty array if no such listeners have
* been added.
*
* @see #addPropertyChangeListener(java.lang.String,java.beans.PropertyChangeListener)
* @see #removePropertyChangeListener(java.lang.String,java.beans.PropertyChangeListener)
* @since 1.4
*/
public synchronized PropertyChangeListener[] getPropertyChangeListeners(String propertyName) {
if (changeSupport == null) {
changeSupport = new PropertyChangeSupport(this);
}
return changeSupport.getPropertyChangeListeners(propertyName);
}
/**
* Fires a PropertyChangeEvent in response to a change in a bound property.
* The event will be delivered to all registered PropertyChangeListeners.
* No event will be delivered if oldValue and newValue are the same.
*
* @param propertyName the name of the property that has changed
* @param oldValue the property's previous value
* @param newValue the property's new value
*/
protected void firePropertyChange(String propertyName, Object oldValue,
Object newValue)
{
if (oldValue == newValue) {
return;
}
PropertyChangeSupport changeSupport = this.changeSupport;
if (changeSupport != null) {
changeSupport.firePropertyChange(propertyName, oldValue, newValue);
}
}
/**
* Adds a VetoableChangeListener to the listener list. The listener is
* registered for all vetoable properties of this class, including the
* following:
*
*
* If listener is null, no exception is thrown and no action is performed.
*
* @param listener the VetoableChangeListener to be added
* @see #removeVetoableChangeListener
* @see #getVetoableChangeListeners
* @see #addVetoableChangeListener(java.lang.String,java.beans.VetoableChangeListener)
*/
public void addVetoableChangeListener(VetoableChangeListener listener) {
if (listener != null) {
synchronized (this) {
if (vetoableSupport == null) {
vetoableSupport =
new VetoableChangeSupport(this);
}
vetoableSupport.addVetoableChangeListener(listener);
}
}
}
/**
* Removes a VetoableChangeListener from the listener list. This method
* should be used to remove the VetoableChangeListeners that were
* registered for all vetoable properties of this class.
* VetoableChangeListener
s
* or an empty array if no vetoable change
* listeners are currently registered
*
* @see #addVetoableChangeListener
* @see #removeVetoableChangeListener
* @see #getVetoableChangeListeners(java.lang.String)
* @since 1.4
*/
public synchronized VetoableChangeListener[] getVetoableChangeListeners() {
if (vetoableSupport == null) {
vetoableSupport = new VetoableChangeSupport(this);
}
return vetoableSupport.getVetoableChangeListeners();
}
/**
* Adds a VetoableChangeListener to the listener list for a specific
* property. The specified property may be user-defined, or one of the
* following:
*
*
* If listener is null, no exception is thrown and no action is performed.
*
* @param propertyName one of the property names listed above
* @param listener the VetoableChangeListener to be added
* @see #addVetoableChangeListener(java.beans.VetoableChangeListener)
* @see #removeVetoableChangeListener
* @see #getVetoableChangeListeners
*/
public void addVetoableChangeListener(String propertyName,
VetoableChangeListener listener) {
if (listener != null) {
synchronized (this) {
if (vetoableSupport == null) {
vetoableSupport =
new VetoableChangeSupport(this);
}
vetoableSupport.addVetoableChangeListener(propertyName,
listener);
}
}
}
/**
* Removes a VetoableChangeListener from the listener list for a specific
* property. This method should be used to remove VetoableChangeListeners
* that were registered for a specific bound property.
* VetoableChangeListener
s
* associated with the named property.
*
* @return all of the VetoableChangeListener
s associated with
* the named property or an empty array if no such listeners have
* been added.
*
* @see #addVetoableChangeListener(java.lang.String,java.beans.VetoableChangeListener)
* @see #removeVetoableChangeListener(java.lang.String,java.beans.VetoableChangeListener)
* @see #getVetoableChangeListeners
* @since 1.4
*/
public synchronized VetoableChangeListener[] getVetoableChangeListeners(String propertyName) {
if (vetoableSupport == null) {
vetoableSupport = new VetoableChangeSupport(this);
}
return vetoableSupport.getVetoableChangeListeners(propertyName);
}
/**
* Fires a PropertyChangeEvent in response to a change in a vetoable
* property. The event will be delivered to all registered
* VetoableChangeListeners. If a VetoableChangeListener throws a
* PropertyVetoException, a new event is fired reverting all
* VetoableChangeListeners to the old value and the exception is then
* rethrown. No event will be delivered if oldValue and newValue are the
* same.
*
* @param propertyName the name of the property that has changed
* @param oldValue the property's previous value
* @param newValue the property's new value
* @throws java.beans.PropertyVetoException if a
* VetoableChangeListener
threw
* PropertyVetoException
*/
protected void fireVetoableChange(String propertyName, Object oldValue,
Object newValue)
throws PropertyVetoException
{
if (oldValue == newValue) {
return;
}
VetoableChangeSupport vetoableSupport =
this.vetoableSupport;
if (vetoableSupport != null) {
vetoableSupport.fireVetoableChange(propertyName, oldValue,
newValue);
}
}
/**
* Adds a KeyEventDispatcher to this KeyboardFocusManager's dispatcher
* chain. This KeyboardFocusManager will request that each
* KeyEventDispatcher dispatch KeyEvents generated by the user before
* finally dispatching the KeyEvent itself. KeyEventDispatchers will be
* notified in the order in which they were added. Notifications will halt
* as soon as one KeyEventDispatcher returns true
from its
* dispatchKeyEvent
method. There is no limit to the total
* number of KeyEventDispatchers which can be added, nor to the number of
* times which a particular KeyEventDispatcher instance can be added.
* addKeyEventDispatcher
.
* addKeyEventDispatcher
. If no other KeyEventDispatchers are
* registered, implementations are free to return null or a List of length
* 0. Client code should not assume one behavior over another, nor should
* it assume that the behavior, once established, will not change.
*
* @return a possibly null or empty List of KeyEventDispatchers
* @see #addKeyEventDispatcher
* @see #removeKeyEventDispatcher
*/
protected synchronized java.util.Listtrue
from its
* postProcessKeyEvent
method. There is no limit to the the
* total number of KeyEventPostProcessors that can be added, nor to the
* number of times that a particular KeyEventPostProcessor instance can be
* added.
* addKeyEventPostProcessor
can be
* removed.
* addKeyEventPostProcessor
. If
* no KeyEventPostProcessors are registered, implementations are free to
* return null or a List of length 0. Client code should not assume one
* behavior over another, nor should it assume that the behavior, once
* established, will not change.
*
* @return a possibly null or empty List of KeyEventPostProcessors
* @see #addKeyEventPostProcessor
* @see #removeKeyEventPostProcessor
*/
protected java.util.ListredispatchEvent
to prevent the AWT event
* dispatcher from recursively requesting that the KeyboardFocusManager
* dispatch the event again. If this method returns false
,
* then the AWT event dispatcher will attempt to dispatch the event itself.
*
* @param e the AWTEvent to be dispatched
* @return true
if this method dispatched the event;
* false
otherwise
* @see #redispatchEvent
* @see #dispatchKeyEvent
*/
public abstract boolean dispatchEvent(AWTEvent e);
/**
* Redispatches an AWTEvent in such a way that the AWT event dispatcher
* will not recursively request that the KeyboardFocusManager, or any
* installed KeyEventDispatchers, dispatch the event again. Client
* implementations of dispatchEvent
and client-defined
* KeyEventDispatchers must call redispatchEvent(target, e)
* instead of target.dispatchEvent(e)
to dispatch an event.
* dispatchEvent
if no
* other KeyEventDispatcher in the dispatcher chain dispatched the
* KeyEvent, or if no other KeyEventDispatchers are registered. If an
* implementation of this method returns false
,
* dispatchEvent
may try to dispatch the KeyEvent itself, or
* may simply return false
. If true
is returned,
* dispatchEvent
should return true
as well.
*
* @param e the KeyEvent which the current KeyboardFocusManager has
* requested that this KeyEventDispatcher dispatch
* @return true
if the KeyEvent was dispatched;
* false
otherwise
* @see #dispatchEvent
*/
public abstract boolean dispatchKeyEvent(KeyEvent e);
/**
* This method will be called by dispatchKeyEvent
.
* By default, this method will handle any unconsumed KeyEvents that
* map to an AWT MenuShortcut
by consuming the event
* and activating the shortcut.
*
* @param e the KeyEvent to post-process
* @return true
to indicate that no other
* KeyEventPostProcessor will be notified of the KeyEvent.
* @see #dispatchKeyEvent
* @see MenuShortcut
*/
public abstract boolean postProcessKeyEvent(KeyEvent e);
/**
* This method initiates a focus traversal operation if and only if the
* KeyEvent represents a focus traversal key for the specified
* focusedComponent. It is expected that focusedComponent is the current
* focus owner, although this need not be the case. If it is not,
* focus traversal will nevertheless proceed as if focusedComponent
* were the current focus owner.
*
* @param focusedComponent the Component that will be the basis for a focus
* traversal operation if the specified event represents a focus
* traversal key for the Component
* @param e the event that may represent a focus traversal key
*/
public abstract void processKeyEvent(Component focusedComponent,
KeyEvent e);
/**
* Called by the AWT to notify the KeyboardFocusManager that it should
* delay dispatching of KeyEvents until the specified Component becomes
* the focus owner. If client code requests a focus change, and the AWT
* determines that this request might be granted by the native windowing
* system, then the AWT will call this method. It is the responsibility of
* the KeyboardFocusManager to delay dispatching of KeyEvents with
* timestamps later than the specified time stamp until the specified
* Component receives a FOCUS_GAINED event, or the AWT cancels the delay
* request by invoking dequeueKeyEvents
or
* discardKeyEvents
.
*
* @param after timestamp of current event, or the current, system time if
* the current event has no timestamp, or the AWT cannot determine
* which event is currently being handled
* @param untilFocused Component which should receive a FOCUS_GAINED event
* before any pending KeyEvents
* @see #dequeueKeyEvents
* @see #discardKeyEvents
*/
protected abstract void enqueueKeyEvents(long after,
Component untilFocused);
/**
* Called by the AWT to notify the KeyboardFocusManager that it should
* cancel delayed dispatching of KeyEvents. All KeyEvents which were
* enqueued because of a call to enqueueKeyEvents
with the
* same timestamp and Component should be released for normal dispatching
* to the current focus owner. If the given timestamp is less than zero,
* the outstanding enqueue request for the given Component with the
* oldest timestamp (if any) should be cancelled.
*
* @param after the timestamp specified in the call to
* enqueueKeyEvents
, or any value < 0
* @param untilFocused the Component specified in the call to
* enqueueKeyEvents
* @see #enqueueKeyEvents
* @see #discardKeyEvents
*/
protected abstract void dequeueKeyEvents(long after,
Component untilFocused);
/**
* Called by the AWT to notify the KeyboardFocusManager that it should
* cancel delayed dispatching of KeyEvents. All KeyEvents which were
* enqueued because of one or more calls to enqueueKeyEvents
* with the same Component should be discarded.
*
* @param comp the Component specified in one or more calls to
* enqueueKeyEvents
* @see #enqueueKeyEvents
* @see #dequeueKeyEvents
*/
protected abstract void discardKeyEvents(Component comp);
/**
* Focuses the Component after aComponent, typically based on a
* FocusTraversalPolicy.
*
* @param aComponent the Component that is the basis for the focus
* traversal operation
* @see FocusTraversalPolicy
*/
public abstract void focusNextComponent(Component aComponent);
/**
* Focuses the Component before aComponent, typically based on a
* FocusTraversalPolicy.
*
* @param aComponent the Component that is the basis for the focus
* traversal operation
* @see FocusTraversalPolicy
*/
public abstract void focusPreviousComponent(Component aComponent);
/**
* Moves the focus up one focus traversal cycle. Typically, the focus owner
* is set to aComponent's focus cycle root, and the current focus cycle
* root is set to the new focus owner's focus cycle root. If, however,
* aComponent's focus cycle root is a Window, then typically the focus
* owner is set to the Window's default Component to focus, and the current
* focus cycle root is unchanged.
*
* @param aComponent the Component that is the basis for the focus
* traversal operation
*/
public abstract void upFocusCycle(Component aComponent);
/**
* Moves the focus down one focus traversal cycle. Typically, if
* aContainer is a focus cycle root, then the focus owner is set to
* aContainer's default Component to focus, and the current focus cycle
* root is set to aContainer. If aContainer is not a focus cycle root, then
* no focus traversal operation occurs.
*
* @param aContainer the Container that is the basis for the focus
* traversal operation
*/
public abstract void downFocusCycle(Container aContainer);
/**
* Focuses the Component after the current focus owner.
*/
public final void focusNextComponent() {
Component focusOwner = getFocusOwner();
if (focusOwner != null) {
focusNextComponent(focusOwner);
}
}
/**
* Focuses the Component before the current focus owner.
*/
public final void focusPreviousComponent() {
Component focusOwner = getFocusOwner();
if (focusOwner != null) {
focusPreviousComponent(focusOwner);
}
}
/**
* Moves the focus up one focus traversal cycle from the current focus
* owner. Typically, the new focus owner is set to the current focus
* owner's focus cycle root, and the current focus cycle root is set to the
* new focus owner's focus cycle root. If, however, the current focus
* owner's focus cycle root is a Window, then typically the focus owner is
* set to the focus cycle root's default Component to focus, and the
* current focus cycle root is unchanged.
*/
public final void upFocusCycle() {
Component focusOwner = getFocusOwner();
if (focusOwner != null) {
upFocusCycle(focusOwner);
}
}
/**
* Moves the focus down one focus traversal cycle from the current focus
* owner, if and only if the current focus owner is a Container that is a
* focus cycle root. Typically, the focus owner is set to the current focus
* owner's default Component to focus, and the current focus cycle root is
* set to the current focus owner. If the current focus owner is not a
* Container that is a focus cycle root, then no focus traversal operation
* occurs.
*/
public final void downFocusCycle() {
Component focusOwner = getFocusOwner();
if (focusOwner instanceof Container) {
downFocusCycle((Container)focusOwner);
}
}
/**
* Dumps the list of focus requests to stderr
*/
void dumpRequests() {
System.err.println(">>> Requests dump, time: " + System.currentTimeMillis());
synchronized (heavyweightRequests) {
for (HeavyweightFocusRequest req : heavyweightRequests) {
System.err.println(">>> Req: " + req);
}
}
System.err.println("");
}
private static final class LightweightFocusRequest {
final Component component;
final boolean temporary;
final CausedFocusEvent.Cause cause;
LightweightFocusRequest(Component component, boolean temporary, CausedFocusEvent.Cause cause) {
this.component = component;
this.temporary = temporary;
this.cause = cause;
}
public String toString() {
return "LightweightFocusRequest[component=" + component +
",temporary=" + temporary + ", cause=" + cause + "]";
}
}
private static final class HeavyweightFocusRequest {
final Component heavyweight;
final LinkedList