JDK-4736093 : REGRESSION: Menu and controls shortcuts are not visible in Win L&F in jdk1.4.1
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.2.0,1.4.1
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_2000,windows_xp
  • CPU: x86
  • Submitted: 2002-08-23
  • Updated: 2002-11-16
  • Resolved: 2002-11-16
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
1.4.2 mantisFixed
Related Reports
Duplicate :  
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Relates :  
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
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: mantis FIXED IN: mantis INTEGRATED IN: mantis mantis-b08
24-08-2004

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; ! } } } ======================================================================
24-08-2004

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 ======================================================================
07-10-2002

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
26-08-2002