United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-4791569 Accelerator keys don't work when JPopupMenu is outside its parent
JDK-4791569 : Accelerator keys don't work when JPopupMenu is outside its parent

Details
Type:
Bug
Submit Date:
2002-12-10
Status:
Resolved
Updated Date:
2004-10-13
Project Name:
JDK
Resolved Date:
2003-04-02
Component:
client-libs
OS:
generic,windows_2000
Sub-Component:
javax.swing
CPU:
x86,generic
Priority:
P4
Resolution:
Fixed
Affected Versions:
1.4.1,1.4.2_05
Fixed Versions:
1.4.2_07 (b01)

Related Reports
Backport:
Duplicate:
Relates:

Sub Tasks

Description
Name: jk109818			Date: 12/10/2002


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

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

A DESCRIPTION OF THE PROBLEM :
JPopupMenuItem accelerator keys (set thanks Command) are
nolonger active as soon as the JPopupMenu is (even
partially) outside the listener area.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1.Right click the mouse button to trigger a PopupMenu so the
popup is partially outside its parent
2.Try to type an accelerator command
3.The command is not effective

(note that the keyboard arrows are still effective)

EXPECTED VERSUS ACTUAL BEHAVIOR :
The accelerator command should be effective

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package sample.popup;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;

/**
 * @author f.savino
 *
 * To change this generated comment edit the template variable "typecomment":
 * Window>Preferences>Java>Templates.
 * To enable and disable the creation of type comments go to
 * Window>Preferences>Java>Code Generation.
 */

public class PopupSample extends JPanel {
	private final String _lstModel[] = { "First Item", "Second Item", "Third Item" };
	private JList _myList = null;
	private JScrollPane _jsp = null;
	private JPopupMenu _myPopupMenu = null;
	private Action _actCut = null;
	private Action _actCopy = null;
	private Action _actPaste = null;
	
	public PopupSample() {
		initMembers();
		initLayout();
		initListener();
	}

	/**
	 * Method initMembers.
	 */
	private void initMembers() {
		_myList = new JList(_lstModel);
		_myPopupMenu = new JPopupMenu("MyPopup");
		// Cut menu item
		_actCut = new AbstractAction("cut") {
			public void actionPerformed(ActionEvent e) {
				JOptionPane.showMessageDialog(PopupSample.this.getTopLevelAncestor(), "Cut");
			}
		};
        _actCut.putValue(Action.ACCELERATOR_KEY,
KeyStroke.getKeyStroke(KeyEvent.VK_X, ActionEvent.CTRL_MASK));
        _myPopupMenu.add(_actCut);
        
		// Copy menu item
		_actCopy = new AbstractAction("Copy") {
			public void actionPerformed(ActionEvent e) {
				JOptionPane.showMessageDialog(PopupSample.this.getTopLevelAncestor(), "Copy");
			}
		};
        _actCopy.putValue(Action.ACCELERATOR_KEY,
KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.CTRL_MASK));
        _myPopupMenu.add(_actCopy);

		// Paste menu item
		_actPaste = new AbstractAction("Paste") {
			public void actionPerformed(ActionEvent e) {
				JOptionPane.showMessageDialog(PopupSample.this.getTopLevelAncestor(), "Paste");
			}
		};
        _actPaste.putValue(Action.ACCELERATOR_KEY,
KeyStroke.getKeyStroke(KeyEvent.VK_V, ActionEvent.CTRL_MASK));
        _myPopupMenu.add(_actPaste);
        
        _jsp = new JScrollPane(_myList);
	}


	/**
	 * Method initLayout.
	 */
	private void initLayout() {
		this.setLayout(new BorderLayout());
		this.add(new JLabel("Right click in the control above..."), BorderLayout.NORTH);
		this.add(_jsp, BorderLayout.CENTER);
	}
	
	/**
	 * Method initListener.
	 */
	private void initListener() {
		_myList.addMouseListener(new MouseAdapter() {
			public void mousePressed(MouseEvent e) {
				maybeShowPopup(e);
			}
			public void mouseReleased(MouseEvent e) {
				maybeShowPopup(e);
			}
			private void maybeShowPopup(MouseEvent e) {
				if (e.isPopupTrigger()) {
					_myPopupMenu.show(e.getComponent(), e.getX(), e.getY());
				}
			}
		});
		_jsp.addMouseListener(new MouseAdapter() {
			public void mousePressed(MouseEvent e) {
				maybeShowPopup(e);
			}
			public void mouseReleased(MouseEvent e) {
				maybeShowPopup(e);
			}
			private void maybeShowPopup(MouseEvent e) {
				if (e.isPopupTrigger()) {
					_myPopupMenu.show(e.getComponent(), e.getX(), e.getY());
				}
			}
		});
	}

	public static void main(String[] args) {
		JFrame frm = new JFrame();
		frm.setTitle("ContextMenu");
		frm.getContentPane().add(new PopupSample());
		// Not 1.2 complient !!!
		frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frm.pack();
		frm.show();
	}
}

---------- END SOURCE ----------
(Review ID: 178961) 
======================================================================
###@###.### 10/13/04 17:04 GMT

                                    

Comments
EVALUATION



Name: azR10139			Date: 12/23/2002


We are hendling the accelerators in the InputMap that we are setting for
JMenuItem with WHEN_IN_FOCUSED_WINDOW mask. But when menuitem to which this
accelerator is set becames member of the heavyweigth popup they are no longer
in the focused window and accelerator stops working.

The idea of suggested fix is to handle keyboard accelerator in the 
BasicMenuItemUI$MenuKeyHandler.menuKeyPressed() method to catch accelerator in
the heavyweigth popup.
###@###.###                12/23/2002
======================================================================

Name: pzR10082			Date: 02/19/2003


Those accelerators are actually handled using Actions. The problem is
that those Actions are never invoked after a Dialog has been displayed.
The method PopupFactory.overlappedByOwnedWindow() is at fault. When
checking whether popup overlaps any of the owned Windows, it doesn't
check visibility of those Windows. When it encounters a Dialog (even
invisible) it finds that it overlaps popup and forces heavyweight
popups.

Heavyweight popups do not process KeyStrokes because they are non-focusable
Windows. So we should register Actions with the Frame rather than with
HeavyWeigthWindow. Method KeyboardManager.getTopAncestor() should be
modified accordingly.

###@###.### 2003-02-19

======================================================================
                                     
2003-02-19
SUGGESTED FIX


###@###.### 2003-03-20

*** /net/diablo/export2/swing/zpm/webrev/src/share/classes/javax/swing/KeyboardManager.java-    Wed Feb 19 13:40:49 2003
--- KeyboardManager.java        Wed Feb 19 13:37:19 2003
***************
*** 114,120 ****
         */
       private static Container getTopAncestor(JComponent c) {
          for(Container p = c.getParent(); p != null; p = p.getParent()) {
!             if (p instanceof Window || p instanceof Applet || p instanceof JInternalFrame) {
                  return p;
            }
          }
--- 114,122 ----
         */
       private static Container getTopAncestor(JComponent c) {
          for(Container p = c.getParent(); p != null; p = p.getParent()) {
!             if (p instanceof Window && ((Window)p).isFocusableWindow() ||
!                 p instanceof Applet || p instanceof JInternalFrame) {
! 
                  return p;
            }
          }
*** /net/diablo/export2/swing/zpm/webrev/src/share/classes/javax/swing/PopupFactory.java-       Wed Feb 19 13:40:48 2003
--- PopupFactory.java   Wed Feb 19 13:36:33 2003
***************
*** 492,504 ****
              Component component = getComponent();
              if(owner != null && component != null) {
                  Window w = SwingUtilities.getWindowAncestor(owner);
!                 if(w == null)
                      return false;
                  Window[] ownedWindows = w.getOwnedWindows();
                  if(ownedWindows != null) {
                      Rectangle bnd = component.getBounds();
                      for(int i=0; i<ownedWindows.length;i++) {
!                         if(bnd.intersects(ownedWindows[i].getBounds())) {
                              return true;
                          }
                      }
--- 492,508 ----
              Component component = getComponent();
              if (owner != null && component != null) {
                  Window w = SwingUtilities.getWindowAncestor(owner);
!                 if (w == null) {
                      return false;
+                 }
                  Window[] ownedWindows = w.getOwnedWindows();
                  if (ownedWindows != null) {
                      Rectangle bnd = component.getBounds();
                      for (int i=0; i<ownedWindows.length;i++) {
!                         Window owned = ownedWindows[i];
!                         if (owned.isVisible() &&
!                             bnd.intersects(owned.getBounds())) {
! 
                              return true;
                          }
                      }

                                     
2004-10-02
CONVERTED DATA

BugTraq+ Release Management Values

COMMIT TO FIX:
1.4.2_07
tiger

FIXED IN:
1.4.2_07
tiger

INTEGRATED IN:
1.4.2_07
tiger
tiger-b04


                                     
2004-10-02



Hardware and Software, Engineered to Work Together