1 /* 2 * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javafx.scene; 27 28 import com.sun.javafx.pgstub.StubToolkit; 29 import com.sun.javafx.sg.prism.NGGroup; 30 import com.sun.javafx.tk.Toolkit; 31 import java.util.concurrent.atomic.AtomicBoolean; 32 import javafx.scene.shape.Rectangle; 33 import javafx.stage.Stage; 34 import org.junit.After; 35 import org.junit.Before; 36 import org.junit.Test; 37 38 import static org.junit.Assert.*; 39 40 public class ParentTest { 41 private StubToolkit toolkit; 42 private Stage stage; 43 44 @Before 45 public void setUp() { 46 toolkit = (StubToolkit) Toolkit.getToolkit(); 47 stage = new Stage(); 48 } 49 50 @After 51 public void tearDown() { 52 stage.close(); 53 } 54 55 @Test 56 public void testGroupLookupCorrectId() { 57 Rectangle rectA = new Rectangle(); 58 Rectangle rectB = new Rectangle(); 59 Rectangle rectC = new Rectangle(); 60 Rectangle rect1 = new Rectangle(); 61 Rectangle rect2 = new Rectangle(); 62 Rectangle rect3 = new Rectangle(); 63 Rectangle rect4 = new Rectangle(); 64 Rectangle rect5 = new Rectangle(); 65 Rectangle rect6 = new Rectangle(); 66 Rectangle rectE = new Rectangle(); 67 Rectangle rectF = new Rectangle(); 68 69 rectA.setId("a"); 70 rectB.setId("b"); 71 rectC.setId("c"); 72 rect1.setId("1"); 73 rect2.setId("2"); 74 rect3.setId("3"); 75 rect4.setId("4"); 76 rect5.setId("5"); 77 rect6.setId("6"); 78 rectE.setId("e"); 79 rectF.setId("f"); 80 81 Group groupD = new Group(rect1, rect2, rect3, rect4, rect5, rect6); 82 groupD.setId("d"); 83 Group group = new Group(rectA, rectB, rectC, groupD, rectE, rectF); 84 85 assertEquals(rect1, group.lookup("#1")); 86 assertEquals(rect2, group.lookup("#2")); 87 assertEquals(rect3, group.lookup("#3")); 88 assertEquals(rect4, group.lookup("#4")); 89 assertEquals(rect5, group.lookup("#5")); 90 assertEquals(rect6, group.lookup("#6")); 91 assertEquals(rectA, group.lookup("#a")); 92 assertEquals(rectB, group.lookup("#b")); 93 assertEquals(rectC, group.lookup("#c")); 94 assertEquals(groupD, group.lookup("#d")); 95 assertEquals(rectE, group.lookup("#e")); 96 assertEquals(rectF, group.lookup("#f")); 97 } 98 99 @Test 100 public void testGroupLookupBadId() { 101 Rectangle rectA = new Rectangle(); 102 Rectangle rectB = new Rectangle(); 103 Rectangle rectC = new Rectangle(); 104 Rectangle rect1 = new Rectangle(); 105 Rectangle rect2 = new Rectangle(); 106 Rectangle rect3 = new Rectangle(); 107 Rectangle rect4 = new Rectangle(); 108 Rectangle rect5 = new Rectangle(); 109 Rectangle rect6 = new Rectangle(); 110 Rectangle rectE = new Rectangle(); 111 Rectangle rectF = new Rectangle(); 112 113 rectA.setId("a"); 114 rectB.setId("b"); 115 rectC.setId("c"); 116 rect1.setId("1"); 117 rect2.setId("2"); 118 rect3.setId("3"); 119 rect4.setId("4"); 120 rect5.setId("5"); 121 rect6.setId("6"); 122 rectE.setId("e"); 123 rectF.setId("f"); 124 125 126 Group groupD = new Group(rect1, rect2, rect3, rect4, rect5, rect6); 127 groupD.setId("d"); 128 Group group = new Group(rectA, rectB, rectC, groupD, rectE, rectF); 129 130 assertNull(group.lookup("#4444")); 131 } 132 133 @Test 134 public void testRemoveChild() { 135 Rectangle rect1 = new Rectangle(); 136 Rectangle rect2 = new Rectangle(); 137 Rectangle rect3 = new Rectangle(); 138 Rectangle rect4 = new Rectangle(); 139 Rectangle rect5 = new Rectangle(); 140 Rectangle rect6 = new Rectangle(); 141 142 Group g = new Group(); 143 Scene s = new Scene(g); 144 stage.setScene(s); 145 stage.show(); 146 147 g.getChildren().addAll(rect1, rect2, rect3, rect4, rect5, rect6); 148 toolkit.fireTestPulse(); 149 150 // try removing node from the end of the observableArrayList 151 g.getChildren().remove(rect6); 152 toolkit.fireTestPulse(); 153 final NGGroup peer = g.impl_getPeer(); 154 assertEquals(5, g.getChildren().size()); 155 assertEquals(5, peer.getChildren().size()); 156 157 // try removing node from the beginning of the observableArrayList 158 g.getChildren().remove(rect1); 159 toolkit.fireTestPulse(); 160 assertEquals(4, g.getChildren().size()); 161 assertEquals(4, peer.getChildren().size()); 162 163 // try removing node from the middle of the observableArrayList 164 g.getChildren().remove(rect3); 165 toolkit.fireTestPulse(); 166 assertEquals(3, g.getChildren().size()); 167 assertEquals(3, peer.getChildren().size()); 168 } 169 170 @Test 171 public void testSetChild() { 172 Rectangle rect1 = new Rectangle(); 173 Rectangle rect2 = new Rectangle(); 174 Rectangle rect3 = new Rectangle(); 175 176 Group g = new Group(); 177 Scene s = new Scene(g); 178 stage.setScene(s); 179 stage.show(); 180 181 g.getChildren().addAll(rect1, rect2); 182 toolkit.fireTestPulse(); 183 184 // try setting node at given index 185 g.getChildren().set(1, rect3); 186 toolkit.fireTestPulse(); 187 assertEquals(2, g.getChildren().size()); 188 assertEquals(2, ((NGGroup)g.impl_getPeer()).getChildren().size()); 189 } 190 191 @Test 192 public void testSetSameChild() { 193 Rectangle rect1 = new Rectangle(); 194 Rectangle rect2 = new Rectangle(); 195 196 Group g = new Group(); 197 Scene s = new Scene(g); 198 stage.setScene(s); 199 stage.show(); 200 201 g.getChildren().addAll(rect1, rect2); 202 toolkit.fireTestPulse(); 203 204 // try setting the same node at given index 205 g.getChildren().set(1, rect2); 206 207 toolkit.fireTestPulse(); 208 assertEquals(2, g.getChildren().size()); 209 assertEquals(2, ((NGGroup)g.impl_getPeer()).getChildren().size()); 210 } 211 212 @Test 213 public void testRemoveAddSameChild() { 214 Rectangle rect1 = new Rectangle(); 215 Rectangle rect2 = new Rectangle(); 216 Rectangle rect3 = new Rectangle(); 217 Rectangle rect4 = new Rectangle(); 218 Rectangle rect5 = new Rectangle(); 219 Rectangle rect6 = new Rectangle(); 220 221 Group g = new Group(); 222 Scene s = new Scene(g); 223 stage.setScene(s); 224 stage.show(); 225 226 g.getChildren().addAll(rect1, rect2, rect3, rect4, rect5, rect6); 227 toolkit.fireTestPulse(); 228 229 // try removing node from the end of the observableArrayList 230 // and add it afterwords 231 g.getChildren().remove(rect6); 232 g.getChildren().add(rect6); 233 toolkit.fireTestPulse(); 234 assertEquals(6, g.getChildren().size()); 235 assertEquals(6, ((NGGroup)g.impl_getPeer()).getChildren().size()); 236 } 237 238 @Test 239 public void testRemoveAddDiferentChild() { 240 Rectangle rect1 = new Rectangle(); 241 Rectangle rect2 = new Rectangle(); 242 Rectangle rect3 = new Rectangle(); 243 Rectangle rect4 = new Rectangle(); 244 Rectangle rect5 = new Rectangle(); 245 Rectangle rect6 = new Rectangle(); 246 247 Group g = new Group(); 248 Scene s = new Scene(g); 249 stage.setScene(s); 250 stage.show(); 251 252 g.getChildren().addAll(rect1, rect2, rect3, rect4, rect5); 253 toolkit.fireTestPulse(); 254 255 // try removing node from the end of the observableArrayList 256 // and add a different one 257 g.getChildren().remove(rect5); 258 g.getChildren().add(rect6); 259 toolkit.fireTestPulse(); 260 assertEquals(5, g.getChildren().size()); 261 assertEquals(5, ((NGGroup)g.impl_getPeer()).getChildren().size()); 262 } 263 264 @Test 265 public void testGetChildrenUnmodifiable() { 266 Rectangle rect1 = new Rectangle(); 267 Rectangle rect2 = new Rectangle(); 268 Rectangle rect3 = new Rectangle(); 269 270 Group g = new Group(); 271 g.getChildren().addAll(rect1,rect2,rect3); 272 273 assertEquals(3, g.getChildrenUnmodifiable().size()); 274 assertSame(rect1, g.getChildrenUnmodifiable().get(0)); 275 assertSame(rect2, g.getChildrenUnmodifiable().get(1)); 276 assertSame(rect3, g.getChildrenUnmodifiable().get(2)); 277 } 278 279 @Test 280 public void testGetChildrenUnmodifiableCantBeModified() { 281 Rectangle rect1 = new Rectangle(); 282 Rectangle rect2 = new Rectangle(); 283 Rectangle rect3 = new Rectangle(); 284 285 Group g = new Group(); 286 g.getChildren().addAll(rect1,rect2,rect3); 287 288 try { 289 g.getChildrenUnmodifiable().add(new Rectangle()); 290 fail("UnsupportedOperationException should have been thrown."); 291 } catch (UnsupportedOperationException uoe) { 292 // expected 293 } 294 } 295 296 @Test 297 public void testRequestLayoutWithoutParent() { 298 Group g = new Group(); 299 g.layout(); 300 // this shouldn't fail even when the group doesn't have a parent 301 g.requestLayout(); 302 } 303 304 @Test 305 public void testRequestLayoutWithoutScene() { 306 Group g = new Group(); 307 g.setManaged(false); 308 g.layout(); 309 // this shouldn't fail even when the scene is not set 310 g.requestLayout(); 311 } 312 313 @Test 314 public void testRequestLayoutClearsCache() { 315 Group g = new Group(); 316 Rectangle r = new Rectangle(100,200); 317 g.getChildren().add(r); 318 319 g.requestLayout(); 320 assertEquals(100, g.prefWidth(-1), 1e-100); 321 assertEquals(200, g.prefHeight(-1), 1e-100); 322 323 r.setWidth(150); 324 r.setHeight(250); 325 g.requestLayout(); 326 327 assertEquals(150, g.prefWidth(-1), 1e-100); 328 assertEquals(250, g.prefHeight(-1), 1e-100); 329 } 330 331 @Test 332 public void testPrefWidthIncludesChildLayoutX() { 333 Rectangle r = new Rectangle(10,10,100,100); 334 r.setLayoutX(10); 335 MockParent p = new MockParent(r); 336 337 assertEquals(120, p.prefWidth(-1), 0); 338 } 339 340 @Test 341 public void testPrefHeightIncludesChildLayoutY() { 342 Rectangle r = new Rectangle(10,10,100,100); 343 r.setLayoutY(10); 344 MockParent p = new MockParent(r); 345 346 assertEquals(120, p.prefHeight(-1), 0); 347 } 348 349 @Test 350 public void testDuplicates() { 351 Group g = new Group(); 352 353 Rectangle r1 = new Rectangle(); 354 Rectangle r2 = new Rectangle(); 355 Rectangle r3 = new Rectangle(); 356 Rectangle r4 = new Rectangle(); 357 358 try { 359 g.getChildren().addAll(r1, r2, r3, r4); 360 g.getChildren().add(r2); 361 fail(); 362 } catch (IllegalArgumentException e) { 363 364 } 365 } 366 367 @Test(expected=NullPointerException.class) 368 public void testAddingNullChild() { 369 Group g = new Group(); 370 g.getChildren().add(null); 371 } 372 373 @Test(expected=NullPointerException.class) 374 public void testNullCheckIsDoneBeforeTestForDuplicates() { 375 Group g = new Group(); 376 g.getChildren().addAll(null, new Rectangle(), null); 377 } 378 379 @Test(expected=IllegalArgumentException.class) 380 public void testAddingClipNodeTwice() { 381 Group g = new Group(); 382 383 Node clipParent = new Rectangle(); 384 Node clipNode = new Rectangle(); 385 386 clipParent.setClip(clipNode); 387 try { 388 // try to add node which is already set as a clip 389 g.getChildren().add(clipNode); 390 fail(); 391 } catch (IllegalArgumentException e) { 392 } 393 394 // try again 395 g.getChildren().add(clipNode); 396 } 397 398 @Test 399 public void testAddingFixedClipNode() { 400 Group g = new Group(); 401 402 Node clipParent = new Rectangle(); 403 Node clipNode = new Rectangle(); 404 405 clipParent.setClip(clipNode); 406 try { 407 // try to add node which is already set as a clip 408 g.getChildren().add(clipNode); 409 fail(); 410 } catch (IllegalArgumentException e) { 411 } 412 413 // fix the problem and add again 414 clipParent.setClip(null); 415 g.getChildren().add(clipNode); 416 } 417 418 @Test(expected=IllegalArgumentException.class) 419 public void testFalsePermutation() { 420 Group g = new Group(); 421 422 Rectangle r1 = new Rectangle(); 423 Rectangle r2 = new Rectangle(); 424 Rectangle r3 = new Rectangle(); 425 Rectangle r4 = new Rectangle(); 426 427 g.getChildren().addAll(r1, r2, r3, r4); 428 g.getChildren().setAll(r1, r2, r2, r4); 429 } 430 431 @Test 432 public void testFalseDuplicates() { 433 Group g = new Group(); 434 435 Rectangle r1 = new Rectangle(); 436 Rectangle r2 = new Rectangle(); 437 Rectangle r3 = new Rectangle(); 438 Rectangle r4 = new Rectangle(); 439 440 g.getChildren().addAll(r1, r2); 441 try { 442 g.getChildren().addAll(r3, r4, r2); 443 fail(); 444 } catch (IllegalArgumentException e) { 445 } 446 try { 447 g.getChildren().add(r3); 448 } catch (IllegalArgumentException e) { 449 fail(); 450 } 451 452 } 453 454 @Test 455 public void nodeCanBeAddedDuringLayout() { 456 final Rectangle rect = new Rectangle(100, 100); 457 final Group g = new Group(rect); 458 459 Group root = new Group() { 460 @Override protected void layoutChildren() { 461 getChildren().setAll(g); 462 } 463 }; 464 465 Scene scene = new Scene(root); 466 467 stage.setScene(scene); 468 stage.show(); 469 470 // there are assertions tested down the stack (see RT-21746) 471 } 472 473 private static class LGroup extends Group { 474 475 private boolean layoutCalled; 476 477 @Override 478 public void requestLayout() { 479 super.requestLayout(); 480 layoutCalled = true; 481 } 482 483 public void assertAndClear(boolean b) { 484 assertEquals(b, layoutCalled); 485 layoutCalled = false; 486 } 487 488 public void clear() { 489 layoutCalled = false; 490 } 491 492 } 493 494 @Test 495 public void requestLayoutAlwaysCalledUpToTheLayoutRoot() { 496 final Group root = new Group(); 497 final LGroup lroot = new LGroup(); 498 lroot.setManaged(false); 499 root.getChildren().add(lroot); 500 final LGroup sub = new LGroup(); 501 lroot.getChildren().add(sub); 502 503 lroot.clear(); 504 sub.clear(); 505 root.layout(); 506 507 lroot.assertAndClear(false); 508 sub.assertAndClear(false); 509 510 sub.requestLayout(); 511 512 lroot.assertAndClear(true); 513 sub.assertAndClear(true); 514 515 sub.requestLayout(); 516 lroot.assertAndClear(true); 517 sub.assertAndClear(true); 518 } 519 520 @Test 521 public void unmanagedParentTest() { 522 final LGroup innerGroup = new LGroup(); 523 innerGroup.setManaged(false); 524 525 final LGroup outerGroup = new LGroup(); 526 outerGroup.setManaged(false); 527 528 Scene s = new Scene(outerGroup); 529 530 innerGroup.assertAndClear(false); 531 outerGroup.assertAndClear(true); 532 533 outerGroup.getChildren().add(innerGroup); 534 innerGroup.requestLayout(); 535 536 innerGroup.assertAndClear(true); 537 outerGroup.assertAndClear(true); 538 539 outerGroup.getChildren().remove(innerGroup); 540 541 innerGroup.assertAndClear(false); 542 outerGroup.assertAndClear(false); 543 544 final LGroup intermediate = new LGroup(); 545 intermediate.setManaged(false); 546 intermediate.setAutoSizeChildren(false); 547 outerGroup.getChildren().add(intermediate); 548 549 innerGroup.assertAndClear(false); 550 intermediate.assertAndClear(true); 551 outerGroup.assertAndClear(true); 552 553 innerGroup.requestLayout(); 554 intermediate.getChildren().add(innerGroup); 555 556 innerGroup.assertAndClear(true); 557 intermediate.assertAndClear(true); 558 outerGroup.assertAndClear(false); 559 560 } 561 562 @Test 563 public void requestLayoutTriggersPulse() { 564 final Group root = new Group(); 565 final LGroup lroot = new LGroup(); 566 lroot.setManaged(false); 567 root.getChildren().add(lroot); 568 final LGroup sub = new LGroup(); 569 lroot.getChildren().add(sub); 570 571 toolkit.clearPulseRequested(); 572 sub.requestLayout(); 573 Scene scene = new Scene(root); 574 assertTrue(toolkit.isPulseRequested()); 575 toolkit.clearPulseRequested(); 576 root.layout(); 577 578 sub.requestLayout(); 579 580 assertTrue(toolkit.isPulseRequested()); 581 } 582 583 @Test 584 public void requestLayoutNotPropagatingDuringLayout() { 585 final LGroup lroot = new LGroup(); 586 lroot.setManaged(false); 587 final LGroup sub = new LGroup() { 588 589 @Override 590 protected void layoutChildren() { 591 super.layoutChildren(); 592 requestLayout(); 593 } 594 595 }; 596 lroot.getChildren().add(sub); 597 lroot.clear(); 598 sub.clear(); 599 600 sub.requestLayout(); 601 lroot.assertAndClear(true); 602 sub.assertAndClear(true); 603 604 lroot.layout(); 605 606 lroot.assertAndClear(false); 607 sub.assertAndClear(true); 608 } 609 610 @Test 611 public void testChildrenPermutationInvalidatesManagedChildrenAndLayout() { 612 LGroup root = new LGroup(); 613 Rectangle r1 = new Rectangle(); 614 Rectangle r2 = new Rectangle(); 615 616 root.getChildren().addAll(r1, r2); 617 618 root.clear(); 619 620 root.getManagedChildren().equals(root.getChildren()); 621 622 root.getChildren().setAll(r2, r1); 623 624 root.getManagedChildren().equals(root.getChildren()); 625 root.assertAndClear(true); 626 627 r2.toFront(); 628 629 root.getManagedChildren().equals(root.getChildren()); 630 root.assertAndClear(true); 631 } 632 633 @Test 634 public void newChildInvalidatesLayoutWhenLayoutBoundsAreValidatedImmediately() { 635 Group root = new Group(); 636 final AtomicBoolean layoutCalled = new AtomicBoolean(); 637 final AtomicBoolean testReady = new AtomicBoolean(); 638 LGroup sub = new LGroup() { 639 640 @Override 641 protected void layoutChildren() { 642 if (testReady.get()) { 643 assertAndClear(true); 644 layoutCalled.set(true); 645 } 646 } 647 648 }; 649 root.getChildren().add(sub); 650 root.getLayoutBounds(); // validate 651 sub.getBoundsInParent(); // validate 652 653 root.layoutBoundsProperty().addListener((observable, oldValue, newValue) -> { 654 // ChangeListener will immediately validate the bounds 655 }); 656 sub.clear(); 657 658 testReady.set(true); 659 sub.getChildren().add(new Rectangle()); 660 assertTrue(layoutCalled.get()); 661 } 662 663 @Test 664 public void sceneListenerCanAddChild() { 665 final Group root = new Group(); 666 final Scene scene = new Scene(root, 600, 450); 667 668 final Group child = new Group(new Group(), new Group(), new Group()); 669 670 child.getChildren().get(1).sceneProperty().addListener(o -> child.getChildren().add(2, new Group())); 671 672 root.getChildren().add(child); 673 674 assertSame(scene, child.getChildren().get(3).getScene()); 675 } 676 677 public static class MockParent extends Parent { 678 public MockParent(Node... children) { 679 getChildren().addAll(children); 680 } 681 } 682 }