Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4812585

BasicComboBoxUI.FocusHandler doesn't hide popup menu when focus is lost

XMLWordPrintable

    • x86, sparc
    • linux, solaris_2.6

      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);
                      }
                  }
              }
          }

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

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

            Unassigned Unassigned
            pavsunw Pav Pav (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: