1 /*
   2  * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javafx.scene.control;
  27 
  28 import static org.junit.Assert.assertEquals;
  29 import static org.junit.Assert.assertFalse;
  30 import static org.junit.Assert.assertTrue;
  31 
  32 import javafx.scene.Node;
  33 import javafx.scene.Parent;
  34 import javafx.scene.Scene;
  35 import javafx.scene.control.skin.MenuBarSkinRetriever;
  36 import javafx.scene.input.KeyCode;
  37 import javafx.scene.input.MouseEvent;
  38 import javafx.scene.layout.AnchorPane;
  39 import javafx.scene.layout.VBox;
  40 import javafx.stage.Stage;
  41 
  42 import org.junit.Before;
  43 import org.junit.Test;
  44 
  45 import com.sun.javafx.pgstub.StubToolkit;
  46 import com.sun.javafx.scene.control.infrastructure.KeyEventFirer;
  47 import com.sun.javafx.scene.control.infrastructure.MouseEventGenerator;
  48 import com.sun.javafx.scene.control.ContextMenuContent;
  49 import com.sun.javafx.scene.control.MenuBarMenuButtonRetriever;
  50 import javafx.scene.control.skin.MenuBarSkin;
  51 import com.sun.javafx.tk.Toolkit;
  52 
  53 
  54 /**
  55  *
  56  * @author lubermud
  57  */
  58 
  59 public class MenuBarTest {
  60     private MenuBar menuBar;
  61     private Toolkit tk;
  62     private Scene scene;
  63     private Stage stage;
  64 
  65     @Before public void setup() {
  66         tk = (StubToolkit)Toolkit.getToolkit();
  67         menuBar = new MenuBar();
  68         menuBar.setUseSystemMenuBar(false);
  69     }
  70     
  71     protected void startApp(Parent root) {
  72         scene = new Scene(root,800,600);
  73         stage = new Stage();
  74         stage.setX(0); // The MouseEventGenerator set the screen X/Y to be the same as local Node X/Y, so we need to keep stage at 0,0
  75         stage.setY(0);
  76         stage.setScene(scene);
  77         stage.show();
  78         tk.firePulse();
  79     }
  80 
  81     @Test public void defaultConstructorHasFalseFocusTraversable() {
  82         assertFalse(menuBar.isFocusTraversable());
  83     }
  84 
  85     @Test public void defaultConstructorButSetTrueFocusTraversable() {
  86             menuBar.setFocusTraversable(true);
  87         assertTrue(menuBar.isFocusTraversable());
  88     }
  89 
  90     @Test public void getMenusHasSizeZero() {
  91         assertEquals(0, menuBar.getMenus().size());
  92     }
  93 
  94     @Test public void getMenusIsAddable() {
  95         menuBar.getMenus().add(new Menu(""));
  96         assertTrue(menuBar.getMenus().size() > 0);
  97     }
  98 
  99     @Test public void getMenusIsClearable() {
 100         menuBar.getMenus().add(new Menu(""));
 101         menuBar.getMenus().clear();
 102         assertEquals(0, menuBar.getMenus().size());
 103     }
 104     
 105      @Test public void getMenusIsRemovable() {
 106            menuBar.getMenus().add(new Menu("blah"));
 107            menuBar.getMenus().add(new Menu("foo"));
 108            menuBar.getMenus().remove(0);
 109            assertEquals(1, menuBar.getMenus().size());
 110      }
 111      
 112     @Test public void testMenuShowHideWithMenuBarWithXYTranslation() {
 113         final MouseEventGenerator generator = new MouseEventGenerator();
 114         AnchorPane root = new AnchorPane();
 115         Menu menu = new Menu("Menu");
 116         menu.getItems().add(new MenuItem("MenuItem"));
 117         menuBar.getMenus().add(menu);
 118         menuBar.setLayoutX(100);
 119         menuBar.setLayoutY(100);
 120         root.getChildren().add(menuBar);
 121         startApp(root);
 122         tk.firePulse();
 123         
 124         MenuBarSkin skin = (MenuBarSkin)menuBar.getSkin();
 125         assertTrue(skin != null);
 126         
 127         double xval = (menuBar.localToScene(menuBar.getLayoutBounds())).getMinX();
 128         double yval = (menuBar.localToScene(menuBar.getLayoutBounds())).getMinY();
 129    
 130         MenuButton mb = MenuBarSkinRetriever.getNodeForMenu(skin, 0);
 131         mb.getScene().getWindow().requestFocus();
 132         scene.impl_processMouseEvent(
 133             generator.generateMouseEvent(MouseEvent.MOUSE_PRESSED, xval+20, yval+20));
 134         scene.impl_processMouseEvent(
 135             generator.generateMouseEvent(MouseEvent.MOUSE_RELEASED, xval+20, yval+20));
 136         assertTrue(menu.isShowing());
 137         
 138     }
 139 
 140     @Test public void testSubMenuDismissalWithKeyNavigation() {
 141         final MouseEventGenerator generator = new MouseEventGenerator();
 142         AnchorPane root = new AnchorPane();
 143         Menu menu = new Menu("Menu");
 144         Menu menu1 = new Menu("Menu With SubMenu");
 145         menu.getItems().add(menu1);
 146 
 147         MenuItem menuItem1 = new MenuItem("MenuItem1");
 148         MenuItem menuItem2 = new MenuItem("MenuItem2");
 149         menu1.getItems().addAll(menuItem1, menuItem2);
 150         
 151         menuBar.getMenus().add(menu);
 152         menuBar.setLayoutX(100);
 153         menuBar.setLayoutY(100);
 154 
 155         root.getChildren().add(menuBar);
 156         startApp(root);
 157         tk.firePulse();
 158         
 159         MenuBarSkin skin = (MenuBarSkin)menuBar.getSkin();
 160         assertTrue(skin != null);
 161         
 162         double xval = (menuBar.localToScene(menuBar.getLayoutBounds())).getMinX();
 163         double yval = (menuBar.localToScene(menuBar.getLayoutBounds())).getMinY();
 164    
 165         MenuButton mb = MenuBarSkinRetriever.getNodeForMenu(skin, 0);
 166         mb.getScene().getWindow().requestFocus();
 167         scene.impl_processMouseEvent(
 168             generator.generateMouseEvent(MouseEvent.MOUSE_PRESSED, xval+20, yval+20));
 169         scene.impl_processMouseEvent(
 170             generator.generateMouseEvent(MouseEvent.MOUSE_RELEASED, xval+20, yval+20));
 171         assertTrue(menu.isShowing());
 172          /* ------------------------------------------------------------------ */
 173         
 174         // Show subMenu
 175         ContextMenuContent menuContent = MenuBarSkinRetriever.getMenuContent(mb); // ContextMenuContent
 176         Node displayNode = MenuBarMenuButtonRetriever.getDisplayNodeForMenuItem(menuContent, 0); // MenuItemContainer
 177         
 178         displayNode.getScene().getWindow().requestFocus();
 179         assertTrue(displayNode.getScene().getWindow().isFocused());
 180         
 181         displayNode.requestFocus(); // requestFocus on 1st Menu
 182         assertTrue(displayNode.isFocused());
 183         // update currentFocusedIndex
 184         MenuBarMenuButtonRetriever.setCurrentFocusedIndex(menuContent, 0);
 185         
 186         // fire KeyEvent (Enter) on menu1 to show submenu
 187         KeyEventFirer keyboard = new KeyEventFirer(menuContent);
 188         keyboard.doKeyPress(KeyCode.ENTER);
 189         tk.firePulse();     
 190         assertTrue(menu1.isShowing()); // subMenu is showing
 191         /* ------------------------------------------------------------------ */
 192         
 193         // Get 1st MenuItem from the submenu
 194         ContextMenuContent subMenuContent = MenuBarMenuButtonRetriever.getSubMenuContent(menuContent);
 195         subMenuContent.getScene().getWindow().requestFocus(); // requestFocus on submenu
 196         assertTrue(subMenuContent.getScene().getWindow().isFocused());
 197         
 198         displayNode = MenuBarMenuButtonRetriever.getDisplayNodeForMenuItem(subMenuContent, 0);
 199         displayNode.requestFocus();
 200         assertTrue(displayNode.isFocused());
 201         
 202         MenuBarMenuButtonRetriever.setCurrentFocusedIndex(subMenuContent, 0);
 203         // fire KeyEvent (Enter) on menuItem1 to hide all menus
 204         keyboard = new KeyEventFirer(subMenuContent);
 205         keyboard.doKeyPress(KeyCode.ENTER);
 206         tk.firePulse();
 207         
 208         // confirm all menus are closed. 
 209         assertTrue(!menu1.isShowing());
 210         assertTrue(!menu.isShowing());
 211     }
 212         
 213     @Test public void checkMenuBarMenusSelectionResetAfterMenuItemIsSelected() {
 214         final MouseEventGenerator generator = new MouseEventGenerator();
 215         AnchorPane root = new AnchorPane();
 216         Menu menu = new Menu("Menu");
 217         MenuItem menuItem = new MenuItem("MenuItem");
 218         menu.getItems().add(menuItem);
 219 
 220         menuBar.getMenus().add(menu);
 221         menuBar.setLayoutX(100);
 222         menuBar.setLayoutY(100);
 223 
 224         root.getChildren().addAll(menuBar);
 225         
 226         startApp(root);
 227         tk.firePulse();
 228         
 229         MenuBarSkin skin = (MenuBarSkin)menuBar.getSkin();
 230         assertTrue(skin != null);
 231         MenuButton mb = MenuBarSkinRetriever.getNodeForMenu(skin, 0);
 232         mb.getScene().getWindow().requestFocus();
 233         
 234         double xval = (menuBar.localToScene(menuBar.getLayoutBounds())).getMinX();
 235         double yval = (menuBar.localToScene(menuBar.getLayoutBounds())).getMinY();
 236    
 237         scene.impl_processMouseEvent(
 238             generator.generateMouseEvent(MouseEvent.MOUSE_PRESSED, xval+20, yval+20));
 239         scene.impl_processMouseEvent(
 240             generator.generateMouseEvent(MouseEvent.MOUSE_RELEASED, xval+20, yval+20));
 241         assertTrue(menu.isShowing());
 242          /* ------------------------------------------------------------------ */
 243         
 244         // Show Menu
 245         ContextMenuContent menuContent = MenuBarSkinRetriever.getMenuContent(mb); // ContextMenuContent
 246         Node displayNode = MenuBarMenuButtonRetriever.getDisplayNodeForMenuItem(menuContent, 0); // MenuItemContainer
 247         
 248         displayNode.getScene().getWindow().requestFocus();
 249         assertTrue(displayNode.getScene().getWindow().isFocused());
 250         
 251         displayNode.requestFocus(); // requestFocus on 1st Menu
 252         assertTrue(displayNode.isFocused());
 253         
 254         // fire KeyEvent (Enter) on menuitem 
 255         KeyEventFirer keyboard = new KeyEventFirer(menuContent);
 256         keyboard.doKeyPress(KeyCode.ENTER);
 257         tk.firePulse();     
 258         
 259         // confirm menu is closed. 
 260         assertTrue(!menu.isShowing());
 261         keyboard.doKeyPress(KeyCode.LEFT);
 262         tk.firePulse();
 263         
 264         // check if focusedMenuIndex is reset to -1 so navigation happens.
 265         int focusedIndex = MenuBarSkinRetriever.getFocusedIndex(skin);
 266         assertEquals(focusedIndex, -1);
 267     }
 268     
 269     @Test public void testMenuOnShownEventFiringWithKeyNavigation() {
 270         final MouseEventGenerator generator = new MouseEventGenerator();
 271         VBox root = new VBox();
 272         Menu menu = new Menu("Menu");
 273 
 274         MenuItem menuItem1 = new MenuItem("MenuItem1");
 275         MenuItem menuItem2 = new MenuItem("MenuItem2");
 276         menu.getItems().addAll(menuItem1, menuItem2);
 277         
 278         menuBar.getMenus().add(menu);
 279         menuBar.setLayoutX(100);
 280         menuBar.setLayoutY(100);
 281         
 282         final CheckBox cb = new CheckBox("showing");
 283         
 284         root.getChildren().addAll(cb,menuBar);
 285         startApp(root);
 286         tk.firePulse();
 287         
 288         MenuBarSkin skin = (MenuBarSkin)menuBar.getSkin();
 289         assertTrue(skin != null);
 290         
 291         MenuButton mb = MenuBarSkinRetriever.getNodeForMenu(skin, 0);
 292         mb.getScene().getWindow().requestFocus();
 293         assertTrue(mb.getScene().getWindow().isFocused());
 294         
 295 
 296         KeyEventFirer keyboard = new KeyEventFirer(mb.getScene());
 297         keyboard.doKeyPress(KeyCode.TAB);
 298         tk.firePulse(); 
 299         mb.requestFocus();
 300         assertTrue(mb.isFocused());
 301         
 302         keyboard = new KeyEventFirer(mb);
 303         keyboard.doDownArrowPress();
 304         tk.firePulse();
 305         assertEquals(menu.showingProperty().get(), true);
 306     }
 307     
 308     @Test public void testKeyNavigationWithDisabledMenuItem() {
 309         VBox root = new VBox();
 310         Menu menu1 = new Menu("Menu1");
 311         Menu menu2 = new Menu("Menu2");
 312         Menu menu3 = new Menu("Menu3");
 313         
 314         MenuItem menuItem1 = new MenuItem("MenuItem1");
 315         MenuItem menuItem2 = new MenuItem("MenuItem2");
 316         MenuItem menuItem3 = new MenuItem("MenuItem3");
 317 
 318         menu1.getItems().add(menuItem1);
 319         menu2.getItems().add(menuItem2);
 320         menu3.getItems().add(menuItem3);
 321         
 322         menuBar.getMenus().addAll(menu1, menu2, menu3);
 323         menu2.setDisable(true);
 324         
 325         root.getChildren().addAll(menuBar);
 326         startApp(root);
 327         tk.firePulse();
 328         
 329         MenuBarSkin skin = (MenuBarSkin)menuBar.getSkin();
 330         assertTrue(skin != null);
 331         
 332         double xval = (menuBar.localToScene(menuBar.getLayoutBounds())).getMinX();
 333         double yval = (menuBar.localToScene(menuBar.getLayoutBounds())).getMinY();
 334    
 335         MenuButton mb = MenuBarSkinRetriever.getNodeForMenu(skin, 0);
 336         mb.getScene().getWindow().requestFocus();
 337         scene.impl_processMouseEvent(
 338             MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_PRESSED, xval+20, yval+20));
 339         scene.impl_processMouseEvent(
 340             MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_RELEASED, xval+20, yval+20));
 341         assertTrue(menu1.isShowing());
 342         
 343         KeyEventFirer keyboard = new KeyEventFirer(mb.getScene());
 344         keyboard.doKeyPress(KeyCode.RIGHT);
 345         tk.firePulse(); 
 346         assertTrue(menu3.isShowing());
 347     }
 348     
 349     
 350      @Test public void testMenuOnShowingEventFiringWithMenuHideOperation() {
 351         VBox root = new VBox();
 352         Menu menu = new Menu("Menu");
 353 
 354         MenuItem menuItem1 = new MenuItem("MenuItem1");
 355         menu.getItems().addAll(menuItem1);
 356         
 357         menuBar.getMenus().add(menu);
 358         menuBar.setLayoutX(100);
 359         menuBar.setLayoutY(100);
 360         
 361         root.getChildren().addAll(menuBar);
 362         startApp(root);
 363         tk.firePulse();
 364         
 365         MenuBarSkin skin = (MenuBarSkin)menuBar.getSkin();
 366         assertTrue(skin != null);
 367         double xval = (menuBar.localToScene(menuBar.getLayoutBounds())).getMinX();
 368         double yval = (menuBar.localToScene(menuBar.getLayoutBounds())).getMinY();
 369         
 370         boolean click = true;
 371         final Boolean firstClick = new Boolean(click);
 372         
 373         menu.setOnShowing(t -> {
 374             // we should not get here when the menu is hidden
 375             assertEquals(firstClick.booleanValue(), true);
 376         });
 377         
 378         MenuButton mb = MenuBarSkinRetriever.getNodeForMenu(skin, 0);
 379         mb.getScene().getWindow().requestFocus();
 380         mb.requestFocus();
 381         assertTrue(mb.isFocused());
 382         // click on menu to show 
 383         scene.impl_processMouseEvent(
 384             MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_PRESSED, xval+20, yval+20));
 385         scene.impl_processMouseEvent(
 386             MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_RELEASED, xval+20, yval+20));
 387         tk.firePulse(); 
 388         assertEquals(menu.showingProperty().get(), true);
 389         click = false;
 390         // click on menu to hide
 391         scene.impl_processMouseEvent(
 392             MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_PRESSED, xval+20, yval+20));
 393         scene.impl_processMouseEvent(
 394             MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_RELEASED, xval+20, yval+20));
 395         tk.firePulse(); 
 396         assertEquals(menu.showingProperty().get(), false);
 397     }
 398      
 399     @Test public void testRemovingMenuItemFromMenuNotInScene() {
 400         VBox root = new VBox();
 401         Menu menu = new Menu("Menu");
 402 
 403         MenuItem menuItem1 = new MenuItem("MenuItem1");
 404         menu.getItems().addAll(menuItem1);
 405         
 406         menuBar.getMenus().add(menu);
 407         root.getChildren().addAll(menuBar);
 408         startApp(root);
 409         tk.firePulse();
 410         
 411         // remove menu from menubar
 412         menuBar.getMenus().remove(menu);
 413         //remove menuitem from menu that was just removed itself.
 414         menu.getItems().remove(menuItem1);
 415         assertEquals(true, menu.getItems().isEmpty());
 416     }
 417 
 418     @Test public void test_rt_37118() {
 419         MenuBar menuBar = new MenuBar();
 420         MenuBarSkin menuBarSkin = new MenuBarSkin(menuBar);
 421     }
 422 }