JDK-5082319 : REGRESSION: JComboBox don't respond to arrow keys on linux (has focus listener)
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 5.0,5.0u1
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: linux
  • CPU: x86
  • Submitted: 2004-08-03
  • Updated: 2005-12-01
  • Resolved: 2004-10-25
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.0u3Fixed 6 b10Fixed
Related Reports
Duplicate :  
Duplicate :  
Duplicate :  
Description
Name: rmT116609			Date: 08/03/2004


FULL PRODUCT VERSION :
java version "1.5.0-beta2"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-beta2-b51)
Java HotSpot(TM) Client VM (build 1.5.0-beta2-b51, mixed mode, sharing)


ADDITIONAL OS VERSION INFORMATION :
Linux gaz 2.4.18 #18 SMP Mon Feb 24 11:42:05 EST 2003 i686 unknown

EXTRA RELEVANT SYSTEM CONFIGURATION :
KDE 3.2

A DESCRIPTION OF THE PROBLEM :
I have an editable JComboBox with a focus listener on the editor.  The ComboBox does not respond to arrow keys.  It works fine if I remove the focus listener.  This is a regression since it worked in 1.4.2.  The arrow keys cannot be used to select items in the combobox.

This same code works fine on Windows.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile and run the example.
Use the mouse to pull down the combo box.
Use the arrow keys to navigate down the drop-down list.


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I expect the arrow keys to cause the selection to change.
ACTUAL -
No response from the arrow keys.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class TestComboJFrame extends JFrame
{
    private static TestComboJFrame sTest;
    private JComboBox fCombo;
    private DefaultComboBoxModel fComboModel;
    private ComboActionListener    fActionListener;
    private String fCurrentItem;
    
    public TestComboJFrame()
    {
        sTest = this;
        
        setTitle("Test Frame");
        JPanel innerPanel = new JPanel(new BorderLayout());
        
        JToolBar tool = new JToolBar();
        fCombo = new JComboBox(new String[] {"test1", "foo", "bar", "abc", "def"});
        //I normally have a combo model here, but it doesn't matter for the test case.
        fCombo.setEditable(true);
        
        fActionListener = new ComboActionListener();
        fCombo.addActionListener(fActionListener);
        
        fCombo.getEditor().getEditorComponent().addFocusListener(new FocusTracker());
        
        tool.add(fCombo);
        innerPanel.add(tool, BorderLayout.NORTH);
        setTitle("Test Combo");
        JTextArea textArea = new JTextArea();
        textArea.setLineWrap(true);
        textArea.setPreferredSize(new Dimension(400,400));
        innerPanel.add(textArea, BorderLayout.CENTER);
        getContentPane().add(innerPanel);
        sTest.setSize(400, 400);
         sTest.setVisible(true);
        
    }
    

    public static void main(String[] args)
    {
        new TestComboJFrame();
    }
   
    
     /**
     * Updates the combo box content and selection in response to focus events
     */
   private class FocusTracker implements FocusListener
    {
        public void focusGained(FocusEvent event)
        {
            if (fCombo != null && fCombo.getEditor() != null)
            {
                fCombo.getEditor().selectAll();
            }
       }

        public void focusLost(FocusEvent event)
        {
            
        }
    }
 
     private class ComboActionListener implements ActionListener
    {
        public void actionPerformed(ActionEvent event)
        {
            // put this on the AWT thread to make sure the popup is dismissed before we
            // process the event, if the popup was in fact dismissed by the user.
            SwingUtilities.invokeLater(new ComboboxActionPerformedThread());
        }
    }

    private class ComboboxActionPerformedThread implements Runnable
    {
        public void run()
        {
            if (!fCombo.isPopupVisible())
            {
                System.out.println("combo change accepted");
            }
        }
    }
    
    
    
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
None, other than removing the focus listener.

Release Regression From : 1.4.2
The above release value was the last known release where this 
bug was known to work. Since then there has been a regression.

(Incident Review ID: 290422) 
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: mustang FIXED IN: mustang
19-09-2004

SUGGESTED FIX Name: at153223 Date: 09/16/2004 ------- DefaultKeyboardFocusManager.java ------- *** /tmp/sccs.wqa4on Mon Aug 30 17:44:57 2004 --- DefaultKeyboardFocusManager.java Mon Aug 30 17:38:39 2004 *************** *** 474,483 **** --- 474,485 ---- restoreFocus(fe, (Window)newFocusedWindow); break; } } + setNativeFocusOwner(getHeavyweight(newFocusOwner)); + Component realOppositeComponent = this.realOppositeComponent; if (realOppositeComponent != null && realOppositeComponent != fe.getOppositeComponent()) { fe = new FocusEvent(newFocusOwner, FocusEvent.FOCUS_GAINED, *************** *** 526,535 **** --- 528,539 ---- if (owningWindow != null) { owningWindow.setTemporaryLostComponent(currentFocusOwner); } } + setNativeFocusOwner(null); + fe.setSource(currentFocusOwner); realOppositeComponent = (fe.getOppositeComponent() != null) ? currentFocusOwner : null; ------- KeyboardFocusManager.java ------- *** /tmp/sccs.iQa4wn Mon Aug 30 17:44:58 2004 --- KeyboardFocusManager.java Mon Aug 30 17:43:34 2004 *************** *** 2860,2870 **** return false; } return (wto != wfrom); } ! private static Component getHeavyweight(Component comp) { if (comp == null || comp.getPeer() == null) { return null; } else if (comp.getPeer() instanceof LightweightPeer) { return comp.getNativeContainer(); } else { --- 2860,2870 ---- return false; } return (wto != wfrom); } ! static Component getHeavyweight(Component comp) { if (comp == null || comp.getPeer() == null) { return null; } else if (comp.getPeer() instanceof LightweightPeer) { return comp.getNativeContainer(); } else { ------- XComponentPeer.java ------- *** /tmp/sccs.t4ayQn Mon Aug 30 17:44:59 2004 --- XComponentPeer.java Mon Aug 30 17:41:19 2004 *************** *** 229,248 **** /** * Called when component receives focus */ public void focusGained(FocusEvent e) { focusLog.log(Level.FINE, "{0}", new Object[] {e}); - XKeyboardFocusManagerPeer.setCurrentNativeFocusOwner(target); bHasFocus = true; } /** * Called when component loses focus */ public void focusLost(FocusEvent e) { focusLog.log(Level.FINE, "{0}", new Object[] {e}); - XKeyboardFocusManagerPeer.setCurrentNativeFocusOwner(null); bHasFocus = false; } public boolean isFocusable() { /* should be implemented by other sub-classes */ --- 229,246 ---- ======================================================================
19-09-2004

EVALUATION Bug not reproducible on Windows but is on Linux. Suspect an AWT issue. ###@###.### 2004-08-04 Name: df153228 Date: 08/05/2004 I have reproduced the bug on Solaris with XToolkit. ###@###.### ====================================================================== Name: df153228 Date: 08/05/2004 The bug is not reproducible with JDK 1.4.2. I suppose it is a regression. ###@###.### ====================================================================== Name: df153228 Date: 08/06/2004 I suppose more correct way will be add ActionListener on JComboBox instead of ComboBoxEditor. Please, see workaround. ###@###.### Workaround: Next code could be workaround for the problem. *** TestComboJFrame.java Fri Aug 6 12:08:57 2004 --- TestComboJFrameNew.java Fri Aug 6 12:04:31 2004 *************** *** 25,31 **** fActionListener = new ComboActionListener(); fCombo.addActionListener(fActionListener); ! fCombo.getEditor().getEditorComponent().addFocusListener(new FocusTracker()); tool.add(fCombo); innerPanel.add(tool, BorderLayout.NORTH); --- 25,31 ---- fActionListener = new ComboActionListener(); fCombo.addActionListener(fActionListener); ! fCombo.addFocusListener(new FocusTracker()); tool.add(fCombo); innerPanel.add(tool, BorderLayout.NORTH); ###@###.### ====================================================================== Name: df153228 Date: 08/06/2004 After showing JCheckBox marker for ComboBoxEditor is added twice. Then we simulate motif behavior we send FOCUS_GAINED event. I suppose one of markers moves away from typeAheadMarkers list. ###@###.### ====================================================================== Name: at153223 Date: 08/30/2004 Here's what happens: The user sets FocusListener on the editor component (which is JTextField in our case): fCombo.getEditor().getEditorComponent().addFocusListener(new FocusTracker()); When the editor component gets focus a 'selectAll' method is performed: private class FocusTracker implements FocusListener { public void focusGained(FocusEvent event) { if (fCombo != null && fCombo.getEditor() != null) { fCombo.getEditor().selectAll(); } } <...> } Here's its code (see javax.swing.plaf.basic.BasicComboBoxEditor): public void selectAll() { editor.selectAll(); editor.requestFocus(); } where 'editor' is the editor component (JTextField). Thus focus is being requested for the component that is already focus owner. This request should be denied in KeyboardFocusManager.shouldNativelyFocusHeavyweight as MToolkit does, but on XToolkit it goes further (and is denied only when FOCUS_GAINED event is dispatched by DefaultKFM). This results in queueing key events for the editor component with the assumption that it will gain focus, but in vain. As I wrote the focus request is denied. The problem is that it happens too late. To fix the bug we should set native focus owner while dispatching FOCUS_GAINED in DKFM, not in peers after all user callbacks are performed. ###@###.### 08/30/2004 ======================================================================
30-08-2004