1 /* 2 * Copyright (c) 2018, 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 package test.robot.javafx.scene; 26 27 import com.sun.glass.ui.Robot; 28 import javafx.application.Application; 29 import javafx.application.Platform; 30 import javafx.scene.Scene; 31 import javafx.scene.control.ContextMenu; 32 import javafx.scene.control.MenuItem; 33 import javafx.scene.control.Tab; 34 import javafx.scene.control.TabPane; 35 import javafx.stage.Stage; 36 import javafx.stage.StageStyle; 37 import javafx.stage.WindowEvent; 38 39 import java.util.concurrent.CountDownLatch; 40 import java.util.concurrent.TimeUnit; 41 42 import org.junit.AfterClass; 43 import org.junit.Assert; 44 import org.junit.BeforeClass; 45 import org.junit.Test; 46 import static org.junit.Assert.fail; 47 48 public class TabContextMenuCloseButtonTest { 49 50 static CountDownLatch startupLatch = new CountDownLatch(1); 51 static CountDownLatch cmlatch; 52 static Robot robot; 53 static TabPane tabPane; 54 static volatile Stage stage; 55 static volatile Scene scene; 56 static ContextMenu cMenu; 57 static boolean cmShown = false; 58 static final int SCENE_WIDTH = 250; 59 static final int SCENE_HEIGHT = SCENE_WIDTH; 60 final int DX = 17; 61 final int DY = DX; 62 63 // Test close button with three mouse buttons. 64 // Pressing left & middle button closes the tab. 65 // Pressing right button does not close the tab. 66 @Test 67 public void testCloseButton() { 68 int mouseButtons[] = { Robot.MOUSE_MIDDLE_BTN, Robot.MOUSE_RIGHT_BTN, Robot.MOUSE_LEFT_BTN }; 69 int expectedTabCount[] = {2, 2, 1}; 70 try { 71 Thread.sleep(1000); // Wait for tabPane to layout 72 } catch (Exception ex) { 73 System.out.println("Thread was interrupted." + ex); 74 } 75 for (int i = 0; i < mouseButtons.length; ++i) { 76 final int ic = i; 77 CountDownLatch pressLatch = new CountDownLatch(1); 78 Platform.runLater(() -> { 79 if (cMenu.isShowing()) { 80 cMenu.hide(); 81 } 82 robot.mouseMove((int) (scene.getWindow().getX() + scene.getX() + DX), 83 (int) (scene.getWindow().getY() + scene.getY() + DY)); 84 robot.mousePress(mouseButtons[ic]); 85 robot.mouseRelease(mouseButtons[ic]); 86 pressLatch.countDown(); 87 }); 88 waitForLatch(pressLatch, 5, "Timeout waiting for Robot.Button." + mouseButtons[i]); 89 try { 90 Thread.sleep(500); // Wait for tabPane to layout 91 } catch (Exception ex) { 92 System.out.println("Thread was interrupted." + ex); 93 } 94 Assert.assertEquals(expectedTabCount[i], tabPane.getTabs().size()); 95 } 96 } 97 98 // Test that pressing right mouse button shows context menu. 99 @Test 100 public void testContextMenu() { 101 try { 102 Thread.sleep(1000); // Wait for tabPane to layout 103 } catch (Exception ex) { 104 System.out.println("Thread was interrupted." + ex); 105 } 106 cmShown = false; 107 CountDownLatch pressLatch = new CountDownLatch(1); 108 cmlatch = new CountDownLatch(1); 109 cMenu.setOnShown(event -> { 110 cmShown = true; 111 cmlatch.countDown(); 112 }); 113 Platform.runLater(() -> { 114 if (cMenu.isShowing()) { 115 cMenu.hide(); 116 } 117 robot.mouseMove((int)(scene.getWindow().getX() + scene.getX() + DX), 118 (int)(scene.getWindow().getY() + scene.getY() + DY)); 119 robot.mousePress(Robot.MOUSE_RIGHT_BTN); 120 robot.mouseRelease(Robot.MOUSE_RIGHT_BTN); 121 pressLatch.countDown(); 122 }); 123 waitForLatch(pressLatch, 5, "Timeout waiting for Robot.MOUSE_RIGHT_BTN."); 124 waitForLatch(cmlatch, 5, "Timeout waiting for ContextMenu to be shown."); 125 Assert.assertTrue("Tab's ContextMenu not shown.", cmShown); 126 } 127 128 public static void setupUI() { 129 CountDownLatch latch = new CountDownLatch(1); 130 Platform.runLater(() -> { 131 cMenu = new ContextMenu(new MenuItem("hello"), new MenuItem("goodbye")); 132 133 for (int i = 0; i < 3; ++i) { 134 Tab tab = new Tab(""); 135 tab.setContextMenu(cMenu); 136 tabPane.getTabs().add(tab); 137 } 138 latch.countDown(); 139 }); 140 waitForLatch(latch, 5, "Timeout waiting for setupTest()."); 141 } 142 143 @BeforeClass 144 public static void initFX() { 145 startupLatch = new CountDownLatch(1); 146 new Thread(() -> Application.launch(TestApp.class, (String[])null)).start(); 147 waitForLatch(startupLatch, 10, "Timeout waiting for FX runtime to start"); 148 setupUI(); 149 } 150 151 @AfterClass 152 public static void exit() { 153 Platform.runLater(() -> { 154 tabPane.getTabs().removeAll(); 155 stage.hide(); 156 }); 157 Platform.exit(); 158 } 159 160 public static class TestApp extends Application { 161 @Override 162 public void start(Stage primaryStage) { 163 robot = com.sun.glass.ui.Application.GetApplication().createRobot(); 164 stage = primaryStage; 165 tabPane = new TabPane(); 166 tabPane.setTabDragPolicy(TabPane.TabDragPolicy.REORDER); 167 tabPane.setTabClosingPolicy(TabPane.TabClosingPolicy.ALL_TABS); 168 scene = new Scene(tabPane, SCENE_WIDTH, SCENE_HEIGHT); 169 stage.setScene(scene); 170 stage.initStyle(StageStyle.UNDECORATED); 171 stage.addEventHandler(WindowEvent.WINDOW_SHOWN, e -> 172 Platform.runLater(startupLatch::countDown)); 173 stage.setAlwaysOnTop(true); 174 stage.show(); 175 } 176 } 177 178 public static void waitForLatch(CountDownLatch latch, int seconds, String msg) { 179 try { 180 if (!latch.await(seconds, TimeUnit.SECONDS)) { 181 fail(msg); 182 } 183 } catch (Exception ex) { 184 fail("Unexpected exception: " + ex); 185 } 186 } 187 }