JDK-7081012 : REGRESSION:Component.transferFocusBackward invokes clearGlobalFocusOwner()
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 7
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2011-08-19
  • Updated: 2013-12-06
  • Resolved: 2011-09-20
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7 JDK 8
7u2Fixed 8 b06Fixed
Description
FULL PRODUCT VERSION :
java version "1.7.0"
Java(TM) SE Runtime Environment (build 1.7.0-b147)
Java HotSpot(TM) Client VM (build 21.0-b17, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Any OS running Java 7. For example: Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
Using Java 1.7, my custom LayoutFocusTraversalPolicy no longer works properly when I press Shift-Tab in my custom Component.

* Pressing Tab to possibly transfer the focus to the next Component works fine.
* Pressing Shift-Tab  to possibly transfer the focus to the previous Component causes my application to completely loose the keyboard focus.
* Everything used to work fine with Java 1.5 and Java 1.6.

After looking at the Java 1.7 source code of java.awt.Component, I've spotted the problem. It's
transferFocusBackward(boolean clearOnFailure) which (unlike  transferFocus(boolean clearOnFailure)), completely ignores the value of parameter clearOnFailure and incorrectly invokes  KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner().

In:
-----------------------------------------------------------------------------------------------------------------
public void transferFocusBackward() {
    transferFocusBackward(false);
}

boolean transferFocusBackward(boolean clearOnFailure) {
    Container rootAncestor = getTraversalRoot();
    Component comp = this;
    while (rootAncestor != null &&
           !(rootAncestor.isShowing() && rootAncestor.canBeFocusOwner()))
    {
        comp = rootAncestor;
        rootAncestor = comp.getFocusCycleRootAncestor();
    }
    boolean res = false;
    if (rootAncestor != null) {
        FocusTraversalPolicy policy = rootAncestor.getFocusTraversalPolicy();
        Component toFocus = policy.getComponentBefore(rootAncestor, comp);
        if (toFocus == null) {
            toFocus = policy.getDefaultComponent(rootAncestor);
        }
        if (toFocus != null) {
            res = toFocus.requestFocusInWindow(CausedFocusEvent.Cause.TRAVERSAL_BACKWARD);
        }
    }
    if (!res) {
        if (focusLog.isLoggable(PlatformLogger.FINER)) {
            focusLog.finer("clear global focus owner");
        }
        KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
    }
    if (focusLog.isLoggable(PlatformLogger.FINER)) {
        focusLog.finer("returning result: " + res);
    }
    return res;
}
-----------------------------------------------------------------------------------------------------------------
replacing:
-----------------------------------------------------------------------------------------------------------------
    if (!res) {
-----------------------------------------------------------------------------------------------------------------
by:
-----------------------------------------------------------------------------------------------------------------
    if (clearOnFailure && !res) {
-----------------------------------------------------------------------------------------------------------------
should fix this regression.

REGRESSION.  Last worked in version 6u26

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Not useful. The bug is obvious. Suffice to read the source code of  Component.transferFocusBackward(boolean clearOnFailure).

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Not useful. The bug is obvious. Suffice to read the source code of  Component.transferFocusBackward(boolean clearOnFailure).
ACTUAL -
Not useful. The bug is obvious. Suffice to read thesource  code of  Component.transferFocusBackward(boolean clearOnFailure).

ERROR MESSAGES/STACK TRACES THAT OCCUR :
Not useful. The bug is obvious. Suffice to read the source code of  Component.transferFocusBackward(boolean clearOnFailure).

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
Not useful. The bug is obvious. Suffice to read the source code of  Component.transferFocusBackward(boolean clearOnFailure).
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Redefine Component.transferFocusBackward in my custom component. I more or less copied the code from Component.java after fixing this bug.

Comments
EVALUATION Sounds reasonable.
01-09-2011