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