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.application.Application;
  33 import javafx.event.Event;
  34 import javafx.event.EventHandler;
  35 import javafx.scene.Node;
  36 import javafx.scene.Parent;
  37 import javafx.scene.Scene;
  38 import javafx.scene.input.KeyCode;
  39 import javafx.scene.input.MouseEvent;
  40 import javafx.scene.layout.AnchorPane;
  41 import javafx.scene.layout.VBox;
  42 import javafx.stage.Stage;
  43 
  44 import org.junit.Before;
  45 import org.junit.Ignore;
  46 import org.junit.Test;
  47 
  48 import com.sun.javafx.pgstub.StubToolkit;
  49 import com.sun.javafx.scene.control.infrastructure.KeyEventFirer;
  50 import com.sun.javafx.scene.control.infrastructure.MouseEventGenerator;
  51 import com.sun.javafx.scene.control.skin.ContextMenuContent;
  52 import com.sun.javafx.scene.control.skin.MenuBarMenuButtonRetriever;
  53 import com.sun.javafx.scene.control.skin.MenuBarSkin;
  54 import com.sun.javafx.tk.Toolkit;
  55 
  56 
  57 /**
  58  *
  59  * @author lubermud
  60  */
  61 
  62 public class MenuBarTest {
  63     private MenuBar menuBar;
  64     private Toolkit tk;
  65     private Scene scene;
  66     private Stage stage;
  67 
  68     @Before public void setup() {
  69         tk = (StubToolkit)Toolkit.getToolkit();
  70         menuBar = new MenuBar();
  71         menuBar.setUseSystemMenuBar(false);
  72     }
  73     
  74     protected void startApp(Parent root) {
  75         scene = new Scene(root,800,600);
  76         stage = new Stage();
  77         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
  78         stage.setY(0);
  79         stage.setScene(scene);
  80         stage.show();
  81         tk.firePulse();
  82     }
  83 
  84     @Test public void defaultConstructorHasFalseFocusTraversable() {
  85         assertFalse(menuBar.isFocusTraversable());
  86     }
  87 
  88     @Test public void defaultConstructorButSetTrueFocusTraversable() {
  89             menuBar.setFocusTraversable(true);
  90         assertTrue(menuBar.isFocusTraversable());
  91     }
  92 
  93     @Test public void getMenusHasSizeZero() {
  94         assertEquals(0, menuBar.getMenus().size());
  95     }
  96 
  97     @Test public void getMenusIsAddable() {
  98         menuBar.getMenus().add(new Menu(""));
  99         assertTrue(menuBar.getMenus().size() > 0);
 100     }
 101 
 102     @Test public void getMenusIsClearable() {
 103         menuBar.getMenus().add(new Menu(""));
 104         menuBar.getMenus().clear();
 105         assertEquals(0, menuBar.getMenus().size());
 106     }
 107     
 108      @Test public void getMenusIsRemovable() {
 109            menuBar.getMenus().add(new Menu("blah"));
 110            menuBar.getMenus().add(new Menu("foo"));
 111            menuBar.getMenus().remove(0);
 112            assertEquals(1, menuBar.getMenus().size());
 113      }
 114      
 115     @Test public void testMenuShowHideWithMenuBarWithXYTranslation() {
 116         final MouseEventGenerator generator = new MouseEventGenerator();
 117         AnchorPane root = new AnchorPane();
 118         Menu menu = new Menu("Menu");
 119         menu.getItems().add(new MenuItem("MenuItem"));
 120         menuBar.getMenus().add(menu);
 121         menuBar.setLayoutX(100);
 122         menuBar.setLayoutY(100);
 123         root.getChildren().add(menuBar);
 124         startApp(root);
 125         tk.firePulse();
 126         
 127         MenuBarSkin skin = (MenuBarSkin)menuBar.getSkin();
 128         assertTrue(skin != null);
 129         
 130         double xval = (menuBar.localToScene(menuBar.getLayoutBounds())).getMinX();
 131         double yval = (menuBar.localToScene(menuBar.getLayoutBounds())).getMinY();
 132    
 133         MenuButton mb = MenuBarMenuButtonRetriever.getNodeForMenu(skin, 0);
 134         mb.getScene().getWindow().requestFocus();
 135         scene.impl_processMouseEvent(
 136             generator.generateMouseEvent(MouseEvent.MOUSE_PRESSED, xval+20, yval+20));
 137         scene.impl_processMouseEvent(
 138             generator.generateMouseEvent(MouseEvent.MOUSE_RELEASED, xval+20, yval+20));
 139         assertTrue(menu.isShowing());
 140         
 141     }
 142 
 143     @Test public void testSubMenuDismissalWithKeyNavigation() {
 144         final MouseEventGenerator generator = new MouseEventGenerator();
 145         AnchorPane root = new AnchorPane();
 146         Menu menu = new Menu("Menu");
 147         Menu menu1 = new Menu("Menu With SubMenu");
 148         menu.getItems().add(menu1);
 149 
 150         MenuItem menuItem1 = new MenuItem("MenuItem1");
 151         MenuItem menuItem2 = new MenuItem("MenuItem2");
 152         menu1.getItems().addAll(menuItem1, menuItem2);
 153         
 154         menuBar.getMenus().add(menu);
 155         menuBar.setLayoutX(100);
 156         menuBar.setLayoutY(100);
 157 
 158         root.getChildren().add(menuBar);
 159         startApp(root);
 160         tk.firePulse();
 161         
 162         MenuBarSkin skin = (MenuBarSkin)menuBar.getSkin();
 163         assertTrue(skin != null);
 164         
 165         double xval = (menuBar.localToScene(menuBar.getLayoutBounds())).getMinX();
 166         double yval = (menuBar.localToScene(menuBar.getLayoutBounds())).getMinY();
 167    
 168         MenuButton mb = MenuBarMenuButtonRetriever.getNodeForMenu(skin, 0);
 169         mb.getScene().getWindow().requestFocus();
 170         scene.impl_processMouseEvent(
 171             generator.generateMouseEvent(MouseEvent.MOUSE_PRESSED, xval+20, yval+20));
 172         scene.impl_processMouseEvent(
 173             generator.generateMouseEvent(MouseEvent.MOUSE_RELEASED, xval+20, yval+20));
 174         assertTrue(menu.isShowing());
 175          /* ------------------------------------------------------------------ */
 176         
 177         // Show subMenu
 178         ContextMenuContent menuContent = MenuBarMenuButtonRetriever.getMenuContent(mb); // ContextMenuContent
 179         Node displayNode = MenuBarMenuButtonRetriever.getDisplayNodeForMenuItem(menuContent, 0); // MenuItemContainer
 180         
 181         displayNode.getScene().getWindow().requestFocus();
 182         assertTrue(displayNode.getScene().getWindow().isFocused());
 183         
 184         displayNode.requestFocus(); // requestFocus on 1st Menu
 185         assertTrue(displayNode.isFocused());
 186         // update currentFocusedIndex
 187         MenuBarMenuButtonRetriever.setCurrentFocusedIndex(menuContent, 0);
 188         
 189         // fire KeyEvent (Enter) on menu1 to show submenu
 190         KeyEventFirer keyboard = new KeyEventFirer(menuContent);
 191         keyboard.doKeyPress(KeyCode.ENTER);
 192         tk.firePulse();     
 193         assertTrue(menu1.isShowing()); // subMenu is showing
 194         /* ------------------------------------------------------------------ */
 195         
 196         // Get 1st MenuItem from the submenu
 197         ContextMenuContent subMenuContent = MenuBarMenuButtonRetriever.getSubMenuContent(menuContent);
 198         subMenuContent.getScene().getWindow().requestFocus(); // requestFocus on submenu
 199         assertTrue(subMenuContent.getScene().getWindow().isFocused());
 200         
 201         displayNode = MenuBarMenuButtonRetriever.getDisplayNodeForMenuItem(subMenuContent, 0);
 202         displayNode.requestFocus();
 203         assertTrue(displayNode.isFocused());
 204         
 205         MenuBarMenuButtonRetriever.setCurrentFocusedIndex(subMenuContent, 0);
 206         // fire KeyEvent (Enter) on menuItem1 to hide all menus
 207         keyboard = new KeyEventFirer(subMenuContent);
 208         keyboard.doKeyPress(KeyCode.ENTER);
 209         tk.firePulse();
 210         
 211         // confirm all menus are closed. 
 212         assertTrue(!menu1.isShowing());
 213         assertTrue(!menu.isShowing());
 214     }
 215         
 216     @Test public void checkMenuBarMenusSelectionResetAfterMenuItemIsSelected() {
 217         final MouseEventGenerator generator = new MouseEventGenerator();
 218         AnchorPane root = new AnchorPane();
 219         Menu menu = new Menu("Menu");
 220         MenuItem menuItem = new MenuItem("MenuItem");
 221         menu.getItems().add(menuItem);
 222 
 223         menuBar.getMenus().add(menu);
 224         menuBar.setLayoutX(100);
 225         menuBar.setLayoutY(100);
 226 
 227         root.getChildren().addAll(menuBar);
 228         
 229         startApp(root);
 230         tk.firePulse();
 231         
 232         MenuBarSkin skin = (MenuBarSkin)menuBar.getSkin();
 233         assertTrue(skin != null);
 234         MenuButton mb = MenuBarMenuButtonRetriever.getNodeForMenu(skin, 0);
 235         mb.getScene().getWindow().requestFocus();
 236         
 237         double xval = (menuBar.localToScene(menuBar.getLayoutBounds())).getMinX();
 238         double yval = (menuBar.localToScene(menuBar.getLayoutBounds())).getMinY();
 239    
 240         scene.impl_processMouseEvent(
 241             generator.generateMouseEvent(MouseEvent.MOUSE_PRESSED, xval+20, yval+20));
 242         scene.impl_processMouseEvent(
 243             generator.generateMouseEvent(MouseEvent.MOUSE_RELEASED, xval+20, yval+20));
 244         assertTrue(menu.isShowing());
 245          /* ------------------------------------------------------------------ */
 246         
 247         // Show Menu
 248         ContextMenuContent menuContent = MenuBarMenuButtonRetriever.getMenuContent(mb); // ContextMenuContent
 249         Node displayNode = MenuBarMenuButtonRetriever.getDisplayNodeForMenuItem(menuContent, 0); // MenuItemContainer
 250         
 251         displayNode.getScene().getWindow().requestFocus();
 252         assertTrue(displayNode.getScene().getWindow().isFocused());
 253         
 254         displayNode.requestFocus(); // requestFocus on 1st Menu
 255         assertTrue(displayNode.isFocused());
 256         
 257         // fire KeyEvent (Enter) on menuitem 
 258         KeyEventFirer keyboard = new KeyEventFirer(menuContent);
 259         keyboard.doKeyPress(KeyCode.ENTER);
 260         tk.firePulse();     
 261         
 262         // confirm menu is closed. 
 263         assertTrue(!menu.isShowing());
 264         keyboard.doKeyPress(KeyCode.LEFT);
 265         tk.firePulse();
 266         
 267         // check if focusedMenuIndex is reset to -1 so navigation happens.
 268         int focusedIndex = MenuBarMenuButtonRetriever.getFocusedIndex(skin);
 269         assertEquals(focusedIndex, -1);
 270     }
 271     
 272     @Test public void testMenuOnShownEventFiringWithKeyNavigation() {
 273         final MouseEventGenerator generator = new MouseEventGenerator();
 274         VBox root = new VBox();
 275         Menu menu = new Menu("Menu");
 276 
 277         MenuItem menuItem1 = new MenuItem("MenuItem1");
 278         MenuItem menuItem2 = new MenuItem("MenuItem2");
 279         menu.getItems().addAll(menuItem1, menuItem2);
 280         
 281         menuBar.getMenus().add(menu);
 282         menuBar.setLayoutX(100);
 283         menuBar.setLayoutY(100);
 284         
 285         final CheckBox cb = new CheckBox("showing");
 286         
 287         root.getChildren().addAll(cb,menuBar);
 288         startApp(root);
 289         tk.firePulse();
 290         
 291         MenuBarSkin skin = (MenuBarSkin)menuBar.getSkin();
 292         assertTrue(skin != null);
 293         
 294         MenuButton mb = MenuBarMenuButtonRetriever.getNodeForMenu(skin, 0);
 295         mb.getScene().getWindow().requestFocus();
 296         assertTrue(mb.getScene().getWindow().isFocused());
 297         
 298 
 299         KeyEventFirer keyboard = new KeyEventFirer(mb.getScene());
 300         keyboard.doKeyPress(KeyCode.TAB);
 301         tk.firePulse(); 
 302         mb.requestFocus();
 303         assertTrue(mb.isFocused());
 304         
 305         keyboard = new KeyEventFirer(mb);
 306         keyboard.doDownArrowPress();
 307         tk.firePulse();
 308         assertEquals(menu.showingProperty().get(), true);
 309     }
 310     
 311     @Test public void testKeyNavigationWithDisabledMenuItem() {
 312         VBox root = new VBox();
 313         Menu menu1 = new Menu("Menu1");
 314         Menu menu2 = new Menu("Menu2");
 315         Menu menu3 = new Menu("Menu3");
 316         
 317         MenuItem menuItem1 = new MenuItem("MenuItem1");
 318         MenuItem menuItem2 = new MenuItem("MenuItem2");
 319         MenuItem menuItem3 = new MenuItem("MenuItem3");
 320 
 321         menu1.getItems().add(menuItem1);
 322         menu2.getItems().add(menuItem2);
 323         menu3.getItems().add(menuItem3);
 324         
 325         menuBar.getMenus().addAll(menu1, menu2, menu3);
 326         menu2.setDisable(true);
 327         
 328         root.getChildren().addAll(menuBar);
 329         startApp(root);
 330         tk.firePulse();
 331         
 332         MenuBarSkin skin = (MenuBarSkin)menuBar.getSkin();
 333         assertTrue(skin != null);
 334         
 335         double xval = (menuBar.localToScene(menuBar.getLayoutBounds())).getMinX();
 336         double yval = (menuBar.localToScene(menuBar.getLayoutBounds())).getMinY();
 337    
 338         MenuButton mb = MenuBarMenuButtonRetriever.getNodeForMenu(skin, 0);
 339         mb.getScene().getWindow().requestFocus();
 340         scene.impl_processMouseEvent(
 341             MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_PRESSED, xval+20, yval+20));
 342         scene.impl_processMouseEvent(
 343             MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_RELEASED, xval+20, yval+20));
 344         assertTrue(menu1.isShowing());
 345         
 346         KeyEventFirer keyboard = new KeyEventFirer(mb.getScene());
 347         keyboard.doKeyPress(KeyCode.RIGHT);
 348         tk.firePulse(); 
 349         assertTrue(menu3.isShowing());
 350     }
 351     
 352     
 353      @Test public void testMenuOnShowingEventFiringWithMenuHideOperation() {
 354         VBox root = new VBox();
 355         Menu menu = new Menu("Menu");
 356 
 357         MenuItem menuItem1 = new MenuItem("MenuItem1");
 358         menu.getItems().addAll(menuItem1);
 359         
 360         menuBar.getMenus().add(menu);
 361         menuBar.setLayoutX(100);
 362         menuBar.setLayoutY(100);
 363         
 364         root.getChildren().addAll(menuBar);
 365         startApp(root);
 366         tk.firePulse();
 367         
 368         MenuBarSkin skin = (MenuBarSkin)menuBar.getSkin();
 369         assertTrue(skin != null);
 370         double xval = (menuBar.localToScene(menuBar.getLayoutBounds())).getMinX();
 371         double yval = (menuBar.localToScene(menuBar.getLayoutBounds())).getMinY();
 372         
 373         boolean click = true;
 374         final Boolean firstClick = new Boolean(click);
 375         
 376         menu.setOnShowing(t -> {
 377             // we should not get here when the menu is hidden
 378             assertEquals(firstClick.booleanValue(), true);
 379         });
 380         
 381         MenuButton mb = MenuBarMenuButtonRetriever.getNodeForMenu(skin, 0);
 382         mb.getScene().getWindow().requestFocus();
 383         mb.requestFocus();
 384         assertTrue(mb.isFocused());
 385         // click on menu to show 
 386         scene.impl_processMouseEvent(
 387             MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_PRESSED, xval+20, yval+20));
 388         scene.impl_processMouseEvent(
 389             MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_RELEASED, xval+20, yval+20));
 390         tk.firePulse(); 
 391         assertEquals(menu.showingProperty().get(), true);
 392         click = false;
 393         // click on menu to hide
 394         scene.impl_processMouseEvent(
 395             MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_PRESSED, xval+20, yval+20));
 396         scene.impl_processMouseEvent(
 397             MouseEventGenerator.generateMouseEvent(MouseEvent.MOUSE_RELEASED, xval+20, yval+20));
 398         tk.firePulse(); 
 399         assertEquals(menu.showingProperty().get(), false);
 400     }
 401      
 402     @Test public void testRemovingMenuItemFromMenuNotInScene() {
 403         VBox root = new VBox();
 404         Menu menu = new Menu("Menu");
 405 
 406         MenuItem menuItem1 = new MenuItem("MenuItem1");
 407         menu.getItems().addAll(menuItem1);
 408         
 409         menuBar.getMenus().add(menu);
 410         root.getChildren().addAll(menuBar);
 411         startApp(root);
 412         tk.firePulse();
 413         
 414         // remove menu from menubar
 415         menuBar.getMenus().remove(menu);
 416         //remove menuitem from menu that was just removed itself.
 417         menu.getItems().remove(menuItem1);
 418         assertEquals(true, menu.getItems().isEmpty());
 419     }
 420 
 421     @Test public void test_rt_37118() {
 422         MenuBar menuBar = new MenuBar();
 423         MenuBarSkin menuBarSkin = new MenuBarSkin(menuBar);
 424     }
 425 }