1 /* 2 * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package java.awt; 26 27 import java.awt.event.FocusEvent; 28 import java.awt.event.KeyEvent; 29 import java.awt.event.WindowEvent; 30 import java.awt.peer.ComponentPeer; 31 import java.awt.peer.LightweightPeer; 32 import java.lang.ref.WeakReference; 33 import java.util.LinkedList; 34 import java.util.Iterator; 35 import java.util.ListIterator; 36 import java.util.Set; 37 38 import sun.util.logging.PlatformLogger; 39 40 import sun.awt.AppContext; 41 import sun.awt.SunToolkit; 42 import sun.awt.AWTAccessor; 43 import sun.awt.TimedWindowEvent; 44 45 /** 46 * The default KeyboardFocusManager for AWT applications. Focus traversal is 47 * done in response to a Component's focus traversal keys, and using a 48 * Container's FocusTraversalPolicy. 49 * <p> 50 * Please see 51 * <a href="http://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html"> 52 * How to Use the Focus Subsystem</a>, 53 * a section in <em>The Java Tutorial</em>, and the 54 * <a href="../../java/awt/doc-files/FocusSpec.html">Focus Specification</a> 55 * for more information. 56 * 57 * @author David Mendenhall 58 * 59 * @see FocusTraversalPolicy 60 * @see Component#setFocusTraversalKeys 61 * @see Component#getFocusTraversalKeys 62 * @since 1.4 63 */ 64 public class DefaultKeyboardFocusManager extends KeyboardFocusManager { 65 private static final PlatformLogger focusLog = PlatformLogger.getLogger("java.awt.focus.DefaultKeyboardFocusManager"); 66 67 // null weak references to not create too many objects 68 private static final WeakReference<Window> NULL_WINDOW_WR = 69 new WeakReference<Window>(null); 70 private static final WeakReference<Component> NULL_COMPONENT_WR = 71 new WeakReference<Component>(null); 72 private WeakReference<Window> realOppositeWindowWR = NULL_WINDOW_WR; 73 private WeakReference<Component> realOppositeComponentWR = NULL_COMPONENT_WR; 74 private int inSendMessage; 75 private LinkedList<KeyEvent> enqueuedKeyEvents = new LinkedList<KeyEvent>(); 76 private LinkedList<TypeAheadMarker> typeAheadMarkers = new LinkedList<TypeAheadMarker>(); 77 private boolean consumeNextKeyTyped; 78 79 static { 80 AWTAccessor.setDefaultKeyboardFocusManagerAccessor( 81 new AWTAccessor.DefaultKeyboardFocusManagerAccessor() { 82 public void consumeNextKeyTyped(DefaultKeyboardFocusManager dkfm, KeyEvent e) { 83 dkfm.consumeNextKeyTyped(e); 84 } 85 }); 86 } 87 88 private static class TypeAheadMarker { 89 long after; 90 Component untilFocused; 91 92 TypeAheadMarker(long after, Component untilFocused) { 93 this.after = after; 94 this.untilFocused = untilFocused; 95 } 96 /** 97 * Returns string representation of the marker 98 */ 99 public String toString() { 100 return ">>> Marker after " + after + " on " + untilFocused; 101 } 102 } 103 104 private Window getOwningFrameDialog(Window window) { 105 while (window != null && !(window instanceof Frame || 106 window instanceof Dialog)) { 107 window = (Window)window.getParent(); 108 } 109 return window; 110 } 111 112 /* 113 * This series of restoreFocus methods is used for recovering from a 114 * rejected focus or activation change. Rejections typically occur when 115 * the user attempts to focus a non-focusable Component or Window. 116 */ 117 private void restoreFocus(FocusEvent fe, Window newFocusedWindow) { 118 Component realOppositeComponent = this.realOppositeComponentWR.get(); 119 Component vetoedComponent = fe.getComponent(); 120 121 if (newFocusedWindow != null && restoreFocus(newFocusedWindow, 122 vetoedComponent, false)) 123 { 124 } else if (realOppositeComponent != null && 125 doRestoreFocus(realOppositeComponent, vetoedComponent, false)) { 126 } else if (fe.getOppositeComponent() != null && 127 doRestoreFocus(fe.getOppositeComponent(), vetoedComponent, false)) { 128 } else { 129 clearGlobalFocusOwnerPriv(); 130 } 131 } 132 private void restoreFocus(WindowEvent we) { 133 Window realOppositeWindow = this.realOppositeWindowWR.get(); 134 if (realOppositeWindow != null 135 && restoreFocus(realOppositeWindow, null, false)) 136 { 137 // do nothing, everything is done in restoreFocus() 138 } else if (we.getOppositeWindow() != null && 139 restoreFocus(we.getOppositeWindow(), null, false)) 140 { 141 // do nothing, everything is done in restoreFocus() 142 } else { 143 clearGlobalFocusOwnerPriv(); 144 } 145 } 146 private boolean restoreFocus(Window aWindow, Component vetoedComponent, 147 boolean clearOnFailure) { 148 Component toFocus = 149 KeyboardFocusManager.getMostRecentFocusOwner(aWindow); 150 151 if (toFocus != null && toFocus != vetoedComponent && doRestoreFocus(toFocus, vetoedComponent, false)) { 152 return true; 153 } else if (clearOnFailure) { 154 clearGlobalFocusOwnerPriv(); 155 return true; 156 } else { 157 return false; 158 } 159 } 160 private boolean restoreFocus(Component toFocus, boolean clearOnFailure) { 161 return doRestoreFocus(toFocus, null, clearOnFailure); 162 } 163 private boolean doRestoreFocus(Component toFocus, Component vetoedComponent, 164 boolean clearOnFailure) 165 { 166 if (toFocus != vetoedComponent && toFocus.isShowing() && toFocus.canBeFocusOwner() && 167 toFocus.requestFocus(false, FocusEvent.Cause.ROLLBACK)) 168 { 169 return true; 170 } else { 171 Component nextFocus = toFocus.getNextFocusCandidate(); 172 if (nextFocus != null && nextFocus != vetoedComponent && 173 nextFocus.requestFocusInWindow(FocusEvent.Cause.ROLLBACK)) 174 { 175 return true; 176 } else if (clearOnFailure) { 177 clearGlobalFocusOwnerPriv(); 178 return true; 179 } else { 180 return false; 181 } 182 } 183 } 184 185 /** 186 * A special type of SentEvent which updates a counter in the target 187 * KeyboardFocusManager if it is an instance of 188 * DefaultKeyboardFocusManager. 189 */ 190 private static class DefaultKeyboardFocusManagerSentEvent 191 extends SentEvent 192 { 193 /* 194 * serialVersionUID 195 */ 196 private static final long serialVersionUID = -2924743257508701758L; 197 198 public DefaultKeyboardFocusManagerSentEvent(AWTEvent nested, 199 AppContext toNotify) { 200 super(nested, toNotify); 201 } 202 public final void dispatch() { 203 KeyboardFocusManager manager = 204 KeyboardFocusManager.getCurrentKeyboardFocusManager(); 205 DefaultKeyboardFocusManager defaultManager = 206 (manager instanceof DefaultKeyboardFocusManager) 207 ? (DefaultKeyboardFocusManager)manager 208 : null; 209 210 if (defaultManager != null) { 211 synchronized (defaultManager) { 212 defaultManager.inSendMessage++; 213 } 214 } 215 216 super.dispatch(); 217 218 if (defaultManager != null) { 219 synchronized (defaultManager) { 220 defaultManager.inSendMessage--; 221 } 222 } 223 } 224 } 225 226 /** 227 * Sends a synthetic AWTEvent to a Component. If the Component is in 228 * the current AppContext, then the event is immediately dispatched. 229 * If the Component is in a different AppContext, then the event is 230 * posted to the other AppContext's EventQueue, and this method blocks 231 * until the event is handled or target AppContext is disposed. 232 * Returns true if successfully dispatched event, false if failed 233 * to dispatch. 234 */ 235 static boolean sendMessage(Component target, AWTEvent e) { 236 e.isPosted = true; 237 AppContext myAppContext = AppContext.getAppContext(); 238 final AppContext targetAppContext = target.appContext; 239 final SentEvent se = 240 new DefaultKeyboardFocusManagerSentEvent(e, myAppContext); 241 242 if (myAppContext == targetAppContext) { 243 se.dispatch(); 244 } else { 245 if (targetAppContext.isDisposed()) { 246 return false; 247 } 248 SunToolkit.postEvent(targetAppContext, se); 249 if (EventQueue.isDispatchThread()) { 250 EventDispatchThread edt = (EventDispatchThread) 251 Thread.currentThread(); 252 edt.pumpEvents(SentEvent.ID, new Conditional() { 253 public boolean evaluate() { 254 return !se.dispatched && !targetAppContext.isDisposed(); 255 } 256 }); 257 } else { 258 synchronized (se) { 259 while (!se.dispatched && !targetAppContext.isDisposed()) { 260 try { 261 se.wait(1000); 262 } catch (InterruptedException ie) { 263 break; 264 } 265 } 266 } 267 } 268 } 269 return se.dispatched; 270 } 271 272 /* 273 * Checks if the focus window event follows key events waiting in the type-ahead 274 * queue (if any). This may happen when a user types ahead in the window, the client 275 * listeners hang EDT for a while, and the user switches b/w toplevels. In that 276 * case the focus window events may be dispatched before the type-ahead events 277 * get handled. This may lead to wrong focus behavior and in order to avoid it, 278 * the focus window events are reposted to the end of the event queue. See 6981400. 279 */ 280 private boolean repostIfFollowsKeyEvents(WindowEvent e) { 281 if (!(e instanceof TimedWindowEvent)) { 282 return false; 283 } 284 TimedWindowEvent we = (TimedWindowEvent)e; 285 long time = we.getWhen(); 286 synchronized (this) { 287 KeyEvent ke = enqueuedKeyEvents.isEmpty() ? null : enqueuedKeyEvents.getFirst(); 288 if (ke != null && time >= ke.getWhen()) { 289 TypeAheadMarker marker = typeAheadMarkers.isEmpty() ? null : typeAheadMarkers.getFirst(); 290 if (marker != null) { 291 Window toplevel = marker.untilFocused.getContainingWindow(); 292 // Check that the component awaiting focus belongs to 293 // the current focused window. See 8015454. 294 if (toplevel != null && toplevel.isFocused()) { 295 SunToolkit.postEvent(AppContext.getAppContext(), new SequencedEvent(e)); 296 return true; 297 } 298 } 299 } 300 } 301 return false; 302 } 303 304 /** 305 * This method is called by the AWT event dispatcher requesting that the 306 * current KeyboardFocusManager dispatch the specified event on its behalf. 307 * DefaultKeyboardFocusManagers dispatch all FocusEvents, all WindowEvents 308 * related to focus, and all KeyEvents. These events are dispatched based 309 * on the KeyboardFocusManager's notion of the focus owner and the focused 310 * and active Windows, sometimes overriding the source of the specified 311 * AWTEvent. If this method returns <code>false</code>, then the AWT event 312 * dispatcher will attempt to dispatch the event itself. 313 * 314 * @param e the AWTEvent to be dispatched 315 * @return <code>true</code> if this method dispatched the event; 316 * <code>false</code> otherwise 317 */ 318 public boolean dispatchEvent(AWTEvent e) { 319 if (focusLog.isLoggable(PlatformLogger.Level.FINE) && (e instanceof WindowEvent || e instanceof FocusEvent)) { 320 focusLog.fine("" + e); 321 } 322 switch (e.getID()) { 323 case WindowEvent.WINDOW_GAINED_FOCUS: { 324 if (repostIfFollowsKeyEvents((WindowEvent)e)) { 325 break; 326 } 327 328 WindowEvent we = (WindowEvent)e; 329 Window oldFocusedWindow = getGlobalFocusedWindow(); 330 Window newFocusedWindow = we.getWindow(); 331 if (newFocusedWindow == oldFocusedWindow) { 332 break; 333 } 334 335 if (!(newFocusedWindow.isFocusableWindow() 336 && newFocusedWindow.isVisible() 337 && newFocusedWindow.isDisplayable())) 338 { 339 // we can not accept focus on such window, so reject it. 340 restoreFocus(we); 341 break; 342 } 343 // If there exists a current focused window, then notify it 344 // that it has lost focus. 345 if (oldFocusedWindow != null) { 346 boolean isEventDispatched = 347 sendMessage(oldFocusedWindow, 348 new WindowEvent(oldFocusedWindow, 349 WindowEvent.WINDOW_LOST_FOCUS, 350 newFocusedWindow)); 351 // Failed to dispatch, clear by ourselves 352 if (!isEventDispatched) { 353 setGlobalFocusOwner(null); 354 setGlobalFocusedWindow(null); 355 } 356 } 357 358 // Because the native libraries do not post WINDOW_ACTIVATED 359 // events, we need to synthesize one if the active Window 360 // changed. 361 Window newActiveWindow = 362 getOwningFrameDialog(newFocusedWindow); 363 Window currentActiveWindow = getGlobalActiveWindow(); 364 if (newActiveWindow != currentActiveWindow) { 365 sendMessage(newActiveWindow, 366 new WindowEvent(newActiveWindow, 367 WindowEvent.WINDOW_ACTIVATED, 368 currentActiveWindow)); 369 if (newActiveWindow != getGlobalActiveWindow()) { 370 // Activation change was rejected. Unlikely, but 371 // possible. 372 restoreFocus(we); 373 break; 374 } 375 } 376 377 setGlobalFocusedWindow(newFocusedWindow); 378 379 if (newFocusedWindow != getGlobalFocusedWindow()) { 380 // Focus change was rejected. Will happen if 381 // newFocusedWindow is not a focusable Window. 382 restoreFocus(we); 383 break; 384 } 385 386 // Restore focus to the Component which last held it. We do 387 // this here so that client code can override our choice in 388 // a WINDOW_GAINED_FOCUS handler. 389 // 390 // Make sure that the focus change request doesn't change the 391 // focused Window in case we are no longer the focused Window 392 // when the request is handled. 393 if (inSendMessage == 0) { 394 // Identify which Component should initially gain focus 395 // in the Window. 396 // 397 // * If we're in SendMessage, then this is a synthetic 398 // WINDOW_GAINED_FOCUS message which was generated by a 399 // the FOCUS_GAINED handler. Allow the Component to 400 // which the FOCUS_GAINED message was targeted to 401 // receive the focus. 402 // * Otherwise, look up the correct Component here. 403 // We don't use Window.getMostRecentFocusOwner because 404 // window is focused now and 'null' will be returned 405 406 407 // Calculating of most recent focus owner and focus 408 // request should be synchronized on KeyboardFocusManager.class 409 // to prevent from thread race when user will request 410 // focus between calculation and our request. 411 // But if focus transfer is synchronous, this synchronization 412 // may cause deadlock, thus we don't synchronize this block. 413 Component toFocus = KeyboardFocusManager. 414 getMostRecentFocusOwner(newFocusedWindow); 415 if ((toFocus == null) && 416 newFocusedWindow.isFocusableWindow()) 417 { 418 toFocus = newFocusedWindow.getFocusTraversalPolicy(). 419 getInitialComponent(newFocusedWindow); 420 } 421 Component tempLost = null; 422 synchronized(KeyboardFocusManager.class) { 423 tempLost = newFocusedWindow.setTemporaryLostComponent(null); 424 } 425 426 // The component which last has the focus when this window was focused 427 // should receive focus first 428 if (focusLog.isLoggable(PlatformLogger.Level.FINER)) { 429 focusLog.finer("tempLost {0}, toFocus {1}", 430 tempLost, toFocus); 431 } 432 if (tempLost != null) { 433 tempLost.requestFocusInWindow(FocusEvent.Cause.ACTIVATION); 434 } 435 436 if (toFocus != null && toFocus != tempLost) { 437 // If there is a component which requested focus when this window 438 // was inactive it expects to receive focus after activation. 439 toFocus.requestFocusInWindow(FocusEvent.Cause.ACTIVATION); 440 } 441 } 442 443 Window realOppositeWindow = this.realOppositeWindowWR.get(); 444 if (realOppositeWindow != we.getOppositeWindow()) { 445 we = new WindowEvent(newFocusedWindow, 446 WindowEvent.WINDOW_GAINED_FOCUS, 447 realOppositeWindow); 448 } 449 return typeAheadAssertions(newFocusedWindow, we); 450 } 451 452 case WindowEvent.WINDOW_ACTIVATED: { 453 WindowEvent we = (WindowEvent)e; 454 Window oldActiveWindow = getGlobalActiveWindow(); 455 Window newActiveWindow = we.getWindow(); 456 if (oldActiveWindow == newActiveWindow) { 457 break; 458 } 459 460 // If there exists a current active window, then notify it that 461 // it has lost activation. 462 if (oldActiveWindow != null) { 463 boolean isEventDispatched = 464 sendMessage(oldActiveWindow, 465 new WindowEvent(oldActiveWindow, 466 WindowEvent.WINDOW_DEACTIVATED, 467 newActiveWindow)); 468 // Failed to dispatch, clear by ourselves 469 if (!isEventDispatched) { 470 setGlobalActiveWindow(null); 471 } 472 if (getGlobalActiveWindow() != null) { 473 // Activation change was rejected. Unlikely, but 474 // possible. 475 break; 476 } 477 } 478 479 setGlobalActiveWindow(newActiveWindow); 480 481 if (newActiveWindow != getGlobalActiveWindow()) { 482 // Activation change was rejected. Unlikely, but 483 // possible. 484 break; 485 } 486 487 return typeAheadAssertions(newActiveWindow, we); 488 } 489 490 case FocusEvent.FOCUS_GAINED: { 491 FocusEvent fe = (FocusEvent)e; 492 Component oldFocusOwner = getGlobalFocusOwner(); 493 Component newFocusOwner = fe.getComponent(); 494 if (oldFocusOwner == newFocusOwner) { 495 if (focusLog.isLoggable(PlatformLogger.Level.FINE)) { 496 focusLog.fine("Skipping {0} because focus owner is the same", e); 497 } 498 // We can't just drop the event - there could be 499 // type-ahead markers associated with it. 500 dequeueKeyEvents(-1, newFocusOwner); 501 break; 502 } 503 504 // If there exists a current focus owner, then notify it that 505 // it has lost focus. 506 if (oldFocusOwner != null) { 507 boolean isEventDispatched = 508 sendMessage(oldFocusOwner, 509 new FocusEvent(oldFocusOwner, 510 FocusEvent.FOCUS_LOST, 511 fe.isTemporary(), 512 newFocusOwner, fe.getCause())); 513 // Failed to dispatch, clear by ourselves 514 if (!isEventDispatched) { 515 setGlobalFocusOwner(null); 516 if (!fe.isTemporary()) { 517 setGlobalPermanentFocusOwner(null); 518 } 519 } 520 } 521 522 // Because the native windowing system has a different notion 523 // of the current focus and activation states, it is possible 524 // that a Component outside of the focused Window receives a 525 // FOCUS_GAINED event. We synthesize a WINDOW_GAINED_FOCUS 526 // event in that case. 527 final Window newFocusedWindow = SunToolkit.getContainingWindow(newFocusOwner); 528 final Window currentFocusedWindow = getGlobalFocusedWindow(); 529 if (newFocusedWindow != null && 530 newFocusedWindow != currentFocusedWindow) 531 { 532 sendMessage(newFocusedWindow, 533 new WindowEvent(newFocusedWindow, 534 WindowEvent.WINDOW_GAINED_FOCUS, 535 currentFocusedWindow)); 536 if (newFocusedWindow != getGlobalFocusedWindow()) { 537 // Focus change was rejected. Will happen if 538 // newFocusedWindow is not a focusable Window. 539 540 // Need to recover type-ahead, but don't bother 541 // restoring focus. That was done by the 542 // WINDOW_GAINED_FOCUS handler 543 dequeueKeyEvents(-1, newFocusOwner); 544 break; 545 } 546 } 547 548 if (!(newFocusOwner.isFocusable() && newFocusOwner.isShowing() && 549 // Refuse focus on a disabled component if the focus event 550 // isn't of UNKNOWN reason (i.e. not a result of a direct request 551 // but traversal, activation or system generated). 552 (newFocusOwner.isEnabled() || fe.getCause().equals(FocusEvent.Cause.UNKNOWN)))) 553 { 554 // we should not accept focus on such component, so reject it. 555 dequeueKeyEvents(-1, newFocusOwner); 556 if (KeyboardFocusManager.isAutoFocusTransferEnabled()) { 557 // If FOCUS_GAINED is for a disposed component (however 558 // it shouldn't happen) its toplevel parent is null. In this 559 // case we have to try to restore focus in the current focused 560 // window (for the details: 6607170). 561 if (newFocusedWindow == null) { 562 restoreFocus(fe, currentFocusedWindow); 563 } else { 564 restoreFocus(fe, newFocusedWindow); 565 } 566 setMostRecentFocusOwner(newFocusedWindow, null); // see: 8013773 567 } 568 break; 569 } 570 571 setGlobalFocusOwner(newFocusOwner); 572 573 if (newFocusOwner != getGlobalFocusOwner()) { 574 // Focus change was rejected. Will happen if 575 // newFocusOwner is not focus traversable. 576 dequeueKeyEvents(-1, newFocusOwner); 577 if (KeyboardFocusManager.isAutoFocusTransferEnabled()) { 578 restoreFocus(fe, newFocusedWindow); 579 } 580 break; 581 } 582 583 if (!fe.isTemporary()) { 584 setGlobalPermanentFocusOwner(newFocusOwner); 585 586 if (newFocusOwner != getGlobalPermanentFocusOwner()) { 587 // Focus change was rejected. Unlikely, but possible. 588 dequeueKeyEvents(-1, newFocusOwner); 589 if (KeyboardFocusManager.isAutoFocusTransferEnabled()) { 590 restoreFocus(fe, newFocusedWindow); 591 } 592 break; 593 } 594 } 595 596 setNativeFocusOwner(getHeavyweight(newFocusOwner)); 597 598 Component realOppositeComponent = this.realOppositeComponentWR.get(); 599 if (realOppositeComponent != null && 600 realOppositeComponent != fe.getOppositeComponent()) { 601 fe = new FocusEvent(newFocusOwner, 602 FocusEvent.FOCUS_GAINED, 603 fe.isTemporary(), 604 realOppositeComponent, fe.getCause()); 605 ((AWTEvent) fe).isPosted = true; 606 } 607 return typeAheadAssertions(newFocusOwner, fe); 608 } 609 610 case FocusEvent.FOCUS_LOST: { 611 FocusEvent fe = (FocusEvent)e; 612 Component currentFocusOwner = getGlobalFocusOwner(); 613 if (currentFocusOwner == null) { 614 if (focusLog.isLoggable(PlatformLogger.Level.FINE)) 615 focusLog.fine("Skipping {0} because focus owner is null", e); 616 break; 617 } 618 // Ignore cases where a Component loses focus to itself. 619 // If we make a mistake because of retargeting, then the 620 // FOCUS_GAINED handler will correct it. 621 if (currentFocusOwner == fe.getOppositeComponent()) { 622 if (focusLog.isLoggable(PlatformLogger.Level.FINE)) 623 focusLog.fine("Skipping {0} because current focus owner is equal to opposite", e); 624 break; 625 } 626 627 setGlobalFocusOwner(null); 628 629 if (getGlobalFocusOwner() != null) { 630 // Focus change was rejected. Unlikely, but possible. 631 restoreFocus(currentFocusOwner, true); 632 break; 633 } 634 635 if (!fe.isTemporary()) { 636 setGlobalPermanentFocusOwner(null); 637 638 if (getGlobalPermanentFocusOwner() != null) { 639 // Focus change was rejected. Unlikely, but possible. 640 restoreFocus(currentFocusOwner, true); 641 break; 642 } 643 } else { 644 Window owningWindow = currentFocusOwner.getContainingWindow(); 645 if (owningWindow != null) { 646 owningWindow.setTemporaryLostComponent(currentFocusOwner); 647 } 648 } 649 650 setNativeFocusOwner(null); 651 652 fe.setSource(currentFocusOwner); 653 654 realOppositeComponentWR = (fe.getOppositeComponent() != null) 655 ? new WeakReference<Component>(currentFocusOwner) 656 : NULL_COMPONENT_WR; 657 658 return typeAheadAssertions(currentFocusOwner, fe); 659 } 660 661 case WindowEvent.WINDOW_DEACTIVATED: { 662 WindowEvent we = (WindowEvent)e; 663 Window currentActiveWindow = getGlobalActiveWindow(); 664 if (currentActiveWindow == null) { 665 break; 666 } 667 668 if (currentActiveWindow != e.getSource()) { 669 // The event is lost in time. 670 // Allow listeners to precess the event but do not 671 // change any global states 672 break; 673 } 674 675 setGlobalActiveWindow(null); 676 if (getGlobalActiveWindow() != null) { 677 // Activation change was rejected. Unlikely, but possible. 678 break; 679 } 680 681 we.setSource(currentActiveWindow); 682 return typeAheadAssertions(currentActiveWindow, we); 683 } 684 685 case WindowEvent.WINDOW_LOST_FOCUS: { 686 if (repostIfFollowsKeyEvents((WindowEvent)e)) { 687 break; 688 } 689 690 WindowEvent we = (WindowEvent)e; 691 Window currentFocusedWindow = getGlobalFocusedWindow(); 692 Window losingFocusWindow = we.getWindow(); 693 Window activeWindow = getGlobalActiveWindow(); 694 Window oppositeWindow = we.getOppositeWindow(); 695 if (focusLog.isLoggable(PlatformLogger.Level.FINE)) 696 focusLog.fine("Active {0}, Current focused {1}, losing focus {2} opposite {3}", 697 activeWindow, currentFocusedWindow, 698 losingFocusWindow, oppositeWindow); 699 if (currentFocusedWindow == null) { 700 break; 701 } 702 703 // Special case -- if the native windowing system posts an 704 // event claiming that the active Window has lost focus to the 705 // focused Window, then discard the event. This is an artifact 706 // of the native windowing system not knowing which Window is 707 // really focused. 708 if (inSendMessage == 0 && losingFocusWindow == activeWindow && 709 oppositeWindow == currentFocusedWindow) 710 { 711 break; 712 } 713 714 Component currentFocusOwner = getGlobalFocusOwner(); 715 if (currentFocusOwner != null) { 716 // The focus owner should always receive a FOCUS_LOST event 717 // before the Window is defocused. 718 Component oppositeComp = null; 719 if (oppositeWindow != null) { 720 oppositeComp = oppositeWindow.getTemporaryLostComponent(); 721 if (oppositeComp == null) { 722 oppositeComp = oppositeWindow.getMostRecentFocusOwner(); 723 } 724 } 725 if (oppositeComp == null) { 726 oppositeComp = oppositeWindow; 727 } 728 sendMessage(currentFocusOwner, 729 new FocusEvent(currentFocusOwner, 730 FocusEvent.FOCUS_LOST, 731 true, 732 oppositeComp, FocusEvent.Cause.ACTIVATION)); 733 } 734 735 setGlobalFocusedWindow(null); 736 if (getGlobalFocusedWindow() != null) { 737 // Focus change was rejected. Unlikely, but possible. 738 restoreFocus(currentFocusedWindow, null, true); 739 break; 740 } 741 742 we.setSource(currentFocusedWindow); 743 realOppositeWindowWR = (oppositeWindow != null) 744 ? new WeakReference<Window>(currentFocusedWindow) 745 : NULL_WINDOW_WR; 746 typeAheadAssertions(currentFocusedWindow, we); 747 748 if (oppositeWindow == null) { 749 // Then we need to deactivate the active Window as well. 750 // No need to synthesize in other cases, because 751 // WINDOW_ACTIVATED will handle it if necessary. 752 sendMessage(activeWindow, 753 new WindowEvent(activeWindow, 754 WindowEvent.WINDOW_DEACTIVATED, 755 null)); 756 if (getGlobalActiveWindow() != null) { 757 // Activation change was rejected. Unlikely, 758 // but possible. 759 restoreFocus(currentFocusedWindow, null, true); 760 } 761 } 762 break; 763 } 764 765 case KeyEvent.KEY_TYPED: 766 case KeyEvent.KEY_PRESSED: 767 case KeyEvent.KEY_RELEASED: 768 return typeAheadAssertions(null, e); 769 770 default: 771 return false; 772 } 773 774 return true; 775 } 776 777 /** 778 * Called by <code>dispatchEvent</code> if no other 779 * KeyEventDispatcher in the dispatcher chain dispatched the KeyEvent, or 780 * if no other KeyEventDispatchers are registered. If the event has not 781 * been consumed, its target is enabled, and the focus owner is not null, 782 * this method dispatches the event to its target. This method will also 783 * subsequently dispatch the event to all registered 784 * KeyEventPostProcessors. After all this operations are finished, 785 * the event is passed to peers for processing. 786 * <p> 787 * In all cases, this method returns <code>true</code>, since 788 * DefaultKeyboardFocusManager is designed so that neither 789 * <code>dispatchEvent</code>, nor the AWT event dispatcher, should take 790 * further action on the event in any situation. 791 * 792 * @param e the KeyEvent to be dispatched 793 * @return <code>true</code> 794 * @see Component#dispatchEvent 795 */ 796 public boolean dispatchKeyEvent(KeyEvent e) { 797 Component focusOwner = (((AWTEvent)e).isPosted) ? getFocusOwner() : e.getComponent(); 798 799 if (focusOwner != null && focusOwner.isShowing() && focusOwner.canBeFocusOwner()) { 800 if (!e.isConsumed()) { 801 Component comp = e.getComponent(); 802 if (comp != null && comp.isEnabled()) { 803 redispatchEvent(comp, e); 804 } 805 } 806 } 807 boolean stopPostProcessing = false; 808 java.util.List<KeyEventPostProcessor> processors = getKeyEventPostProcessors(); 809 if (processors != null) { 810 for (java.util.Iterator<KeyEventPostProcessor> iter = processors.iterator(); 811 !stopPostProcessing && iter.hasNext(); ) 812 { 813 stopPostProcessing = iter.next(). 814 postProcessKeyEvent(e); 815 } 816 } 817 if (!stopPostProcessing) { 818 postProcessKeyEvent(e); 819 } 820 821 // Allow the peer to process KeyEvent 822 Component source = e.getComponent(); 823 ComponentPeer peer = source.peer; 824 825 if (peer == null || peer instanceof LightweightPeer) { 826 // if focus owner is lightweight then its native container 827 // processes event 828 Container target = source.getNativeContainer(); 829 if (target != null) { 830 peer = target.peer; 831 } 832 } 833 if (peer != null) { 834 peer.handleEvent(e); 835 } 836 837 return true; 838 } 839 840 /** 841 * This method will be called by <code>dispatchKeyEvent</code>. It will 842 * handle any unconsumed KeyEvents that map to an AWT 843 * <code>MenuShortcut</code> by consuming the event and activating the 844 * shortcut. 845 * 846 * @param e the KeyEvent to post-process 847 * @return <code>true</code> 848 * @see #dispatchKeyEvent 849 * @see MenuShortcut 850 */ 851 public boolean postProcessKeyEvent(KeyEvent e) { 852 if (!e.isConsumed()) { 853 Component target = e.getComponent(); 854 Container p = (Container) 855 (target instanceof Container ? target : target.getParent()); 856 if (p != null) { 857 p.postProcessKeyEvent(e); 858 } 859 } 860 return true; 861 } 862 863 private void pumpApprovedKeyEvents() { 864 KeyEvent ke; 865 do { 866 ke = null; 867 synchronized (this) { 868 if (enqueuedKeyEvents.size() != 0) { 869 ke = enqueuedKeyEvents.getFirst(); 870 if (typeAheadMarkers.size() != 0) { 871 TypeAheadMarker marker = typeAheadMarkers.getFirst(); 872 // Fixed 5064013: may appears that the events have the same time 873 // if (ke.getWhen() >= marker.after) { 874 // The fix is rolled out. 875 876 if (ke.getWhen() > marker.after) { 877 ke = null; 878 } 879 } 880 if (ke != null) { 881 if (focusLog.isLoggable(PlatformLogger.Level.FINER)) { 882 focusLog.finer("Pumping approved event {0}", ke); 883 } 884 enqueuedKeyEvents.removeFirst(); 885 } 886 } 887 } 888 if (ke != null) { 889 preDispatchKeyEvent(ke); 890 } 891 } while (ke != null); 892 } 893 894 /** 895 * Dumps the list of type-ahead queue markers to stderr 896 */ 897 void dumpMarkers() { 898 if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) { 899 focusLog.finest(">>> Markers dump, time: {0}", System.currentTimeMillis()); 900 synchronized (this) { 901 if (typeAheadMarkers.size() != 0) { 902 Iterator<TypeAheadMarker> iter = typeAheadMarkers.iterator(); 903 while (iter.hasNext()) { 904 TypeAheadMarker marker = iter.next(); 905 focusLog.finest(" {0}", marker); 906 } 907 } 908 } 909 } 910 } 911 912 private boolean typeAheadAssertions(Component target, AWTEvent e) { 913 914 // Clear any pending events here as well as in the FOCUS_GAINED 915 // handler. We need this call here in case a marker was removed in 916 // response to a call to dequeueKeyEvents. 917 pumpApprovedKeyEvents(); 918 919 switch (e.getID()) { 920 case KeyEvent.KEY_TYPED: 921 case KeyEvent.KEY_PRESSED: 922 case KeyEvent.KEY_RELEASED: { 923 KeyEvent ke = (KeyEvent)e; 924 synchronized (this) { 925 if (e.isPosted && typeAheadMarkers.size() != 0) { 926 TypeAheadMarker marker = typeAheadMarkers.getFirst(); 927 // Fixed 5064013: may appears that the events have the same time 928 // if (ke.getWhen() >= marker.after) { 929 // The fix is rolled out. 930 931 if (ke.getWhen() > marker.after) { 932 if (focusLog.isLoggable(PlatformLogger.Level.FINER)) { 933 focusLog.finer("Storing event {0} because of marker {1}", ke, marker); 934 } 935 enqueuedKeyEvents.addLast(ke); 936 return true; 937 } 938 } 939 } 940 941 // KeyEvent was posted before focus change request 942 return preDispatchKeyEvent(ke); 943 } 944 945 case FocusEvent.FOCUS_GAINED: 946 if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) { 947 focusLog.finest("Markers before FOCUS_GAINED on {0}", target); 948 } 949 dumpMarkers(); 950 // Search the marker list for the first marker tied to 951 // the Component which just gained focus. Then remove 952 // that marker, any markers which immediately follow 953 // and are tied to the same component, and all markers 954 // that precede it. This handles the case where 955 // multiple focus requests were made for the same 956 // Component in a row and when we lost some of the 957 // earlier requests. Since FOCUS_GAINED events will 958 // not be generated for these additional requests, we 959 // need to clear those markers too. 960 synchronized (this) { 961 boolean found = false; 962 if (hasMarker(target)) { 963 for (Iterator<TypeAheadMarker> iter = typeAheadMarkers.iterator(); 964 iter.hasNext(); ) 965 { 966 if (iter.next().untilFocused == target) { 967 found = true; 968 } else if (found) { 969 break; 970 } 971 iter.remove(); 972 } 973 } else { 974 // Exception condition - event without marker 975 if (focusLog.isLoggable(PlatformLogger.Level.FINER)) { 976 focusLog.finer("Event without marker {0}", e); 977 } 978 } 979 } 980 focusLog.finest("Markers after FOCUS_GAINED"); 981 dumpMarkers(); 982 983 redispatchEvent(target, e); 984 985 // Now, dispatch any pending KeyEvents which have been 986 // released because of the FOCUS_GAINED event so that we don't 987 // have to wait for another event to be posted to the queue. 988 pumpApprovedKeyEvents(); 989 return true; 990 991 default: 992 redispatchEvent(target, e); 993 return true; 994 } 995 } 996 997 /** 998 * Returns true if there are some marker associated with component <code>comp</code> 999 * in a markers' queue 1000 * @since 1.5 1001 */ 1002 private boolean hasMarker(Component comp) { 1003 for (Iterator<TypeAheadMarker> iter = typeAheadMarkers.iterator(); iter.hasNext(); ) { 1004 if (iter.next().untilFocused == comp) { 1005 return true; 1006 } 1007 } 1008 return false; 1009 } 1010 1011 /** 1012 * Clears markers queue 1013 * @since 1.5 1014 */ 1015 void clearMarkers() { 1016 synchronized(this) { 1017 typeAheadMarkers.clear(); 1018 } 1019 } 1020 1021 @SuppressWarnings("deprecation") 1022 private boolean preDispatchKeyEvent(KeyEvent ke) { 1023 if (((AWTEvent) ke).isPosted) { 1024 Component focusOwner = getFocusOwner(); 1025 ke.setSource(((focusOwner != null) ? focusOwner : getFocusedWindow())); 1026 } 1027 if (ke.getSource() == null) { 1028 return true; 1029 } 1030 1031 // Explicitly set the key event timestamp here (not in Component.dispatchEventImpl): 1032 // - A key event is anyway passed to this method which starts its actual dispatching. 1033 // - If a key event is put to the type ahead queue, its time stamp should not be registered 1034 // until its dispatching actually starts (by this method). 1035 EventQueue.setCurrentEventAndMostRecentTime(ke); 1036 1037 /** 1038 * Fix for 4495473. 1039 * This fix allows to correctly dispatch events when native 1040 * event proxying mechanism is active. 1041 * If it is active we should redispatch key events after 1042 * we detected its correct target. 1043 */ 1044 if (KeyboardFocusManager.isProxyActive(ke)) { 1045 Component source = (Component)ke.getSource(); 1046 Container target = source.getNativeContainer(); 1047 if (target != null) { 1048 ComponentPeer peer = target.peer; 1049 if (peer != null) { 1050 peer.handleEvent(ke); 1051 /** 1052 * Fix for 4478780 - consume event after it was dispatched by peer. 1053 */ 1054 ke.consume(); 1055 } 1056 } 1057 return true; 1058 } 1059 1060 java.util.List<KeyEventDispatcher> dispatchers = getKeyEventDispatchers(); 1061 if (dispatchers != null) { 1062 for (java.util.Iterator<KeyEventDispatcher> iter = dispatchers.iterator(); 1063 iter.hasNext(); ) 1064 { 1065 if (iter.next(). 1066 dispatchKeyEvent(ke)) 1067 { 1068 return true; 1069 } 1070 } 1071 } 1072 return dispatchKeyEvent(ke); 1073 } 1074 1075 /* 1076 * @param e is a KEY_PRESSED event that can be used 1077 * to track the next KEY_TYPED related. 1078 */ 1079 private void consumeNextKeyTyped(KeyEvent e) { 1080 consumeNextKeyTyped = true; 1081 } 1082 1083 private void consumeTraversalKey(KeyEvent e) { 1084 e.consume(); 1085 consumeNextKeyTyped = (e.getID() == KeyEvent.KEY_PRESSED) && 1086 !e.isActionKey(); 1087 } 1088 1089 /* 1090 * return true if event was consumed 1091 */ 1092 private boolean consumeProcessedKeyEvent(KeyEvent e) { 1093 if ((e.getID() == KeyEvent.KEY_TYPED) && consumeNextKeyTyped) { 1094 e.consume(); 1095 consumeNextKeyTyped = false; 1096 return true; 1097 } 1098 return false; 1099 } 1100 1101 /** 1102 * This method initiates a focus traversal operation if and only if the 1103 * KeyEvent represents a focus traversal key for the specified 1104 * focusedComponent. It is expected that focusedComponent is the current 1105 * focus owner, although this need not be the case. If it is not, 1106 * focus traversal will nevertheless proceed as if focusedComponent 1107 * were the focus owner. 1108 * 1109 * @param focusedComponent the Component that is the basis for a focus 1110 * traversal operation if the specified event represents a focus 1111 * traversal key for the Component 1112 * @param e the event that may represent a focus traversal key 1113 */ 1114 public void processKeyEvent(Component focusedComponent, KeyEvent e) { 1115 // consume processed event if needed 1116 if (consumeProcessedKeyEvent(e)) { 1117 return; 1118 } 1119 1120 // KEY_TYPED events cannot be focus traversal keys 1121 if (e.getID() == KeyEvent.KEY_TYPED) { 1122 return; 1123 } 1124 1125 if (focusedComponent.getFocusTraversalKeysEnabled() && 1126 !e.isConsumed()) 1127 { 1128 AWTKeyStroke stroke = AWTKeyStroke.getAWTKeyStrokeForEvent(e), 1129 oppStroke = AWTKeyStroke.getAWTKeyStroke(stroke.getKeyCode(), 1130 stroke.getModifiers(), 1131 !stroke.isOnKeyRelease()); 1132 Set<AWTKeyStroke> toTest; 1133 boolean contains, containsOpp; 1134 1135 toTest = focusedComponent.getFocusTraversalKeys( 1136 KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); 1137 contains = toTest.contains(stroke); 1138 containsOpp = toTest.contains(oppStroke); 1139 1140 if (contains || containsOpp) { 1141 consumeTraversalKey(e); 1142 if (contains) { 1143 focusNextComponent(focusedComponent); 1144 } 1145 return; 1146 } else if (e.getID() == KeyEvent.KEY_PRESSED) { 1147 // Fix for 6637607: consumeNextKeyTyped should be reset. 1148 consumeNextKeyTyped = false; 1149 } 1150 1151 toTest = focusedComponent.getFocusTraversalKeys( 1152 KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); 1153 contains = toTest.contains(stroke); 1154 containsOpp = toTest.contains(oppStroke); 1155 1156 if (contains || containsOpp) { 1157 consumeTraversalKey(e); 1158 if (contains) { 1159 focusPreviousComponent(focusedComponent); 1160 } 1161 return; 1162 } 1163 1164 toTest = focusedComponent.getFocusTraversalKeys( 1165 KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); 1166 contains = toTest.contains(stroke); 1167 containsOpp = toTest.contains(oppStroke); 1168 1169 if (contains || containsOpp) { 1170 consumeTraversalKey(e); 1171 if (contains) { 1172 upFocusCycle(focusedComponent); 1173 } 1174 return; 1175 } 1176 1177 if (!((focusedComponent instanceof Container) && 1178 ((Container)focusedComponent).isFocusCycleRoot())) { 1179 return; 1180 } 1181 1182 toTest = focusedComponent.getFocusTraversalKeys( 1183 KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS); 1184 contains = toTest.contains(stroke); 1185 containsOpp = toTest.contains(oppStroke); 1186 1187 if (contains || containsOpp) { 1188 consumeTraversalKey(e); 1189 if (contains) { 1190 downFocusCycle((Container)focusedComponent); 1191 } 1192 } 1193 } 1194 } 1195 1196 /** 1197 * Delays dispatching of KeyEvents until the specified Component becomes 1198 * the focus owner. KeyEvents with timestamps later than the specified 1199 * timestamp will be enqueued until the specified Component receives a 1200 * FOCUS_GAINED event, or the AWT cancels the delay request by invoking 1201 * <code>dequeueKeyEvents</code> or <code>discardKeyEvents</code>. 1202 * 1203 * @param after timestamp of current event, or the current, system time if 1204 * the current event has no timestamp, or the AWT cannot determine 1205 * which event is currently being handled 1206 * @param untilFocused Component which will receive a FOCUS_GAINED event 1207 * before any pending KeyEvents 1208 * @see #dequeueKeyEvents 1209 * @see #discardKeyEvents 1210 */ 1211 protected synchronized void enqueueKeyEvents(long after, 1212 Component untilFocused) { 1213 if (untilFocused == null) { 1214 return; 1215 } 1216 1217 if (focusLog.isLoggable(PlatformLogger.Level.FINER)) { 1218 focusLog.finer("Enqueue at {0} for {1}", 1219 after, untilFocused); 1220 } 1221 1222 int insertionIndex = 0, 1223 i = typeAheadMarkers.size(); 1224 ListIterator<TypeAheadMarker> iter = typeAheadMarkers.listIterator(i); 1225 1226 for (; i > 0; i--) { 1227 TypeAheadMarker marker = iter.previous(); 1228 if (marker.after <= after) { 1229 insertionIndex = i; 1230 break; 1231 } 1232 } 1233 1234 typeAheadMarkers.add(insertionIndex, 1235 new TypeAheadMarker(after, untilFocused)); 1236 } 1237 1238 /** 1239 * Releases for normal dispatching to the current focus owner all 1240 * KeyEvents which were enqueued because of a call to 1241 * <code>enqueueKeyEvents</code> with the same timestamp and Component. 1242 * If the given timestamp is less than zero, the outstanding enqueue 1243 * request for the given Component with the <b>oldest</b> timestamp (if 1244 * any) should be cancelled. 1245 * 1246 * @param after the timestamp specified in the call to 1247 * <code>enqueueKeyEvents</code>, or any value < 0 1248 * @param untilFocused the Component specified in the call to 1249 * <code>enqueueKeyEvents</code> 1250 * @see #enqueueKeyEvents 1251 * @see #discardKeyEvents 1252 */ 1253 protected synchronized void dequeueKeyEvents(long after, 1254 Component untilFocused) { 1255 if (untilFocused == null) { 1256 return; 1257 } 1258 1259 if (focusLog.isLoggable(PlatformLogger.Level.FINER)) { 1260 focusLog.finer("Dequeue at {0} for {1}", 1261 after, untilFocused); 1262 } 1263 1264 TypeAheadMarker marker; 1265 ListIterator<TypeAheadMarker> iter = typeAheadMarkers.listIterator 1266 ((after >= 0) ? typeAheadMarkers.size() : 0); 1267 1268 if (after < 0) { 1269 while (iter.hasNext()) { 1270 marker = iter.next(); 1271 if (marker.untilFocused == untilFocused) 1272 { 1273 iter.remove(); 1274 return; 1275 } 1276 } 1277 } else { 1278 while (iter.hasPrevious()) { 1279 marker = iter.previous(); 1280 if (marker.untilFocused == untilFocused && 1281 marker.after == after) 1282 { 1283 iter.remove(); 1284 return; 1285 } 1286 } 1287 } 1288 } 1289 1290 /** 1291 * Discards all KeyEvents which were enqueued because of one or more calls 1292 * to <code>enqueueKeyEvents</code> with the specified Component, or one of 1293 * its descendants. 1294 * 1295 * @param comp the Component specified in one or more calls to 1296 * <code>enqueueKeyEvents</code>, or a parent of such a Component 1297 * @see #enqueueKeyEvents 1298 * @see #dequeueKeyEvents 1299 */ 1300 protected synchronized void discardKeyEvents(Component comp) { 1301 if (comp == null) { 1302 return; 1303 } 1304 1305 long start = -1; 1306 1307 for (Iterator<TypeAheadMarker> iter = typeAheadMarkers.iterator(); iter.hasNext(); ) { 1308 TypeAheadMarker marker = iter.next(); 1309 Component toTest = marker.untilFocused; 1310 boolean match = (toTest == comp); 1311 while (!match && toTest != null && !(toTest instanceof Window)) { 1312 toTest = toTest.getParent(); 1313 match = (toTest == comp); 1314 } 1315 if (match) { 1316 if (start < 0) { 1317 start = marker.after; 1318 } 1319 iter.remove(); 1320 } else if (start >= 0) { 1321 purgeStampedEvents(start, marker.after); 1322 start = -1; 1323 } 1324 } 1325 1326 purgeStampedEvents(start, -1); 1327 } 1328 1329 // Notes: 1330 // * must be called inside a synchronized block 1331 // * if 'start' is < 0, then this function does nothing 1332 // * if 'end' is < 0, then all KeyEvents from 'start' to the end of the 1333 // queue will be removed 1334 private void purgeStampedEvents(long start, long end) { 1335 if (start < 0) { 1336 return; 1337 } 1338 1339 for (Iterator<KeyEvent> iter = enqueuedKeyEvents.iterator(); iter.hasNext(); ) { 1340 KeyEvent ke = iter.next(); 1341 long time = ke.getWhen(); 1342 1343 if (start < time && (end < 0 || time <= end)) { 1344 iter.remove(); 1345 } 1346 1347 if (end >= 0 && time > end) { 1348 break; 1349 } 1350 } 1351 } 1352 1353 /** 1354 * Focuses the Component before aComponent, typically based on a 1355 * FocusTraversalPolicy. 1356 * 1357 * @param aComponent the Component that is the basis for the focus 1358 * traversal operation 1359 * @see FocusTraversalPolicy 1360 * @see Component#transferFocusBackward 1361 */ 1362 public void focusPreviousComponent(Component aComponent) { 1363 if (aComponent != null) { 1364 aComponent.transferFocusBackward(); 1365 } 1366 } 1367 1368 /** 1369 * Focuses the Component after aComponent, typically based on a 1370 * FocusTraversalPolicy. 1371 * 1372 * @param aComponent the Component that is the basis for the focus 1373 * traversal operation 1374 * @see FocusTraversalPolicy 1375 * @see Component#transferFocus 1376 */ 1377 public void focusNextComponent(Component aComponent) { 1378 if (aComponent != null) { 1379 aComponent.transferFocus(); 1380 } 1381 } 1382 1383 /** 1384 * Moves the focus up one focus traversal cycle. Typically, the focus owner 1385 * is set to aComponent's focus cycle root, and the current focus cycle 1386 * root is set to the new focus owner's focus cycle root. If, however, 1387 * aComponent's focus cycle root is a Window, then the focus owner is set 1388 * to the focus cycle root's default Component to focus, and the current 1389 * focus cycle root is unchanged. 1390 * 1391 * @param aComponent the Component that is the basis for the focus 1392 * traversal operation 1393 * @see Component#transferFocusUpCycle 1394 */ 1395 public void upFocusCycle(Component aComponent) { 1396 if (aComponent != null) { 1397 aComponent.transferFocusUpCycle(); 1398 } 1399 } 1400 1401 /** 1402 * Moves the focus down one focus traversal cycle. If aContainer is a focus 1403 * cycle root, then the focus owner is set to aContainer's default 1404 * Component to focus, and the current focus cycle root is set to 1405 * aContainer. If aContainer is not a focus cycle root, then no focus 1406 * traversal operation occurs. 1407 * 1408 * @param aContainer the Container that is the basis for the focus 1409 * traversal operation 1410 * @see Container#transferFocusDownCycle 1411 */ 1412 public void downFocusCycle(Container aContainer) { 1413 if (aContainer != null && aContainer.isFocusCycleRoot()) { 1414 aContainer.transferFocusDownCycle(); 1415 } 1416 } 1417 }