1 /*
   2  * Copyright (c) 2011, 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.skin;
  27 
  28 import static org.junit.Assert.assertEquals;
  29 
  30 import com.sun.javafx.menu.MenuBase;
  31 import com.sun.javafx.pgstub.StubToolkit;
  32 import com.sun.javafx.tk.Toolkit;
  33 import javafx.beans.value.ObservableValue;
  34 import javafx.geometry.Insets;
  35 import javafx.scene.Group;
  36 import javafx.scene.Scene;
  37 import javafx.scene.control.Menu;
  38 import javafx.scene.control.MenuBar;
  39 import javafx.scene.control.skin.MenuBarSkin;
  40 import javafx.stage.Stage;
  41 
  42 import java.util.List;
  43 
  44 import org.junit.Before;
  45 import org.junit.BeforeClass;
  46 import org.junit.Test;
  47 
  48 /**
  49  * This fails with IllegalStateException because of the toolkit's check for the FX application thread
  50  */
  51 public class MenuBarSkinTest {
  52     private MenuBar menubar;
  53     private MenuBarSkinMock skin;
  54     private static Toolkit tk;
  55     private Scene scene;
  56     private Stage stage;
  57 
  58 
  59     @BeforeClass public static void initToolKit() {
  60         tk = Toolkit.getToolkit();
  61     }
  62 
  63     @Before public void setup() {
  64         menubar = new MenuBar();
  65         menubar.setUseSystemMenuBar(false);
  66         menubar.getMenus().addAll(new Menu("File"), new Menu("Edit"));
  67 
  68         // Pending RT-37118, MenuBar needs to be in a scene in order to set the skin.
  69         scene = new Scene(new Group(menubar));
  70         skin = new MenuBarSkinMock(menubar);
  71         menubar.setSkin(skin);
  72 
  73         // Set some padding so that any places where padding was being
  74         // computed but wasn't expected will be caught.
  75         menubar.setPadding(new Insets(10, 10, 10, 10));
  76 
  77         stage = new Stage();
  78 
  79         // MenuBar needs to have a stage in order for system menus to work
  80         stage.setScene(scene);
  81 
  82         // Stage has to be focused in order for system menus to work
  83         stage.setFocused(true);
  84     }
  85     
  86     @Test public void maxHeightTracksPreferred() {
  87         menubar.setPrefHeight(100);
  88         assertEquals(100, menubar.maxHeight(-1), 0);
  89     }
  90 
  91     @Test public void testDispose() {
  92 
  93         if (tk.getSystemMenu().isSupported()) {
  94             // setting system menu bar true should create a sceneProperty listener for RT-36554
  95             menubar.setUseSystemMenuBar(true);
  96             assertEquals(menubar.getMenus().size(), getSystemMenus().size());
  97         }
  98 
  99         // This will cause the dispose method to be called.
 100         menubar.setSkin(null);
 101 
 102         if (tk.getSystemMenu().isSupported()) {
 103 
 104             // dispose should clean up the system menu.
 105             assertEquals(0, getSystemMenus().size());
 106 
 107         }
 108 
 109     }
 110 
 111     @Test public void testSetUseSystemMenuBar() {
 112         if (tk.getSystemMenu().isSupported()) {
 113             menubar.setUseSystemMenuBar(true);
 114             assertEquals(menubar.getMenus().size(), getSystemMenus().size());
 115 
 116             menubar.setUseSystemMenuBar(false);
 117             assertEquals(0, getSystemMenus().size());
 118 
 119             menubar.setUseSystemMenuBar(true);
 120             assertEquals(menubar.getMenus().size(), getSystemMenus().size());
 121         }
 122     }
 123 
 124     @Test public void testSystemMenuBarUpdatesWhenMenusChange() {
 125 
 126         if (tk.getSystemMenu().isSupported()) {
 127             menubar.setUseSystemMenuBar(true);
 128             assertEquals(menubar.getMenus().size(), getSystemMenus().size());
 129 
 130             menubar.getMenus().add(new Menu("testSystemMenuBarUpdatesWhenMenusChange"));
 131             assertEquals(menubar.getMenus().size(), getSystemMenus().size());
 132         }
 133     }
 134 
 135     @Test public void testRT_36554() {
 136 
 137         if (tk.getSystemMenu().isSupported()) {
 138 
 139             menubar.setUseSystemMenuBar(true);
 140             assertEquals(menubar.getMenus().size(), getSystemMenus().size());
 141 
 142             // removing the menubar from the scene should remove the system menus.
 143             ((Group)scene.getRoot()).getChildren().remove(menubar);
 144             assertEquals(0, getSystemMenus().size());
 145 
 146             // adding the menubar from the scene should add back the system menus.
 147             ((Group)scene.getRoot()).getChildren().add(menubar);
 148             assertEquals(menubar.getMenus().size(), getSystemMenus().size());
 149 
 150             // remove, then set useSystemMenuBar to false. Upon re-adding,
 151             // there should still be no system menu.
 152             ((Group)scene.getRoot()).getChildren().remove(menubar);
 153             assertEquals(0, getSystemMenus().size());
 154 
 155             menubar.setUseSystemMenuBar(false);
 156             ((Group)scene.getRoot()).getChildren().add(menubar);
 157             assertEquals(0, getSystemMenus().size());
 158 
 159             // setting useSystemMenuBar to true again, should add back the system menus.
 160             menubar.setUseSystemMenuBar(true);
 161             assertEquals(menubar.getMenus().size(), getSystemMenus().size());
 162         }
 163     }
 164 
 165     public static final class MenuBarSkinMock extends MenuBarSkin {
 166         boolean propertyChanged = false;
 167         int propertyChangeCount = 0;
 168         public MenuBarSkinMock(MenuBar menubar) {
 169             super(menubar);
 170         }
 171 
 172         public void addWatchedProperty(ObservableValue<?> p) {
 173             p.addListener(o -> {
 174                 propertyChanged = true;
 175                 propertyChangeCount++;
 176             });
 177         }
 178     }
 179 
 180     private List<MenuBase> getSystemMenus() {
 181         return ((StubToolkit.StubSystemMenu)tk.getSystemMenu()).getMenus();
 182     }
 183 
 184 }