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

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

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