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