JDK-6471783 : Mnemonics and accelerators are unreliable for JMenuBar within JApplet
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 5.0
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2006-09-18
  • Updated: 2011-02-16
  • Resolved: 2006-10-16
Related Reports
Duplicate :  
Relates :  
Description
FULL PRODUCT VERSION :
Version 1.5.0 (build 1.5.0_07-b03)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
When using mnemonics and/or accelerators for menu items within a JApplet, results are unreliable. Events are variously either handled by the applet, by the browser, or ignored completely. The outcome of these keyboard shortcuts appears to be in part, though not wholly, related to inconsistent focus handling.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile and run test case provided.

Use ctrl-E and ctrl-N (or alt-F-E and alt-F-N) to create new internal frames, using E to create frames which contain a focusable component and N to create frames which do not.

Note that when run as an application, behaviour is exactly as expected.

When run as an applet in a web browser, behaviour is inconsistent.

When the menu items are selected using the mouse, behaviour in all instances is as expected.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
1. Ctrl-E or Alt-F followed by E should open a frame with a label and a text pane.
2. Ctrl-N or Alt-F followed by N should open a frame with a label.
3. After closing any internal frames, 1 and 2 should still function as before.
ACTUAL -
There may be occasional variations in results since the bug is fundamentally one of unpredictability, but the following are repeatable symptoms observed running JRE 1.5.0_07 under Java Plugin in Internet Explorer 6.0.2900.2180.

1. Neither Ctrl-N nor Ctrl-E are functional until either item has been selected with the mouse.
2. When first loaded, pressing Alt-F does nothing.
3. When one or more internal frames are open, Alt-F works correctly.
4. When one or more frames have been opened, but all have been closed, Alt-F subsequently opens the browser's 'File' menu.
5. Following the use of Alt-F as per item 4, Alt-F is subsequently ignored.
6. When an 'editable' frame's text pane has focus, Ctrl-E and Ctrl-N both work correctly.
7. When a 'non editable' frame has focus, Ctrl-E and Ctrl-N both work correctly.
8. On closing any frame where one or more frames remain open, focus seems to be randomly either assigned to a frame or not, as a result of which Ctrl-E will either be handled by the applet (opening a new frame) or by the browser (displaying the search pane).
9. On Ctrl-E being handled by the browser to *hide* the search pane, it is subsequently handled correctly by the applet if there are internal frames open, otherwise it is handled by the browser to reopen the search pane.
10. After closing one or more internal frames, pressing Ctrl will sometimes underline the browser's menu mnemonic characters (as might normally be expected by pressing Alt) - this of course reaults in Ctrl-N or Ctrl-E not being handled by the applet. On further investigation it appears that this coincides with the occasions when closing an internal frame fails to assign focus to the text pane within the internal frame behind it.

I have also on a few occasions managed to spawn a new browser window by using Ctrl-N, but this appears to be difficult to reproduce.

In summary, the results are that when used in a fully fledged applet with complex focus dynamics, mnemonics and accelerators are almost entirely unreliable.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JApplet;
import javax.swing.JComponent;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

public class TestApplet extends JApplet
{
	public static void main(String[] args)
	{
		SwingUtilities.invokeLater(new App());
	}
	
	public void init()
	{
		super.init();
		
		App app = new App();
		setJMenuBar(app.getMenuBar());
		setContentPane(app.getContent());
	}
	
	private static class App implements Runnable
	{
		private int counter = 0;
		private JMenuBar menuBar = null;
		private JDesktopPane desktop = null;
		
		public void run()
		{
			try
			{
				UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
			}
			catch (Exception e)
			{
			}
			
			JFrame frame = new JFrame();
			frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			frame.setJMenuBar(getMenuBar());
			frame.setContentPane(getContent());
			frame.pack();
			frame.setLocationRelativeTo(null);
			frame.setVisible(true);
		}
		
		private JMenuBar getMenuBar()
		{
			if (this.menuBar == null)
			{
				this.menuBar = new JMenuBar();
				
				JMenu file = new JMenu("File");
				file.setMnemonic('F');
				this.menuBar.add(file);
				
				file.add(new JMenuItem(new Editable()));
				file.add(new JMenuItem(new NonEditable()));
			}
			
			return this.menuBar;
		}
		
		private JComponent getContent()
		{
			if (this.desktop == null)
			{
				this.desktop = new JDesktopPane();
				this.desktop.setPreferredSize(new Dimension(400, 200));
			}
			
			return this.desktop;
		}
		
		private abstract class New extends AbstractAction
		{
			protected New(String name)
			{
				putValue(Action.NAME, name);
				putValue(MNEMONIC_KEY, new Integer(name.charAt(0)));
				putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(name.charAt(0), InputEvent.CTRL_MASK));
			}
			
			public void actionPerformed(ActionEvent e)
			{
				counter ++;
				
				JPanel panel = new JPanel(new BorderLayout(4, 4));
				panel.add(new JLabel("Frame " + counter, JLabel.CENTER), BorderLayout.NORTH);
				panel.add(getContent(), BorderLayout.CENTER);
				
				JInternalFrame f = new JInternalFrame();
				f.setDefaultCloseOperation(JInternalFrame.DISPOSE_ON_CLOSE);
				f.setClosable(true);
				f.setResizable(true);
				f.setContentPane(panel);
				f.pack();
				desktop.add(f);
				f.setVisible(true);
			}
			
			protected abstract JComponent getContent();
		}
		
		private class Editable extends New
		{
			private Editable()
			{
				super("Editable");
			}
			
			protected JComponent getContent()
			{
				return new JScrollPane(new JTextPane());
			}
		}
		
		private class NonEditable extends New
		{
			private NonEditable()
			{
				super("Non-Editable");
			}
			
			protected JComponent getContent()
			{
				return new JPanel();
			}
		}
	}
}

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

Comments
EVALUATION I reproduced all problems described for 1.5 But most of them (except item 1&2) were fixed for 1.6 (see 5051557) I tested it with latest 1.6 both for IE and Mozilla The first two described issues happen because an applet with no focused children doesn't initially get focus, it behaves the same way for 1.4 and 1.5 so it's not a regression I filed a bug 6482294 for this problem for AWT The workaround is simple: setFocusable(true); in Applet's constructor or init() method Closed as duplicate of 5051557
16-10-2006

EVALUATION Need more investigations...
20-09-2006