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

Save This Page
Home » openjdk-7 » java » awt » [javadoc | source]