1 /* 2 * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javafx.scene.control; 27 28 import com.sun.javafx.application.PlatformImpl; 29 import com.sun.javafx.scene.control.behavior.TreeCellBehavior; 30 import com.sun.javafx.scene.control.infrastructure.KeyEventFirer; 31 import com.sun.javafx.scene.control.infrastructure.KeyModifier; 32 import com.sun.javafx.scene.control.infrastructure.StageLoader; 33 import com.sun.javafx.scene.control.infrastructure.VirtualFlowTestUtils; 34 import javafx.scene.control.skin.TextFieldSkin; 35 import com.sun.javafx.scene.control.test.Employee; 36 import com.sun.javafx.scene.control.test.Person; 37 import com.sun.javafx.scene.control.test.RT_22463_Person; 38 import com.sun.javafx.tk.Toolkit; 39 40 import java.util.*; 41 import java.util.stream.Collectors; 42 43 import javafx.application.Platform; 44 import javafx.beans.InvalidationListener; 45 import javafx.beans.Observable; 46 import static com.sun.javafx.scene.control.infrastructure.ControlTestUtils.assertStyleClassContains; 47 import static org.junit.Assert.*; 48 import static org.junit.Assert.assertEquals; 49 50 import javafx.beans.binding.Bindings; 51 import javafx.beans.property.ObjectProperty; 52 import javafx.beans.property.ReadOnlyBooleanWrapper; 53 import javafx.beans.property.SimpleObjectProperty; 54 import javafx.collections.FXCollections; 55 import javafx.collections.ListChangeListener; 56 import javafx.collections.ObservableList; 57 import javafx.event.ActionEvent; 58 import javafx.scene.Group; 59 import javafx.scene.Node; 60 import javafx.scene.Scene; 61 import javafx.scene.control.cell.CheckBoxTreeCell; 62 import javafx.scene.control.cell.TextFieldTreeCell; 63 import com.sun.javafx.scene.control.VirtualScrollBar; 64 import javafx.scene.image.ImageView; 65 import javafx.scene.input.KeyCode; 66 import javafx.scene.layout.VBox; 67 import javafx.scene.paint.Color; 68 import javafx.scene.shape.Circle; 69 import javafx.scene.shape.Rectangle; 70 import javafx.stage.Stage; 71 import javafx.util.Callback; 72 73 import org.junit.Before; 74 import org.junit.Ignore; 75 import org.junit.Test; 76 77 public class TreeViewTest { 78 private TreeView<String> treeView; 79 private MultipleSelectionModel<TreeItem<String>> sm; 80 private FocusModel<TreeItem<String>> fm; 81 82 // sample data #1 83 private TreeItem<String> root; 84 private TreeItem<String> child1; 85 private TreeItem<String> child2; 86 private TreeItem<String> child3; 87 88 // sample data #1 89 private TreeItem<String> myCompanyRootNode; 90 private TreeItem<String> salesDepartment; 91 private TreeItem<String> ethanWilliams; 92 private TreeItem<String> emmaJones; 93 private TreeItem<String> michaelBrown; 94 private TreeItem<String> annaBlack; 95 private TreeItem<String> rodgerYork; 96 private TreeItem<String> susanCollins; 97 98 private TreeItem<String> itSupport; 99 private TreeItem<String> mikeGraham; 100 private TreeItem<String> judyMayer; 101 private TreeItem<String> gregorySmith; 102 103 private String debug() { 104 StringBuilder sb = new StringBuilder("Selected Indices: ["); 105 106 List<Integer> indices = sm.getSelectedIndices(); 107 for (Integer index : indices) { 108 sb.append(index); 109 sb.append(", "); 110 } 111 112 sb.append("] \nFocus: " + fm.getFocusedIndex()); 113 // sb.append(" \nAnchor: " + getAnchor()); 114 return sb.toString(); 115 } 116 117 @Before public void setup() { 118 treeView = new TreeView<String>(); 119 sm = treeView.getSelectionModel(); 120 fm = treeView.getFocusModel(); 121 122 // build sample data #2, even though it may not be used... 123 myCompanyRootNode = new TreeItem<String>("MyCompany Human Resources"); 124 salesDepartment = new TreeItem<String>("Sales Department"); 125 ethanWilliams = new TreeItem<String>("Ethan Williams"); 126 emmaJones = new TreeItem<String>("Emma Jones"); 127 michaelBrown = new TreeItem<String>("Michael Brown"); 128 annaBlack = new TreeItem<String>("Anna Black"); 129 rodgerYork = new TreeItem<String>("Rodger York"); 130 susanCollins = new TreeItem<String>("Susan Collins"); 131 132 itSupport = new TreeItem<String>("IT Support"); 133 mikeGraham = new TreeItem<String>("Mike Graham"); 134 judyMayer = new TreeItem<String>("Judy Mayer"); 135 gregorySmith = new TreeItem<String>("Gregory Smith"); 136 137 myCompanyRootNode.getChildren().setAll( 138 salesDepartment, 139 itSupport 140 ); 141 salesDepartment.getChildren().setAll( 142 ethanWilliams, 143 emmaJones, 144 michaelBrown, 145 annaBlack, 146 rodgerYork, 147 susanCollins 148 ); 149 itSupport.getChildren().setAll( 150 mikeGraham, 151 judyMayer, 152 gregorySmith 153 ); 154 } 155 156 private void installChildren() { 157 root = new TreeItem<String>("Root"); 158 child1 = new TreeItem<String>("Child 1"); 159 child2 = new TreeItem<String>("Child 2"); 160 child3 = new TreeItem<String>("Child 3"); 161 root.setExpanded(true); 162 root.getChildren().setAll(child1, child2, child3); 163 treeView.setRoot(root); 164 } 165 166 @Test public void ensureCorrectInitialState() { 167 installChildren(); 168 assertEquals(0, treeView.getRow(root)); 169 assertEquals(1, treeView.getRow(child1)); 170 assertEquals(2, treeView.getRow(child2)); 171 assertEquals(3, treeView.getRow(child3)); 172 } 173 174 /********************************************************************* 175 * Tests for the constructors * 176 ********************************************************************/ 177 178 @Test public void noArgConstructorSetsTheStyleClass() { 179 assertStyleClassContains(treeView, "tree-view"); 180 } 181 182 @Test public void noArgConstructorSetsNonNullSelectionModel() { 183 assertNotNull(treeView.getSelectionModel()); 184 } 185 186 @Test public void noArgConstructorSetsNullItems() { 187 assertNull(treeView.getRoot()); 188 } 189 190 @Test public void noArgConstructor_selectedItemIsNull() { 191 assertNull(treeView.getSelectionModel().getSelectedItem()); 192 } 193 194 @Test public void noArgConstructor_selectedIndexIsNegativeOne() { 195 assertEquals(-1, treeView.getSelectionModel().getSelectedIndex()); 196 } 197 198 @Test public void singleArgConstructorSetsTheStyleClass() { 199 final TreeView<String> b2 = new TreeView<>(new TreeItem<>("Hi")); 200 assertStyleClassContains(b2, "tree-view"); 201 } 202 203 @Test public void singleArgConstructorSetsNonNullSelectionModel() { 204 final TreeView<String> b2 = new TreeView<>(new TreeItem<>("Hi")); 205 assertNotNull(b2.getSelectionModel()); 206 } 207 208 @Test public void singleArgConstructorAllowsNullItems() { 209 final TreeView<String> b2 = new TreeView<>(null); 210 assertNull(b2.getRoot()); 211 } 212 213 @Test public void singleArgConstructor_selectedItemIsNotNull() { 214 TreeItem<String> hiItem = new TreeItem<>("Hi"); 215 final TreeView<String> b2 = new TreeView<>(hiItem); 216 assertNull(b2.getSelectionModel().getSelectedItem()); 217 } 218 219 @Test public void singleArgConstructor_selectedIndexIsZero() { 220 final TreeView<String> b2 = new TreeView<>(new TreeItem<>("Hi")); 221 assertEquals(-1, b2.getSelectionModel().getSelectedIndex()); 222 } 223 224 /********************************************************************* 225 * Tests for selection model * 226 ********************************************************************/ 227 228 @Test public void selectionModelCanBeNull() { 229 treeView.setSelectionModel(null); 230 assertNull(treeView.getSelectionModel()); 231 } 232 233 @Test public void selectionModelCanBeBound() { 234 MultipleSelectionModel<TreeItem<String>> sm = new TreeView.TreeViewBitSetSelectionModel<String>(treeView); 235 ObjectProperty<MultipleSelectionModel<TreeItem<String>>> other = new SimpleObjectProperty<MultipleSelectionModel<TreeItem<String>>>(sm); 236 treeView.selectionModelProperty().bind(other); 237 assertSame(sm, treeView.getSelectionModel()); 238 } 239 240 @Test public void selectionModelCanBeChanged() { 241 MultipleSelectionModel<TreeItem<String>> sm = new TreeView.TreeViewBitSetSelectionModel<String>(treeView); 242 treeView.setSelectionModel(sm); 243 assertSame(sm, treeView.getSelectionModel()); 244 } 245 246 @Test public void canSetSelectedItemToAnItemEvenWhenThereAreNoItems() { 247 TreeItem<String> element = new TreeItem<String>("I AM A CRAZY RANDOM STRING"); 248 treeView.getSelectionModel().select(element); 249 assertEquals(-1, treeView.getSelectionModel().getSelectedIndex()); 250 assertSame(element, treeView.getSelectionModel().getSelectedItem()); 251 } 252 253 @Test public void canSetSelectedItemToAnItemNotInTheDataModel() { 254 installChildren(); 255 TreeItem<String> element = new TreeItem<String>("I AM A CRAZY RANDOM STRING"); 256 treeView.getSelectionModel().select(element); 257 assertEquals(-1, treeView.getSelectionModel().getSelectedIndex()); 258 assertSame(element, treeView.getSelectionModel().getSelectedItem()); 259 } 260 261 @Test public void settingTheSelectedItemToAnItemInItemsResultsInTheCorrectSelectedIndex() { 262 installChildren(); 263 treeView.getSelectionModel().select(child1); 264 assertEquals(1, treeView.getSelectionModel().getSelectedIndex()); 265 assertSame(child1, treeView.getSelectionModel().getSelectedItem()); 266 } 267 268 @Ignore("Not yet supported") 269 @Test public void settingTheSelectedItemToANonexistantItemAndThenSettingItemsWhichContainsItResultsInCorrectSelectedIndex() { 270 treeView.getSelectionModel().select(child1); 271 installChildren(); 272 assertEquals(1, treeView.getSelectionModel().getSelectedIndex()); 273 assertSame(child1, treeView.getSelectionModel().getSelectedItem()); 274 } 275 276 @Ignore("Not yet supported") 277 @Test public void ensureSelectionClearsWhenAllItemsAreRemoved_selectIndex0() { 278 installChildren(); 279 treeView.getSelectionModel().select(0); 280 treeView.setRoot(null); 281 assertEquals(-1, treeView.getSelectionModel().getSelectedIndex()); 282 assertEquals(null, treeView.getSelectionModel().getSelectedItem()); 283 } 284 285 @Ignore("Not yet supported") 286 @Test public void ensureSelectionClearsWhenAllItemsAreRemoved_selectIndex2() { 287 installChildren(); 288 treeView.getSelectionModel().select(2); 289 treeView.setRoot(null); 290 assertEquals(-1, treeView.getSelectionModel().getSelectedIndex()); 291 assertEquals(null, treeView.getSelectionModel().getSelectedItem()); 292 } 293 294 @Ignore("Not yet supported") 295 @Test public void ensureSelectedItemRemainsAccurateWhenItemsAreCleared() { 296 installChildren(); 297 treeView.getSelectionModel().select(2); 298 treeView.setRoot(null); 299 assertNull(treeView.getSelectionModel().getSelectedItem()); 300 assertEquals(-1, treeView.getSelectionModel().getSelectedIndex()); 301 302 TreeItem<String> newRoot = new TreeItem<String>("New Root"); 303 TreeItem<String> newChild1 = new TreeItem<String>("New Child 1"); 304 TreeItem<String> newChild2 = new TreeItem<String>("New Child 2"); 305 TreeItem<String> newChild3 = new TreeItem<String>("New Child 3"); 306 newRoot.setExpanded(true); 307 newRoot.getChildren().setAll(newChild1, newChild2, newChild3); 308 treeView.setRoot(root); 309 310 treeView.getSelectionModel().select(2); 311 assertEquals(newChild2, treeView.getSelectionModel().getSelectedItem()); 312 } 313 314 @Test public void ensureSelectionIsCorrectWhenItemsChange() { 315 installChildren(); 316 treeView.getSelectionModel().select(0); 317 assertEquals(root, treeView.getSelectionModel().getSelectedItem()); 318 319 TreeItem newRoot = new TreeItem<>("New Root"); 320 treeView.setRoot(newRoot); 321 assertEquals(-1, treeView.getSelectionModel().getSelectedIndex()); 322 assertNull(treeView.getSelectionModel().getSelectedItem()); 323 } 324 325 @Test public void ensureSelectionRemainsOnBranchWhenExpanded() { 326 installChildren(); 327 root.setExpanded(false); 328 treeView.getSelectionModel().select(0); 329 assertTrue(treeView.getSelectionModel().isSelected(0)); 330 root.setExpanded(true); 331 assertTrue(treeView.getSelectionModel().isSelected(0)); 332 assertTrue(treeView.getSelectionModel().getSelectedItems().contains(root)); 333 } 334 335 /********************************************************************* 336 * Tests for misc * 337 ********************************************************************/ 338 @Test public void ensureRootIndexIsZeroWhenRootIsShowing() { 339 installChildren(); 340 assertEquals(0, treeView.getRow(root)); 341 } 342 343 @Test public void ensureRootIndexIsNegativeOneWhenRootIsNotShowing() { 344 installChildren(); 345 treeView.setShowRoot(false); 346 assertEquals(-1, treeView.getRow(root)); 347 } 348 349 @Test public void ensureCorrectIndexWhenRootTreeItemHasParent() { 350 installChildren(); 351 treeView.setRoot(child1); 352 assertEquals(-1, treeView.getRow(root)); 353 assertEquals(0, treeView.getRow(child1)); 354 assertEquals(1, treeView.getRow(child2)); 355 assertEquals(2, treeView.getRow(child3)); 356 } 357 358 @Test public void ensureCorrectIndexWhenRootTreeItemHasParentAndRootIsNotShowing() { 359 installChildren(); 360 treeView.setRoot(child1); 361 treeView.setShowRoot(false); 362 363 // despite the fact there are children in this tree, in reality none are 364 // visible as the root node has no children (only siblings), and the 365 // root node is not visible. 366 assertEquals(0, treeView.getExpandedItemCount()); 367 368 assertEquals(-1, treeView.getRow(root)); 369 assertEquals(-1, treeView.getRow(child1)); 370 assertEquals(-1, treeView.getRow(child2)); 371 assertEquals(-1, treeView.getRow(child3)); 372 } 373 374 @Test public void ensureCorrectIndexWhenRootTreeItemIsCollapsed() { 375 installChildren(); 376 root.setExpanded(false); 377 assertEquals(0, treeView.getRow(root)); 378 379 // note that the indices are negative, as these children rows are not 380 // visible in the tree 381 assertEquals(-1, treeView.getRow(child1)); 382 assertEquals(-1, treeView.getRow(child2)); 383 assertEquals(-1, treeView.getRow(child3)); 384 } 385 386 @Test public void removingLastTest() { 387 TreeView tree_view = new TreeView(); 388 MultipleSelectionModel sm = tree_view.getSelectionModel(); 389 TreeItem<String> tree_model = new TreeItem<String>("Root"); 390 TreeItem node = new TreeItem("Data item"); 391 tree_model.getChildren().add(node); 392 tree_view.setRoot(tree_model); 393 tree_model.setExpanded(true); 394 // select the 'Data item' in the selection model 395 sm.select(tree_model.getChildren().get(0)); 396 // remove the 'Data item' from the root node 397 tree_model.getChildren().remove(sm.getSelectedItem()); 398 399 // Previously the selection was cleared, but this was changed to instead 400 // move the selection upwards. 401 // assert the there are no selected items any longer 402 // assertTrue("items: " + sm.getSelectedItem(), sm.getSelectedItems().isEmpty()); 403 assertEquals(tree_model, sm.getSelectedItem()); 404 } 405 406 /********************************************************************* 407 * Tests from bug reports * 408 ********************************************************************/ 409 @Ignore @Test public void test_rt17112() { 410 TreeItem<String> root1 = new TreeItem<String>("Root"); 411 root1.setExpanded(true); 412 addChildren(root1, "child"); 413 for (TreeItem child : root1.getChildren()) { 414 addChildren(child, (String)child.getValue()); 415 child.setExpanded(true); 416 } 417 418 final TreeView treeView1 = new TreeView(); 419 final MultipleSelectionModel sm = treeView1.getSelectionModel(); 420 sm.setSelectionMode(SelectionMode.MULTIPLE); 421 treeView1.setRoot(root1); 422 423 final TreeItem<String> rt17112_child1 = root1.getChildren().get(1); 424 final TreeItem<String> rt17112_child1_0 = rt17112_child1.getChildren().get(0); 425 final TreeItem<String> rt17112_child2 = root1.getChildren().get(2); 426 427 sm.getSelectedItems().addListener(new InvalidationListener() { 428 int count = 0; 429 @Override public void invalidated(Observable observable) { 430 if (count == 0) { 431 assertEquals(rt17112_child1_0, sm.getSelectedItem()); 432 assertEquals(1, sm.getSelectedIndices().size()); 433 assertEquals(6, sm.getSelectedIndex()); 434 assertTrue(treeView1.getFocusModel().isFocused(6)); 435 } else if (count == 1) { 436 assertEquals(rt17112_child1, sm.getSelectedItem()); 437 assertFalse(sm.getSelectedItems().contains(rt17112_child2)); 438 assertEquals(1, sm.getSelectedIndices().size()); 439 assertTrue(treeView1.getFocusModel().isFocused(5)); 440 } 441 count++; 442 } 443 }); 444 445 // this triggers the first callback above, so that count == 0 446 sm.select(rt17112_child1_0); 447 448 // this triggers the second callback above, so that count == 1 449 rt17112_child1.setExpanded(false); 450 } 451 private void addChildren(TreeItem parent, String name) { 452 for (int i=0; i<3; i++) { 453 TreeItem<String> ti = new TreeItem<String>(name+"-"+i); 454 parent.getChildren().add(ti); 455 } 456 } 457 458 @Test public void test_rt17522_focusShouldMoveWhenItemAddedAtFocusIndex() { 459 installChildren(); 460 FocusModel fm = treeView.getFocusModel(); 461 fm.focus(1); // focus on child1 462 assertTrue(fm.isFocused(1)); 463 assertEquals(child1, fm.getFocusedItem()); 464 465 TreeItem child0 = new TreeItem("child0"); 466 root.getChildren().add(0, child0); // 0th index == position of child1 in root 467 468 assertEquals(child1, fm.getFocusedItem()); 469 assertTrue(fm.isFocused(2)); 470 } 471 472 @Test public void test_rt17522_focusShouldMoveWhenItemAddedBeforeFocusIndex() { 473 installChildren(); 474 FocusModel fm = treeView.getFocusModel(); 475 fm.focus(1); // focus on child1 476 assertTrue(fm.isFocused(1)); 477 478 TreeItem child0 = new TreeItem("child0"); 479 root.getChildren().add(0, child0); 480 assertTrue("Focused index: " + fm.getFocusedIndex(), fm.isFocused(2)); 481 } 482 483 @Test public void test_rt17522_focusShouldNotMoveWhenItemAddedAfterFocusIndex() { 484 installChildren(); 485 FocusModel fm = treeView.getFocusModel(); 486 fm.focus(1); // focus on child1 487 assertTrue(fm.isFocused(1)); 488 489 TreeItem child4 = new TreeItem("child4"); 490 root.getChildren().add(3, child4); 491 assertTrue("Focused index: " + fm.getFocusedIndex(), fm.isFocused(1)); 492 } 493 494 @Test public void test_rt17522_focusShouldBeMovedWhenFocusedItemIsRemoved_1() { 495 installChildren(); 496 FocusModel fm = treeView.getFocusModel(); 497 fm.focus(1); 498 assertTrue(fm.isFocused(1)); 499 500 root.getChildren().remove(child1); 501 assertEquals(0, fm.getFocusedIndex()); 502 assertEquals(treeView.getTreeItem(0), fm.getFocusedItem()); 503 } 504 505 @Test public void test_rt17522_focusShouldMoveWhenItemRemovedBeforeFocusIndex() { 506 installChildren(); 507 FocusModel fm = treeView.getFocusModel(); 508 fm.focus(2); 509 assertTrue(fm.isFocused(2)); 510 511 root.getChildren().remove(child1); 512 assertTrue(fm.isFocused(1)); 513 assertEquals(child2, fm.getFocusedItem()); 514 } 515 516 // This test fails as, in TreeView FocusModel, we do not know the index of the 517 // removed tree items, which means we don't know whether they existed before 518 // or after the focused item. 519 // @Test public void test_rt17522_focusShouldNotMoveWhenItemRemovedAfterFocusIndex() { 520 // installChildren(); 521 // FocusModel fm = treeView.getFocusModel(); 522 // fm.focus(1); 523 // assertTrue(fm.isFocused(1)); 524 // 525 // root.getChildren().remove(child3); 526 // assertTrue("Focused index: " + fm.getFocusedIndex(), fm.isFocused(1)); 527 // assertEquals(child1, fm.getFocusedItem()); 528 // } 529 530 @Test public void test_rt18385() { 531 installChildren(); 532 // table.getItems().addAll("row1", "row2", "row3"); 533 treeView.getSelectionModel().select(1); 534 treeView.getRoot().getChildren().add(new TreeItem("Another Row")); 535 assertEquals(1, treeView.getSelectionModel().getSelectedIndices().size()); 536 assertEquals(1, treeView.getSelectionModel().getSelectedItems().size()); 537 } 538 539 @Test public void test_rt18339_onlyEditWhenTreeViewIsEditable_editableIsFalse() { 540 treeView.setEditable(false); 541 treeView.edit(root); 542 assertEquals(null, treeView.getEditingItem()); 543 } 544 545 @Test public void test_rt18339_onlyEditWhenTreeViewIsEditable_editableIsTrue() { 546 treeView.setEditable(true); 547 treeView.edit(root); 548 assertEquals(root, treeView.getEditingItem()); 549 } 550 551 @Test public void test_rt14451() { 552 installChildren(); 553 treeView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); 554 treeView.getSelectionModel().selectRange(0, 2); // select from 0 (inclusive) to 2 (exclusive) 555 assertEquals(2, treeView.getSelectionModel().getSelectedIndices().size()); 556 } 557 558 @Test public void test_rt21586() { 559 installChildren(); 560 treeView.getSelectionModel().select(1); 561 assertEquals(1, treeView.getSelectionModel().getSelectedIndex()); 562 assertEquals(child1, treeView.getSelectionModel().getSelectedItem()); 563 564 TreeItem root = new TreeItem<>("New Root"); 565 TreeItem child1 = new TreeItem<>("New Child 1"); 566 TreeItem child2 = new TreeItem<>("New Child 2"); 567 TreeItem child3 = new TreeItem<>("New Child 3"); 568 root.setExpanded(true); 569 root.getChildren().setAll(child1, child2, child3); 570 treeView.setRoot(root); 571 assertEquals(-1, treeView.getSelectionModel().getSelectedIndex()); 572 assertNull(treeView.getSelectionModel().getSelectedItem()); 573 } 574 575 @Test public void test_rt27181() { 576 myCompanyRootNode.setExpanded(true); 577 treeView.setRoot(myCompanyRootNode); 578 579 // start test 580 salesDepartment.setExpanded(true); 581 treeView.getSelectionModel().select(salesDepartment); 582 583 assertEquals(1, treeView.getFocusModel().getFocusedIndex()); 584 itSupport.setExpanded(true); 585 assertEquals(1, treeView.getFocusModel().getFocusedIndex()); 586 } 587 588 @Test public void test_rt27185() { 589 myCompanyRootNode.setExpanded(true); 590 treeView.setRoot(myCompanyRootNode); 591 592 // start test 593 itSupport.setExpanded(true); 594 treeView.getSelectionModel().select(mikeGraham); 595 596 assertEquals(mikeGraham, treeView.getFocusModel().getFocusedItem()); 597 salesDepartment.setExpanded(true); 598 assertEquals(mikeGraham, treeView.getFocusModel().getFocusedItem()); 599 } 600 601 @Ignore("Bug hasn't been fixed yet") 602 @Test public void test_rt28114() { 603 myCompanyRootNode.setExpanded(true); 604 treeView.setRoot(myCompanyRootNode); 605 606 // start test 607 itSupport.setExpanded(true); 608 treeView.getSelectionModel().select(itSupport); 609 assertEquals(itSupport, treeView.getFocusModel().getFocusedItem()); 610 assertEquals(itSupport, treeView.getSelectionModel().getSelectedItem()); 611 assertTrue(! itSupport.isLeaf()); 612 assertTrue(itSupport.isExpanded()); 613 614 itSupport.getChildren().remove(mikeGraham); 615 assertEquals(itSupport, treeView.getFocusModel().getFocusedItem()); 616 assertEquals(itSupport, treeView.getSelectionModel().getSelectedItem()); 617 assertTrue(itSupport.isLeaf()); 618 assertTrue(!itSupport.isExpanded()); 619 } 620 621 @Test public void test_rt27820_1() { 622 TreeItem root = new TreeItem("root"); 623 root.setExpanded(true); 624 TreeItem child = new TreeItem("child"); 625 root.getChildren().add(child); 626 treeView.setRoot(root); 627 628 treeView.getSelectionModel().select(0); 629 assertEquals(1, treeView.getSelectionModel().getSelectedItems().size()); 630 assertEquals(root, treeView.getSelectionModel().getSelectedItem()); 631 632 treeView.setRoot(null); 633 assertEquals(0, treeView.getSelectionModel().getSelectedItems().size()); 634 assertNull(treeView.getSelectionModel().getSelectedItem()); 635 } 636 637 @Test public void test_rt27820_2() { 638 TreeItem root = new TreeItem("root"); 639 root.setExpanded(true); 640 TreeItem child = new TreeItem("child"); 641 root.getChildren().add(child); 642 treeView.setRoot(root); 643 644 treeView.getSelectionModel().select(1); 645 assertEquals(1, treeView.getSelectionModel().getSelectedItems().size()); 646 assertEquals(child, treeView.getSelectionModel().getSelectedItem()); 647 648 treeView.setRoot(null); 649 assertEquals(0, treeView.getSelectionModel().getSelectedItems().size()); 650 assertNull(treeView.getSelectionModel().getSelectedItem()); 651 } 652 653 @Test public void test_rt28390() { 654 // There should be no NPE when a TreeView is shown and the disclosure 655 // node is null in a TreeCell 656 TreeItem root = new TreeItem("root"); 657 treeView.setRoot(root); 658 659 // install a custom cell factory that forces the disclosure node to be 660 // null (because by default a null disclosure node will be replaced by 661 // a non-null one). 662 treeView.setCellFactory(new Callback() { 663 @Override public Object call(Object p) { 664 TreeCell treeCell = new TreeCell() { 665 { 666 disclosureNodeProperty().addListener((ov, t, t1) -> { 667 setDisclosureNode(null); 668 }); 669 } 670 671 @Override protected void updateItem(Object item, boolean empty) { 672 super.updateItem(item, empty); 673 setText(item == null ? "" : item.toString()); 674 } 675 }; 676 treeCell.setDisclosureNode(null); 677 return treeCell; 678 } 679 }); 680 681 try { 682 Group group = new Group(); 683 group.getChildren().setAll(treeView); 684 Scene scene = new Scene(group); 685 Stage stage = new Stage(); 686 stage.setScene(scene); 687 stage.show(); 688 } catch (NullPointerException e) { 689 System.out.println("A null disclosure node is valid, so we shouldn't have an NPE here."); 690 e.printStackTrace(); 691 assertTrue(false); 692 } 693 } 694 695 @Test public void test_rt28534() { 696 TreeItem root = new TreeItem("root"); 697 root.getChildren().setAll( 698 new TreeItem(new Person("Jacob", "Smith", "jacob.smith@example.com")), 699 new TreeItem(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), 700 new TreeItem(new Person("Ethan", "Williams", "ethan.williams@example.com")), 701 new TreeItem(new Person("Emma", "Jones", "emma.jones@example.com")), 702 new TreeItem(new Person("Michael", "Brown", "michael.brown@example.com"))); 703 root.setExpanded(true); 704 705 TreeView<Person> tree = new TreeView<Person>(root); 706 707 VirtualFlowTestUtils.assertRowsNotEmpty(tree, 0, 6); // rows 0 - 6 should be filled 708 VirtualFlowTestUtils.assertRowsEmpty(tree, 6, -1); // rows 6+ should be empty 709 710 // now we replace the data and expect the cells that have no data 711 // to be empty 712 root.getChildren().setAll( 713 new TreeItem(new Person("*_*Emma", "Jones", "emma.jones@example.com")), 714 new TreeItem(new Person("_Michael", "Brown", "michael.brown@example.com"))); 715 716 VirtualFlowTestUtils.assertRowsNotEmpty(tree, 0, 3); // rows 0 - 3 should be filled 717 VirtualFlowTestUtils.assertRowsEmpty(tree, 3, -1); // rows 3+ should be empty 718 } 719 720 @Test public void test_rt28556() { 721 List<Employee> employees = Arrays.<Employee>asList( 722 new Employee("Ethan Williams", "Sales Department"), 723 new Employee("Emma Jones", "Sales Department"), 724 new Employee("Michael Brown", "Sales Department"), 725 new Employee("Anna Black", "Sales Department"), 726 new Employee("Rodger York", "Sales Department"), 727 new Employee("Susan Collins", "Sales Department"), 728 new Employee("Mike Graham", "IT Support"), 729 new Employee("Judy Mayer", "IT Support"), 730 new Employee("Gregory Smith", "IT Support"), 731 new Employee("Jacob Smith", "Accounts Department"), 732 new Employee("Isabella Johnson", "Accounts Department")); 733 734 TreeItem<String> rootNode = new TreeItem<String>("MyCompany Human Resources"); 735 rootNode.setExpanded(true); 736 737 List<TreeItem<String>> nodeList = FXCollections.observableArrayList(); 738 for (Employee employee : employees) { 739 nodeList.add(new TreeItem<String>(employee.getName())); 740 } 741 rootNode.getChildren().setAll(nodeList); 742 743 TreeView<String> treeView = new TreeView<String>(rootNode); 744 745 final double indent = PlatformImpl.isCaspian() ? 31 : 746 PlatformImpl.isModena() ? 35 : 747 0; 748 749 // ensure all children of the root node have the correct indentation 750 // before the sort occurs 751 VirtualFlowTestUtils.assertLayoutX(treeView, 1, 11, indent); 752 for (TreeItem<String> children : rootNode.getChildren()) { 753 assertEquals(rootNode, children.getParent()); 754 } 755 756 // run sort 757 Collections.sort(rootNode.getChildren(), (o1, o2) -> o1.getValue().compareTo(o2.getValue())); 758 759 // ensure the same indentation exists after the sort (which is where the 760 // bug is - it drops down to 21.0px indentation when it shouldn't). 761 VirtualFlowTestUtils.assertLayoutX(treeView, 1, 11, indent); 762 for (TreeItem<String> children : rootNode.getChildren()) { 763 assertEquals(rootNode, children.getParent()); 764 } 765 } 766 767 @Test public void test_rt22463() { 768 RT_22463_Person rootPerson = new RT_22463_Person(); 769 rootPerson.setName("Root"); 770 TreeItem<RT_22463_Person> root = new TreeItem<RT_22463_Person>(rootPerson); 771 root.setExpanded(true); 772 773 final TreeView<RT_22463_Person> tree = new TreeView<RT_22463_Person>(); 774 tree.setRoot(root); 775 776 // before the change things display fine 777 RT_22463_Person p1 = new RT_22463_Person(); 778 p1.setId(1l); 779 p1.setName("name1"); 780 RT_22463_Person p2 = new RT_22463_Person(); 781 p2.setId(2l); 782 p2.setName("name2"); 783 root.getChildren().addAll( 784 new TreeItem<RT_22463_Person>(p1), 785 new TreeItem<RT_22463_Person>(p2)); 786 VirtualFlowTestUtils.assertCellTextEquals(tree, 1, "name1"); 787 VirtualFlowTestUtils.assertCellTextEquals(tree, 2, "name2"); 788 789 // now we change the persons but they are still equal as the ID's don't 790 // change - but the items list is cleared so the cells should update 791 RT_22463_Person new_p1 = new RT_22463_Person(); 792 new_p1.setId(1l); 793 new_p1.setName("updated name1"); 794 RT_22463_Person new_p2 = new RT_22463_Person(); 795 new_p2.setId(2l); 796 new_p2.setName("updated name2"); 797 root.getChildren().clear(); 798 root.getChildren().setAll( 799 new TreeItem<RT_22463_Person>(new_p1), 800 new TreeItem<RT_22463_Person>(new_p2)); 801 VirtualFlowTestUtils.assertCellTextEquals(tree, 1, "updated name1"); 802 VirtualFlowTestUtils.assertCellTextEquals(tree, 2, "updated name2"); 803 } 804 805 @Test public void test_rt28637() { 806 TreeItem<String> s1, s2, s3, s4; 807 ObservableList<TreeItem<String>> items = FXCollections.observableArrayList( 808 s1 = new TreeItem<String>("String1"), 809 s2 = new TreeItem<String>("String2"), 810 s3 = new TreeItem<String>("String3"), 811 s4 = new TreeItem<String>("String4")); 812 813 final TreeView<String> treeView = new TreeView<String>(); 814 815 TreeItem<String> root = new TreeItem<String>("Root"); 816 root.setExpanded(true); 817 treeView.setRoot(root); 818 treeView.setShowRoot(false); 819 root.getChildren().addAll(items); 820 821 treeView.getSelectionModel().select(0); 822 assertEquals((Object)s1, treeView.getSelectionModel().getSelectedItem()); 823 assertEquals((Object)s1, treeView.getSelectionModel().getSelectedItems().get(0)); 824 assertEquals(0, treeView.getSelectionModel().getSelectedIndex()); 825 826 root.getChildren().remove(treeView.getSelectionModel().getSelectedItem()); 827 assertEquals((Object)s2, treeView.getSelectionModel().getSelectedItem()); 828 assertEquals((Object)s2, treeView.getSelectionModel().getSelectedItems().get(0)); 829 assertEquals(0, treeView.getSelectionModel().getSelectedIndex()); 830 } 831 832 @Ignore("Test passes from within IDE but not when run from command line. Needs more investigation.") 833 @Test public void test_rt28678() { 834 TreeItem<String> s1, s2, s3, s4; 835 ObservableList<TreeItem<String>> items = FXCollections.observableArrayList( 836 s1 = new TreeItem<String>("String1"), 837 s2 = new TreeItem<String>("String2"), 838 s3 = new TreeItem<String>("String3"), 839 s4 = new TreeItem<String>("String4")); 840 841 final TreeView<String> treeView = new TreeView<String>(); 842 843 TreeItem<String> root = new TreeItem<String>("Root"); 844 root.setExpanded(true); 845 treeView.setRoot(root); 846 treeView.setShowRoot(false); 847 root.getChildren().addAll(items); 848 849 Node graphic = new Circle(6, Color.RED); 850 851 assertNull(s2.getGraphic()); 852 TreeCell s2Cell = (TreeCell) VirtualFlowTestUtils.getCell(treeView, 1); 853 assertNull(s2Cell.getGraphic()); 854 855 s2.setGraphic(graphic); 856 Toolkit.getToolkit().firePulse(); 857 858 assertEquals(graphic, s2.getGraphic()); 859 assertEquals(graphic, s2Cell.getGraphic()); 860 } 861 862 @Test public void test_rt29390() { 863 ObservableList<TreeItem<Person>> persons = FXCollections.observableArrayList( 864 new TreeItem<Person>(new Person("Jacob", "Smith", "jacob.smith@example.com")), 865 new TreeItem<Person>(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), 866 new TreeItem<Person>(new Person("Ethan", "Williams", "ethan.williams@example.com")), 867 new TreeItem<Person>(new Person("Emma", "Jones", "emma.jones@example.com")), 868 new TreeItem<Person>(new Person("Jacob", "Smith", "jacob.smith@example.com")), 869 new TreeItem<Person>(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), 870 new TreeItem<Person>(new Person("Ethan", "Williams", "ethan.williams@example.com")), 871 new TreeItem<Person>(new Person("Emma", "Jones", "emma.jones@example.com")), 872 new TreeItem<Person>(new Person("Jacob", "Smith", "jacob.smith@example.com")), 873 new TreeItem<Person>(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), 874 new TreeItem<Person>(new Person("Ethan", "Williams", "ethan.williams@example.com")), 875 new TreeItem<Person>(new Person("Emma", "Jones", "emma.jones@example.com")), 876 new TreeItem<Person>(new Person("Jacob", "Smith", "jacob.smith@example.com")), 877 new TreeItem<Person>(new Person("Isabella", "Johnson", "isabella.johnson@example.com")), 878 new TreeItem<Person>(new Person("Ethan", "Williams", "ethan.williams@example.com")), 879 new TreeItem<Person>(new Person("Emma", "Jones", "emma.jones@example.com") 880 )); 881 882 TreeView<Person> treeView = new TreeView<>(); 883 treeView.setMaxHeight(50); 884 treeView.setPrefHeight(50); 885 886 TreeItem<Person> root = new TreeItem<Person>(new Person("Root", null, null)); 887 root.setExpanded(true); 888 treeView.setRoot(root); 889 treeView.setShowRoot(false); 890 root.getChildren().setAll(persons); 891 892 Toolkit.getToolkit().firePulse(); 893 894 // we want the vertical scrollbar 895 VirtualScrollBar scrollBar = VirtualFlowTestUtils.getVirtualFlowVerticalScrollbar(treeView); 896 897 assertNotNull(scrollBar); 898 assertTrue(scrollBar.isVisible()); 899 assertTrue(scrollBar.getVisibleAmount() > 0.0); 900 assertTrue(scrollBar.getVisibleAmount() < 1.0); 901 902 // this next test is likely to be brittle, but we'll see...If it is the 903 // cause of failure then it can be commented out 904 assertEquals(0.125, scrollBar.getVisibleAmount(), 0.0); 905 } 906 907 @Test public void test_rt27180_collapseBranch_childSelected_singleSelection() { 908 sm.setSelectionMode(SelectionMode.SINGLE); 909 910 treeView.setRoot(myCompanyRootNode); 911 myCompanyRootNode.setExpanded(true); 912 salesDepartment.setExpanded(true); 913 itSupport.setExpanded(true); 914 sm.select(2); // ethanWilliams 915 assertFalse(sm.isSelected(1)); // salesDepartment 916 assertTrue(sm.isSelected(2)); // ethanWilliams 917 assertTrue(treeView.getFocusModel().isFocused(2)); 918 assertEquals(1, sm.getSelectedIndices().size()); 919 920 // now collapse the salesDepartment, selection should 921 // not jump down to the itSupport people 922 salesDepartment.setExpanded(false); 923 assertTrue(sm.isSelected(1)); // salesDepartment 924 assertTrue(treeView.getFocusModel().isFocused(1)); 925 assertEquals(1, sm.getSelectedIndices().size()); 926 } 927 928 @Test public void test_rt27180_collapseBranch_laterSiblingSelected_singleSelection() { 929 sm.setSelectionMode(SelectionMode.SINGLE); 930 931 treeView.setRoot(myCompanyRootNode); 932 myCompanyRootNode.setExpanded(true); 933 salesDepartment.setExpanded(true); 934 itSupport.setExpanded(true); 935 sm.select(8); // itSupport 936 assertFalse(sm.isSelected(1)); // salesDepartment 937 assertTrue(sm.isSelected(8)); // itSupport 938 assertTrue(treeView.getFocusModel().isFocused(8)); 939 assertEquals(1, sm.getSelectedIndices().size()); 940 941 salesDepartment.setExpanded(false); 942 assertTrue(sm.isSelected(2)); // itSupport 943 assertTrue(treeView.getFocusModel().isFocused(2)); 944 assertEquals(1, sm.getSelectedIndices().size()); 945 } 946 947 @Test public void test_rt27180_collapseBranch_laterSiblingAndChildrenSelected() { 948 sm.setSelectionMode(SelectionMode.MULTIPLE); 949 950 treeView.setRoot(myCompanyRootNode); 951 treeView.getSelectionModel().clearSelection(); 952 953 myCompanyRootNode.setExpanded(true); 954 salesDepartment.setExpanded(true); 955 itSupport.setExpanded(true); 956 sm.selectIndices(8, 9, 10); // itSupport, and two people 957 assertFalse(sm.isSelected(1)); // salesDepartment 958 assertTrue(sm.isSelected(8)); // itSupport 959 assertTrue(sm.isSelected(9)); // mikeGraham 960 assertTrue(sm.isSelected(10)); // judyMayer 961 assertTrue(treeView.getFocusModel().isFocused(10)); 962 assertEquals(3, sm.getSelectedIndices().size()); 963 964 salesDepartment.setExpanded(false); 965 assertTrue(sm.isSelected(2)); // itSupport 966 assertTrue(sm.isSelected(3)); // mikeGraham 967 assertTrue(sm.isSelected(4)); // judyMayer 968 assertTrue(treeView.getFocusModel().isFocused(4)); 969 assertEquals(3, sm.getSelectedIndices().size()); 970 } 971 972 @Test public void test_rt27180_expandBranch_laterSiblingSelected_singleSelection() { 973 sm.setSelectionMode(SelectionMode.SINGLE); 974 975 treeView.setRoot(myCompanyRootNode); 976 myCompanyRootNode.setExpanded(true); 977 salesDepartment.setExpanded(false); 978 itSupport.setExpanded(true); 979 sm.select(2); // itSupport 980 assertFalse(sm.isSelected(1)); // salesDepartment 981 assertTrue(sm.isSelected(2)); // itSupport 982 assertTrue(treeView.getFocusModel().isFocused(2)); 983 assertEquals(1, sm.getSelectedIndices().size()); 984 985 salesDepartment.setExpanded(true); 986 assertTrue(sm.isSelected(8)); // itSupport 987 assertTrue(treeView.getFocusModel().isFocused(8)); 988 assertEquals(1, sm.getSelectedIndices().size()); 989 } 990 991 @Test public void test_rt27180_expandBranch_laterSiblingAndChildrenSelected() { 992 sm.setSelectionMode(SelectionMode.MULTIPLE); 993 994 treeView.setRoot(myCompanyRootNode); 995 treeView.getSelectionModel().clearSelection(); 996 997 myCompanyRootNode.setExpanded(true); 998 salesDepartment.setExpanded(false); 999 itSupport.setExpanded(true); 1000 sm.selectIndices(2,3,4); // itSupport, and two people 1001 assertFalse(sm.isSelected(1)); // salesDepartment 1002 assertTrue(sm.isSelected(2)); // itSupport 1003 assertTrue(sm.isSelected(3)); // mikeGraham 1004 assertTrue(sm.isSelected(4)); // judyMayer 1005 assertTrue(treeView.getFocusModel().isFocused(4)); 1006 assertEquals(3, sm.getSelectedIndices().size()); 1007 1008 salesDepartment.setExpanded(true); 1009 assertTrue(sm.isSelected(8)); // itSupport 1010 assertTrue(sm.isSelected(9)); // mikeGraham 1011 assertTrue(sm.isSelected(10)); // judyMayer 1012 assertTrue(treeView.getFocusModel().isFocused(10)); 1013 assertEquals(3, sm.getSelectedIndices().size()); 1014 } 1015 1016 @Test public void test_rt30400() { 1017 // create a treeview that'll render cells using the check box cell factory 1018 TreeItem<String> rootItem = new TreeItem<>("root"); 1019 treeView.setRoot(rootItem); 1020 treeView.setMinHeight(100); 1021 treeView.setPrefHeight(100); 1022 treeView.setCellFactory( 1023 CheckBoxTreeCell.forTreeView( 1024 param -> new ReadOnlyBooleanWrapper(true))); 1025 1026 // because only the first row has data, all other rows should be 1027 // empty (and not contain check boxes - we just check the first four here) 1028 VirtualFlowTestUtils.assertRowsNotEmpty(treeView, 0, 1); 1029 VirtualFlowTestUtils.assertCellNotEmpty(VirtualFlowTestUtils.getCell(treeView, 0)); 1030 VirtualFlowTestUtils.assertCellEmpty(VirtualFlowTestUtils.getCell(treeView, 1)); 1031 VirtualFlowTestUtils.assertCellEmpty(VirtualFlowTestUtils.getCell(treeView, 2)); 1032 VirtualFlowTestUtils.assertCellEmpty(VirtualFlowTestUtils.getCell(treeView, 3)); 1033 } 1034 1035 @Test public void test_rt31165() { 1036 installChildren(); 1037 treeView.setEditable(true); 1038 treeView.setCellFactory(TextFieldTreeCell.forTreeView()); 1039 1040 IndexedCell cell = VirtualFlowTestUtils.getCell(treeView, 1); 1041 assertEquals(child1.getValue(), cell.getText()); 1042 assertFalse(cell.isEditing()); 1043 1044 treeView.edit(child1); 1045 1046 assertEquals(child1, treeView.getEditingItem()); 1047 assertTrue(cell.isEditing()); 1048 1049 VirtualFlowTestUtils.getVirtualFlow(treeView).requestLayout(); 1050 Toolkit.getToolkit().firePulse(); 1051 1052 assertEquals(child1, treeView.getEditingItem()); 1053 assertTrue(cell.isEditing()); 1054 } 1055 1056 @Test public void test_rt31404() { 1057 installChildren(); 1058 1059 IndexedCell cell = VirtualFlowTestUtils.getCell(treeView, 0); 1060 assertEquals("Root", cell.getText()); 1061 1062 treeView.setShowRoot(false); 1063 assertEquals("Child 1", cell.getText()); 1064 } 1065 1066 @Test public void test_rt31471() { 1067 installChildren(); 1068 1069 IndexedCell cell = VirtualFlowTestUtils.getCell(treeView, 0); 1070 assertEquals("Root", cell.getItem()); 1071 1072 treeView.setFixedCellSize(50); 1073 1074 VirtualFlowTestUtils.getVirtualFlow(treeView).requestLayout(); 1075 Toolkit.getToolkit().firePulse(); 1076 1077 assertEquals("Root", cell.getItem()); 1078 assertEquals(50, cell.getHeight(), 0.00); 1079 } 1080 1081 private int rt_31200_count = 0; 1082 @Test public void test_rt_31200_tableRow() { 1083 installChildren(); 1084 treeView.setCellFactory(new Callback<TreeView<String>, TreeCell<String>>() { 1085 @Override 1086 public TreeCell<String> call(TreeView<String> param) { 1087 return new TreeCell<String>() { 1088 ImageView view = new ImageView(); 1089 { setGraphic(view); }; 1090 1091 @Override 1092 protected void updateItem(String item, boolean empty) { 1093 if (getItem() == null ? item == null : getItem().equals(item)) { 1094 rt_31200_count++; 1095 } 1096 super.updateItem(item, empty); 1097 if (item == null || empty) { 1098 view.setImage(null); 1099 setText(null); 1100 } else { 1101 setText(item.toString()); 1102 } 1103 } 1104 }; 1105 } 1106 }); 1107 1108 StageLoader sl = new StageLoader(treeView); 1109 1110 assertEquals(24, rt_31200_count); 1111 1112 // resize the stage 1113 sl.getStage().setHeight(250); 1114 Toolkit.getToolkit().firePulse(); 1115 sl.getStage().setHeight(50); 1116 Toolkit.getToolkit().firePulse(); 1117 assertEquals(24, rt_31200_count); 1118 1119 sl.dispose(); 1120 } 1121 1122 @Test public void test_rt_30484() { 1123 installChildren(); 1124 treeView.setCellFactory(new Callback<TreeView<String>, TreeCell<String>>() { 1125 @Override public TreeCell<String> call(TreeView<String> param) { 1126 return new TreeCell<String>() { 1127 Rectangle graphic = new Rectangle(10, 10, Color.RED); 1128 { setGraphic(graphic); }; 1129 1130 @Override protected void updateItem(String item, boolean empty) { 1131 super.updateItem(item, empty); 1132 if (item == null || empty) { 1133 graphic.setVisible(false); 1134 setText(null); 1135 } else { 1136 graphic.setVisible(true); 1137 setText(item); 1138 } 1139 } 1140 }; 1141 } 1142 }); 1143 1144 // First two four have content, so the graphic should show. 1145 // All other rows have no content, so graphic should not show. 1146 1147 VirtualFlowTestUtils.assertGraphicIsVisible(treeView, 0); 1148 VirtualFlowTestUtils.assertGraphicIsVisible(treeView, 1); 1149 VirtualFlowTestUtils.assertGraphicIsVisible(treeView, 2); 1150 VirtualFlowTestUtils.assertGraphicIsVisible(treeView, 3); 1151 VirtualFlowTestUtils.assertGraphicIsNotVisible(treeView, 4); 1152 VirtualFlowTestUtils.assertGraphicIsNotVisible(treeView, 5); 1153 } 1154 1155 private int rt_29650_start_count = 0; 1156 private int rt_29650_commit_count = 0; 1157 private int rt_29650_cancel_count = 0; 1158 @Test public void test_rt_29650() { 1159 installChildren(); 1160 treeView.setOnEditStart(t -> { 1161 rt_29650_start_count++; 1162 }); 1163 treeView.setOnEditCommit(t -> { 1164 rt_29650_commit_count++; 1165 }); 1166 treeView.setOnEditCancel(t -> { 1167 rt_29650_cancel_count++; 1168 }); 1169 1170 treeView.setEditable(true); 1171 treeView.setCellFactory(TextFieldTreeCell.forTreeView()); 1172 1173 StageLoader sl = new StageLoader(treeView); 1174 1175 treeView.edit(root); 1176 TreeCell rootCell = (TreeCell) VirtualFlowTestUtils.getCell(treeView, 0); 1177 TextField textField = (TextField) rootCell.getGraphic(); 1178 textField.setSkin(new TextFieldSkin(textField)); 1179 textField.setText("Testing!"); 1180 KeyEventFirer keyboard = new KeyEventFirer(textField); 1181 keyboard.doKeyPress(KeyCode.ENTER); 1182 1183 assertEquals("Testing!", root.getValue()); 1184 assertEquals(1, rt_29650_start_count); 1185 assertEquals(1, rt_29650_commit_count); 1186 assertEquals(0, rt_29650_cancel_count); 1187 1188 sl.dispose(); 1189 } 1190 1191 private int rt_33559_count = 0; 1192 @Test public void test_rt_33559() { 1193 installChildren(); 1194 1195 treeView.setShowRoot(true); 1196 final MultipleSelectionModel sm = treeView.getSelectionModel(); 1197 sm.setSelectionMode(SelectionMode.MULTIPLE); 1198 sm.clearAndSelect(0); 1199 1200 treeView.getSelectionModel().getSelectedItems().addListener((ListChangeListener) c -> { 1201 while (c.next()) { 1202 System.out.println(c); 1203 rt_33559_count++; 1204 } 1205 }); 1206 1207 assertEquals(0, rt_33559_count); 1208 root.setExpanded(true); 1209 assertEquals(0, rt_33559_count); 1210 } 1211 1212 @Test public void test_rt34103() { 1213 treeView.setRoot(new TreeItem("Root")); 1214 treeView.getRoot().setExpanded(true); 1215 1216 for (int i = 0; i < 4; i++) { 1217 TreeItem parent = new TreeItem("item - " + i); 1218 treeView.getRoot().getChildren().add(parent); 1219 1220 for (int j = 0; j < 4; j++) { 1221 TreeItem child = new TreeItem("item - " + i + " " + j); 1222 parent.getChildren().add(child); 1223 } 1224 } 1225 1226 treeView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); 1227 1228 TreeItem item0 = treeView.getTreeItem(1); 1229 assertEquals("item - 0", item0.getValue()); 1230 item0.setExpanded(true); 1231 1232 treeView.getSelectionModel().clearSelection(); 1233 treeView.getSelectionModel().selectIndices(1,2,3); 1234 assertEquals(3, treeView.getSelectionModel().getSelectedIndices().size()); 1235 1236 item0.setExpanded(false); 1237 Toolkit.getToolkit().firePulse(); 1238 assertEquals(1, treeView.getSelectionModel().getSelectedIndices().size()); 1239 } 1240 1241 @Test public void test_rt26718() { 1242 treeView.setRoot(new TreeItem("Root")); 1243 treeView.getRoot().setExpanded(true); 1244 1245 for (int i = 0; i < 4; i++) { 1246 TreeItem parent = new TreeItem("item - " + i); 1247 treeView.getRoot().getChildren().add(parent); 1248 1249 for (int j = 0; j < 4; j++) { 1250 TreeItem child = new TreeItem("item - " + i + " " + j); 1251 parent.getChildren().add(child); 1252 } 1253 } 1254 1255 treeView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); 1256 1257 final TreeItem item0 = treeView.getTreeItem(1); 1258 final TreeItem item1 = treeView.getTreeItem(2); 1259 1260 assertEquals("item - 0", item0.getValue()); 1261 assertEquals("item - 1", item1.getValue()); 1262 1263 item0.setExpanded(true); 1264 item1.setExpanded(true); 1265 Toolkit.getToolkit().firePulse(); 1266 1267 treeView.getSelectionModel().selectRange(0, 8); 1268 assertEquals(8, treeView.getSelectionModel().getSelectedIndices().size()); 1269 assertEquals(7, treeView.getSelectionModel().getSelectedIndex()); 1270 assertEquals(7, treeView.getFocusModel().getFocusedIndex()); 1271 1272 // collapse item0 - but because the selected and focused indices are 1273 // not children of item 0, they should remain where they are (but of 1274 // course be shifted up). The bug was that focus was moving up to item0, 1275 // which makes no sense 1276 item0.setExpanded(false); 1277 Toolkit.getToolkit().firePulse(); 1278 assertEquals(3, treeView.getSelectionModel().getSelectedIndex()); 1279 assertEquals(3, treeView.getFocusModel().getFocusedIndex()); 1280 } 1281 1282 @Test public void test_rt26721_collapseParent_firstRootChild() { 1283 treeView.setRoot(new TreeItem("Root")); 1284 treeView.getRoot().setExpanded(true); 1285 1286 for (int i = 0; i < 4; i++) { 1287 TreeItem parent = new TreeItem("item - " + i); 1288 treeView.getRoot().getChildren().add(parent); 1289 1290 for (int j = 0; j < 4; j++) { 1291 TreeItem child = new TreeItem("item - " + i + " " + j); 1292 parent.getChildren().add(child); 1293 } 1294 } 1295 1296 treeView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); 1297 1298 final TreeItem<String> item0 = treeView.getTreeItem(1); 1299 final TreeItem<String> item0child0 = item0.getChildren().get(0); 1300 final TreeItem<String> item1 = treeView.getTreeItem(2); 1301 1302 assertEquals("item - 0", item0.getValue()); 1303 assertEquals("item - 1", item1.getValue()); 1304 1305 item0.setExpanded(true); 1306 item1.setExpanded(true); 1307 Toolkit.getToolkit().firePulse(); 1308 1309 // select the first child of item0 1310 treeView.getSelectionModel().select(item0child0); 1311 1312 assertEquals(item0child0, treeView.getSelectionModel().getSelectedItem()); 1313 assertEquals(item0child0, treeView.getFocusModel().getFocusedItem()); 1314 1315 // collapse item0 - we expect the selection / focus to move up to item0 1316 item0.setExpanded(false); 1317 Toolkit.getToolkit().firePulse(); 1318 assertEquals(item0, treeView.getSelectionModel().getSelectedItem()); 1319 assertEquals(item0, treeView.getFocusModel().getFocusedItem()); 1320 } 1321 1322 @Test public void test_rt26721_collapseParent_lastRootChild() { 1323 treeView.setRoot(new TreeItem("Root")); 1324 treeView.getRoot().setExpanded(true); 1325 1326 for (int i = 0; i < 4; i++) { 1327 TreeItem parent = new TreeItem("item - " + i); 1328 treeView.getRoot().getChildren().add(parent); 1329 1330 for (int j = 0; j < 4; j++) { 1331 TreeItem child = new TreeItem("item - " + i + " " + j); 1332 parent.getChildren().add(child); 1333 } 1334 } 1335 1336 treeView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); 1337 1338 final TreeItem<String> item3 = treeView.getTreeItem(4); 1339 final TreeItem<String> item3child0 = item3.getChildren().get(0); 1340 1341 assertEquals("item - 3", item3.getValue()); 1342 assertEquals("item - 3 0", item3child0.getValue()); 1343 1344 item3.setExpanded(true); 1345 Toolkit.getToolkit().firePulse(); 1346 1347 // select the first child of item0 1348 treeView.getSelectionModel().select(item3child0); 1349 1350 assertEquals(item3child0, treeView.getSelectionModel().getSelectedItem()); 1351 assertEquals(item3child0, treeView.getFocusModel().getFocusedItem()); 1352 1353 // collapse item3 - we expect the selection / focus to move up to item3 1354 item3.setExpanded(false); 1355 Toolkit.getToolkit().firePulse(); 1356 assertEquals(item3, treeView.getSelectionModel().getSelectedItem()); 1357 assertEquals(item3, treeView.getFocusModel().getFocusedItem()); 1358 } 1359 1360 @Test public void test_rt26721_collapseGrandParent() { 1361 treeView.setRoot(new TreeItem("Root")); 1362 treeView.getRoot().setExpanded(true); 1363 1364 for (int i = 0; i < 4; i++) { 1365 TreeItem parent = new TreeItem("item - " + i); 1366 treeView.getRoot().getChildren().add(parent); 1367 1368 for (int j = 0; j < 4; j++) { 1369 TreeItem child = new TreeItem("item - " + i + " " + j); 1370 parent.getChildren().add(child); 1371 } 1372 } 1373 1374 treeView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); 1375 1376 final TreeItem<String> item0 = treeView.getTreeItem(1); 1377 final TreeItem<String> item0child0 = item0.getChildren().get(0); 1378 final TreeItem<String> item1 = treeView.getTreeItem(2); 1379 1380 assertEquals("item - 0", item0.getValue()); 1381 assertEquals("item - 1", item1.getValue()); 1382 1383 item0.setExpanded(true); 1384 item1.setExpanded(true); 1385 Toolkit.getToolkit().firePulse(); 1386 1387 // select the first child of item0 1388 treeView.getSelectionModel().select(item0child0); 1389 1390 assertEquals(item0child0, treeView.getSelectionModel().getSelectedItem()); 1391 assertEquals(item0child0, treeView.getFocusModel().getFocusedItem()); 1392 1393 // collapse root - we expect the selection / focus to move up to root 1394 treeView.getRoot().setExpanded(false); 1395 Toolkit.getToolkit().firePulse(); 1396 assertEquals(treeView.getRoot(), treeView.getSelectionModel().getSelectedItem()); 1397 assertEquals(treeView.getRoot(), treeView.getFocusModel().getFocusedItem()); 1398 } 1399 1400 @Test public void test_rt34694() { 1401 TreeItem treeNode = new TreeItem("Controls"); 1402 treeNode.getChildren().addAll( 1403 new TreeItem("Button"), 1404 new TreeItem("ButtonBar"), 1405 new TreeItem("LinkBar"), 1406 new TreeItem("LinkButton"), 1407 new TreeItem("PopUpButton"), 1408 new TreeItem("ToggleButtonBar") 1409 ); 1410 1411 final TreeView treeView = new TreeView(); 1412 treeView.setRoot(treeNode); 1413 treeNode.setExpanded(true); 1414 1415 treeView.getSelectionModel().select(0); 1416 assertTrue(treeView.getSelectionModel().isSelected(0)); 1417 assertTrue(treeView.getFocusModel().isFocused(0)); 1418 1419 treeNode.getChildren().clear(); 1420 treeNode.getChildren().addAll( 1421 new TreeItem("Button1"), 1422 new TreeItem("ButtonBar1"), 1423 new TreeItem("LinkBar1"), 1424 new TreeItem("LinkButton1"), 1425 new TreeItem("PopUpButton1"), 1426 new TreeItem("ToggleButtonBar1") 1427 ); 1428 Toolkit.getToolkit().firePulse(); 1429 1430 assertTrue(treeView.getSelectionModel().isSelected(0)); 1431 assertTrue(treeView.getFocusModel().isFocused(0)); 1432 } 1433 1434 private int test_rt_35213_eventCount = 0; 1435 @Test public void test_rt35213() { 1436 final TreeView<String> view = new TreeView<>(); 1437 1438 TreeItem<String> root = new TreeItem<>("Boss"); 1439 view.setRoot(root); 1440 1441 TreeItem<String> group1 = new TreeItem<>("Group 1"); 1442 TreeItem<String> group2 = new TreeItem<>("Group 2"); 1443 TreeItem<String> group3 = new TreeItem<>("Group 3"); 1444 1445 root.getChildren().addAll(group1, group2, group3); 1446 1447 TreeItem<String> employee1 = new TreeItem<>("Employee 1"); 1448 TreeItem<String> employee2 = new TreeItem<>("Employee 2"); 1449 1450 group2.getChildren().addAll(employee1, employee2); 1451 1452 view.expandedItemCountProperty().addListener((observableValue, oldCount, newCount) -> { 1453 1454 // DEBUG OUTPUT 1455 // System.out.println("new expanded item count: " + newCount.intValue()); 1456 // for (int i = 0; i < newCount.intValue(); i++) { 1457 // TreeItem<String> item = view.getTreeItem(i); 1458 // String text = item.getValue(); 1459 // System.out.println("person found at index " + i + " is " + text); 1460 // } 1461 // System.out.println("------------------------------------------"); 1462 1463 if (test_rt_35213_eventCount == 0) { 1464 assertEquals(4, newCount); 1465 assertEquals("Boss", view.getTreeItem(0).getValue()); 1466 assertEquals("Group 1", view.getTreeItem(1).getValue()); 1467 assertEquals("Group 2", view.getTreeItem(2).getValue()); 1468 assertEquals("Group 3", view.getTreeItem(3).getValue()); 1469 } else if (test_rt_35213_eventCount == 1) { 1470 assertEquals(6, newCount); 1471 assertEquals("Boss", view.getTreeItem(0).getValue()); 1472 assertEquals("Group 1", view.getTreeItem(1).getValue()); 1473 assertEquals("Group 2", view.getTreeItem(2).getValue()); 1474 assertEquals("Employee 1", view.getTreeItem(3).getValue()); 1475 assertEquals("Employee 2", view.getTreeItem(4).getValue()); 1476 assertEquals("Group 3", view.getTreeItem(5).getValue()); 1477 } else if (test_rt_35213_eventCount == 2) { 1478 assertEquals(4, newCount); 1479 assertEquals("Boss", view.getTreeItem(0).getValue()); 1480 assertEquals("Group 1", view.getTreeItem(1).getValue()); 1481 assertEquals("Group 2", view.getTreeItem(2).getValue()); 1482 assertEquals("Group 3", view.getTreeItem(3).getValue()); 1483 } 1484 1485 test_rt_35213_eventCount++; 1486 }); 1487 1488 StageLoader sl = new StageLoader(view); 1489 1490 root.setExpanded(true); 1491 Toolkit.getToolkit().firePulse(); 1492 1493 group2.setExpanded(true); 1494 Toolkit.getToolkit().firePulse(); 1495 1496 group2.setExpanded(false); 1497 Toolkit.getToolkit().firePulse(); 1498 1499 sl.dispose(); 1500 } 1501 1502 @Test public void test_rt23245_itemIsInTree() { 1503 final TreeView<String> view = new TreeView<String>(); 1504 final List<TreeItem<String>> items = new ArrayList<>(); 1505 for (int i = 0; i < 10; i++) { 1506 final TreeItem<String> item = new TreeItem<String>("Item" + i); 1507 item.setExpanded(true); 1508 items.add(item); 1509 } 1510 1511 // link the items up so that the next item is the child of the current item 1512 for (int i = 0; i < 9; i++) { 1513 items.get(i).getChildren().add(items.get(i + 1)); 1514 } 1515 1516 view.setRoot(items.get(0)); 1517 1518 for (int i = 0; i < 10; i++) { 1519 // we expect the level of the tree item at the ith position to be 1520 // 0, as every iteration we are setting the ith item as the root. 1521 assertEquals(0, view.getTreeItemLevel(items.get(i))); 1522 1523 // whilst we are testing, we should also ensure that the ith item 1524 // is indeed the root item, and that the ith item is indeed the item 1525 // at the 0th position 1526 assertEquals(items.get(i), view.getRoot()); 1527 assertEquals(items.get(i), view.getTreeItem(0)); 1528 1529 // shuffle the next item into the root position (keeping its parent 1530 // chain intact - which is what exposes this issue in the first place). 1531 if (i < 9) { 1532 view.setRoot(items.get(i + 1)); 1533 } 1534 } 1535 } 1536 1537 @Test public void test_rt23245_itemIsNotInTree_noRootNode() { 1538 final TreeView<String> view = new TreeView<String>(); 1539 final List<TreeItem<String>> items = new ArrayList<>(); 1540 for (int i = 0; i < 10; i++) { 1541 final TreeItem<String> item = new TreeItem<String>("Item" + i); 1542 item.setExpanded(true); 1543 items.add(item); 1544 } 1545 1546 // link the items up so that the next item is the child of the current item 1547 for (int i = 0; i < 9; i++) { 1548 items.get(i).getChildren().add(items.get(i + 1)); 1549 } 1550 1551 for (int i = 0; i < 10; i++) { 1552 // because we have no root (and we are not changing the root like 1553 // the previous test), we expect the tree item level of the item 1554 // in the ith position to be i. 1555 assertEquals(i, view.getTreeItemLevel(items.get(i))); 1556 1557 // all items requested from the TreeView should be null, as the 1558 // TreeView does not have a root item 1559 assertNull(view.getTreeItem(i)); 1560 } 1561 } 1562 1563 @Test public void test_rt23245_itemIsNotInTree_withUnrelatedRootNode() { 1564 final TreeView<String> view = new TreeView<String>(); 1565 final List<TreeItem<String>> items = new ArrayList<>(); 1566 for (int i = 0; i < 10; i++) { 1567 final TreeItem<String> item = new TreeItem<String>("Item" + i); 1568 item.setExpanded(true); 1569 items.add(item); 1570 } 1571 1572 // link the items up so that the next item is the child of the current item 1573 for (int i = 0; i < 9; i++) { 1574 items.get(i).getChildren().add(items.get(i + 1)); 1575 } 1576 1577 view.setRoot(new TreeItem("Unrelated root node")); 1578 1579 for (int i = 0; i < 10; i++) { 1580 // because we have no root (and we are not changing the root like 1581 // the previous test), we expect the tree item level of the item 1582 // in the ith position to be i. 1583 assertEquals(i, view.getTreeItemLevel(items.get(i))); 1584 1585 // all items requested from the TreeView should be null except for 1586 // the root node 1587 assertNull(view.getTreeItem(i + 1)); 1588 } 1589 } 1590 1591 @Test public void test_rt35039_setRoot() { 1592 TreeItem<String> root = new TreeItem<>("Root"); 1593 root.setExpanded(true); 1594 root.getChildren().addAll( 1595 new TreeItem("aabbaa"), 1596 new TreeItem("bbc")); 1597 1598 final TreeView<String> treeView = new TreeView<>(); 1599 treeView.setRoot(root); 1600 1601 StageLoader sl = new StageLoader(treeView); 1602 1603 // We start with selection on row -1 1604 assertNull(treeView.getSelectionModel().getSelectedItem()); 1605 1606 // select "bbc" and ensure everything is set to that 1607 treeView.getSelectionModel().select(2); 1608 assertEquals("bbc", treeView.getSelectionModel().getSelectedItem().getValue()); 1609 1610 // change the items list - but retain the same content. We expect 1611 // that "bbc" remains selected as it is still in the list 1612 treeView.setRoot(root); 1613 assertEquals("bbc", treeView.getSelectionModel().getSelectedItem().getValue()); 1614 1615 sl.dispose(); 1616 } 1617 1618 @Test public void test_rt35039_resetRootChildren() { 1619 TreeItem aabbaa = new TreeItem("aabbaa"); 1620 TreeItem bbc = new TreeItem("bbc"); 1621 1622 TreeItem<String> root = new TreeItem<>("Root"); 1623 root.setExpanded(true); 1624 root.getChildren().setAll(aabbaa, bbc); 1625 1626 final TreeView<String> treeView = new TreeView<>(); 1627 treeView.setRoot(root); 1628 1629 StageLoader sl = new StageLoader(treeView); 1630 1631 // We start with selection on row -1 1632 assertNull(treeView.getSelectionModel().getSelectedItem()); 1633 1634 // select "bbc" and ensure everything is set to that 1635 treeView.getSelectionModel().select(2); 1636 assertEquals("bbc", treeView.getSelectionModel().getSelectedItem().getValue()); 1637 1638 // change the items list - but retain the same content. We expect 1639 // that "bbc" remains selected as it is still in the list 1640 root.getChildren().setAll(aabbaa, bbc); 1641 assertEquals("bbc", treeView.getSelectionModel().getSelectedItem().getValue()); 1642 1643 sl.dispose(); 1644 } 1645 1646 @Test public void test_rt35857() { 1647 TreeItem<String> root = new TreeItem<>("Root"); 1648 root.setExpanded(true); 1649 TreeItem a = new TreeItem("A"); 1650 TreeItem b = new TreeItem("B"); 1651 TreeItem c = new TreeItem("C"); 1652 root.getChildren().setAll(a, b, c); 1653 1654 final TreeView<String> treeTableView = new TreeView<String>(root); 1655 1656 treeTableView.getSelectionModel().select(1); 1657 1658 ObservableList<TreeItem<String>> selectedItems = treeTableView.getSelectionModel().getSelectedItems(); 1659 assertEquals(1, selectedItems.size()); 1660 assertEquals("A", selectedItems.get(0).getValue()); 1661 1662 root.getChildren().removeAll(selectedItems); 1663 assertEquals(2, root.getChildren().size()); 1664 assertEquals("B", root.getChildren().get(0).getValue()); 1665 assertEquals("C", root.getChildren().get(1).getValue()); 1666 } 1667 1668 private int rt_35889_cancel_count = 0; 1669 @Test public void test_rt35889() { 1670 TreeItem a = new TreeItem("a"); 1671 TreeItem b = new TreeItem("b"); 1672 TreeItem<String> root = new TreeItem<>("Root"); 1673 root.setExpanded(true); 1674 root.getChildren().setAll(a, b); 1675 1676 final TreeView<String> textFieldTreeView = new TreeView<String>(root); 1677 textFieldTreeView.setEditable(true); 1678 textFieldTreeView.setCellFactory(TextFieldTreeCell.forTreeView()); 1679 textFieldTreeView.setOnEditCancel(t -> { 1680 rt_35889_cancel_count++; 1681 System.out.println("On Edit Cancel: " + t); 1682 }); 1683 1684 TreeCell cell0 = (TreeCell) VirtualFlowTestUtils.getCell(textFieldTreeView, 0); 1685 assertNull(cell0.getGraphic()); 1686 assertEquals("Root", cell0.getText()); 1687 1688 textFieldTreeView.edit(root); 1689 TextField textField = (TextField) cell0.getGraphic(); 1690 assertNotNull(textField); 1691 1692 assertEquals(0, rt_35889_cancel_count); 1693 1694 textField.setText("Z"); 1695 textField.getOnAction().handle(new ActionEvent()); 1696 1697 assertEquals(0, rt_35889_cancel_count); 1698 } 1699 1700 @Test public void test_rt36255_selection_does_not_expand_item() { 1701 TreeItem a = new TreeItem("a"); 1702 TreeItem b = new TreeItem("b"); 1703 b.getChildren().add(new TreeItem("bb")); 1704 1705 final TreeItem<String> root = new TreeItem<>(); 1706 root.getChildren().addAll(a, b); 1707 root.setExpanded(true); 1708 TreeView<String> view = new TreeView<>(root); 1709 view.setCellFactory(TextFieldTreeCell.forTreeView()); 1710 1711 view.getSelectionModel().select(a); 1712 1713 assertEquals(Arrays.asList(a), view.getSelectionModel().getSelectedItems()); 1714 assertFalse(b.isExpanded()); 1715 1716 view.getSelectionModel().select(b); 1717 assertEquals(Arrays.asList(b), view.getSelectionModel().getSelectedItems()); 1718 assertFalse(b.isExpanded()); 1719 } 1720 1721 @Test public void test_rt25679() { 1722 Button focusBtn = new Button("Focus here"); 1723 1724 TreeItem<String> root = new TreeItem<>("Root"); 1725 root.getChildren().setAll(new TreeItem("a"), new TreeItem("b")); 1726 root.setExpanded(true); 1727 1728 final TreeView<String> treeView = new TreeView<>(root); 1729 SelectionModel sm = treeView.getSelectionModel(); 1730 1731 VBox vbox = new VBox(focusBtn, treeView); 1732 1733 StageLoader sl = new StageLoader(vbox); 1734 sl.getStage().requestFocus(); 1735 focusBtn.requestFocus(); 1736 Toolkit.getToolkit().firePulse(); 1737 1738 // test initial state 1739 assertEquals(sl.getStage().getScene().getFocusOwner(), focusBtn); 1740 assertTrue(focusBtn.isFocused()); 1741 assertEquals(-1, sm.getSelectedIndex()); 1742 assertNull(sm.getSelectedItem()); 1743 1744 // move focus to the treeview 1745 treeView.requestFocus(); 1746 1747 // ensure that there is a selection (where previously there was not one) 1748 assertEquals(sl.getStage().getScene().getFocusOwner(), treeView); 1749 assertTrue(treeView.isFocused()); 1750 assertEquals(-1, sm.getSelectedIndex()); 1751 assertNull(sm.getSelectedItem()); 1752 1753 sl.dispose(); 1754 } 1755 1756 @Test public void test_rt36885_addChildBeforeSelection() { 1757 test_rt36885(false); 1758 } 1759 1760 @Test public void test_rt36885_addChildAfterSelection() { 1761 test_rt36885(true); 1762 } 1763 1764 private void test_rt36885(boolean addChildToAAfterSelection) { 1765 TreeItem<String> root = new TreeItem<>("Root"); // 0 1766 TreeItem<String> a = new TreeItem<>("a"); // 1 1767 TreeItem<String> a1 = new TreeItem<>("a1"); // a expanded = 2, a collapsed = -1 1768 TreeItem<String> b = new TreeItem<>("b"); // a expanded = 3, a collapsed = 2 1769 TreeItem<String> b1 = new TreeItem<>("b1"); // a expanded = 4, a collapsed = 3 1770 TreeItem<String> b2 = new TreeItem<>("b2"); // a expanded = 5, a collapsed = 4 1771 1772 root.setExpanded(true); 1773 root.getChildren().setAll(a, b); 1774 1775 a.setExpanded(false); 1776 if (!addChildToAAfterSelection) { 1777 a.getChildren().add(a1); 1778 } 1779 1780 b.setExpanded(true); 1781 b.getChildren().addAll(b1, b2); 1782 1783 final TreeView<String> treeView = new TreeView<String>(root); 1784 1785 treeView.getFocusModel().focusedIndexProperty().addListener((observable, oldValue, newValue) -> { 1786 System.out.println("focusedIndex: " + oldValue + " to " + newValue); 1787 }); 1788 1789 MultipleSelectionModel<TreeItem<String>> sm = treeView.getSelectionModel(); 1790 FocusModel<TreeItem<String>> fm = treeView.getFocusModel(); 1791 1792 sm.select(b1); 1793 assertEquals(3, sm.getSelectedIndex()); 1794 assertEquals(b1, sm.getSelectedItem()); 1795 assertEquals(3, fm.getFocusedIndex()); 1796 assertEquals(b1, fm.getFocusedItem()); 1797 1798 if (addChildToAAfterSelection) { 1799 a.getChildren().add(a1); 1800 } 1801 1802 a.setExpanded(true); 1803 assertEquals(4, sm.getSelectedIndex()); 1804 assertEquals(b1, sm.getSelectedItem()); 1805 assertEquals(4, fm.getFocusedIndex()); 1806 assertEquals(b1, fm.getFocusedItem()); 1807 } 1808 1809 private int rt_37061_index_counter = 0; 1810 private int rt_37061_item_counter = 0; 1811 @Test public void test_rt_37061() { 1812 TreeItem<Integer> root = new TreeItem<>(0); 1813 root.setExpanded(true); 1814 TreeView<Integer> tv = new TreeView<>(); 1815 tv.setRoot(root); 1816 tv.getSelectionModel().select(0); 1817 1818 // note we add the listeners after the selection is made, so the counters 1819 // at this point are still both at zero. 1820 tv.getSelectionModel().selectedIndexProperty().addListener((observable, oldValue, newValue) -> { 1821 rt_37061_index_counter++; 1822 }); 1823 1824 tv.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> { 1825 rt_37061_item_counter++; 1826 }); 1827 1828 // add a new item. This does not impact the selected index or selected item 1829 // so the counters should remain at zero. 1830 tv.getRoot().getChildren().add(new TreeItem("1")); 1831 assertEquals(0, rt_37061_index_counter); 1832 assertEquals(0, rt_37061_item_counter); 1833 } 1834 1835 private int rt_37395_index_addCount = 0; 1836 private int rt_37395_index_removeCount = 0; 1837 private int rt_37395_index_permutationCount = 0; 1838 private int rt_37395_item_addCount = 0; 1839 private int rt_37395_item_removeCount = 0; 1840 private int rt_37395_item_permutationCount = 0; 1841 1842 @Test public void test_rt_37395() { 1843 // tree items - 3 items, 2nd item has 2 children 1844 TreeItem<String> root = new TreeItem<>(); 1845 1846 TreeItem<String> two = new TreeItem<>("two"); 1847 two.getChildren().add(new TreeItem<>("childOne")); 1848 two.getChildren().add(new TreeItem<>("childTwo")); 1849 1850 root.getChildren().add(new TreeItem<>("one")); 1851 root.getChildren().add(two); 1852 root.getChildren().add(new TreeItem<>("three")); 1853 1854 // tree 1855 TreeView<String> tree = new TreeView<>(); 1856 tree.setShowRoot(false); 1857 tree.setRoot(root); 1858 1859 MultipleSelectionModel sm = tree.getSelectionModel(); 1860 sm.getSelectedIndices().addListener(new ListChangeListener<Integer>() { 1861 @Override public void onChanged(Change<? extends Integer> c) { 1862 while (c.next()) { 1863 if (c.wasRemoved()) { 1864 c.getRemoved().forEach(item -> { 1865 if (item == null) { 1866 fail("Removed index should never be null"); 1867 } else { 1868 rt_37395_index_removeCount++; 1869 } 1870 }); 1871 } 1872 if (c.wasAdded()) { 1873 c.getAddedSubList().forEach(item -> { 1874 rt_37395_index_addCount++; 1875 }); 1876 } 1877 if (c.wasPermutated()) { 1878 rt_37395_index_permutationCount++; 1879 } 1880 } 1881 } 1882 }); 1883 sm.getSelectedItems().addListener(new ListChangeListener<TreeItem<String>>() { 1884 @Override public void onChanged(Change<? extends TreeItem<String>> c) { 1885 while (c.next()) { 1886 if (c.wasRemoved()) { 1887 c.getRemoved().forEach(item -> { 1888 if (item == null) { 1889 fail("Removed item should never be null"); 1890 } else { 1891 rt_37395_item_removeCount++; 1892 } 1893 }); 1894 } 1895 if (c.wasAdded()) { 1896 c.getAddedSubList().forEach(item -> { 1897 rt_37395_item_addCount++; 1898 }); 1899 } 1900 if (c.wasPermutated()) { 1901 rt_37395_item_permutationCount++; 1902 } 1903 } 1904 } 1905 }); 1906 1907 assertEquals(0, rt_37395_index_removeCount); 1908 assertEquals(0, rt_37395_index_addCount); 1909 assertEquals(0, rt_37395_index_permutationCount); 1910 assertEquals(0, rt_37395_item_removeCount); 1911 assertEquals(0, rt_37395_item_addCount); 1912 assertEquals(0, rt_37395_item_permutationCount); 1913 1914 StageLoader sl = new StageLoader(tree); 1915 1916 // step one: select item 'three' in index 2 1917 sm.select(2); 1918 assertEquals(0, rt_37395_index_removeCount); 1919 assertEquals(1, rt_37395_index_addCount); 1920 assertEquals(0, rt_37395_index_permutationCount); 1921 assertEquals(0, rt_37395_item_removeCount); 1922 assertEquals(1, rt_37395_item_addCount); 1923 assertEquals(0, rt_37395_item_permutationCount); 1924 1925 // step two: expand item 'two' 1926 // The first part of the bug report was that we received add/remove 1927 // change events here, when in reality we shouldn't have, so lets enforce 1928 // that. We do expect a permutation event on the index, as it has been 1929 // pushed down, but this should not result in an item permutation event, 1930 // as it remains unchanged 1931 two.setExpanded(true); 1932 assertEquals(0, rt_37395_index_removeCount); 1933 assertEquals(1, rt_37395_index_addCount); 1934 assertEquals(1, rt_37395_index_permutationCount); 1935 assertEquals(0, rt_37395_item_removeCount); 1936 assertEquals(1, rt_37395_item_addCount); 1937 assertEquals(0, rt_37395_item_permutationCount); 1938 1939 // step three: collapse item 'two' 1940 // Same argument as in step two above: no addition or removal, just a 1941 // permutation on the index 1942 two.setExpanded(false); 1943 assertEquals(0, rt_37395_index_removeCount); 1944 assertEquals(1, rt_37395_index_addCount); 1945 assertEquals(2, rt_37395_index_permutationCount); 1946 assertEquals(0, rt_37395_item_removeCount); 1947 assertEquals(1, rt_37395_item_addCount); 1948 assertEquals(0, rt_37395_item_permutationCount); 1949 1950 sl.dispose(); 1951 } 1952 1953 @Test public void test_rt_37502() { 1954 final TreeView<Long> tree = new TreeView<>(new NumberTreeItem(1)); 1955 tree.setCellFactory(new Callback<TreeView<Long>, TreeCell<Long>>() { 1956 @Override 1957 public TreeCell<Long> call(TreeView<Long> param) { 1958 return new TreeCell<Long>() { 1959 @Override 1960 protected void updateItem(Long item, boolean empty) { 1961 super.updateItem(item, empty); 1962 if (!empty) { 1963 setText(item != null ? String.valueOf(item) : ""); 1964 } else{ 1965 setText(null); 1966 } 1967 } 1968 }; 1969 } 1970 }); 1971 1972 StageLoader sl = new StageLoader(tree); 1973 1974 tree.getSelectionModel().select(0); 1975 tree.getRoot().setExpanded(true); 1976 Toolkit.getToolkit().firePulse(); 1977 1978 sl.dispose(); 1979 } 1980 1981 private static class NumberTreeItem extends TreeItem<Long>{ 1982 private boolean loaded = false; 1983 1984 private NumberTreeItem(long value) { 1985 super(value); 1986 } 1987 1988 @Override public boolean isLeaf() { 1989 return false; 1990 } 1991 1992 @Override public ObservableList<TreeItem<Long>> getChildren() { 1993 if(!loaded){ 1994 final ObservableList<TreeItem<Long>> children = super.getChildren(); 1995 for (int i = 0; i < 10; i++) { 1996 children.add(new NumberTreeItem(10 * getValue() + i)); 1997 } 1998 loaded = true; 1999 } 2000 return super.getChildren(); 2001 } 2002 } 2003 2004 private int rt_37538_count = 0; 2005 @Test public void test_rt_37538_noCNextCall() { 2006 test_rt_37538(false, false); 2007 } 2008 2009 @Test public void test_rt_37538_callCNextOnce() { 2010 test_rt_37538(true, false); 2011 } 2012 2013 @Test public void test_rt_37538_callCNextInLoop() { 2014 test_rt_37538(false, true); 2015 } 2016 2017 private void test_rt_37538(boolean callCNextOnce, boolean callCNextInLoop) { 2018 // create table with a bunch of rows and 1 column... 2019 TreeItem<Integer> root = new TreeItem<>(0); 2020 root.setExpanded(true); 2021 for (int i = 1; i <= 50; i++) { 2022 root.getChildren().add(new TreeItem<>(i)); 2023 } 2024 2025 final TreeView<Integer> tree = new TreeView<>(root); 2026 2027 tree.getSelectionModel().getSelectedItems().addListener((ListChangeListener.Change<? extends TreeItem<Integer>> c) -> { 2028 if (callCNextOnce) { 2029 c.next(); 2030 } else if (callCNextInLoop) { 2031 while (c.next()) { 2032 // no-op 2033 } 2034 } 2035 2036 if (rt_37538_count >= 1) { 2037 Thread.dumpStack(); 2038 fail("This method should only be called once"); 2039 } 2040 2041 rt_37538_count++; 2042 }); 2043 2044 StageLoader sl = new StageLoader(tree); 2045 assertEquals(0, rt_37538_count); 2046 tree.getSelectionModel().select(0); 2047 assertEquals(1, rt_37538_count); 2048 sl.dispose(); 2049 } 2050 2051 @Ignore("Fix not yet developed for TreeView") 2052 @Test public void test_rt_35395_fixedCellSize() { 2053 test_rt_35395(true); 2054 } 2055 2056 @Ignore("Fix not yet developed for TreeView") 2057 @Test public void test_rt_35395_notFixedCellSize() { 2058 test_rt_35395(false); 2059 } 2060 2061 private int rt_35395_counter; 2062 private void test_rt_35395(boolean useFixedCellSize) { 2063 rt_35395_counter = 0; 2064 2065 TreeItem<String> root = new TreeItem<>("green"); 2066 root.setExpanded(true); 2067 for (int i = 0; i < 20; i++) { 2068 root.getChildren().addAll(new TreeItem<>("red"), new TreeItem<>("green"), new TreeItem<>("blue"), new TreeItem<>("purple")); 2069 } 2070 2071 TreeView<String> treeView = new TreeView<>(root); 2072 if (useFixedCellSize) { 2073 treeView.setFixedCellSize(24); 2074 } 2075 treeView.setCellFactory(tv -> new TreeCell<String>() { 2076 @Override protected void updateItem(String color, boolean empty) { 2077 rt_35395_counter += 1; 2078 super.updateItem(color, empty); 2079 setText(null); 2080 if(empty) { 2081 setGraphic(null); 2082 } else { 2083 Rectangle rect = new Rectangle(16, 16); 2084 rect.setStyle("-fx-fill: " + color); 2085 setGraphic(rect); 2086 } 2087 } 2088 }); 2089 2090 StageLoader sl = new StageLoader(treeView); 2091 2092 Platform.runLater(() -> { 2093 rt_35395_counter = 0; 2094 root.getChildren().set(10, new TreeItem<>("yellow")); 2095 Platform.runLater(() -> { 2096 Toolkit.getToolkit().firePulse(); 2097 assertEquals(1, rt_35395_counter); 2098 rt_35395_counter = 0; 2099 root.getChildren().set(30, new TreeItem<>("yellow")); 2100 Platform.runLater(() -> { 2101 Toolkit.getToolkit().firePulse(); 2102 assertEquals(0, rt_35395_counter); 2103 rt_35395_counter = 0; 2104 treeView.scrollTo(5); 2105 Platform.runLater(() -> { 2106 Toolkit.getToolkit().firePulse(); 2107 assertEquals(5, rt_35395_counter); 2108 rt_35395_counter = 0; 2109 treeView.scrollTo(55); 2110 Platform.runLater(() -> { 2111 Toolkit.getToolkit().firePulse(); 2112 2113 int expected = useFixedCellSize ? 17 : 53; 2114 assertEquals(expected, rt_35395_counter); 2115 sl.dispose(); 2116 }); 2117 }); 2118 }); 2119 }); 2120 }); 2121 } 2122 2123 @Test public void test_rt_37632() { 2124 final TreeItem<String> rootOne = new TreeItem<>("Root 1"); 2125 final TreeItem<String> rootTwo = new TreeItem<>("Root 2"); 2126 2127 final TreeView<String> treeView = new TreeView<>(); 2128 MultipleSelectionModel<TreeItem<String>> sm = treeView.getSelectionModel(); 2129 treeView.setRoot(rootOne); 2130 treeView.getSelectionModel().selectFirst(); 2131 2132 assertEquals(0, sm.getSelectedIndex()); 2133 assertEquals(rootOne, sm.getSelectedItem()); 2134 assertEquals(1, sm.getSelectedIndices().size()); 2135 assertEquals(0, (int) sm.getSelectedIndices().get(0)); 2136 assertEquals(1, sm.getSelectedItems().size()); 2137 assertEquals(rootOne, sm.getSelectedItems().get(0)); 2138 2139 treeView.setRoot(rootTwo); 2140 2141 assertEquals(-1, sm.getSelectedIndex()); 2142 assertNull(sm.getSelectedItem()); 2143 assertEquals(0, sm.getSelectedIndices().size()); 2144 assertEquals(0, sm.getSelectedItems().size()); 2145 } 2146 2147 @Test public void test_rt_37853_replaceRoot() { 2148 test_rt_37853(true); 2149 } 2150 2151 @Test public void test_rt_37853_replaceRootChildren() { 2152 test_rt_37853(false); 2153 } 2154 2155 private int rt_37853_cancelCount; 2156 private int rt_37853_commitCount; 2157 private void test_rt_37853(boolean replaceRoot) { 2158 treeView.setCellFactory(TextFieldTreeCell.forTreeView()); 2159 treeView.setEditable(true); 2160 treeView.setRoot(new TreeItem<>("Root")); 2161 treeView.getRoot().setExpanded(true); 2162 2163 for (int i = 0; i < 10; i++) { 2164 treeView.getRoot().getChildren().add(new TreeItem<>("" + i)); 2165 } 2166 2167 StageLoader sl = new StageLoader(treeView); 2168 2169 treeView.setOnEditCancel(editEvent -> rt_37853_cancelCount++); 2170 treeView.setOnEditCommit(editEvent -> rt_37853_commitCount++); 2171 2172 assertEquals(0, rt_37853_cancelCount); 2173 assertEquals(0, rt_37853_commitCount); 2174 2175 treeView.edit(treeView.getRoot().getChildren().get(0)); 2176 assertNotNull(treeView.getEditingItem()); 2177 2178 if (replaceRoot) { 2179 treeView.setRoot(new TreeItem<>("New Root")); 2180 } else { 2181 treeView.getRoot().getChildren().clear(); 2182 for (int i = 0; i < 10; i++) { 2183 treeView.getRoot().getChildren().add(new TreeItem<>("new item " + i)); 2184 } 2185 } 2186 2187 assertEquals(1, rt_37853_cancelCount); 2188 assertEquals(0, rt_37853_commitCount); 2189 2190 sl.dispose(); 2191 } 2192 2193 @Test public void test_rt_38787_remove_b() { 2194 // Remove 'b', selection moves to 'a' 2195 test_rt_38787("a", 0, 1); 2196 } 2197 2198 @Test public void test_rt_38787_remove_b_c() { 2199 // Remove 'b' and 'c', selection moves to 'a' 2200 test_rt_38787("a", 0, 1, 2); 2201 } 2202 2203 @Test public void test_rt_38787_remove_c_d() { 2204 // Remove 'c' and 'd', selection moves to 'b' 2205 test_rt_38787("b", 1, 2, 3); 2206 } 2207 2208 @Test public void test_rt_38787_remove_a() { 2209 // Remove 'a', selection moves to 'b', now in index 0 2210 test_rt_38787("b", 0, 0); 2211 } 2212 2213 private void test_rt_38787(String expectedItem, int expectedIndex, int... indicesToRemove) { 2214 TreeItem<String> a, b, c, d; 2215 TreeItem<String> root = new TreeItem<>("Root"); 2216 root.setExpanded(true); 2217 root.getChildren().addAll( 2218 a = new TreeItem<String>("a"), 2219 b = new TreeItem<String>("b"), 2220 c = new TreeItem<String>("c"), 2221 d = new TreeItem<String>("d") 2222 ); 2223 2224 TreeView<String> stringTreeView = new TreeView<>(root); 2225 stringTreeView.setShowRoot(false); 2226 2227 // TableColumn<String,String> column = new TableColumn<>("Column"); 2228 // column.setCellValueFactory(cdf -> new ReadOnlyStringWrapper(cdf.getValue())); 2229 // stringTableView.getColumns().add(column); 2230 2231 MultipleSelectionModel<TreeItem<String>> sm = stringTreeView.getSelectionModel(); 2232 sm.select(b); 2233 2234 // test pre-conditions 2235 assertEquals(1, sm.getSelectedIndex()); 2236 assertEquals(1, (int)sm.getSelectedIndices().get(0)); 2237 assertEquals(b, sm.getSelectedItem()); 2238 assertEquals(b, sm.getSelectedItems().get(0)); 2239 assertFalse(sm.isSelected(0)); 2240 assertTrue(sm.isSelected(1)); 2241 assertFalse(sm.isSelected(2)); 2242 2243 // removing items 2244 List<TreeItem<String>> itemsToRemove = new ArrayList<>(indicesToRemove.length); 2245 for (int index : indicesToRemove) { 2246 itemsToRemove.add(root.getChildren().get(index)); 2247 } 2248 root.getChildren().removeAll(itemsToRemove); 2249 2250 // testing against expectations 2251 assertEquals(expectedIndex, sm.getSelectedIndex()); 2252 assertEquals(expectedIndex, (int)sm.getSelectedIndices().get(0)); 2253 assertEquals(expectedItem, sm.getSelectedItem().getValue()); 2254 assertEquals(expectedItem, sm.getSelectedItems().get(0).getValue()); 2255 } 2256 2257 private int rt_38341_indices_count = 0; 2258 private int rt_38341_items_count = 0; 2259 @Test public void test_rt_38341() { 2260 Callback<Integer, TreeItem<String>> callback = number -> { 2261 final TreeItem<String> root = new TreeItem<>("Root " + number); 2262 final TreeItem<String> child = new TreeItem<>("Child " + number); 2263 2264 root.getChildren().add(child); 2265 return root; 2266 }; 2267 2268 final TreeItem<String> root = new TreeItem<String>(); 2269 root.setExpanded(true); 2270 root.getChildren().addAll(callback.call(1), callback.call(2)); 2271 2272 final TreeView<String> treeView = new TreeView<>(root); 2273 treeView.setShowRoot(false); 2274 2275 MultipleSelectionModel<TreeItem<String>> sm = treeView.getSelectionModel(); 2276 sm.getSelectedIndices().addListener((ListChangeListener<Integer>) c -> rt_38341_indices_count++); 2277 sm.getSelectedItems().addListener((ListChangeListener<TreeItem<String>>) c -> rt_38341_items_count++); 2278 2279 assertEquals(0, rt_38341_indices_count); 2280 assertEquals(0, rt_38341_items_count); 2281 2282 // expand the first child of root, and select it (note: root isn't visible) 2283 root.getChildren().get(0).setExpanded(true); 2284 sm.select(1); 2285 assertEquals(1, sm.getSelectedIndex()); 2286 assertEquals(1, sm.getSelectedIndices().size()); 2287 assertEquals(1, (int)sm.getSelectedIndices().get(0)); 2288 assertEquals(1, sm.getSelectedItems().size()); 2289 assertEquals("Child 1", sm.getSelectedItem().getValue()); 2290 assertEquals("Child 1", sm.getSelectedItems().get(0).getValue()); 2291 2292 assertEquals(1, rt_38341_indices_count); 2293 assertEquals(1, rt_38341_items_count); 2294 2295 // now delete it 2296 root.getChildren().get(0).getChildren().remove(0); 2297 2298 // selection should move to the childs parent in index 0 2299 assertEquals(0, sm.getSelectedIndex()); 2300 assertEquals(1, sm.getSelectedIndices().size()); 2301 assertEquals(0, (int)sm.getSelectedIndices().get(0)); 2302 assertEquals(1, sm.getSelectedItems().size()); 2303 assertEquals("Root 1", sm.getSelectedItem().getValue()); 2304 assertEquals("Root 1", sm.getSelectedItems().get(0).getValue()); 2305 2306 // we also expect there to be an event in the selection model for 2307 // selected indices and selected items 2308 assertEquals(2, rt_38341_indices_count); 2309 assertEquals(2, rt_38341_items_count); 2310 } 2311 2312 private int rt_38943_index_count = 0; 2313 private int rt_38943_item_count = 0; 2314 @Test public void test_rt_38943() { 2315 TreeItem<String> root = new TreeItem<>("Root"); 2316 root.setExpanded(true); 2317 root.getChildren().addAll( 2318 new TreeItem<>("a"), 2319 new TreeItem<>("b"), 2320 new TreeItem<>("c"), 2321 new TreeItem<>("d") 2322 ); 2323 2324 final TreeView<String> treeView = new TreeView<>(root); 2325 treeView.setShowRoot(false); 2326 2327 MultipleSelectionModel<TreeItem<String>> sm = treeView.getSelectionModel(); 2328 2329 sm.selectedIndexProperty().addListener((observable, oldValue, newValue) -> rt_38943_index_count++); 2330 sm.selectedItemProperty().addListener((observable, oldValue, newValue) -> rt_38943_item_count++); 2331 2332 assertEquals(-1, sm.getSelectedIndex()); 2333 assertNull(sm.getSelectedItem()); 2334 assertEquals(0, rt_38943_index_count); 2335 assertEquals(0, rt_38943_item_count); 2336 2337 sm.select(0); 2338 assertEquals(0, sm.getSelectedIndex()); 2339 assertEquals("a", sm.getSelectedItem().getValue()); 2340 assertEquals(1, rt_38943_index_count); 2341 assertEquals(1, rt_38943_item_count); 2342 2343 sm.clearSelection(0); 2344 assertEquals(-1, sm.getSelectedIndex()); 2345 assertNull(sm.getSelectedItem()); 2346 assertEquals(2, rt_38943_index_count); 2347 assertEquals(2, rt_38943_item_count); 2348 } 2349 2350 @Test public void test_rt_38884() { 2351 final TreeItem<String> root = new TreeItem<>("Root"); 2352 final TreeItem<String> foo = new TreeItem<>("foo"); 2353 2354 TreeView<String> treeView = new TreeView<>(root); 2355 treeView.setShowRoot(false); 2356 root.setExpanded(true); 2357 2358 treeView.getSelectionModel().getSelectedItems().addListener((ListChangeListener.Change<? extends TreeItem<String>> c) -> { 2359 while (c.next()) { 2360 if (c.wasRemoved()) { 2361 assertTrue(c.getRemovedSize() > 0); 2362 2363 List<? extends TreeItem<String>> removed = c.getRemoved(); 2364 TreeItem<String> removedItem = null; 2365 try { 2366 removedItem = removed.get(0); 2367 } catch (Exception e) { 2368 fail(); 2369 } 2370 2371 assertEquals(foo, removedItem); 2372 } 2373 } 2374 }); 2375 2376 root.getChildren().add(foo); 2377 treeView.getSelectionModel().select(0); 2378 root.getChildren().clear(); 2379 } 2380 2381 private int rt_37360_add_count = 0; 2382 private int rt_37360_remove_count = 0; 2383 @Test public void test_rt_37360() { 2384 TreeItem<String> root = new TreeItem<>("Root"); 2385 root.setExpanded(true); 2386 root.getChildren().addAll( 2387 new TreeItem<>("a"), 2388 new TreeItem<>("b") 2389 ); 2390 2391 TreeView<String> stringTreeView = new TreeView<>(root); 2392 stringTreeView.setShowRoot(false); 2393 2394 MultipleSelectionModel<TreeItem<String>> sm = stringTreeView.getSelectionModel(); 2395 sm.setSelectionMode(SelectionMode.MULTIPLE); 2396 sm.getSelectedItems().addListener((ListChangeListener<TreeItem<String>>) c -> { 2397 while (c.next()) { 2398 if (c.wasAdded()) { 2399 rt_37360_add_count += c.getAddedSize(); 2400 } 2401 if (c.wasRemoved()) { 2402 rt_37360_remove_count += c.getRemovedSize(); 2403 } 2404 } 2405 }); 2406 2407 assertEquals(0, sm.getSelectedItems().size()); 2408 assertEquals(0, rt_37360_add_count); 2409 assertEquals(0, rt_37360_remove_count); 2410 2411 sm.select(0); 2412 assertEquals(1, sm.getSelectedItems().size()); 2413 assertEquals(1, rt_37360_add_count); 2414 assertEquals(0, rt_37360_remove_count); 2415 2416 sm.select(1); 2417 assertEquals(2, sm.getSelectedItems().size()); 2418 assertEquals(2, rt_37360_add_count); 2419 assertEquals(0, rt_37360_remove_count); 2420 2421 sm.clearAndSelect(1); 2422 assertEquals(1, sm.getSelectedItems().size()); 2423 assertEquals(2, rt_37360_add_count); 2424 assertEquals(1, rt_37360_remove_count); 2425 } 2426 2427 private int rt_37366_count = 0; 2428 @Test public void test_rt_37366() { 2429 final TreeItem<String> treeItem2 = new TreeItem<>("Item 2"); 2430 treeItem2.getChildren().addAll(new TreeItem<>("Item 21"), new TreeItem<>("Item 22")); 2431 2432 final TreeItem<String> root1 = new TreeItem<>("Root Node 1"); 2433 root1.getChildren().addAll(new TreeItem<>("Item 1"), treeItem2, new TreeItem<>("Item 3")); 2434 root1.setExpanded(true); 2435 2436 final TreeItem<String> root2 = new TreeItem<>("Root Node 2"); 2437 2438 final TreeItem<String> hiddenRoot = new TreeItem<>("Hidden Root Node"); 2439 hiddenRoot.getChildren().add(root1); 2440 hiddenRoot.getChildren().add(root2); 2441 2442 final TreeView<String> treeView = new TreeView<>(hiddenRoot); 2443 treeView.setShowRoot(false); 2444 2445 MultipleSelectionModel<TreeItem<String>> sm = treeView.getSelectionModel(); 2446 sm.setSelectionMode(SelectionMode.MULTIPLE); 2447 sm.getSelectedItems().addListener((ListChangeListener.Change<? extends TreeItem<String>> c) -> { 2448 rt_37366_count++; 2449 }); 2450 2451 assertEquals(0, rt_37366_count); 2452 2453 sm.select(1); 2454 assertEquals(1, rt_37366_count); 2455 assertFalse(sm.isSelected(0)); 2456 assertTrue(sm.isSelected(1)); 2457 assertFalse(sm.isSelected(2)); 2458 2459 sm.select(2); 2460 assertEquals(2, rt_37366_count); 2461 assertFalse(sm.isSelected(0)); 2462 assertTrue(sm.isSelected(1)); 2463 assertTrue(sm.isSelected(2)); 2464 2465 root1.setExpanded(false); 2466 assertEquals(3, rt_37366_count); 2467 assertTrue(sm.isSelected(0)); 2468 assertFalse(sm.isSelected(1)); 2469 assertFalse(sm.isSelected(2)); 2470 } 2471 2472 @Test public void test_rt_38491() { 2473 TreeItem<String> a; 2474 TreeItem<String> root = new TreeItem<>("Root"); 2475 root.setExpanded(true); 2476 root.getChildren().addAll( 2477 a = new TreeItem<>("a"), 2478 new TreeItem<>("b") 2479 ); 2480 2481 TreeView<String> stringTreeView = new TreeView<>(root); 2482 stringTreeView.setShowRoot(false); 2483 2484 MultipleSelectionModel<TreeItem<String>> sm = stringTreeView.getSelectionModel(); 2485 sm.setSelectionMode(SelectionMode.MULTIPLE); 2486 2487 FocusModel<TreeItem<String>> fm = stringTreeView.getFocusModel(); 2488 2489 StageLoader sl = new StageLoader(stringTreeView); 2490 2491 // test pre-conditions 2492 assertTrue(sm.isEmpty()); 2493 assertEquals(a, fm.getFocusedItem()); 2494 assertEquals(0, fm.getFocusedIndex()); 2495 2496 // click on row 0 2497 VirtualFlowTestUtils.clickOnRow(stringTreeView, 0); 2498 assertTrue(sm.isSelected(0)); 2499 assertEquals(a, sm.getSelectedItem()); 2500 assertTrue(fm.isFocused(0)); 2501 assertEquals(a, fm.getFocusedItem()); 2502 assertEquals(0, fm.getFocusedIndex()); 2503 2504 Integer anchor = TreeCellBehavior.getAnchor(stringTreeView, null); 2505 assertNotNull(anchor); 2506 assertTrue(TreeCellBehavior.hasNonDefaultAnchor(stringTreeView)); 2507 assertEquals(0, (int)anchor); 2508 2509 // now add a new item at row 0. This has the effect of pushing down 2510 // the selected item into row 1. 2511 root.getChildren().add(0, new TreeItem("z")); 2512 2513 // The first bug was that selection and focus were not moving down to 2514 // be on row 1, so we test that now 2515 assertFalse(sm.isSelected(0)); 2516 assertFalse(fm.isFocused(0)); 2517 assertTrue(sm.isSelected(1)); 2518 assertEquals(a, sm.getSelectedItem()); 2519 assertTrue(fm.isFocused(1)); 2520 assertEquals(a, fm.getFocusedItem()); 2521 assertEquals(1, fm.getFocusedIndex()); 2522 2523 // The second bug was that the anchor was not being pushed down as well 2524 // (when it should). 2525 anchor = TreeCellBehavior.getAnchor(stringTreeView, null); 2526 assertNotNull(anchor); 2527 assertTrue(TreeCellBehavior.hasNonDefaultAnchor(stringTreeView)); 2528 assertEquals(1, (int)anchor); 2529 2530 sl.dispose(); 2531 } 2532 2533 private final ObservableList<TreeItem<String>> rt_39256_list = FXCollections.observableArrayList(); 2534 @Test public void test_rt_39256() { 2535 TreeItem<String> root = new TreeItem<>("Root"); 2536 root.setExpanded(true); 2537 root.getChildren().addAll( 2538 new TreeItem<>("a"), 2539 new TreeItem<>("b"), 2540 new TreeItem<>("c"), 2541 new TreeItem<>("d") 2542 ); 2543 2544 TreeView<String> stringTreeView = new TreeView<>(root); 2545 stringTreeView.setShowRoot(false); 2546 2547 MultipleSelectionModel<TreeItem<String>> sm = stringTreeView.getSelectionModel(); 2548 sm.setSelectionMode(SelectionMode.MULTIPLE); 2549 2550 // rt_39256_list.addListener((ListChangeListener<TreeItem<String>>) change -> { 2551 // while (change.next()) { 2552 // System.err.println("number of selected persons (in bound list): " + change.getList().size()); 2553 // } 2554 // }); 2555 2556 Bindings.bindContent(rt_39256_list, sm.getSelectedItems()); 2557 2558 assertEquals(0, sm.getSelectedItems().size()); 2559 assertEquals(0, rt_39256_list.size()); 2560 2561 sm.selectAll(); 2562 assertEquals(4, sm.getSelectedItems().size()); 2563 assertEquals(4, rt_39256_list.size()); 2564 2565 sm.selectAll(); 2566 assertEquals(4, sm.getSelectedItems().size()); 2567 assertEquals(4, rt_39256_list.size()); 2568 2569 sm.selectAll(); 2570 assertEquals(4, sm.getSelectedItems().size()); 2571 assertEquals(4, rt_39256_list.size()); 2572 } 2573 2574 private final ObservableList<TreeItem<String>> rt_39482_list = FXCollections.observableArrayList(); 2575 @Test public void test_rt_39482() { 2576 TreeItem<String> root = new TreeItem<>("Root"); 2577 root.setExpanded(true); 2578 root.getChildren().addAll( 2579 new TreeItem<>("a"), 2580 new TreeItem<>("b"), 2581 new TreeItem<>("c"), 2582 new TreeItem<>("d") 2583 ); 2584 2585 TreeView<String> stringTreeView = new TreeView<>(root); 2586 stringTreeView.setShowRoot(false); 2587 2588 MultipleSelectionModel<TreeItem<String>> sm = stringTreeView.getSelectionModel(); 2589 sm.setSelectionMode(SelectionMode.MULTIPLE); 2590 2591 // rt_39256_list.addListener((ListChangeListener<TreeItem<String>>) change -> { 2592 // while (change.next()) { 2593 // System.err.println("number of selected persons (in bound list): " + change.getList().size()); 2594 // } 2595 // }); 2596 2597 Bindings.bindContent(rt_39482_list, sm.getSelectedItems()); 2598 2599 assertEquals(0, sm.getSelectedItems().size()); 2600 assertEquals(0, rt_39482_list.size()); 2601 2602 test_rt_39482_selectRow("a", sm, 0); 2603 test_rt_39482_selectRow("b", sm, 1); 2604 test_rt_39482_selectRow("c", sm, 2); 2605 test_rt_39482_selectRow("d", sm, 3); 2606 } 2607 2608 private void test_rt_39482_selectRow(String expectedString, 2609 MultipleSelectionModel<TreeItem<String>> sm, 2610 int rowToSelect) { 2611 System.out.println("\nSelect row " + rowToSelect); 2612 sm.selectAll(); 2613 assertEquals(4, sm.getSelectedIndices().size()); 2614 assertEquals(4, sm.getSelectedItems().size()); 2615 assertEquals(4, rt_39482_list.size()); 2616 2617 sm.clearAndSelect(rowToSelect); 2618 assertEquals(1, sm.getSelectedIndices().size()); 2619 assertEquals(1, sm.getSelectedItems().size()); 2620 assertEquals(expectedString, sm.getSelectedItem().getValue()); 2621 assertEquals(expectedString, rt_39482_list.get(0).getValue()); 2622 assertEquals(1, rt_39482_list.size()); 2623 } 2624 2625 @Test public void test_rt_39559_useSM_selectAll() { 2626 test_rt_39559(true); 2627 } 2628 2629 @Test public void test_rt_39559_useKeyboard_selectAll() { 2630 test_rt_39559(false); 2631 } 2632 2633 private void test_rt_39559(boolean useSMSelectAll) { 2634 TreeItem<String> a, b; 2635 TreeItem<String> root = new TreeItem<>("Root"); 2636 root.setExpanded(true); 2637 root.getChildren().addAll( 2638 a = new TreeItem<>("a"), 2639 b = new TreeItem<>("b"), 2640 new TreeItem<>("c"), 2641 new TreeItem<>("d") 2642 ); 2643 2644 TreeView<String> stringTreeView = new TreeView<>(root); 2645 stringTreeView.setShowRoot(false); 2646 2647 MultipleSelectionModel<TreeItem<String>> sm = stringTreeView.getSelectionModel(); 2648 sm.setSelectionMode(SelectionMode.MULTIPLE); 2649 2650 StageLoader sl = new StageLoader(stringTreeView); 2651 KeyEventFirer keyboard = new KeyEventFirer(stringTreeView); 2652 2653 assertEquals(0, sm.getSelectedItems().size()); 2654 2655 sm.clearAndSelect(0); 2656 2657 if (useSMSelectAll) { 2658 sm.selectAll(); 2659 } else { 2660 keyboard.doKeyPress(KeyCode.A, KeyModifier.getShortcutKey()); 2661 } 2662 2663 assertEquals(4, sm.getSelectedItems().size()); 2664 assertEquals(0, (int) TreeCellBehavior.getAnchor(stringTreeView, -1)); 2665 2666 keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT); 2667 2668 assertEquals(0, (int) TreeCellBehavior.getAnchor(stringTreeView, -1)); 2669 assertEquals(2, sm.getSelectedItems().size()); 2670 assertEquals(a, sm.getSelectedItems().get(0)); 2671 assertEquals(b, sm.getSelectedItems().get(1)); 2672 2673 sl.dispose(); 2674 } 2675 2676 @Test public void test_rt_16068_firstElement_selectAndRemoveSameRow() { 2677 // select and then remove the 'a' item, selection and focus should both 2678 // stay at the first row, now 'b' 2679 test_rt_16068(0, 0, 0); 2680 } 2681 2682 @Test public void test_rt_16068_firstElement_selectRowAndRemoveLaterSibling() { 2683 // select row 'a', and remove row 'c', selection and focus should not change 2684 test_rt_16068(0, 2, 0); 2685 } 2686 2687 @Test public void test_rt_16068_middleElement_selectAndRemoveSameRow() { 2688 // select and then remove the 'b' item, selection and focus should both 2689 // move up one row to the 'a' item 2690 test_rt_16068(1, 1, 0); 2691 } 2692 2693 @Test public void test_rt_16068_middleElement_selectRowAndRemoveLaterSibling() { 2694 // select row 'b', and remove row 'c', selection and focus should not change 2695 test_rt_16068(1, 2, 1); 2696 } 2697 2698 @Test public void test_rt_16068_middleElement_selectRowAndRemoveEarlierSibling() { 2699 // select row 'b', and remove row 'a', selection and focus should move up 2700 // one row, remaining on 'b' 2701 test_rt_16068(1, 0, 0); 2702 } 2703 2704 @Test public void test_rt_16068_lastElement_selectAndRemoveSameRow() { 2705 // select and then remove the 'd' item, selection and focus should both 2706 // move up one row to the 'c' item 2707 test_rt_16068(3, 3, 2); 2708 } 2709 2710 @Test public void test_rt_16068_lastElement_selectRowAndRemoveEarlierSibling() { 2711 // select row 'd', and remove row 'a', selection and focus should move up 2712 // one row, remaining on 'd' 2713 test_rt_16068(3, 0, 2); 2714 } 2715 2716 private void test_rt_16068(int indexToSelect, int indexToRemove, int expectedIndex) { 2717 TreeItem<String> root = new TreeItem<>("Root"); 2718 root.setExpanded(true); 2719 root.getChildren().addAll( 2720 new TreeItem<>("a"), // 0 2721 new TreeItem<>("b"), // 1 2722 new TreeItem<>("c"), // 2 2723 new TreeItem<>("d") // 3 2724 ); 2725 2726 TreeView<String> stringTreeView = new TreeView<>(root); 2727 stringTreeView.setShowRoot(false); 2728 MultipleSelectionModel<TreeItem<String>> sm = stringTreeView.getSelectionModel(); 2729 FocusModel<TreeItem<String>> fm = stringTreeView.getFocusModel(); 2730 2731 sm.select(indexToSelect); 2732 assertEquals(indexToSelect, sm.getSelectedIndex()); 2733 assertEquals(root.getChildren().get(indexToSelect).getValue(), sm.getSelectedItem().getValue()); 2734 assertEquals(indexToSelect, fm.getFocusedIndex()); 2735 assertEquals(root.getChildren().get(indexToSelect).getValue(), fm.getFocusedItem().getValue()); 2736 2737 root.getChildren().remove(indexToRemove); 2738 assertEquals(expectedIndex, sm.getSelectedIndex()); 2739 assertEquals(root.getChildren().get(expectedIndex).getValue(), sm.getSelectedItem().getValue()); 2740 assertEquals(debug(), expectedIndex, fm.getFocusedIndex()); 2741 assertEquals(root.getChildren().get(expectedIndex).getValue(), fm.getFocusedItem().getValue()); 2742 } 2743 2744 2745 private ObservableList<String> test_rt_39661_setup() { 2746 ObservableList<String> rawItems = FXCollections.observableArrayList( 2747 "9-item", "8-item", "7-item", "6-item", 2748 "5-item", "4-item", "3-item", "2-item", "1-item"); 2749 root = createSubTree("root", rawItems); 2750 root.setExpanded(true); 2751 treeView = new TreeView(root); 2752 return rawItems; 2753 } 2754 2755 private TreeItem createSubTree(Object item, ObservableList<String> rawItems) { 2756 TreeItem child = new TreeItem(item); 2757 child.getChildren().setAll(rawItems.stream() 2758 .map(rawItem -> new TreeItem(rawItem)) 2759 .collect(Collectors.toList())); 2760 return child; 2761 } 2762 2763 @Test public void test_rt_39661_rowLessThanExpandedItemCount() { 2764 ObservableList<String> rawItems = test_rt_39661_setup(); 2765 TreeItem child = createSubTree("child", rawItems); 2766 TreeItem grandChild = (TreeItem) child.getChildren().get(rawItems.size() - 1); 2767 root.getChildren().add(child); 2768 assertTrue("row of item must be less than expandedItemCount, but was: " + treeView.getRow(grandChild), 2769 treeView.getRow(grandChild) < treeView.getExpandedItemCount()); 2770 } 2771 2772 @Test public void test_rt_39661_rowOfGrandChildParentCollapsedUpdatedOnInsertAbove() { 2773 ObservableList<String> rawItems = test_rt_39661_setup(); 2774 int grandIndex = 2; 2775 int childIndex = 3; 2776 2777 TreeItem child = createSubTree("addedChild2", rawItems); 2778 TreeItem grandChild = (TreeItem) child.getChildren().get(grandIndex); 2779 root.getChildren().add(childIndex, child); 2780 2781 int rowOfGrand = treeView.getRow(grandChild); 2782 root.getChildren().add(childIndex - 1, createSubTree("other", rawItems)); 2783 2784 assertEquals(-1, treeView.getRow(grandChild)); 2785 } 2786 2787 @Test public void test_rt_39661_rowOfGrandChildParentCollapsedUpdatedOnInsertAboveWithoutAccess() { 2788 ObservableList<String> rawItems = test_rt_39661_setup(); 2789 int grandIndex = 2; 2790 int childIndex = 3; 2791 2792 TreeItem child = createSubTree("addedChild2", rawItems); 2793 TreeItem grandChild = (TreeItem) child.getChildren().get(grandIndex); 2794 root.getChildren().add(childIndex, child); 2795 2796 int rowOfGrand = 7; //treeView.getRow(grandChild); 2797 root.getChildren().add(childIndex, createSubTree("other", rawItems)); 2798 2799 assertEquals(-1, treeView.getRow(grandChild)); 2800 } 2801 2802 @Test public void test_rt_39661_rowOfGrandChildParentExpandedUpdatedOnInsertAbove() { 2803 ObservableList<String> rawItems = test_rt_39661_setup(); 2804 int grandIndex = 2; 2805 int childIndex = 3; 2806 TreeItem child = createSubTree("addedChild2", rawItems); 2807 TreeItem grandChild = (TreeItem) child.getChildren().get(grandIndex); 2808 child.setExpanded(true); 2809 root.getChildren().add(childIndex, child); 2810 int rowOfGrand = treeView.getRow(grandChild); 2811 root.getChildren().add(childIndex -1, createSubTree("other", rawItems)); 2812 assertEquals(rowOfGrand + 1, treeView.getRow(grandChild)); 2813 } 2814 2815 /** 2816 * Testing getRow on grandChild: compare collapsed/expanded parent. 2817 */ 2818 @Test public void test_rt_39661_rowOfGrandChildDependsOnParentExpansion() { 2819 ObservableList<String> rawItems = test_rt_39661_setup(); 2820 int grandIndex = 2; 2821 int childIndex = 3; 2822 TreeItem collapsedChild = createSubTree("addedChild", rawItems); 2823 TreeItem collapsedGrandChild = (TreeItem) collapsedChild.getChildren().get(grandIndex); 2824 root.getChildren().add(childIndex, collapsedChild); 2825 int collapedGrandIndex = treeView.getRow(collapsedGrandChild); 2826 int collapsedRowCount = treeView.getExpandedItemCount(); 2827 // start again 2828 test_rt_39661_setup(); 2829 assertEquals(collapsedRowCount - 1, treeView.getExpandedItemCount()); 2830 TreeItem expandedChild = createSubTree("addedChild2", rawItems); 2831 TreeItem expandedGrandChild = (TreeItem) expandedChild.getChildren().get(grandIndex); 2832 expandedChild.setExpanded(true); 2833 root.getChildren().add(childIndex, expandedChild); 2834 assertNotSame("getRow must depend on expansionState " + collapedGrandIndex, 2835 collapedGrandIndex, treeView.getRow(expandedGrandChild)); 2836 } 2837 2838 @Test public void test_rt_39661_rowOfGrandChildInCollapsedChild() { 2839 ObservableList<String> rawItems = test_rt_39661_setup(); 2840 2841 // create a collapsed new child to insert into the root 2842 TreeItem newChild = createSubTree("added-child", rawItems); 2843 TreeItem grandChild = (TreeItem) newChild.getChildren().get(2); 2844 root.getChildren().add(6, newChild); 2845 2846 // query the row of a grand-child 2847 int row = treeView.getRow(grandChild); 2848 2849 // grandChild not visible, row coordinate in tree is not available 2850 assertEquals("grandChild not visible", -1, row); 2851 2852 // the other way round: if we get a row, expect the item at the row be the grandChild 2853 if (row > -1) { 2854 assertEquals(grandChild, treeView.getTreeItem(row)); 2855 } 2856 } 2857 2858 @Test public void test_rt_39661_rowOfRootChild() { 2859 ObservableList<String> rawItems = test_rt_39661_setup(); 2860 int index = 2; 2861 2862 TreeItem child = (TreeItem) root.getChildren().get(index); 2863 assertEquals(index + 1, treeView.getRow(child)); 2864 } 2865 2866 @Test public void test_rt_39661_expandedItemCount() { 2867 ObservableList<String> rawItems = test_rt_39661_setup(); 2868 int initialRowCount = treeView.getExpandedItemCount(); 2869 assertEquals(root.getChildren().size() + 1, initialRowCount); 2870 2871 TreeItem collapsedChild = createSubTree("collapsed-child", rawItems); 2872 root.getChildren().add(collapsedChild); 2873 assertEquals(initialRowCount + 1, treeView.getExpandedItemCount()); 2874 2875 TreeItem expandedChild = createSubTree("expanded-child", rawItems); 2876 expandedChild.setExpanded(true); 2877 root.getChildren().add(0, expandedChild); 2878 assertEquals(2 * initialRowCount + 1, treeView.getExpandedItemCount()); 2879 } 2880 2881 @Test public void test_rt_22599() { 2882 TreeItem<RT22599_DataType> root = new TreeItem<>(); 2883 root.getChildren().setAll( 2884 new TreeItem<>(new RT22599_DataType(1, "row1")), 2885 new TreeItem<>(new RT22599_DataType(2, "row2")), 2886 new TreeItem<>(new RT22599_DataType(3, "row3"))); 2887 root.setExpanded(true); 2888 2889 TreeView<RT22599_DataType> tree = new TreeView<>(root); 2890 tree.setShowRoot(false); 2891 2892 StageLoader sl = new StageLoader(tree); 2893 2894 // testing initial state 2895 assertNotNull(tree.getSkin()); 2896 assertEquals("row1", VirtualFlowTestUtils.getCell(tree, 0).getText()); 2897 assertEquals("row2", VirtualFlowTestUtils.getCell(tree, 1).getText()); 2898 assertEquals("row3", VirtualFlowTestUtils.getCell(tree, 2).getText()); 2899 2900 // change row 0 (where "row1" currently resides), keeping same id. 2901 // Because 'set' is called, the control should update to the new content 2902 // without any user interaction 2903 TreeItem<RT22599_DataType> data; 2904 root.getChildren().set(0, data = new TreeItem<>(new RT22599_DataType(0, "row1a"))); 2905 Toolkit.getToolkit().firePulse(); 2906 assertEquals("row1a", VirtualFlowTestUtils.getCell(tree, 0).getText()); 2907 2908 // change the row 0 (where we currently have "row1a") value directly. 2909 // Because there is no associated property, this won't be observed, so 2910 // the control should still show "row1a" rather than "row1b" 2911 data.getValue().text = "row1b"; 2912 Toolkit.getToolkit().firePulse(); 2913 assertEquals("row1a", VirtualFlowTestUtils.getCell(tree, 0).getText()); 2914 2915 // call refresh() to force a refresh of all visible cells 2916 tree.refresh(); 2917 Toolkit.getToolkit().firePulse(); 2918 assertEquals("row1b", VirtualFlowTestUtils.getCell(tree, 0).getText()); 2919 2920 sl.dispose(); 2921 } 2922 2923 private static class RT22599_DataType { 2924 public int id = 0; 2925 public String text = ""; 2926 2927 public RT22599_DataType(int id, String text) { 2928 this.id = id; 2929 this.text = text; 2930 } 2931 2932 @Override public String toString() { 2933 return text; 2934 } 2935 2936 @Override public boolean equals(Object obj) { 2937 if (obj == null) return false; 2938 return id == ((RT22599_DataType)obj).id; 2939 } 2940 } 2941 2942 private int rt_39966_count = 0; 2943 @Test public void test_rt_39966() { 2944 TreeItem<String> root = new TreeItem<>("Root"); 2945 TreeView<String> table = new TreeView<>(root); 2946 table.setShowRoot(true); 2947 2948 StageLoader sl = new StageLoader(table); 2949 2950 // initially there is no selection 2951 assertTrue(table.getSelectionModel().isEmpty()); 2952 2953 table.getSelectionModel().selectedItemProperty().addListener((value, s1, s2) -> { 2954 if (rt_39966_count == 0) { 2955 rt_39966_count++; 2956 assertFalse(table.getSelectionModel().isEmpty()); 2957 } else { 2958 assertTrue(debug(), table.getSelectionModel().isEmpty()); 2959 } 2960 }); 2961 2962 // our assertion two lines down always succeeds. What fails is our 2963 // assertion above within the listener. 2964 table.getSelectionModel().select(0); 2965 assertFalse(table.getSelectionModel().isEmpty()); 2966 2967 table.setRoot(null); 2968 assertTrue(debug(),table.getSelectionModel().isEmpty()); 2969 2970 sl.dispose(); 2971 } 2972 2973 /** 2974 * Bullet 1: selected index must be updated 2975 * Corner case: last selected. Fails for core 2976 */ 2977 @Test public void test_rt_40012_selectedAtLastOnDisjointRemoveItemsAbove() { 2978 TreeItem<String> root = new TreeItem<>("Root"); 2979 root.setExpanded(true); 2980 root.getChildren().addAll( 2981 new TreeItem<>("0"), 2982 new TreeItem<>("1"), 2983 new TreeItem<>("2"), 2984 new TreeItem<>("3"), 2985 new TreeItem<>("4"), 2986 new TreeItem<>("5") 2987 ); 2988 2989 TreeView<String> treeView = new TreeView<>(root); 2990 treeView.setShowRoot(false); 2991 sm = treeView.getSelectionModel(); 2992 2993 int last = root.getChildren().size() - 1; 2994 2995 // selecting item "5" 2996 sm.select(last); 2997 2998 // disjoint remove of 2 elements above the last selected 2999 // Removing "1" and "3" 3000 root.getChildren().removeAll(root.getChildren().get(1), root.getChildren().get(3)); 3001 3002 // selection should move up two places such that it remains on item "5", 3003 // but in index (last - 2). 3004 int expected = last - 2; 3005 assertEquals("5", sm.getSelectedItem().getValue()); 3006 assertEquals("selected index after disjoint removes above", expected, sm.getSelectedIndex()); 3007 } 3008 3009 /** 3010 * Variant of 1: if selectedIndex is not updated, 3011 * the old index is no longer valid 3012 * for accessing the items. 3013 */ 3014 @Test public void test_rt_40012_accessSelectedAtLastOnDisjointRemoveItemsAbove() { 3015 TreeItem<String> root = new TreeItem<>("Root"); 3016 root.setExpanded(true); 3017 root.getChildren().addAll( 3018 new TreeItem<>("0"), 3019 new TreeItem<>("1"), 3020 new TreeItem<>("2"), 3021 new TreeItem<>("3"), 3022 new TreeItem<>("4"), 3023 new TreeItem<>("5") 3024 ); 3025 3026 TreeView<String> treeView = new TreeView<>(root); 3027 treeView.setShowRoot(false); 3028 sm = treeView.getSelectionModel(); 3029 3030 int last = root.getChildren().size() - 1; 3031 3032 // selecting item "5" 3033 sm.select(last); 3034 3035 // disjoint remove of 2 elements above the last selected 3036 root.getChildren().removeAll(root.getChildren().get(1), root.getChildren().get(3)); 3037 int selected = sm.getSelectedIndex(); 3038 if (selected > -1) { 3039 root.getChildren().get(selected); 3040 } 3041 } 3042 3043 /** 3044 * Bullet 2: selectedIndex notification count 3045 * 3046 * Note that we don't use the corner case of having the last index selected 3047 * (which fails already on updating the index) 3048 */ 3049 private int rt_40012_count = 0; 3050 @Test public void test_rt_40012_selectedIndexNotificationOnDisjointRemovesAbove() { 3051 TreeItem<String> root = new TreeItem<>("Root"); 3052 root.setExpanded(true); 3053 root.getChildren().addAll( 3054 new TreeItem<>("0"), 3055 new TreeItem<>("1"), 3056 new TreeItem<>("2"), 3057 new TreeItem<>("3"), 3058 new TreeItem<>("4"), 3059 new TreeItem<>("5") 3060 ); 3061 3062 TreeView<String> treeView = new TreeView<>(root); 3063 treeView.setShowRoot(false); 3064 sm = treeView.getSelectionModel(); 3065 3066 int last = root.getChildren().size() - 2; 3067 sm.select(last); 3068 assertEquals(last, sm.getSelectedIndex()); 3069 3070 rt_40012_count = 0; 3071 sm.selectedIndexProperty().addListener(o -> rt_40012_count++); 3072 3073 // disjoint remove of 2 elements above the last selected 3074 root.getChildren().removeAll(root.getChildren().get(1), root.getChildren().get(3)); 3075 assertEquals("sanity: selectedIndex must be shifted by -2", last - 2, sm.getSelectedIndex()); 3076 assertEquals("must fire single event on removes above", 1, rt_40012_count); 3077 } 3078 3079 /** 3080 * Bullet 3: unchanged selectedItem must not fire change 3081 */ 3082 @Test 3083 public void test_rt_40012_selectedItemNotificationOnDisjointRemovesAbove() { 3084 TreeItem<String> root = new TreeItem<>("Root"); 3085 root.setExpanded(true); 3086 root.getChildren().addAll( 3087 new TreeItem<>("0"), 3088 new TreeItem<>("1"), 3089 new TreeItem<>("2"), 3090 new TreeItem<>("3"), 3091 new TreeItem<>("4"), 3092 new TreeItem<>("5") 3093 ); 3094 3095 TreeView<String> treeView = new TreeView<>(root); 3096 treeView.setShowRoot(false); 3097 sm = treeView.getSelectionModel(); 3098 3099 int last = root.getChildren().size() - 2; 3100 Object lastItem = root.getChildren().get(last); 3101 sm.select(last); 3102 assertEquals(lastItem, sm.getSelectedItem()); 3103 3104 rt_40012_count = 0; 3105 sm.selectedItemProperty().addListener(o -> rt_40012_count++); 3106 3107 // disjoint remove of 2 elements above the last selected 3108 root.getChildren().removeAll(root.getChildren().get(1), root.getChildren().get(3)); 3109 assertEquals("sanity: selectedItem unchanged", lastItem, sm.getSelectedItem()); 3110 assertEquals("must not fire on unchanged selected item", 0, rt_40012_count); 3111 } 3112 3113 private int rt_40010_count = 0; 3114 @Test public void test_rt_40010() { 3115 TreeItem<String> root = new TreeItem<>("Root"); 3116 TreeItem<String> child = new TreeItem<>("child"); 3117 root.setExpanded(true); 3118 root.getChildren().addAll(child); 3119 3120 TreeView<String> treeView = new TreeView<>(root); 3121 sm = treeView.getSelectionModel(); 3122 3123 sm.getSelectedIndices().addListener((ListChangeListener<? super Integer>) l -> rt_40010_count++); 3124 sm.getSelectedItems().addListener((ListChangeListener<? super TreeItem<String>>) l -> rt_40010_count++); 3125 3126 assertEquals(0, rt_40010_count); 3127 3128 sm.select(1); 3129 assertEquals(1, sm.getSelectedIndex()); 3130 assertEquals(child, sm.getSelectedItem()); 3131 assertEquals(2, rt_40010_count); 3132 3133 root.getChildren().remove(child); 3134 assertEquals(0, sm.getSelectedIndex()); 3135 assertEquals(root, sm.getSelectedItem()); 3136 assertEquals(4, rt_40010_count); 3137 } 3138 3139 @Test public void test_rt_39674_staticChildren() { 3140 TreeItem<String> item2; 3141 TreeItem<String> root = new TreeItem<>("Root"); 3142 root.setExpanded(true); 3143 root.getChildren().addAll( 3144 new TreeItem<>("0"), 3145 new TreeItem<>("1"), 3146 item2 = new TreeItem<>("2"), 3147 new TreeItem<>("3"), 3148 new TreeItem<>("4"), 3149 new TreeItem<>("5") 3150 ); 3151 3152 item2.getChildren().addAll( 3153 new TreeItem<>("0"), 3154 new TreeItem<>("1"), 3155 new TreeItem<>("2"), 3156 new TreeItem<>("3"), 3157 new TreeItem<>("4"), 3158 new TreeItem<>("5") 3159 ); 3160 3161 TreeView<String> treeView = new TreeView<>(root); 3162 sm = treeView.getSelectionModel(); 3163 3164 StageLoader sl = new StageLoader(treeView); 3165 3166 sm.select(4); // select treeitem "3" in index 4 3167 assertEquals(4, sm.getSelectedIndex()); 3168 assertEquals("3", sm.getSelectedItem().getValue()); 3169 3170 item2.setExpanded(true); // expand item 2. Selection should move to position 9 3171 assertEquals(10, sm.getSelectedIndex()); 3172 assertEquals("3", sm.getSelectedItem().getValue()); 3173 3174 sl.dispose(); 3175 } 3176 3177 @Ignore("RT-39674 not yet fixed") 3178 @Test public void test_rt_39674_dynamicChildren() { 3179 TreeItem<Integer> root = createTreeItem(0); 3180 root.setExpanded(true); 3181 3182 TreeView<Integer> treeView = new TreeView<>(root); 3183 SelectionModel<TreeItem<Integer>> sm = treeView.getSelectionModel(); 3184 3185 StageLoader sl = new StageLoader(treeView); 3186 3187 sm.select(5); 3188 assertEquals(5, sm.getSelectedIndex()); 3189 assertEquals(4, (int)sm.getSelectedItem().getValue()); 3190 3191 root.getChildren().get(2).setExpanded(true); 3192 assertEquals(12, sm.getSelectedIndex()); 3193 assertEquals(4, (int)sm.getSelectedItem().getValue()); 3194 3195 sl.dispose(); 3196 } 3197 3198 private TreeItem<Integer> createTreeItem(final int index) { 3199 final TreeItem<Integer> node = new TreeItem<Integer>(index) { 3200 private boolean isLeaf; 3201 private boolean isFirstTimeChildren = true; 3202 private boolean isFirstTimeLeaf = true; 3203 3204 @Override 3205 public ObservableList<TreeItem<Integer>> getChildren() { 3206 if (isFirstTimeChildren) { 3207 isFirstTimeChildren = false; 3208 super.getChildren().setAll(buildChildren(this)); 3209 } 3210 return super.getChildren(); 3211 } 3212 3213 @Override 3214 public boolean isLeaf() { 3215 if (isFirstTimeLeaf) { 3216 isFirstTimeLeaf = false; 3217 int index = getValue(); 3218 isLeaf = index % 2 != 0; 3219 } 3220 3221 return isLeaf; 3222 } 3223 }; 3224 return node; 3225 } 3226 3227 private ObservableList<TreeItem<Integer>> buildChildren(TreeItem<Integer> TreeItem) { 3228 Integer index = TreeItem.getValue(); 3229 if (index % 2 == 0) { 3230 ObservableList<TreeItem<Integer>> children = FXCollections.observableArrayList(); 3231 for (int i = 0; i < 5; i++) { 3232 children.add(createTreeItem(i)); 3233 } 3234 3235 return children; 3236 } 3237 3238 return FXCollections.emptyObservableList(); 3239 } 3240 3241 /** 3242 * ClearAndSelect fires invalid change event if selectedIndex is unchanged. 3243 */ 3244 private int rt_40212_count = 0; 3245 @Test public void test_rt_40212() { 3246 TreeItem<String> root = new TreeItem<>("Root"); 3247 root.setExpanded(true); 3248 root.getChildren().addAll( 3249 new TreeItem<>("0"), 3250 new TreeItem<>("1"), 3251 new TreeItem<>("2"), 3252 new TreeItem<>("3"), 3253 new TreeItem<>("4"), 3254 new TreeItem<>("5") 3255 ); 3256 3257 TreeView<String> stringTreeView = new TreeView<>(root); 3258 stringTreeView.setShowRoot(false); 3259 3260 MultipleSelectionModel<TreeItem<String>> sm = stringTreeView.getSelectionModel(); 3261 sm.setSelectionMode(SelectionMode.MULTIPLE); 3262 3263 sm.selectRange(3, 5); 3264 int selected = sm.getSelectedIndex(); 3265 3266 sm.getSelectedIndices().addListener((ListChangeListener<Integer>) change -> { 3267 assertEquals("sanity: selectedIndex unchanged", selected, sm.getSelectedIndex()); 3268 while(change.next()) { 3269 assertEquals("single event on clearAndSelect already selected", 1, ++rt_40212_count); 3270 3271 boolean type = change.wasAdded() || change.wasRemoved() || change.wasPermutated() || change.wasUpdated(); 3272 assertTrue("at least one of the change types must be true", type); 3273 } 3274 }); 3275 3276 sm.clearAndSelect(selected); 3277 } 3278 3279 @Test public void test_rt_40280() { 3280 final TreeView<String> view = new TreeView<>(); 3281 StageLoader sl = new StageLoader(view); 3282 view.getFocusModel().getFocusedIndex(); 3283 sl.dispose(); 3284 } 3285 3286 @Test public void test_rt_40278_showRoot() { 3287 TreeItem<String> root = new TreeItem<>("Root"); 3288 root.setExpanded(true); 3289 root.getChildren().addAll(new TreeItem<>("0"),new TreeItem<>("1")); 3290 3291 TreeView<String> view = new TreeView<>(root); 3292 view.setShowRoot(false); 3293 MultipleSelectionModel<TreeItem<String>> sm = view.getSelectionModel(); 3294 3295 assertFalse("sanity: test setup such that root is not showing", view.isShowRoot()); 3296 sm.select(0); 3297 assertEquals(0, sm.getSelectedIndex()); 3298 assertEquals(view.getTreeItem(sm.getSelectedIndex()), sm.getSelectedItem()); 3299 view.setShowRoot(true); 3300 assertEquals(1, sm.getSelectedIndex()); 3301 assertEquals(view.getTreeItem(sm.getSelectedIndex()), sm.getSelectedItem()); 3302 } 3303 3304 @Test public void test_rt_40278_hideRoot_selectionOnChild() { 3305 TreeItem<String> root = new TreeItem<>("Root"); 3306 root.setExpanded(true); 3307 root.getChildren().addAll(new TreeItem<>("0"),new TreeItem<>("1")); 3308 3309 TreeView<String> view = new TreeView<>(root); 3310 view.setShowRoot(true); 3311 MultipleSelectionModel<TreeItem<String>> sm = view.getSelectionModel(); 3312 3313 assertTrue("sanity: test setup such that root is showing", view.isShowRoot()); 3314 sm.select(1); 3315 assertEquals(1, sm.getSelectedIndex()); 3316 assertEquals(view.getTreeItem(sm.getSelectedIndex()), sm.getSelectedItem()); 3317 view.setShowRoot(false); 3318 assertEquals(0, sm.getSelectedIndex()); 3319 assertEquals(view.getTreeItem(sm.getSelectedIndex()), sm.getSelectedItem()); 3320 } 3321 3322 @Test public void test_rt_40278_hideRoot_selectionOnRoot() { 3323 TreeItem<String> root = new TreeItem<>("Root"); 3324 root.setExpanded(true); 3325 root.getChildren().addAll(new TreeItem<>("0"),new TreeItem<>("1")); 3326 3327 TreeView<String> view = new TreeView<>(root); 3328 view.setShowRoot(true); 3329 MultipleSelectionModel<TreeItem<String>> sm = view.getSelectionModel(); 3330 3331 assertTrue("sanity: test setup such that root is showing", view.isShowRoot()); 3332 sm.select(0); 3333 assertEquals(0, sm.getSelectedIndex()); 3334 assertEquals(view.getTreeItem(sm.getSelectedIndex()), sm.getSelectedItem()); 3335 view.setShowRoot(false); 3336 assertEquals(0, sm.getSelectedIndex()); 3337 assertEquals(view.getTreeItem(sm.getSelectedIndex()), sm.getSelectedItem()); 3338 } 3339 3340 /** 3341 * Test list change of selectedIndices on setIndices. Fails for core .. 3342 */ 3343 @Test public void test_rt_40263() { 3344 TreeItem<Integer> root = new TreeItem<>(-1); 3345 root.setExpanded(true); 3346 3347 for (int i = 0; i < 10; i++) { 3348 root.getChildren().add(new TreeItem<Integer>(i)); 3349 } 3350 3351 final TreeView<Integer> view = new TreeView<>(root); 3352 MultipleSelectionModel<TreeItem<Integer>> sm = view.getSelectionModel(); 3353 sm.setSelectionMode(SelectionMode.MULTIPLE); 3354 3355 int[] indices = new int[]{2, 5, 7}; 3356 ListChangeListener<Integer> l = c -> { 3357 // firstly, we expect only one change 3358 int subChanges = 0; 3359 while(c.next()) { 3360 subChanges++; 3361 } 3362 assertEquals(1, subChanges); 3363 3364 // secondly, we expect the added size to be three, as that is the 3365 // number of items selected 3366 c.reset(); 3367 c.next(); 3368 System.out.println("Added items: " + c.getAddedSubList()); 3369 assertEquals(indices.length, c.getAddedSize()); 3370 assertArrayEquals(indices, c.getAddedSubList().stream().mapToInt(i -> i).toArray()); 3371 }; 3372 sm.getSelectedIndices().addListener(l); 3373 sm.selectIndices(indices[0], indices); 3374 } 3375 }