changeset 1062:9290aa06a02c

fix RT-20411 Menubar hogs keyboard focus after a menu item is selected.
author Paru Somashekar <paru.somashekar@oracle.com>
date Thu, 17 May 2012 21:50:38 -0700
parents 254946092c0a
children eb89f9cc63e6
files javafx-ui-controls/src/com/sun/javafx/scene/control/skin/MenuBarSkin.java javafx-ui-controls/test/com/sun/javafx/scene/control/skin/MenuBarMenuButtonRetriever.java javafx-ui-controls/test/javafx/scene/control/MenuBarTest.java
diffstat 3 files changed, 91 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/MenuBarSkin.java	Thu May 17 13:09:58 2012 -0700
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/MenuBarSkin.java	Thu May 17 21:50:38 2012 -0700
@@ -25,8 +25,6 @@
 
 package com.sun.javafx.scene.control.skin;
 
-import com.sun.javafx.css.StyleManager;
-import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.WeakHashMap;
@@ -52,14 +50,10 @@
 import javafx.scene.control.MenuButton;
 import javafx.scene.control.MenuItem;
 import javafx.scene.control.SeparatorMenuItem;
-import javafx.scene.input.KeyCode;
-import javafx.scene.input.KeyCodeCombination;
 import javafx.scene.input.KeyEvent;
 import javafx.scene.input.MouseEvent;
 import javafx.scene.layout.HBox;
-import javafx.stage.Modality;
 import javafx.stage.Stage;
-import javafx.stage.Window;
 
 import com.sun.javafx.menu.MenuBase;
 import com.sun.javafx.scene.control.GlobalMenuAdapter;
@@ -69,11 +63,8 @@
 import com.sun.javafx.scene.traversal.TraverseListener;
 import com.sun.javafx.stage.StageHelper;
 import com.sun.javafx.tk.Toolkit;
-import javafx.beans.property.*;
-import javafx.event.Event;
+import javafx.event.ActionEvent;
 import javafx.event.EventType;
-import javafx.geometry.Side;
-import javafx.scene.control.*;
 import javafx.scene.input.*;
 
 
@@ -335,6 +326,10 @@
         return null;
     }
     
+    int getFocusedMenuIndex() {
+        return focusedMenuIndex;
+    }
+    
     private boolean menusContainCustomMenuItem() {
         for (Menu menu : getSkinnable().getMenus()) {
             if (menuContainsCustomMenuItem(menu)) {
@@ -368,7 +363,30 @@
         return -1;
     }
     
+    // RT-20411 : reset menu selected/focused state 
+    private EventHandler<ActionEvent> menuActionEventHandler = new EventHandler<ActionEvent>() {
+        @Override
+        public void handle(ActionEvent t) {
+            unSelectMenus();
+        }
+    };
+    
+    private void updateActionListeners(Menu m, boolean add) {
+        for (MenuItem mi : m.getItems()) {
+            if (mi instanceof Menu) {
+                updateActionListeners((Menu)mi, add);
+            } else {
+                if (add) {
+                    mi.addEventHandler(ActionEvent.ACTION, menuActionEventHandler);
+                } else {
+                    mi.removeEventHandler(ActionEvent.ACTION, menuActionEventHandler);
+                }
+            }
+        }
+    }
+    
     private void rebuildUI() {
+        int index = 0;
         for(Node n : container.getChildren()) {
             //Stop observing menu's showing & disable property for changes.
             //Need to unbind before clearing container's children.
@@ -379,6 +397,8 @@
             menuButton.textProperty().unbind();
             menuButton.graphicProperty().unbind();
             menuButton.styleProperty().unbind();
+            updateActionListeners(getSkinnable().getMenus().get(index), false);
+            index++;
         }
         container.getChildren().clear();
 
@@ -625,6 +645,7 @@
                     }
                 }
             });
+            updateActionListeners(menu, true);
         }
         requestLayout();
     }
--- a/javafx-ui-controls/test/com/sun/javafx/scene/control/skin/MenuBarMenuButtonRetriever.java	Thu May 17 13:09:58 2012 -0700
+++ b/javafx-ui-controls/test/com/sun/javafx/scene/control/skin/MenuBarMenuButtonRetriever.java	Thu May 17 21:50:38 2012 -0700
@@ -49,4 +49,8 @@
     public static void setCurrentFocusedIndex(ContextMenuContent cmc, int i) {
         cmc.setCurrentFocusedIndex(i);
     }
+    
+    public static int getFocusedIndex(MenuBarSkin skin) {
+        return skin.getFocusedMenuIndex();
+    }
 }
--- a/javafx-ui-controls/test/javafx/scene/control/MenuBarTest.java	Thu May 17 13:09:58 2012 -0700
+++ b/javafx-ui-controls/test/javafx/scene/control/MenuBarTest.java	Thu May 17 21:50:38 2012 -0700
@@ -175,6 +175,62 @@
         assertTrue(!menu.isShowing());
     }
         
+    @Test public void checkMenuBarMenusSelectionResetAfterMenuItemIsSelected() {
+        final MouseEventGenerator generator = new MouseEventGenerator();
+        AnchorPane root = new AnchorPane();
+        Menu menu = new Menu("Menu");
+        MenuItem menuItem = new MenuItem("MenuItem");
+        menu.getItems().add(menuItem);
+
+        menuBar.getMenus().add(menu);
+        menuBar.setLayoutX(100);
+        menuBar.setLayoutY(100);
+
+        root.getChildren().addAll(menuBar);
+        
+        startApp(root);
+        tk.firePulse();
+        
+        MenuBarSkin skin = (MenuBarSkin)menuBar.getSkin();
+        assertTrue(skin != null);
+        MenuButton mb = MenuBarMenuButtonRetriever.getNodeForMenu(skin, 0);
+        mb.getScene().getWindow().requestFocus();
+        
+        double xval = (menuBar.localToScene(menuBar.getLayoutBounds())).getMinX();
+        double yval = (menuBar.localToScene(menuBar.getLayoutBounds())).getMinY();
+   
+        scene.impl_processMouseEvent(
+            generator.generateMouseEvent(MouseEvent.MOUSE_PRESSED, xval+20, yval+20));
+        scene.impl_processMouseEvent(
+            generator.generateMouseEvent(MouseEvent.MOUSE_RELEASED, xval+20, yval+20));
+        assertTrue(menu.isShowing());
+         /* ------------------------------------------------------------------ */
+        
+        // Show Menu
+        ContextMenuContent menuContent = MenuBarMenuButtonRetriever.getMenuContent(mb); // ContextMenuContent
+        Node displayNode = MenuBarMenuButtonRetriever.getDisplayNodeForMenuItem(menuContent, 0); // MenuItemContainer
+        
+        displayNode.getScene().getWindow().requestFocus();
+        assertTrue(displayNode.getScene().getWindow().isFocused());
+        
+        displayNode.requestFocus(); // requestFocus on 1st Menu
+        assertTrue(displayNode.isFocused());
+        
+        // fire KeyEvent (Enter) on menuitem 
+        KeyEventFirer keyboard = new KeyEventFirer(menuContent);
+        keyboard.doKeyPress(KeyCode.ENTER);
+        tk.firePulse();     
+        
+        // confirm menu is closed. 
+        assertTrue(!menu.isShowing());
+        keyboard.doKeyPress(KeyCode.LEFT);
+        tk.firePulse();
+        
+        // check if focusedMenuIndex is reset to -1 so navigation happens.
+        int focusedIndex = MenuBarMenuButtonRetriever.getFocusedIndex(skin);
+        assertEquals(focusedIndex, -1);
+        
+    }
 //    static final class MouseEventTracker {
 //        private Node node;
 //