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 javafx.beans.property.BooleanProperty; 29 import javafx.beans.property.SimpleBooleanProperty; 30 import javafx.event.ActionEvent; 31 import javafx.event.EventHandler; 32 import javafx.scene.Scene; 33 import javafx.scene.input.KeyCode; 34 import javafx.scene.input.MouseButton; 35 import javafx.scene.layout.BackgroundFill; 36 import javafx.scene.layout.HBox; 37 import javafx.scene.layout.Region; 38 import javafx.scene.layout.StackPane; 39 import javafx.scene.paint.LinearGradient; 40 import javafx.scene.paint.Stop; 41 import javafx.scene.shape.Rectangle; 42 import javafx.stage.Stage; 43 import javafx.stage.WindowEvent; 44 import java.util.List; 45 import com.sun.javafx.pgstub.StubToolkit; 46 import com.sun.javafx.scene.control.infrastructure.ContextMenuEventFirer; 47 import com.sun.javafx.scene.control.infrastructure.KeyEventFirer; 48 import com.sun.javafx.scene.control.infrastructure.MouseEventFirer; 49 import com.sun.javafx.tk.Toolkit; 50 import org.junit.Before; 51 import org.junit.After; 52 import org.junit.Ignore; 53 import org.junit.Test; 54 import static com.sun.javafx.scene.control.infrastructure.ControlTestUtils.assertPseudoClassDoesNotExist; 55 import static com.sun.javafx.scene.control.infrastructure.ControlTestUtils.assertPseudoClassExists; 56 import static com.sun.javafx.scene.control.infrastructure.ControlTestUtils.assertStyleClassContains; 57 import static org.junit.Assert.assertEquals; 58 import static org.junit.Assert.assertFalse; 59 import static org.junit.Assert.assertNull; 60 import static org.junit.Assert.assertSame; 61 import static org.junit.Assert.assertTrue; 62 import static org.junit.Assert.fail; 63 64 //import com.sun.javafx.test.MouseEventGenerator; 65 66 /** 67 * action (which can be bound, and can be null), 68 * and that action is called when the button is fired. 69 */ 70 public class ButtonTest { 71 private Button btn; 72 private Toolkit tk; 73 private Scene scene; 74 private Stage stage; 75 private StackPane root; 76 private MouseEventFirer mouse; 77 78 @Before public void setup() { 79 btn = new Button(); 80 tk = (StubToolkit)Toolkit.getToolkit();//This step is not needed (Just to make sure StubToolkit is loaded into VM) 81 root = new StackPane(); 82 scene = new Scene(root); 83 stage = new Stage(); 84 stage.setScene(scene); 85 mouse = new MouseEventFirer(btn); 86 } 87 88 @After public void after() { 89 stage.hide(); 90 mouse.dispose(); 91 } 92 93 /********************************************************************* 94 * Helper methods * 95 ********************************************************************/ 96 private void show() { 97 stage.show(); 98 } 99 100 /********************************************************************* 101 * Tests for the constructors * 102 ********************************************************************/ 103 104 @Test public void defaultConstructorShouldHaveNoGraphicAndEmptyString() { 105 assertNull(btn.getGraphic()); 106 assertEquals("", btn.getText()); 107 } 108 109 @Test public void oneArgConstructorShouldHaveNoGraphicAndSpecifiedString() { 110 Button b2 = new Button(null); 111 assertNull(b2.getGraphic()); 112 assertNull(b2.getText()); 113 114 b2 = new Button(""); 115 assertNull(b2.getGraphic()); 116 assertEquals("", b2.getText()); 117 118 b2 = new Button("Hello"); 119 assertNull(b2.getGraphic()); 120 assertEquals("Hello", b2.getText()); 121 } 122 123 @Test public void twoArgConstructorShouldHaveSpecifiedGraphicAndSpecifiedString() { 124 Button b2 = new Button(null, null); 125 assertNull(b2.getGraphic()); 126 assertNull(b2.getText()); 127 128 Rectangle rect = new Rectangle(); 129 b2 = new Button("Hello", rect); 130 assertSame(rect, b2.getGraphic()); 131 assertEquals("Hello", b2.getText()); 132 } 133 134 @Test public void defaultConstructorShouldSetStyleClassTo_button() { 135 assertStyleClassContains(btn, "button"); 136 } 137 138 @Test public void oneArgConstructorShouldSetStyleClassTo_button() { 139 Button b2 = new Button(null); 140 assertStyleClassContains(b2, "button"); 141 } 142 143 @Test public void twoArgConstructorShouldSetStyleClassTo_button() { 144 Button b2 = new Button(null, null); 145 assertStyleClassContains(b2, "button"); 146 } 147 148 /********************************************************************* 149 * Tests for the defaultButton state * 150 ********************************************************************/ 151 152 @Test public void defaultButtonIsFalseByDefault() { 153 assertFalse(btn.isDefaultButton()); 154 assertFalse(btn.defaultButtonProperty().getValue()); 155 } 156 157 @Test public void defaultButtonCanBeSet() { 158 btn.setDefaultButton(true); 159 assertTrue(btn.isDefaultButton()); 160 } 161 162 @Test public void defaultButtonSetToNonDefaultValueIsReflectedInModel() { 163 btn.setDefaultButton(true); 164 assertTrue(btn.defaultButtonProperty().getValue()); 165 } 166 167 @Test public void defaultButtonCanBeCleared() { 168 btn.setDefaultButton(true); 169 btn.setDefaultButton(false); 170 assertFalse(btn.isDefaultButton()); 171 } 172 173 @Test public void defaultButtonCanBeBound() { 174 BooleanProperty other = new SimpleBooleanProperty(true); 175 btn.defaultButtonProperty().bind(other); 176 assertTrue(btn.isDefaultButton()); 177 } 178 179 @Test public void settingDefaultButtonSetsPseudoClass() { 180 btn.setDefaultButton(true); 181 assertPseudoClassExists(btn, "default"); 182 } 183 184 @Test public void clearingDefaultButtonClearsPseudoClass() { 185 btn.setDefaultButton(true); 186 btn.setDefaultButton(false); 187 assertPseudoClassDoesNotExist(btn, "default"); 188 } 189 190 @Test public void defaultButtonSetToTrueViaBindingSetsPseudoClass() { 191 BooleanProperty other = new SimpleBooleanProperty(true); 192 btn.defaultButtonProperty().bind(other); 193 assertPseudoClassExists(btn, "default"); 194 } 195 196 @Test public void defaultButtonSetToFalseViaBindingClearsPseudoClass() { 197 BooleanProperty other = new SimpleBooleanProperty(true); 198 btn.defaultButtonProperty().bind(other); 199 other.setValue(false); 200 assertPseudoClassDoesNotExist(btn, "default"); 201 } 202 203 @Ignore("impl_cssSet API removed") 204 @Test public void cannotSpecifyDefaultButtonViaCSS() { 205 // btn.impl_cssSet("-fx-default-button", true); 206 assertFalse(btn.isDefaultButton()); 207 } 208 209 @Test public void defaultButtonPropertyHasBeanReference() { 210 assertSame(btn, btn.defaultButtonProperty().getBean()); 211 } 212 213 @Test public void defaultButtonPropertyHasName() { 214 assertEquals("defaultButton", btn.defaultButtonProperty().getName()); 215 } 216 217 @Test public void disabledDefaultButtonCannotGetInvoked_RT20929() { 218 root.getChildren().add(btn); 219 220 btn.setOnAction(actionEvent -> { 221 fail(); 222 }); 223 224 btn.setDefaultButton(true); 225 btn.setDisable(true); 226 show(); 227 228 KeyEventFirer keyboard = new KeyEventFirer(btn); 229 keyboard.doKeyPress(KeyCode.ENTER); 230 231 tk.firePulse(); 232 } 233 234 @Test public void defaultButtonCanBeInvokeAfterRemovingFromTheScene_RT22106() { 235 btn.setDefaultButton(true); 236 btn.setOnAction(actionEvent -> { 237 fail(); 238 }); 239 root.getChildren().add(btn); 240 show(); 241 242 root.getChildren().remove(btn); 243 244 KeyEventFirer keyboard = new KeyEventFirer(root); 245 keyboard.doKeyPress(KeyCode.ENTER); 246 247 tk.firePulse(); 248 } 249 250 /********************************************************************* 251 * Tests for the cancelButton state * 252 ********************************************************************/ 253 254 @Test public void cancelButtonIsFalseByDefault() { 255 assertFalse(btn.isCancelButton()); 256 assertFalse(btn.cancelButtonProperty().getValue()); 257 } 258 259 @Test public void cancelButtonCanBeSet() { 260 btn.setCancelButton(true); 261 assertTrue(btn.isCancelButton()); 262 } 263 264 @Test public void cancelButtonSetToNonDefaultValueIsReflectedInModel() { 265 btn.setCancelButton(true); 266 assertTrue(btn.cancelButtonProperty().getValue()); 267 } 268 269 @Test public void cancelButtonCanBeCleared() { 270 btn.setCancelButton(true); 271 btn.setCancelButton(false); 272 assertFalse(btn.isCancelButton()); 273 } 274 275 @Test public void cancelButtonCanBeBound() { 276 BooleanProperty other = new SimpleBooleanProperty(true); 277 btn.cancelButtonProperty().bind(other); 278 assertTrue(btn.isCancelButton()); 279 } 280 281 @Test public void settingCancelButtonSetsPseudoClass() { 282 btn.setCancelButton(true); 283 assertPseudoClassExists(btn, "cancel"); 284 } 285 286 @Test public void clearingCancelButtonClearsPseudoClass() { 287 btn.setCancelButton(true); 288 btn.setCancelButton(false); 289 assertPseudoClassDoesNotExist(btn, "cancel"); 290 } 291 292 @Test public void cancelButtonSetToTrueViaBindingSetsPseudoClass() { 293 BooleanProperty other = new SimpleBooleanProperty(true); 294 btn.cancelButtonProperty().bind(other); 295 assertPseudoClassExists(btn, "cancel"); 296 } 297 298 @Test public void cancelButtonSetToFalseViaBindingClearsPseudoClass() { 299 BooleanProperty other = new SimpleBooleanProperty(true); 300 btn.cancelButtonProperty().bind(other); 301 other.setValue(false); 302 assertPseudoClassDoesNotExist(btn, "cancel"); 303 } 304 305 @Ignore("impl_cssSet API removed") 306 @Test public void cannotSpecifyCancelButtonViaCSS() { 307 // btn.impl_cssSet("-fx-cancel-button", true); 308 assertFalse(btn.isCancelButton()); 309 } 310 311 @Test public void cancelButtonPropertyHasBeanReference() { 312 assertSame(btn, btn.cancelButtonProperty().getBean()); 313 } 314 315 @Test public void cancelButtonPropertyHasName() { 316 assertEquals("cancelButton", btn.cancelButtonProperty().getName()); 317 } 318 319 @Test public void cancelButtonCanBeInvokeAfterRemovingFromTheScene_RT22106() { 320 btn.setCancelButton(true); 321 btn.setOnAction(actionEvent -> { 322 fail(); 323 }); 324 root.getChildren().add(btn); 325 show(); 326 327 root.getChildren().remove(btn); 328 329 KeyEventFirer keyboard = new KeyEventFirer(root); 330 keyboard.doKeyPress(KeyCode.ESCAPE); 331 332 tk.firePulse(); 333 } 334 335 336 @Test public void conextMenuShouldntShowOnAction() { 337 ContextMenu popupMenu = new ContextMenu(); 338 MenuItem item1 = new MenuItem("_About"); 339 popupMenu.getItems().add(item1); 340 popupMenu.setOnShown(w -> { 341 fail(); 342 }); 343 344 btn.setContextMenu(popupMenu); 345 btn.setDefaultButton(true); 346 347 root.getChildren().add(btn); 348 show(); 349 350 // None of these should cause the context menu to appear, 351 // so fire them all, and see if anything happens. 352 KeyEventFirer keyboard = new KeyEventFirer(btn); 353 keyboard.doKeyPress(KeyCode.ENTER); 354 355 btn.fireEvent(new ActionEvent()); 356 btn.fire(); 357 358 mouse.fireMousePressed(); 359 mouse.fireMouseReleased(); 360 mouse.fireMouseClicked(); 361 } 362 363 private int count = 0; 364 @Test public void contextMenuShouldShowOnInSomeCircumstances() { 365 ContextMenu popupMenu = new ContextMenu(); 366 MenuItem item1 = new MenuItem("_About"); 367 popupMenu.getItems().add(item1); 368 popupMenu.setOnShown(w -> { 369 System.out.println("popup shown"); 370 count++; 371 }); 372 373 btn.setContextMenu(popupMenu); 374 btn.setDefaultButton(true); 375 376 root.getChildren().add(btn); 377 show(); 378 379 btn.setOnAction(event -> { 380 fail(); 381 }); 382 383 assertEquals(0, count); 384 385 /* Note that right-mouse press events don't force the popup open */ 386 mouse.fireMousePressed(MouseButton.SECONDARY); 387 assertEquals(0, count); 388 389 mouse.fireMouseClicked(MouseButton.SECONDARY); 390 assertEquals(0, count); 391 392 mouse.fireMouseReleased(MouseButton.SECONDARY); 393 assertEquals(0, count); 394 395 /* Only context menu events force it to appear */ 396 ContextMenuEventFirer.fireContextMenuEvent(btn); 397 assertEquals(1, count); 398 } 399 400 static class MyButton extends Button { 401 MyButton(String text) { 402 super(text); 403 } 404 405 void setHoverPseudoclassState(boolean b) { 406 setHover(b); 407 } 408 } 409 410 List<Stop> getStops(Button button) { 411 Skin skin = button.getSkin(); 412 Region region = (Region)skin.getNode(); 413 List<BackgroundFill> fills = region.getBackground().getFills(); 414 BackgroundFill top = fills.get(fills.size()-1); 415 LinearGradient topFill = (LinearGradient)top.getFill(); 416 return topFill.getStops(); 417 } 418 419 @Test 420 public void testRT_23207() { 421 422 HBox hBox = new HBox(); 423 hBox.setSpacing(5); 424 hBox.setTranslateY(30); 425 MyButton red = new MyButton("Red"); 426 red.setStyle("-fx-base: red;"); 427 MyButton green = new MyButton("Green"); 428 green.setStyle("-fx-base: green;"); 429 hBox.getChildren().add(red); 430 hBox.getChildren().add(green); 431 432 Scene scene = new Scene(hBox, 500, 300); 433 Stage stage = new Stage(); 434 stage.setScene(scene); 435 stage.show(); 436 437 Toolkit.getToolkit().firePulse(); 438 439 List<Stop> redStops0 = getStops(red); 440 List<Stop> greenStops0 = getStops(green); 441 442 red.setHoverPseudoclassState(true); 443 444 Toolkit.getToolkit().firePulse(); 445 446 List<Stop> redStops1 = getStops(red); 447 List<Stop> greenStops1 = getStops(green); 448 449 red.setHoverPseudoclassState(false); 450 green.setHoverPseudoclassState(true); 451 452 Toolkit.getToolkit().firePulse(); 453 454 List<Stop> redStops2 = getStops(red); 455 List<Stop> greenStops2 = getStops(green); 456 457 green.setHoverPseudoclassState(false); 458 459 Toolkit.getToolkit().firePulse(); 460 461 List<Stop> redStops3 = getStops(red); 462 List<Stop> greenStops3 = getStops(green); 463 464 // did red change color after red hover=true? 465 assertFalse(redStops0.equals(redStops1)); 466 // did red change back to original color after green hover=true? 467 assertTrue(redStops0.equals(redStops2)); 468 // did red stay original color after green hover=false? 469 assertTrue(redStops0.equals(redStops3)); 470 // did green stay green after red hover=true? 471 assertTrue(greenStops0.equals(greenStops1)); 472 // did green change after green hover=true? 473 assertFalse(greenStops0.equals(greenStops2)); 474 // did green revert to original after green hover=false? 475 // This is the acid test. If this fails, then RT-23207 is present. 476 assertTrue(greenStops0.equals(greenStops3)); 477 478 } 479 480 481 // private Button button1; 482 // private Button button2; 483 // 484 // @Override protected Node createNodeToTest() { 485 // button1 = createButton("Button1"); 486 // button2 = createButton("Button2"); 487 // button2.setLayoutX(0); 488 // button2.setLayoutY(110); 489 // Group group = new Group(); 490 // group.getChildren().addAll(button1, button2); 491 // group.setAutoSizeChildren(false); 492 // return group; 493 // } 494 // 495 // private static Button createButton(String text) { 496 // Button button = new Button(text); 497 // button.resize(100, 100); 498 // return button; 499 // } 500 // 501 // @Test public void pressEventsShouldLeadToFocusGained() { 502 // mouse().positionAtCenterOf(button2); 503 // mouse().leftPress(); 504 // assertTrue(button2.isFocused()); 505 // } 506 // 507 // @Test public void pressEventsShouldLeadToFocusGained_efficiently() { 508 // executeInUIThread(new Runnable() { 509 // @Override public void run() { 510 // mouse().positionAtCenterOf(button2); 511 // mouse().leftPress(); 512 // } 513 // }); 514 // assertTrue(button2.isFocused()); 515 // } 516 }