JDK-4812585 : BasicComboBoxUI.FocusHandler doesn't hide popup menu when focus is lost
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.4.0,1.4.2
  • Priority: P4
  • Status: Closed
  • Resolution: Cannot Reproduce
  • OS: linux,solaris_2.6
  • CPU: x86,sparc
  • Submitted: 2003-02-04
  • Updated: 2022-08-03
  • Resolved: 2022-08-03
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
Name: apR10229			Date: 02/04/2003



The problem is that javax.swing.plaf.basic.BasicComboBoxUI.FocusHandler
listener does not hide popup menu when focus is lost and
LightWeightPopupEnabled property is set to false.

-----------------------
Java API Doc says: "public class BasicComboBoxUI.FocusHandler
extends Object implements FocusListener

This listener hides the popup when the focus is lost. It also repaints
when focus is gained or lost."
------------------------

In other words we can not hide heavyweight popup menu by invoking
focusLost() method. Reference implementation still use workaround to bug
request 4168483, but it is not fixed. RI works OK only when
LightWeightPopupEnabled property is set to true.

See below for an example that reproduces this abnormal behavior
and for a licensee request.


-------------------- Test.java ----------------------
import javax.swing.*;
import javax.swing.plaf.*;
import javax.swing.plaf.basic.*;
import java.awt.*;
import java.awt.event.*;
import java.lang.reflect.*;

class Test {
    public static void main(String[] args) {
        String title[] = { "test0", "test1", "test2", "test3", "test4" };
        final StubComboUI ui = new StubComboUI();
        final JComboBox comboBox = new JComboBox(title);
        final StubComboUI.StubFH c = ui.new StubFH();
        final FocusEvent event = new FocusEvent(comboBox, FocusEvent.FOCUS_LOST);
        JFrame frame = new JFrame("Test");

        comboBox.setUI(ui);
        comboBox.setLightWeightPopupEnabled(false);

        frame.getContentPane().add(comboBox, BorderLayout.CENTER);
        frame.pack();
        frame.setLocation(100,100);
        frame.setSize(200,50);
        frame.setVisible(true);

        try {
            SwingUtilities.invokeAndWait(new Runnable() {
                    public synchronized void run() {
                        ui.setPopupVisible(comboBox, true);
                        c.focusLost(event);
                    }
                });
        } catch (InterruptedException e){
            System.out.println("InterruptedException: " + e);
            e.printStackTrace();
        } catch (InvocationTargetException e){
            System.out.println("InvocationTargetException: " + e);
            e.printStackTrace();
        }

        ComboPopup popup = ((StubComboUI)comboBox.getUI()).stubGetPopup();
        System.out.println("isLightWeightPopupEnabled(): "+
            comboBox.isLightWeightPopupEnabled());
        System.out.println("After invoking FocusHandler.focusLost():");
        System.out.println("Popup has focus: "+
            ((StubComboUI)comboBox.getUI()).stubHasFocus());
        System.out.println("Popup is visible: "+popup.isVisible());
    }
}

class StubComboUI extends BasicComboBoxUI {
    public StubComboUI() {
        super();
    }
    public boolean stubHasFocus() {
        return super.hasFocus;
    }
    public class StubFH extends FocusHandler {
        public StubFH() {
            super();
        }
    }
    public ComboPopup stubGetPopup() {
        return super.popup;
    }
}

------------------- example output ------------------
<pav@libra(pts/5).260> java -cp . Test

isLightWeightPopupEnabled(): false
After invoking FocusHandler.focusLost():
Popup has focus: false
Popup is visible: true

------------------ licensee request -----------------

licensee support engineer wrote:
- - - - - - - - - - - - - - - -

  Dear plaf test writers,

Apple fails the JCK 1.4a test
javasoft.sqe.tests.api.javax.swing.plaf.basic.BasicComboBoxUI.FocusHandler.publicTests
-TestCaseID FocusHandler2003 on their Aqua L&F. The reason for the
failure is that Aqua ComboBox uses a heavyweight popup menu, but
reference implementation is using a lightweight popup menu by default.
This is up to the L&F to choose:

JComboBox spec:

"public void setLightWeightPopupEnabled(boolean aFlag)......The default
value for the lightWeightPopupEnabled property is true, unless otherwise
specified by the look and feel. Some look and feels always use
heavyweight popups, no matter what the value of this property. "

There's a hack in the swing code that prevents this test from behaving
correctly with a heavyweight popup (please see Apple's message below).
If the test is modified to set setLightWeightPopupEnabled(false), it
will fail on reference implementation too. The reference implementation
bug needs to be filed and the test excluded.


Apple wrote:
- - - - - -

Environment:
JCK14a, Mac OS X 10.2.3, jdk14a.jtx from 01/29/03, Default Look & Feel:
apple.laf.AquaLookAndFeel

Problem:
The test
javasoft.sqe.tests.api.javax.swing.plaf.basic.BasicComboBoxUI.FocusHandler.publicTests
-TestCaseID
FocusHandler2003 fails with the message: "Method focusLost works wrong"

Analysis:
For better fidelity with Apple's Aqua HI guidelines, we force JPopupMenus
to be heavyweight in all cases. This
gives us correct translucency and shadows on the menus. In the Sun shared
file BasicComboBoxUI.java there are
hacks in Swing that are incompatible with the forcing of heavyweight
JPopupMenus. Here is the relevant code (note
'comboBox.isLightWeightPopupEnabled()'):

     public class FocusHandler implements FocusListener {
        public void focusGained( FocusEvent e ) {
            hasFocus = true;
            comboBox.repaint();

            // Notify assistive technologies that the combo box
            // gained focus.
            if (comboBox instanceof Accessible) {
                AccessibleContext ac =
                    ((Accessible)comboBox).getAccessibleContext();
                if (ac != null) {
                    ac.firePropertyChange(
                        AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
                        null, AccessibleState.FOCUSED);
                }
            }
        }

        public void focusLost( FocusEvent e ) {
            hasFocus = false;
            // GES, 980818:
            // Note that the second check here is a workaround to bug
            // 4168483.  There is a bogus focusLost sent to the
            // ComboBox with isTemporary false when a mediumweight menu
            // is popped up.  Until this is fixed in AWT, we make the
            // tradeoff of not popping down mediumweight popups when
            // the combobox loses focus.  Although this means that the
            // combobox does not remove such menus when you tab out,
            // it is seen as more desirable than the alternative which
            // is that mediumweight combobox menus dissappear immediately
            // on popup, rendering them completely unusable.
            if ( !e.isTemporary() && comboBox.isLightWeightPopupEnabled())
{
                setPopupVisible(comboBox, false);
            }
            comboBox.repaint();

            // Notify assistive technologies that the combo box
            // lost focus.
            if (comboBox instanceof Accessible) {
                AccessibleContext ac =
                    ((Accessible)comboBox).getAccessibleContext();
                if (ac != null) {
                    ac.firePropertyChange(
                        AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
                        AccessibleState.FOCUSED, null);
                }
            }
        }
    }

------------------------------------------------------------------

======================================================================

Comments
isLightWeightPopupEnabled(): false After invoking FocusHandler.focusLost(): Popup has focus: false Popup is visible: false
03-08-2022

EVALUATION Contribution forum : https://jdk-collaboration.dev.java.net/servlets/ProjectForumMessageView?forumID=1463&messageID=13480
08-06-2006

EVALUATION This is an excellent report. Thanks for providing a lot of detail. The original conditions for which the workaround 4168463 was implemented should be investigated and removed if possible. It was patched a long time ago and the focus architecture was completely rewritten for 1.4. ###@###.### 2003-02-19
19-02-2003