JDK-6180261 : Focus error when disabling in focus JTextField from TreeSelectionListener
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 5.0
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: linux
  • CPU: x86
  • Submitted: 2004-10-16
  • Updated: 2007-05-31
  • Resolved: 2005-08-06
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.
Other JDK 6
5.0u12Fixed 6 b47Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.5.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-b64)
Java HotSpot(TM) Client VM (build 1.5.0-b64, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Linux gao-2004.weiqigao.com 2.4.22-1.2149.nptl #1 Wed Jan 7 12:57:33 EST 2004 i686 athlon i386 GNU/Linux

A DESCRIPTION OF THE PROBLEM :
On a panel with a JTree (tree), and two JTextFields (f1 and f2), if the TreeSelectionListener to tree is programmed to disable the text fields when a non-leaf node is selected, and enable the text fields when a leaf node is selected, then clicking on f1 and then a non-leaf node results in f2 getting the focus.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Run java MyFrame
2. Click on "Field 1"
3. Click on "colors" tree node

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
[Tue Jan 27 21:49:51 CST 2004]: FOCUS_GAINED on tree
[Tue Jan 27 21:49:55 CST 2004]: FOCUS_LOST   on tree opposite f1
[Tue Jan 27 21:49:55 CST 2004]: FOCUS_GAINED on f1   opposite tree
[Tue Jan 27 21:49:57 CST 2004]: FOCUS_LOST   on f1   opposite tree
[Tue Jan 27 21:49:57 CST 2004]: FOCUS_GAINED on tree opposite f1

tree has focus
ACTUAL -
[Tue Jan 27 21:49:51 CST 2004]: FOCUS_GAINED on tree
[Tue Jan 27 21:49:55 CST 2004]: FOCUS_LOST   on tree opposite f1
[Tue Jan 27 21:49:55 CST 2004]: FOCUS_GAINED on f1   opposite tree
[Tue Jan 27 21:49:57 CST 2004]: FOCUS_LOST   on f1   opposite tree
[Tue Jan 27 21:49:57 CST 2004]: FOCUS_GAINED on tree opposite f1
[Tue Jan 27 21:49:57 CST 2004]: FOCUS_LOST   on tree opposite f2
[Tue Jan 27 21:49:57 CST 2004]: FOCUS_GAINED on f2   opposite tree

tree does not have focus

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import javax.swing.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.TreeNode;
import java.awt.*;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.util.Date;

public class MyFrame extends JFrame implements FocusListener, TreeSelectionListener {
    JTree tree = new JTree();
    JTextField f1 = new JTextField("Field 1", 20);
    JTextField f2 = new JTextField("Field 2", 20);
    JComponent[] fields = {f1, f2};

    public MyFrame() {
        super("MyFrame");
        layoutGui();
        hookupListeners();
        mainLoop();
    }

    private void layoutGui() {
        Container contentPane = getContentPane();

        contentPane.setLayout(new GridBagLayout());
        tree.expandRow(1);
        contentPane.add(tree, new GridBagConstraints(0, 0, 2, 1, 1.0, 0.0,
                GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL,
                new Insets(16, 16, 8, 16), 0, 0));
        contentPane.add(f1, new GridBagConstraints(0, 1, 1, 1, 1.0, 0.0,
                GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL,
                new Insets(8, 16, 8, 16), 0, 0));
        contentPane.add(f2, new GridBagConstraints(0, 2, 1, 1, 1.0, 0.0,
                GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL,
                new Insets(8, 16, 16, 16), 0, 0));
    }

    public void hookupListeners() {
        tree.addFocusListener(this);
        f1.addFocusListener(this);
        f2.addFocusListener(this);
        tree.addTreeSelectionListener(this);
    }

    public void mainLoop() {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        pack();
        setVisible(true);
    }

    public void focusGained(FocusEvent fe) {
        inspectFocusEvent(fe);
    }

    public void focusLost(FocusEvent fe) {
        inspectFocusEvent(fe);
    }

    private void inspectFocusEvent(FocusEvent fe) {
        StringBuffer buffer = new StringBuffer("[" + new Date().toString() + "]: ");

        String str = fe.getID() == FocusEvent.FOCUS_GAINED ? "FOCUS_GAINED on " :
                fe.getID() == FocusEvent.FOCUS_LOST ? "FOCUS_LOST   on " :
                "";
        buffer.append(str).append(findComponentName(fe.getSource()));

        if (fe.getOppositeComponent() != null) {
            buffer.append(" opposite " + findComponentName(fe.getOppositeComponent()));
        }

        System.out.println(buffer.toString());
    }

    private String findComponentName(Object component) {
        return component == f1 ? "f1  " :
                component == f2 ? "f2  " :
                component == tree ? "tree" :
                "";
    }

    public void valueChanged(final TreeSelectionEvent e) {
        Object obj = e.getNewLeadSelectionPath().getLastPathComponent();
        if (obj instanceof TreeNode) {
            for (int i = 0; i < fields.length; i++) {
                fields[i].setEnabled(((TreeNode) obj).isLeaf());
            }
        }
    }

    public static void main(String[] args) {
        new MyFrame();
    }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Surround the content of the valueChanged() method with SwingUtilities.invokeLater().
###@###.### 10/16/04 18:45 GMT

Comments
SUGGESTED FIX Check if there are any pending focus requests before doing auto-transfer *** /export/dom/work/bugs/6/smart_auto_transfer/fix2/src/share/classes/java/awt/Component.java- 2005-07-19 17:49:55.505570656 +0400 --- /export/dom/work/bugs/6/smart_auto_transfer/fix2/src/share/classes/java/awt/Component.java 2005-07-19 17:49:55.359592848 +0400 *************** *** 7059,7064 **** --- 7059,7071 ---- return; } + // Check if there are pending focus requests. We shouldn't do + // auto-transfer if user has already took care of this + // component becoming ineligible to hold focus. + if (KeyboardFocusManager.hasFocusRequests()) { + return; + } + // the following code will execute only if this Component is the focus // owner *** /export/dom/work/bugs/6/smart_auto_transfer/fix2/src/share/classes/java/awt/KeyboardFocusManager.java- 2005-07-19 17:49:56.897359072 +0400 --- /export/dom/work/bugs/6/smart_auto_transfer/fix2/src/share/classes/java/awt/KeyboardFocusManager.java 2005-07-19 17:49:56.857365152 +0400 *************** *** 2477,2482 **** --- 2477,2488 ---- return null; } + static boolean hasFocusRequests() { + synchronized (heavyweightRequests) { + return heavyweightRequests.size() > 0; + } + } + static void processCurrentLightweightRequests() { KeyboardFocusManager manager = getCurrentKeyboardFocusManager(); LinkedList localLightweightRequests = null; ###@###.### 2005-07-19 13:54:55 GMT
19-07-2005

EVALUATION JTree requests focus on mouse presses. There should be no reason for focus to move the one of the text fields. Re-assigning to AWT. ###@###.### 10/18/04 15:33 GMT When TreeSelectionListener.valueChanged() is performed and is disabling f1, autoFocusTransfer is initiated by Component.disable() method. It requests focus on the next component that happens to be f2. The possible solution is to allow user to forbid auto focus transferring. The question is in which way. We should determine it. ###@###.### 2004-12-21 15:57:52 GMT ###@###.### 2005-07-19 13:54:55 GMT
18-10-2004