History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/awt/DefaultKeyboardFocusManager.java (1 of 18352 files). Show all

Unified · Split

java/pkg/java/awt/DefaultKeyboardFocusManager.java+1358−0
@@ -0,0 +1,1358 @@
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+}