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