0001 /*
0002 * Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
0003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004 *
0005 * This code is free software; you can redistribute it and/or modify it
0006 * under the terms of the GNU General Public License version 2 only, as
0007 * published by the Free Software Foundation. Sun designates this
0008 * particular file as subject to the "Classpath" exception as provided
0009 * by Sun in the LICENSE file that accompanied this code.
0010 *
0011 * This code is distributed in the hope that it will be useful, but WITHOUT
0012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014 * version 2 for more details (a copy is included in the LICENSE file that
0015 * accompanied this code).
0016 *
0017 * You should have received a copy of the GNU General Public License version
0018 * 2 along with this work; if not, write to the Free Software Foundation,
0019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020 *
0021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022 * CA 95054 USA or visit www.sun.com if you need additional information or
0023 * have any questions.
0024 */
0025 package java.awt;
0026
0027 import java.awt.event.FocusEvent;
0028 import java.awt.event.KeyEvent;
0029 import java.awt.event.WindowEvent;
0030 import java.awt.peer.ComponentPeer;
0031 import java.awt.peer.LightweightPeer;
0032 import java.lang.ref.WeakReference;
0033 import java.util.LinkedList;
0034 import java.util.Iterator;
0035 import java.util.ListIterator;
0036 import java.util.Set;
0037
0038 import java.util.logging.Level;
0039 import java.util.logging.Logger;
0040
0041 import sun.awt.AppContext;
0042 import sun.awt.SunToolkit;
0043 import sun.awt.CausedFocusEvent;
0044
0045 /**
0046 * The default KeyboardFocusManager for AWT applications. Focus traversal is
0047 * done in response to a Component's focus traversal keys, and using a
0048 * Container's FocusTraversalPolicy.
0049 * <p>
0050 * Please see
0051 * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/focus.html">
0052 * How to Use the Focus Subsystem</a>,
0053 * a section in <em>The Java Tutorial</em>, and the
0054 * <a href="../../java/awt/doc-files/FocusSpec.html">Focus Specification</a>
0055 * for more information.
0056 *
0057 * @author David Mendenhall
0058 * @version 1.51, 06/25/07
0059 *
0060 * @see FocusTraversalPolicy
0061 * @see Component#setFocusTraversalKeys
0062 * @see Component#getFocusTraversalKeys
0063 * @since 1.4
0064 */
0065 public class DefaultKeyboardFocusManager extends KeyboardFocusManager {
0066 private static final Logger focusLog = Logger
0067 .getLogger("java.awt.focus.DefaultKeyboardFocusManager");
0068
0069 // null weak references to not create too many objects
0070 private static final WeakReference<Window> NULL_WINDOW_WR = new WeakReference<Window>(
0071 null);
0072 private static final WeakReference<Component> NULL_COMPONENT_WR = new WeakReference<Component>(
0073 null);
0074 private WeakReference<Window> realOppositeWindowWR = NULL_WINDOW_WR;
0075 private WeakReference<Component> realOppositeComponentWR = NULL_COMPONENT_WR;
0076 private int inSendMessage;
0077 private LinkedList enqueuedKeyEvents = new LinkedList(),
0078 typeAheadMarkers = new LinkedList();
0079 private boolean consumeNextKeyTyped;
0080
0081 private static class TypeAheadMarker {
0082 long after;
0083 Component untilFocused;
0084
0085 TypeAheadMarker(long after, Component untilFocused) {
0086 this .after = after;
0087 this .untilFocused = untilFocused;
0088 }
0089
0090 /**
0091 * Returns string representation of the marker
0092 */
0093 public String toString() {
0094 return ">>> Marker after " + after + " on " + untilFocused;
0095 }
0096 }
0097
0098 private Window getOwningFrameDialog(Window window) {
0099 while (window != null
0100 && !(window instanceof Frame || window instanceof Dialog)) {
0101 window = (Window) window.getParent();
0102 }
0103 return window;
0104 }
0105
0106 /*
0107 * This series of restoreFocus methods is used for recovering from a
0108 * rejected focus or activation change. Rejections typically occur when
0109 * the user attempts to focus a non-focusable Component or Window.
0110 */
0111 private void restoreFocus(FocusEvent fe, Window newFocusedWindow) {
0112 Component realOppositeComponent = this .realOppositeComponentWR
0113 .get();
0114 Component vetoedComponent = fe.getComponent();
0115
0116 if (newFocusedWindow != null
0117 && restoreFocus(newFocusedWindow, vetoedComponent,
0118 false)) {
0119 } else if (realOppositeComponent != null
0120 && doRestoreFocus(realOppositeComponent,
0121 vetoedComponent, false)) {
0122 } else if (fe.getOppositeComponent() != null
0123 && doRestoreFocus(fe.getOppositeComponent(),
0124 vetoedComponent, false)) {
0125 } else {
0126 clearGlobalFocusOwner();
0127 }
0128 }
0129
0130 private void restoreFocus(WindowEvent we) {
0131 Window realOppositeWindow = this .realOppositeWindowWR.get();
0132 if (realOppositeWindow != null
0133 && restoreFocus(realOppositeWindow, null, false)) {
0134 // do nothing, everything is done in restoreFocus()
0135 } else if (we.getOppositeWindow() != null
0136 && restoreFocus(we.getOppositeWindow(), null, false)) {
0137 // do nothing, everything is done in restoreFocus()
0138 } else {
0139 clearGlobalFocusOwner();
0140 }
0141 }
0142
0143 private boolean restoreFocus(Window aWindow,
0144 Component vetoedComponent, boolean clearOnFailure) {
0145 Component toFocus = KeyboardFocusManager
0146 .getMostRecentFocusOwner(aWindow);
0147
0148 if (toFocus != null && toFocus != vetoedComponent
0149 && doRestoreFocus(toFocus, vetoedComponent, false)) {
0150 return true;
0151 } else if (clearOnFailure) {
0152 clearGlobalFocusOwner();
0153 return true;
0154 } else {
0155 return false;
0156 }
0157 }
0158
0159 private boolean restoreFocus(Component toFocus,
0160 boolean clearOnFailure) {
0161 return doRestoreFocus(toFocus, null, clearOnFailure);
0162 }
0163
0164 private boolean doRestoreFocus(Component toFocus,
0165 Component vetoedComponent, boolean clearOnFailure) {
0166 if (toFocus.isShowing()
0167 && toFocus.isFocusable()
0168 && toFocus.requestFocus(false,
0169 CausedFocusEvent.Cause.ROLLBACK)) {
0170 return true;
0171 } else {
0172 Component nextFocus = toFocus.preNextFocusHelper();
0173 if (nextFocus != vetoedComponent
0174 && Component.postNextFocusHelper(nextFocus,
0175 CausedFocusEvent.Cause.ROLLBACK)) {
0176 return true;
0177 } else if (clearOnFailure) {
0178 clearGlobalFocusOwner();
0179 return true;
0180 } else {
0181 return false;
0182 }
0183 }
0184 }
0185
0186 /**
0187 * A special type of SentEvent which updates a counter in the target
0188 * KeyboardFocusManager if it is an instance of
0189 * DefaultKeyboardFocusManager.
0190 */
0191 private static class DefaultKeyboardFocusManagerSentEvent extends
0192 SentEvent {
0193 /*
0194 * serialVersionUID
0195 */
0196 private static final long serialVersionUID = -2924743257508701758L;
0197
0198 public DefaultKeyboardFocusManagerSentEvent(AWTEvent nested,
0199 AppContext toNotify) {
0200 super (nested, toNotify);
0201 }
0202
0203 public final void dispatch() {
0204 KeyboardFocusManager manager = KeyboardFocusManager
0205 .getCurrentKeyboardFocusManager();
0206 DefaultKeyboardFocusManager defaultManager = (manager instanceof DefaultKeyboardFocusManager) ? (DefaultKeyboardFocusManager) manager
0207 : null;
0208
0209 if (defaultManager != null) {
0210 synchronized (defaultManager) {
0211 defaultManager.inSendMessage++;
0212 }
0213 }
0214
0215 super .dispatch();
0216
0217 if (defaultManager != null) {
0218 synchronized (defaultManager) {
0219 defaultManager.inSendMessage--;
0220 }
0221 }
0222 }
0223 }
0224
0225 /**
0226 * Sends a synthetic AWTEvent to a Component. If the Component is in
0227 * the current AppContext, then the event is immediately dispatched.
0228 * If the Component is in a different AppContext, then the event is
0229 * posted to the other AppContext's EventQueue, and this method blocks
0230 * until the event is handled or target AppContext is disposed.
0231 * Returns true if successfuly dispatched event, false if failed
0232 * to dispatch.
0233 */
0234 static boolean sendMessage(Component target, AWTEvent e) {
0235 e.isPosted = true;
0236 AppContext myAppContext = AppContext.getAppContext();
0237 final AppContext targetAppContext = target.appContext;
0238 final SentEvent se = new DefaultKeyboardFocusManagerSentEvent(
0239 e, myAppContext);
0240
0241 if (myAppContext == targetAppContext) {
0242 se.dispatch();
0243 } else {
0244 if (targetAppContext.isDisposed()) {
0245 return false;
0246 }
0247 SunToolkit.postEvent(targetAppContext, se);
0248 if (EventQueue.isDispatchThread()) {
0249 EventDispatchThread edt = (EventDispatchThread) Thread
0250 .currentThread();
0251 edt.pumpEvents(SentEvent.ID, new Conditional() {
0252 public boolean evaluate() {
0253 return !se.dispatched
0254 && !targetAppContext.isDisposed();
0255 }
0256 });
0257 } else {
0258 synchronized (se) {
0259 while (!se.dispatched
0260 && !targetAppContext.isDisposed()) {
0261 try {
0262 se.wait(1000);
0263 } catch (InterruptedException ie) {
0264 break;
0265 }
0266 }
0267 }
0268 }
0269 }
0270 return se.dispatched;
0271 }
0272
0273 /**
0274 * This method is called by the AWT event dispatcher requesting that the
0275 * current KeyboardFocusManager dispatch the specified event on its behalf.
0276 * DefaultKeyboardFocusManagers dispatch all FocusEvents, all WindowEvents
0277 * related to focus, and all KeyEvents. These events are dispatched based
0278 * on the KeyboardFocusManager's notion of the focus owner and the focused
0279 * and active Windows, sometimes overriding the source of the specified
0280 * AWTEvent. If this method returns <code>false</code>, then the AWT event
0281 * dispatcher will attempt to dispatch the event itself.
0282 *
0283 * @param e the AWTEvent to be dispatched
0284 * @return <code>true</code> if this method dispatched the event;
0285 * <code>false</code> otherwise
0286 */
0287 public boolean dispatchEvent(AWTEvent e) {
0288 if (focusLog.isLoggable(Level.FINE)
0289 && (e instanceof WindowEvent || e instanceof FocusEvent))
0290 focusLog.fine("" + e);
0291 switch (e.getID()) {
0292 case WindowEvent.WINDOW_GAINED_FOCUS: {
0293 WindowEvent we = (WindowEvent) e;
0294 Window oldFocusedWindow = getGlobalFocusedWindow();
0295 Window newFocusedWindow = we.getWindow();
0296 if (newFocusedWindow == oldFocusedWindow) {
0297 break;
0298 }
0299
0300 if (!(newFocusedWindow.isFocusableWindow()
0301 && newFocusedWindow.isVisible() && newFocusedWindow
0302 .isDisplayable())) {
0303 // we can not accept focus on such window, so reject it.
0304 restoreFocus(we);
0305 break;
0306 }
0307 // If there exists a current focused window, then notify it
0308 // that it has lost focus.
0309 if (oldFocusedWindow != null) {
0310 boolean isEventDispatched = sendMessage(
0311 oldFocusedWindow, new WindowEvent(
0312 oldFocusedWindow,
0313 WindowEvent.WINDOW_LOST_FOCUS,
0314 newFocusedWindow));
0315 // Failed to dispatch, clear by ourselfves
0316 if (!isEventDispatched) {
0317 setGlobalFocusOwner(null);
0318 setGlobalFocusedWindow(null);
0319 }
0320 }
0321
0322 // Because the native libraries do not post WINDOW_ACTIVATED
0323 // events, we need to synthesize one if the active Window
0324 // changed.
0325 Window newActiveWindow = getOwningFrameDialog(newFocusedWindow);
0326 Window currentActiveWindow = getGlobalActiveWindow();
0327 if (newActiveWindow != currentActiveWindow) {
0328 sendMessage(newActiveWindow, new WindowEvent(
0329 newActiveWindow, WindowEvent.WINDOW_ACTIVATED,
0330 currentActiveWindow));
0331 if (newActiveWindow != getGlobalActiveWindow()) {
0332 // Activation change was rejected. Unlikely, but
0333 // possible.
0334 restoreFocus(we);
0335 break;
0336 }
0337 }
0338
0339 setGlobalFocusedWindow(newFocusedWindow);
0340
0341 if (newFocusedWindow != getGlobalFocusedWindow()) {
0342 // Focus change was rejected. Will happen if
0343 // newFocusedWindow is not a focusable Window.
0344 restoreFocus(we);
0345 break;
0346 }
0347
0348 // Restore focus to the Component which last held it. We do
0349 // this here so that client code can override our choice in
0350 // a WINDOW_GAINED_FOCUS handler.
0351 //
0352 // Make sure that the focus change request doesn't change the
0353 // focused Window in case we are no longer the focused Window
0354 // when the request is handled.
0355 if (inSendMessage == 0) {
0356 // Identify which Component should initially gain focus
0357 // in the Window.
0358 //
0359 // * If we're in SendMessage, then this is a synthetic
0360 // WINDOW_GAINED_FOCUS message which was generated by a
0361 // the FOCUS_GAINED handler. Allow the Component to
0362 // which the FOCUS_GAINED message was targeted to
0363 // receive the focus.
0364 // * Otherwise, look up the correct Component here.
0365 // We don't use Window.getMostRecentFocusOwner because
0366 // window is focused now and 'null' will be returned
0367
0368 // Calculating of most recent focus owner and focus
0369 // request should be synchronized on KeyboardFocusManager.class
0370 // to prevent from thread race when user will request
0371 // focus between calculation and our request.
0372 // But if focus transfer is synchronous, this synchronization
0373 // may cause deadlock, thus we don't synchronize this block.
0374 Component toFocus = KeyboardFocusManager
0375 .getMostRecentFocusOwner(newFocusedWindow);
0376 if ((toFocus == null)
0377 && newFocusedWindow.isFocusableWindow()) {
0378 toFocus = newFocusedWindow
0379 .getFocusTraversalPolicy()
0380 .getInitialComponent(newFocusedWindow);
0381 }
0382 Component tempLost = null;
0383 synchronized (KeyboardFocusManager.class) {
0384 tempLost = newFocusedWindow
0385 .setTemporaryLostComponent(null);
0386 }
0387
0388 // The component which last has the focus when this window was focused
0389 // should receive focus first
0390 if (focusLog.isLoggable(Level.FINER)) {
0391 focusLog.log(Level.FINER,
0392 "tempLost {0}, toFocus {1}", new Object[] {
0393 tempLost, toFocus });
0394 }
0395 if (tempLost != null) {
0396 tempLost
0397 .requestFocusInWindow(CausedFocusEvent.Cause.ACTIVATION);
0398 }
0399
0400 if (toFocus != null && toFocus != tempLost) {
0401 // If there is a component which requested focus when this window
0402 // was inactive it expects to receive focus after activation.
0403 toFocus
0404 .requestFocusInWindow(CausedFocusEvent.Cause.ACTIVATION);
0405 }
0406 }
0407
0408 Window realOppositeWindow = this .realOppositeWindowWR.get();
0409 if (realOppositeWindow != we.getOppositeWindow()) {
0410 we = new WindowEvent(newFocusedWindow,
0411 WindowEvent.WINDOW_GAINED_FOCUS,
0412 realOppositeWindow);
0413 }
0414 return typeAheadAssertions(newFocusedWindow, we);
0415 }
0416
0417 case WindowEvent.WINDOW_ACTIVATED: {
0418 WindowEvent we = (WindowEvent) e;
0419 Window oldActiveWindow = getGlobalActiveWindow();
0420 Window newActiveWindow = we.getWindow();
0421 if (oldActiveWindow == newActiveWindow) {
0422 break;
0423 }
0424
0425 // If there exists a current active window, then notify it that
0426 // it has lost activation.
0427 if (oldActiveWindow != null) {
0428 boolean isEventDispatched = sendMessage(
0429 oldActiveWindow, new WindowEvent(
0430 oldActiveWindow,
0431 WindowEvent.WINDOW_DEACTIVATED,
0432 newActiveWindow));
0433 // Failed to dispatch, clear by ourselfves
0434 if (!isEventDispatched) {
0435 setGlobalActiveWindow(null);
0436 }
0437 if (getGlobalActiveWindow() != null) {
0438 // Activation change was rejected. Unlikely, but
0439 // possible.
0440 break;
0441 }
0442 }
0443
0444 setGlobalActiveWindow(newActiveWindow);
0445
0446 if (newActiveWindow != getGlobalActiveWindow()) {
0447 // Activation change was rejected. Unlikely, but
0448 // possible.
0449 break;
0450 }
0451
0452 return typeAheadAssertions(newActiveWindow, we);
0453 }
0454
0455 case FocusEvent.FOCUS_GAINED: {
0456 FocusEvent fe = (FocusEvent) e;
0457 CausedFocusEvent.Cause cause = (fe instanceof CausedFocusEvent) ? ((CausedFocusEvent) fe)
0458 .getCause()
0459 : CausedFocusEvent.Cause.UNKNOWN;
0460 Component oldFocusOwner = getGlobalFocusOwner();
0461 Component newFocusOwner = fe.getComponent();
0462 if (oldFocusOwner == newFocusOwner) {
0463 if (focusLog.isLoggable(Level.FINE)) {
0464 focusLog
0465 .log(
0466 Level.FINE,
0467 "Skipping {0} because focus owner is the same",
0468 new Object[] { e });
0469 }
0470 // We can't just drop the event - there could be
0471 // type-ahead markers associated with it.
0472 dequeueKeyEvents(-1, newFocusOwner);
0473 break;
0474 }
0475
0476 // If there exists a current focus owner, then notify it that
0477 // it has lost focus.
0478 if (oldFocusOwner != null) {
0479 boolean isEventDispatched = sendMessage(oldFocusOwner,
0480 new CausedFocusEvent(oldFocusOwner,
0481 FocusEvent.FOCUS_LOST,
0482 fe.isTemporary(), newFocusOwner, cause));
0483 // Failed to dispatch, clear by ourselfves
0484 if (!isEventDispatched) {
0485 setGlobalFocusOwner(null);
0486 if (!fe.isTemporary()) {
0487 setGlobalPermanentFocusOwner(null);
0488 }
0489 }
0490 }
0491
0492 // Because the native windowing system has a different notion
0493 // of the current focus and activation states, it is possible
0494 // that a Component outside of the focused Window receives a
0495 // FOCUS_GAINED event. We synthesize a WINDOW_GAINED_FOCUS
0496 // event in that case.
0497 final Window newFocusedWindow = Component
0498 .getContainingWindow(newFocusOwner);
0499 final Window currentFocusedWindow = getGlobalFocusedWindow();
0500 if (newFocusedWindow != null
0501 && newFocusedWindow != currentFocusedWindow) {
0502 sendMessage(newFocusedWindow, new WindowEvent(
0503 newFocusedWindow,
0504 WindowEvent.WINDOW_GAINED_FOCUS,
0505 currentFocusedWindow));
0506 if (newFocusedWindow != getGlobalFocusedWindow()) {
0507 // Focus change was rejected. Will happen if
0508 // newFocusedWindow is not a focusable Window.
0509
0510 // Need to recover type-ahead, but don't bother
0511 // restoring focus. That was done by the
0512 // WINDOW_GAINED_FOCUS handler
0513 dequeueKeyEvents(-1, newFocusOwner);
0514 break;
0515 }
0516 }
0517
0518 if (!(newFocusOwner.isFocusable()
0519 && newFocusOwner.isEnabled() && newFocusOwner
0520 .isShowing())) {
0521 // we should not accept focus on such component, so reject it.
0522 dequeueKeyEvents(-1, newFocusOwner);
0523 if (KeyboardFocusManager.isAutoFocusTransferEnabled()) {
0524 restoreFocus(fe, newFocusedWindow);
0525 }
0526 break;
0527 }
0528
0529 setGlobalFocusOwner(newFocusOwner);
0530
0531 if (newFocusOwner != getGlobalFocusOwner()) {
0532 // Focus change was rejected. Will happen if
0533 // newFocusOwner is not focus traversable.
0534 dequeueKeyEvents(-1, newFocusOwner);
0535 if (KeyboardFocusManager.isAutoFocusTransferEnabled()) {
0536 restoreFocus(fe, (Window) newFocusedWindow);
0537 }
0538 break;
0539 }
0540
0541 if (!fe.isTemporary()) {
0542 setGlobalPermanentFocusOwner(newFocusOwner);
0543
0544 if (newFocusOwner != getGlobalPermanentFocusOwner()) {
0545 // Focus change was rejected. Unlikely, but possible.
0546 dequeueKeyEvents(-1, newFocusOwner);
0547 if (KeyboardFocusManager
0548 .isAutoFocusTransferEnabled()) {
0549 restoreFocus(fe, (Window) newFocusedWindow);
0550 }
0551 break;
0552 }
0553 }
0554
0555 setNativeFocusOwner(getHeavyweight(newFocusOwner));
0556
0557 Component realOppositeComponent = this .realOppositeComponentWR
0558 .get();
0559 if (realOppositeComponent != null
0560 && realOppositeComponent != fe
0561 .getOppositeComponent()) {
0562 fe = new CausedFocusEvent(newFocusOwner,
0563 FocusEvent.FOCUS_GAINED, fe.isTemporary(),
0564 realOppositeComponent, cause);
0565 ((AWTEvent) fe).isPosted = true;
0566 }
0567 return typeAheadAssertions(newFocusOwner, fe);
0568 }
0569
0570 case FocusEvent.FOCUS_LOST: {
0571 FocusEvent fe = (FocusEvent) e;
0572 Component currentFocusOwner = getGlobalFocusOwner();
0573 if (currentFocusOwner == null) {
0574 if (focusLog.isLoggable(Level.FINE))
0575 focusLog.log(Level.FINE,
0576 "Skipping {0} because focus owner is null",
0577 new Object[] { e });
0578 break;
0579 }
0580 // Ignore cases where a Component loses focus to itself.
0581 // If we make a mistake because of retargeting, then the
0582 // FOCUS_GAINED handler will correct it.
0583 if (currentFocusOwner == fe.getOppositeComponent()) {
0584 if (focusLog.isLoggable(Level.FINE))
0585 focusLog
0586 .log(
0587 Level.FINE,
0588 "Skipping {0} because current focus owner is equal to opposite",
0589 new Object[] { e });
0590 break;
0591 }
0592
0593 setGlobalFocusOwner(null);
0594
0595 if (getGlobalFocusOwner() != null) {
0596 // Focus change was rejected. Unlikely, but possible.
0597 restoreFocus(currentFocusOwner, true);
0598 break;
0599 }
0600
0601 if (!fe.isTemporary()) {
0602 setGlobalPermanentFocusOwner(null);
0603
0604 if (getGlobalPermanentFocusOwner() != null) {
0605 // Focus change was rejected. Unlikely, but possible.
0606 restoreFocus(currentFocusOwner, true);
0607 break;
0608 }
0609 } else {
0610 Window owningWindow = currentFocusOwner
0611 .getContainingWindow();
0612 if (owningWindow != null) {
0613 owningWindow
0614 .setTemporaryLostComponent(currentFocusOwner);
0615 }
0616 }
0617
0618 setNativeFocusOwner(null);
0619
0620 fe.setSource(currentFocusOwner);
0621
0622 realOppositeComponentWR = (fe.getOppositeComponent() != null) ? new WeakReference<Component>(
0623 currentFocusOwner)
0624 : NULL_COMPONENT_WR;
0625
0626 return typeAheadAssertions(currentFocusOwner, fe);
0627 }
0628
0629 case WindowEvent.WINDOW_DEACTIVATED: {
0630 WindowEvent we = (WindowEvent) e;
0631 Window currentActiveWindow = getGlobalActiveWindow();
0632 if (currentActiveWindow == null) {
0633 break;
0634 }
0635
0636 if (currentActiveWindow != e.getSource()) {
0637 // The event is lost in time.
0638 // Allow listeners to precess the event but do not
0639 // change any global states
0640 break;
0641 }
0642
0643 setGlobalActiveWindow(null);
0644 if (getGlobalActiveWindow() != null) {
0645 // Activation change was rejected. Unlikely, but possible.
0646 break;
0647 }
0648
0649 we.setSource(currentActiveWindow);
0650 return typeAheadAssertions(currentActiveWindow, we);
0651 }
0652
0653 case WindowEvent.WINDOW_LOST_FOCUS: {
0654 WindowEvent we = (WindowEvent) e;
0655 Window currentFocusedWindow = getGlobalFocusedWindow();
0656 Window losingFocusWindow = we.getWindow();
0657 Window activeWindow = getGlobalActiveWindow();
0658 Window oppositeWindow = we.getOppositeWindow();
0659 if (focusLog.isLoggable(Level.FINE))
0660 focusLog
0661 .log(
0662 Level.FINE,
0663 "Active {0}, Current focused {1}, losing focus {2} opposite {3}",
0664 new Object[] { activeWindow,
0665 currentFocusedWindow,
0666 losingFocusWindow,
0667 oppositeWindow });
0668 if (currentFocusedWindow == null) {
0669 break;
0670 }
0671
0672 // Special case -- if the native windowing system posts an
0673 // event claiming that the active Window has lost focus to the
0674 // focused Window, then discard the event. This is an artifact
0675 // of the native windowing system not knowing which Window is
0676 // really focused.
0677 if (inSendMessage == 0 && losingFocusWindow == activeWindow
0678 && oppositeWindow == currentFocusedWindow) {
0679 break;
0680 }
0681
0682 Component currentFocusOwner = getGlobalFocusOwner();
0683 if (currentFocusOwner != null) {
0684 // The focus owner should always receive a FOCUS_LOST event
0685 // before the Window is defocused.
0686 Component oppositeComp = null;
0687 if (oppositeWindow != null) {
0688 oppositeComp = oppositeWindow
0689 .getTemporaryLostComponent();
0690 if (oppositeComp == null) {
0691 oppositeComp = oppositeWindow
0692 .getMostRecentFocusOwner();
0693 }
0694 }
0695 if (oppositeComp == null) {
0696 oppositeComp = oppositeWindow;
0697 }
0698 sendMessage(currentFocusOwner,
0699 new CausedFocusEvent(currentFocusOwner,
0700 FocusEvent.FOCUS_LOST, true,
0701 oppositeComp,
0702 CausedFocusEvent.Cause.ACTIVATION));
0703 }
0704
0705 setGlobalFocusedWindow(null);
0706 if (getGlobalFocusedWindow() != null) {
0707 // Focus change was rejected. Unlikely, but possible.
0708 restoreFocus(currentFocusedWindow, null, true);
0709 break;
0710 }
0711
0712 we.setSource(currentFocusedWindow);
0713 realOppositeWindowWR = (oppositeWindow != null) ? new WeakReference<Window>(
0714 currentFocusedWindow)
0715 : NULL_WINDOW_WR;
0716 typeAheadAssertions(currentFocusedWindow, we);
0717
0718 if (oppositeWindow == null) {
0719 // Then we need to deactive the active Window as well.
0720 // No need to synthesize in other cases, because
0721 // WINDOW_ACTIVATED will handle it if necessary.
0722 sendMessage(activeWindow, new WindowEvent(activeWindow,
0723 WindowEvent.WINDOW_DEACTIVATED, null));
0724 if (getGlobalActiveWindow() != null) {
0725 // Activation change was rejected. Unlikely,
0726 // but possible.
0727 restoreFocus(currentFocusedWindow, null, true);
0728 }
0729 }
0730 break;
0731 }
0732
0733 case KeyEvent.KEY_TYPED:
0734 case KeyEvent.KEY_PRESSED:
0735 case KeyEvent.KEY_RELEASED:
0736 return typeAheadAssertions(null, e);
0737
0738 default:
0739 return false;
0740 }
0741
0742 return true;
0743 }
0744
0745 /**
0746 * Called by <code>dispatchEvent</code> if no other
0747 * KeyEventDispatcher in the dispatcher chain dispatched the KeyEvent, or
0748 * if no other KeyEventDispatchers are registered. If the event has not
0749 * been consumed, its target is enabled, and the focus owner is not null,
0750 * this method dispatches the event to its target. This method will also
0751 * subsequently dispatch the event to all registered
0752 * KeyEventPostProcessors. After all this operations are finished,
0753 * the event is passed to peers for processing.
0754 * <p>
0755 * In all cases, this method returns <code>true</code>, since
0756 * DefaultKeyboardFocusManager is designed so that neither
0757 * <code>dispatchEvent</code>, nor the AWT event dispatcher, should take
0758 * further action on the event in any situation.
0759 *
0760 * @param e the KeyEvent to be dispatched
0761 * @return <code>true</code>
0762 * @see Component#dispatchEvent
0763 */
0764 public boolean dispatchKeyEvent(KeyEvent e) {
0765 Component focusOwner = (((AWTEvent) e).isPosted) ? getFocusOwner()
0766 : e.getComponent();
0767
0768 if (focusOwner != null && focusOwner.isShowing()
0769 && focusOwner.isFocusable() && focusOwner.isEnabled()) {
0770 if (!e.isConsumed()) {
0771 Component comp = e.getComponent();
0772 if (comp != null && comp.isEnabled()) {
0773 redispatchEvent(comp, e);
0774 }
0775 }
0776 }
0777 boolean stopPostProcessing = false;
0778 java.util.List processors = getKeyEventPostProcessors();
0779 if (processors != null) {
0780 for (java.util.Iterator iter = processors.iterator(); !stopPostProcessing
0781 && iter.hasNext();) {
0782 stopPostProcessing = (((KeyEventPostProcessor) (iter
0783 .next())).postProcessKeyEvent(e));
0784 }
0785 }
0786 if (!stopPostProcessing) {
0787 postProcessKeyEvent(e);
0788 }
0789
0790 // Allow the peer to process KeyEvent
0791 Component source = e.getComponent();
0792 ComponentPeer peer = source.getPeer();
0793
0794 if (peer == null || peer instanceof LightweightPeer) {
0795 // if focus owner is lightweight then its native container
0796 // processes event
0797 Container target = source.getNativeContainer();
0798 if (target != null) {
0799 peer = target.getPeer();
0800 }
0801 }
0802 if (peer != null) {
0803 peer.handleEvent(e);
0804 }
0805
0806 return true;
0807 }
0808
0809 /**
0810 * This method will be called by <code>dispatchKeyEvent</code>. It will
0811 * handle any unconsumed KeyEvents that map to an AWT
0812 * <code>MenuShortcut</code> by consuming the event and activating the
0813 * shortcut.
0814 *
0815 * @param e the KeyEvent to post-process
0816 * @return <code>true</code>
0817 * @see #dispatchKeyEvent
0818 * @see MenuShortcut
0819 */
0820 public boolean postProcessKeyEvent(KeyEvent e) {
0821 if (!e.isConsumed()) {
0822 Component target = e.getComponent();
0823 Container p = (Container) (target instanceof Container ? target
0824 : target.getParent());
0825 if (p != null) {
0826 p.postProcessKeyEvent(e);
0827 }
0828 }
0829 return true;
0830 }
0831
0832 private void pumpApprovedKeyEvents() {
0833 KeyEvent ke;
0834 do {
0835 ke = null;
0836 synchronized (this ) {
0837 if (enqueuedKeyEvents.size() != 0) {
0838 ke = (KeyEvent) enqueuedKeyEvents.getFirst();
0839 if (typeAheadMarkers.size() != 0) {
0840 TypeAheadMarker marker = (TypeAheadMarker) typeAheadMarkers
0841 .getFirst();
0842 // Fixed 5064013: may appears that the events have the same time
0843 // if (ke.getWhen() >= marker.after) {
0844 // The fix is rolled out.
0845
0846 if (ke.getWhen() > marker.after) {
0847 ke = null;
0848 }
0849 }
0850 if (ke != null) {
0851 focusLog.log(Level.FINER,
0852 "Pumping approved event {0}",
0853 new Object[] { ke });
0854 enqueuedKeyEvents.removeFirst();
0855 }
0856 }
0857 }
0858 if (ke != null) {
0859 preDispatchKeyEvent(ke);
0860 }
0861 } while (ke != null);
0862 }
0863
0864 /**
0865 * Dumps the list of type-ahead queue markers to stderr
0866 */
0867 void dumpMarkers() {
0868 if (focusLog.isLoggable(Level.FINEST)) {
0869 focusLog.log(Level.FINEST, ">>> Markers dump, time: {0}",
0870 System.currentTimeMillis());
0871 synchronized (this ) {
0872 if (typeAheadMarkers.size() != 0) {
0873 Iterator iter = typeAheadMarkers.iterator();
0874 while (iter.hasNext()) {
0875 TypeAheadMarker marker = (TypeAheadMarker) iter
0876 .next();
0877 focusLog.log(Level.FINEST, " {0}", marker);
0878 }
0879 }
0880 }
0881 }
0882 }
0883
0884 private boolean typeAheadAssertions(Component target, AWTEvent e) {
0885
0886 // Clear any pending events here as well as in the FOCUS_GAINED
0887 // handler. We need this call here in case a marker was removed in
0888 // response to a call to dequeueKeyEvents.
0889 pumpApprovedKeyEvents();
0890
0891 switch (e.getID()) {
0892 case KeyEvent.KEY_TYPED:
0893 case KeyEvent.KEY_PRESSED:
0894 case KeyEvent.KEY_RELEASED: {
0895 KeyEvent ke = (KeyEvent) e;
0896 synchronized (this ) {
0897 if (e.isPosted && typeAheadMarkers.size() != 0) {
0898 TypeAheadMarker marker = (TypeAheadMarker) typeAheadMarkers
0899 .getFirst();
0900 // Fixed 5064013: may appears that the events have the same time
0901 // if (ke.getWhen() >= marker.after) {
0902 // The fix is rolled out.
0903
0904 if (ke.getWhen() > marker.after) {
0905 focusLog
0906 .log(
0907 Level.FINER,
0908 "Storing event {0} because of marker {1}",
0909 new Object[] { ke, marker });
0910 enqueuedKeyEvents.addLast(ke);
0911 return true;
0912 }
0913 }
0914 }
0915
0916 // KeyEvent was posted before focus change request
0917 return preDispatchKeyEvent(ke);
0918 }
0919
0920 case FocusEvent.FOCUS_GAINED:
0921 focusLog.log(Level.FINEST,
0922 "Markers before FOCUS_GAINED on {0}",
0923 new Object[] { target });
0924 dumpMarkers();
0925 // Search the marker list for the first marker tied to
0926 // the Component which just gained focus. Then remove
0927 // that marker, any markers which immediately follow
0928 // and are tied to the same component, and all markers
0929 // that preceed it. This handles the case where
0930 // multiple focus requests were made for the same
0931 // Component in a row and when we lost some of the
0932 // earlier requests. Since FOCUS_GAINED events will
0933 // not be generated for these additional requests, we
0934 // need to clear those markers too.
0935 synchronized (this ) {
0936 boolean found = false;
0937 if (hasMarker(target)) {
0938 for (Iterator iter = typeAheadMarkers.iterator(); iter
0939 .hasNext();) {
0940 if (((TypeAheadMarker) iter.next()).untilFocused == target) {
0941 found = true;
0942 } else if (found) {
0943 break;
0944 }
0945 iter.remove();
0946 }
0947 } else {
0948 // Exception condition - event without marker
0949 focusLog.log(Level.FINER,
0950 "Event without marker {0}", e);
0951 }
0952 }
0953 focusLog.log(Level.FINEST, "Markers after FOCUS_GAINED");
0954 dumpMarkers();
0955
0956 redispatchEvent(target, e);
0957
0958 // Now, dispatch any pending KeyEvents which have been
0959 // released because of the FOCUS_GAINED event so that we don't
0960 // have to wait for another event to be posted to the queue.
0961 pumpApprovedKeyEvents();
0962 return true;
0963
0964 default:
0965 redispatchEvent(target, e);
0966 return true;
0967 }
0968 }
0969
0970 /**
0971 * Returns true if there are some marker associated with component <code>comp</code>
0972 * in a markers' queue
0973 * @since 1.5
0974 */
0975 private boolean hasMarker(Component comp) {
0976 for (Iterator iter = typeAheadMarkers.iterator(); iter
0977 .hasNext();) {
0978 if (((TypeAheadMarker) iter.next()).untilFocused == comp) {
0979 return true;
0980 }
0981 }
0982 return false;
0983 }
0984
0985 /**
0986 * Clears markers queue
0987 * @since 1.5
0988 */
0989 void clearMarkers() {
0990 synchronized (this ) {
0991 typeAheadMarkers.clear();
0992 }
0993 }
0994
0995 private boolean preDispatchKeyEvent(KeyEvent ke) {
0996 if (((AWTEvent) ke).isPosted) {
0997 Component focusOwner = getFocusOwner();
0998 ke.setSource(((focusOwner != null) ? focusOwner
0999 : getFocusedWindow()));
1000 }
1001 if (ke.getSource() == null) {
1002 return true;
1003 }
1004
1005 // Explicitly set the current event and most recent timestamp here in
1006 // addition to the call in Component.dispatchEventImpl. Because
1007 // KeyEvents can be delivered in response to a FOCUS_GAINED event, the
1008 // current timestamp may be incorrect. We need to set it here so that
1009 // KeyEventDispatchers will use the correct time.
1010 EventQueue.setCurrentEventAndMostRecentTime(ke);
1011
1012 /**
1013 * Fix for 4495473.
1014 * This fix allows to correctly dispatch events when native
1015 * event proxying mechanism is active.
1016 * If it is active we should redispatch key events after
1017 * we detected its correct target.
1018 */
1019 if (KeyboardFocusManager.isProxyActive(ke)) {
1020 Component source = (Component) ke.getSource();
1021 Container target = source.getNativeContainer();
1022 if (target != null) {
1023 ComponentPeer peer = target.getPeer();
1024 if (peer != null) {
1025 peer.handleEvent(ke);
1026 /**
1027 * Fix for 4478780 - consume event after it was dispatched by peer.
1028 */
1029 ke.consume();
1030 }
1031 }
1032 return true;
1033 }
1034
1035 java.util.List dispatchers = getKeyEventDispatchers();
1036 if (dispatchers != null) {
1037 for (java.util.Iterator iter = dispatchers.iterator(); iter
1038 .hasNext();) {
1039 if (((KeyEventDispatcher) (iter.next()))
1040 .dispatchKeyEvent(ke)) {
1041 return true;
1042 }
1043 }
1044 }
1045 return dispatchKeyEvent(ke);
1046 }
1047
1048 /*
1049 * @param e is a KEY_PRESSED event that can be used
1050 * to track the next KEY_TYPED related.
1051 */
1052 private void consumeNextKeyTyped(KeyEvent e) {
1053 consumeNextKeyTyped = true;
1054 }
1055
1056 private void consumeTraversalKey(KeyEvent e) {
1057 e.consume();
1058 consumeNextKeyTyped = (e.getID() == KeyEvent.KEY_PRESSED)
1059 && !e.isActionKey();
1060 }
1061
1062 /*
1063 * return true if event was consumed
1064 */
1065 private boolean consumeProcessedKeyEvent(KeyEvent e) {
1066 if ((e.getID() == KeyEvent.KEY_TYPED) && consumeNextKeyTyped) {
1067 e.consume();
1068 consumeNextKeyTyped = false;
1069 return true;
1070 }
1071 return false;
1072 }
1073
1074 /**
1075 * This method initiates a focus traversal operation if and only if the
1076 * KeyEvent represents a focus traversal key for the specified
1077 * focusedComponent. It is expected that focusedComponent is the current
1078 * focus owner, although this need not be the case. If it is not,
1079 * focus traversal will nevertheless proceed as if focusedComponent
1080 * were the focus owner.
1081 *
1082 * @param focusedComponent the Component that is the basis for a focus
1083 * traversal operation if the specified event represents a focus
1084 * traversal key for the Component
1085 * @param e the event that may represent a focus traversal key
1086 */
1087 public void processKeyEvent(Component focusedComponent, KeyEvent e) {
1088 // consume processed event if needed
1089 if (consumeProcessedKeyEvent(e)) {
1090 return;
1091 }
1092
1093 // KEY_TYPED events cannot be focus traversal keys
1094 if (e.getID() == KeyEvent.KEY_TYPED) {
1095 return;
1096 }
1097
1098 if (focusedComponent.getFocusTraversalKeysEnabled()
1099 && !e.isConsumed()) {
1100 AWTKeyStroke stroke = AWTKeyStroke
1101 .getAWTKeyStrokeForEvent(e), oppStroke = AWTKeyStroke
1102 .getAWTKeyStroke(stroke.getKeyCode(), stroke
1103 .getModifiers(), !stroke.isOnKeyRelease());
1104 Set toTest;
1105 boolean contains, containsOpp;
1106
1107 toTest = focusedComponent
1108 .getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
1109 contains = toTest.contains(stroke);
1110 containsOpp = toTest.contains(oppStroke);
1111
1112 if (contains || containsOpp) {
1113 consumeTraversalKey(e);
1114 if (contains) {
1115 focusNextComponent(focusedComponent);
1116 }
1117 return;
1118 }
1119
1120 toTest = focusedComponent
1121 .getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
1122 contains = toTest.contains(stroke);
1123 containsOpp = toTest.contains(oppStroke);
1124
1125 if (contains || containsOpp) {
1126 consumeTraversalKey(e);
1127 if (contains) {
1128 focusPreviousComponent(focusedComponent);
1129 }
1130 return;
1131 }
1132
1133 toTest = focusedComponent
1134 .getFocusTraversalKeys(KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS);
1135 contains = toTest.contains(stroke);
1136 containsOpp = toTest.contains(oppStroke);
1137
1138 if (contains || containsOpp) {
1139 consumeTraversalKey(e);
1140 if (contains) {
1141 upFocusCycle(focusedComponent);
1142 }
1143 return;
1144 }
1145
1146 if (!((focusedComponent instanceof Container) && ((Container) focusedComponent)
1147 .isFocusCycleRoot())) {
1148 return;
1149 }
1150
1151 toTest = focusedComponent
1152 .getFocusTraversalKeys(KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS);
1153 contains = toTest.contains(stroke);
1154 containsOpp = toTest.contains(oppStroke);
1155
1156 if (contains || containsOpp) {
1157 consumeTraversalKey(e);
1158 if (contains) {
1159 downFocusCycle((Container) focusedComponent);
1160 }
1161 }
1162 }
1163 }
1164
1165 /**
1166 * Delays dispatching of KeyEvents until the specified Component becomes
1167 * the focus owner. KeyEvents with timestamps later than the specified
1168 * timestamp will be enqueued until the specified Component receives a
1169 * FOCUS_GAINED event, or the AWT cancels the delay request by invoking
1170 * <code>dequeueKeyEvents</code> or <code>discardKeyEvents</code>.
1171 *
1172 * @param after timestamp of current event, or the current, system time if
1173 * the current event has no timestamp, or the AWT cannot determine
1174 * which event is currently being handled
1175 * @param untilFocused Component which will receive a FOCUS_GAINED event
1176 * before any pending KeyEvents
1177 * @see #dequeueKeyEvents
1178 * @see #discardKeyEvents
1179 */
1180 protected synchronized void enqueueKeyEvents(long after,
1181 Component untilFocused) {
1182 if (untilFocused == null) {
1183 return;
1184 }
1185
1186 focusLog.log(Level.FINER, "Enqueue at {0} for {1}",
1187 new Object[] { after, untilFocused });
1188
1189 int insertionIndex = 0, i = typeAheadMarkers.size();
1190 ListIterator iter = typeAheadMarkers.listIterator(i);
1191
1192 for (; i > 0; i--) {
1193 TypeAheadMarker marker = (TypeAheadMarker) iter.previous();
1194 if (marker.after <= after) {
1195 insertionIndex = i;
1196 break;
1197 }
1198 }
1199
1200 typeAheadMarkers.add(insertionIndex, new TypeAheadMarker(after,
1201 untilFocused));
1202 }
1203
1204 /**
1205 * Releases for normal dispatching to the current focus owner all
1206 * KeyEvents which were enqueued because of a call to
1207 * <code>enqueueKeyEvents</code> with the same timestamp and Component.
1208 * If the given timestamp is less than zero, the outstanding enqueue
1209 * request for the given Component with the <b>oldest</b> timestamp (if
1210 * any) should be cancelled.
1211 *
1212 * @param after the timestamp specified in the call to
1213 * <code>enqueueKeyEvents</code>, or any value < 0
1214 * @param untilFocused the Component specified in the call to
1215 * <code>enqueueKeyEvents</code>
1216 * @see #enqueueKeyEvents
1217 * @see #discardKeyEvents
1218 */
1219 protected synchronized void dequeueKeyEvents(long after,
1220 Component untilFocused) {
1221 if (untilFocused == null) {
1222 return;
1223 }
1224
1225 focusLog.log(Level.FINER, "Dequeue at {0} for {1}",
1226 new Object[] { after, untilFocused });
1227
1228 TypeAheadMarker marker;
1229 ListIterator iter = typeAheadMarkers
1230 .listIterator((after >= 0) ? typeAheadMarkers.size()
1231 : 0);
1232
1233 if (after < 0) {
1234 while (iter.hasNext()) {
1235 marker = (TypeAheadMarker) iter.next();
1236 if (marker.untilFocused == untilFocused) {
1237 iter.remove();
1238 return;
1239 }
1240 }
1241 } else {
1242 while (iter.hasPrevious()) {
1243 marker = (TypeAheadMarker) iter.previous();
1244 if (marker.untilFocused == untilFocused
1245 && marker.after == after) {
1246 iter.remove();
1247 return;
1248 }
1249 }
1250 }
1251 }
1252
1253 /**
1254 * Discards all KeyEvents which were enqueued because of one or more calls
1255 * to <code>enqueueKeyEvents</code> with the specified Component, or one of
1256 * its descendants.
1257 *
1258 * @param comp the Component specified in one or more calls to
1259 * <code>enqueueKeyEvents</code>, or a parent of such a Component
1260 * @see #enqueueKeyEvents
1261 * @see #dequeueKeyEvents
1262 */
1263 protected synchronized void discardKeyEvents(Component comp) {
1264 if (comp == null) {
1265 return;
1266 }
1267
1268 long start = -1;
1269
1270 for (Iterator iter = typeAheadMarkers.iterator(); iter
1271 .hasNext();) {
1272 TypeAheadMarker marker = (TypeAheadMarker) iter.next();
1273 Component toTest = marker.untilFocused;
1274 boolean match = (toTest == comp);
1275 while (!match && toTest != null
1276 && !(toTest instanceof Window)) {
1277 toTest = toTest.getParent();
1278 match = (toTest == comp);
1279 }
1280 if (match) {
1281 if (start < 0) {
1282 start = marker.after;
1283 }
1284 iter.remove();
1285 } else if (start >= 0) {
1286 purgeStampedEvents(start, marker.after);
1287 start = -1;
1288 }
1289 }
1290
1291 purgeStampedEvents(start, -1);
1292 }
1293
1294 // Notes:
1295 // * must be called inside a synchronized block
1296 // * if 'start' is < 0, then this function does nothing
1297 // * if 'end' is < 0, then all KeyEvents from 'start' to the end of the
1298 // queue will be removed
1299 private void purgeStampedEvents(long start, long end) {
1300 if (start < 0) {
1301 return;
1302 }
1303
1304 for (Iterator iter = enqueuedKeyEvents.iterator(); iter
1305 .hasNext();) {
1306 KeyEvent ke = (KeyEvent) iter.next();
1307 long time = ke.getWhen();
1308
1309 if (start < time && (end < 0 || time <= end)) {
1310 iter.remove();
1311 }
1312
1313 if (end >= 0 && time > end) {
1314 break;
1315 }
1316 }
1317 }
1318
1319 /**
1320 * Focuses the Component before aComponent, typically based on a
1321 * FocusTraversalPolicy.
1322 *
1323 * @param aComponent the Component that is the basis for the focus
1324 * traversal operation
1325 * @see FocusTraversalPolicy
1326 * @see Component#transferFocusBackward
1327 */
1328 public void focusPreviousComponent(Component aComponent) {
1329 if (aComponent != null) {
1330 aComponent.transferFocusBackward();
1331 }
1332 }
1333
1334 /**
1335 * Focuses the Component after aComponent, typically based on a
1336 * FocusTraversalPolicy.
1337 *
1338 * @param aComponent the Component that is the basis for the focus
1339 * traversal operation
1340 * @see FocusTraversalPolicy
1341 * @see Component#transferFocus
1342 */
1343 public void focusNextComponent(Component aComponent) {
1344 if (aComponent != null) {
1345 aComponent.transferFocus();
1346 }
1347 }
1348
1349 /**
1350 * Moves the focus up one focus traversal cycle. Typically, the focus owner
1351 * is set to aComponent's focus cycle root, and the current focus cycle
1352 * root is set to the new focus owner's focus cycle root. If, however,
1353 * aComponent's focus cycle root is a Window, then the focus owner is set
1354 * to the focus cycle root's default Component to focus, and the current
1355 * focus cycle root is unchanged.
1356 *
1357 * @param aComponent the Component that is the basis for the focus
1358 * traversal operation
1359 * @see Component#transferFocusUpCycle
1360 */
1361 public void upFocusCycle(Component aComponent) {
1362 if (aComponent != null) {
1363 aComponent.transferFocusUpCycle();
1364 }
1365 }
1366
1367 /**
1368 * Moves the focus down one focus traversal cycle. If aContainer is a focus
1369 * cycle root, then the focus owner is set to aContainer's default
1370 * Component to focus, and the current focus cycle root is set to
1371 * aContainer. If aContainer is not a focus cycle root, then no focus
1372 * traversal operation occurs.
1373 *
1374 * @param aContainer the Container that is the basis for the focus
1375 * traversal operation
1376 * @see Container#transferFocusDownCycle
1377 */
1378 public void downFocusCycle(Container aContainer) {
1379 if (aContainer != null && aContainer.isFocusCycleRoot()) {
1380 aContainer.transferFocusDownCycle();
1381 }
1382 }
1383 }
|