1 /* 2 * Copyright (c) 2010, 2013, 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; 27 28 import com.sun.javafx.geom.BoxBounds; 29 import com.sun.javafx.geom.PickRay; 30 import com.sun.javafx.geom.transform.Affine2D; 31 import com.sun.javafx.geom.transform.Affine3D; 32 import com.sun.javafx.geom.transform.BaseTransform; 33 import com.sun.javafx.geom.transform.Translate2D; 34 import com.sun.javafx.pgstub.StubStage; 35 import com.sun.javafx.pgstub.StubToolkit; 36 import com.sun.javafx.scene.DirtyBits; 37 import com.sun.javafx.scene.input.PickResultChooser; 38 import com.sun.javafx.sg.prism.NGGroup; 39 import com.sun.javafx.sg.prism.NGNode; 40 import com.sun.javafx.sg.prism.NGRectangle; 41 import com.sun.javafx.test.objects.TestScene; 42 import com.sun.javafx.test.objects.TestStage; 43 import com.sun.javafx.tk.Toolkit; 44 import javafx.beans.property.*; 45 import javafx.geometry.BoundingBox; 46 import javafx.geometry.Bounds; 47 import javafx.geometry.NodeOrientation; 48 import javafx.geometry.Point2D; 49 import javafx.geometry.Point3D; 50 import javafx.scene.effect.DropShadow; 51 import javafx.scene.effect.Effect; 52 import javafx.scene.shape.*; 53 import javafx.scene.transform.Rotate; 54 import javafx.scene.transform.Transform; 55 import org.junit.Rule; 56 import org.junit.Test; 57 import org.junit.rules.ExpectedException; 58 59 import java.lang.reflect.Method; 60 import java.util.Comparator; 61 import javafx.scene.layout.AnchorPane; 62 import javafx.scene.transform.Affine; 63 import javafx.scene.transform.Scale; 64 import javafx.scene.transform.Shear; 65 import javafx.scene.transform.Translate; 66 import javafx.stage.Stage; 67 68 import static org.junit.Assert.*; 69 import org.junit.Ignore; 70 /** 71 * Tests various aspects of Node. 72 * 73 */ 74 public class NodeTest { 75 @Rule 76 public ExpectedException thrown = ExpectedException.none(); 77 78 // Things to test: 79 // When parent is changed, should cursor on toolkit change as well if 80 // the current node has the mouse over it and didn't explicitly set a 81 // cursor?? 82 83 // Test CSS integration 84 85 // Events: 86 // Events should *not* be delivered to invisible nodes as per the 87 // specification for visible 88 89 // A Node must lose focus when it is no longer visible 90 91 // A node made invisible must cause the cursor to be updated 92 93 // Setting the cursor should override the parent cursor when hover 94 // (test that this happens both when the node already has hover set and 95 // when hover is changed to true) 96 97 // Setting the cursor to null should revert to parent cursor when hover 98 // (test that this happens both when the node already has hover set and 99 // when hover is changed to true) 100 101 // Clip: 102 // Test setting/clearing the clip affects the bounds 103 // Test changing bounds / smooth / etc on clip updates bounds of clipped Node 104 105 // Effect: 106 // Test setting/clearing the effect affects the bounds 107 // Test changing state on Effect updates bounds of Node 108 109 // Test that a disabled Group affects the disabled property of child nodes 110 111 // Test contains, intersects methods 112 // Test parentToLocal/localToStage/etc 113 114 // Test computeCompleteBounds 115 // (other bounds test situtations explicitly tested in BoundsTest) 116 117 // Test transforms end up setting the correct matrix on the peer 118 // In particular, test that pivots are taken correctly into account 119 120 // Test hover is updated when mouse enters 121 // Test hover is updated when mouse exists 122 // Test hover is updated when mouse was over but a higher node then 123 // turns on blocks mouse 124 // Test hover is updated when node moves out from under the cursor 125 // TODO most of these cases cannot be handled until/unless we update 126 // the list of nodes under the cursor on pulse events 127 128 // Test pressed is updated when mouse is pressed 129 // Test pressed is updated when mouse is released 130 // TODO shoudl pressed obey the semantics of a button that is armed & pressed? 131 // Or should "armed" be put on Node? What to do here? 132 133 // Test various onMouseXXX event handlers 134 135 // Test onKeyXXX handlers 136 137 // Test focused is updated? 138 // Test nodes which are not focusable are not focused! 139 // Test focus... (SHOULD NOT DEPEND ON KEY LISTENERS BEING INSTALLED!!) 140 141 // Test that clip is taken into account for both "contains" and 142 // "intersects". See http://javafx-jira.kenai.com/browse/RT-646 143 144 145 146 /*************************************************************************** 147 * * 148 * Basic Node Tests * 149 * * 150 **************************************************************************/ 151 152 // TODO disable this because it depends on TestNode 153 // @Test public void testPeerNotifiedOfVisibilityChanges() { 154 // Rectangle rect = new Rectangle(); 155 // Node peer = rect.impl_getPGNode(); 156 // assertEquals(peer.visible, rect.visible); 157 // 158 // rect.visible = false; 159 // assertEquals(peer.visible, rect.visible); 160 // 161 // rect.visible = true; 162 // assertEquals(peer.visible, rect.visible); 163 // } 164 165 /*************************************************************************** 166 * * 167 * Testing Node Bounds * 168 * * 169 **************************************************************************/ 170 171 // TODO disable this because it depends on TestNode 172 // public function testContainsCallsPeer():Void { 173 // var rect = Rectangle { }; 174 // var peer = rect.impl_getPGNode() as TestNode; 175 // peer.numTimesContainsCalled = 0; 176 // 177 // rect.contains(0, 0); 178 // assertEquals(1, peer.numTimesContainsCalled); 179 // 180 // rect.contains(Point2D { x:10, y:10 }); 181 // assertEquals(2, peer.numTimesContainsCalled); 182 // } 183 184 // TODO disable this because it depends on TestNode 185 // public function testIntersectsCallsPeer():Void { 186 // var rect = Rectangle { }; 187 // var peer = rect.impl_getPGNode() as TestNode; 188 // peer.numTimesIntersectsCalled = 0; 189 // 190 // rect.intersects(0, 0, 10, 10); 191 // assertEquals(1, peer.numTimesIntersectsCalled); 192 // 193 // rect.intersects(BoundingBox { minX:10, minY:10, width:100, height:100 }); 194 // assertEquals(2, peer.numTimesIntersectsCalled); 195 // } 196 197 /*************************************************************************** 198 * * 199 * Testing Node transforms * 200 * * 201 **************************************************************************/ 202 203 /** 204 * Tests that the function which converts a com.sun.javafx.geom.Point2D 205 * in parent coords to local coords works properly. 206 */ 207 @Test public void testParentToLocalGeomPoint() { 208 Rectangle rect = new Rectangle(); 209 rect.setTranslateX(10); 210 rect.setTranslateY(10); 211 rect.setWidth(100); 212 rect.setHeight(100); 213 rect.getTransforms().clear(); 214 rect.getTransforms().addAll(Transform.scale(2, 2), Transform.translate(30, 30)); 215 216 Point2D pt = new Point2D(0, 0); 217 pt = rect.parentToLocal(pt); 218 assertEquals(new Point2D(-35, -35), pt); 219 } 220 221 // TODO need to test with some observableArrayList of transforms which cannot be 222 // cleanly inverted so that we can test that code path 223 224 @Test public void testLocalToParentGeomPoint() { 225 Rectangle rect = new Rectangle(); 226 rect.setTranslateX(10); 227 rect.setTranslateY(10); 228 rect.setWidth(100); 229 rect.setHeight(100); 230 rect.getTransforms().clear(); 231 rect.getTransforms().addAll(Transform.scale(2, 2), Transform.translate(30, 30)); 232 233 Point2D pt = new Point2D(0, 0); 234 pt = rect.localToParent(pt); 235 assertEquals(new Point2D(70, 70), pt); 236 } 237 238 @Test public void testPickingNodeDirectlyNoTransforms() { 239 Rectangle rect = new Rectangle(); 240 rect.setX(10); 241 rect.setY(10); 242 rect.setWidth(100); 243 rect.setHeight(100); 244 245 // needed since picking doesn't work unless rooted in a scene and visible 246 Scene scene = new Scene(new Group()); 247 scene.getRoot().getChildren().add(rect); 248 249 PickResultChooser res = new PickResultChooser(); 250 rect.impl_pickNode(new PickRay(50, 50, 1, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY), res); 251 assertSame(rect, res.getIntersectedNode()); 252 res = new PickResultChooser(); 253 rect.impl_pickNode(new PickRay(0, 0, 1, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY), res); 254 assertNull(res.getIntersectedNode()); 255 } 256 257 @Test public void testPickingNodeDirectlyWithTransforms() { 258 Rectangle rect = new Rectangle(); 259 rect.setTranslateX(10); 260 rect.setTranslateY(10); 261 rect.setWidth(100); 262 rect.setHeight(100); 263 264 // needed since picking doesn't work unless rooted in a scene and visible 265 Scene scene = new Scene(new Group()); 266 scene.getRoot().getChildren().add(rect); 267 268 PickResultChooser res = new PickResultChooser(); 269 rect.impl_pickNode(new PickRay(50, 50, 1, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY), res); 270 assertSame(rect, res.getIntersectedNode()); 271 res = new PickResultChooser(); 272 rect.impl_pickNode(new PickRay(0, 0, 1, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY), res); 273 assertNull(res.getIntersectedNode()); 274 } 275 276 @Test public void testEffectSharedOnNodes() { 277 Effect effect = new DropShadow(); 278 Rectangle node = new Rectangle(); 279 node.setEffect(effect); 280 281 Rectangle node2 = new Rectangle(); 282 node2.setEffect(effect); 283 284 assertEquals(effect, node.getEffect()); 285 assertEquals(effect, node2.getEffect()); 286 } 287 288 public static void testBooleanPropertyPropagation( 289 final Node node, 290 final String propertyName, 291 final boolean initialValue, 292 final boolean newValue) throws Exception { 293 294 final StringBuilder propertyNameBuilder = new StringBuilder(propertyName); 295 propertyNameBuilder.setCharAt(0, Character.toUpperCase(propertyName.charAt(0))); 296 final String setterName = new StringBuilder("set").append(propertyNameBuilder).toString(); 297 final String getterName = new StringBuilder("is").append(propertyNameBuilder).toString(); 298 299 final Class<? extends Node> nodeClass = node.getClass(); 300 final Method setter = nodeClass.getMethod(setterName, boolean.class); 301 final Method getter = nodeClass.getMethod(getterName); 302 303 final NGNode peer = node.impl_getPeer(); 304 final Class<? extends NGNode> impl_class = peer.getClass(); 305 final Method impl_getter = impl_class.getMethod(getterName); 306 307 308 // 1. Create test scene 309 final Scene scene = new Scene(new Group()); 310 scene.getRoot().getChildren().add(node); 311 312 // 2. Initial setup 313 setter.invoke(node, initialValue); 314 node.impl_syncPeer(); 315 assertEquals(initialValue, getter.invoke(node)); 316 assertEquals(initialValue, impl_getter.invoke(peer)); 317 318 // 3. Change value of the property 319 setter.invoke(node, newValue); 320 321 // 4. Check that the property value has changed but has not propagated to PGNode 322 assertEquals(newValue, getter.invoke(node)); 323 assertEquals(initialValue, impl_getter.invoke(peer)); 324 325 // 5. Propagate the property value to PGNode 326 node.impl_syncPeer(); 327 328 // 6. Check that the value has been propagated to PGNode 329 assertEquals(newValue, impl_getter.invoke(peer)); 330 } 331 332 333 public static void testFloatPropertyPropagation( 334 final Node node, 335 final String propertyName, 336 final float initialValue, 337 final float newValue) throws Exception { 338 339 testFloatPropertyPropagation(node, propertyName, propertyName, initialValue, newValue); 340 } 341 342 public static void syncNode(Node node) { 343 node.updateBounds(); 344 node.impl_syncPeer(); 345 } 346 347 public static void assertBooleanPropertySynced( 348 final Node node, 349 final String propertyName, 350 final String pgPropertyName, 351 final boolean value) throws Exception { 352 353 final Scene scene = new Scene(new Group(), 500, 500); 354 355 final StringBuilder propertyNameBuilder = new StringBuilder(propertyName); 356 propertyNameBuilder.setCharAt(0, Character.toUpperCase(propertyName.charAt(0))); 357 final String getterName = new StringBuilder("is").append(propertyNameBuilder).toString(); 358 Method getterMethod = node.getClass().getMethod(getterName, new Class[]{}); 359 Boolean defaultValue = (Boolean)getterMethod.invoke(node); 360 BooleanProperty v = new SimpleBooleanProperty(defaultValue); 361 362 Method modelMethod = node.getClass().getMethod( 363 propertyName + "Property", 364 new Class[]{}); 365 BooleanProperty model = (BooleanProperty)modelMethod.invoke(node); 366 model.bind(v); 367 368 ((Group)scene.getRoot()).getChildren().add(node); 369 370 NodeTest.syncNode(node); 371 assertEquals(defaultValue, TestUtils.getBooleanValue(node, pgPropertyName)); 372 373 v.set(value); 374 NodeTest.syncNode(node); 375 assertEquals(value, TestUtils.getBooleanValue(node, pgPropertyName)); 376 } 377 378 public static void assertIntPropertySynced( 379 final Node node, 380 final String propertyName, 381 final String pgPropertyName, 382 final int value) throws Exception { 383 384 final Scene scene = new Scene(new Group(), 500, 500); 385 386 final StringBuilder propertyNameBuilder = new StringBuilder(propertyName); 387 propertyNameBuilder.setCharAt(0, Character.toUpperCase(propertyName.charAt(0))); 388 final String getterName = new StringBuilder("get").append(propertyNameBuilder).toString(); 389 Method getterMethod = node.getClass().getMethod(getterName, new Class[]{}); 390 Integer defaultValue = (Integer)getterMethod.invoke(node); 391 IntegerProperty v = new SimpleIntegerProperty(defaultValue); 392 393 Method modelMethod = node.getClass().getMethod( 394 propertyName + "Property", 395 new Class[]{}); 396 IntegerProperty model = (IntegerProperty)modelMethod.invoke(node); 397 model.bind(v); 398 399 ((Group)scene.getRoot()).getChildren().add(node); 400 401 NodeTest.syncNode(node); 402 assertTrue(numbersEquals(defaultValue, 403 (Number)TestUtils.getObjectValue(node, pgPropertyName))); 404 405 v.set(value); 406 NodeTest.syncNode(node); 407 assertTrue(numbersEquals(new Integer(value), 408 (Number)TestUtils.getObjectValue(node, pgPropertyName))); 409 } 410 411 public static boolean numbersEquals(Number expected, Number value) { 412 return numbersEquals(expected, value, 0.001); 413 } 414 415 public static boolean numbersEquals(Number expected, Number value, double delta) { 416 boolean res = (Math.abs(expected.doubleValue() - value.doubleValue()) < delta); 417 if (!res) { 418 System.err.println("expected=" + expected + ", value=" + value); 419 } 420 return res; 421 } 422 423 public static void assertDoublePropertySynced( 424 final Node node, 425 final String propertyName, 426 final String pgPropertyName, 427 final double value) throws Exception { 428 429 final Scene scene = new Scene(new Group(), 500, 500); 430 431 final StringBuilder propertyNameBuilder = new StringBuilder(propertyName); 432 propertyNameBuilder.setCharAt(0, Character.toUpperCase(propertyName.charAt(0))); 433 final String getterName = new StringBuilder("get").append(propertyNameBuilder).toString(); 434 Method getterMethod = node.getClass().getMethod(getterName, new Class[]{}); 435 Double defaultValue = (Double)getterMethod.invoke(node); 436 DoubleProperty v = new SimpleDoubleProperty(defaultValue); 437 438 Method modelMethod = node.getClass().getMethod( 439 propertyName + "Property", 440 new Class[]{}); 441 DoubleProperty model = (DoubleProperty)modelMethod.invoke(node); 442 model.bind(v); 443 444 scene.getRoot().getChildren().add(node); 445 446 NodeTest.syncNode(node); 447 assertTrue(numbersEquals(defaultValue, 448 (Number)TestUtils.getObjectValue(node, pgPropertyName))); 449 450 v.set(value); 451 NodeTest.syncNode(node); 452 assertTrue(numbersEquals(new Double(value), 453 (Number)TestUtils.getObjectValue(node, pgPropertyName))); 454 } 455 456 457 public static void assertObjectPropertySynced( 458 final Node node, 459 final String propertyName, 460 final String pgPropertyName, 461 final Object value) throws Exception { 462 463 final Scene scene = new Scene(new Group(), 500, 500); 464 465 final StringBuilder propertyNameBuilder = new StringBuilder(propertyName); 466 propertyNameBuilder.setCharAt(0, Character.toUpperCase(propertyName.charAt(0))); 467 final String getterName = new StringBuilder("get").append(propertyNameBuilder).toString(); 468 Method getterMethod = node.getClass().getMethod(getterName, new Class[]{}); 469 Object defaultValue = getterMethod.invoke(node); 470 ObjectProperty v = new SimpleObjectProperty(defaultValue); 471 472 Method modelMethod = node.getClass().getMethod( 473 propertyName + "Property", 474 new Class[]{}); 475 ObjectProperty model = (ObjectProperty)modelMethod.invoke(node); 476 model.bind(v); 477 478 ((Group)scene.getRoot()).getChildren().add(node); 479 480 NodeTest.syncNode(node); 481 // sometimes enum is used on node but int on PGNode 482 Object result1 = TestUtils.getObjectValue(node, pgPropertyName); 483 if (result1 instanceof Integer) { 484 assertTrue(((Enum)defaultValue).ordinal() == ((Integer)result1).intValue()); 485 } else { 486 assertEquals(defaultValue, TestUtils.getObjectValue(node, pgPropertyName)); 487 } 488 489 v.set(value); 490 NodeTest.syncNode(node); 491 492 Object result2 = TestUtils.getObjectValue(node, pgPropertyName); 493 if (result2 instanceof Integer) { 494 assertTrue(((Enum)value).ordinal() == ((Integer)result2).intValue()); 495 } else { 496 assertEquals(value, TestUtils.getObjectValue(node, pgPropertyName)); 497 } 498 } 499 500 501 502 public static void assertObjectProperty_AsStringSynced( 503 final Node node, 504 final String propertyName, 505 final String pgPropertyName, 506 final Object value) throws Exception { 507 508 final Scene scene = new Scene(new Group(), 500, 500); 509 510 final StringBuilder propertyNameBuilder = new StringBuilder(propertyName); 511 propertyNameBuilder.setCharAt(0, Character.toUpperCase(propertyName.charAt(0))); 512 final String getterName = new StringBuilder("get").append(propertyNameBuilder).toString(); 513 Method getterMethod = node.getClass().getMethod(getterName, new Class[]{}); 514 Object defaultValue = getterMethod.invoke(node); 515 ObjectProperty v = new SimpleObjectProperty(defaultValue); 516 517 Method modelMethod = node.getClass().getMethod( 518 propertyName + "Property", 519 new Class[]{}); 520 ObjectProperty model = (ObjectProperty)modelMethod.invoke(node); 521 model.bind(v); 522 523 scene.getRoot().getChildren().add(node); 524 525 NodeTest.syncNode(node); 526 assertEquals( 527 defaultValue.toString(), 528 TestUtils.getObjectValue(node, pgPropertyName).toString()); 529 530 v.set(value); 531 NodeTest.syncNode(node); 532 533 assertEquals( 534 value.toString(), 535 TestUtils.getObjectValue(node, pgPropertyName).toString()); 536 } 537 538 public static void assertStringPropertySynced( 539 final Node node, 540 final String propertyName, 541 final String pgPropertyName, 542 final String value) throws Exception { 543 544 final Scene scene = new Scene(new Group(), 500, 500); 545 546 final StringBuilder propertyNameBuilder = new StringBuilder(propertyName); 547 propertyNameBuilder.setCharAt(0, Character.toUpperCase(propertyName.charAt(0))); 548 final String getterName = new StringBuilder("get").append(propertyNameBuilder).toString(); 549 Method getterMethod = node.getClass().getMethod(getterName, new Class[]{}); 550 String defaultValue = (String)getterMethod.invoke(node); 551 StringProperty v = new SimpleStringProperty(defaultValue); 552 553 Method modelMethod = node.getClass().getMethod( 554 propertyName + "Property", 555 new Class[]{}); 556 StringProperty model = (StringProperty)modelMethod.invoke(node); 557 model.bind(v); 558 559 ((Group)scene.getRoot()).getChildren().add(node); 560 561 NodeTest.syncNode(node); 562 assertEquals( 563 defaultValue, 564 TestUtils.getStringValue(node, pgPropertyName)); 565 566 v.set(value); 567 NodeTest.syncNode(node); 568 569 assertEquals( 570 value, 571 TestUtils.getStringValue(node, pgPropertyName)); 572 } 573 574 public static void testFloatPropertyPropagation( 575 final Node node, 576 final String propertyName, 577 final String pgPropertyName, 578 final float initialValue, 579 final float newValue) throws Exception { 580 581 final StringBuilder propertyNameBuilder = new StringBuilder(propertyName); 582 propertyNameBuilder.setCharAt(0, Character.toUpperCase(propertyName.charAt(0))); 583 584 final StringBuilder pgPropertyNameBuilder = new StringBuilder(pgPropertyName); 585 pgPropertyNameBuilder.setCharAt(0, Character.toUpperCase(pgPropertyName.charAt(0))); 586 587 final String setterName = new StringBuilder("set").append(propertyNameBuilder).toString(); 588 final String getterName = new StringBuilder("get").append(propertyNameBuilder).toString(); 589 final String pgGetterName = new StringBuilder("get").append(pgPropertyNameBuilder).toString(); 590 591 final Class<? extends Node> nodeClass = node.getClass(); 592 final Method setter = nodeClass.getMethod(setterName, float.class); 593 final Method getter = nodeClass.getMethod(getterName); 594 595 final NGNode peer = node.impl_getPeer(); 596 final Class<? extends NGNode> impl_class = peer.getClass(); 597 final Method impl_getter = impl_class.getMethod(pgGetterName); 598 599 600 // 1. Create test scene 601 final Scene scene = new Scene(new Group()); 602 scene.getRoot().getChildren().add(node); 603 604 // 2. Initial setup 605 setter.invoke(node, initialValue); 606 node.impl_syncPeer(); 607 assertEquals(initialValue, (Float) getter.invoke(node), 1e-100); 608 assertEquals(initialValue, (Float) impl_getter.invoke(peer), 1e-100); 609 610 // 3. Change value of the property 611 setter.invoke(node, newValue); 612 613 // 4. Check that the property value has changed but has not propagated to PGNode 614 assertEquals(newValue, (Float) getter.invoke(node), 1e-100); 615 assertEquals(initialValue, (Float) impl_getter.invoke(peer), 1e-100); 616 617 // 5. Propagate the property value to PGNode 618 node.impl_syncPeer(); 619 620 // 6. Check that the value has been propagated to PGNode 621 assertEquals(newValue, (Float) impl_getter.invoke(peer), 1e-100); 622 } 623 624 public static void testDoublePropertyPropagation( 625 final Node node, 626 final String propertyName, 627 final double initialValue, 628 final double newValue) throws Exception { 629 630 testDoublePropertyPropagation(node, propertyName, propertyName, initialValue, newValue); 631 } 632 633 634 public static void testDoublePropertyPropagation( 635 final Node node, 636 final String propertyName, 637 final String pgPropertyName, 638 final double initialValue, 639 final double newValue) throws Exception { 640 641 final StringBuilder propertyNameBuilder = new StringBuilder(propertyName); 642 propertyNameBuilder.setCharAt(0, Character.toUpperCase(propertyName.charAt(0))); 643 644 final StringBuilder pgPropertyNameBuilder = new StringBuilder(pgPropertyName); 645 pgPropertyNameBuilder.setCharAt(0, Character.toUpperCase(pgPropertyName.charAt(0))); 646 647 final String setterName = new StringBuilder("set").append(propertyNameBuilder).toString(); 648 final String getterName = new StringBuilder("get").append(propertyNameBuilder).toString(); 649 final String pgGetterName = new StringBuilder("get").append(pgPropertyNameBuilder).toString(); 650 651 final Class<? extends Node> nodeClass = node.getClass(); 652 final Method setter = nodeClass.getMethod(setterName, double.class); 653 final Method getter = nodeClass.getMethod(getterName); 654 655 final NGNode peer = node.impl_getPeer(); 656 final Class<? extends NGNode> impl_class = peer.getClass(); 657 final Method impl_getter = impl_class.getMethod(pgGetterName); 658 659 660 // 1. Create test scene 661 final Scene scene = new Scene(new Group()); 662 scene.getRoot().getChildren().add(node); 663 664 // 2. Initial setup 665 setter.invoke(node, initialValue); 666 node.impl_syncPeer(); 667 assertEquals(initialValue, (Double) getter.invoke(node), 1e-100); 668 assertEquals((float) initialValue, (Float) impl_getter.invoke(peer), 1e-100); 669 670 // 3. Change value of the property 671 setter.invoke(node, newValue); 672 673 // 4. Check that the property value has changed but has not propagated to PGNode 674 assertEquals(newValue, (Double) getter.invoke(node), 1e-100); 675 assertEquals((float) initialValue, (Float) impl_getter.invoke(peer), 1e-100); 676 677 // 5. Propagate the property value to PGNode 678 node.impl_syncPeer(); 679 680 // 6. Check that the value has been propagated to PGNode 681 assertEquals((float) newValue, (Float) impl_getter.invoke(peer), 1e-100); 682 } 683 684 public interface ObjectValueConvertor { 685 Object toSg(Object pgValue); 686 } 687 688 public static final Comparator DEFAULT_OBJ_COMPARATOR = 689 new Comparator() { 690 @Override 691 public int compare(final Object sgValue, final Object pgValue) { 692 assertEquals(sgValue, pgValue); 693 return 0; 694 } 695 }; 696 697 public static void testObjectPropertyPropagation( 698 final Node node, 699 final String propertyName, 700 final Object initialValue, 701 final Object newValue) throws Exception { 702 703 testObjectPropertyPropagation(node, propertyName, propertyName, initialValue, newValue); 704 } 705 706 public static void testObjectPropertyPropagation( 707 final Node node, 708 final String propertyName, 709 final String pgPropertyName, 710 final Object initialValue, 711 final Object newValue) throws Exception { 712 testObjectPropertyPropagation(node, propertyName, pgPropertyName, 713 initialValue, newValue, DEFAULT_OBJ_COMPARATOR); 714 } 715 716 public static void testObjectPropertyPropagation( 717 final Node node, 718 final String propertyName, 719 final String pgPropertyName, 720 final Object initialValue, 721 final Object newValue, 722 final ObjectValueConvertor convertor) throws Exception { 723 testObjectPropertyPropagation( 724 node, propertyName, pgPropertyName, 725 initialValue, newValue, 726 new Comparator() { 727 @Override 728 public int compare(final Object sgValue, 729 final Object pgValue) { 730 assertEquals(sgValue, convertor.toSg(pgValue)); 731 return 0; 732 } 733 }); 734 } 735 736 public static void testObjectPropertyPropagation( 737 final Node node, 738 final String propertyName, 739 final String pgPropertyName, 740 final Object initialValue, 741 final Object newValue, 742 final Comparator comparator) throws Exception { 743 final StringBuilder propertyNameBuilder = new StringBuilder(propertyName); 744 propertyNameBuilder.setCharAt(0, Character.toUpperCase(propertyName.charAt(0))); 745 746 final StringBuilder pgPropertyNameBuilder = new StringBuilder(pgPropertyName); 747 pgPropertyNameBuilder.setCharAt(0, Character.toUpperCase(pgPropertyName.charAt(0))); 748 749 final String setterName = new StringBuilder("set").append(propertyNameBuilder).toString(); 750 final String getterName = new StringBuilder("get").append(propertyNameBuilder).toString(); 751 final String pgGetterName = new StringBuilder("get").append(pgPropertyNameBuilder).toString(); 752 753 final Class<? extends Node> nodeClass = node.getClass(); 754 final Method getter = nodeClass.getMethod(getterName); 755 final Method setter = nodeClass.getMethod(setterName, getter.getReturnType()); 756 757 final NGNode peer = node.impl_getPeer(); 758 final Class<? extends NGNode> impl_class = peer.getClass(); 759 final Method impl_getter = impl_class.getMethod(pgGetterName); 760 761 762 // 1. Create test scene 763 final Scene scene = new Scene(new Group()); 764 scene.getRoot().getChildren().add(node); 765 766 // 2. Initial setup 767 setter.invoke(node, initialValue); 768 node.impl_syncPeer(); 769 assertEquals(initialValue, getter.invoke(node)); 770 assertEquals(0, comparator.compare(initialValue, 771 impl_getter.invoke(peer))); 772 773 // 3. Change value of the property 774 setter.invoke(node, newValue); 775 776 // 4. Check that the property value has changed but has not propagated to PGNode 777 assertEquals(newValue, getter.invoke(node)); 778 assertEquals(0, comparator.compare(initialValue, 779 impl_getter.invoke(peer))); 780 781 // 5. Propagate the property value to PGNode 782 node.impl_syncPeer(); 783 784 // 6. Check that the value has been propagated to PGNode 785 assertEquals(0, comparator.compare(newValue, 786 impl_getter.invoke(peer))); 787 } 788 789 790 public static void testIntPropertyPropagation( 791 final Node node, 792 final String propertyName, 793 final int initialValue, 794 final int newValue) throws Exception { 795 796 testIntPropertyPropagation(node, propertyName, propertyName, initialValue, newValue); 797 } 798 799 800 public static void testIntPropertyPropagation( 801 final Node node, 802 final String propertyName, 803 final String pgPropertyName, 804 final int initialValue, 805 final int newValue) throws Exception { 806 807 final StringBuilder propertyNameBuilder = new StringBuilder(propertyName); 808 propertyNameBuilder.setCharAt(0, Character.toUpperCase(propertyName.charAt(0))); 809 810 final StringBuilder pgPropertyNameBuilder = new StringBuilder(pgPropertyName); 811 pgPropertyNameBuilder.setCharAt(0, Character.toUpperCase(pgPropertyName.charAt(0))); 812 813 final String setterName = new StringBuilder("set").append(propertyNameBuilder).toString(); 814 final String getterName = new StringBuilder("get").append(propertyNameBuilder).toString(); 815 final String pgGetterName = new StringBuilder("get").append(pgPropertyNameBuilder).toString(); 816 817 final Class<? extends Node> nodeClass = node.getClass(); 818 final Method getter = nodeClass.getMethod(getterName); 819 final Method setter = nodeClass.getMethod(setterName, getter.getReturnType()); 820 821 final NGNode peer = node.impl_getPeer(); 822 final Class<? extends NGNode> impl_class = peer.getClass(); 823 final Method impl_getter = impl_class.getMethod(pgGetterName); 824 825 826 // 1. Create test scene 827 final Scene scene = new Scene(new Group()); 828 scene.getRoot().getChildren().add(node); 829 830 // 2. Initial setup 831 setter.invoke(node, initialValue); 832 assertEquals(initialValue, getter.invoke(node)); 833 node.impl_syncPeer(); 834 assertEquals(initialValue, ((Number) impl_getter.invoke(peer)).intValue()); 835 836 // 3. Change value of the property 837 setter.invoke(node, newValue); 838 839 // 4. Check that the property value has changed but has not propagated to PGNode 840 assertEquals(newValue, getter.invoke(node)); 841 assertEquals(initialValue, ((Number) impl_getter.invoke(peer)).intValue()); 842 843 // 5. Propagate the property value to PGNode 844 node.impl_syncPeer(); 845 846 // 6. Check that the value has been propagated to PGNode 847 assertEquals(newValue, ((Number) impl_getter.invoke(peer)).intValue()); 848 } 849 850 public static void callSyncPGNode(final Node node) { 851 node.impl_syncPeer(); 852 } 853 854 @Test 855 public void testToFront() { 856 Rectangle rect1 = new Rectangle(); 857 Rectangle rect2 = new Rectangle(); 858 Group g = new Group(); 859 860 Scene scene = new Scene(g); 861 g.getChildren().add(rect1); 862 g.getChildren().add(rect2); 863 864 rect1.toFront(); 865 rect2.toFront(); 866 867 // toFront should not remove rectangle from scene 868 assertEquals(scene, rect2.getScene()); 869 assertEquals(scene, rect1.getScene()); 870 // test corect order of scene content 871 assertEquals(rect2, g.getChildren().get(1)); 872 assertEquals(rect1, g.getChildren().get(0)); 873 874 rect1.toFront(); 875 assertEquals(scene, rect2.getScene()); 876 assertEquals(scene, rect1.getScene()); 877 assertEquals(rect1, g.getChildren().get(1)); 878 assertEquals(rect2, g.getChildren().get(0)); 879 } 880 881 @Test 882 public void testClip() { 883 Rectangle rect1 = new Rectangle(); 884 Rectangle rect2 = new Rectangle(); 885 rect1.setClip(rect2); 886 887 Scene scene = new Scene(new Group()); 888 scene.getRoot().getChildren().add(rect1); 889 assertEquals(rect2, rect1.getClip()); 890 assertEquals(scene, rect2.getScene()); 891 892 } 893 894 @Test 895 public void testInvalidClip() { 896 Rectangle rectA = new Rectangle(300, 300); 897 Rectangle clip1 = new Rectangle(10, 10); 898 Rectangle clip2 = new Rectangle(100, 100); 899 clip2.setClip(rectA); 900 rectA.setClip(clip1); 901 assertEquals(rectA.getClip(), clip1); 902 thrown.expect(IllegalArgumentException.class); 903 try { 904 rectA.setClip(clip2); 905 } catch (final IllegalArgumentException e) { 906 assertNotSame(rectA.getClip(), clip2); 907 throw e; 908 } 909 } 910 911 @Test public void testProperties() { 912 Rectangle node = new Rectangle(); 913 javafx.collections.ObservableMap<Object, Object> properties = node.getProperties(); 914 915 /* If we ask for it, we should get it. 916 */ 917 assertNotNull(properties); 918 919 /* What we put in, we should get out. 920 */ 921 properties.put("MyKey", "MyValue"); 922 assertEquals("MyValue", properties.get("MyKey")); 923 924 /* If we ask for it again, we should get the same thing. 925 */ 926 javafx.collections.ObservableMap<Object, Object> properties2 = node.getProperties(); 927 assertEquals(properties2, properties); 928 929 /* What we put in to the other one, we should get out of this one because 930 * they should be the same thing. 931 */ 932 assertEquals("MyValue", properties2.get("MyKey")); 933 } 934 935 public static boolean isDirty(Node node, DirtyBits[] dbs) { 936 for(DirtyBits db:dbs) { 937 if (!node.impl_isDirty(db)) { 938 System.out.printf("@NodeTest:check dirty: %s [%d]\n",db,db.ordinal()); 939 return false; 940 } 941 } 942 return true; 943 } 944 945 @Test 946 public void testDefaultValueForOpacityIsOneWhenReadFromGetter() { 947 final Node node = new Rectangle(); 948 assertEquals(1, node.getOpacity(), .005); 949 } 950 951 @Test 952 public void testDefaultValueForOpacityIsOneWhenReadFromProperty() { 953 final Node node = new Rectangle(); 954 assertEquals(1, node.opacityProperty().get(), .005); 955 } 956 957 @Test 958 public void settingOpacityThroughSetterShouldAffectBothGetterAndProperty() { 959 final Node node = new Rectangle(); 960 node.setOpacity(.5); 961 assertEquals(.5, node.getOpacity(), .005); 962 assertEquals(.5, node.opacityProperty().get(), .005); 963 } 964 965 @Test 966 public void settingOpacityThroughPropertyShouldAffectBothGetterAndProperty() { 967 final Node node = new Rectangle(); 968 node.opacityProperty().set(.5); 969 assertEquals(.5, node.getOpacity(), .005); 970 assertEquals(.5, node.opacityProperty().get(), .005); 971 } 972 973 @Test 974 public void testDefaultValueForVisibleIsTrueWhenReadFromGetter() { 975 final Node node = new Rectangle(); 976 assertTrue(node.isVisible()); 977 } 978 979 @Test 980 public void testDefaultValueForVisibleIsTrueWhenReadFromProperty() { 981 final Node node = new Rectangle(); 982 assertTrue(node.visibleProperty().get()); 983 } 984 985 @Test 986 public void settingVisibleThroughSetterShouldAffectBothGetterAndProperty() { 987 final Node node = new Rectangle(); 988 node.setVisible(false); 989 assertFalse(node.isVisible()); 990 assertFalse(node.visibleProperty().get()); 991 } 992 993 @Test 994 public void settingVisibleThroughPropertyShouldAffectBothGetterAndProperty() { 995 final Node node = new Rectangle(); 996 node.visibleProperty().set(false); 997 assertFalse(node.isVisible()); 998 assertFalse(node.visibleProperty().get()); 999 } 1000 1001 @Test 1002 public void testDefaultStyleIsEmptyString() { 1003 final Node node = new Rectangle(); 1004 assertEquals("", node.getStyle()); 1005 assertEquals("", node.styleProperty().get()); 1006 node.setStyle(null); 1007 assertEquals("", node.styleProperty().get()); 1008 assertEquals("", node.getStyle()); 1009 } 1010 1011 @Test 1012 public void testSynchronizationOfInvisibleNodes() { 1013 final Group g = new Group(); 1014 final Circle c = new CircleTest.StubCircle(50); 1015 final NGGroup sg = g.impl_getPeer(); 1016 final CircleTest.StubNGCircle sc = c.impl_getPeer(); 1017 g.getChildren().add(c); 1018 1019 syncNode(g); 1020 syncNode(c); 1021 assertFalse(sg.getChildren().isEmpty()); 1022 assertEquals(50.0, sc.getRadius(), 0.01); 1023 1024 g.setVisible(false); 1025 1026 syncNode(g); 1027 syncNode(c); 1028 assertFalse(sg.isVisible()); 1029 1030 final Rectangle r = new Rectangle(); 1031 g.getChildren().add(r); 1032 c.setRadius(100); 1033 1034 syncNode(g); 1035 syncNode(c); 1036 assertEquals(1, sg.getChildren().size()); 1037 assertEquals(50.0, sc.getRadius(), 0.01); 1038 1039 g.setVisible(true); 1040 1041 syncNode(g); 1042 syncNode(c); 1043 assertEquals(2, sg.getChildren().size()); 1044 assertEquals(100.0, sc.getRadius(), 0.01); 1045 1046 } 1047 1048 @Test 1049 public void testSynchronizationOfInvisibleNodes_2() { 1050 final Group g = new Group(); 1051 final Circle c = new CircleTest.StubCircle(50); 1052 1053 Scene s = new Scene(g); 1054 Stage st = new Stage(); 1055 st.show(); 1056 st.setScene(s); 1057 1058 final NGGroup sg = g.impl_getPeer(); 1059 final CircleTest.StubNGCircle sc = c.impl_getPeer(); 1060 1061 g.getChildren().add(c); 1062 1063 s.scenePulseListener.pulse(); 1064 1065 g.setVisible(false); 1066 1067 s.scenePulseListener.pulse(); 1068 1069 assertFalse(sg.isVisible()); 1070 assertTrue(sc.isVisible()); 1071 1072 c.setCenterX(10); // Make the circle dirty. It won't be synchronized as it is practically invisible (through the parent) 1073 1074 s.scenePulseListener.pulse(); 1075 1076 c.setVisible(false); // As circle is invisible and dirty, this won't trigger a synchronization 1077 1078 s.scenePulseListener.pulse(); 1079 1080 assertFalse(sg.isVisible()); 1081 assertTrue(sc.isVisible()); // This has not been synchronized, as it's not necessary 1082 // The rendering will stop at the Group, which is invisible 1083 1084 g.setVisible(true); 1085 1086 s.scenePulseListener.pulse(); 1087 1088 assertTrue(sg.isVisible()); 1089 assertFalse(sc.isVisible()); // Now the group is visible again, we need to synchronize also 1090 // the Circle 1091 } 1092 1093 @Test 1094 public void testSynchronizationOfInvisibleNodes_2_withClip() { 1095 final Group g = new Group(); 1096 final Circle c = new CircleTest.StubCircle(50); 1097 1098 Scene s = new Scene(g); 1099 Stage st = new Stage(); 1100 st.show(); 1101 st.setScene(s); 1102 1103 final NGGroup sg = g.impl_getPeer(); 1104 final CircleTest.StubNGCircle sc = c.impl_getPeer(); 1105 1106 g.setClip(c); 1107 1108 s.scenePulseListener.pulse(); 1109 1110 g.setVisible(false); 1111 1112 s.scenePulseListener.pulse(); 1113 1114 assertFalse(sg.isVisible()); 1115 assertTrue(sc.isVisible()); 1116 1117 c.setCenterX(10); // Make the circle dirty. It won't be synchronized as it is practically invisible (through the parent) 1118 1119 s.scenePulseListener.pulse(); 1120 1121 c.setVisible(false); // As circle is invisible and dirty, this won't trigger a synchronization 1122 1123 s.scenePulseListener.pulse(); 1124 1125 assertFalse(sg.isVisible()); 1126 assertTrue(sc.isVisible()); // This has not been synchronized, as it's not necessary 1127 // The rendering will stop at the Group, which is invisible 1128 1129 g.setVisible(true); 1130 1131 s.scenePulseListener.pulse(); 1132 1133 assertTrue(sg.isVisible()); 1134 assertFalse(sc.isVisible()); // Now the group is visible again, we need to synchronize also 1135 // the Circle 1136 } 1137 1138 @Test 1139 public void testLocalToScreen() { 1140 Rectangle rect = new Rectangle(); 1141 1142 rect.setTranslateX(10); 1143 rect.setTranslateY(20); 1144 1145 TestScene scene = new TestScene(new Group(rect)); 1146 final TestStage testStage = new TestStage(""); 1147 testStage.setX(100); 1148 testStage.setY(200); 1149 scene.set_window(testStage); 1150 Point2D p = rect.localToScreen(new Point2D(1, 2)); 1151 assertEquals(111.0, p.getX(), 0.0001); 1152 assertEquals(222.0, p.getY(), 0.0001); 1153 Bounds b = rect.localToScreen(new BoundingBox(1, 2, 3, 4)); 1154 assertEquals(111.0, b.getMinX(), 0.0001); 1155 assertEquals(222.0, b.getMinY(), 0.0001); 1156 assertEquals(3.0, b.getWidth(), 0.0001); 1157 assertEquals(4.0, b.getHeight(), 0.0001); 1158 } 1159 1160 @Test 1161 public void testLocalToScreen3D() { 1162 Box box = new Box(10, 10, 10); 1163 1164 box.setTranslateX(10); 1165 box.setTranslateY(20); 1166 1167 TestScene scene = new TestScene(new Group(box)); 1168 scene.setCamera(new PerspectiveCamera()); 1169 final TestStage testStage = new TestStage(""); 1170 testStage.setX(100); 1171 testStage.setY(200); 1172 scene.set_window(testStage); 1173 1174 Point2D p = box.localToScreen(new Point3D(1, 2, -5)); 1175 assertEquals(111.42, p.getX(), 0.1); 1176 assertEquals(223.14, p.getY(), 0.1); 1177 Bounds b = box.localToScreen(new BoundingBox(1, 2, -5, 1, 2, 10)); 1178 assertEquals(110.66, b.getMinX(), 0.1); 1179 assertEquals(221.08, b.getMinY(), 0.1); 1180 assertEquals(1.88, b.getWidth(), 0.1); 1181 assertEquals(4.3, b.getHeight(), 0.1); 1182 assertEquals(0.0, b.getDepth(), 0.0001); 1183 } 1184 1185 @Test 1186 public void testScreenToLocal() { 1187 Rectangle rect = new Rectangle(); 1188 1189 rect.setTranslateX(10); 1190 rect.setTranslateY(20); 1191 1192 TestScene scene = new TestScene(new Group(rect)); 1193 final TestStage testStage = new TestStage(""); 1194 testStage.setX(100); 1195 testStage.setY(200); 1196 scene.set_window(testStage); 1197 1198 assertEquals(new Point2D(1, 2), rect.screenToLocal(new Point2D(111, 222))); 1199 assertEquals(new BoundingBox(1, 2, 3, 4), rect.screenToLocal(new BoundingBox(111, 222, 3, 4))); 1200 } 1201 1202 @Test 1203 public void testLocalToScreenWithTranslatedCamera() { 1204 Rectangle rect = new Rectangle(); 1205 1206 rect.setTranslateX(10); 1207 rect.setTranslateY(20); 1208 1209 ParallelCamera cam = new ParallelCamera(); 1210 TestScene scene = new TestScene(new Group(rect, cam)); 1211 scene.setCamera(cam); 1212 final TestStage testStage = new TestStage(""); 1213 testStage.setX(100); 1214 testStage.setY(200); 1215 cam.setTranslateX(30); 1216 cam.setTranslateY(20); 1217 scene.set_window(testStage); 1218 1219 Point2D p = rect.localToScreen(new Point2D(1, 2)); 1220 assertEquals(81.0, p.getX(), 0.0001); 1221 assertEquals(202.0, p.getY(), 0.0001); 1222 Bounds b = rect.localToScreen(new BoundingBox(1, 2, 3, 4)); 1223 assertEquals(81.0, b.getMinX(), 0.0001); 1224 assertEquals(202.0, b.getMinY(), 0.0001); 1225 assertEquals(3.0, b.getWidth(), 0.0001); 1226 assertEquals(4.0, b.getHeight(), 0.0001); 1227 } 1228 1229 @Test 1230 public void testScreenToLocalWithTranslatedCamera() { 1231 Rectangle rect = new Rectangle(); 1232 1233 rect.setTranslateX(10); 1234 rect.setTranslateY(20); 1235 1236 ParallelCamera cam = new ParallelCamera(); 1237 TestScene scene = new TestScene(new Group(rect, cam)); 1238 scene.setCamera(cam); 1239 final TestStage testStage = new TestStage(""); 1240 testStage.setX(100); 1241 testStage.setY(200); 1242 cam.setTranslateX(30); 1243 cam.setTranslateY(20); 1244 scene.set_window(testStage); 1245 1246 assertEquals(new Point2D(31, 22), rect.screenToLocal(new Point2D(111, 222))); 1247 assertEquals(new BoundingBox(31, 22, 3, 4), rect.screenToLocal(new BoundingBox(111, 222, 3, 4))); 1248 } 1249 1250 @Test 1251 public void testLocalToScreenInsideSubScene() { 1252 Rectangle rect = new Rectangle(); 1253 rect.setTranslateX(4); 1254 rect.setTranslateY(9); 1255 SubScene subScene = new SubScene(new Group(rect), 100, 100); 1256 subScene.setTranslateX(6); 1257 subScene.setTranslateY(11); 1258 1259 TestScene scene = new TestScene(new Group(subScene)); 1260 final TestStage testStage = new TestStage(""); 1261 testStage.setX(100); 1262 testStage.setY(200); 1263 scene.set_window(testStage); 1264 1265 Point2D p = rect.localToScreen(new Point2D(1, 2)); 1266 assertEquals(111.0, p.getX(), 0.0001); 1267 assertEquals(222.0, p.getY(), 0.0001); 1268 Bounds b = rect.localToScreen(new BoundingBox(1, 2, 3, 4)); 1269 assertEquals(111.0, b.getMinX(), 0.0001); 1270 assertEquals(222.0, b.getMinY(), 0.0001); 1271 assertEquals(3.0, b.getWidth(), 0.0001); 1272 assertEquals(4.0, b.getHeight(), 0.0001); 1273 } 1274 1275 @Test 1276 public void testScreenToLocalInsideSubScene() { 1277 Rectangle rect = new Rectangle(); 1278 rect.setTranslateX(4); 1279 rect.setTranslateY(9); 1280 SubScene subScene = new SubScene(new Group(rect), 100, 100); 1281 subScene.setTranslateX(6); 1282 subScene.setTranslateY(11); 1283 1284 TestScene scene = new TestScene(new Group(subScene)); 1285 final TestStage testStage = new TestStage(""); 1286 testStage.setX(100); 1287 testStage.setY(200); 1288 scene.set_window(testStage); 1289 1290 assertEquals(new Point2D(1, 2), rect.screenToLocal(new Point2D(111, 222))); 1291 assertEquals(new BoundingBox(1, 2, 3, 4), rect.screenToLocal(new BoundingBox(111, 222, 3, 4))); 1292 } 1293 1294 @Test 1295 public void test2DLocalToScreenOn3DRotatedSubScene() { 1296 Rectangle rect = new Rectangle(); 1297 rect.setTranslateX(5); 1298 rect.setTranslateY(10); 1299 SubScene subScene = new SubScene(new Group(rect), 100, 100); 1300 subScene.setTranslateX(5); 1301 subScene.setTranslateY(10); 1302 subScene.setRotationAxis(Rotate.Y_AXIS); 1303 subScene.setRotate(40); 1304 1305 TestScene scene = new TestScene(new Group(subScene)); 1306 scene.setCamera(new PerspectiveCamera()); 1307 final TestStage testStage = new TestStage(""); 1308 testStage.setX(100); 1309 testStage.setY(200); 1310 scene.set_window(testStage); 1311 1312 Point2D p = rect.localToScreen(new Point2D(1, 2)); 1313 assertEquals(124.36, p.getX(), 0.1); 1314 assertEquals(226.0, p.getY(), 0.1); 1315 Bounds b = rect.localToScreen(new BoundingBox(1, 2, 3, 4)); 1316 assertEquals(124.36, b.getMinX(), 0.1); 1317 assertEquals(225.75, b.getMinY(), 0.1); 1318 assertEquals(1.85, b.getWidth(), 0.1); 1319 assertEquals(3.76, b.getHeight(), 0.1); 1320 } 1321 1322 @Test 1323 public void test2DScreenToLocalTo3DRotatedSubScene() { 1324 Rectangle rect = new Rectangle(); 1325 rect.setTranslateX(5); 1326 rect.setTranslateY(10); 1327 SubScene subScene = new SubScene(new Group(rect), 100, 100); 1328 subScene.setTranslateX(5); 1329 subScene.setTranslateY(10); 1330 subScene.setRotationAxis(Rotate.Y_AXIS); 1331 subScene.setRotate(40); 1332 1333 TestScene scene = new TestScene(new Group(subScene)); 1334 scene.setCamera(new PerspectiveCamera()); 1335 final TestStage testStage = new TestStage(""); 1336 testStage.setX(100); 1337 testStage.setY(200); 1338 scene.set_window(testStage); 1339 1340 Point2D p = rect.screenToLocal(new Point2D(124.36, 226.0)); 1341 assertEquals(1, p.getX(), 0.1); 1342 assertEquals(2, p.getY(), 0.1); 1343 Bounds b = rect.screenToLocal(new BoundingBox(124.36, 225.75, 1.85, 3.76)); 1344 assertEquals(1, b.getMinX(), 0.1); 1345 assertEquals(1.72, b.getMinY(), 0.1); 1346 assertEquals(3, b.getWidth(), 0.1); 1347 assertEquals(4.52, b.getHeight(), 0.1); 1348 } 1349 1350 @Test 1351 public void testScreenToLocalWithNonInvertibleTransform() { 1352 Rectangle rect = new Rectangle(); 1353 1354 rect.setScaleX(0.0); 1355 1356 TestScene scene = new TestScene(new Group(rect)); 1357 final TestStage testStage = new TestStage(""); 1358 testStage.setX(100); 1359 testStage.setY(200); 1360 scene.set_window(testStage); 1361 1362 assertNull(rect.screenToLocal(new Point2D(111, 222))); 1363 assertNull(rect.screenToLocal(new BoundingBox(111, 222, 3, 4))); 1364 } 1365 1366 @Test 1367 public void testScreenToLocalInsideNonInvertibleSubScene() { 1368 Rectangle rect = new Rectangle(); 1369 rect.setTranslateX(4); 1370 rect.setTranslateY(9); 1371 SubScene subScene = new SubScene(new Group(rect), 100, 100); 1372 subScene.setScaleX(0.0); 1373 1374 TestScene scene = new TestScene(new Group(subScene)); 1375 final TestStage testStage = new TestStage(""); 1376 testStage.setX(100); 1377 testStage.setY(200); 1378 scene.set_window(testStage); 1379 1380 assertNull(rect.screenToLocal(new Point2D(111, 222))); 1381 assertNull(rect.screenToLocal(new BoundingBox(111, 222, 3, 4))); 1382 } 1383 1384 @Test 1385 public void testRootMirroringWithTranslate() { 1386 final Group rootGroup = new Group(); 1387 rootGroup.setTranslateX(20); 1388 rootGroup.setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT); 1389 final Scene scene = new Scene(rootGroup, 200, 200); 1390 1391 final Point2D trPoint = scene.getRoot().localToScene(0, 0); 1392 assertEquals(180, trPoint.getX(), 0.1); 1393 } 1394 1395 1396 @Test 1397 public void testLayoutXYTriggersParentSizeChange() { 1398 final Group rootGroup = new Group(); 1399 final Group subGroup = new Group(); 1400 rootGroup.getChildren().add(subGroup); 1401 1402 Rectangle r = new Rectangle(50,50); 1403 r.setManaged(false); 1404 Rectangle staticR = new Rectangle(1,1); 1405 subGroup.getChildren().addAll(r, staticR); 1406 1407 assertEquals(50,subGroup.getLayoutBounds().getWidth(), 1e-10); 1408 assertEquals(50,subGroup.getLayoutBounds().getHeight(), 1e-10); 1409 1410 r.setLayoutX(50); 1411 1412 rootGroup.layout(); 1413 1414 assertEquals(100,subGroup.getLayoutBounds().getWidth(), 1e-10); 1415 assertEquals(50,subGroup.getLayoutBounds().getHeight(), 1e-10); 1416 1417 } 1418 1419 @Test 1420 public void testLayoutXYWontBreakLayout() { 1421 final Group rootGroup = new Group(); 1422 final AnchorPane pane = new AnchorPane(); 1423 rootGroup.getChildren().add(pane); 1424 1425 Rectangle r = new Rectangle(50,50); 1426 pane.getChildren().add(r); 1427 1428 AnchorPane.setLeftAnchor(r, 10d); 1429 AnchorPane.setTopAnchor(r, 10d); 1430 1431 rootGroup.layout(); 1432 1433 assertEquals(10, r.getLayoutX(), 1e-10); 1434 assertEquals(10, r.getLayoutY(), 1e-10); 1435 1436 r.setLayoutX(50); 1437 1438 assertEquals(50, r.getLayoutX(), 1e-10); 1439 assertEquals(10, r.getLayoutY(), 1e-10); 1440 1441 rootGroup.layout(); 1442 1443 assertEquals(10, r.getLayoutX(), 1e-10); 1444 assertEquals(10, r.getLayoutY(), 1e-10); 1445 1446 } 1447 1448 @Test 1449 public void clipShouldUpdateAfterParentVisibilityChange() { 1450 1451 final Group root = new Group(); 1452 Scene scene = new Scene(root, 300, 300); 1453 1454 final Group parent = new Group(); 1455 parent.setVisible(false); 1456 1457 final Circle circle = new Circle(100, 100, 100); 1458 parent.getChildren().add(circle); 1459 1460 final Rectangle clip = new Rectangle(100, 100) { 1461 @Override protected NGNode impl_createPeer() { 1462 return new MockNGRect(); 1463 } 1464 }; 1465 circle.setClip(clip); 1466 1467 root.getChildren().add(parent); 1468 parent.setVisible(true); 1469 1470 Stage stage = new Stage(); 1471 stage.setScene(scene); 1472 stage.show(); 1473 1474 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1475 1476 clip.setWidth(300); 1477 1478 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1479 1480 assertEquals(300, ((MockNGRect) clip.impl_getPeer()).w, 1e-10); 1481 } 1482 1483 @Test 1484 public void untransformedNodeShouldSyncIdentityTransform() { 1485 final Node node = createTestRect(); 1486 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1487 assertSame(BaseTransform.IDENTITY_TRANSFORM, 1488 ((MockNGRect) node.impl_getPeer()).t); 1489 } 1490 1491 @Test 1492 public void nodeTransfomedByIdentitiesShouldSyncIdentityTransform() { 1493 final Node node = createTestRect(); 1494 node.setRotationAxis(Rotate.X_AXIS); 1495 node.getTransforms().add(new Translate()); 1496 node.getTransforms().add(new Scale()); 1497 node.getTransforms().add(new Affine()); 1498 node.getTransforms().add(new Rotate(0, Rotate.Y_AXIS)); 1499 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1500 assertSame(BaseTransform.IDENTITY_TRANSFORM, 1501 ((MockNGRect) node.impl_getPeer()).t); 1502 } 1503 1504 @Test 1505 public void translatedNodeShouldSyncTranslateTransform1() { 1506 final Node node = createTestRect(); 1507 node.setTranslateX(30); 1508 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1509 assertSame(Translate2D.class, 1510 ((MockNGRect) node.impl_getPeer()).t.getClass()); 1511 } 1512 1513 @Test 1514 public void translatedNodeShouldSyncTranslateTransform2() { 1515 final Node node = createTestRect(); 1516 node.getTransforms().add(new Translate(20, 10)); 1517 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1518 assertSame(Translate2D.class, 1519 ((MockNGRect) node.impl_getPeer()).t.getClass()); 1520 } 1521 1522 @Test 1523 public void multitranslatedNodeShouldSyncTranslateTransform() { 1524 final Node node = createTestRect(); 1525 node.setTranslateX(30); 1526 node.getTransforms().add(new Translate(20, 10)); 1527 node.getTransforms().add(new Translate(10, 20)); 1528 node.getTransforms().add(new Translate(5, 5, 0)); 1529 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1530 assertSame(Translate2D.class, 1531 ((MockNGRect) node.impl_getPeer()).t.getClass()); 1532 } 1533 1534 @Test 1535 public void mirroringShouldSyncAffine2DTransform() { 1536 final Node node = createTestRect(); 1537 node.setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT); 1538 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1539 assertSame(Affine2D.class, 1540 ((MockNGRect) node.impl_getPeer()).t.getClass()); 1541 } 1542 1543 @Test 1544 public void rotatedNodeShouldSyncAffine2DTransform1() { 1545 final Node node = createTestRect(); 1546 node.setRotate(20); 1547 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1548 assertSame(Affine2D.class, 1549 ((MockNGRect) node.impl_getPeer()).t.getClass()); 1550 } 1551 1552 @Test 1553 public void rotatedNodeShouldSyncAffine2DTransform2() { 1554 final Node node = createTestRect(); 1555 node.getTransforms().add(new Rotate(20)); 1556 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1557 assertSame(Affine2D.class, 1558 ((MockNGRect) node.impl_getPeer()).t.getClass()); 1559 } 1560 1561 @Test 1562 public void multiRotatedNodeShouldSyncAffine2DTransform() { 1563 final Node node = createTestRect(); 1564 node.setRotate(20); 1565 node.getTransforms().add(new Rotate(20)); 1566 node.getTransforms().add(new Rotate(0, Rotate.X_AXIS)); 1567 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1568 assertSame(Affine2D.class, 1569 ((MockNGRect) node.impl_getPeer()).t.getClass()); 1570 } 1571 1572 @Test 1573 public void scaledNodeShouldSyncAffine2DTransform1() { 1574 final Node node = createTestRect(); 1575 node.setScaleX(2); 1576 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1577 assertSame(Affine2D.class, 1578 ((MockNGRect) node.impl_getPeer()).t.getClass()); 1579 } 1580 1581 @Test 1582 public void scaledNodeShouldSyncAffine2DTransform2() { 1583 final Node node = createTestRect(); 1584 node.getTransforms().add(new Scale(2, 1)); 1585 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1586 assertSame(Affine2D.class, 1587 ((MockNGRect) node.impl_getPeer()).t.getClass()); 1588 } 1589 1590 @Test 1591 public void multiScaledNodeShouldSyncAffine2DTransform() { 1592 final Node node = createTestRect(); 1593 node.setScaleX(20); 1594 node.getTransforms().add(new Scale(2, 1)); 1595 node.getTransforms().add(new Scale(0.5, 2, 1)); 1596 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1597 assertSame(Affine2D.class, 1598 ((MockNGRect) node.impl_getPeer()).t.getClass()); 1599 } 1600 1601 @Test 1602 public void shearedNodeShouldSyncAffine2DTransform() { 1603 final Node node = createTestRect(); 1604 node.getTransforms().add(new Shear(2, 1)); 1605 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1606 assertSame(Affine2D.class, 1607 ((MockNGRect) node.impl_getPeer()).t.getClass()); 1608 } 1609 1610 @Test 1611 public void ztranslatedNodeShouldSyncAffine3DTransform1() { 1612 final Node node = createTestRect(); 1613 node.setTranslateZ(30); 1614 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1615 assertSame(Affine3D.class, 1616 ((MockNGRect) node.impl_getPeer()).t.getClass()); 1617 } 1618 1619 @Test 1620 public void ztranslatedNodeShouldSyncAffine3DTransform2() { 1621 final Node node = createTestRect(); 1622 node.getTransforms().add(new Translate(0, 0, 10)); 1623 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1624 assertSame(Affine3D.class, 1625 ((MockNGRect) node.impl_getPeer()).t.getClass()); 1626 } 1627 1628 @Test 1629 public void zscaledNodeShouldSyncAffine3DTransform1() { 1630 final Node node = createTestRect(); 1631 node.setScaleZ(0.5); 1632 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1633 assertSame(Affine3D.class, 1634 ((MockNGRect) node.impl_getPeer()).t.getClass()); 1635 } 1636 1637 @Test 1638 public void zscaledNodeShouldSyncAffine3DTransform2() { 1639 final Node node = createTestRect(); 1640 node.getTransforms().add(new Scale(1, 1, 2)); 1641 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1642 assertSame(Affine3D.class, 1643 ((MockNGRect) node.impl_getPeer()).t.getClass()); 1644 } 1645 1646 @Test 1647 public void nonZRotatedNodeShouldSyncAffine3DTransform1() { 1648 final Node node = createTestRect(); 1649 node.setRotationAxis(Rotate.Y_AXIS); 1650 node.setRotate(10); 1651 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1652 assertSame(Affine3D.class, 1653 ((MockNGRect) node.impl_getPeer()).t.getClass()); 1654 } 1655 1656 @Test 1657 public void nonZRotatedNodeShouldSyncAffine3DTransform2() { 1658 final Node node = createTestRect(); 1659 node.getTransforms().add(new Rotate(10, Rotate.X_AXIS)); 1660 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1661 assertSame(Affine3D.class, 1662 ((MockNGRect) node.impl_getPeer()).t.getClass()); 1663 } 1664 1665 @Test 1666 public void translateTransformShouldBeReusedWhenPossible() { 1667 final Node node = createTestRect(); 1668 node.setTranslateX(10); 1669 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1670 1671 BaseTransform t = ((MockNGRect) node.impl_getPeer()).t; 1672 1673 ((MockNGRect) node.impl_getPeer()).t = null; 1674 node.setTranslateX(20); 1675 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1676 1677 assertSame(t, ((MockNGRect) node.impl_getPeer()).t); 1678 } 1679 1680 @Test 1681 public void affine2DTransformShouldBeReusedWhenPossible() { 1682 final Node node = createTestRect(); 1683 node.setScaleX(10); 1684 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1685 1686 BaseTransform t = ((MockNGRect) node.impl_getPeer()).t; 1687 1688 ((MockNGRect) node.impl_getPeer()).t = null; 1689 node.setRotate(20); 1690 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1691 1692 assertSame(t, ((MockNGRect) node.impl_getPeer()).t); 1693 } 1694 1695 @Test 1696 public void affine3DTransformShouldBeReusedWhenPossible() { 1697 final Node node = createTestRect(); 1698 node.setScaleZ(10); 1699 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1700 1701 BaseTransform t = ((MockNGRect) node.impl_getPeer()).t; 1702 1703 ((MockNGRect) node.impl_getPeer()).t = null; 1704 node.setRotate(20); 1705 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1706 1707 assertSame(t, ((MockNGRect) node.impl_getPeer()).t); 1708 } 1709 1710 @Test 1711 public void rtlSceneSizeShouldBeComputedCorrectly() { 1712 Scene scene = new Scene(new Group(new Rectangle(100, 100))); 1713 scene.setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT); 1714 Stage stage = new Stage(); 1715 stage.setScene(scene); 1716 stage.show(); 1717 assertEquals(100.0, scene.getWidth(), 0.00001); 1718 } 1719 1720 private Node createTestRect() { 1721 final Rectangle rect = new Rectangle() { 1722 @Override protected NGNode impl_createPeer() { 1723 return new MockNGRect(); 1724 } 1725 }; 1726 Scene scene = new Scene(new Group(rect)); 1727 Stage stage = new Stage(); 1728 stage.setScene(scene); 1729 stage.show(); 1730 return rect; 1731 } 1732 1733 private class MockNGRect extends NGRectangle { 1734 double w = 0; 1735 BaseTransform t = null; 1736 1737 @Override public void updateRectangle(float x, float y, float width, 1738 float height, float arcWidth, float arcHeight) { 1739 w = width; 1740 } 1741 1742 @Override 1743 public void setTransformMatrix(BaseTransform tx) { 1744 t = tx; 1745 } 1746 } 1747 }