United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-4736093 REGRESSION: Menu and controls shortcuts are not visible in Win L&F in jdk1.4.1
JDK-4736093 : REGRESSION: Menu and controls shortcuts are not visible in Win L&F in jdk1.4.1

Details
Type:
Bug
Submit Date:
2002-08-23
Status:
Resolved
Updated Date:
2002-11-16
Project Name:
JDK
Resolved Date:
2002-11-16
Component:
client-libs
OS:
windows_xp,windows_2000
Sub-Component:
javax.swing
CPU:
x86
Priority:
P3
Resolution:
Fixed
Affected Versions:
1.2.0,1.4.1
Fixed Versions:
1.4.2 (mantis)

Related Reports
Duplicate:
Duplicate:
Duplicate:
Relates:
Relates:
Relates:

Sub Tasks

Description
y

Name: rmT116609			Date: 08/23/2002


FULL PRODUCT VERSION :
java version "1.4.1-rc"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1-rc-b19)
Java HotSpot(TM) Client VM (build 1.4.0-rc-b19, mixed mode)

FULL OPERATING SYSTEM VERSION :
Microsoft Windows 2000 [Version 5.00.2195]

EXTRA RELEVANT SYSTEM CONFIGURATION :
can reproduce in j2sdk 1.4.1 beta and 1.4.1 rc

can not reproduce in j2sdk 1.4.0_01

A DESCRIPTION OF THE PROBLEM :
Menu shortcuts and shortcuts of the controls on the main panel are not visible, but fully fuctional.  This is only for Windows Look & Feel.  Pressing Alt button does not make shortcuts visible.  This was broken between jdk 1.4.0_01
and jdk 1.4.1 beta.

Notice that shortcuts of the JCheckBoxMenuItem controls are visible. This problem causes jdk1.4.1 to be unusable for any professional UI application with Windows L&F.


REGRESSION.  Last worked in version 1.4

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Run SwinfSet2 demo
2. In "Look and Feel" menu select "Windows Style Look And
Feel".
3. Select the second tool bar button (JButton, ... demo)


EXPECTED VERSUS ACTUAL BEHAVIOR :
Notice that labels of the check boxes (on the Display Options panel) do not have shortcuts.  If you press Alt-b, the shortcut of "Paint Border" check box is activated (but still invisible).

Also open File menu -- all menu items do not show shortcuts (but they are working, i.e. try press "b" for "About". I reinstall jdk 1.4.0_01 -- this is working properly.

Please, note the importance of this bug -- 1.4.1 can not be used for any commercial UI application.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
Just use SwingSet2 demo
---------- END SOURCE ----------

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

(Review ID: 163547) 
======================================================================

                                    

Comments
WORK AROUND

Install the binding in the InputMap associated with JRootPane, which will
not be blown away by BasicRootPaneUI:

frame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
              KeyStroke.getKeyStroke(KeyEvent.VK_ALT, Event.ALT_MASK, false),
              "repaint");

This will work for apps that invoke setJMenuBar(mb).
###@###.### 2002-08-26
                                     
2002-08-26
EVALUATION

Yes, this is a regression. WindowsRootPaneUI's installKeyboardActions is
broken.
SwingSet isn't helping though, it does not do a setJMenuBar for its menu when
it should.
###@###.### 2002-08-23

There are two problems here:
1. SwingSet2 does not install the menubar via setJMenuBar. There is no
reason for this and it should be chaged.
2. WindowsRootPaneUI is getting the UI InputMap and placing bindings into it.
Because BasicRootPaneUI will occasionally clear this InputMap the bindings
that WindowsRootPaneUI installed are lost. WindowsRootPaneUI should be
creating a new UI InputMap and setting the parent to point to that of the
InputMap from Basic.
###@###.### 2002-08-26

Name: azR10139			Date: 10/07/2002


The reason of this bug is that BasicRootPaneUI class resets keyboard action
table every time BasicRootPaneUI.installKeyboardActions() method is called.
This makes usege of inputmap unstable. Also we are turning mnemonic
displaying on and off in different classes. The idea of suggestede fix is
to collect all the functionality, related to the Alt pressing and releasing in
one class. The logic now is similar to logic used for native Win32 apps in
W2K/WXP environment.

1. User press Alt.
1.1. If no menu selected and we do have JMenuBar in this RootPane or in
root JFrame we turn mnemonic on, set flag to select first menu in JMenuBar
on Alt releasing if no other key pressed and consuming event to prevent AWT 
from selecting system menu of this window on Alt release.
1.2. If no menu selected and we can't find JMenuBar to select we are turn
mnemonic on and do not consume event.
1.3. If there are menu selected we are clearing menu selection, setting the
flag that we are cancelled menu on press and consuming event.

2. User releases Alt
2.1. If menu are cancelled on Alt or no JMenuBar accessible press we just
turning mnemonics off.
2.2. If there are JMenuBar accessible and no button were pressed since Alt
we are selecting first menu in JMenuBar.

Turning mnemonic on and off consist from calling
BasicLookAndFeel.setMnemonicHidden() with appropriate parameter and repainting
all the components  which do have mnemonics in window where event origins and
all the owned windows. This optimisation also deals with bug 4748780:
1.4 REGRESSION: Pressing ALT key causes JThree to repaint in Windows L&F

In the WindowsLookAndFeel.uninitialize() method i also added uninitialisation
of WindowsPopupMenuUI.mnemonicListener which eliminates bug 4692725:
WindowsPopupMenuUI.MenuListener does not reset repaintRoot on UI change.
This bug originally must be named as 
'WindowsPopupMenuUI.MnemonicListener does not reset repaintRoot on UI change.'
because there were no MenuListener class in the WindowsPopupMenuUI.java

Also, because we are eliminating inner class AltProcessor from 
BasicPopupMenuUI bug 4692727:
WindowsPopupMenuUI.MenuListener does not get reinstalled on second windows inst
which relates on WindowsPopupMenuUI.AltProcessor class.

###@###.###                10/07/2002
======================================================================
                                     
2002-10-07
SUGGESTED FIX



Name: azR10139			Date: 10/07/2002



------- WindowsLookAndFeel.java -------
*** /tmp/sccs.lUaOZx	Mon Oct  7 19:40:57 2002
--- WindowsLookAndFeel.java	Fri Oct  4 19:13:06 2002
***************
*** 139,144 ****
--- 139,146 ----
  	    // do this if we know it's 98/2000 or greater....
  	    PopupFactory.setSharedInstance(new WindowsPopupFactory());
  	}
+         KeyboardFocusManager.getCurrentKeyboardFocusManager().
+             addKeyEventPostProcessor(WindowsRootPaneUI.altProcessor);
      }
      
      /** 
***************
*** 1496,1506 ****
          if (WindowsPopupMenuUI.mnemonicListener != null) {
              MenuSelectionManager.defaultManager().
                  removeChangeListener(WindowsPopupMenuUI.mnemonicListener);
          }
!         if (WindowsPopupMenuUI.altProcessor != null) {
!             KeyboardFocusManager.getCurrentKeyboardFocusManager().
!                 removeKeyEventPostProcessor(WindowsPopupMenuUI.altProcessor);
!         }
          DesktopProperty.flushUnreferencedProperties();
      }
  
--- 1498,1507 ----
          if (WindowsPopupMenuUI.mnemonicListener != null) {
              MenuSelectionManager.defaultManager().
                  removeChangeListener(WindowsPopupMenuUI.mnemonicListener);
+             WindowsPopupMenuUI.mnemonicListener = null;
          }
!         KeyboardFocusManager.getCurrentKeyboardFocusManager().
!             removeKeyEventPostProcessor(WindowsRootPaneUI.altProcessor);
          DesktopProperty.flushUnreferencedProperties();
      }
  

------- WindowsPopupMenuUI.java -------
*** /tmp/sccs.luaa0x	Mon Oct  7 19:41:24 2002
--- WindowsPopupMenuUI.java	Fri Oct  4 19:13:26 2002
***************
*** 30,36 ****
  public class WindowsPopupMenuUI extends BasicPopupMenuUI {
  
      static MnemonicListener mnemonicListener = null;
-     static KeyEventPostProcessor altProcessor = null;
  
      public static ComponentUI createUI(JComponent c) {
  	return new WindowsPopupMenuUI();
--- 30,35 ----
***************
*** 45,56 ****
              MenuSelectionManager.defaultManager().
                  addChangeListener(mnemonicListener);
          }
- 
-         if (altProcessor == null) {
-             altProcessor = new AltProcessor();
-             KeyboardFocusManager.getCurrentKeyboardFocusManager().
-                 addKeyEventPostProcessor(altProcessor);
-         }
      }
  
      /**
--- 44,49 ----
***************
*** 85,148 ****
              }
          }
      }
- 
-     static class AltProcessor implements KeyEventPostProcessor {
-         static boolean altKeyPressed = false;
-         static boolean menuCanceledOnPress = false;
- 
-         void altPressed() {
-             MenuSelectionManager msm =
-                 MenuSelectionManager.defaultManager();
-             MenuElement[] path = msm.getSelectedPath();
-             if (path.length > 0 && ! (path[0] instanceof ComboPopup)) {
-                 msm.clearSelectedPath();
-                 menuCanceledOnPress = true;
-             } else {
-                 menuCanceledOnPress = false;
-             }
-         }
- 
-         void altReleased(KeyEvent ev) {
-             if (menuCanceledOnPress) {
-                 return;
-             }
- 
-             MenuSelectionManager msm =
-                 MenuSelectionManager.defaultManager();
-             if (msm.getSelectedPath().length == 0) {
-                 // if no menu is active, we try activating the menubar
-                 JRootPane root = SwingUtilities.getRootPane(ev.getComponent());
-                 java.awt.Window w = SwingUtilities.getWindowAncestor(root);
- 
-                 JMenuBar mbar = root != null ? root.getJMenuBar() : null;
-                 JMenu menu = mbar != null ? mbar.getMenu(0) : null;
- 
-                 if (menu != null) {
-                     MenuElement[] path = new MenuElement[2];
-                     path[0] = mbar;
-                     path[1] = menu;
-                     msm.setSelectedPath(path);
-                 }
-             }
-         }
- 
-         public boolean postProcessKeyEvent(KeyEvent ev) {
-             if (ev.getKeyCode() == KeyEvent.VK_ALT) {
-                 if (ev.getID() == KeyEvent.KEY_PRESSED) {
-                     if (!altKeyPressed) {
-                         altPressed();
-                     }
-                     altKeyPressed = true;
-                 } else if (ev.getID() == KeyEvent.KEY_RELEASED) {
-                     if (altKeyPressed) {
-                         altReleased(ev);
-                     }
-                     altKeyPressed = false;
-                 }
-             } else {
-                 altKeyPressed = false;
-             }
-             return false;
-         }
-     }
  }
--- 78,81 ----

------- WindowsRootPaneUI.java -------
*** /tmp/sccs.11aO1x	Mon Oct  7 19:43:29 2002
--- WindowsRootPaneUI.java	Mon Oct  7 19:43:20 2002
***************
*** 8,14 ****
--- 8,17 ----
  package com.sun.java.swing.plaf.windows;
  
  import java.awt.Component;
+ import java.awt.Container;
  import java.awt.Event;
+ import java.awt.KeyEventPostProcessor;
+ import java.awt.Window;
  
  import java.awt.event.ActionEvent;
  import java.awt.event.KeyEvent;
***************
*** 21,26 ****
--- 24,35 ----
  import javax.swing.JRootPane;
  import javax.swing.SwingUtilities;
  import javax.swing.UIManager;
+ import javax.swing.AbstractButton;
+ import javax.swing.JFrame;
+ import javax.swing.JMenu;
+ import javax.swing.JMenuBar;
+ import javax.swing.MenuElement;
+ import javax.swing.MenuSelectionManager;
  
  import javax.swing.plaf.ActionMapUIResource;
  import javax.swing.plaf.ComponentUI;
***************
*** 27,32 ****
--- 36,42 ----
  import javax.swing.plaf.InputMapUIResource;
  
  import javax.swing.plaf.basic.BasicRootPaneUI;
+ import javax.swing.plaf.basic.ComboPopup;
  
  /**
   * Windows implementation of RootPaneUI, there is one shared between all
***************
*** 39,87 ****
  public class WindowsRootPaneUI extends BasicRootPaneUI {
  
      private final static WindowsRootPaneUI windowsRootPaneUI = new WindowsRootPaneUI();
!     private final static AltAction altAction = new AltAction();
  
      public static ComponentUI createUI(JComponent c) {
  	return windowsRootPaneUI;
      }
  
!     protected void installKeyboardActions(JRootPane root) {
! 	super.installKeyboardActions(root);
  
! 	InputMap km = SwingUtilities.getUIInputMap(root, 
! 				     JComponent.WHEN_IN_FOCUSED_WINDOW);
! 	if (km == null) {
! 	    km = new InputMapUIResource();
! 	    SwingUtilities.replaceUIInputMap(root, 
! 				     JComponent.WHEN_IN_FOCUSED_WINDOW, km);
! 	}
! 	km.put(KeyStroke.getKeyStroke(KeyEvent.VK_ALT, Event.ALT_MASK, false), "repaint");
  
! 	ActionMap am = SwingUtilities.getUIActionMap(root);
! 	if (am == null) {
! 	    am = new ActionMapUIResource();
! 	    SwingUtilities.replaceUIActionMap(root, am);
! 	}
! 	am.put("repaint", altAction);
!     }    
  
!     protected void uninstallKeyboardActions(JRootPane root) {
! 	super.uninstallKeyboardActions(root);
! 	
! 	SwingUtilities.replaceUIInputMap(root, JComponent.WHEN_IN_FOCUSED_WINDOW, null);
! 	SwingUtilities.replaceUIActionMap(root, null);
!     }
  
!     /**
!      * Repaints the hierarchy if the Alt key is pressed.
!      */
!     static class AltAction extends AbstractAction {
! 	public void actionPerformed(ActionEvent e) {
! 	    WindowsLookAndFeel.setMnemonicHidden(false);
! 	    Object object = e.getSource();
! 	    if (object instanceof Component) {
!                 WindowsLookAndFeel.repaintRootPane((Component)object);
! 	    }
! 	}
      }
  }
--- 49,186 ----
  public class WindowsRootPaneUI extends BasicRootPaneUI {
  
      private final static WindowsRootPaneUI windowsRootPaneUI = new WindowsRootPaneUI();
!     static final AltProcessor altProcessor = new AltProcessor();
  
      public static ComponentUI createUI(JComponent c) {
  	return windowsRootPaneUI;
      }
  
!     static class AltProcessor implements KeyEventPostProcessor {
!         static boolean altKeyPressed = false;
!         static boolean menuCanceledOnPress = false;
!         static JRootPane root = null;
!         static Window winAncestor = null;
  
!         void repaintMnemonicsInWindow(Window w) {
!             if(w == null || !w.isShowing()) {
!                 return;
!             }
  
!             Window[] ownedWindows = w.getOwnedWindows();
!             for(int i=0;i<ownedWindows.length;i++) {
!                 repaintMnemonicsInWindow(ownedWindows[i]);
!             }
  
!             repaintMnemonicsInComponents(w.getComponents());
!         }
  
!         void repaintMnemonicsInComponents(Component[] c) {
!             for(int i=0;i<c.length;i++) {
!                 if(c[i] instanceof AbstractButton
!                    && ((AbstractButton)c[i]).getMnemonic() != '\0') {
!                     c[i].repaint();
!                     continue;
!                 }
!                 if(c[i] instanceof Container) {
!                     repaintMnemonicsInComponents(
!                       ((Container)c[i]).getComponents());
!                 }
!             }
!         }
! 
!         void altPressed(KeyEvent ev) {
!             MenuSelectionManager msm =
!                 MenuSelectionManager.defaultManager();
!             MenuElement[] path = msm.getSelectedPath();
!             if (path.length > 0 && ! (path[0] instanceof ComboPopup)) {
!                 msm.clearSelectedPath();
!                 menuCanceledOnPress = true;
!                 ev.consume();
!             } else if(path.length > 0) { // We are in ComboBox
!                 menuCanceledOnPress = false;
!                 WindowsLookAndFeel.setMnemonicHidden(false);
!                 repaintMnemonicsInWindow(winAncestor);
!                 ev.consume();
!             } else {
!                 menuCanceledOnPress = false;
! 	        WindowsLookAndFeel.setMnemonicHidden(false);
!                 repaintMnemonicsInWindow(winAncestor);
!                 JMenuBar mbar = root != null ? root.getJMenuBar() : null;
!                 if(mbar == null && winAncestor instanceof JFrame) {
!                     mbar = ((JFrame)winAncestor).getJMenuBar();
!                 }
!                 JMenu menu = mbar != null ? mbar.getMenu(0) : null;
!                 if(menu != null) {
!                     ev.consume();
!                 }
!             }
!         }
! 
!         void altReleased(KeyEvent ev) {
!             if (menuCanceledOnPress) {
! 	        WindowsLookAndFeel.setMnemonicHidden(true);
!                 repaintMnemonicsInWindow(winAncestor);
!                 return;
!             }
! 
!             MenuSelectionManager msm =
!                 MenuSelectionManager.defaultManager();
!             if (msm.getSelectedPath().length == 0) {
!                 // if no menu is active, we try activating the menubar
! 
!                 JMenuBar mbar = root != null ? root.getJMenuBar() : null;
!                 if(mbar == null && winAncestor instanceof JFrame) {
!                     mbar = ((JFrame)winAncestor).getJMenuBar();
!                 }
!                 JMenu menu = mbar != null ? mbar.getMenu(0) : null;
! 
!                 if (menu != null) {
!                     MenuElement[] path = new MenuElement[2];
!                     path[0] = mbar;
!                     path[1] = menu;
!                     msm.setSelectedPath(path);
!                 } else if(!WindowsLookAndFeel.isMnemonicHidden()) {
!                     WindowsLookAndFeel.setMnemonicHidden(true);
!                     repaintMnemonicsInWindow(winAncestor);
!                 }
!             } else {
!                 if((msm.getSelectedPath())[0] instanceof ComboPopup) {
!                     WindowsLookAndFeel.setMnemonicHidden(true);
!                     repaintMnemonicsInWindow(winAncestor);
!                 }
!             }
! 
!         }
! 
!         public boolean postProcessKeyEvent(KeyEvent ev) {
!             if (ev.getKeyCode() == KeyEvent.VK_ALT) {
!                 root = SwingUtilities.getRootPane(ev.getComponent());
!                 winAncestor = SwingUtilities.getWindowAncestor(root);
! 
!                 if (ev.getID() == KeyEvent.KEY_PRESSED) {
!                     if (!altKeyPressed) {
!                         altPressed(ev);
!                     }
!                     altKeyPressed = true;
!                     return true;
!                 } else if (ev.getID() == KeyEvent.KEY_RELEASED) {
!                     if (altKeyPressed) {
!                         altReleased(ev);
!                     } else {
!                         MenuSelectionManager msm =
!                             MenuSelectionManager.defaultManager();
!                         MenuElement[] path = msm.getSelectedPath();
!                         if (path.length <= 0) {
!                             WindowsLookAndFeel.setMnemonicHidden(true);
!                             repaintMnemonicsInWindow(winAncestor);
!                         }
!                     }
!                     altKeyPressed = false;
!                 }
!             } else {
!                 altKeyPressed = false;
!             }
!             return false;
!         }
      }
  }

======================================================================
                                     
2004-08-24
CONVERTED DATA

BugTraq+ Release Management Values

COMMIT TO FIX:
mantis

FIXED IN:
mantis

INTEGRATED IN:
mantis
mantis-b08


                                     
2004-08-24



Hardware and Software, Engineered to Work Together